Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 21 additions & 16 deletions apps/meteor/client/NavBarV2/NavBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,23 @@ import {
NavBarItemOmnichannelQueue,
NavBarItemOmnichannelCallToggle,
} from './NavBarOmnichannelToolbar';
import { NavBarItemMarketPlaceMenu, NavBarItemAuditMenu, NavBarItemDirectoryPage, NavBarItemHomePage } from './NavBarPagesToolbar';
import {
NavBarItemMarketPlaceMenu,
NavBarItemDirectoryPage,
NavBarItemHomePage,
NavBarItemCreateNew,
NavBarItemSort,
} from './NavBarPagesToolbar';
import { NavBarItemLoginPage, NavBarItemAdministrationMenu, UserMenu } from './NavBarSettingsToolbar';
import { NavBarItemVoipDialer } from './NavBarVoipToolbar';
import { NavBarItemVoipDialer, NavBarItemVoipToggler } from './NavBarVoipToolbar';
import { useIsCallEnabled, useIsCallReady } from '../contexts/CallContext';
import { useOmnichannelEnabled } from '../hooks/omnichannel/useOmnichannelEnabled';
import { useOmnichannelShowQueueLink } from '../hooks/omnichannel/useOmnichannelShowQueueLink';
import { useHasLicenseModule } from '../hooks/useHasLicenseModule';

