Skip to content

Commit

Permalink
chore!: Remove deprecated URL App installation (#33210)
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinSchoeler committed Sep 27, 2024
1 parent 335ae33 commit 50abbe6
Show file tree
Hide file tree
Showing 5 changed files with 16 additions and 58 deletions.
5 changes: 5 additions & 0 deletions .changeset/heavy-carrots-reflect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rocket.chat/meteor": major
---

Removes private App installation via URL method following a deprecation warning.
32 changes: 6 additions & 26 deletions apps/meteor/client/views/marketplace/AppInstallPage.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,20 @@
import { Button, ButtonGroup, Icon, Field, FieldGroup, FieldLabel, FieldRow, TextInput, Callout } from '@rocket.chat/fuselage';
import { Button, ButtonGroup, Field, FieldGroup, FieldLabel, FieldRow, TextInput } from '@rocket.chat/fuselage';
import { useUniqueId } from '@rocket.chat/fuselage-hooks';
import { useTranslation, useRouter, useSearchParameter } from '@rocket.chat/ui-contexts';
import { useTranslation, useRouter } from '@rocket.chat/ui-contexts';
import React, { useCallback } from 'react';
import { useForm, Controller } from 'react-hook-form';

import { Page, PageHeader, PageScrollableContent } from '../../components/Page';
import { useSingleFileInput } from '../../hooks/useSingleFileInput';
import { useInstallApp } from './hooks/useInstallApp';

const PLACEHOLDER_URL = 'https://rocket.chat/apps/package.zip';

const AppInstallPage = () => {
const t = useTranslation();
const router = useRouter();

const queryUrl = useSearchParameter('url');

const { control, setValue, watch } = useForm<{ file: File; url: string }>({ defaultValues: { url: queryUrl || '' } });
const { file, url } = watch();
const { install, isInstalling } = useInstallApp(file, url);
const { control, setValue, watch } = useForm<{ file: File }>();
const { file } = watch();
const { install, isInstalling } = useInstallApp(file);

const [handleUploadButtonClick] = useSingleFileInput((value) => setValue('file', value), 'app');

Expand All @@ -32,29 +28,13 @@ const AppInstallPage = () => {
});
}, [router]);

const urlField = useUniqueId();
const fileField = useUniqueId();

