From 435073e9c59e50a8553afb3ead6611a1950258ee Mon Sep 17 00:00:00 2001 From: martmull Date: Tue, 7 Jul 2026 17:05:54 +0200 Subject: [PATCH] Display featured applications in marketplace (#22635) ## After image image image - Remove IS_MARKETPLACE_SETTING_TAB_VISIBLE feature flag - add vetted toggle in admin app tab - added people data labs, last contact and call recorder to default vetted applications Review in cubic --------- Co-authored-by: prastoin --- .../public/call-recorder/package.json | 2 +- .../call-recorder/src/application-config.ts | 1 + .../public/people-data-labs/package.json | 2 +- .../src/application-config.ts | 1 + .../public/twenty-last-contact/package.json | 2 +- .../src/application-config.ts | 1 + .../src/metadata/generated/schema.graphql | 2 +- .../src/metadata/generated/schema.ts | 5 +- .../src/metadata/generated/types.ts | 3 + .../src/generated-admin/graphql.ts | 2 +- .../src/generated-metadata/graphql.ts | 2 +- ...nApplicationRegistrationGeneralToggles.tsx | 25 +++- .../applications/SettingsApplications.tsx | 20 +-- .../tabs/SettingsApplicationsAvailableTab.tsx | 72 ++++++++--- .../tabs/SettingsApplicationsDeveloperTab.tsx | 118 +----------------- ...is-featured-on-application-registration.ts | 35 ++++++ .../instance-commands.constant.ts | 2 + ...rketplace-curated-applications.constant.ts | 4 - ...ketplace-featured-applications.constant.ts | 17 +++ .../application-registration.service.ts | 10 +- .../update-application-registration.input.ts | 5 + .../workspace-entity-manager.spec.ts | 1 - .../core/utils/seed-feature-flags.util.ts | 5 - .../twenty-shared/src/types/FeatureFlagKey.ts | 1 - 24 files changed, 161 insertions(+), 177 deletions(-) create mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/2-19/2-19-instance-command-slow-1783120000000-backfill-is-featured-on-application-registration.ts delete mode 100644 packages/twenty-server/src/engine/core-modules/application/application-marketplace/constants/marketplace-curated-applications.constant.ts create mode 100644 packages/twenty-server/src/engine/core-modules/application/application-marketplace/constants/marketplace-featured-applications.constant.ts diff --git a/packages/twenty-apps/public/call-recorder/package.json b/packages/twenty-apps/public/call-recorder/package.json index 73bdfaef63..0044d27611 100644 --- a/packages/twenty-apps/public/call-recorder/package.json +++ b/packages/twenty-apps/public/call-recorder/package.json @@ -1,6 +1,6 @@ { "name": "@twentyhq/call-recorder", - "version": "1.0.7", + "version": "1.0.8", "license": "MIT", "engines": { "node": "^24.5.0", diff --git a/packages/twenty-apps/public/call-recorder/src/application-config.ts b/packages/twenty-apps/public/call-recorder/src/application-config.ts index 69be0d5cb0..3564df8111 100644 --- a/packages/twenty-apps/public/call-recorder/src/application-config.ts +++ b/packages/twenty-apps/public/call-recorder/src/application-config.ts @@ -43,6 +43,7 @@ export default defineApplication({ displayName: APP_DISPLAY_NAME, description: APP_DESCRIPTION, logoUrl: 'public/logo.svg', + category: 'Productivity', author: 'Twenty', screenshots: ['public/gallery/call-recorder-cover.png'], applicationVariables: { diff --git a/packages/twenty-apps/public/people-data-labs/package.json b/packages/twenty-apps/public/people-data-labs/package.json index a0ccb7e197..0a5352c7b5 100644 --- a/packages/twenty-apps/public/people-data-labs/package.json +++ b/packages/twenty-apps/public/people-data-labs/package.json @@ -1,6 +1,6 @@ { "name": "@twentyhq/people-data-labs", - "version": "1.0.4", + "version": "1.0.5", "description": "People Data Labs enrichment app for Twenty", "license": "MIT", "engines": { diff --git a/packages/twenty-apps/public/people-data-labs/src/application-config.ts b/packages/twenty-apps/public/people-data-labs/src/application-config.ts index 5750fb7f3f..427d043b48 100644 --- a/packages/twenty-apps/public/people-data-labs/src/application-config.ts +++ b/packages/twenty-apps/public/people-data-labs/src/application-config.ts @@ -7,6 +7,7 @@ export default defineApplication({ displayName: 'People Data Labs', description: 'Enrich People and Companies with People Data Labs data.', logoUrl: 'public/people-data-labs-icon.png', + category: 'Enrichment', author: 'Twenty', screenshots: ['public/gallery/cover.png'], serverVariables: { diff --git a/packages/twenty-apps/public/twenty-last-contact/package.json b/packages/twenty-apps/public/twenty-last-contact/package.json index 8537a4cb1b..51cdfb4764 100644 --- a/packages/twenty-apps/public/twenty-last-contact/package.json +++ b/packages/twenty-apps/public/twenty-last-contact/package.json @@ -1,6 +1,6 @@ { "name": "@twentyhq/last-contact", - "version": "1.0.2", + "version": "1.0.3", "license": "MIT", "engines": { "node": "^24.5.0", diff --git a/packages/twenty-apps/public/twenty-last-contact/src/application-config.ts b/packages/twenty-apps/public/twenty-last-contact/src/application-config.ts index b2e367a322..891d82a3df 100644 --- a/packages/twenty-apps/public/twenty-last-contact/src/application-config.ts +++ b/packages/twenty-apps/public/twenty-last-contact/src/application-config.ts @@ -10,6 +10,7 @@ export default defineApplication({ universalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER, logoUrl: 'public/logo.png', author: 'Twenty', + category: 'Productivity', screenshots: ['public/gallery/cover.png'], displayName: APP_DISPLAY_NAME, description: APP_DESCRIPTION, diff --git a/packages/twenty-client-sdk/src/metadata/generated/schema.graphql b/packages/twenty-client-sdk/src/metadata/generated/schema.graphql index 5efeff3ea2..1859539512 100644 --- a/packages/twenty-client-sdk/src/metadata/generated/schema.graphql +++ b/packages/twenty-client-sdk/src/metadata/generated/schema.graphql @@ -1752,7 +1752,6 @@ type FeatureFlag { enum FeatureFlagKey { IS_UNIQUE_INDEXES_ENABLED IS_JSON_FILTER_ENABLED - IS_MARKETPLACE_SETTING_TAB_VISIBLE IS_EMAIL_GROUP_ENABLED IS_JUNCTION_RELATIONS_ENABLED IS_REST_METADATA_API_NEW_FORMAT_DIRECT @@ -4326,6 +4325,7 @@ input UpdateApplicationRegistrationPayload { oAuthScopes: [String!] isListed: Boolean isPreInstalled: Boolean + isFeatured: Boolean } input CreateApplicationRegistrationVariableInput { diff --git a/packages/twenty-client-sdk/src/metadata/generated/schema.ts b/packages/twenty-client-sdk/src/metadata/generated/schema.ts index 75aad50c8d..233f977f5f 100644 --- a/packages/twenty-client-sdk/src/metadata/generated/schema.ts +++ b/packages/twenty-client-sdk/src/metadata/generated/schema.ts @@ -1396,7 +1396,7 @@ export interface FeatureFlag { __typename: 'FeatureFlag' } -export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' | 'IS_EMAIL_GROUP_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT' | 'IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED' | 'IS_SETTINGS_DISCOVERY_HERO_ENABLED' | 'IS_MESSAGING_CALENDAR_WEBHOOK_ENABLED' +export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_EMAIL_GROUP_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT' | 'IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED' | 'IS_SETTINGS_DISCOVERY_HERO_ENABLED' | 'IS_MESSAGING_CALENDAR_WEBHOOK_ENABLED' export interface WorkspaceUrls { customUrl?: Scalars['String'] @@ -6575,7 +6575,7 @@ export interface CreateApplicationRegistrationInput {name: Scalars['String'],uni export interface UpdateApplicationRegistrationInput {id: Scalars['String'],update: UpdateApplicationRegistrationPayload} -export interface UpdateApplicationRegistrationPayload {name?: (Scalars['String'] | null),oAuthRedirectUris?: (Scalars['String'][] | null),oAuthScopes?: (Scalars['String'][] | null),isListed?: (Scalars['Boolean'] | null),isPreInstalled?: (Scalars['Boolean'] | null)} +export interface UpdateApplicationRegistrationPayload {name?: (Scalars['String'] | null),oAuthRedirectUris?: (Scalars['String'][] | null),oAuthScopes?: (Scalars['String'][] | null),isListed?: (Scalars['Boolean'] | null),isPreInstalled?: (Scalars['Boolean'] | null),isFeatured?: (Scalars['Boolean'] | null)} export interface CreateApplicationRegistrationVariableInput {applicationRegistrationId: Scalars['String'],key: Scalars['String'],value: Scalars['String'],description?: (Scalars['String'] | null),isSecret?: (Scalars['Boolean'] | null)} @@ -9238,7 +9238,6 @@ export const enumLogicFunctionExecutionStatus = { export const enumFeatureFlagKey = { IS_UNIQUE_INDEXES_ENABLED: 'IS_UNIQUE_INDEXES_ENABLED' as const, IS_JSON_FILTER_ENABLED: 'IS_JSON_FILTER_ENABLED' as const, - IS_MARKETPLACE_SETTING_TAB_VISIBLE: 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' as const, IS_EMAIL_GROUP_ENABLED: 'IS_EMAIL_GROUP_ENABLED' as const, IS_JUNCTION_RELATIONS_ENABLED: 'IS_JUNCTION_RELATIONS_ENABLED' as const, IS_REST_METADATA_API_NEW_FORMAT_DIRECT: 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT' as const, diff --git a/packages/twenty-client-sdk/src/metadata/generated/types.ts b/packages/twenty-client-sdk/src/metadata/generated/types.ts index e75f5a026f..6918aa6cf7 100644 --- a/packages/twenty-client-sdk/src/metadata/generated/types.ts +++ b/packages/twenty-client-sdk/src/metadata/generated/types.ts @@ -11096,6 +11096,9 @@ export default { "isPreInstalled": [ 6 ], + "isFeatured": [ + 6 + ], "__typename": [ 1 ] diff --git a/packages/twenty-front/src/generated-admin/graphql.ts b/packages/twenty-front/src/generated-admin/graphql.ts index b2dea28a89..02cf3c6f47 100644 --- a/packages/twenty-front/src/generated-admin/graphql.ts +++ b/packages/twenty-front/src/generated-admin/graphql.ts @@ -317,7 +317,6 @@ export enum FeatureFlagKey { IS_JSON_FILTER_ENABLED = 'IS_JSON_FILTER_ENABLED', IS_JUNCTION_RELATIONS_ENABLED = 'IS_JUNCTION_RELATIONS_ENABLED', IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED = 'IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED', - IS_MARKETPLACE_SETTING_TAB_VISIBLE = 'IS_MARKETPLACE_SETTING_TAB_VISIBLE', IS_MESSAGING_CALENDAR_WEBHOOK_ENABLED = 'IS_MESSAGING_CALENDAR_WEBHOOK_ENABLED', IS_REST_METADATA_API_NEW_FORMAT_DIRECT = 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT', IS_SETTINGS_DISCOVERY_HERO_ENABLED = 'IS_SETTINGS_DISCOVERY_HERO_ENABLED', @@ -834,6 +833,7 @@ export type UpdateApplicationRegistrationInput = { }; export type UpdateApplicationRegistrationPayload = { + isFeatured?: InputMaybe; isListed?: InputMaybe; isPreInstalled?: InputMaybe; name?: InputMaybe; diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index 38ef462868..8b4740c8c6 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -1756,7 +1756,6 @@ export enum FeatureFlagKey { IS_JSON_FILTER_ENABLED = 'IS_JSON_FILTER_ENABLED', IS_JUNCTION_RELATIONS_ENABLED = 'IS_JUNCTION_RELATIONS_ENABLED', IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED = 'IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED', - IS_MARKETPLACE_SETTING_TAB_VISIBLE = 'IS_MARKETPLACE_SETTING_TAB_VISIBLE', IS_MESSAGING_CALENDAR_WEBHOOK_ENABLED = 'IS_MESSAGING_CALENDAR_WEBHOOK_ENABLED', IS_REST_METADATA_API_NEW_FORMAT_DIRECT = 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT', IS_SETTINGS_DISCOVERY_HERO_ENABLED = 'IS_SETTINGS_DISCOVERY_HERO_ENABLED', @@ -5347,6 +5346,7 @@ export type UpdateApplicationRegistrationInput = { }; export type UpdateApplicationRegistrationPayload = { + isFeatured?: InputMaybe; isListed?: InputMaybe; isPreInstalled?: InputMaybe; name?: InputMaybe; diff --git a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminApplicationRegistrationGeneralToggles.tsx b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminApplicationRegistrationGeneralToggles.tsx index f0417687c0..501e93810e 100644 --- a/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminApplicationRegistrationGeneralToggles.tsx +++ b/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminApplicationRegistrationGeneralToggles.tsx @@ -1,7 +1,12 @@ import { Section } from 'twenty-ui/layout'; import { AppTooltip, Card, TooltipDelay } from 'twenty-ui/surfaces'; import { SettingsOptionCardContentToggle } from '@/settings/components/SettingsOptions/SettingsOptionCardContentToggle'; -import { IconArrowBarToDown, IconPinned, IconReload } from 'twenty-ui/icon'; +import { + IconArrowBarToDown, + IconPinned, + IconReload, + IconShield, +} from 'twenty-ui/icon'; import { Button } from 'twenty-ui/input'; import { H2Title } from 'twenty-ui/typography'; import { type ApplicationRegistration } from '~/generated-metadata/graphql'; @@ -104,6 +109,24 @@ export const SettingsAdminApplicationRegistrationGeneralToggles = ({ } /> + + + updateRegistration({ + variables: { + input: { + id: registration.id, + update: { isFeatured: checked }, + }, + }, + }) + } + /> + { PermissionFlagType.API_KEYS_AND_WEBHOOKS, ); - const isMarketplaceSettingTabVisible = useIsFeatureEnabled( - FeatureFlagKey.IS_MARKETPLACE_SETTING_TAB_VISIBLE, - ); - const tabs = [ - ...(isMarketplaceSettingTabVisible - ? [{ id: 'marketplace', title: t`Marketplace`, Icon: IconDownload }] - : []), + { id: 'marketplace', title: t`Marketplace`, Icon: IconDownload }, { id: 'installed', title: t`Installed`, Icon: IconApps }, ...(hasDeveloperAccess ? [{ id: 'developer', title: t`Developer`, Icon: IconCode }] @@ -58,11 +48,7 @@ export const SettingsApplications = () => { case 'developer': return ; default: - return isMarketplaceSettingTabVisible ? ( - - ) : ( - - ); + return ; } }; diff --git a/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationsAvailableTab.tsx b/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationsAvailableTab.tsx index ba3caf2057..d331e0463f 100644 --- a/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationsAvailableTab.tsx +++ b/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationsAvailableTab.tsx @@ -5,6 +5,7 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; import { type ReactNode, useState } from 'react'; +import { InlineBanner } from 'twenty-ui/feedback'; import { IconSparkles } from 'twenty-ui/icon'; import { SearchInput } from 'twenty-ui/input'; import { Section } from 'twenty-ui/layout'; @@ -17,6 +18,16 @@ const StyledSearchInputContainer = styled.div` padding-bottom: ${themeCssVariables.spacing[2]}; `; +const StyledContentContainer = styled.div` + display: flex; + flex-direction: column; + gap: ${themeCssVariables.spacing[3]}; +`; + +const StyledNotFeaturedContainer = styled.div` + margin-top: ${themeCssVariables.spacing[3]}; +`; + const StyledCardsGrid = styled.div` display: grid; gap: ${themeCssVariables.spacing[3]}; @@ -56,14 +67,13 @@ export const SettingsApplicationsAvailableTab = () => { }) : marketplaceApps; - const filteredApplications = showFeaturedOnly - ? textFilteredApplications.filter((application) => application.isFeatured) - : textFilteredApplications; + const featuredApplications = textFilteredApplications.filter( + (application) => application.isFeatured, + ); - const nonFeaturedCount = showFeaturedOnly - ? textFilteredApplications.filter((application) => !application.isFeatured) - .length - : 0; + const nonFeaturedApplications = textFilteredApplications.filter( + (application) => !application.isFeatured, + ); if (isLoading) { return ( @@ -74,7 +84,11 @@ export const SettingsApplicationsAvailableTab = () => { } const showNonFeaturedHint = - filteredApplications.length === 0 && nonFeaturedCount > 0; + showFeaturedOnly && + featuredApplications.length === 0 && + nonFeaturedApplications.length > 0; + + const hasNoApplications = textFilteredApplications.length === 0; return (
@@ -109,10 +123,11 @@ export const SettingsApplicationsAvailableTab = () => { /> - {filteredApplications.length === 0 ? ( + {hasNoApplications || + (showFeaturedOnly && featuredApplications.length === 0) ? ( {showNonFeaturedHint - ? t`No featured applications found. ${nonFeaturedCount} non-featured result(s) available — ` + ? t`No featured applications found. ${nonFeaturedApplications.length} non-featured result(s) available — ` : t`No applications available`} {showNonFeaturedHint && ( setShowFeaturedOnly(false)}> @@ -121,14 +136,35 @@ export const SettingsApplicationsAvailableTab = () => { )} ) : ( - - {filteredApplications.map((application) => ( - - ))} - + + {featuredApplications.length > 0 && ( + + {featuredApplications.map((application) => ( + + ))} + + )} + + {!showFeaturedOnly && nonFeaturedApplications.length > 0 && ( + + + + {nonFeaturedApplications.map((application) => ( + + ))} + + + )} + )}
); diff --git a/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationsDeveloperTab.tsx b/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationsDeveloperTab.tsx index 9fecd79c08..3650c264bb 100644 --- a/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationsDeveloperTab.tsx +++ b/packages/twenty-front/src/pages/settings/applications/tabs/SettingsApplicationsDeveloperTab.tsx @@ -1,26 +1,18 @@ import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; -import { SettingsEmptyPlaceholder } from '@/settings/components/SettingsEmptyPlaceholder'; -import { - StyledActionTableCell, - StyledNameTableCell, -} from '@/settings/data-model/object-details/components/SettingsObjectItemTableRowStyledComponents'; import { getDocumentationUrl } from '@/support/utils/getDocumentationUrl'; import { Table } from '@/ui/layout/table/components/Table'; -import { TableCell } from '@/ui/layout/table/components/TableCell'; import { TableHeader } from '@/ui/layout/table/components/TableHeader'; import { TableRow } from '@/ui/layout/table/components/TableRow'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { useQuery } from '@apollo/client/react'; import { styled } from '@linaria/react'; import { useLingui } from '@lingui/react/macro'; -import { useContext, useMemo, useState } from 'react'; +import { useContext, useState } from 'react'; import { ThemeContext, themeCssVariables } from 'twenty-ui/theme-constants'; -import { FeatureFlagKey, SettingsPath } from 'twenty-shared/types'; +import { SettingsPath } from 'twenty-shared/types'; import { getSettingsPath } from 'twenty-shared/utils'; import { CommandBlock } from 'twenty-ui/data-display'; -import { InlineBanner } from 'twenty-ui/feedback'; import { IconArrowUpRight, IconChevronRight, IconCopy } from 'twenty-ui/icon'; -import { OverflowingTextWithTooltip } from 'twenty-ui/surfaces'; import { H2Title } from 'twenty-ui/typography'; import { Button, SearchInput } from 'twenty-ui/input'; import { Section } from 'twenty-ui/layout'; @@ -29,14 +21,10 @@ import { FindManyApplicationRegistrationsDocument, } from '~/generated-metadata/graphql'; import { useCopyToClipboard } from '~/hooks/useCopyToClipboard'; -import { useMarketplaceApps } from '~/modules/marketplace/hooks/useMarketplaceApps'; import { APPLICATION_TABLE_ROW_GRID_TEMPLATE_COLUMNS, SettingsApplicationTableRow, } from '~/pages/settings/applications/components/SettingsApplicationTableRow'; -import { getApplicationDescriptionSummary } from '~/pages/settings/applications/utils/getApplicationDescriptionSummary'; -import { ApplicationDisplay } from '@/applications/components/ApplicationDisplay'; -import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; const StyledButtonContainer = styled.div` display: flex; @@ -53,43 +41,17 @@ const StyledTableRowsContainer = styled.div` padding: ${themeCssVariables.spacing[2]} 0; `; -const NPM_PACKAGES_GRID_COLUMNS = '200px 1fr 36px'; - export const SettingsApplicationsDeveloperTab = () => { const { t } = useLingui(); const { theme } = useContext(ThemeContext); const currentWorkspaceMember = useAtomStateValue(currentWorkspaceMemberState); - const [displayNotVettedApps, setDisplayNotVettedApps] = useState(false); - const { copyToClipboard } = useCopyToClipboard(); const { data } = useQuery(FindManyApplicationRegistrationsDocument); - const isMarketplaceSettingTabVisible = useIsFeatureEnabled( - FeatureFlagKey.IS_MARKETPLACE_SETTING_TAB_VISIBLE, - ); - - const [marketplaceAppSearchTerm, setMarketplaceAppSearchTerm] = useState(''); - const [myAppsSearchTerm, setMyAppsSearchTerm] = useState(''); - const { data: marketplaceApps } = useMarketplaceApps(); - - const filteredMarketplaceApps = useMemo(() => { - if (!marketplaceAppSearchTerm) { - return marketplaceApps; - } - - const lowerSearch = marketplaceAppSearchTerm.toLowerCase(); - - return marketplaceApps.filter( - (application) => - application.name.toLowerCase().includes(lowerSearch) || - application.description.toLowerCase().includes(lowerSearch), - ); - }, [marketplaceApps, marketplaceAppSearchTerm]); - const registrations: ApplicationRegistrationListItemFragment[] = data?.findManyApplicationRegistrations ?? []; @@ -191,82 +153,6 @@ export const SettingsApplicationsDeveloperTab = () => { )} - - {!isMarketplaceSettingTabVisible && ( -
- - setDisplayNotVettedApps(true), - }} - /> - {displayNotVettedApps && ( - <> - - - - {filteredMarketplaceApps.length === 0 ? ( - {t`No application found`} - ) : ( - - - {t`Name`} - {t`Description`} - - - - {filteredMarketplaceApps.map((application) => ( - - - - - - - - - - - - ))} - -
- )} - - )} -
- )} ); }; diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/2-19/2-19-instance-command-slow-1783120000000-backfill-is-featured-on-application-registration.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/2-19/2-19-instance-command-slow-1783120000000-backfill-is-featured-on-application-registration.ts new file mode 100644 index 0000000000..955a78f548 --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/2-19/2-19-instance-command-slow-1783120000000-backfill-is-featured-on-application-registration.ts @@ -0,0 +1,35 @@ +import { DataSource, QueryRunner } from 'typeorm'; + +import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator'; +import { SlowInstanceCommand } from 'src/engine/core-modules/upgrade/interfaces/slow-instance-command.interface'; + +const FEATURED_UNIVERSAL_IDENTIFIERS = [ + '8da4b8b5-5edf-4880-b51f-ab6e679ec617', + '4a1178c1-3535-4a47-b592-231d3216b36f', + '66a504cc-0a75-410e-a43f-cdeae1db1522' +]; + +@RegisteredInstanceCommand('2.19.0', 1783120000000, { type: 'slow' }) +export class BackfillIsFeaturedOnApplicationRegistrationSlowInstanceCommand + implements SlowInstanceCommand +{ + async runDataMigration(dataSource: DataSource): Promise { + await dataSource.query( + `UPDATE "core"."applicationRegistration" + SET "isFeatured" = true + WHERE "universalIdentifier" = ANY($1::uuid[])`, + [FEATURED_UNIVERSAL_IDENTIFIERS], + ); + } + + public async up(_queryRunner: QueryRunner): Promise {} + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `UPDATE "core"."applicationRegistration" + SET "isFeatured" = false + WHERE "universalIdentifier" = ANY($1::uuid[])`, + [FEATURED_UNIVERSAL_IDENTIFIERS], + ); + } +} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/instance-commands.constant.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/instance-commands.constant.ts index cc5d934d7b..da650ab15f 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/instance-commands.constant.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/instance-commands.constant.ts @@ -98,6 +98,7 @@ import { AddLogoToApplicationRegistrationFastInstanceCommand } from './2-19/2-19 import { BackfillLogoOnApplicationRegistrationSlowInstanceCommand } from './2-19/2-19-instance-command-slow-1783069673191-backfill-logo-on-application-registration'; import { AddDisplayFieldsToApplicationRegistrationFastInstanceCommand } from './2-19/2-19-instance-command-fast-1783073776590-add-display-fields-to-application-registration'; import { BackfillDisplayFieldsOnApplicationRegistrationSlowInstanceCommand } from './2-19/2-19-instance-command-slow-1783073776591-backfill-display-fields-on-application-registration'; +import { BackfillIsFeaturedOnApplicationRegistrationSlowInstanceCommand } from './2-19/2-19-instance-command-slow-1783120000000-backfill-is-featured-on-application-registration'; export const INSTANCE_COMMANDS = [ AddViewFieldGroupIdIndexOnViewFieldFastInstanceCommand, @@ -198,4 +199,5 @@ export const INSTANCE_COMMANDS = [ BackfillDisplayFieldsOnApplicationRegistrationSlowInstanceCommand, AddStatusToFileFastInstanceCommand, AddPendingMimeCheckToFileFastInstanceCommand, + BackfillIsFeaturedOnApplicationRegistrationSlowInstanceCommand, ]; diff --git a/packages/twenty-server/src/engine/core-modules/application/application-marketplace/constants/marketplace-curated-applications.constant.ts b/packages/twenty-server/src/engine/core-modules/application/application-marketplace/constants/marketplace-curated-applications.constant.ts deleted file mode 100644 index 7f4a34b34a..0000000000 --- a/packages/twenty-server/src/engine/core-modules/application/application-marketplace/constants/marketplace-curated-applications.constant.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const MARKETPLACE_CURATED_APPLICATIONS: { - universalIdentifier: string; - position?: number; -}[] = []; diff --git a/packages/twenty-server/src/engine/core-modules/application/application-marketplace/constants/marketplace-featured-applications.constant.ts b/packages/twenty-server/src/engine/core-modules/application/application-marketplace/constants/marketplace-featured-applications.constant.ts new file mode 100644 index 0000000000..1080f0b4e7 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/application/application-marketplace/constants/marketplace-featured-applications.constant.ts @@ -0,0 +1,17 @@ +export const MARKETPLACE_FEATURED_APPLICATIONS: { + universalIdentifier: string; + position?: number; +}[] = [ + { + universalIdentifier: '8da4b8b5-5edf-4880-b51f-ab6e679ec617', + position: 1, + }, + { + universalIdentifier: '4a1178c1-3535-4a47-b592-231d3216b36f', + position: 2, + }, + { + universalIdentifier: '66a504cc-0a75-410e-a43f-cdeae1db1522', + position: 3, + }, +]; diff --git a/packages/twenty-server/src/engine/core-modules/application/application-registration/application-registration.service.ts b/packages/twenty-server/src/engine/core-modules/application/application-registration/application-registration.service.ts index 28e4be0b8d..3a3f63db43 100644 --- a/packages/twenty-server/src/engine/core-modules/application/application-registration/application-registration.service.ts +++ b/packages/twenty-server/src/engine/core-modules/application/application-registration/application-registration.service.ts @@ -32,7 +32,7 @@ import { ApplicationEntity } from 'src/engine/core-modules/application/applicati import { validateRedirectUri } from 'src/engine/core-modules/auth/utils/validate-redirect-uri.util'; import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; import { ApplicationRegistrationVariableService } from 'src/engine/core-modules/application/application-registration-variable/application-registration-variable.service'; -import { MARKETPLACE_CURATED_APPLICATIONS } from 'src/engine/core-modules/application/application-marketplace/constants/marketplace-curated-applications.constant'; +import { MARKETPLACE_FEATURED_APPLICATIONS } from 'src/engine/core-modules/application/application-marketplace/constants/marketplace-featured-applications.constant'; const BCRYPT_SALT_ROUNDS = 10; @@ -281,6 +281,7 @@ export class ApplicationRegistrationService { if (isDefined(update.isListed)) updateData.isListed = update.isListed; if (isDefined(update.isPreInstalled)) updateData.isPreInstalled = update.isPreInstalled; + if (isDefined(update.isFeatured)) updateData.isFeatured = update.isFeatured; if (Object.keys(updateData).length > 0) { await this.applicationRegistrationRepository.update(id, updateData); @@ -383,13 +384,13 @@ export class ApplicationRegistrationService { params.universalIdentifier, ); - const curatedIdentifiers = new Set( - MARKETPLACE_CURATED_APPLICATIONS.map( + const featuredIdentifiers = new Set( + MARKETPLACE_FEATURED_APPLICATIONS.map( (entry) => entry.universalIdentifier, ), ); - const isFeatured = curatedIdentifiers.has(params.universalIdentifier); + const isFeatured = featuredIdentifiers.has(params.universalIdentifier); if (isDefined(existing)) { await this.applicationRegistrationRepository.save({ @@ -400,7 +401,6 @@ export class ApplicationRegistrationService { latestAvailableVersion: params.latestAvailableVersion, manifest: params.manifest, ...fromManifestApplicationToDisplayFields(params.manifest?.application), - isFeatured, }); } else { const registration = this.applicationRegistrationRepository.create({ diff --git a/packages/twenty-server/src/engine/core-modules/application/application-registration/dtos/update-application-registration.input.ts b/packages/twenty-server/src/engine/core-modules/application/application-registration/dtos/update-application-registration.input.ts index 82c018d648..e83321bed5 100644 --- a/packages/twenty-server/src/engine/core-modules/application/application-registration/dtos/update-application-registration.input.ts +++ b/packages/twenty-server/src/engine/core-modules/application/application-registration/dtos/update-application-registration.input.ts @@ -46,6 +46,11 @@ export class UpdateApplicationRegistrationPayload { @IsBoolean() @IsOptional() isPreInstalled?: boolean; + + @Field(() => Boolean, { nullable: true }) + @IsBoolean() + @IsOptional() + isFeatured?: boolean; } @InputType() diff --git a/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts b/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts index 05c53838d3..a9301fd032 100644 --- a/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts +++ b/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts @@ -236,7 +236,6 @@ describe('WorkspaceEntityManager', () => { featureFlagsMap: { IS_UNIQUE_INDEXES_ENABLED: false, IS_JSON_FILTER_ENABLED: false, - IS_MARKETPLACE_SETTING_TAB_VISIBLE: false, IS_EMAIL_GROUP_ENABLED: false, IS_JUNCTION_RELATIONS_ENABLED: false, IS_REST_METADATA_API_NEW_FORMAT_DIRECT: false, diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-feature-flags.util.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-feature-flags.util.ts index 67129da061..be80046277 100644 --- a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-feature-flags.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/core/utils/seed-feature-flags.util.ts @@ -35,11 +35,6 @@ export const seedFeatureFlags = async ({ workspaceId: workspaceId, value: true, }, - { - key: FeatureFlagKey.IS_MARKETPLACE_SETTING_TAB_VISIBLE, - workspaceId: workspaceId, - value: true, - }, { key: FeatureFlagKey.IS_SETTINGS_DISCOVERY_HERO_ENABLED, workspaceId: workspaceId, diff --git a/packages/twenty-shared/src/types/FeatureFlagKey.ts b/packages/twenty-shared/src/types/FeatureFlagKey.ts index 356b38b573..463eda1bac 100644 --- a/packages/twenty-shared/src/types/FeatureFlagKey.ts +++ b/packages/twenty-shared/src/types/FeatureFlagKey.ts @@ -1,7 +1,6 @@ export enum FeatureFlagKey { IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED', IS_JSON_FILTER_ENABLED = 'IS_JSON_FILTER_ENABLED', - IS_MARKETPLACE_SETTING_TAB_VISIBLE = 'IS_MARKETPLACE_SETTING_TAB_VISIBLE', IS_EMAIL_GROUP_ENABLED = 'IS_EMAIL_GROUP_ENABLED', IS_JUNCTION_RELATIONS_ENABLED = 'IS_JUNCTION_RELATIONS_ENABLED', IS_REST_METADATA_API_NEW_FORMAT_DIRECT = 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT',