MM-49869 - add channels button lhs sidebar (#22701)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
29cff3269c
Коммит
bb939e28c9
@@ -9,3 +9,10 @@ export function setAddChannelDropdown(open: boolean) {
|
|||||||
open,
|
open,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setAddChannelCtaDropdown(open: boolean) {
|
||||||
|
return {
|
||||||
|
type: ActionTypes.ADD_CHANNEL_CTA_DROPDOWN_TOGGLE,
|
||||||
|
open,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`components/new_channel_modal should match snapshot 1`] = `
|
||||||
|
<MenuWrapper
|
||||||
|
animationComponent={[Function]}
|
||||||
|
className="AddChannelsCtaDropdown"
|
||||||
|
onToggle={[Function]}
|
||||||
|
open={false}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-label="Add Channels Dropdown"
|
||||||
|
className="SidebarChannelNavigator__addChannelsCtaLhsButton SidebarChannelNavigator__addChannelsCtaLhsButton--untouched"
|
||||||
|
id="addChannelsCta"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
aria-label="Add channels"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className="icon-plus-box"
|
||||||
|
/>
|
||||||
|
<span>
|
||||||
|
Add Channels
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</button>
|
||||||
|
<Menu
|
||||||
|
ariaLabel="Add Channels Dropdown"
|
||||||
|
id="AddChannelCtaDropdown"
|
||||||
|
>
|
||||||
|
<MenuGroup>
|
||||||
|
<MenuItemAction
|
||||||
|
id="showNewChannel"
|
||||||
|
onClick={[Function]}
|
||||||
|
show={true}
|
||||||
|
text="Create New Channel"
|
||||||
|
/>
|
||||||
|
<MenuItemAction
|
||||||
|
id="showMoreChannels"
|
||||||
|
onClick={[Function]}
|
||||||
|
show={true}
|
||||||
|
text="Browse Channels"
|
||||||
|
/>
|
||||||
|
</MenuGroup>
|
||||||
|
</Menu>
|
||||||
|
</MenuWrapper>
|
||||||
|
`;
|
||||||
@@ -82,7 +82,7 @@ exports[`components/sidebar/invite_members_button should match snapshot 1`] = `
|
|||||||
>
|
>
|
||||||
<li
|
<li
|
||||||
aria-label="Invite Members"
|
aria-label="Invite Members"
|
||||||
className="SidebarChannelNavigator_inviteMembersLhsButton SidebarChannelNavigator_inviteMembersLhsButton--untouched"
|
className="SidebarChannelNavigator__inviteMembersLhsButton SidebarChannelNavigator__inviteMembersLhsButton--untouched"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
className="icon-plus-box"
|
className="icon-plus-box"
|
||||||
|
|||||||
@@ -189,14 +189,12 @@ const AddChannelDropdown = ({
|
|||||||
placement='top'
|
placement='top'
|
||||||
overlay={tooltip}
|
overlay={tooltip}
|
||||||
>
|
>
|
||||||
<>
|
<button
|
||||||
<button
|
className={'AddChannelDropdown_dropdownButton'}
|
||||||
className={'AddChannelDropdown_dropdownButton'}
|
aria-label={intl.formatMessage({id: 'sidebar_left.add_channel_dropdown.dropdownAriaLabel', defaultMessage: 'Add Channel Dropdown'})}
|
||||||
aria-label={intl.formatMessage({id: 'sidebar_left.add_channel_dropdown.dropdownAriaLabel', defaultMessage: 'Add Channel Dropdown'})}
|
>
|
||||||
>
|
<i className='icon-plus'/>
|
||||||
<i className='icon-plus'/>
|
</button>
|
||||||
</button>
|
|
||||||
</>
|
|
||||||
</OverlayTrigger>
|
</OverlayTrigger>
|
||||||
<Menu
|
<Menu
|
||||||
id='AddChannelDropdown'
|
id='AddChannelDropdown'
|
||||||
|
|||||||
@@ -0,0 +1,148 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import {shallow} from 'enzyme';
|
||||||
|
|
||||||
|
import {mountWithIntl} from 'tests/helpers/intl-test-helper';
|
||||||
|
|
||||||
|
import {GlobalState} from 'types/store';
|
||||||
|
import Permissions from 'mattermost-redux/constants/permissions';
|
||||||
|
import {UsersState} from '@mattermost/types/users';
|
||||||
|
|
||||||
|
import {trackEvent} from 'actions/telemetry_actions.jsx';
|
||||||
|
|
||||||
|
import AddChannelsCtaButton from './add_channels_cta_button';
|
||||||
|
|
||||||
|
jest.mock('actions/telemetry_actions.jsx', () => {
|
||||||
|
const original = jest.requireActual('actions/telemetry_actions.jsx');
|
||||||
|
return {
|
||||||
|
...original,
|
||||||
|
trackEvent: jest.fn(),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const mockDispatch = jest.fn();
|
||||||
|
let mockState: GlobalState;
|
||||||
|
|
||||||
|
jest.mock('react-redux', () => ({
|
||||||
|
...jest.requireActual('react-redux') as typeof import('react-redux'),
|
||||||
|
useSelector: (selector: (state: typeof mockState) => unknown) => selector(mockState),
|
||||||
|
useDispatch: () => mockDispatch,
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('components/new_channel_modal', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mockState = {
|
||||||
|
entities: {
|
||||||
|
general: {
|
||||||
|
config: {},
|
||||||
|
},
|
||||||
|
channels: {
|
||||||
|
currentChannelId: 'current_channel_id',
|
||||||
|
channels: {},
|
||||||
|
roles: {
|
||||||
|
current_channel_id: [
|
||||||
|
'channel_user',
|
||||||
|
'channel_admin',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
teams: {
|
||||||
|
currentTeamId: 'current_team_id',
|
||||||
|
myMembers: {
|
||||||
|
current_team_id: {
|
||||||
|
roles: 'team_user team_admin',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
teams: {
|
||||||
|
current_team_id: {
|
||||||
|
id: 'current_team_id',
|
||||||
|
description: 'Curent team description',
|
||||||
|
name: 'current-team',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
preferences: {
|
||||||
|
myPreferences: {},
|
||||||
|
},
|
||||||
|
users: {
|
||||||
|
currentUserId: 'current_user_id',
|
||||||
|
profiles: {
|
||||||
|
current_user_id: {roles: 'system_user'},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
roles: {
|
||||||
|
roles: {
|
||||||
|
guest_user: {
|
||||||
|
permissions: [],
|
||||||
|
},
|
||||||
|
system_user: {
|
||||||
|
permissions: [Permissions.JOIN_PUBLIC_CHANNELS, Permissions.CREATE_PRIVATE_CHANNEL, Permissions.CREATE_PUBLIC_CHANNEL],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
views: {
|
||||||
|
addChannelCtaDropdown: {
|
||||||
|
isOpen: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as unknown as GlobalState;
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should match snapshot', () => {
|
||||||
|
expect(
|
||||||
|
shallow(
|
||||||
|
<AddChannelsCtaButton/>,
|
||||||
|
),
|
||||||
|
).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should find the add channels button when user has permissions', () => {
|
||||||
|
const wrapper = mountWithIntl(
|
||||||
|
<AddChannelsCtaButton/>,
|
||||||
|
);
|
||||||
|
expect(wrapper.find('.AddChannelsCtaDropdown').exists()).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return nothing when user does not have permissions', () => {
|
||||||
|
const guestUser = {
|
||||||
|
currentUserId: 'guest_user_id',
|
||||||
|
profiles: {
|
||||||
|
user_id: {
|
||||||
|
id: 'guest_user_id',
|
||||||
|
roles: 'team_role',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as unknown as UsersState;
|
||||||
|
mockState = {...mockState, entities: {...mockState.entities, users: guestUser}};
|
||||||
|
|
||||||
|
const wrapper = mountWithIntl(
|
||||||
|
<AddChannelsCtaButton/>,
|
||||||
|
);
|
||||||
|
expect(wrapper.find('.AddChannelsCtaDropdown').exists()).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should fire dispatch to save preferences when button is clicked', () => {
|
||||||
|
const wrapper = mountWithIntl(
|
||||||
|
<AddChannelsCtaButton/>,
|
||||||
|
);
|
||||||
|
const button = wrapper.find('.AddChannelsCtaDropdown button');
|
||||||
|
expect(mockDispatch).not.toHaveBeenCalled();
|
||||||
|
button.simulate('click');
|
||||||
|
expect(mockDispatch).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should fire trackEvent to send telemetry when button is clicked', () => {
|
||||||
|
const wrapper = mountWithIntl(
|
||||||
|
<AddChannelsCtaButton/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
const button = wrapper.find('.AddChannelsCtaDropdown button');
|
||||||
|
expect(mockDispatch).not.toHaveBeenCalled();
|
||||||
|
button.simulate('click');
|
||||||
|
|
||||||
|
expect(trackEvent).toHaveBeenCalledWith('ui', 'add_channels_cta_button_clicked');
|
||||||
|
});
|
||||||
|
});
|
||||||
155
webapp/channels/src/components/sidebar/add_channels_cta_button.tsx
Обычный файл
155
webapp/channels/src/components/sidebar/add_channels_cta_button.tsx
Обычный файл
@@ -0,0 +1,155 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import React, {useCallback} from 'react';
|
||||||
|
|
||||||
|
import {useIntl} from 'react-intl';
|
||||||
|
|
||||||
|
import {useSelector, useDispatch} from 'react-redux';
|
||||||
|
|
||||||
|
import MenuWrapper from 'components/widgets/menu/menu_wrapper';
|
||||||
|
import Menu from 'components/widgets/menu/menu';
|
||||||
|
import MoreChannels from 'components/more_channels';
|
||||||
|
import NewChannelModal from 'components/new_channel_modal/new_channel_modal';
|
||||||
|
|
||||||
|
import {isAddChannelCtaDropdownOpen} from 'selectors/views/add_channel_dropdown';
|
||||||
|
|
||||||
|
import {GlobalState} from 'types/store';
|
||||||
|
|
||||||
|
import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams';
|
||||||
|
import {haveICurrentChannelPermission} from 'mattermost-redux/selectors/entities/roles';
|
||||||
|
import {DispatchFunc} from 'mattermost-redux/types/actions';
|
||||||
|
import Permissions from 'mattermost-redux/constants/permissions';
|
||||||
|
import {getBool} from 'mattermost-redux/selectors/entities/preferences';
|
||||||
|
import {savePreferences} from 'mattermost-redux/actions/preferences';
|
||||||
|
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/common';
|
||||||
|
|
||||||
|
import {setAddChannelCtaDropdown} from 'actions/views/add_channel_dropdown';
|
||||||
|
import {openModal} from 'actions/views/modals';
|
||||||
|
import {trackEvent} from 'actions/telemetry_actions';
|
||||||
|
|
||||||
|
import {ModalIdentifiers, Preferences, Touched} from 'utils/constants';
|
||||||
|
|
||||||
|
const AddChannelsCtaButton = (): JSX.Element | null => {
|
||||||
|
const dispatch = useDispatch<DispatchFunc>();
|
||||||
|
const currentTeamId = useSelector(getCurrentTeamId);
|
||||||
|
const intl = useIntl();
|
||||||
|
const touchedAddChannelsCtaButton = useSelector((state: GlobalState) => getBool(state, Preferences.TOUCHED, Touched.ADD_CHANNELS_CTA));
|
||||||
|
|
||||||
|
const canCreatePublicChannel = useSelector((state: GlobalState) => haveICurrentChannelPermission(state, Permissions.CREATE_PUBLIC_CHANNEL));
|
||||||
|
const canCreatePrivateChannel = useSelector((state: GlobalState) => haveICurrentChannelPermission(state, Permissions.CREATE_PRIVATE_CHANNEL));
|
||||||
|
const canCreateChannel = canCreatePrivateChannel || canCreatePublicChannel;
|
||||||
|
const canJoinPublicChannel = useSelector((state: GlobalState) => haveICurrentChannelPermission(state, Permissions.JOIN_PUBLIC_CHANNELS));
|
||||||
|
const isAddChannelCtaOpen = useSelector(isAddChannelCtaDropdownOpen);
|
||||||
|
const currentUserId = useSelector(getCurrentUserId);
|
||||||
|
const openAddChannelsCtaOpen = useCallback((open: boolean) => {
|
||||||
|
dispatch(setAddChannelCtaDropdown(open));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
let buttonClass = 'SidebarChannelNavigator__addChannelsCtaLhsButton';
|
||||||
|
|
||||||
|
if (!touchedAddChannelsCtaButton) {
|
||||||
|
buttonClass += ' SidebarChannelNavigator__addChannelsCtaLhsButton--untouched';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((!canCreateChannel && !canJoinPublicChannel) || !currentTeamId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const showMoreChannelsModal = () => {
|
||||||
|
dispatch(openModal({
|
||||||
|
modalId: ModalIdentifiers.MORE_CHANNELS,
|
||||||
|
dialogType: MoreChannels,
|
||||||
|
dialogProps: {morePublicChannelsModalType: 'public'},
|
||||||
|
}));
|
||||||
|
trackEvent('ui', 'browse_channels_button_is_clicked');
|
||||||
|
};
|
||||||
|
|
||||||
|
const showNewChannelModal = () => {
|
||||||
|
dispatch(openModal({
|
||||||
|
modalId: ModalIdentifiers.NEW_CHANNEL_MODAL,
|
||||||
|
dialogType: NewChannelModal,
|
||||||
|
}));
|
||||||
|
trackEvent('ui', 'create_new_channel_button_is_clicked');
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderDropdownItems = () => {
|
||||||
|
let joinPublicChannel;
|
||||||
|
if (canJoinPublicChannel) {
|
||||||
|
joinPublicChannel = (
|
||||||
|
<Menu.ItemAction
|
||||||
|
id='showMoreChannels'
|
||||||
|
onClick={showMoreChannelsModal}
|
||||||
|
text={intl.formatMessage({id: 'sidebar_left.add_channel_dropdown.browseChannels', defaultMessage: 'Browse Channels'})}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let createChannel;
|
||||||
|
if (canCreateChannel) {
|
||||||
|
createChannel = (
|
||||||
|
<Menu.ItemAction
|
||||||
|
id='showNewChannel'
|
||||||
|
onClick={showNewChannelModal}
|
||||||
|
text={intl.formatMessage({id: 'sidebar_left.add_channel_dropdown.createNewChannel', defaultMessage: 'Create New Channel'})}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Menu.Group>
|
||||||
|
{createChannel}
|
||||||
|
{joinPublicChannel}
|
||||||
|
</Menu.Group>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const trackOpen = (opened: boolean) => {
|
||||||
|
openAddChannelsCtaOpen(opened);
|
||||||
|
trackEvent('ui', 'add_channels_cta_button_clicked');
|
||||||
|
if (!touchedAddChannelsCtaButton) {
|
||||||
|
dispatch(savePreferences(
|
||||||
|
currentUserId,
|
||||||
|
[{
|
||||||
|
category: Preferences.TOUCHED,
|
||||||
|
user_id: currentUserId,
|
||||||
|
name: Touched.ADD_CHANNELS_CTA,
|
||||||
|
value: 'true',
|
||||||
|
}],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MenuWrapper
|
||||||
|
className='AddChannelsCtaDropdown'
|
||||||
|
onToggle={trackOpen}
|
||||||
|
open={isAddChannelCtaOpen}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
className={buttonClass}
|
||||||
|
id={'addChannelsCta'}
|
||||||
|
aria-label={intl.formatMessage({id: 'sidebar_left.add_channel_dropdown.dropdownAriaLabel', defaultMessage: 'Add Channels Dropdown'})}
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
aria-label={intl.formatMessage({id: 'sidebar_left.sidebar_channel_navigator.addChannelsCta', defaultMessage: 'Add channels'})}
|
||||||
|
>
|
||||||
|
<i className='icon-plus-box'/>
|
||||||
|
<span>
|
||||||
|
{intl.formatMessage({id: 'sidebar_left.addChannelsCta', defaultMessage: 'Add Channels'})}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</button>
|
||||||
|
<Menu
|
||||||
|
id='AddChannelCtaDropdown'
|
||||||
|
ariaLabel={intl.formatMessage({id: 'sidebar_left.add_channel_cta_dropdown.dropdownAriaLabel', defaultMessage: 'Add Channels Dropdown'})}
|
||||||
|
>
|
||||||
|
{renderDropdownItems()}
|
||||||
|
</Menu>
|
||||||
|
</MenuWrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AddChannelsCtaButton;
|
||||||
@@ -32,7 +32,7 @@ type Props = {
|
|||||||
isAdmin: boolean;
|
isAdmin: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const InviteMembersButton: React.FC<Props> = (props: Props): JSX.Element | null => {
|
const InviteMembersButton = (props: Props): JSX.Element | null => {
|
||||||
const dispatch = useDispatch<DispatchFunc>();
|
const dispatch = useDispatch<DispatchFunc>();
|
||||||
|
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
@@ -50,10 +50,10 @@ const InviteMembersButton: React.FC<Props> = (props: Props): JSX.Element | null
|
|||||||
props.onClick();
|
props.onClick();
|
||||||
};
|
};
|
||||||
|
|
||||||
let buttonClass = 'SidebarChannelNavigator_inviteMembersLhsButton';
|
let buttonClass = 'SidebarChannelNavigator__inviteMembersLhsButton';
|
||||||
|
|
||||||
if (!props.touchedInviteMembersButton && Number(totalUserCount) <= Constants.USER_LIMIT) {
|
if (!props.touchedInviteMembersButton && Number(totalUserCount) <= Constants.USER_LIMIT) {
|
||||||
buttonClass += ' SidebarChannelNavigator_inviteMembersLhsButton--untouched';
|
buttonClass += ' SidebarChannelNavigator__inviteMembersLhsButton--untouched';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!currentTeamId || !totalUserCount) {
|
if (!currentTeamId || !totalUserCount) {
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ import KeyboardShortcutSequence, {
|
|||||||
KEYBOARD_SHORTCUTS,
|
KEYBOARD_SHORTCUTS,
|
||||||
} from 'components/keyboard_shortcuts/keyboard_shortcuts_sequence';
|
} from 'components/keyboard_shortcuts/keyboard_shortcuts_sequence';
|
||||||
|
|
||||||
|
import AddChannelsCtaButton from '../add_channels_cta_button';
|
||||||
|
|
||||||
import SidebarCategorySortingMenu from './sidebar_category_sorting_menu';
|
import SidebarCategorySortingMenu from './sidebar_category_sorting_menu';
|
||||||
import SidebarCategoryMenu from './sidebar_category_menu';
|
import SidebarCategoryMenu from './sidebar_category_menu';
|
||||||
|
|
||||||
@@ -342,6 +344,13 @@ export default class SidebarCategory extends React.PureComponent<Props, State> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let addChannelsCtaButton = null;
|
||||||
|
if (category.type === 'channels' && !category.collapsed) {
|
||||||
|
addChannelsCtaButton = (
|
||||||
|
<AddChannelsCtaButton/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classNames('SidebarChannelGroup a11y__section', {
|
className={classNames('SidebarChannelGroup a11y__section', {
|
||||||
@@ -399,6 +408,7 @@ export default class SidebarCategory extends React.PureComponent<Props, State> {
|
|||||||
}}
|
}}
|
||||||
</Droppable>
|
</Droppable>
|
||||||
{inviteMembersButton}
|
{inviteMembersButton}
|
||||||
|
{addChannelsCtaButton}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -4854,6 +4854,7 @@
|
|||||||
"shortcuts.team_nav.prev.mac": "Previous team:\t⌘|⌥|Up",
|
"shortcuts.team_nav.prev.mac": "Previous team:\t⌘|⌥|Up",
|
||||||
"shortcuts.team_nav.switcher": "Navigate to a specific team:\tCtrl|Alt|[1-9]",
|
"shortcuts.team_nav.switcher": "Navigate to a specific team:\tCtrl|Alt|[1-9]",
|
||||||
"shortcuts.team_nav.switcher.mac": "Navigate to a specific team:\t⌘|⌥|[1-9]",
|
"shortcuts.team_nav.switcher.mac": "Navigate to a specific team:\t⌘|⌥|[1-9]",
|
||||||
|
"sidebar_left.add_channel_cta_dropdown.dropdownAriaLabel": "Add Channel Dropdown",
|
||||||
"sidebar_left.add_channel_dropdown.browseChannels": "Browse Channels",
|
"sidebar_left.add_channel_dropdown.browseChannels": "Browse Channels",
|
||||||
"sidebar_left.add_channel_dropdown.browseOrCreateChannels": "Browse or create channels",
|
"sidebar_left.add_channel_dropdown.browseOrCreateChannels": "Browse or create channels",
|
||||||
"sidebar_left.add_channel_dropdown.createCategory": "Create New Category",
|
"sidebar_left.add_channel_dropdown.createCategory": "Create New Category",
|
||||||
@@ -4863,6 +4864,7 @@
|
|||||||
"sidebar_left.add_channel_dropdown.invitePeopleExtraText": "Add people to the team",
|
"sidebar_left.add_channel_dropdown.invitePeopleExtraText": "Add people to the team",
|
||||||
"sidebar_left.add_channel_dropdown.work_template": "Create from a template",
|
"sidebar_left.add_channel_dropdown.work_template": "Create from a template",
|
||||||
"sidebar_left.add_channel_dropdown.work_template_extra": "Set up a channel with linked boards, and playbooks",
|
"sidebar_left.add_channel_dropdown.work_template_extra": "Set up a channel with linked boards, and playbooks",
|
||||||
|
"sidebar_left.addChannelsCta": "Add channels",
|
||||||
"sidebar_left.channel_filter.filterByUnread": "Filter by unread",
|
"sidebar_left.channel_filter.filterByUnread": "Filter by unread",
|
||||||
"sidebar_left.channel_filter.filterUnreadAria": "unreads filter",
|
"sidebar_left.channel_filter.filterUnreadAria": "unreads filter",
|
||||||
"sidebar_left.channel_filter.showAllChannels": "Show all channels",
|
"sidebar_left.channel_filter.showAllChannels": "Show all channels",
|
||||||
@@ -4901,6 +4903,7 @@
|
|||||||
"sidebar_left.sidebar_channel_menu.unfavoriteChannel": "Unfavorite",
|
"sidebar_left.sidebar_channel_menu.unfavoriteChannel": "Unfavorite",
|
||||||
"sidebar_left.sidebar_channel_menu.unmuteChannel": "Unmute Channel",
|
"sidebar_left.sidebar_channel_menu.unmuteChannel": "Unmute Channel",
|
||||||
"sidebar_left.sidebar_channel_menu.unmuteConversation": "Unmute Conversation",
|
"sidebar_left.sidebar_channel_menu.unmuteConversation": "Unmute Conversation",
|
||||||
|
"sidebar_left.sidebar_channel_navigator.addChannelsCta": "Add channels",
|
||||||
"sidebar_left.sidebar_channel_navigator.inviteUsers": "Invite Users",
|
"sidebar_left.sidebar_channel_navigator.inviteUsers": "Invite Users",
|
||||||
"sidebar_left.sidebar_channel.selectedCount": "{count} selected",
|
"sidebar_left.sidebar_channel.selectedCount": "{count} selected",
|
||||||
"sidebar_right_menu.console": "System Console",
|
"sidebar_right_menu.console": "System Console",
|
||||||
|
|||||||
21
webapp/channels/src/reducers/views/add_channel_cta_dropdown.ts
Обычный файл
21
webapp/channels/src/reducers/views/add_channel_cta_dropdown.ts
Обычный файл
@@ -0,0 +1,21 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import {combineReducers} from 'redux';
|
||||||
|
|
||||||
|
import {GenericAction} from 'mattermost-redux/types/actions';
|
||||||
|
|
||||||
|
import {ActionTypes} from 'utils/constants';
|
||||||
|
|
||||||
|
export function isOpen(state = false, action: GenericAction) {
|
||||||
|
switch (action.type) {
|
||||||
|
case ActionTypes.ADD_CHANNEL_CTA_DROPDOWN_TOGGLE:
|
||||||
|
return action.open;
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default combineReducers({
|
||||||
|
isOpen,
|
||||||
|
});
|
||||||
@@ -25,6 +25,7 @@ import productMenu from './product_menu';
|
|||||||
import textbox from './textbox';
|
import textbox from './textbox';
|
||||||
import statusDropdown from './status_dropdown';
|
import statusDropdown from './status_dropdown';
|
||||||
import addChannelDropdown from './add_channel_dropdown';
|
import addChannelDropdown from './add_channel_dropdown';
|
||||||
|
import addChannelCtaDropdown from './add_channel_cta_dropdown';
|
||||||
import threads from './threads';
|
import threads from './threads';
|
||||||
import onboardingTasks from './onboarding_tasks';
|
import onboardingTasks from './onboarding_tasks';
|
||||||
|
|
||||||
@@ -50,6 +51,7 @@ export default combineReducers({
|
|||||||
channelSidebar,
|
channelSidebar,
|
||||||
statusDropdown,
|
statusDropdown,
|
||||||
addChannelDropdown,
|
addChannelDropdown,
|
||||||
|
addChannelCtaDropdown,
|
||||||
onboardingTasks,
|
onboardingTasks,
|
||||||
threads,
|
threads,
|
||||||
productMenu,
|
productMenu,
|
||||||
|
|||||||
@@ -178,6 +178,46 @@ $sidebarOpacityAnimationDuration: 0.15s;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__inviteMembersLhsButton,
|
||||||
|
&__addChannelsCtaLhsButton {
|
||||||
|
display: flex;
|
||||||
|
padding: 6px 0;
|
||||||
|
margin-left: 15px;
|
||||||
|
color: rgba(var(--sidebar-text-rgb), 0.72);
|
||||||
|
line-height: 20px;
|
||||||
|
list-style: none;
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
align-self: flex-end;
|
||||||
|
margin-top: -2px;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--untouched {
|
||||||
|
color: var(--sidebar-unread-text);
|
||||||
|
font-weight: $font-weight--semibold;
|
||||||
|
|
||||||
|
i::before {
|
||||||
|
font-weight: $font-weight--semibold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__addChannelsCtaLhsButton {
|
||||||
|
border: none;
|
||||||
|
margin-left: 0;
|
||||||
|
background: none;
|
||||||
|
|
||||||
|
li {
|
||||||
|
display: flex;
|
||||||
|
margin-left: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.AddChannelDropdown_dropdownButton,
|
.AddChannelDropdown_dropdownButton,
|
||||||
.SidebarChannelNavigator_inviteUsers,
|
.SidebarChannelNavigator_inviteUsers,
|
||||||
.SidebarChannelNavigator_jumpToButton,
|
.SidebarChannelNavigator_jumpToButton,
|
||||||
@@ -700,35 +740,12 @@ $sidebarOpacityAnimationDuration: 0.15s;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.SidebarChannelNavigator_inviteMembersLhsButton {
|
.AddChannelsCtaDropdown .dropdown-menu {
|
||||||
display: flex;
|
margin-left: 20px;
|
||||||
padding: 6px 0;
|
|
||||||
margin-left: 15px;
|
|
||||||
color: rgba(var(--sidebar-text-rgb), 0.72);
|
|
||||||
line-height: 20px;
|
|
||||||
list-style: none;
|
|
||||||
|
|
||||||
i {
|
|
||||||
font-size: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
|
||||||
align-self: flex-end;
|
|
||||||
margin-top: -2px;
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--untouched {
|
|
||||||
color: var(--sidebar-unread-text);
|
|
||||||
font-weight: $font-weight--semibold;
|
|
||||||
|
|
||||||
i::before {
|
|
||||||
font-weight: $font-weight--semibold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#introTextInvite {
|
#introTextInvite,
|
||||||
|
#addChannelsCta {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
@@ -737,6 +754,14 @@ $sidebarOpacityAnimationDuration: 0.15s;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#AddChannelCtaDropdown {
|
||||||
|
position: fixed;
|
||||||
|
|
||||||
|
ul {
|
||||||
|
min-width: 232px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.SidebarChannelNavigator_inviteUsersSticky {
|
.SidebarChannelNavigator_inviteUsersSticky {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
|
|||||||
@@ -6,3 +6,7 @@ import {GlobalState} from 'types/store';
|
|||||||
export function isAddChannelDropdownOpen(state: GlobalState) {
|
export function isAddChannelDropdownOpen(state: GlobalState) {
|
||||||
return state.views.addChannelDropdown.isOpen;
|
return state.views.addChannelDropdown.isOpen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isAddChannelCtaDropdownOpen(state: GlobalState) {
|
||||||
|
return state.views.addChannelCtaDropdown.isOpen;
|
||||||
|
}
|
||||||
|
|||||||
@@ -180,6 +180,10 @@ export type ViewsState = {
|
|||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
addChannelCtaDropdown: {
|
||||||
|
isOpen: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
onboardingTasks: {
|
onboardingTasks: {
|
||||||
isShowOnboardingTaskCompletion: boolean;
|
isShowOnboardingTaskCompletion: boolean;
|
||||||
isShowOnboardingCompleteProfileTour: boolean;
|
isShowOnboardingCompleteProfileTour: boolean;
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ export const Preferences = {
|
|||||||
// For one off things that have a special, attention-grabbing UI until you interact with them
|
// For one off things that have a special, attention-grabbing UI until you interact with them
|
||||||
export const Touched = {
|
export const Touched = {
|
||||||
INVITE_MEMBERS: 'invite_members',
|
INVITE_MEMBERS: 'invite_members',
|
||||||
|
ADD_CHANNELS_CTA: 'add_channels_cta',
|
||||||
};
|
};
|
||||||
|
|
||||||
// Category for actions/interactions that will happen just once
|
// Category for actions/interactions that will happen just once
|
||||||
@@ -264,6 +265,7 @@ export const ActionTypes = keyMirror({
|
|||||||
|
|
||||||
STATUS_DROPDOWN_TOGGLE: null,
|
STATUS_DROPDOWN_TOGGLE: null,
|
||||||
ADD_CHANNEL_DROPDOWN_TOGGLE: null,
|
ADD_CHANNEL_DROPDOWN_TOGGLE: null,
|
||||||
|
ADD_CHANNEL_CTA_DROPDOWN_TOGGLE: null,
|
||||||
|
|
||||||
SHOW_ONBOARDING_TASK_COMPLETION: null,
|
SHOW_ONBOARDING_TASK_COMPLETION: null,
|
||||||
SHOW_ONBOARDING_COMPLETE_PROFILE_TOUR: null,
|
SHOW_ONBOARDING_COMPLETE_PROFILE_TOUR: null,
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user