return (
<Page flexDirection='column'>
<PageHeader title={t('App_Installation')} />
<PageScrollableContent>
<FieldGroup display='flex' flexDirection='column' alignSelf='center' maxWidth='x600' w='full'>
<Field>
<FieldLabel htmlFor={urlField}>{t('App_Url_to_Install_From')}</FieldLabel>
<Callout type='warning' title={t('App_Installation_Deprecation_Title')}>
{t('App_Installation_Deprecation')}
</Callout>
<FieldRow>
<Controller
name='url'
control={control}
render={({ field }) => (
<TextInput id={urlField} placeholder={PLACEHOLDER_URL} addon={<Icon name='permalink' size='x20' />} {...field} />
)}
/>
</FieldRow>
</Field>
<Field>
<FieldLabel htmlFor={fileField}>{t('App_Url_to_Install_From_File')}</FieldLabel>
<FieldRow>
Expand All @@ -79,7 +59,7 @@ const AppInstallPage = () => {
</Field>
<Field>
<ButtonGroup>
<Button disabled={!url && !file?.name} loading={isInstalling} onClick={install}>
<Button disabled={!file?.name} loading={isInstalling} onClick={install}>
{t('Install')}
</Button>
<Button onClick={handleCancel}>{t('Cancel')}</Button>
Expand Down
28 changes: 4 additions & 24 deletions apps/meteor/client/views/marketplace/hooks/useInstallApp.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { App, AppPermission } from '@rocket.chat/core-typings';
import { useRouter, useSetModal, useUpload, useEndpoint } from '@rocket.chat/ui-contexts';
import { useRouter, useSetModal, useUpload } from '@rocket.chat/ui-contexts';
import { useMutation } from '@tanstack/react-query';
import React, { useCallback, useState } from 'react';

Expand All @@ -15,7 +15,7 @@ import { handleInstallError } from '../helpers/handleInstallError';
import { getManifestFromZippedApp } from '../lib/getManifestFromZippedApp';
import { useAppsCountQuery } from './useAppsCountQuery';

export const useInstallApp = (file: File, url: string): { install: () => void; isInstalling: boolean } => {
export const useInstallApp = (file: File): { install: () => void; isInstalling: boolean } => {
const reloadAppsList = useAppsReload();
const openExternalLink = useExternalLink();
const setModal = useSetModal();
Expand All @@ -28,9 +28,6 @@ export const useInstallApp = (file: File, url: string): { install: () => void; i
const uploadAppEndpoint = useUpload('/apps');
const uploadUpdateEndpoint = useUpload('/apps/update');

// TODO: This function should not be called in a next major version, it will be changed by an endpoint deprecation.
const downloadPrivateAppFromUrl = useEndpoint('POST', '/apps');

const [isInstalling, setInstalling] = useState(false);

const { mutate: sendFile } = useMutation(
Expand Down Expand Up @@ -102,17 +99,6 @@ export const useInstallApp = (file: File, url: string): { install: () => void; i
await handleAppPermissionsReview(permissions, appFile);
};

/** @deprecated */
const getAppFile = async (): Promise<File | undefined> => {
try {
const { buff } = (await downloadPrivateAppFromUrl({ url, downloadOnly: true })) as { buff: { data: ArrayLike<number> } };

return new File([Uint8Array.from(buff.data)], 'app.zip', { type: 'application/zip' });
} catch (error) {
handleInstallError(error as Error);
}
};

const extractManifestFromAppFile = async (appFile: File) => {
try {
return getManifestFromZippedApp(appFile);
Expand All @@ -122,19 +108,13 @@ export const useInstallApp = (file: File, url: string): { install: () => void; i
};

const install = async () => {
let appFile: File | undefined;

setInstalling(true);

if (!appCountQuery.data) {
return cancelAction();
}

if (!file) {
appFile = await getAppFile();
} else {
appFile = file;
}
const appFile = file;

if (!appFile) {
return cancelAction();
Expand All @@ -157,7 +137,7 @@ export const useInstallApp = (file: File, url: string): { install: () => void; i
limit={appCountQuery.data.limit}
appName={manifest.name}
handleClose={cancelAction}
handleConfirm={() => uploadFile(appFile as File, manifest)}
handleConfirm={() => uploadFile(appFile, manifest)}
handleEnableUnlimitedApps={() => {
openExternalLink(manageSubscriptionUrl);
setModal(null);
Expand Down
6 changes: 0 additions & 6 deletions apps/meteor/ee/server/apps/communication/rest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -328,12 +328,6 @@ export class AppsRestApi {
orchestrator.getRocketChatLogger().error('Error getting the app from url:', e.response.data);
return API.v1.internalError();
}

if (this.bodyParams.downloadOnly) {
apiDeprecationLogger.parameter(this.request.route, 'downloadOnly', '7.0.0', this.response);

return API.v1.success({ buff });
}
} else if ('appId' in this.bodyParams && this.bodyParams.appId && this.bodyParams.marketplace && this.bodyParams.version) {
const baseUrl = orchestrator.getMarketplaceUrl();

Expand Down
3 changes: 1 addition & 2 deletions packages/rest-typings/src/apps/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,9 +248,8 @@ export type AppsEndpoints = {
version: string;
permissionsGranted?: IPermission[];
url?: string;
downloadOnly?: boolean;
}
| { url: string; downloadOnly?: boolean },
| { url: string },
):
| {
app: App;
Expand Down

0 comments on commit 50abbe6

Please sign in to comment.