diff --git a/e2e-tests/cypress/tests/integration/channels/channel/archived_channels_1_spec.ts b/e2e-tests/cypress/tests/integration/channels/channel/archived_channels_1_spec.ts index 215fb828d4..206d8abc8b 100644 --- a/e2e-tests/cypress/tests/integration/channels/channel/archived_channels_1_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/channel/archived_channels_1_spec.ts @@ -94,11 +94,8 @@ describe('Leave an archived channel', () => { // # Archive the channel cy.uiArchiveChannel(); - // # Click on add channel button - cy.get('#SidebarContainer .AddChannelDropdown_dropdownButton').click(); - // # Click on browse channels - cy.get('#showMoreChannels').click(); + cy.uiBrowseOrCreateChannel('Browse channels'); // # More channels modal opens cy.get('#browseChannelsModal').should('be.visible'); @@ -141,11 +138,8 @@ describe('Leave an archived channel', () => { cy.uiArchiveChannel(); }); - // # Click on add channel button - cy.get('#SidebarContainer .AddChannelDropdown_dropdownButton').click(); - - // # Click on browse channels - cy.get('#showMoreChannels').click(); + // # Click on browse channels from menu + cy.uiBrowseOrCreateChannel('Browse channels'); // # More channels modal opens cy.get('#browseChannelsModal').should('be.visible').then(() => { @@ -194,11 +188,8 @@ describe('Leave an archived channel', () => { cy.url().should('include', `/${testTeam.name}/channels/${archivedPublicChannel1.name}`); }); - // # Click on add channel button - cy.get('#SidebarContainer .AddChannelDropdown_dropdownButton').click(); - - // # Click on browse channels - cy.get('#showMoreChannels').click(); + // # Click on browse channels from menu + cy.uiBrowseOrCreateChannel('Browse channels'); // # More channels modal opens cy.get('#browseChannelsModal').should('be.visible').then(() => { @@ -248,11 +239,8 @@ describe('Leave an archived channel', () => { cy.get('#confirmModal').should('be.visible'); cy.get('#confirmModalButton').click(); - // # Click on add channel button - cy.get('#SidebarContainer .AddChannelDropdown_dropdownButton').click(); - - // # Click on browse channels - cy.get('#showMoreChannels').click(); + // # Click on browse channels from menu + cy.uiBrowseOrCreateChannel('Browse channels'); // # More channels modal opens cy.get('#browseChannelsModal').should('be.visible').then(() => { @@ -283,11 +271,8 @@ describe('Leave an archived channel', () => { cy.uiArchiveChannel(); }); - // # Click on add channel button - cy.get('#SidebarContainer .AddChannelDropdown_dropdownButton').click(); - - // # Click on browse channels - cy.get('#showMoreChannels').click(); + // # Click on browse channels from menu + cy.uiBrowseOrCreateChannel('Browse channels'); // # More channels modal opens and lands on all channels cy.get('#browseChannelsModal').should('be.visible').then(() => { @@ -318,11 +303,8 @@ describe('Leave an archived channel', () => { // # Archive the channel cy.uiArchiveChannel(); - // # Click on add channel button - cy.get('#SidebarContainer .AddChannelDropdown_dropdownButton').click(); - - // # Click on browse channels - cy.get('#showMoreChannels').click(); + // # Click on browse channels from menu + cy.uiBrowseOrCreateChannel('Browse channels'); // # Modal should not contain the created channel cy.findByText(channelType.all).should('be.visible').click(); diff --git a/e2e-tests/cypress/tests/integration/channels/channel/browse_channels_spec.ts b/e2e-tests/cypress/tests/integration/channels/channel/browse_channels_spec.ts index edc0739e55..2396442511 100644 --- a/e2e-tests/cypress/tests/integration/channels/channel/browse_channels_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/channel/browse_channels_spec.ts @@ -70,7 +70,7 @@ describe('Channels', () => { cy.visit(`/${testTeam.name}/channels/town-square`); // # Go to LHS and click 'Browse channels' - cy.uiBrowseOrCreateChannel('Browse channels').click(); + cy.uiBrowseOrCreateChannel('Browse channels'); cy.get('#browseChannelsModal').should('be.visible').within(() => { // * Dropdown should be visible, defaulting to "All Channels" @@ -113,7 +113,7 @@ describe('Channels', () => { }); // # Go to LHS and click 'Browse channels' - cy.uiBrowseOrCreateChannel('Browse channels').click(); + cy.uiBrowseOrCreateChannel('Browse channels'); cy.get('#browseChannelsModal').should('be.visible'); @@ -167,7 +167,7 @@ describe('Channels', () => { }); // # Go to LHS and click 'Browse channels' - cy.uiBrowseOrCreateChannel('Browse channels').click(); + cy.uiBrowseOrCreateChannel('Browse channels'); cy.get('#browseChannelsModal').should('be.visible').within(() => { // * Verify that channel has zero members @@ -233,7 +233,7 @@ describe('Channels', () => { }); // # Go to LHS and click 'Browse channels' - cy.uiBrowseOrCreateChannel('Browse channels').click(); + cy.uiBrowseOrCreateChannel('Browse channels'); // * Dropdown should be visible, defaulting to "All channels" cy.get('#menuWrapper').should('be.visible').within((el) => { @@ -288,7 +288,7 @@ function verifyBrowseChannelsModalWithArchivedSelection(isEnabled, testUser, tes function verifyBrowseChannelsModal(isEnabled) { // # Go to LHS and click 'Browse channels' - cy.uiBrowseOrCreateChannel('Browse channels').click(); + cy.uiBrowseOrCreateChannel('Browse channels'); // * Verify that the browse channels modal is open and with or without option to view archived channels cy.get('#browseChannelsModal').should('be.visible').within(() => { diff --git a/e2e-tests/cypress/tests/integration/channels/channel/browse_public_channels_spec.ts b/e2e-tests/cypress/tests/integration/channels/channel/browse_public_channels_spec.ts index 1d97d60d7f..29c83de595 100644 --- a/e2e-tests/cypress/tests/integration/channels/channel/browse_public_channels_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/channel/browse_public_channels_spec.ts @@ -66,7 +66,7 @@ describe('browse public channels', () => { cy.visit(`/${testTeam.name}/channels/town-square`); // # Go to LHS and click 'Browse channels' - cy.uiBrowseOrCreateChannel('Browse channels').click(); + cy.uiBrowseOrCreateChannel('Browse channels'); // * Assert that the browse channel modal is visible cy.findByRole('dialog', {name: 'Browse Channels'}).should('be.visible').then(() => { @@ -108,7 +108,7 @@ describe('browse public channels', () => { cy.visit(`/${testTeam.name}/channels/town-square`); // # Go to LHS and click 'Browse channels' - cy.uiBrowseOrCreateChannel('Browse channels').click(); + cy.uiBrowseOrCreateChannel('Browse channels'); // * Assert the moreChannelsModel is visible cy.findByRole('dialog', {name: 'Browse Channels'}).should('be.visible').then(() => { diff --git a/e2e-tests/cypress/tests/integration/channels/channel_settings/channel_name_validations_spec.ts b/e2e-tests/cypress/tests/integration/channels/channel_settings/channel_name_validations_spec.ts index 3b1041ac10..5160f77fe8 100644 --- a/e2e-tests/cypress/tests/integration/channels/channel_settings/channel_name_validations_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/channel_settings/channel_name_validations_spec.ts @@ -53,7 +53,7 @@ describe('Channel routing', () => { it('MM-T884_2 Creating new channel validates against two user IDs being used as channel name', () => { // # click on create public channel - cy.uiBrowseOrCreateChannel('Create new channel').click(); + cy.uiBrowseOrCreateChannel('Create new channel'); // * Verify that the new channel modal is visible cy.get('#new-channel-modal').should('be.visible').within(() => { @@ -73,7 +73,7 @@ describe('Channel routing', () => { it('MM-T884_3 Creating a new channel validates against gm-like names being used as channel name', () => { // # click on create public channel - cy.uiBrowseOrCreateChannel('Create new channel').click(); + cy.uiBrowseOrCreateChannel('Create new channel'); // * Verify that the new channel modal is visible cy.findByRole('dialog', {name: 'Create a new channel'}).within(() => { diff --git a/e2e-tests/cypress/tests/integration/channels/channel_sidebar/category_sorting_1_spec.ts b/e2e-tests/cypress/tests/integration/channels/channel_sidebar/category_sorting_1_spec.ts index e4ba8271b3..c4c39ff061 100644 --- a/e2e-tests/cypress/tests/integration/channels/channel_sidebar/category_sorting_1_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/channel_sidebar/category_sorting_1_spec.ts @@ -139,11 +139,8 @@ function createCategoryFromSidebarMenu() { // # Start with a new category const categoryName = `category-${getRandomId()}`; - // # Click on the sidebar menu dropdown - cy.uiGetLHSAddChannelButton().click(); - - // # Click on create category link - cy.findByText('Create new category').should('be.visible').click(); + // # Click on the sidebar menu dropdown and select Create Category + cy.uiBrowseOrCreateChannel('Create new category'); // # Verify that Create Category modal has shown up. // # Wait for a while until the modal has fully loaded, especially during first-time access. diff --git a/e2e-tests/cypress/tests/integration/channels/channel_sidebar/category_sorting_spec.ts b/e2e-tests/cypress/tests/integration/channels/channel_sidebar/category_sorting_spec.ts index 0e46cd6d62..aec2827e7c 100644 --- a/e2e-tests/cypress/tests/integration/channels/channel_sidebar/category_sorting_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/channel_sidebar/category_sorting_spec.ts @@ -22,11 +22,8 @@ describe('Category sorting', () => { }); it('MM-T3916 Create Category character limit', () => { - // # Click on the sidebar menu dropdown - cy.uiGetLHSAddChannelButton().click(); - - // # Click on create category link - cy.findByText('Create new category').should('be.visible').click(); + // # Click on the sidebar menu dropdown and select Create Category + cy.uiBrowseOrCreateChannel('Create new category'); // # Add a name 26 characters in length e.g `abcdefghijklmnopqrstuvwxyz` cy.get('#editCategoryModal').should('be.visible').wait(TIMEOUTS.HALF_SEC).within(() => { diff --git a/e2e-tests/cypress/tests/integration/channels/channel_sidebar/custom_categories_spec.ts b/e2e-tests/cypress/tests/integration/channels/channel_sidebar/custom_categories_spec.ts index 226ad58698..ab813297d7 100644 --- a/e2e-tests/cypress/tests/integration/channels/channel_sidebar/custom_categories_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/channel_sidebar/custom_categories_spec.ts @@ -89,11 +89,8 @@ function createCategoryFromSidebarMenu() { // # Start with a new category const categoryName = `category-${getRandomId()}`; - // # Click on the sidebar menu dropdown - cy.uiGetLHSAddChannelButton().click(); - - // # Click on create category link - cy.findByText('Create new category').should('be.visible').click(); + // # Click on the sidebar menu dropdown and select Create Category + cy.uiBrowseOrCreateChannel('Create new category'); // # Verify that Create Category modal has shown up. // # Wait for a while until the modal has fully loaded, especially during first-time access. diff --git a/e2e-tests/cypress/tests/integration/channels/channel_sidebar/new_channel_dropdown_spec.ts b/e2e-tests/cypress/tests/integration/channels/channel_sidebar/new_channel_dropdown_spec.ts index 96655a6902..f1acfa370f 100644 --- a/e2e-tests/cypress/tests/integration/channels/channel_sidebar/new_channel_dropdown_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/channel_sidebar/new_channel_dropdown_spec.ts @@ -61,11 +61,8 @@ describe('Channel sidebar', () => { cy.get('#channelHeaderTitle').should('contain', 'Town Square'); cy.url().should('include', `/${teamName}/channels/town-square`); - // # Click the New Channel Dropdown button - cy.uiGetLHSAddChannelButton().should('be.visible').click(); - - // # Click the Browse channels dropdown item - cy.get('.AddChannelDropdown .MenuItem:contains(Browse channels) button').should('be.visible').click(); + // # Click on the sidebar menu dropdown and select browse channels + cy.uiBrowseOrCreateChannel('Browse channels'); // * Verify that the more channels modal is visible cy.get('#browseChannelsModal').should('be.visible'); diff --git a/e2e-tests/cypress/tests/integration/channels/enterprise/accessibility/accessibility_modals_dialogs_spec.ts b/e2e-tests/cypress/tests/integration/channels/enterprise/accessibility/accessibility_modals_dialogs_spec.ts index 5486671a20..c11aad30d3 100644 --- a/e2e-tests/cypress/tests/integration/channels/enterprise/accessibility/accessibility_modals_dialogs_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/enterprise/accessibility/accessibility_modals_dialogs_spec.ts @@ -104,7 +104,7 @@ describe('Verify Accessibility Support in Modals & Dialogs', () => { cy.reload(); // * Verify the aria-label in more public channels button - cy.uiBrowseOrCreateChannel('Browse channels').click(); + cy.uiBrowseOrCreateChannel('Browse channels'); // * Verify the accessibility support in More Channels Dialog cy.findByRole('dialog', {name: 'Browse Channels'}).within(() => { @@ -140,7 +140,7 @@ describe('Verify Accessibility Support in Modals & Dialogs', () => { it.skip('MM-T1468 Accessibility Support in Add people to Channel Dialog screen', () => { // # Add atleast 5 users for (let i = 0; i < 5; i++) { - cy.apiCreateUser().then(({user}) => { // eslint-disable-line + cy.apiCreateUser().then(({user}) => { // eslint-disable-line cy.apiAddUserToTeam(testTeam.id, user.id); }); } diff --git a/e2e-tests/cypress/tests/integration/channels/enterprise/ldap/ldap_group_sync_spec.ts b/e2e-tests/cypress/tests/integration/channels/enterprise/ldap/ldap_group_sync_spec.ts index 725eb48427..1211829fcf 100644 --- a/e2e-tests/cypress/tests/integration/channels/enterprise/ldap/ldap_group_sync_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/enterprise/ldap/ldap_group_sync_spec.ts @@ -234,7 +234,7 @@ context('ldap', () => { // # Go to team page to look for this channel in public channel directory cy.visit(`/${testTeam.name}`); - cy.uiBrowseOrCreateChannel('Browse channels').click(); + cy.uiBrowseOrCreateChannel('Browse channels'); // * Search private channel name and make sure it is still visible cy.get('#searchChannelsTextbox').type(testChannel.display_name); @@ -456,7 +456,7 @@ context('ldap', () => { cy.visit(`/${testTeam.name}/channels/off-topic`); // # Go to LHS and click 'Browse channels' - cy.uiBrowseOrCreateChannel('Browse channels').click(); + cy.uiBrowseOrCreateChannel('Browse channels'); // * Search public channel and ensure it appears in the list cy.get('#searchChannelsTextbox').type(publicChannel.display_name); @@ -473,7 +473,7 @@ context('ldap', () => { cy.visit(`/${testTeam.name}/channels/off-topic`); // # Go to LHS and click 'Browse channels' - cy.uiBrowseOrCreateChannel('Browse channels').click(); + cy.uiBrowseOrCreateChannel('Browse channels'); // * Search private channel name and make sure it isn't there in public channel directory cy.get('#searchChannelsTextbox').type(publicChannel.display_name); diff --git a/e2e-tests/cypress/tests/integration/channels/enterprise/permissions/team_permissions_spec.ts b/e2e-tests/cypress/tests/integration/channels/enterprise/permissions/team_permissions_spec.ts index 336b125d15..a1b0160fe3 100644 --- a/e2e-tests/cypress/tests/integration/channels/enterprise/permissions/team_permissions_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/enterprise/permissions/team_permissions_spec.ts @@ -148,7 +148,7 @@ describe('Team Permissions', () => { cy.visit(`/${testTeam.name}/channels/town-square`); // # Click on create new channel at LHS - cy.uiBrowseOrCreateChannel('Create new channel').click(); + cy.uiBrowseOrCreateChannel('Create new channel'); // * Verify that the create private channel is disabled cy.findByRole('dialog', {name: 'Create a new channel'}).find('#public-private-selector-button-P').should('have.class', 'disabled'); diff --git a/e2e-tests/cypress/tests/integration/channels/enterprise/system_console/about/edition_and_license_spec.js b/e2e-tests/cypress/tests/integration/channels/enterprise/system_console/about/edition_and_license_spec.js index 8b8068d5be..ac05be32d3 100644 --- a/e2e-tests/cypress/tests/integration/channels/enterprise/system_console/about/edition_and_license_spec.js +++ b/e2e-tests/cypress/tests/integration/channels/enterprise/system_console/about/edition_and_license_spec.js @@ -105,7 +105,7 @@ function verifyCreatePublicChannel(teamName, testUsers) { cy.visit(`/${teamName}/channels/town-square`); // # Click on create new channel at LHS - cy.uiBrowseOrCreateChannel('Create new channel').click(); + cy.uiBrowseOrCreateChannel('Create new channel'); cy.findByRole('dialog', {name: 'Create a new channel'}).within(() => { // * Verify if creating a public channel is disabled or not diff --git a/e2e-tests/cypress/tests/integration/channels/multi_team_and_dm/existing_channel_name_spec.js b/e2e-tests/cypress/tests/integration/channels/multi_team_and_dm/existing_channel_name_spec.js index 24ad292117..17a2822701 100644 --- a/e2e-tests/cypress/tests/integration/channels/multi_team_and_dm/existing_channel_name_spec.js +++ b/e2e-tests/cypress/tests/integration/channels/multi_team_and_dm/existing_channel_name_spec.js @@ -77,7 +77,7 @@ describe('Channel', () => { */ function verifyExistingChannelError(newChannelName, makePrivate = false) { // Click on '+' button for Public or Private Channel - cy.uiBrowseOrCreateChannel('Create new channel').click(); + cy.uiBrowseOrCreateChannel('Create new channel'); if (makePrivate) { cy.get('#public-private-selector-button-P').click(); diff --git a/e2e-tests/cypress/tests/support/ui/channel.js b/e2e-tests/cypress/tests/support/ui/channel.js index 978c50af42..43c1e87c3e 100644 --- a/e2e-tests/cypress/tests/support/ui/channel.js +++ b/e2e-tests/cypress/tests/support/ui/channel.js @@ -11,7 +11,7 @@ Cypress.Commands.add('uiCreateChannel', ({ name = '', createBoard = '', }) => { - cy.uiBrowseOrCreateChannel('Create new channel').click(); + cy.uiBrowseOrCreateChannel('Create new channel'); cy.get('#new-channel-modal').should('be.visible'); if (isPrivate) { diff --git a/e2e-tests/cypress/tests/support/ui/channel_sidebar.ts b/e2e-tests/cypress/tests/support/ui/channel_sidebar.ts index b279fc77ca..bdbed42164 100644 --- a/e2e-tests/cypress/tests/support/ui/channel_sidebar.ts +++ b/e2e-tests/cypress/tests/support/ui/channel_sidebar.ts @@ -13,11 +13,8 @@ import {getRandomId} from '../../utils'; * cy.uiCreateSidebarCategory(); */ function uiCreateSidebarCategory(categoryName: string = `category-${getRandomId()}`): ChainableT { - // # Click the New Category/Channel Dropdown button - cy.uiGetLHSAddChannelButton().click(); - - // # Click the Create new category dropdown item - cy.get('.AddChannelDropdown').should('be.visible').contains('.MenuItem', 'Create new category').click(); + // # Click on the sidebar menu dropdown and select Create Category + cy.uiBrowseOrCreateChannel('Create new category'); cy.findByRole('dialog', {name: 'Rename Category'}).should('be.visible').within(() => { // # Fill in the category name and click 'Create' diff --git a/e2e-tests/cypress/tests/support/ui/sidebar_left.ts b/e2e-tests/cypress/tests/support/ui/sidebar_left.ts index aad4631134..1393478a87 100644 --- a/e2e-tests/cypress/tests/support/ui/sidebar_left.ts +++ b/e2e-tests/cypress/tests/support/ui/sidebar_left.ts @@ -31,8 +31,7 @@ Cypress.Commands.add('uiOpenTeamMenu', (item = '') => { }); Cypress.Commands.add('uiGetLHSAddChannelButton', () => { - return cy.uiGetLHS(). - find('.AddChannelDropdown_dropdownButton'); + return cy.uiGetLHS().findByRole('button', {name: 'Browse or create channels'}); }); Cypress.Commands.add('uiGetLHSTeamMenu', () => { @@ -88,15 +87,16 @@ Cypress.Commands.add('uiGetLhsSection', (section) => { parent(); }); -Cypress.Commands.add('uiBrowseOrCreateChannel', (item) => { - cy.get('.AddChannelDropdown_dropdownButton'). - should('be.visible'). - click(); - cy.get('.dropdown-menu').should('be.visible'); +Cypress.Commands.add('uiBrowseOrCreateChannel', (menuitem) => { + cy.uiGetLHSAddChannelButton().should('be.visible').click(); - if (item) { - cy.findByRole('menuitem', {name: item}); - } + cy.get('#browserOrAddChannelMenu'). + should('exist').and('be.visible'). + within(() => { + if (menuitem) { + cy.findByText(menuitem).should('exist').click(); + } + }); }); Cypress.Commands.add('uiAddDirectMessage', () => { diff --git a/webapp/channels/src/actions/views/add_channel_dropdown.ts b/webapp/channels/src/actions/views/add_channel_dropdown.ts index 251d2acf5e..b49cf3bd20 100644 --- a/webapp/channels/src/actions/views/add_channel_dropdown.ts +++ b/webapp/channels/src/actions/views/add_channel_dropdown.ts @@ -3,13 +3,6 @@ import {ActionTypes} from 'utils/constants'; -export function setAddChannelDropdown(open: boolean) { - return { - type: ActionTypes.ADD_CHANNEL_DROPDOWN_TOGGLE, - open, - }; -} - export function setAddChannelCtaDropdown(open: boolean) { return { type: ActionTypes.ADD_CHANNEL_CTA_DROPDOWN_TOGGLE, diff --git a/webapp/channels/src/components/menu/index.ts b/webapp/channels/src/components/menu/index.ts index 0f21a10199..5c4a46de45 100644 --- a/webapp/channels/src/components/menu/index.ts +++ b/webapp/channels/src/components/menu/index.ts @@ -8,3 +8,4 @@ export {SubMenu} from './sub_menu'; export {MenuItem as Item} from './menu_item'; export type {FirstMenuItemProps} from './menu_item'; export {MenuItemSeparator as Separator} from './menu_item_separator'; +export {openMenu, dismissMenu} from './menu_utils'; diff --git a/webapp/channels/src/components/menu/menu.tsx b/webapp/channels/src/components/menu/menu.tsx index 48b20602d1..28600decb3 100644 --- a/webapp/channels/src/components/menu/menu.tsx +++ b/webapp/channels/src/components/menu/menu.tsx @@ -34,6 +34,8 @@ import {MenuContext, useMenuContextValue} from './menu_context'; import './menu.scss'; +export const ELEMENT_ID_FOR_MENU_BACKDROP = 'backdropForMenuComponent'; + const MENU_OPEN_ANIMATION_DURATION = 150; const MENU_CLOSE_ANIMATION_DURATION = 100; @@ -56,8 +58,13 @@ type MenuButtonTooltipProps = { } type MenuProps = { + + /** + * ID is mandatory as it is used in mobileWebview to open modal equivalent to menu + */ id: string; 'aria-label'?: string; + 'aria-labelledby'?: string; /** * @warning Make the styling of your components such a way that they don't need this handler @@ -244,9 +251,10 @@ export function Menu(props: Props) { disableAutoFocusItem={disableAutoFocusItem} // This is not anti-pattern, see handleMenuButtonMouseDown MenuListProps={{ id: props.menu.id, - 'aria-label': props.menu?.['aria-label'] ?? '', + 'aria-label': props.menu?.['aria-label'], + 'aria-labelledby': props.menu?.['aria-labelledby'], style: { - width: props.menu.width || 'inherit', + width: props.menu?.width, }, }} TransitionProps={{ @@ -257,6 +265,11 @@ export function Menu(props: Props) { exit: MENU_CLOSE_ANIMATION_DURATION, }, }} + slotProps={{ + backdrop: { + id: ELEMENT_ID_FOR_MENU_BACKDROP, + }, + }} // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error This exists in source code of mui, but its types are missing onTransitionExited={providerValue.handleClosed} diff --git a/webapp/channels/src/components/menu/menu_utils.ts b/webapp/channels/src/components/menu/menu_utils.ts new file mode 100644 index 0000000000..3f354e3513 --- /dev/null +++ b/webapp/channels/src/components/menu/menu_utils.ts @@ -0,0 +1,29 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {ELEMENT_ID_FOR_MENU_BACKDROP} from './menu'; + +/** + * Since the menu component requires actual interaction with the button + * of the menu for opening the menus, we trigger it from here by clicking on the menu button + */ +export function openMenu(buttonId: string) { + const menuButton = document.getElementById(buttonId); + if (!menuButton) { + return; + } + + menuButton.click(); +} + +/** + * Dismisses the menu by clicking on the backdrop + */ +export function dismissMenu() { + const menuOverlay = document.getElementById(ELEMENT_ID_FOR_MENU_BACKDROP); + if (!menuOverlay) { + return; + } + + menuOverlay.click(); +} diff --git a/webapp/channels/src/components/onboarding_tasks/complete_your_profile_tour_tip.tsx b/webapp/channels/src/components/onboarding_tasks/complete_your_profile_tour_tip.tsx index 369db76804..4ede9f1b21 100644 --- a/webapp/channels/src/components/onboarding_tasks/complete_your_profile_tour_tip.tsx +++ b/webapp/channels/src/components/onboarding_tasks/complete_your_profile_tour_tip.tsx @@ -13,7 +13,7 @@ import {isShowOnboardingCompleteProfileTour} from 'selectors/views/onboarding_ta import {OnboardingTasksName, TaskNameMapToSteps} from './constants'; import {useHandleOnBoardingTaskData} from './onboarding_tasks_manager'; -const translate = {x: 0, y: -2}; +const translate = {x: 1, y: -9}; export const CompleteYourProfileTour = () => { const dispatch = useDispatch(); @@ -43,7 +43,7 @@ export const CompleteYourProfileTour = () => {

); - const overlayPunchOut = useMeasurePunchouts(['userAccountMenu'], [], {y: -6, height: 6, x: 0, width: 0}); + const overlayPunchOut = useMeasurePunchouts(['userAccountMenu'], [], {x: -2.5, y: -2.5, width: 5, height: 5}); const onDismiss = (e: React.MouseEvent) => { e.stopPropagation(); e.preventDefault(); @@ -58,13 +58,12 @@ export const CompleteYourProfileTour = () => { overlayPunchOut={overlayPunchOut} step={steps.STARTED} placement='left-start' - pulsatingDotPlacement='left' + pulsatingDotPlacement='left-end' pulsatingDotTranslate={translate} handleDismiss={onDismiss} singleTip={true} showOptOut={false} interactivePunchOut={true} - zIndex={1058} /> ); }; diff --git a/webapp/channels/src/components/onboarding_tasks/onboarding_tasks_manager.tsx b/webapp/channels/src/components/onboarding_tasks/onboarding_tasks_manager.tsx index 011346935e..bcfdb9af8f 100644 --- a/webapp/channels/src/components/onboarding_tasks/onboarding_tasks_manager.tsx +++ b/webapp/channels/src/components/onboarding_tasks/onboarding_tasks_manager.tsx @@ -29,6 +29,7 @@ import Phone from 'components/common/svg_images_components/phone_svg'; import Security from 'components/common/svg_images_components/security_svg'; import Sunglasses from 'components/common/svg_images_components/sunglasses_svg'; import LearnMoreTrialModal from 'components/learn_more_trial_modal/learn_more_trial_modal'; +import {openMenu} from 'components/menu'; import { AutoTourStatus, FINISHED, @@ -37,9 +38,9 @@ import { TTNameMapToATStatusKey, TutorialTourName, } from 'components/tours'; +import {ELEMENT_ID_FOR_USER_ACCOUNT_MENU_BUTTON} from 'components/user_account_menu/user_account_menu'; import {ModalIdentifiers, TELEMETRY_CATEGORIES} from 'utils/constants'; -import {clickOnMenuButton, MenuButtonIds} from 'utils/keyboard'; import type {GlobalState} from 'types/store'; @@ -239,7 +240,7 @@ export const useHandleOnBoardingTaskTrigger = () => { break; } case OnboardingTasksName.COMPLETE_YOUR_PROFILE: { - clickOnMenuButton(MenuButtonIds.userAccountMenu); + openMenu(ELEMENT_ID_FOR_USER_ACCOUNT_MENU_BUTTON); dispatch(setShowOnboardingCompleteProfileTour(true)); handleSaveData(taskName, TaskNameMapToSteps[taskName].STARTED, true); if (inAdminConsole) { diff --git a/webapp/channels/src/components/post_view/post_header_custom_status/post_header_custom_status.tsx b/webapp/channels/src/components/post_view/post_header_custom_status/post_header_custom_status.tsx index 79231ea9b6..af7ad7458a 100644 --- a/webapp/channels/src/components/post_view/post_header_custom_status/post_header_custom_status.tsx +++ b/webapp/channels/src/components/post_view/post_header_custom_status/post_header_custom_status.tsx @@ -8,10 +8,10 @@ import {useSelector} from 'react-redux'; import {makeGetCustomStatus, showPostHeaderUpdateStatusButton, isCustomStatusEnabled} from 'selectors/views/custom_status'; import CustomStatusEmoji from 'components/custom_status/custom_status_emoji'; +import {openMenu} from 'components/menu'; +import {ELEMENT_ID_FOR_USER_ACCOUNT_MENU_BUTTON} from 'components/user_account_menu/user_account_menu'; import EmojiIcon from 'components/widgets/icons/emoji_icon'; -import {clickOnMenuButton, MenuButtonIds} from 'utils/keyboard'; - import type {GlobalState} from 'types/store'; interface ComponentProps { @@ -51,7 +51,7 @@ const PostHeaderCustomStatus = (props: ComponentProps) => { const updateStatus = (event: React.MouseEvent) => { event.preventDefault(); - clickOnMenuButton(MenuButtonIds.userAccountMenu); + openMenu(ELEMENT_ID_FOR_USER_ACCOUNT_MENU_BUTTON); }; return ( diff --git a/webapp/channels/src/components/sidebar/__snapshots__/sidebar.test.tsx.snap b/webapp/channels/src/components/sidebar/__snapshots__/sidebar.test.tsx.snap index 0cda1e5e7d..99d837490b 100644 --- a/webapp/channels/src/components/sidebar/__snapshots__/sidebar.test.tsx.snap +++ b/webapp/channels/src/components/sidebar/__snapshots__/sidebar.test.tsx.snap @@ -18,7 +18,6 @@ exports[`components/sidebar should match snapshot 1`] = ` showMoreChannelsModal={[Function]} showNewChannelModal={[Function]} unreadFilterEnabled={false} - userGroupsEnabled={false} />
void; - showCreateUserGroupModal: () => void; - invitePeopleModal: () => void; - showNewChannelModal: () => void; - showCreateCategoryModal: () => void; - handleOpenDirectMessagesModal: (e: Event) => void; - unreadFilterEnabled: boolean; - showCreateTutorialTip: boolean; - showInviteTutorialTip: boolean; - isAddChannelOpen: boolean; - openAddChannelOpen: (open: boolean) => void; - canCreateCustomGroups: boolean; -}; - -const AddChannelDropdown = ({ - canCreateChannel, - canJoinPublicChannel, - showMoreChannelsModal, - showCreateUserGroupModal, - invitePeopleModal, - showNewChannelModal, - showCreateCategoryModal, - handleOpenDirectMessagesModal, - unreadFilterEnabled, - showCreateTutorialTip, - showInviteTutorialTip, - isAddChannelOpen, - openAddChannelOpen, - canCreateCustomGroups, -}: Props) => { - const intl = useIntl(); - - const renderDropdownItems = () => { - const invitePeople = ( - - } - text={intl.formatMessage({id: 'sidebar_left.add_channel_dropdown.invitePeople', defaultMessage: 'Invite people'})} - extraText={intl.formatMessage({id: 'sidebar_left.add_channel_dropdown.invitePeopleExtraText', defaultMessage: 'Add people to the team'})} - /> - {showInviteTutorialTip && } - - ); - - let joinPublicChannel; - if (canJoinPublicChannel) { - joinPublicChannel = ( - } - text={intl.formatMessage({id: 'sidebar_left.add_channel_dropdown.browseChannels', defaultMessage: 'Browse channels'})} - /> - ); - } - - let createChannel; - if (canCreateChannel) { - createChannel = ( - } - text={intl.formatMessage({id: 'sidebar_left.add_channel_dropdown.createNewChannel', defaultMessage: 'Create new channel'})} - /> - ); - } - - let createCategory; - if (!unreadFilterEnabled) { - createCategory = ( - - } - text={intl.formatMessage({id: 'sidebar_left.add_channel_dropdown.createCategory', defaultMessage: 'Create new category'})} - /> - ); - } - - const createDirectMessage = ( - } - text={intl.formatMessage({id: 'sidebar.openDirectMessage', defaultMessage: 'Open a direct message'})} - /> - ); - - let createUserGroup; - if (canCreateCustomGroups) { - createUserGroup = ( - } - text={intl.formatMessage({id: 'sidebar.createUserGroup', defaultMessage: 'Create New User Group'})} - /> - ); - } - - return ( - <> - - {createChannel} - {joinPublicChannel} - {createDirectMessage} - {showCreateTutorialTip && } - {createUserGroup} - - {createCategory} - {invitePeople} - - ); - }; - - const trackOpen = (opened: boolean) => { - openAddChannelOpen(opened); - if (opened) { - trackEvent('ui', 'ui_add_channel_dropdown_opened'); - } - }; - - if (!(canCreateChannel || canJoinPublicChannel)) { - return null; - } - - return ( - - - - - - {renderDropdownItems()} - - - ); -}; - -export default AddChannelDropdown; diff --git a/webapp/channels/src/components/sidebar/channel_navigator/channel_navigator.test.tsx b/webapp/channels/src/components/sidebar/channel_navigator/channel_navigator.test.tsx index 3139b7a35f..d6f1e63d65 100644 --- a/webapp/channels/src/components/sidebar/channel_navigator/channel_navigator.test.tsx +++ b/webapp/channels/src/components/sidebar/channel_navigator/channel_navigator.test.tsx @@ -4,11 +4,11 @@ import {shallow} from 'enzyme'; import React from 'react'; +import BrowserOrAddChannelMenu from 'components/sidebar/sidebar_header/sidebar_browse_or_add_channel_menu'; + import ChannelNavigator from './channel_navigator'; import type {Props} from './channel_navigator'; -import AddChannelDropdown from '../add_channel_dropdown'; - let props: Props; describe('Components/ChannelNavigator', () => { @@ -23,8 +23,8 @@ describe('Components/ChannelNavigator', () => { }; }); - it('should not show AddChannelDropdown', () => { + it('should not show BrowserOrAddChannelMenu', () => { const wrapper = shallow(); - expect(wrapper.find(AddChannelDropdown).length).toBe(0); + expect(wrapper.find(BrowserOrAddChannelMenu).length).toBe(0); }); }); diff --git a/webapp/channels/src/components/sidebar/index.ts b/webapp/channels/src/components/sidebar/index.ts index fe67d9ebb2..98ba9eedfa 100644 --- a/webapp/channels/src/components/sidebar/index.ts +++ b/webapp/channels/src/components/sidebar/index.ts @@ -29,7 +29,6 @@ import Sidebar from './sidebar'; function mapStateToProps(state: GlobalState) { const currentTeam = getCurrentTeam(state); const unreadFilterEnabled = isUnreadFilterEnabled(state); - const userGroupsEnabled = isCustomGroupsEnabled(state); let canCreatePublicChannel = false; let canCreatePrivateChannel = false; @@ -41,7 +40,7 @@ function mapStateToProps(state: GlobalState) { canJoinPublicChannel = haveICurrentChannelPermission(state, Permissions.JOIN_PUBLIC_CHANNELS); } - const canCreateCustomGroups = haveISystemPermission(state, {permission: Permissions.CREATE_CUSTOM_GROUP}) && isCustomGroupsEnabled(state); + const canCreateCustomGroups = isCustomGroupsEnabled(state) && haveISystemPermission(state, {permission: Permissions.CREATE_CUSTOM_GROUP}); return { teamId: currentTeam ? currentTeam.id : '', @@ -52,7 +51,6 @@ function mapStateToProps(state: GlobalState) { unreadFilterEnabled, isMobileView: getIsMobileView(state), isKeyBoardShortcutModalOpen: isModalOpen(state, ModalIdentifiers.KEYBOARD_SHORTCUTS_MODAL), - userGroupsEnabled, canCreateCustomGroups, rhsState: getRhsState(state), rhsOpen: getIsRhsOpen(state), diff --git a/webapp/channels/src/components/sidebar/sidebar.tsx b/webapp/channels/src/components/sidebar/sidebar.tsx index 8291183127..10d6b5923e 100644 --- a/webapp/channels/src/components/sidebar/sidebar.tsx +++ b/webapp/channels/src/components/sidebar/sidebar.tsx @@ -48,7 +48,6 @@ type Props = { unreadFilterEnabled: boolean; isMobileView: boolean; isKeyBoardShortcutModalOpen: boolean; - userGroupsEnabled: boolean; canCreateCustomGroups: boolean; rhsState?: RhsState; rhsOpen?: boolean; @@ -180,8 +179,8 @@ export default class Sidebar extends React.PureComponent { trackEvent('ui', 'ui_channels_create_user_group'); }; - handleOpenMoreDirectChannelsModal = (e: Event) => { - e.preventDefault(); + handleOpenMoreDirectChannelsModal = (e?: Event) => { + e?.preventDefault(); if (this.state.showDirectChannelsModal) { this.hideMoreDirectChannelsModal(); } else { @@ -248,7 +247,6 @@ export default class Sidebar extends React.PureComponent { canJoinPublicChannel={this.props.canJoinPublicChannel} handleOpenDirectMessagesModal={this.handleOpenMoreDirectChannelsModal} unreadFilterEnabled={this.props.unreadFilterEnabled} - userGroupsEnabled={this.props.userGroupsEnabled} canCreateCustomGroups={this.props.canCreateCustomGroups} /> )} diff --git a/webapp/channels/src/components/sidebar/sidebar_header/index.ts b/webapp/channels/src/components/sidebar/sidebar_header/index.ts index 9c25973bbe..648ced088c 100644 --- a/webapp/channels/src/components/sidebar/sidebar_header/index.ts +++ b/webapp/channels/src/components/sidebar/sidebar_header/index.ts @@ -2,4 +2,5 @@ // See LICENSE.txt for license information. import SidebarHeader from './sidebar_header'; + export default SidebarHeader; diff --git a/webapp/channels/src/components/sidebar/sidebar_header/sidebar_browse_or_add_channel_menu.tsx b/webapp/channels/src/components/sidebar/sidebar_header/sidebar_browse_or_add_channel_menu.tsx new file mode 100644 index 0000000000..5f8f389358 --- /dev/null +++ b/webapp/channels/src/components/sidebar/sidebar_header/sidebar_browse_or_add_channel_menu.tsx @@ -0,0 +1,176 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; +import {FormattedMessage, useIntl} from 'react-intl'; + +import { + PlusIcon, + AccountPlusOutlineIcon, + FolderPlusOutlineIcon, + AccountMultiplePlusOutlineIcon, + GlobeIcon, + AccountOutlineIcon, +} from '@mattermost/compass-icons/components'; + +import * as Menu from 'components/menu'; +import {OnboardingTourSteps} from 'components/tours'; +import {useShowOnboardingTutorialStep, CreateAndJoinChannelsTour, InvitePeopleTour} from 'components/tours/onboarding_tour'; + +export const ELEMENT_ID_FOR_BROWSE_OR_ADD_CHANNEL_MENU = 'browseOrAddChannelMenuButton'; + +type Props = { + canCreateChannel: boolean; + onCreateNewChannelClick: () => void; + canJoinPublicChannel: boolean; + onBrowseChannelClick: () => void; + onOpenDirectMessageClick: () => void; + canCreateCustomGroups: boolean; + onCreateNewUserGroupClick: () => void; + unreadFilterEnabled: boolean; + onCreateNewCategoryClick: () => void; + onInvitePeopleClick: () => void; +}; + +export default function SidebarBrowserOrAddChannelMenu(props: Props) { + const {formatMessage} = useIntl(); + + const showCreateAndJoinChannelsTutorialTip = useShowOnboardingTutorialStep(OnboardingTourSteps.CREATE_AND_JOIN_CHANNELS); + const showInvitePeopleTutorialTip = useShowOnboardingTutorialStep(OnboardingTourSteps.INVITE_PEOPLE); + + let createNewChannelMenuItem: JSX.Element | null = null; + if (props.canCreateChannel) { + createNewChannelMenuItem = ( + } + labels={( + + )} + trailingElements={showCreateAndJoinChannelsTutorialTip && } + /> + ); + } + + let browseChannelsMenuItem: JSX.Element | null = null; + if (props.canJoinPublicChannel) { + browseChannelsMenuItem = ( + } + labels={( + + )} + /> + ); + } + + const createDirectMessageMenuItem = ( + } + labels={( + + )} + /> + ); + + let createUserGroupMenuItem: JSX.Element | null = null; + if (props.canCreateCustomGroups) { + createUserGroupMenuItem = ( + } + labels={( + + )} + /> + ); + } + + let createNewCategoryMenuItem: JSX.Element | null = null; + if (!props.unreadFilterEnabled) { + createNewCategoryMenuItem = ( + } + labels={( + + )} + /> + ); + } + + const invitePeopleMenuItem = ( + } + labels={( + <> + + + + )} + trailingElements={showInvitePeopleTutorialTip && } + /> + ); + + return ( + , + }} + menuButtonTooltip={{ + text: formatMessage({id: 'sidebarLeft.browserOrCreateChannelMenuButton.label', defaultMessage: 'Browse or create channels'}), + }} + menu={{ + id: 'browserOrAddChannelMenu', + 'aria-labelledby': ELEMENT_ID_FOR_BROWSE_OR_ADD_CHANNEL_MENU, + }} + > + {createNewChannelMenuItem} + {browseChannelsMenuItem} + {createDirectMessageMenuItem} + {createUserGroupMenuItem} + {Boolean(createNewCategoryMenuItem) && + + } + {createNewCategoryMenuItem} + + {invitePeopleMenuItem} + + ); +} diff --git a/webapp/channels/src/components/sidebar/sidebar_header/sidebar_header.scss b/webapp/channels/src/components/sidebar/sidebar_header/sidebar_header.scss index 0bed0f1c4d..a86f2bb00c 100644 --- a/webapp/channels/src/components/sidebar/sidebar_header/sidebar_header.scss +++ b/webapp/channels/src/components/sidebar/sidebar_header/sidebar_header.scss @@ -1,3 +1,13 @@ +.sidebarHeaderContainer { + display: flex; + height: 55px; + flex-direction: row; + flex-wrap: nowrap; + align-items: center; + justify-content: space-between; + padding: 0 16px; +} + .sidebarHeader { display: flex; margin: 0; diff --git a/webapp/channels/src/components/sidebar/sidebar_header/sidebar_header.test.tsx b/webapp/channels/src/components/sidebar/sidebar_header/sidebar_header.test.tsx index 04807c0c80..e09aacc7a8 100644 --- a/webapp/channels/src/components/sidebar/sidebar_header/sidebar_header.test.tsx +++ b/webapp/channels/src/components/sidebar/sidebar_header/sidebar_header.test.tsx @@ -9,11 +9,10 @@ import IconButton from '@mattermost/compass-components/components/icon-button'; import {CloudProducts} from 'utils/constants'; import {FileSizes} from 'utils/file_utils'; +import BrowserOrAddChannelMenu from './sidebar_browse_or_add_channel_menu'; import SidebarHeader from './sidebar_header'; import type {Props} from './sidebar_header'; -import AddChannelDropdown from '../add_channel_dropdown'; - let props: Props; const mockDispatch = jest.fn(); @@ -37,7 +36,6 @@ describe('Components/SidebarHeader', () => { handleOpenDirectMessagesModal: jest.fn(), unreadFilterEnabled: true, showCreateUserGroupModal: jest.fn(), - userGroupsEnabled: false, canCreateCustomGroups: true, }; @@ -130,9 +128,9 @@ describe('Components/SidebarHeader', () => { }; }); - it('should show AddChannelDropdown', () => { + it('should show BrowserOrAddChannelMenu', () => { const wrapper = shallow(); - expect(wrapper.find(AddChannelDropdown).length).toBe(1); + expect(wrapper.find(BrowserOrAddChannelMenu).length).toBe(1); }); it('should embed teams menu dropdown into heading', () => { diff --git a/webapp/channels/src/components/sidebar/sidebar_header/sidebar_header.tsx b/webapp/channels/src/components/sidebar/sidebar_header/sidebar_header.tsx index 4660f3efaa..e0dc4ad17f 100644 --- a/webapp/channels/src/components/sidebar/sidebar_header/sidebar_header.tsx +++ b/webapp/channels/src/components/sidebar/sidebar_header/sidebar_header.tsx @@ -1,58 +1,20 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useCallback, useState} from 'react'; -import {useDispatch, useSelector} from 'react-redux'; -import styled from 'styled-components'; +import React, {useState} from 'react'; +import {useSelector} from 'react-redux'; -import Flex from '@mattermost/compass-components/utilities/layout/Flex'; // eslint-disable-line no-restricted-imports - -import {getTheme} from 'mattermost-redux/selectors/entities/preferences'; import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams'; -import {setAddChannelDropdown} from 'actions/views/add_channel_dropdown'; -import {isAddChannelDropdownOpen} from 'selectors/views/add_channel_dropdown'; - import useGetUsageDeltas from 'components/common/hooks/useGetUsageDeltas'; -import CompassThemeProvider from 'components/compass_theme_provider/compass_theme_provider'; import MainMenu from 'components/main_menu'; -import AddChannelDropdown from 'components/sidebar/add_channel_dropdown'; -import {OnboardingTourSteps} from 'components/tours'; -import {useShowOnboardingTutorialStep} from 'components/tours/onboarding_tour'; import MenuWrapper from 'components/widgets/menu/menu_wrapper'; import WithTooltip from 'components/with_tooltip'; +import SidebarBrowseOrAddChannelMenu from './sidebar_browse_or_add_channel_menu'; + import './sidebar_header.scss'; -import type {GlobalState} from 'types/store'; - -type SidebarHeaderContainerProps = { - id?: string; -} - -const SidebarHeaderContainer = styled(Flex).attrs(() => ({ - element: 'header', - row: true, - justify: 'space-between', - alignment: 'center', -}))` - height: 55px; - padding: 0 16px; - gap: 8px; - - .dropdown-menu { - position: absolute; - transform: translate(0, 0); - margin-left: 0; - min-width: 210px; - } - - #SidebarContainer & .AddChannelDropdown_dropdownButton { - border-radius: 16px; - font-size: 18px; - } -`; - export type Props = { showNewChannelModal: () => void; showMoreChannelsModal: () => void; @@ -61,23 +23,14 @@ export type Props = { showCreateCategoryModal: () => void; canCreateChannel: boolean; canJoinPublicChannel: boolean; - handleOpenDirectMessagesModal: (e: Event) => void; + handleOpenDirectMessagesModal: () => void; unreadFilterEnabled: boolean; - userGroupsEnabled: boolean; canCreateCustomGroups: boolean; } const SidebarHeader = (props: Props) => { - const dispatch = useDispatch(); - const currentTeam = useSelector((state: GlobalState) => getCurrentTeam(state)); - const showCreateTutorialTip = useShowOnboardingTutorialStep(OnboardingTourSteps.CREATE_AND_JOIN_CHANNELS); - const showInviteTutorialTip = useShowOnboardingTutorialStep(OnboardingTourSteps.INVITE_PEOPLE); + const currentTeam = useSelector(getCurrentTeam); const usageDeltas = useGetUsageDeltas(); - const isAddChannelOpen = useSelector(isAddChannelDropdownOpen); - const theme = useSelector(getTheme); - const openAddChannelOpen = useCallback((open: boolean) => { - dispatch(setAddChannelDropdown(open)); - }, []); const [menuToggled, setMenuToggled] = useState(false); @@ -90,48 +43,44 @@ const SidebarHeader = (props: Props) => { } return ( - - + - - -

- -

-
- -
- + + + + -
-
+ + {(props.canCreateChannel || props.canJoinPublicChannel) && ( + + )} + ); }; diff --git a/webapp/channels/src/components/threading/channel_threads/thread_footer/__snapshots__/thread_footer.test.tsx.snap b/webapp/channels/src/components/threading/channel_threads/thread_footer/__snapshots__/thread_footer.test.tsx.snap index fb52483df6..f5a967e52f 100644 --- a/webapp/channels/src/components/threading/channel_threads/thread_footer/__snapshots__/thread_footer.test.tsx.snap +++ b/webapp/channels/src/components/threading/channel_threads/thread_footer/__snapshots__/thread_footer.test.tsx.snap @@ -76,13 +76,13 @@ exports[`components/threading/channel_threads/thread_footer should report total