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
2 changes: 1 addition & 1 deletion apps/meteor/app/livechat/client/ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Tracker.autorun((c) => {
});

AccountBox.addItem({
name: 'Omnichannel',
name: 'Manage_Omnichannel',
icon: 'headset',
href: '/omnichannel/current',
sideNav: 'omnichannelFlex',
Expand Down
9 changes: 6 additions & 3 deletions apps/meteor/app/ui-utils/client/lib/AccountBox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import type { IUIActionButton, IUActionButtonWhen } from '@rocket.chat/apps-engi
import type { UserStatus } from '@rocket.chat/core-typings';
import { ReactiveVar } from 'meteor/reactive-var';
import { Tracker } from 'meteor/tracker';
import type { TranslationKey } from '@rocket.chat/ui-contexts';
import type { Icon } from '@rocket.chat/fuselage';
import type { ComponentProps } from 'react';

import { SideNav } from './SideNav';
import { applyDropdownActionButtonFilters } from '../../../ui-message/client/actionButtons/lib/applyButtonFilters';
Expand All @@ -17,9 +20,9 @@ export interface IAppAccountBoxItem extends IUIActionButton {
when?: Omit<IUActionButtonWhen, 'roomTypes' | 'messageActionContext'>;
}

type AccountBoxItem = {
name: string;
icon: string;
export type AccountBoxItem = {
name: TranslationKey;
icon: ComponentProps<typeof Icon>['name'];
href: string;
sideNav?: string;
condition: () => boolean;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { OptionDivider } from '@rocket.chat/fuselage';
import React, { FC, Fragment } from 'react';

import { AccountBoxItem, IAppAccountBoxItem, isAppAccountBoxItem } from '../../../app/ui-utils/client/lib/AccountBox';
import AdministrationModelList from './AdministrationModelList';
import AppsModelList from './AppsModelList';
import AuditModelList from './AuditModelList';
import SettingsModelList from './SettingsModelList';

type AdministrationListProps = {
accountBoxItems: (IAppAccountBoxItem | AccountBoxItem)[];
closeList: () => void;
hasAdminPermission: boolean;
hasAuditLicense: boolean;
hasAuditPermission: boolean;
hasAuditLogPermission: boolean;
hasManageApps: boolean;
hasSettingsPermission: boolean;
};

const AdministrationList: FC<AdministrationListProps> = ({
accountBoxItems,
hasAuditPermission,
hasAuditLogPermission,
hasManageApps,
hasSettingsPermission,
hasAdminPermission,
closeList,
}) => {
const appBoxItems = accountBoxItems.filter((item): item is IAppAccountBoxItem => isAppAccountBoxItem(item));
const adminBoxItems = accountBoxItems.filter((item): item is AccountBoxItem => !isAppAccountBoxItem(item));
const showAudit = hasAuditPermission || hasAuditLogPermission;
const showManageApps = hasManageApps || !!appBoxItems.length;
const showAdmin = hasAdminPermission || !!adminBoxItems.length;
const showSettings = hasSettingsPermission;

const list = [
showAdmin && <AdministrationModelList showAdmin={showAdmin} accountBoxItems={adminBoxItems} closeList={closeList} />,
showSettings && <SettingsModelList closeList={closeList} />,
showManageApps && <AppsModelList appBoxItems={appBoxItems} closeList={closeList} showManageApps={showManageApps} />,
showAudit && <AuditModelList showAudit={hasAuditPermission} showAuditLog={hasAuditLogPermission} closeList={closeList} />,
];

return (
<>
{list.filter(Boolean).map((item, index) => (
<Fragment key={index}>
{index > 0 && <OptionDivider />}
{item}
</Fragment>
))}
</>
);
};

export default AdministrationList;
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { OptionTitle } from '@rocket.chat/fuselage';
import { useTranslation, useRoute } from '@rocket.chat/ui-contexts';
import { FlowRouter } from 'meteor/kadira:flow-router';
import React, { FC } from 'react';

import { userHasAllPermission } from '../../../app/authorization/client';
import { SideNav } from '../../../app/ui-utils/client';
import { AccountBoxItem } from '../../../app/ui-utils/client/lib/AccountBox';
import { getUpgradeTabLabel, isFullyFeature } from '../../../lib/upgradeTab';
import { useUpgradeTabParams } from '../../views/hooks/useUpgradeTabParams';
import Emoji from '../Emoji';
import ListItem from '../Sidebar/ListItem';

type AdministrationModelListProps = {
accountBoxItems: AccountBoxItem[];
showAdmin: boolean;
closeList: () => void;
};

const INFO_PERMISSIONS = ['view-statistics'];

const AdministrationModelList: FC<AdministrationModelListProps> = ({ accountBoxItems, showAdmin, closeList }) => {
const t = useTranslation();
const { tabType, trialEndDate, isLoading } = useUpgradeTabParams();
const shouldShowEmoji = isFullyFeature(tabType);
const label = getUpgradeTabLabel(tabType);
const hasInfoPermission = userHasAllPermission(INFO_PERMISSIONS);

const infoRoute = useRoute('admin-info');
const adminRoute = useRoute('admin-index');
const upgradeRoute = useRoute('upgrade');
const showUpgradeItem = !isLoading && tabType;

return (
<>
<OptionTitle>{t('Administration')}</OptionTitle>
<ul>
{showAdmin && (
<>
{showUpgradeItem && (
<ListItem
icon='arrow-stack-up'
text={
<>
{t(label)} {shouldShowEmoji && <Emoji emojiHandle=':zap:' />}
</>
}
action={(): void => {
upgradeRoute.push({ type: tabType }, trialEndDate ? { trialEndDate } : undefined);
closeList();
}}
/>
)}
<ListItem
icon='cog'
text={t('Manage_workspace')}
action={(): void => {
if (hasInfoPermission) {
infoRoute.push();
closeList();
return;
}

adminRoute.push({ context: '/' });
closeList();
}}
/>
</>
)}
{accountBoxItems.length > 0 && (
<>
{accountBoxItems.map((item, key) => {
const action = (): void => {
if (item.href) {
FlowRouter.go(item.href);
}
if (item.sideNav) {
SideNav.setFlex(item.sideNav);
SideNav.openFlex();
}
closeList();
};

return <ListItem text={t(item.name)} icon={item.icon} action={action} key={item.name + key} />;
})}
</>
)}
</ul>
</>
);
};

export default AdministrationModelList;
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { OptionTitle } from '@rocket.chat/fuselage';
import { useTranslation, useRoute } from '@rocket.chat/ui-contexts';
import React, { FC } from 'react';

import { triggerActionButtonAction } from '../../../app/ui-message/client/ActionManager';
import { IAppAccountBoxItem } from '../../../app/ui-utils/client/lib/AccountBox';
import ListItem from '../Sidebar/ListItem';

type AppsModelListProps = {
appBoxItems: IAppAccountBoxItem[];
showManageApps: boolean;
closeList: () => void;
};

const AppsModelList: FC<AppsModelListProps> = ({ appBoxItems, showManageApps, closeList }) => {
const t = useTranslation();
const marketplaceRoute = useRoute('admin-marketplace');

return (
<>
<OptionTitle>{t('Apps')}</OptionTitle>
<ul>
{showManageApps && (
<>
<ListItem
icon='cube'
text={t('Marketplace')}
action={(): void => {
marketplaceRoute.push();
closeList();
}}
/>
<ListItem
icon='cube'
text={t('Installed')}
action={(): void => {
marketplaceRoute.push({ context: 'installed' });
closeList();
}}
/>
</>
)}
{appBoxItems.length > 0 && (
<>
{appBoxItems.map((item, key) => {
const action = (): void => {
triggerActionButtonAction({
rid: '',
mid: '',
actionId: item.actionId,
appId: item.appId,
payload: { context: item.context },
});
closeList();
};
return <ListItem text={(t.has(item.name) && t(item.name)) || item.name} action={action} key={item.actionId + key} />;
})}
</>
)}
</ul>
</>
);
};

export default AppsModelList;
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { OptionTitle } from '@rocket.chat/fuselage';
import { useRoute, useTranslation } from '@rocket.chat/ui-contexts';
import React, { FC } from 'react';

import ListItem from '../Sidebar/ListItem';

type AuditModelListProps = {
closeList: () => void;
showAudit: boolean;
showAuditLog: boolean;
};

const AuditModelList: FC<AuditModelListProps> = ({ showAudit, showAuditLog, closeList }) => {
const t = useTranslation();

const auditHomeRoute = useRoute('audit-home');
const auditSettingsRoute = useRoute('audit-log');

return (
<>
<OptionTitle>{t('Audit')}</OptionTitle>
<ul>
{showAudit && (
<ListItem
icon='document-eye'
text={t('Messages')}
action={(): void => {
auditHomeRoute.push();
closeList();
}}
/>
)}
{showAuditLog && (
<ListItem
icon='document-eye'
text={t('Logs')}
action={(): void => {
auditSettingsRoute.push();
closeList();
}}
/>
)}
</ul>
</>
);
};

export default AuditModelList;
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { OptionTitle } from '@rocket.chat/fuselage';
import { useTranslation, useRoute } from '@rocket.chat/ui-contexts';
import React, { FC } from 'react';

import ListItem from '../Sidebar/ListItem';

type SettingsModelListProps = {
closeList: () => void;
};

const SettingsModelList: FC<SettingsModelListProps> = ({ closeList }) => {
const t = useTranslation();
const settingsRoute = useRoute('admin-settings');

return (
<>
<OptionTitle>{t('Settings')}</OptionTitle>
<ul>
<ListItem
icon='customize'
text={t('Workspace_settings')}
action={(): void => {
settingsRoute.push();
closeList();
}}
/>
</ul>
</>
);
};

export default SettingsModelList;
4 changes: 2 additions & 2 deletions apps/meteor/client/components/Sidebar/ListItem.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Option, OptionColumn, OptionContent, OptionIcon } from '@rocket.chat/fuselage';
import React, { ComponentProps, MouseEventHandler, ReactElement } from 'react';
import React, { ComponentProps, MouseEventHandler, ReactElement, ReactNode } from 'react';

type ListItemProps = {
text: string;
text: ReactNode;
icon?: ComponentProps<typeof OptionIcon>['name'];
input?: any;
action?: MouseEventHandler<HTMLOrSVGElement>;
Expand Down
Loading