diff --git a/apps/meteor/client/views/admin/apps/WarningModal.tsx b/apps/meteor/client/components/WarningModal.tsx similarity index 100% rename from apps/meteor/client/views/admin/apps/WarningModal.tsx rename to apps/meteor/client/components/WarningModal.tsx diff --git a/apps/meteor/client/sidebar/RoomMenu.tsx b/apps/meteor/client/sidebar/RoomMenu.tsx index bbcf5532c4e81..5b213c118f8ba 100644 --- a/apps/meteor/client/sidebar/RoomMenu.tsx +++ b/apps/meteor/client/sidebar/RoomMenu.tsx @@ -19,9 +19,9 @@ import React, { memo, ReactElement, useMemo } from 'react'; import { RoomManager } from '../../app/ui-utils/client'; import { UiTextContext } from '../../definition/IRoomTypeConfig'; import { GenericModalDoNotAskAgain } from '../components/GenericModal'; +import WarningModal from '../components/WarningModal'; import { useDontAskAgain } from '../hooks/useDontAskAgain'; import { roomCoordinator } from '../lib/rooms/roomCoordinator'; -import WarningModal from '../views/admin/apps/WarningModal'; const fields: Fields = { f: true, diff --git a/apps/meteor/client/views/admin/apps/AppDetailsPage.tsx b/apps/meteor/client/views/admin/apps/AppDetailsPage/AppDetailsPage.tsx similarity index 81% rename from apps/meteor/client/views/admin/apps/AppDetailsPage.tsx rename to apps/meteor/client/views/admin/apps/AppDetailsPage/AppDetailsPage.tsx index 1eee7d1993467..84f3ead9d1655 100644 --- a/apps/meteor/client/views/admin/apps/AppDetailsPage.tsx +++ b/apps/meteor/client/views/admin/apps/AppDetailsPage/AppDetailsPage.tsx @@ -1,23 +1,24 @@ import { ISetting } from '@rocket.chat/apps-engine/definition/settings'; +import { App } from '@rocket.chat/core-typings'; import { Button, ButtonGroup, Box, Throbber, Tabs } from '@rocket.chat/fuselage'; import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; import { useTranslation, useCurrentRoute, useRoute, useRouteParameter } from '@rocket.chat/ui-contexts'; -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 AppDetails from './AppDetails'; -import AppDetailsHeader from './AppDetailsHeader'; -import AppLogs from './AppLogs'; -import AppReleases from './AppReleases'; -import AppSecurity from './AppSecurity'; -import LoadingDetails from './LoadingDetails'; -import SettingsDisplay from './SettingsDisplay'; -import { handleAPIError } from './helpers'; -import { useAppInfo } from './hooks/useAppInfo'; - -const AppDetailsPage: FC<{ id: string }> = function AppDetailsPage({ id }) { +import React, { useState, useCallback, useRef, ReactElement } from 'react'; + +import { ISettings } from '../../../../../app/apps/client/@types/IOrchestrator'; +import { Apps } from '../../../../../app/apps/client/orchestrator'; +import Page from '../../../../components/Page'; +import { handleAPIError } from '../helpers'; +import { useAppInfo } from '../hooks/useAppInfo'; +import AppDetailsPageHeader from './AppDetailsPageHeader'; +import AppDetailsPageLoading from './AppDetailsPageLoading'; +import AppDetails from './tabs/AppDetails'; +import AppLogs from './tabs/AppLogs'; +import AppReleases from './tabs/AppReleases'; +import AppSecurity from './tabs/AppSecurity'; +import AppSettings from './tabs/AppSettings'; + +const AppDetailsPage = ({ id }: { id: App['id'] }): ReactElement => { const t = useTranslation(); const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false); @@ -81,11 +82,10 @@ const AppDetailsPage: FC<{ id: string }> = function AppDetailsPage({ id }) { - {!appData && } + {!appData && } {appData && ( <> - - + handleTabClick('details')} selected={!tab || tab === 'details'}> {t('Details')} @@ -111,9 +111,7 @@ const AppDetailsPage: FC<{ id: string }> = function AppDetailsPage({ id }) { )} - {Boolean(!tab || tab === 'details') && } - {tab === 'security' && isSecurityVisible && ( = function AppDetailsPage({ id }) { privacyLink={privacyLink} /> )} - {tab === 'releases' && } - {Boolean(tab === 'settings' && settings && Object.values(settings).length) && ( - )} - {tab === 'logs' && } )} diff --git a/apps/meteor/client/views/admin/apps/AppDetailsHeader.tsx b/apps/meteor/client/views/admin/apps/AppDetailsPage/AppDetailsPageHeader.tsx similarity index 76% rename from apps/meteor/client/views/admin/apps/AppDetailsHeader.tsx rename to apps/meteor/client/views/admin/apps/AppDetailsPage/AppDetailsPageHeader.tsx index a663189018bf5..381b091354972 100644 --- a/apps/meteor/client/views/admin/apps/AppDetailsHeader.tsx +++ b/apps/meteor/client/views/admin/apps/AppDetailsPage/AppDetailsPageHeader.tsx @@ -1,15 +1,15 @@ +import type { App } from '@rocket.chat/core-typings'; import { Box } from '@rocket.chat/fuselage'; import { useTranslation } from '@rocket.chat/ui-contexts'; import moment from 'moment'; import React, { ReactElement } from 'react'; -import AppAvatar from '../../../components/avatar/AppAvatar'; -import AppMenu from './AppMenu'; -import AppStatus from './AppStatus'; -import BundleChips from './BundleChips'; -import { App } from './types'; +import AppAvatar from '../../../../components/avatar/AppAvatar'; +import AppMenu from '../AppMenu'; +import BundleChips from '../BundleChips'; +import AppStatus from './tabs/AppStatus'; -const AppDetailsHeader = ({ app }: { app: App }): ReactElement => { +const AppDetailsPageHeader = ({ app }: { app: App }): ReactElement => { const t = useTranslation(); const { iconFileData, name, author, version, iconFileContent, installed, isSubscribed, modifiedAt, bundledIn } = app; const lastUpdated = modifiedAt && moment(modifiedAt).fromNow(); @@ -26,9 +26,7 @@ const AppDetailsHeader = ({ app }: { app: App }): ReactElement => { {app?.shortDescription && {app.shortDescription}} - - - + {(installed || isSubscribed) && } @@ -53,4 +51,4 @@ const AppDetailsHeader = ({ app }: { app: App }): ReactElement => { ); }; -export default AppDetailsHeader; +export default AppDetailsPageHeader; diff --git a/apps/meteor/client/views/admin/apps/LoadingDetails.tsx b/apps/meteor/client/views/admin/apps/AppDetailsPage/AppDetailsPageLoading.tsx similarity index 85% rename from apps/meteor/client/views/admin/apps/LoadingDetails.tsx rename to apps/meteor/client/views/admin/apps/AppDetailsPage/AppDetailsPageLoading.tsx index 0e2966edb3f11..8037bfc900b09 100644 --- a/apps/meteor/client/views/admin/apps/LoadingDetails.tsx +++ b/apps/meteor/client/views/admin/apps/AppDetailsPage/AppDetailsPageLoading.tsx @@ -1,7 +1,7 @@ import { Box, Skeleton } from '@rocket.chat/fuselage'; import React, { FC } from 'react'; -const LoadingDetails: FC = () => ( +const AppDetailsPageLoading: FC = () => ( @@ -12,4 +12,4 @@ const LoadingDetails: FC = () => ( ); -export default LoadingDetails; +export default AppDetailsPageLoading; diff --git a/apps/meteor/client/views/admin/apps/AppDetailsPage/index.ts b/apps/meteor/client/views/admin/apps/AppDetailsPage/index.ts new file mode 100644 index 0000000000000..083aa6ad66fdf --- /dev/null +++ b/apps/meteor/client/views/admin/apps/AppDetailsPage/index.ts @@ -0,0 +1 @@ +export { default } from './AppDetailsPage'; diff --git a/apps/meteor/client/views/admin/apps/AppDetails.tsx b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppDetails/AppDetails.tsx similarity index 88% rename from apps/meteor/client/views/admin/apps/AppDetails.tsx rename to apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppDetails/AppDetails.tsx index 26a72f67f007c..b596b2ab338d2 100644 --- a/apps/meteor/client/views/admin/apps/AppDetails.tsx +++ b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppDetails/AppDetails.tsx @@ -1,17 +1,14 @@ import { Box, ButtonGroup, Callout, Chip, Margins } from '@rocket.chat/fuselage'; import { ExternalLink } from '@rocket.chat/ui-client'; import { TranslationKey, useTranslation } from '@rocket.chat/ui-contexts'; -import React, { FC } from 'react'; +import React, { ReactElement } from 'react'; -import APIsDisplay from './APIsDisplay'; -import ScreenshotCarouselAnchor from './components/ScreenshotCarouselAnchor'; -import { AppInfo } from './definitions/AppInfo'; +import ScreenshotCarouselAnchor from '../../../components/ScreenshotCarouselAnchor'; +import { AppInfo } from '../../../definitions/AppInfo'; +import AppDetailsAPIs from './AppDetailsAPIs'; -type AppDetailsProps = { - app: AppInfo; -}; - -const AppDetails: FC = ({ app }) => { +const AppDetails = ({ app }: { app: AppInfo }): ReactElement => { + const t = useTranslation(); const { author: { homepage, support }, detailedDescription, @@ -21,8 +18,6 @@ const AppDetails: FC = ({ app }) => { apis, } = app; - const t = useTranslation(); - const isMarkdown = detailedDescription && Object.keys(detailedDescription).length !== 0 && detailedDescription.rendered; const isCarouselVisible = screenshots && Boolean(screenshots.length); @@ -90,7 +85,7 @@ const AppDetails: FC = ({ app }) => { {apis?.length ? ( - + ) : null} diff --git a/apps/meteor/client/views/admin/apps/APIsDisplay.tsx b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppDetails/AppDetailsAPIs.tsx similarity index 86% rename from apps/meteor/client/views/admin/apps/APIsDisplay.tsx rename to apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppDetails/AppDetailsAPIs.tsx index 2cfbde0103c3d..6ffc649667156 100644 --- a/apps/meteor/client/views/admin/apps/APIsDisplay.tsx +++ b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppDetails/AppDetailsAPIs.tsx @@ -3,13 +3,13 @@ import { Box } from '@rocket.chat/fuselage'; import { useAbsoluteUrl, useTranslation } from '@rocket.chat/ui-contexts'; import React, { FC, Fragment } from 'react'; -import { apiCurlGetter } from './helpers'; +import { apiCurlGetter } from '../../../helpers'; -type APIsDisplayProps = { +type AppDetailsAPIsProps = { apis: IApiEndpointMetadata[]; }; -const APIsDisplay: FC = ({ apis }) => { +const AppDetailsAPIs: FC = ({ apis }) => { const t = useTranslation(); const absoluteUrl = useAbsoluteUrl(); const getApiCurl = apiCurlGetter(absoluteUrl); @@ -48,4 +48,4 @@ const APIsDisplay: FC = ({ apis }) => { ); }; -export default APIsDisplay; +export default AppDetailsAPIs; diff --git a/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppDetails/index.ts b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppDetails/index.ts new file mode 100644 index 0000000000000..dd31f61506df5 --- /dev/null +++ b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppDetails/index.ts @@ -0,0 +1 @@ +export { default } from './AppDetails'; diff --git a/apps/meteor/client/views/admin/apps/AppLogs.tsx b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppLogs/AppLogs.tsx similarity index 77% rename from apps/meteor/client/views/admin/apps/AppLogs.tsx rename to apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppLogs/AppLogs.tsx index 3a213cf30cf84..22c54c8bfca2b 100644 --- a/apps/meteor/client/views/admin/apps/AppLogs.tsx +++ b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppLogs/AppLogs.tsx @@ -2,10 +2,10 @@ import { Accordion, Box } from '@rocket.chat/fuselage'; import { useTranslation } from '@rocket.chat/ui-contexts'; import React, { ReactElement } from 'react'; -import { useFormatDateAndTime } from '../../../hooks/useFormatDateAndTime'; -import AccordionLoading from './AccordionLoading'; -import LogItem from './LogItem'; -import { useLogs } from './hooks/useLogs'; +import { useFormatDateAndTime } from '../../../../../../hooks/useFormatDateAndTime'; +import AccordionLoading from '../../../AccordionLoading'; +import { useLogs } from '../../../hooks/useLogs'; +import AppLogsItem from './AppLogsItem'; const AppLogs = ({ id }: { id: string }): ReactElement => { const t = useTranslation(); @@ -23,7 +23,7 @@ const AppLogs = ({ id }: { id: string }): ReactElement => { {isSuccess && ( {data?.logs?.map((log) => ( - = ({ entries, instanceId, title, ...props }) => { +const AppLogsItem: FC = ({ entries, instanceId, title, ...props }) => { const t = useTranslation(); return ( @@ -22,10 +22,10 @@ const LogItem: FC = ({ entries, instanceId, title, ...props }) => )} {entries.map(({ severity, timestamp, caller, args }, i) => ( - + ))} ); }; -export default LogItem; +export default AppLogsItem; diff --git a/apps/meteor/client/views/admin/apps/LogEntry.tsx b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppLogs/AppLogsItemEntry.tsx similarity index 69% rename from apps/meteor/client/views/admin/apps/LogEntry.tsx rename to apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppLogs/AppLogsItemEntry.tsx index 80db19ffa8f50..25ea68df133bd 100644 --- a/apps/meteor/client/views/admin/apps/LogEntry.tsx +++ b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppLogs/AppLogsItemEntry.tsx @@ -2,16 +2,16 @@ import { Box } from '@rocket.chat/fuselage'; import { useTranslation } from '@rocket.chat/ui-contexts'; import React, { FC } from 'react'; -import { useHighlightedCode } from '../../../hooks/useHighlightedCode'; +import { useHighlightedCode } from '../../../../../../hooks/useHighlightedCode'; -type LogEntryProps = { +type AppLogsItemEntryProps = { severity: string; timestamp: string; caller: string; args: unknown; }; -const LogEntry: FC = ({ severity, timestamp, caller, args }) => { +const AppLogsItemEntry: FC = ({ severity, timestamp, caller, args }) => { const t = useTranslation(); return ( @@ -32,4 +32,4 @@ const LogEntry: FC = ({ severity, timestamp, caller, args }) => { ); }; -export default LogEntry; +export default AppLogsItemEntry; diff --git a/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppLogs/index.ts b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppLogs/index.ts new file mode 100644 index 0000000000000..cb7d5a66b1699 --- /dev/null +++ b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppLogs/index.ts @@ -0,0 +1 @@ +export { default } from './AppLogs'; diff --git a/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppReleases/AppReleases.tsx b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppReleases/AppReleases.tsx new file mode 100644 index 0000000000000..b8a7cd289a44f --- /dev/null +++ b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppReleases/AppReleases.tsx @@ -0,0 +1,30 @@ +import { App } from '@rocket.chat/core-typings'; +import { Accordion } from '@rocket.chat/fuselage'; +import React, { ReactElement } from 'react'; + +import { useEndpointData } from '../../../../../../hooks/useEndpointData'; +import { AsyncStatePhase } from '../../../../../../lib/asyncState/AsyncStatePhase'; +import AccordionLoading from '../../../AccordionLoading'; +import AppReleasesItem from './AppReleasesItem'; + +// TODO: replace useEndpointData +const AppReleases = ({ id }: { id: App['id'] }): ReactElement => { + const result = useEndpointData(`/apps/${id}/versions`); + + return ( + <> + + {result.phase === AsyncStatePhase.LOADING && } + {result.phase === AsyncStatePhase.RESOLVED && ( + <> + {result.value.apps.map((release) => ( + + ))} + + )} + + + ); +}; + +export default AppReleases; diff --git a/apps/meteor/client/views/admin/apps/ReleaseItem.tsx b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppReleases/AppReleasesItem.tsx similarity index 66% rename from apps/meteor/client/views/admin/apps/ReleaseItem.tsx rename to apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppReleases/AppReleasesItem.tsx index e8046c84730d2..c35476bf28e0a 100644 --- a/apps/meteor/client/views/admin/apps/ReleaseItem.tsx +++ b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppReleases/AppReleasesItem.tsx @@ -1,9 +1,10 @@ import { Accordion, Box } from '@rocket.chat/fuselage'; -import React from 'react'; +import { useTranslation } from '@rocket.chat/ui-contexts'; +import React, { ReactElement } from 'react'; -import { useTimeAgo } from '../../../hooks/useTimeAgo'; +import { useTimeAgo } from '../../../../../../hooks/useTimeAgo'; -type release = { +type IRelease = { version: string; createdDate: string; detailedChangelog: { @@ -13,10 +14,11 @@ type release = { }; type ReleaseItemProps = { - release: release; + release: IRelease; }; -const ReleaseItem = ({ release, ...props }: ReleaseItemProps): JSX.Element => { +const AppReleasesItem = ({ release, ...props }: ReleaseItemProps): ReactElement => { + const t = useTranslation(); const formatDate = useTimeAgo(); const title = ( @@ -35,10 +37,10 @@ const ReleaseItem = ({ release, ...props }: ReleaseItemProps): JSX.Element => { {release.detailedChangelog?.rendered ? ( ) : ( - 'No release information provided' + t('No_release_information_provided') )} ); }; -export default ReleaseItem; +export default AppReleasesItem; diff --git a/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppReleases/index.ts b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppReleases/index.ts new file mode 100644 index 0000000000000..9fa2054b24fc3 --- /dev/null +++ b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppReleases/index.ts @@ -0,0 +1 @@ +export { default } from './AppReleases'; diff --git a/apps/meteor/client/views/admin/apps/AppSecurity.tsx b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppSecurity.tsx similarity index 100% rename from apps/meteor/client/views/admin/apps/AppSecurity.tsx rename to apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppSecurity.tsx diff --git a/apps/meteor/client/views/admin/apps/AppSetting.tsx b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppSettings/AppSetting.tsx similarity index 90% rename from apps/meteor/client/views/admin/apps/AppSetting.tsx rename to apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppSettings/AppSetting.tsx index 07447d9d79707..5aec371aacc68 100644 --- a/apps/meteor/client/views/admin/apps/AppSetting.tsx +++ b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppSettings/AppSetting.tsx @@ -3,13 +3,14 @@ import { ISettingBase, SettingValue } from '@rocket.chat/core-typings'; import { useRouteParameter, useTranslation } from '@rocket.chat/ui-contexts'; import React, { useMemo, useCallback, ReactElement } from 'react'; -import MarkdownText from '../../../components/MarkdownText'; -import MemoizedSetting from '../settings/MemoizedSetting'; +import MarkdownText from '../../../../../../components/MarkdownText'; +import MemoizedSetting from '../../../../settings/MemoizedSetting'; type AppTranslationFunction = { (key: string, ...replaces: unknown[]): string; has: (key: string | undefined) => boolean; }; + const useAppTranslation = (appId: string): AppTranslationFunction => { const t = useTranslation(); @@ -57,7 +58,7 @@ type AppSettingProps = { onChange: (value: SettingValue) => void; value: SettingValue; }; -function AppSetting({ appSetting, onChange, value, ...props }: AppSettingProps): ReactElement { +const AppSetting = ({ appSetting, onChange, value, ...props }: AppSettingProps): ReactElement => { const appId = useRouteParameter('id'); const tApp = useAppTranslation(appId || ''); @@ -94,6 +95,6 @@ function AppSetting({ appSetting, onChange, value, ...props }: AppSettingProps): {...props} /> ); -} +}; export default AppSetting; diff --git a/apps/meteor/client/views/admin/apps/SettingsDisplay.tsx b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppSettings/AppSettings.tsx similarity index 80% rename from apps/meteor/client/views/admin/apps/SettingsDisplay.tsx rename to apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppSettings/AppSettings.tsx index 056001f520a45..1e50f1a34ae4c 100644 --- a/apps/meteor/client/views/admin/apps/SettingsDisplay.tsx +++ b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppSettings/AppSettings.tsx @@ -4,23 +4,23 @@ import { Box } from '@rocket.chat/fuselage'; import { useTranslation } from '@rocket.chat/ui-contexts'; import React, { FC, useMemo, useEffect, MutableRefObject } from 'react'; -import { ISettings } from '../../../../app/apps/client/@types/IOrchestrator'; -import { useForm } from '../../../hooks/useForm'; +import { ISettings } from '../../../../../../../app/apps/client/@types/IOrchestrator'; +import { useForm } from '../../../../../../hooks/useForm'; import AppSettingsAssembler from './AppSettingsAssembler'; -type SettingsDisplayProps = { +type AppSettingsProps = { settings: ISettings; setHasUnsavedChanges: (hasUnsavedChanges: boolean) => void; settingsRef: MutableRefObject>; }; -const SettingsDisplay: FC = ({ settings, setHasUnsavedChanges, settingsRef }) => { +const AppSettings: FC = ({ settings, setHasUnsavedChanges, settingsRef }) => { const t = useTranslation(); const stringifiedSettings = JSON.stringify(settings); const reducedSettings = useMemo(() => { - const settings: SettingsDisplayProps['settings'] = JSON.parse(stringifiedSettings); + const settings: AppSettingsProps['settings'] = JSON.parse(stringifiedSettings); return Object.values(settings).reduce((ret, { id, value, packageValue }) => ({ ...ret, [id]: value ?? packageValue }), {}); }, [stringifiedSettings]); @@ -49,4 +49,4 @@ const SettingsDisplay: FC = ({ settings, setHasUnsavedChan ); }; -export default SettingsDisplay; +export default AppSettings; diff --git a/apps/meteor/client/views/admin/apps/AppSettingsAssembler.tsx b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppSettings/AppSettingsAssembler.tsx similarity index 89% rename from apps/meteor/client/views/admin/apps/AppSettingsAssembler.tsx rename to apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppSettings/AppSettingsAssembler.tsx index ed8eaba62ace6..eb67909e859ad 100644 --- a/apps/meteor/client/views/admin/apps/AppSettingsAssembler.tsx +++ b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppSettings/AppSettingsAssembler.tsx @@ -3,7 +3,7 @@ import { Box } from '@rocket.chat/fuselage'; import { capitalize } from '@rocket.chat/string-helpers'; import React, { ReactElement } from 'react'; -import { ISettings } from '../../../../app/apps/client/@types/IOrchestrator'; +import { ISettings } from '../../../../../../../app/apps/client/@types/IOrchestrator'; import AppSetting from './AppSetting'; type AppSettingsAssemblerProps = { diff --git a/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppSettings/index.ts b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppSettings/index.ts new file mode 100644 index 0000000000000..b1579d346e3a5 --- /dev/null +++ b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppSettings/index.ts @@ -0,0 +1 @@ +export { default } from './AppSettings'; diff --git a/apps/meteor/client/views/admin/apps/AppStatus.js b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppStatus/AppStatus.js similarity index 88% rename from apps/meteor/client/views/admin/apps/AppStatus.js rename to apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppStatus/AppStatus.js index 7b97beee52776..7c4b7df60bc2c 100644 --- a/apps/meteor/client/views/admin/apps/AppStatus.js +++ b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppStatus/AppStatus.js @@ -3,12 +3,12 @@ import { useSafely } from '@rocket.chat/fuselage-hooks'; import { useSetModal, useMethod, useTranslation } from '@rocket.chat/ui-contexts'; import React, { useCallback, useState, memo } from 'react'; -import { Apps } from '../../../../app/apps/client/orchestrator'; -import AppPermissionsReviewModal from './AppPermissionsReviewModal'; -import CloudLoginModal from './CloudLoginModal'; -import IframeModal from './IframeModal'; -import PriceDisplay from './PriceDisplay'; -import { appButtonProps, appStatusSpanProps, handleAPIError, warnStatusChange, handleInstallError } from './helpers'; +import { Apps } from '../../../../../../../app/apps/client/orchestrator'; +import AppPermissionsReviewModal from '../../../AppPermissionsReviewModal'; +import CloudLoginModal from '../../../CloudLoginModal'; +import IframeModal from '../../../IframeModal'; +import { appButtonProps, appStatusSpanProps, handleAPIError, warnStatusChange, handleInstallError } from '../../../helpers'; +import AppStatusPriceDisplay from './AppStatusPriceDisplay'; const installApp = async ({ id, name, version, permissionsGranted }) => { try { @@ -139,8 +139,8 @@ const AppStatus = ({ app, showStatus = true, isAppDetailsPage, isSubscribed, ins )} {shouldShowPriceDisplay && !installed && ( - - + + )} diff --git a/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppStatus/AppStatusPriceDisplay.tsx b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppStatus/AppStatusPriceDisplay.tsx new file mode 100644 index 0000000000000..fae7f7a31ee9e --- /dev/null +++ b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppStatus/AppStatusPriceDisplay.tsx @@ -0,0 +1,32 @@ +import type { AppPricingPlan } from '@rocket.chat/core-typings'; +import { Box, Tag } from '@rocket.chat/fuselage'; +import { TranslationKey, useTranslation } from '@rocket.chat/ui-contexts'; +import React, { FC, useMemo } from 'react'; + +import { formatPriceAndPurchaseType } from '../../../helpers'; + +type AppStatusPriceDisplayProps = { + purchaseType: string; + pricingPlans: AppPricingPlan[]; + price: number; + showType?: boolean; + marginInline?: string; +}; + +const AppStatusPriceDisplay: FC = ({ purchaseType, pricingPlans, price, showType = true }) => { + const t = useTranslation(); + + const { type, price: formattedPrice } = useMemo( + () => formatPriceAndPurchaseType(purchaseType, pricingPlans, price), + [purchaseType, pricingPlans, price], + ); + + return ( + + {showType && {t(type as TranslationKey)}} + {!showType && type === 'Free' ? t(type) : formattedPrice} + + ); +}; + +export default AppStatusPriceDisplay; diff --git a/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppStatus/index.ts b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppStatus/index.ts new file mode 100644 index 0000000000000..658eb6cedecff --- /dev/null +++ b/apps/meteor/client/views/admin/apps/AppDetailsPage/tabs/AppStatus/index.ts @@ -0,0 +1 @@ +export { default } from './AppStatus'; diff --git a/apps/meteor/client/views/admin/apps/AppMenu.js b/apps/meteor/client/views/admin/apps/AppMenu.js index b0d12d2cd8822..52f50bea75479 100644 --- a/apps/meteor/client/views/admin/apps/AppMenu.js +++ b/apps/meteor/client/views/admin/apps/AppMenu.js @@ -2,9 +2,9 @@ import { Box, Icon, Menu } from '@rocket.chat/fuselage'; import { useSetModal, useMethod, useEndpoint, useTranslation, useRoute, useRouteParameter } from '@rocket.chat/ui-contexts'; import React, { useMemo, useCallback } from 'react'; +import WarningModal from '../../../components/WarningModal'; import CloudLoginModal from './CloudLoginModal'; import IframeModal from './IframeModal'; -import WarningModal from './WarningModal'; import { appEnabledStatuses, warnStatusChange, handleAPIError } from './helpers'; function AppMenu({ app, ...props }) { diff --git a/apps/meteor/client/views/admin/apps/AppReleases.tsx b/apps/meteor/client/views/admin/apps/AppReleases.tsx deleted file mode 100644 index e0a64daef7f2a..0000000000000 --- a/apps/meteor/client/views/admin/apps/AppReleases.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { Accordion } from '@rocket.chat/fuselage'; -import React from 'react'; - -import { useEndpointData } from '../../../hooks/useEndpointData'; -import { AsyncStatePhase } from '../../../lib/asyncState/AsyncStatePhase'; -import AccordionLoading from './AccordionLoading'; -import ReleaseItem from './ReleaseItem'; - -const AppReleases = ({ id }: { id: string }): JSX.Element => { - const result = useEndpointData(`/apps/${id}/versions`); - - return ( - <> - - {result.phase === AsyncStatePhase.LOADING && } - {result.phase === AsyncStatePhase.RESOLVED && ( - <> - {result.value.apps.map((release) => ( - - ))} - - )} - - - ); -}; - -export default AppReleases; diff --git a/apps/meteor/client/views/admin/apps/AppRow.tsx b/apps/meteor/client/views/admin/apps/AppsList/AppRow.tsx similarity index 88% rename from apps/meteor/client/views/admin/apps/AppRow.tsx rename to apps/meteor/client/views/admin/apps/AppsList/AppRow.tsx index f71fe26f2b593..0e2ff0ffe8622 100644 --- a/apps/meteor/client/views/admin/apps/AppRow.tsx +++ b/apps/meteor/client/views/admin/apps/AppsList/AppRow.tsx @@ -1,3 +1,4 @@ +import type { App } from '@rocket.chat/core-typings'; import { css } from '@rocket.chat/css-in-js'; import { Box } from '@rocket.chat/fuselage'; import { useBreakpoints } from '@rocket.chat/fuselage-hooks'; @@ -5,13 +6,15 @@ import colors from '@rocket.chat/fuselage-tokens/colors'; import { useRoute } from '@rocket.chat/ui-contexts'; import React, { FC, memo, KeyboardEvent, MouseEvent } from 'react'; -import AppAvatar from '../../../components/avatar/AppAvatar'; -import AppMenu from './AppMenu'; -import AppStatus from './AppStatus'; -import BundleChips from './BundleChips'; -import { App } from './types'; +import AppAvatar from '../../../../components/avatar/AppAvatar'; +import AppStatus from '../AppDetailsPage/tabs/AppStatus/AppStatus'; +import AppMenu from '../AppMenu'; +import BundleChips from '../BundleChips'; -const AppRow: FC = (props) => { +type AppRowProps = App & { isMarketplace: boolean }; + +// TODO: org props +const AppRow: FC = (props) => { const { name, id, description, iconFileData, marketplaceVersion, iconFileContent, installed, isSubscribed, isMarketplace, bundledIn } = props; diff --git a/apps/meteor/client/views/admin/apps/AppsList.tsx b/apps/meteor/client/views/admin/apps/AppsList/AppsList.tsx similarity index 100% rename from apps/meteor/client/views/admin/apps/AppsList.tsx rename to apps/meteor/client/views/admin/apps/AppsList/AppsList.tsx diff --git a/apps/meteor/client/views/admin/apps/AppsList/index.ts b/apps/meteor/client/views/admin/apps/AppsList/index.ts new file mode 100644 index 0000000000000..921f6d70e274b --- /dev/null +++ b/apps/meteor/client/views/admin/apps/AppsList/index.ts @@ -0,0 +1 @@ +export { default } from './AppsList'; diff --git a/apps/meteor/client/views/admin/apps/AppsFilters.tsx b/apps/meteor/client/views/admin/apps/AppsPage/AppsFilters.tsx similarity index 83% rename from apps/meteor/client/views/admin/apps/AppsFilters.tsx rename to apps/meteor/client/views/admin/apps/AppsPage/AppsFilters.tsx index a60818d1c84f5..b77da9994c0c8 100644 --- a/apps/meteor/client/views/admin/apps/AppsFilters.tsx +++ b/apps/meteor/client/views/admin/apps/AppsPage/AppsFilters.tsx @@ -2,12 +2,12 @@ import { useMediaQuery } from '@rocket.chat/fuselage-hooks'; import { useTranslation } from '@rocket.chat/ui-contexts'; import React, { ReactElement } from 'react'; -import FilterByText from '../../../components/FilterByText'; -import CategoryDropDown from './components/CategoryFilter/CategoryDropDown'; -import TagList from './components/CategoryFilter/TagList'; -import RadioDropDown from './components/RadioDropDown/RadioDropDown'; -import { CategoryDropdownItem, CategoryOnSelected, selectedCategoriesList } from './definitions/CategoryDropdownDefinitions'; -import { RadioDropDownGroup, RadioDropDownOnSelected } from './definitions/RadioDropDownDefinitions'; +import FilterByText from '../../../../components/FilterByText'; +import CategoryDropDown from '../components/CategoryFilter/CategoryDropDown'; +import TagList from '../components/CategoryFilter/TagList'; +import RadioDropDown from '../components/RadioDropDown/RadioDropDown'; +import { CategoryDropdownItem, CategoryOnSelected, selectedCategoriesList } from '../definitions/CategoryDropdownDefinitions'; +import { RadioDropDownGroup, RadioDropDownOnSelected } from '../definitions/RadioDropDownDefinitions'; type AppsFiltersProps = { setText: React.Dispatch> & { diff --git a/apps/meteor/client/views/admin/apps/AppsPage.tsx b/apps/meteor/client/views/admin/apps/AppsPage/AppsPage.tsx similarity index 97% rename from apps/meteor/client/views/admin/apps/AppsPage.tsx rename to apps/meteor/client/views/admin/apps/AppsPage/AppsPage.tsx index f716e34d39eee..400ec4c3bcf15 100644 --- a/apps/meteor/client/views/admin/apps/AppsPage.tsx +++ b/apps/meteor/client/views/admin/apps/AppsPage/AppsPage.tsx @@ -2,7 +2,7 @@ import { Button, ButtonGroup, Icon, Skeleton, Tabs } from '@rocket.chat/fuselage import { useRoute, useSetting, useMethod, useTranslation } from '@rocket.chat/ui-contexts'; import React, { useEffect, useState, ReactElement } from 'react'; -import Page from '../../../components/Page'; +import Page from '../../../../components/Page'; import AppsPageContent from './AppsPageContent'; type AppsPageProps = { diff --git a/apps/meteor/client/views/admin/apps/ConnectionErrorEmptyState.tsx b/apps/meteor/client/views/admin/apps/AppsPage/AppsPageConnectionError.tsx similarity index 82% rename from apps/meteor/client/views/admin/apps/ConnectionErrorEmptyState.tsx rename to apps/meteor/client/views/admin/apps/AppsPage/AppsPageConnectionError.tsx index 2db606117f23e..4afe7f8a1928b 100644 --- a/apps/meteor/client/views/admin/apps/ConnectionErrorEmptyState.tsx +++ b/apps/meteor/client/views/admin/apps/AppsPage/AppsPageConnectionError.tsx @@ -2,7 +2,7 @@ import { Box, States, StatesIcon, StatesTitle, StatesSubtitle, StatesActions, St import { useTranslation } from '@rocket.chat/ui-contexts'; import React, { ReactElement } from 'react'; -const ConnectionErrorEmptyState = ({ onButtonClick }: { onButtonClick: () => void }): ReactElement => { +const AppsPageContentError = ({ onButtonClick }: { onButtonClick: () => void }): ReactElement => { const t = useTranslation(); return ( @@ -22,4 +22,4 @@ const ConnectionErrorEmptyState = ({ onButtonClick }: { onButtonClick: () => voi ); }; -export default ConnectionErrorEmptyState; +export default AppsPageContentError; diff --git a/apps/meteor/client/views/admin/apps/AppsPageContent.tsx b/apps/meteor/client/views/admin/apps/AppsPage/AppsPageContent.tsx similarity index 89% rename from apps/meteor/client/views/admin/apps/AppsPageContent.tsx rename to apps/meteor/client/views/admin/apps/AppsPage/AppsPageContent.tsx index 422916a24be77..ea6be4c0422b4 100644 --- a/apps/meteor/client/views/admin/apps/AppsPageContent.tsx +++ b/apps/meteor/client/views/admin/apps/AppsPage/AppsPageContent.tsx @@ -3,21 +3,21 @@ import { useDebouncedState } from '@rocket.chat/fuselage-hooks'; import { useRoute, useTranslation } from '@rocket.chat/ui-contexts'; import React, { ReactElement, useMemo, useState } from 'react'; -import { usePagination } from '../../../components/GenericTable/hooks/usePagination'; -import { AsyncStatePhase } from '../../../lib/asyncState'; -import { useAppsReload, useAppsResult } from './AppsContext'; +import { usePagination } from '../../../../components/GenericTable/hooks/usePagination'; +import { AsyncStatePhase } from '../../../../lib/asyncState'; +import { useAppsReload, useAppsResult } from '../AppsContext'; +import AppsList from '../AppsList'; +import { RadioDropDownGroup } from '../definitions/RadioDropDownDefinitions'; +import { useCategories } from '../hooks/useCategories'; +import { useFilteredApps } from '../hooks/useFilteredApps'; +import { useRadioToggle } from '../hooks/useRadioToggle'; import AppsFilters from './AppsFilters'; -import AppsList from './AppsList'; +import AppsPageConnectionError from './AppsPageConnectionError'; import AppsPageContentSkeleton from './AppsPageContentSkeleton'; -import ConnectionErrorEmptyState from './ConnectionErrorEmptyState'; import FeaturedAppsSections from './FeaturedAppsSections'; import NoInstalledAppMatchesEmptyState from './NoInstalledAppMatchesEmptyState'; import NoInstalledAppsFoundEmptyState from './NoInstalledAppsFoundEmptyState'; import NoMarketplaceOrInstalledAppMatchesEmptyState from './NoMarketplaceOrInstalledAppMatchesEmptyState'; -import { RadioDropDownGroup } from './definitions/RadioDropDownDefinitions'; -import { useCategories } from './hooks/useCategories'; -import { useFilteredApps } from './hooks/useFilteredApps'; -import { useRadioToggle } from './hooks/useRadioToggle'; const AppsPageContent = ({ isMarketplace }: { isMarketplace: boolean }): ReactElement => { const t = useTranslation(); @@ -134,7 +134,7 @@ const AppsPageContent = ({ isMarketplace }: { isMarketplace: boolean }): ReactEl /> )} {noInstalledAppsFound && marketplaceRoute.push({ context: '' })} />} - {appsResult.phase === AsyncStatePhase.REJECTED && } + {appsResult.phase === AsyncStatePhase.REJECTED && } ); }; diff --git a/apps/meteor/client/views/admin/apps/AppsPageContentSkeleton.tsx b/apps/meteor/client/views/admin/apps/AppsPage/AppsPageContentSkeleton.tsx similarity index 100% rename from apps/meteor/client/views/admin/apps/AppsPageContentSkeleton.tsx rename to apps/meteor/client/views/admin/apps/AppsPage/AppsPageContentSkeleton.tsx diff --git a/apps/meteor/client/views/admin/apps/FeaturedAppsSections.tsx b/apps/meteor/client/views/admin/apps/AppsPage/FeaturedAppsSections.tsx similarity index 82% rename from apps/meteor/client/views/admin/apps/FeaturedAppsSections.tsx rename to apps/meteor/client/views/admin/apps/AppsPage/FeaturedAppsSections.tsx index faab9cf91fdc4..0327316f51ff6 100644 --- a/apps/meteor/client/views/admin/apps/FeaturedAppsSections.tsx +++ b/apps/meteor/client/views/admin/apps/AppsPage/FeaturedAppsSections.tsx @@ -2,9 +2,9 @@ import { App } from '@rocket.chat/core-typings'; import { useTranslation } from '@rocket.chat/ui-contexts'; import React, { ReactElement } from 'react'; -import AppsList from './AppsList'; -import normalizeFeaturedApps from './helpers/normalizeFeaturedApps'; -import { useFeaturedApps } from './hooks/useFeaturedApps'; +import AppsList from '../AppsList'; +import normalizeFeaturedApps from '../helpers/normalizeFeaturedApps'; +import { useFeaturedApps } from '../hooks/useFeaturedApps'; type FeaturedSectionsProps = { appsResult: App[]; diff --git a/apps/meteor/client/views/admin/apps/NoInstalledAppMatchesEmptyState.tsx b/apps/meteor/client/views/admin/apps/AppsPage/NoInstalledAppMatchesEmptyState.tsx similarity index 100% rename from apps/meteor/client/views/admin/apps/NoInstalledAppMatchesEmptyState.tsx rename to apps/meteor/client/views/admin/apps/AppsPage/NoInstalledAppMatchesEmptyState.tsx diff --git a/apps/meteor/client/views/admin/apps/NoInstalledAppsFoundEmptyState.tsx b/apps/meteor/client/views/admin/apps/AppsPage/NoInstalledAppsFoundEmptyState.tsx similarity index 100% rename from apps/meteor/client/views/admin/apps/NoInstalledAppsFoundEmptyState.tsx rename to apps/meteor/client/views/admin/apps/AppsPage/NoInstalledAppsFoundEmptyState.tsx diff --git a/apps/meteor/client/views/admin/apps/NoMarketplaceOrInstalledAppMatchesEmptyState.tsx b/apps/meteor/client/views/admin/apps/AppsPage/NoMarketplaceOrInstalledAppMatchesEmptyState.tsx similarity index 100% rename from apps/meteor/client/views/admin/apps/NoMarketplaceOrInstalledAppMatchesEmptyState.tsx rename to apps/meteor/client/views/admin/apps/AppsPage/NoMarketplaceOrInstalledAppMatchesEmptyState.tsx diff --git a/apps/meteor/client/views/admin/apps/AppsPage/index.ts b/apps/meteor/client/views/admin/apps/AppsPage/index.ts new file mode 100644 index 0000000000000..ef92dc3807173 --- /dev/null +++ b/apps/meteor/client/views/admin/apps/AppsPage/index.ts @@ -0,0 +1 @@ +export { default } from './AppsPage'; diff --git a/apps/meteor/client/views/admin/apps/AppsRoute.tsx b/apps/meteor/client/views/admin/apps/AppsRoute.tsx index 0fe081d2fb101..9480e86fd1a9f 100644 --- a/apps/meteor/client/views/admin/apps/AppsRoute.tsx +++ b/apps/meteor/client/views/admin/apps/AppsRoute.tsx @@ -5,7 +5,7 @@ import PageSkeleton from '../../../components/PageSkeleton'; import NotAuthorizedPage from '../../notAuthorized/NotAuthorizedPage'; import AppDetailsPage from './AppDetailsPage'; import AppInstallPage from './AppInstallPage'; -import AppsPage from './AppsPage'; +import AppsPage from './AppsPage/AppsPage'; import AppsProvider from './AppsProvider'; const AppsRoute: FC = () => { diff --git a/apps/meteor/client/views/admin/apps/PriceDisplay.tsx b/apps/meteor/client/views/admin/apps/PriceDisplay.tsx deleted file mode 100644 index df7a8a302be10..0000000000000 --- a/apps/meteor/client/views/admin/apps/PriceDisplay.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import type { AppPricingPlan } from '@rocket.chat/core-typings'; -import { Box, Tag, Margins } from '@rocket.chat/fuselage'; -import { TranslationKey, useTranslation } from '@rocket.chat/ui-contexts'; -import React, { FC, useMemo } from 'react'; - -import { formatPricingPlan, formatPrice } from './helpers'; - -type PriceDisplayProps = { - purchaseType: string; - pricingPlans: AppPricingPlan[]; - price: number; - showType?: boolean; - marginInline?: string; -}; - -type PlanType = 'Subscription' | 'Paid' | 'Free'; - -type FormattedPriceAndPlan = { - type: PlanType; - price: string; -}; - -const formatPriceAndPurchaseType = (purchaseType: string, pricingPlans: AppPricingPlan[], price: number): FormattedPriceAndPlan => { - if (purchaseType === 'subscription') { - const type = 'Subscription'; - if (!pricingPlans || !Array.isArray(pricingPlans) || pricingPlans.length === 0) { - return { type, price: '-' }; - } - - return { type, price: formatPricingPlan(pricingPlans[0]) }; - } - - if (price > 0) { - return { type: 'Paid', price: formatPrice(price) }; - } - - return { type: 'Free', price: '-' }; -}; - -const PriceDisplay: FC = ({ purchaseType, pricingPlans, price, showType = true }) => { - const t = useTranslation(); - - const { type, price: formattedPrice } = useMemo( - () => formatPriceAndPurchaseType(purchaseType, pricingPlans, price), - [purchaseType, pricingPlans, price], - ); - - return ( - - - {showType && ( - - {t(type as TranslationKey)} - - )} - {!showType && type === 'Free' ? t(type) : formattedPrice} - - - ); -}; - -export default PriceDisplay; diff --git a/apps/meteor/client/views/admin/apps/helpers.ts b/apps/meteor/client/views/admin/apps/helpers.ts index 8d7c0dcf70886..bc045ab77e28f 100644 --- a/apps/meteor/client/views/admin/apps/helpers.ts +++ b/apps/meteor/client/views/admin/apps/helpers.ts @@ -16,6 +16,25 @@ const appErroredStatuses = [ AppStatus.INVALID_LICENSE_DISABLED, ]; +type appButtonResponseProps = { + action: 'update' | 'install' | 'purchase'; + icon?: 'reload'; + label: 'Update' | 'Install' | 'Subscribe' | 'See Pricing' | 'Try now' | 'Buy'; +}; + +type appStatusSpanResponseProps = { + type?: 'failed' | 'warning'; + icon: 'warning' | 'ban' | 'checkmark-circled' | 'check'; + label: 'Config Needed' | 'Failed' | 'Disabled' | 'Trial period' | 'Installed'; +}; + +type PlanType = 'Subscription' | 'Paid' | 'Free'; + +type FormattedPriceAndPlan = { + type: PlanType; + price: string; +}; + export const apiCurlGetter = (absoluteUrl: (path: string) => string) => (method: string, api: IApiEndpointMetadata): string[] => { @@ -90,12 +109,6 @@ export const warnStatusChange = (appName: string, status: AppStatus): void => { dispatchToastMessage({ type: 'info', message: (t(`App_status_${status}`), appName) }); }; -type appButtonPropsResponse = { - action: 'update' | 'install' | 'purchase'; - icon?: 'reload'; - label: 'Update' | 'Install' | 'Subscribe' | 'See Pricing' | 'Try now' | 'Buy'; -}; - export const appButtonProps = ({ installed, version, @@ -106,7 +119,7 @@ export const appButtonProps = ({ subscriptionInfo, pricingPlans, isEnterpriseOnly, -}: App): appButtonPropsResponse | undefined => { +}: App): appButtonResponseProps | undefined => { const canUpdate = installed && version && marketplaceVersion && semver.lt(version, marketplaceVersion); if (canUpdate) { return { @@ -167,13 +180,7 @@ export const appButtonProps = ({ }; }; -type appStatusSpanPropsResponse = { - type?: 'failed' | 'warning'; - icon: 'warning' | 'ban' | 'checkmark-circled' | 'check'; - label: 'Config Needed' | 'Failed' | 'Disabled' | 'Trial period' | 'Installed'; -}; - -export const appStatusSpanProps = ({ installed, status, subscriptionInfo }: App): appStatusSpanPropsResponse | undefined => { +export const appStatusSpanProps = ({ installed, status, subscriptionInfo }: App): appStatusSpanResponseProps | undefined => { if (!installed) { return; } @@ -230,3 +237,20 @@ export const formatPricingPlan = ({ strategy, price, tiers = [], trialDays }: Ap trialDays, }); }; + +export const formatPriceAndPurchaseType = (purchaseType: string, pricingPlans: AppPricingPlan[], price: number): FormattedPriceAndPlan => { + if (purchaseType === 'subscription') { + const type = 'Subscription'; + if (!pricingPlans || !Array.isArray(pricingPlans) || pricingPlans.length === 0) { + return { type, price: '-' }; + } + + return { type, price: formatPricingPlan(pricingPlans[0]) }; + } + + if (price > 0) { + return { type: 'Paid', price: formatPrice(price) }; + } + + return { type: 'Free', price: '-' }; +}; diff --git a/apps/meteor/client/views/room/contextualBar/Info/RoomInfo/RoomInfoWithData.js b/apps/meteor/client/views/room/contextualBar/Info/RoomInfo/RoomInfoWithData.js index 592352e7a03c8..4ae1429dba000 100644 --- a/apps/meteor/client/views/room/contextualBar/Info/RoomInfo/RoomInfoWithData.js +++ b/apps/meteor/client/views/room/contextualBar/Info/RoomInfo/RoomInfoWithData.js @@ -17,10 +17,10 @@ import React from 'react'; import { RoomManager } from '../../../../../../app/ui-utils/client'; import { UiTextContext } from '../../../../../../definition/IRoomTypeConfig'; import GenericModal from '../../../../../components/GenericModal'; +import WarningModal from '../../../../../components/WarningModal'; import { useEndpointActionExperimental } from '../../../../../hooks/useEndpointActionExperimental'; import * as Federation from '../../../../../lib/federation/Federation'; import { roomCoordinator } from '../../../../../lib/rooms/roomCoordinator'; -import WarningModal from '../../../../admin/apps/WarningModal'; import { useTabBarClose } from '../../../contexts/ToolboxContext'; import ChannelToTeamModal from '../ChannelToTeamModal/ChannelToTeamModal'; import RoomInfo from './RoomInfo'; diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json index 3cf83c9cb8474..1ec47b30bbc14 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json @@ -3454,6 +3454,7 @@ "No_pages_yet_Try_hitting_Reload_Pages_button": "No pages yet. Try hitting \"Reload Pages\" button.", "No_pinned_messages": "No pinned messages", "No_previous_chat_found": "No previous chat found", + "No_release_information_provided": "No release information provided", "No_results_found": "No results found", "No_results_found_for": "No results found for:", "No_snippet_messages": "No snippet",