const NavBar = () => {
const t = useTranslation();
const user = useUser();

const hasAuditLicense = useHasLicenseModule('auditing') === true;

const showOmnichannel = useOmnichannelEnabled();
const hasManageAppsPermission = usePermission('manage-apps');
const hasAccessMarketplacePermission = usePermission('access-marketplace');
Expand All @@ -51,30 +54,32 @@ const NavBar = () => {
<NavBarItemHomePage title={t('Home')} />
<NavBarItemDirectoryPage title={t('Directory')} />
{showMarketplace && <NavBarItemMarketPlaceMenu />}
{hasAuditLicense && <NavBarItemAuditMenu />}
<NavBarItemCreateNew />
<NavBarItemSort />
</NavBarGroup>
{showOmnichannel && (
</NavBarSection>
<NavBarSection>
{showVoip && (
<>
<NavBarGroup role='toolbar' ref={voipToolbarRef} {...voipToolbarProps}>
<NavBarItemVoipDialer primary={isCallEnabled} />
<NavBarItemVoipToggler />
</NavBarGroup>
<NavBarDivider />
</>
)}
{showOmnichannel && (
<>
<NavBarGroup role='toolbar' ref={omnichannelToolbarRef} {...omnichannelToolbarProps}>
{showOmnichannelQueueLink && <NavBarItemOmnichannelQueue title={t('Queue')} />}
{isCallReady && <NavBarItemOmniChannelCallDialPad />}
<NavBarItemOmnichannelContact title={t('Contact_Center')} />
{isCallEnabled && <NavBarItemOmnichannelCallToggle />}
<NavBarItemOmnichannelLivechatToggle />
</NavBarGroup>
</>
)}
{showVoip && (
<>
<NavBarDivider />
<NavBarGroup role='toolbar' ref={voipToolbarRef} {...voipToolbarProps}>
<NavBarItemVoipDialer primary={isCallEnabled} />
</NavBarGroup>
</>
)}
</NavBarSection>
<NavBarSection>
<NavBarGroup aria-label={t('Workspace_and_user_settings')}>
<NavBarItemAdministrationMenu />
{user ? <UserMenu user={user} /> : <NavBarItemLoginPage />}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ import { GenericMenu } from '@rocket.chat/ui-client';
import type { HTMLAttributes } from 'react';
import { useTranslation } from 'react-i18next';

import { useCreateRoom } from './hooks/useCreateRoomMenu';
import { useCreateNewMenu } from './hooks/useCreateNewMenu';

type CreateRoomProps = Omit<HTMLAttributes<HTMLElement>, 'is'>;

const CreateRoom = (props: CreateRoomProps) => {
const NavBarItemCreateNew = (props: CreateRoomProps) => {
const { t } = useTranslation();

const sections = useCreateRoom();
const sections = useCreateNewMenu();

return <GenericMenu icon='edit-rounded' sections={sections} title={t('Create_new')} is={SidebarV2Action} {...props} />;
return <GenericMenu icon='plus' sections={sections} title={t('Create_new')} is={SidebarV2Action} {...props} />;
};

export default CreateRoom;
export default NavBarItemCreateNew;
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import { useTranslation } from 'react-i18next';

import { useSortMenu } from './hooks/useSortMenu';

type SortProps = Omit<HTMLAttributes<HTMLElement>, 'is'>;
type NavBarItemSortProps = Omit<HTMLAttributes<HTMLElement>, 'is'>;

const Sort = (props: SortProps) => {
const NavBarItemSort = (props: NavBarItemSortProps) => {
const { t } = useTranslation();

const sections = useSortMenu();

return <GenericMenu icon='sort' sections={sections} title={t('Display')} selectionMode='multiple' is={SidebarV2Action} {...props} />;
};

export default Sort;
export default NavBarItemSort;
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ import type { ComponentProps, ReactElement } from 'react';
import { useId, useEffect, useMemo } from 'react';
import { useForm, Controller } from 'react-hook-form';

import { useEncryptedRoomDescription } from './hooks/useEncryptedRoomDescription';
import UserAutoCompleteMultipleFederated from '../../components/UserAutoCompleteMultiple/UserAutoCompleteMultipleFederated';
import { useHasLicenseModule } from '../../hooks/useHasLicenseModule';
import { goToRoomById } from '../../lib/utils/goToRoomById';
import { useEncryptedRoomDescription } from './useEncryptedRoomDescription';
import UserAutoCompleteMultipleFederated from '../../../components/UserAutoCompleteMultiple/UserAutoCompleteMultipleFederated';
import { useHasLicenseModule } from '../../../hooks/useHasLicenseModule';
import { goToRoomById } from '../../../lib/utils/goToRoomById';

type CreateChannelModalProps = {
teamId?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { useMutation } from '@tanstack/react-query';
import { useId, memo } from 'react';
import { useForm, Controller } from 'react-hook-form';

import UserAutoCompleteMultipleFederated from '../../components/UserAutoCompleteMultiple/UserAutoCompleteMultipleFederated';
import { goToRoomById } from '../../lib/utils/goToRoomById';
import UserAutoCompleteMultipleFederated from '../../../components/UserAutoCompleteMultiple/UserAutoCompleteMultipleFederated';
import { goToRoomById } from '../../../lib/utils/goToRoomById';

type CreateDirectMessageProps = { onClose: () => void };

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ import type { ComponentProps, ReactElement } from 'react';
import { useId, memo, useEffect, useMemo } from 'react';
import { Controller, useForm } from 'react-hook-form';

import { useEncryptedRoomDescription } from './hooks/useEncryptedRoomDescription';
import UserAutoCompleteMultiple from '../../components/UserAutoCompleteMultiple';
import { goToRoomById } from '../../lib/utils/goToRoomById';
import { useEncryptedRoomDescription } from './useEncryptedRoomDescription';
import UserAutoCompleteMultiple from '../../../components/UserAutoCompleteMultiple';
import { goToRoomById } from '../../../lib/utils/goToRoomById';

type CreateTeamModalInputs = {
name: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import type { GenericMenuItemProps } from '@rocket.chat/ui-client';
import { useTranslation, useSetting, useAtLeastOnePermission } from '@rocket.chat/ui-contexts';

import CreateDiscussion from '../../../../components/CreateDiscussion';
import CreateChannelModal from '../../CreateChannelModal';
import CreateDirectMessage from '../../CreateDirectMessage';
import CreateTeamModal from '../../CreateTeamModal';
import { useCreateRoomModal } from '../../hooks/useCreateRoomModal';
import { useCreateRoomModal } from './useCreateRoomModal';
import CreateDiscussion from '../../../components/CreateDiscussion';
import CreateChannelModal from '../actions/CreateChannelModal';
import CreateDirectMessage from '../actions/CreateDirectMessage';
import CreateTeamModal from '../actions/CreateTeamModal';

const CREATE_CHANNEL_PERMISSIONS = ['create-c', 'create-p'];
const CREATE_TEAM_PERMISSIONS = ['create-team'];
const CREATE_DIRECT_PERMISSIONS = ['create-d'];
const CREATE_DISCUSSION_PERMISSIONS = ['start-discussion', 'start-discussion-other-user'];

export const useCreateRoomItems = (): GenericMenuItemProps[] => {
export const useCreateNewItems = (): GenericMenuItemProps[] => {
const t = useTranslation();
const discussionEnabled = useSetting('Discussion_enabled');

Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { useAtLeastOnePermission, useSetting } from '@rocket.chat/ui-contexts';
import { useTranslation } from 'react-i18next';

import { useCreateRoomItems } from './useCreateRoomItems';
import { useCreateNewItems } from './useCreateNewItems';
import { useMatrixFederationItems } from './useMatrixFederationItems';
import { useIsEnterprise } from '../../../../hooks/useIsEnterprise';
import { useIsEnterprise } from '../../../hooks/useIsEnterprise';

const CREATE_ROOM_PERMISSIONS = ['create-c', 'create-p', 'create-d', 'start-discussion', 'start-discussion-other-user'];

export const useCreateRoom = () => {
export const useCreateNewMenu = () => {
const { t } = useTranslation();
const showCreate = useAtLeastOnePermission(CREATE_ROOM_PERMISSIONS);

const { data } = useIsEnterprise();
const isMatrixEnabled = useSetting('Federation_Matrix_enabled') && data?.isEnterprise;

const createRoomItems = useCreateRoomItems();
const createRoomItems = useCreateNewItems();
const matrixFederationSearchItems = useMatrixFederationItems({ isMatrixEnabled });

const sections = [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { GenericMenuItemProps } from '@rocket.chat/ui-client';
import { useTranslation } from 'react-i18next';

import MatrixFederationSearch from '../../MatrixFederationSearch';
import { useCreateRoomModal } from '../../hooks/useCreateRoomModal';
import { useCreateRoomModal } from './useCreateRoomModal';
import MatrixFederationSearch from '../../../sidebarv2/header/MatrixFederationSearch';

export const useMatrixFederationItems = ({
isMatrixEnabled,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useTranslation } from 'react-i18next';
import {
OmnichannelSortingDisclaimer,
useOmnichannelSortingDisclaimer,
} from '../../../../components/Omnichannel/OmnichannelSortingDisclaimer';
} from '../../../components/Omnichannel/OmnichannelSortingDisclaimer';

export const useSortModeItems = (): GenericMenuItemProps[] => {
const { t } = useTranslation();
Expand Down
3 changes: 2 additions & 1 deletion apps/meteor/client/NavBarV2/NavBarPagesToolbar/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { default as NavBarItemAuditMenu } from './NavBarItemAuditMenu';
export { default as NavBarItemHomePage } from './NavBarItemHomePage';
export { default as NavBarItemMarketPlaceMenu } from './NavBarItemMarketPlaceMenu';
export { default as NavBarItemDirectoryPage } from './NavBarItemDirectoryPage';
export { default as NavBarItemCreateNew } from './NavBarItemCreateNew';
export { default as NavBarItemSort } from './NavBarItemSort';
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { mockAppRoot } from '@rocket.chat/mock-providers';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import NavBarItemAdministrationMenu from './NavBarItemAdministrationMenu';

it('should not display the menu if no permission is set', async () => {
render(<NavBarItemAdministrationMenu />, { wrapper: mockAppRoot().build() });

expect(screen.queryByRole('button', { name: 'Manage' })).not.toBeInTheDocument();
});

it('should display the workspace menu item if at least one admin permission is set', async () => {
render(<NavBarItemAdministrationMenu />, { wrapper: mockAppRoot().withPermission('access-permissions').build() });

const menuButton = await screen.findByRole('button', { name: 'Manage' });
await userEvent.click(menuButton);
expect(await screen.findByRole('menuitem', { name: 'Workspace' })).toBeInTheDocument();
});

it('should display the omnichannel menu item if view-livechat-manager permission is set', async () => {
render(<NavBarItemAdministrationMenu />, {
wrapper: mockAppRoot().withPermission('view-livechat-manager').withPermission('access-permissions').build(),
});

const menuButton = await screen.findByRole('button', { name: 'Manage' });
await userEvent.click(menuButton);
expect(await screen.findByRole('menuitem', { name: 'Omnichannel' })).toBeInTheDocument();
});

it('should not display any audit items if has at least one admin permission, some audit permission and the auditing module is not enabled', async () => {
render(<NavBarItemAdministrationMenu />, {
wrapper: mockAppRoot().withPermission('access-permissions').withPermission('can-audit').build(),
});

const menuButton = await screen.findByRole('button', { name: 'Manage' });
await userEvent.click(menuButton);

expect(screen.queryByRole('menuitem', { name: 'Messages' })).not.toBeInTheDocument();
});

it('should display audit items if has at least one admin permission, both audit permission and the auditing module is enabled', async () => {
render(<NavBarItemAdministrationMenu />, {
wrapper: mockAppRoot()
.withEndpoint('GET', '/v1/licenses.info', () => ({
license: {
license: {
// @ts-expect-error: just for testing
grantedModules: [{ module: 'auditing' }],
},
// @ts-expect-error: just for testing
activeModules: ['auditing'],
},
}))
.withJohnDoe()
.withPermission('can-audit')
.withPermission('can-audit-log')
.build(),
});

const menuButton = await screen.findByRole('button', { name: 'Manage' });
await userEvent.click(menuButton);

await waitFor(() => {
expect(screen.getByText('Messages')).toBeInTheDocument();
});

expect(await screen.findByRole('menuitem', { name: 'Messages' })).toBeInTheDocument();
expect(await screen.findByRole('menuitem', { name: 'Logs' })).toBeInTheDocument();
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,28 @@ import type { HTMLAttributes } from 'react';
import { useTranslation } from 'react-i18next';

import { useAdministrationMenu } from './hooks/useAdministrationMenu';
import { useAuditMenu } from './hooks/useAuditMenu';

type NavBarItemAdministrationMenuProps = Omit<HTMLAttributes<HTMLElement>, 'is'>;

const NavBarItemAdministrationMenu = (props: NavBarItemAdministrationMenuProps) => {
const { t } = useTranslation();
const currentRoute = useCurrentRoutePath();

const sections = useAdministrationMenu();
const adminSection = useAdministrationMenu();
const auditSection = useAuditMenu();

if (!sections[0].items.length) {
const adminRoutesRegex = new RegExp(['/omnichannel/', '/admin', '/audit'].join('|'));
const pressed = adminRoutesRegex.test(currentRoute || '');

const sections = [adminSection, auditSection].filter((section) => section.items.length > 0);

if (sections.length === 0) {
return null;
}

return (
<GenericMenu
sections={sections}
title={t('Manage')}
is={NavBarItem}
icon='cog'
pressed={currentRoute?.includes('/omnichannel/') || currentRoute?.includes('/admin')}
placement='bottom-end'
{...props}
/>
<GenericMenu sections={sections} title={t('Manage')} is={NavBarItem} icon='cog' pressed={pressed} placement='bottom-end' {...props} />
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,12 @@ import { useTranslation } from 'react-i18next';
import UserMenuHeader from '../UserMenuHeader';
import { useAccountItems } from './useAccountItems';
import { useStatusItems } from './useStatusItems';
import { useVoipItemsSection } from './useVoipItemsSection';

export const useUserMenu = (user: IUser) => {
const { t } = useTranslation();

const statusItems = useStatusItems();
const accountItems = useAccountItems();
const voipSection = useVoipItemsSection();

const logout = useLogout();
const handleLogout = useEffectEvent(() => {
Expand All @@ -37,7 +35,6 @@ export const useUserMenu = (user: IUser) => {
title: t('Status'),
items: statusItems,
},
voipSection,
{
title: t('Account'),
items: accountItems,
Expand Down
Loading
Loading