From 7fb8cc1c3984b875097d6761da08539e9df8cea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Malfait?= Date: Wed, 11 Mar 2026 11:40:00 +0100 Subject: [PATCH] Improve apps settings UI and remove unused tarball upload code (#18549) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Improves the Developer Tab in Settings > Applications: adds source-type badges (Dev / Npm / Internal), better empty state with `yarn twenty app:dev` CLI command, renames sections to "Create & Develop" and "Your Apps" - Simplifies the Distribution Tab: only shows marketplace section for npm-sourced apps, removes the manual `isListed` toggle (now managed automatically by the catalog sync cron) - Removes dead frontend code: `installApplication` mutation (unused — installs go through `installMarketplaceApp`), `uploadAppTarball` mutation/hook, and `SettingsUploadTarballModal` ## Test plan - [ ] Navigate to Settings > Applications > Developer tab: verify badges show correctly, empty state shows CLI command - [ ] Create/view a LOCAL app registration: verify Distribution tab does NOT show marketplace section - [ ] Create/view an NPM app registration: verify Distribution tab shows marketplace section with Featured toggle - [ ] Verify no references to upload tarball or install application remain in the UI Made with [Cursor](https://cursor.com) --- .../graphql/mutations/installApplication.ts | 7 - .../graphql/mutations/uploadAppTarball.ts | 11 -- .../marketplace/hooks/useUploadAppTarball.ts | 61 -------- .../components/SettingsUploadTarballModal.tsx | 132 ---------------- ...ApplicationRegistrationDistributionTab.tsx | 91 ++++------- .../tabs/SettingsApplicationsDeveloperTab.tsx | 141 +++++++++++------- 6 files changed, 114 insertions(+), 329 deletions(-) delete mode 100644 packages/twenty-front/src/modules/marketplace/graphql/mutations/installApplication.ts delete mode 100644 packages/twenty-front/src/modules/marketplace/graphql/mutations/uploadAppTarball.ts delete mode 100644 packages/twenty-front/src/modules/marketplace/hooks/useUploadAppTarball.ts delete mode 100644 packages/twenty-front/src/pages/settings/applications/components/SettingsUploadTarballModal.tsx diff --git a/packages/twenty-front/src/modules/marketplace/graphql/mutations/installApplication.ts b/packages/twenty-front/src/modules/marketplace/graphql/mutations/installApplication.ts deleted file mode 100644 index e7731d94a7..0000000000 --- a/packages/twenty-front/src/modules/marketplace/graphql/mutations/installApplication.ts +++ /dev/null @@ -1,7 +0,0 @@ -import gql from 'graphql-tag'; - -export const INSTALL_APPLICATION = gql` - mutation InstallApplication($appRegistrationId: String!, $version: String) { - installApplication(appRegistrationId: $appRegistrationId, version: $version) - } -`; diff --git a/packages/twenty-front/src/modules/marketplace/graphql/mutations/uploadAppTarball.ts b/packages/twenty-front/src/modules/marketplace/graphql/mutations/uploadAppTarball.ts deleted file mode 100644 index 05d3911683..0000000000 --- a/packages/twenty-front/src/modules/marketplace/graphql/mutations/uploadAppTarball.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { gql } from '@apollo/client'; - -export const UPLOAD_APP_TARBALL = gql` - mutation UploadAppTarball($file: Upload!, $universalIdentifier: String) { - uploadAppTarball(file: $file, universalIdentifier: $universalIdentifier) { - id - universalIdentifier - name - } - } -`; diff --git a/packages/twenty-front/src/modules/marketplace/hooks/useUploadAppTarball.ts b/packages/twenty-front/src/modules/marketplace/hooks/useUploadAppTarball.ts deleted file mode 100644 index 87ed302d9c..0000000000 --- a/packages/twenty-front/src/modules/marketplace/hooks/useUploadAppTarball.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; -import { useMutation } from '@apollo/client'; -import { t } from '@lingui/core/macro'; -import { useState } from 'react'; -import { isDefined } from 'twenty-shared/utils'; -import { UPLOAD_APP_TARBALL } from '~/modules/marketplace/graphql/mutations/uploadAppTarball'; - -type UploadResult = - | { - success: true; - registrationId: string; - universalIdentifier: string; - } - | { - success: false; - }; - -export const useUploadAppTarball = () => { - const [uploadAppTarball] = useMutation(UPLOAD_APP_TARBALL); - const { enqueueErrorSnackBar } = useSnackBar(); - const [isUploading, setIsUploading] = useState(false); - - const upload = async (file: File): Promise => { - setIsUploading(true); - - try { - const result = await uploadAppTarball({ - variables: { file }, - }); - - const registration = result.data?.uploadAppTarball; - - if ( - !isDefined(registration?.id) || - !isDefined(registration?.universalIdentifier) - ) { - enqueueErrorSnackBar({ message: t`Upload failed.` }); - - return { success: false }; - } - - return { - success: true, - registrationId: registration.id, - universalIdentifier: registration.universalIdentifier, - }; - } catch (error) { - const graphqlMessage = error instanceof Error ? error.message : undefined; - - enqueueErrorSnackBar({ - message: graphqlMessage ?? t`Failed to upload tarball.`, - }); - - return { success: false }; - } finally { - setIsUploading(false); - } - }; - - return { upload, isUploading }; -}; diff --git a/packages/twenty-front/src/pages/settings/applications/components/SettingsUploadTarballModal.tsx b/packages/twenty-front/src/pages/settings/applications/components/SettingsUploadTarballModal.tsx deleted file mode 100644 index 4d00c028b9..0000000000 --- a/packages/twenty-front/src/pages/settings/applications/components/SettingsUploadTarballModal.tsx +++ /dev/null @@ -1,132 +0,0 @@ -import { styled } from '@linaria/react'; -import { useRef } from 'react'; - -import { FIND_MANY_APPLICATION_REGISTRATIONS } from '@/settings/application-registrations/graphql/queries/findManyApplicationRegistrations'; -import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; -import { useModal } from '@/ui/layout/modal/hooks/useModal'; -import { useApolloClient, useMutation } from '@apollo/client'; -import { useLingui } from '@lingui/react/macro'; -import { t } from '@lingui/core/macro'; -import { isDefined } from 'twenty-shared/utils'; -import { H1Title, H1TitleFontColor } from 'twenty-ui/display'; -import { SectionAlignment, SectionFontColor } from 'twenty-ui/layout'; -import { INSTALL_APPLICATION } from '~/modules/marketplace/graphql/mutations/installApplication'; -import { useUploadAppTarball } from '~/modules/marketplace/hooks/useUploadAppTarball'; -import { - StyledAppModal, - StyledAppModalButton, - StyledAppModalSection, - StyledAppModalTitle, -} from '~/pages/settings/applications/components/SettingsAppModalLayout'; - -export const UPLOAD_TARBALL_MODAL_ID = 'upload-tarball-modal'; - -const StyledFileInput = styled.input` - display: none; -`; - -export const SettingsUploadTarballModal = () => { - const { t: tFn } = useLingui(); - const { closeModal } = useModal(); - const { upload, isUploading } = useUploadAppTarball(); - const [installApplication] = useMutation(INSTALL_APPLICATION); - const { enqueueSuccessSnackBar, enqueueErrorSnackBar } = useSnackBar(); - const apolloClient = useApolloClient(); - const fileInputRef = useRef(null); - - const handleSelectFile = () => { - fileInputRef.current?.click(); - }; - - const handleFileChange = async ( - event: React.ChangeEvent, - ) => { - const file = event.target.files?.[0]; - - if (!isDefined(file)) { - return; - } - - try { - const uploadResult = await upload(file); - - if (!uploadResult.success) { - return; - } - - const registrationId = uploadResult.registrationId; - - if (isDefined(registrationId)) { - try { - await installApplication({ - variables: { appRegistrationId: registrationId }, - }); - enqueueSuccessSnackBar({ - message: t`Application installed successfully.`, - }); - } catch { - enqueueErrorSnackBar({ - message: t`Tarball uploaded but installation failed.`, - }); - } - } - - await apolloClient.refetchQueries({ - include: [FIND_MANY_APPLICATION_REGISTRATIONS], - }); - closeModal(UPLOAD_TARBALL_MODAL_ID); - } finally { - if (isDefined(fileInputRef.current)) { - fileInputRef.current.value = ''; - } - } - }; - - const handleCancel = () => { - closeModal(UPLOAD_TARBALL_MODAL_ID); - }; - - return ( - - - - - - {tFn`Select a .tar.gz application package to upload and install.`} - - - - - - - - ); -}; diff --git a/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationRegistrationDistributionTab.tsx b/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationRegistrationDistributionTab.tsx index 1a705864c5..f9736e2404 100644 --- a/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationRegistrationDistributionTab.tsx +++ b/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationRegistrationDistributionTab.tsx @@ -1,11 +1,7 @@ import { SettingsAdminTableCard } from '@/settings/admin-panel/components/SettingsAdminTableCard'; import { SettingsOptionCardContentToggle } from '@/settings/components/SettingsOptions/SettingsOptionCardContentToggle'; -import { UPDATE_APPLICATION_REGISTRATION } from '@/settings/application-registrations/graphql/mutations/updateApplicationRegistration'; import { FIND_APPLICATION_REGISTRATION_STATS } from '@/settings/application-registrations/graphql/queries/findApplicationRegistrationStats'; -import { FIND_MANY_APPLICATION_REGISTRATIONS } from '@/settings/application-registrations/graphql/queries/findManyApplicationRegistrations'; -import { FIND_ONE_APPLICATION_REGISTRATION } from '@/settings/application-registrations/graphql/queries/findOneApplicationRegistration'; -import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; -import { useMutation, useQuery } from '@apollo/client'; +import { useQuery } from '@apollo/client'; import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { @@ -35,7 +31,6 @@ export const SettingsApplicationRegistrationDistributionTab = ({ registration: ApplicationRegistrationData; }) => { const { t } = useLingui(); - const { enqueueErrorSnackBar } = useSnackBar(); const applicationRegistrationId = registration.id; @@ -47,32 +42,6 @@ export const SettingsApplicationRegistrationDistributionTab = ({ skip: !applicationRegistrationId, }); - const [updateRegistration] = useMutation(UPDATE_APPLICATION_REGISTRATION, { - refetchQueries: [ - FIND_ONE_APPLICATION_REGISTRATION, - FIND_MANY_APPLICATION_REGISTRATIONS, - ], - }); - - const handleToggleListed = async () => { - try { - await updateRegistration({ - variables: { - input: { - id: applicationRegistrationId, - update: { - isListed: !registration.isListed, - }, - }, - }, - }); - } catch { - enqueueErrorSnackBar({ - message: t`Error updating marketplace listing`, - }); - } - }; - const marketplacePageUrl = getSettingsPath( SettingsPath.AvailableApplicationDetail, { @@ -111,41 +80,31 @@ export const SettingsApplicationRegistrationDistributionTab = ({ return ( <> -
- - - + - {}} - disabled - /> - - -
+ + {}} + disabled + /> + + +