Skip to content

Commit

Permalink
[NEW] Create releases tab in the marketplace app info page (#25965)
Browse files Browse the repository at this point in the history
  • Loading branch information
rique223 authored Jun 29, 2022
1 parent 80ae54e commit 8486202
Show file tree
Hide file tree
Showing 14 changed files with 209 additions and 58 deletions.
32 changes: 32 additions & 0 deletions apps/meteor/app/apps/server/communication/rest.js
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,38 @@ export class AppsRestApi {
},
);

this.api.addRoute(
':id/versions',
{ authRequired: true, permissionsRequired: ['manage-apps'] },
{
get() {
const baseUrl = orchestrator.getMarketplaceUrl();

const headers = {}; // DO NOT ATTACH THE FRAMEWORK/ENGINE VERSION HERE.
const token = getWorkspaceAccessToken();
if (token) {
headers.Authorization = `Bearer ${token}`;
}

let result;
try {
result = HTTP.get(`${baseUrl}/v1/apps/${this.urlParams.id}`, {
headers,
});
} catch (e) {
return handleError('Unable to access Marketplace. Does the server has access to the internet?', e);
}

if (!result || result.statusCode !== 200) {
orchestrator.getRocketChatLogger().error('Error getting the App versions from the Marketplace:', result.data);
return API.v1.failure();
}

return API.v1.success({ apps: result.data });
},
},
);

