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
18 changes: 16 additions & 2 deletions apps/meteor/client/views/admin/apps/AppDetailsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import APIsDisplay from './APIsDisplay';
import AppDetailsHeader from './AppDetailsHeader';
import AppDetailsPageContent from './AppDetailsPageContent';
import AppLogsPage from './AppLogsPage';
import AppSecurityPage from './AppSecurityPage';
import LoadingDetails from './LoadingDetails';
import SettingsDisplay from './SettingsDisplay';
import { handleAPIError } from './helpers';
Expand All @@ -37,7 +38,7 @@ const AppDetailsPage: FC<{ id: string }> = function AppDetailsPage({ id }) {
const router = useRoute(currentRouteName);
const handleReturn = useMutableCallback((): void => router.push({}));

const { installed, settings, apis } = appData || {};
const { installed, settings, apis, privacyPolicySummary, permissions, tosLink, privacyLink } = appData || {};
const showApis = apis?.length;

const saveAppSettings = useCallback(async () => {
Expand All @@ -57,7 +58,7 @@ const AppDetailsPage: FC<{ id: string }> = function AppDetailsPage({ id }) {
setIsSaving(false);
}, [id, settings]);

const handleTabClick = (tab: 'details' | 'logs' | 'settings'): void => {
const handleTabClick = (tab: 'details' | 'security' | 'logs' | 'settings'): void => {
appsRoute.replace({ ...urlParams, tab });
};

Expand All @@ -82,6 +83,11 @@ const AppDetailsPage: FC<{ id: string }> = function AppDetailsPage({ id }) {
<Tabs.Item onClick={(): void => handleTabClick('details')} selected={!tab || tab === 'details'}>
{t('Details')}
</Tabs.Item>
{Boolean(installed) && (
<Tabs.Item onClick={(): void => handleTabClick('security')} selected={tab === 'security'}>
{t('Security')}
</Tabs.Item>
)}
{Boolean(installed) && (
<Tabs.Item onClick={(): void => handleTabClick('logs')} selected={tab === 'logs'}>
{t('Logs')}
Expand All @@ -96,6 +102,14 @@ const AppDetailsPage: FC<{ id: string }> = function AppDetailsPage({ id }) {

{Boolean(!tab || tab === 'details') && <AppDetailsPageContent app={appData} />}
{Boolean((!tab || tab === 'details') && !!showApis) && <APIsDisplay apis={apis || []} />}
{tab === 'security' && (
<AppSecurityPage
privacyPolicySummary={privacyPolicySummary}
appPermissions={permissions}
tosLink={tosLink}
privacyLink={privacyLink}
/>
)}
{tab === 'logs' && <AppLogsPage id={id} />}
{Boolean(tab === 'settings' && settings && Object.values(settings).length) && (
<SettingsDisplay
Expand Down
92 changes: 92 additions & 0 deletions apps/meteor/client/views/admin/apps/AppSecurityPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { AppPermission } from '@rocket.chat/core-typings';
import { Box, Margins } from '@rocket.chat/fuselage';
import { TranslationKey, useTranslation } from '@rocket.chat/ui-contexts';
import React, { FC } from 'react';

type AppSecurityPageProps = {
privacyPolicySummary: string | undefined;
appPermissions: AppPermission[] | undefined;
tosLink: string | undefined;
privacyLink: string | undefined;
};

const AppSecurityPage: FC<AppSecurityPageProps> = ({ privacyPolicySummary, appPermissions, tosLink, privacyLink }) => {
const t = useTranslation();

const defaultPermissions = [
'user.read',
'user.write',
'upload.read',
'upload.write',
'ui.interact',
'server-setting.read',
'server-setting.write',
'room.read',
'room.write',
'message.read',
'message.write',
'livechat-department.read',
'livechat-department.write',
'livechat-room.read',
'livechat-room.write',
'livechat-message.read',
'livechat-message.write',
'livechat-visitor.read',
'livechat-visitor.write',
'livechat-status.read',
'livechat-custom-fields.write',
'scheduler',
'networking',
'persistence',
'env.read',
'slashcommand',
'api',
];

const handleHumanizePermissionName = (permission: string): string =>
t(`Apps_Permissions_${permission.replace('.', '_')}` as TranslationKey);

return (
<Box maxWidth='x640' w='full' marginInline='auto'>
<Box display='flex' flexDirection='column'>
<Margins block='x17'>
<Box is='section'>
<Box fontScale='h4' mbe='x8'>
{t('Privacy_summary')}
</Box>
<Box is='p' lineHeight='x20'>
{privacyPolicySummary?.length && privacyPolicySummary}
</Box>
</Box>

<Box is='section'>
<Box fontScale='h4' mbe='x8'>
{t('Permissions')}
</Box>
<Box is='ol' type='1' style={{ listStyleType: 'decimal' }} mis='x24'>
{appPermissions?.length
? appPermissions.map((permission) => <li key={permission.name}>{handleHumanizePermissionName(permission.name)}</li>)
: defaultPermissions.map((permission) => <li key={permission}>{handleHumanizePermissionName(permission)}</li>)}
</Box>
</Box>

<Box is='section'>
<Box fontScale='h4' mbe='x8'>
{t('Policies')}
</Box>
<Box display='flex' flexDirection='column'>
<Box is='a' href={tosLink}>
Terms of use
</Box>
<Box is='a' href={privacyLink}>
Privacy policy
</Box>
</Box>
</Box>
</Margins>
</Box>
</Box>
);
};

export default AppSecurityPage;
6 changes: 4 additions & 2 deletions apps/meteor/client/views/admin/apps/AppStatus.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ const AppStatus = ({ app, showStatus = true, isAppDetailsPage, installed = false
color: status.label === 'Disabled' ? colors.y800 : 'primary-500',
};

const shouldShowPriceDisplay = isAppDetailsPage && button && button.action !== 'update';

return (
<Box {...props}>
{button && (
Expand All @@ -128,12 +130,12 @@ const AppStatus = ({ app, showStatus = true, isAppDetailsPage, installed = false
<Throbber inheritColor />
) : (
<>
{button.icon && <Icon name={button.icon} />}
{button.icon && <Icon name={button.icon} mie='x8' />}
{t(button.label)}
</>
)}
</Button>
{isAppDetailsPage && (
{shouldShowPriceDisplay && (
<Box pi='x14' color='primary-500'>
{!installed && (
<PriceDisplay purchaseType={purchaseType} pricingPlans={pricingPlans} price={price} showType={false} marginInline='x8' />
Expand Down
32 changes: 18 additions & 14 deletions apps/meteor/client/views/admin/apps/hooks/useAppInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,24 +47,13 @@ export const useAppInfo = (appId: string): AppInfo | undefined => {
return;
}

const app = apps.find((app) => app.id === appId) ?? {
const appResult = apps.find((app) => app.id === appId) ?? {
...(await Apps.getApp(appId)),
installed: true,
marketplace: false,
};

const [bundledIn, settings, apis, screenshots] = await Promise.all([
app.marketplace === false
? []
: getBundledIn({
marketplace: 'true',
update: 'true',
appVersion: appId,
})
.then(({ app }) => getBundledInApp(app))
.catch(() => ({
settings: {},
})),
const [settings, apis, screenshots, bundledIn] = await Promise.all([
getSettings().catch(() => ({
settings: {},
})),
Expand All @@ -74,10 +63,25 @@ export const useAppInfo = (appId: string): AppInfo | undefined => {
getScreenshots().catch(() => ({
screenshots: [],
})),
appResult.marketplace === false
? []
: getBundledIn({
marketplace: 'true',
update: 'true',
appVersion: appId,
})
.then(({ app }) => {
appResult.tosLink = app.tosLink;
appResult.privacyLink = app.privacyLink;
return getBundledInApp(app);
})
.catch(() => ({
settings: {},
})),
]);

setAppData({
...app,
...appResult,
bundledIn: bundledIn as App['bundledIn'],
settings: settings.settings as ISettings,
apis: apis ? apis.apis : [],
Expand Down
2 changes: 2 additions & 0 deletions apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -3499,6 +3499,7 @@
"Please_wait_while_OTR_is_being_established": "Please wait while OTR is being established",
"Please_wait_while_your_account_is_being_deleted": "Please wait while your account is being deleted...",
"Please_wait_while_your_profile_is_being_saved": "Please wait while your profile is being saved...",
"Policies": "Policies",
"Pool": "Pool",
"Port": "Port",
"Post_as": "Post as",
Expand All @@ -3525,6 +3526,7 @@
"Priority_removed": "Priority removed",
"Privacy": "Privacy",
"Privacy_Policy": "Privacy Policy",
"Privacy_summary": "Privacy summary",
"Private": "Private",
"Private_Channel": "Private Channel",
"Private_Channels": "Private Channels",
Expand Down
9 changes: 8 additions & 1 deletion packages/core-typings/src/Apps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ export type AppSubscriptionInfo = {
isSubscribedViaBundle: boolean;
};

export type AppPermission = {
name: string;
};

export type App = {
id: string;
iconFileData: string;
Expand All @@ -65,6 +69,7 @@ export type App = {
support: string;
};
description: string;
privacyPolicySummary: string;
detailedDescription: {
raw: string;
rendered: string;
Expand Down Expand Up @@ -97,8 +102,10 @@ export type App = {
errors: { [key: string]: string };
warnings: { [key: string]: string };
};
tosLink: string;
privacyLink: string;
marketplace: unknown;
modifiedAt: string;
permissions: unknown[];
permissions: AppPermission[];
languages: string[];
};