this.api.addRoute(
':id/sync',
{ authRequired: true, permissionsRequired: ['manage-apps'] },
Expand Down
3 changes: 1 addition & 2 deletions apps/meteor/client/views/admin/apps/APIsDisplay.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { IApiEndpointMetadata } from '@rocket.chat/apps-engine/definition/api';
import { Box, Divider } from '@rocket.chat/fuselage';
import { Box } from '@rocket.chat/fuselage';
import { useAbsoluteUrl, useTranslation } from '@rocket.chat/ui-contexts';
import React, { FC, Fragment } from 'react';

Expand All @@ -16,7 +16,6 @@ const APIsDisplay: FC<APIsDisplayProps> = ({ apis }) => {

return (
<>
<Divider />
<Box display='flex' flexDirection='column'>
<Box fontScale='h4' mb='x12'>
{t('APIs')}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Box, Skeleton, Margins } from '@rocket.chat/fuselage';
import React, { FC } from 'react';

const LogsLoading: FC = () => (
const AccordionLoading: FC = () => (
<Box w='full' alignSelf='center'>
<Margins block='x2'>
<Skeleton variant='rect' width='100%' height='x80' />
Expand All @@ -11,4 +11,4 @@ const LogsLoading: FC = () => (
</Box>
);

export default LogsLoading;
export default AccordionLoading;
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,22 @@ import { ExternalLink } from '@rocket.chat/ui-client';
import { TranslationKey, useTranslation } from '@rocket.chat/ui-contexts';
import React, { FC } from 'react';

import APIsDisplay from './APIsDisplay';
import ScreenshotCarouselAnchor from './components/ScreenshotCarouselAnchor';
import { AppInfo } from './definitions/AppInfo';

type AppDetailsPageContentProps = {
type AppDetailsProps = {
app: AppInfo;
};

const AppDetailsPageContent: FC<AppDetailsPageContentProps> = ({ app }) => {
const AppDetails: FC<AppDetailsProps> = ({ app }) => {
const {
author: { homepage, support },
detailedDescription,
description,
categories = [],
screenshots,
apis,
} = app;

const t = useTranslation();
Expand Down Expand Up @@ -90,10 +92,12 @@ const AppDetailsPageContent: FC<AppDetailsPageContentProps> = ({ app }) => {
</Box>
</Box>
</Box>

<Box is='section'>{apis?.length && <APIsDisplay apis={apis || []} />}</Box>
</Margins>
</Box>
</Box>
);
};

export default AppDetailsPageContent;
export default AppDetails;
4 changes: 2 additions & 2 deletions apps/meteor/client/views/admin/apps/AppDetailsHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Box } from '@rocket.chat/fuselage';
import { useTranslation } from '@rocket.chat/ui-contexts';
import { formatDistanceStrict } from 'date-fns';
import moment from 'moment';
import React, { ReactElement } from 'react';

import AppAvatar from '../../../components/avatar/AppAvatar';
Expand All @@ -12,7 +12,7 @@ import { App } from './types';
const AppDetailsHeader = ({ app }: { app: App }): ReactElement => {
const t = useTranslation();
const { iconFileData, name, author, version, iconFileContent, installed, isSubscribed, modifiedAt, bundledIn, description } = app;
const lastUpdated = modifiedAt && formatDistanceStrict(new Date(modifiedAt), new Date(), { addSuffix: false });
const lastUpdated = modifiedAt && moment(modifiedAt).fromNow();

return (
<Box display='flex' flexDirection='row' mbe='x20' w='full'>
Expand Down
45 changes: 30 additions & 15 deletions apps/meteor/client/views/admin/apps/AppDetailsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import React, { useState, useCallback, useRef, FC } from 'react';
import { ISettings } from '../../../../app/apps/client/@types/IOrchestrator';
import { Apps } from '../../../../app/apps/client/orchestrator';
import Page from '../../../components/Page';
import APIsDisplay from './APIsDisplay';
import AppDetails from './AppDetails';
import AppDetailsHeader from './AppDetailsHeader';
import AppDetailsPageContent from './AppDetailsPageContent';
import AppLogsPage from './AppLogsPage';
import AppSecurityPage from './AppSecurityPage';
import AppLogs from './AppLogs';
import AppReleases from './AppReleases';
import AppSecurity from './AppSecurity';
import LoadingDetails from './LoadingDetails';
import SettingsDisplay from './SettingsDisplay';
import { handleAPIError } from './helpers';
Expand All @@ -26,8 +26,9 @@ const AppDetailsPage: FC<{ id: string }> = function AppDetailsPage({ id }) {
const settingsRef = useRef<Record<string, ISetting['value']>>({});
const appData = useAppInfo(id);

const [, urlParams] = useCurrentRoute();
const [routeName, urlParams] = useCurrentRoute();
const appsRoute = useRoute('admin-apps');
const marketplaceRoute = useRoute('admin-marketplace');
const tab = useRouteParameter('tab');

const [currentRouteName] = useCurrentRoute();
Expand All @@ -38,8 +39,7 @@ const AppDetailsPage: FC<{ id: string }> = function AppDetailsPage({ id }) {
const router = useRoute(currentRouteName);
const handleReturn = useMutableCallback((): void => router.push({}));

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

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

const handleTabClick = (tab: 'details' | 'security' | 'logs' | 'settings'): void => {
appsRoute.replace({ ...urlParams, tab });
const handleTabClick = (tab: 'details' | 'security' | 'releases' | 'settings' | 'logs'): void => {
if (routeName === 'admin-marketplace') {
marketplaceRoute.replace({ ...urlParams, tab });
}

if (routeName === 'admin-apps') {
appsRoute.replace({ ...urlParams, tab });
}
};

return (
Expand Down Expand Up @@ -89,35 +95,44 @@ const AppDetailsPage: FC<{ id: string }> = function AppDetailsPage({ id }) {
</Tabs.Item>
)}
{Boolean(installed) && (
<Tabs.Item onClick={(): void => handleTabClick('logs')} selected={tab === 'logs'}>
{t('Logs')}
<Tabs.Item onClick={(): void => handleTabClick('releases')} selected={tab === 'releases'}>
{t('Releases')}
</Tabs.Item>
)}
{Boolean(installed && settings && Object.values(settings).length) && (
<Tabs.Item onClick={(): void => handleTabClick('settings')} selected={tab === 'settings'}>
{t('Settings')}
</Tabs.Item>
)}
{Boolean(installed) && (
<Tabs.Item onClick={(): void => handleTabClick('logs')} selected={tab === 'logs'}>
{t('Logs')}
</Tabs.Item>
)}
</Tabs>

{Boolean(!tab || tab === 'details') && <AppDetailsPageContent app={appData} />}
{Boolean((!tab || tab === 'details') && !!showApis) && <APIsDisplay apis={apis || []} />}
{Boolean(!tab || tab === 'details') && <AppDetails app={appData} />}

{tab === 'security' && (
<AppSecurityPage
<AppSecurity
privacyPolicySummary={privacyPolicySummary}
appPermissions={permissions}
tosLink={tosLink}
privacyLink={privacyLink}
/>
)}
{tab === 'logs' && <AppLogsPage id={id} />}

{tab === 'releases' && <AppReleases id={id} />}

{Boolean(tab === 'settings' && settings && Object.values(settings).length) && (
<SettingsDisplay
settings={settings || ({} as ISettings)}
setHasUnsavedChanges={setHasUnsavedChanges}
settingsRef={settingsRef}
/>
)}

{tab === 'logs' && <AppLogs id={id} />}
</>
)}
</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ import { useSafely } from '@rocket.chat/fuselage-hooks';
import { useEndpoint } from '@rocket.chat/ui-contexts';
import React, { useCallback, useState, useEffect } from 'react';

import Page from '../../../components/Page';
import { useFormatDateAndTime } from '../../../hooks/useFormatDateAndTime';
import AccordionLoading from './AccordionLoading';
import LogItem from './LogItem';
import LogsLoading from './LogsLoading';

const useAppWithLogs = ({ id }) => {
const [data, setData] = useSafely(useState({}));
Expand All @@ -32,7 +31,7 @@ const useAppWithLogs = ({ id }) => {
return [filteredData, total, fetchData];
};

function AppLogsPage({ id, ...props }) {
function AppLogs({ id }) {
const formatDateAndTime = useFormatDateAndTime();

const [app] = useAppWithLogs({ id });
Expand All @@ -41,32 +40,28 @@ function AppLogsPage({ id, ...props }) {
const showData = !loading && !app.error;

return (
<Page flexDirection='column' {...props}>
<Page.ScrollableContent>
{loading && <LogsLoading />}
{app.error && (
<Box maxWidth='x600' alignSelf='center' fontScale='hh21'>
{app.error.message}
</Box>
)}
{showData && (
<>
<Accordion width='100%' alignSelf='center'>
{app.logs &&
app.logs.map((log) => (
<LogItem
key={log._createdAt}
title={`${formatDateAndTime(log._createdAt)}: "${log.method}" (${log.totalTime}ms)`}
instanceId={log.instanceId}
entries={log.entries}
/>
))}
</Accordion>
</>
)}
</Page.ScrollableContent>
</Page>
<>
{loading && <AccordionLoading />}
{app.error && (
<Box maxWidth='x600' alignSelf='center' fontScale='hh21'>
{app.error.message}
</Box>
)}
{showData && (
<Accordion width='100%' alignSelf='center'>
{app.logs &&
app.logs.map((log) => (
<LogItem
key={log._createdAt}
title={`${formatDateAndTime(log._createdAt)}: "${log.method}" (${log.totalTime}ms)`}
instanceId={log.instanceId}
entries={log.entries}
/>
))}
</Accordion>
)}
</>
);
}

export default AppLogsPage;
export default AppLogs;
52 changes: 52 additions & 0 deletions apps/meteor/client/views/admin/apps/AppReleases.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Accordion } from '@rocket.chat/fuselage';
import React, { useEffect, useState } from 'react';

import { useEndpointData } from '../../../hooks/useEndpointData';
import { AsyncStatePhase } from '../../../lib/asyncState/AsyncStatePhase';
import AccordionLoading from './AccordionLoading';
import ReleaseItem from './ReleaseItem';

type release = {
version: string;
createdDate: string;
detailedChangelog: {
raw: string;
rendered: string;
};
};

const AppReleases = ({ id }: { id: string }): JSX.Element => {
const { value, phase, error } = useEndpointData(`/apps/${id}/versions`);

const [releases, setReleases] = useState([] as release[]);

const isLoading = phase === AsyncStatePhase.LOADING;
const isSuccess = phase === AsyncStatePhase.RESOLVED;
const didFail = phase === AsyncStatePhase.REJECTED || error;

useEffect(() => {
if (isSuccess && value?.apps) {
const { apps } = value;

setReleases(
apps.map((app) => ({
version: app.version,
createdDate: app.createdDate,
detailedChangelog: app.detailedChangelog,
})),
);
}
}, [isSuccess, value]);

return (
<>
<Accordion width='100%' alignSelf='center'>
{didFail && error}
{isLoading && <AccordionLoading />}
{isSuccess && releases.length && releases.map((release) => <ReleaseItem release={release} key={release.version} />)}
</Accordion>
</>
);
};

export default AppReleases;
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import { Box, Margins } from '@rocket.chat/fuselage';
import { TranslationKey, useTranslation } from '@rocket.chat/ui-contexts';
import React, { FC } from 'react';

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

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

const defaultPermissions = [
Expand Down Expand Up @@ -89,4 +89,4 @@ const AppSecurityPage: FC<AppSecurityPageProps> = ({ privacyPolicySummary, appPe
);
};

export default AppSecurityPage;
export default AppSecurity;
Loading

0 comments on commit 8486202

Please sign in to comment.