diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index 61ed7e1b8a6..0c7898e916a 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -316,12 +316,6 @@ export type ApiKeyToken = { token: Scalars['String']; }; -export enum AppRegistrationSourceType { - LOCAL = 'LOCAL', - NPM = 'NPM', - TARBALL = 'TARBALL' -} - export type AppToken = { __typename?: 'AppToken'; createdAt: Scalars['DateTime']; @@ -362,20 +356,28 @@ export type ApplicationRegistration = { description?: Maybe; id: Scalars['UUID']; isFeatured: Scalars['Boolean']; + isListed: Scalars['Boolean']; latestAvailableVersion?: Maybe; logoUrl?: Maybe; name: Scalars['String']; oAuthClientId: Scalars['String']; oAuthRedirectUris: Array; oAuthScopes: Array; + ownerWorkspaceId?: Maybe; sourcePackage?: Maybe; - sourceType: AppRegistrationSourceType; + sourceType: ApplicationRegistrationSourceType; termsUrl?: Maybe; universalIdentifier: Scalars['String']; updatedAt: Scalars['DateTime']; websiteUrl?: Maybe; }; +export enum ApplicationRegistrationSourceType { + LOCAL = 'LOCAL', + NPM = 'NPM', + TARBALL = 'TARBALL' +} + export type ApplicationRegistrationStats = { __typename?: 'ApplicationRegistrationStats'; activeInstalls: Scalars['Int']; @@ -387,7 +389,7 @@ export type ApplicationRegistrationSummary = { __typename?: 'ApplicationRegistrationSummary'; id: Scalars['UUID']; latestAvailableVersion?: Maybe; - sourceType: AppRegistrationSourceType; + sourceType: ApplicationRegistrationSourceType; }; export type ApplicationRegistrationVariable = { @@ -1086,15 +1088,6 @@ export type CreateAppTokenInput = { expiresAt: Scalars['DateTime']; }; -export type CreateApplicationInput = { - applicationRegistrationId?: InputMaybe; - description?: InputMaybe; - name: Scalars['String']; - sourcePath: Scalars['String']; - universalIdentifier: Scalars['String']; - version: Scalars['String']; -}; - export type CreateApplicationRegistration = { __typename?: 'CreateApplicationRegistration'; applicationRegistration: ApplicationRegistration; @@ -2235,6 +2228,7 @@ export type MarketplaceApp = { frontComponents: Array; icon: Scalars['String']; id: Scalars['String']; + isFeatured: Scalars['Boolean']; logicFunctions: Array; logo?: Maybe; name: Scalars['String']; @@ -2383,7 +2377,6 @@ export type Mutation = { createObjectEvent: Analytics; createOneAgent: Agent; createOneAppToken: AppToken; - createOneApplication: Application; createOneField: Field; createOneLogicFunction: LogicFunction; createOneObject: Object; @@ -2456,7 +2449,7 @@ export type Mutation = { initiateOTPProvisioningForAuthenticatedUser: InitiateTwoFactorAuthenticationProvisioning; installApplication: Scalars['Boolean']; installMarketplaceApp: Scalars['Boolean']; - installNpmApp: Scalars['Boolean']; + registerNpmPackage: ApplicationRegistration; removeQueryFromEventStream: Scalars['Boolean']; removeRoleFromAgent: Scalars['Boolean']; renewApplicationToken: ApplicationTokenPair; @@ -2467,6 +2460,7 @@ export type Mutation = { revokeApiKey?: Maybe; rotateApplicationRegistrationClientSecret: RotateClientSecret; runEvaluationInput: AgentTurn; + runWorkspaceMigration: Scalars['Boolean']; saveImapSmtpCaldavAccount: ImapSmtpCaldavConnectionSuccess; sendInvitations: SendInvitations; setAdminAiModelEnabled: Scalars['Boolean']; @@ -2482,6 +2476,7 @@ export type Mutation = { switchSubscriptionInterval: BillingUpdate; syncApplication: WorkspaceMigration; trackAnalytics: Analytics; + transferApplicationRegistrationOwnership: ApplicationRegistration; uninstallApplication: Scalars['Boolean']; updateApiKey?: Maybe; updateApplicationRegistration: ApplicationRegistration; @@ -2707,11 +2702,6 @@ export type MutationCreateOneAppTokenArgs = { }; -export type MutationCreateOneApplicationArgs = { - input: CreateApplicationInput; -}; - - export type MutationCreateOneFieldArgs = { input: CreateOneFieldMetadataInput; }; @@ -3042,7 +3032,8 @@ export type MutationInitiateOtpProvisioningArgs = { export type MutationInstallApplicationArgs = { - workspaceMigration: WorkspaceMigrationInput; + appRegistrationId: Scalars['String']; + version?: InputMaybe; }; @@ -3052,9 +3043,8 @@ export type MutationInstallMarketplaceAppArgs = { }; -export type MutationInstallNpmAppArgs = { +export type MutationRegisterNpmPackageArgs = { packageName: Scalars['String']; - version?: InputMaybe; }; @@ -3111,6 +3101,11 @@ export type MutationRunEvaluationInputArgs = { }; +export type MutationRunWorkspaceMigrationArgs = { + workspaceMigration: WorkspaceMigrationInput; +}; + + export type MutationSaveImapSmtpCaldavAccountArgs = { accountOwnerId: Scalars['UUID']; connectionParameters: EmailAccountConnectionParameters; @@ -3184,6 +3179,12 @@ export type MutationTrackAnalyticsArgs = { }; +export type MutationTransferApplicationRegistrationOwnershipArgs = { + applicationRegistrationId: Scalars['String']; + targetWorkspaceSubdomain: Scalars['String']; +}; + + export type MutationUninstallApplicationArgs = { universalIdentifier: Scalars['String']; }; @@ -3932,6 +3933,7 @@ export type Query = { agentTurns: Array; apiKey?: Maybe; apiKeys: Array; + applicationRegistrationTarballUrl?: Maybe; barChartData: BarChartData; billingPortalSession: BillingSession; chatMessages: Array; @@ -3946,6 +3948,7 @@ export type Query = { eventLogs: EventLogQueryResult; field: Field; fields: FieldConnection; + findAllApplicationRegistrations: Array; findApplicationRegistrationByClientId?: Maybe; findApplicationRegistrationByUniversalIdentifier?: Maybe; findApplicationRegistrationStats: ApplicationRegistrationStats; @@ -3960,6 +3963,7 @@ export type Query = { findOneApplication: Application; findOneApplicationRegistration: ApplicationRegistration; findOneLogicFunction: LogicFunction; + findOneMarketplaceApp: MarketplaceApp; findWorkspaceFromInviteHash: Workspace; findWorkspaceInvitations: Array; frontComponent?: Maybe; @@ -4035,6 +4039,11 @@ export type QueryApiKeyArgs = { }; +export type QueryApplicationRegistrationTarballUrlArgs = { + id: Scalars['String']; +}; + + export type QueryBarChartDataArgs = { input: BarChartDataInput; }; @@ -4135,6 +4144,11 @@ export type QueryFindOneLogicFunctionArgs = { }; +export type QueryFindOneMarketplaceAppArgs = { + universalIdentifier: Scalars['String']; +}; + + export type QueryFindWorkspaceFromInviteHashArgs = { inviteHash: Scalars['String']; }; @@ -4827,6 +4841,7 @@ export type UpdateApplicationRegistrationInput = { export type UpdateApplicationRegistrationPayload = { author?: InputMaybe; description?: InputMaybe; + isListed?: InputMaybe; logoUrl?: InputMaybe; name?: InputMaybe; oAuthRedirectUris?: InputMaybe>; @@ -5818,19 +5833,26 @@ export type UpdateOneApplicationVariableMutationVariables = Exact<{ export type UpdateOneApplicationVariableMutation = { __typename?: 'Mutation', updateOneApplicationVariable: boolean }; -export type ApplicationFieldsFragment = { __typename?: 'Application', id: string, name: string, description?: string | null, version?: string | null, universalIdentifier: string, applicationRegistrationId?: string | null, canBeUninstalled: boolean, defaultRoleId?: string | null, settingsCustomTabFrontComponentId?: string | null, availablePackages: any, applicationRegistration?: { __typename?: 'ApplicationRegistrationSummary', id: string, latestAvailableVersion?: string | null, sourceType: AppRegistrationSourceType } | null, applicationVariables: Array<{ __typename?: 'ApplicationVariable', id: string, key: string, value: string, description: string, isSecret: boolean }>, agents: Array<{ __typename?: 'Agent', id: string, name: string, label: string, description?: string | null, icon?: string | null, prompt: string, modelId: string, responseFormat?: any | null, roleId?: string | null, isCustom: boolean, modelConfiguration?: any | null, evaluationInputs: Array, applicationId?: string | null, createdAt: string, updatedAt: string }>, objects: Array<{ __typename?: 'Object', id: string, universalIdentifier: string, nameSingular: string, namePlural: string, labelSingular: string, labelPlural: string, description?: string | null, icon?: string | null, isCustom: boolean, isRemote: boolean, isActive: boolean, isSystem: boolean, isUIReadOnly: boolean, createdAt: string, updatedAt: string, labelIdentifierFieldMetadataId?: string | null, imageIdentifierFieldMetadataId?: string | null, applicationId: string, shortcut?: string | null, isLabelSyncedWithName: boolean, isSearchable: boolean, duplicateCriteria?: Array> | null, indexMetadataList: Array<{ __typename?: 'Index', id: string, createdAt: string, updatedAt: string, name: string, indexWhereClause?: string | null, indexType: IndexType, isUnique: boolean, isCustom?: boolean | null, indexFieldMetadataList: Array<{ __typename?: 'IndexField', id: string, fieldMetadataId: string, createdAt: string, updatedAt: string, order: number }> }>, fieldsList: Array<{ __typename?: 'Field', id: string, universalIdentifier: string, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, isCustom?: boolean | null, isActive?: boolean | null, isSystem?: boolean | null, isUIReadOnly?: boolean | null, isNullable?: boolean | null, isUnique?: boolean | null, createdAt: string, updatedAt: string, defaultValue?: any | null, options?: any | null, settings?: any | null, isLabelSyncedWithName?: boolean | null, morphId?: string | null, applicationId: string, relation?: { __typename?: 'Relation', type: RelationType, sourceObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, targetObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'Field', id: string, name: string }, targetFieldMetadata: { __typename?: 'Field', id: string, name: string } } | null, morphRelations?: Array<{ __typename?: 'Relation', type: RelationType, sourceObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, targetObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'Field', id: string, name: string }, targetFieldMetadata: { __typename?: 'Field', id: string, name: string } }> | null }> }>, logicFunctions: Array<{ __typename?: 'LogicFunction', id: string, name: string, description?: string | null, runtime: string, timeoutSeconds: number, sourceHandlerPath: string, handlerName: string, toolInputSchema?: any | null, isTool: boolean, cronTriggerSettings?: any | null, databaseEventTriggerSettings?: any | null, httpRouteTriggerSettings?: any | null, applicationId?: string | null, createdAt: string, updatedAt: string }> }; +export type ApplicationFieldsFragment = { __typename?: 'Application', id: string, name: string, description?: string | null, version?: string | null, universalIdentifier: string, applicationRegistrationId?: string | null, canBeUninstalled: boolean, defaultRoleId?: string | null, settingsCustomTabFrontComponentId?: string | null, availablePackages: any, applicationRegistration?: { __typename?: 'ApplicationRegistrationSummary', id: string, latestAvailableVersion?: string | null, sourceType: ApplicationRegistrationSourceType } | null, applicationVariables: Array<{ __typename?: 'ApplicationVariable', id: string, key: string, value: string, description: string, isSecret: boolean }>, agents: Array<{ __typename?: 'Agent', id: string, name: string, label: string, description?: string | null, icon?: string | null, prompt: string, modelId: string, responseFormat?: any | null, roleId?: string | null, isCustom: boolean, modelConfiguration?: any | null, evaluationInputs: Array, applicationId?: string | null, createdAt: string, updatedAt: string }>, objects: Array<{ __typename?: 'Object', id: string, universalIdentifier: string, nameSingular: string, namePlural: string, labelSingular: string, labelPlural: string, description?: string | null, icon?: string | null, isCustom: boolean, isRemote: boolean, isActive: boolean, isSystem: boolean, isUIReadOnly: boolean, createdAt: string, updatedAt: string, labelIdentifierFieldMetadataId?: string | null, imageIdentifierFieldMetadataId?: string | null, applicationId: string, shortcut?: string | null, isLabelSyncedWithName: boolean, isSearchable: boolean, duplicateCriteria?: Array> | null, indexMetadataList: Array<{ __typename?: 'Index', id: string, createdAt: string, updatedAt: string, name: string, indexWhereClause?: string | null, indexType: IndexType, isUnique: boolean, isCustom?: boolean | null, indexFieldMetadataList: Array<{ __typename?: 'IndexField', id: string, fieldMetadataId: string, createdAt: string, updatedAt: string, order: number }> }>, fieldsList: Array<{ __typename?: 'Field', id: string, universalIdentifier: string, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, isCustom?: boolean | null, isActive?: boolean | null, isSystem?: boolean | null, isUIReadOnly?: boolean | null, isNullable?: boolean | null, isUnique?: boolean | null, createdAt: string, updatedAt: string, defaultValue?: any | null, options?: any | null, settings?: any | null, isLabelSyncedWithName?: boolean | null, morphId?: string | null, applicationId: string, relation?: { __typename?: 'Relation', type: RelationType, sourceObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, targetObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'Field', id: string, name: string }, targetFieldMetadata: { __typename?: 'Field', id: string, name: string } } | null, morphRelations?: Array<{ __typename?: 'Relation', type: RelationType, sourceObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, targetObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'Field', id: string, name: string }, targetFieldMetadata: { __typename?: 'Field', id: string, name: string } }> | null }> }>, logicFunctions: Array<{ __typename?: 'LogicFunction', id: string, name: string, description?: string | null, runtime: string, timeoutSeconds: number, sourceHandlerPath: string, handlerName: string, toolInputSchema?: any | null, isTool: boolean, cronTriggerSettings?: any | null, databaseEventTriggerSettings?: any | null, httpRouteTriggerSettings?: any | null, applicationId?: string | null, createdAt: string, updatedAt: string }> }; export type FindManyApplicationsQueryVariables = Exact<{ [key: string]: never; }>; -export type FindManyApplicationsQuery = { __typename?: 'Query', findManyApplications: Array<{ __typename?: 'Application', id: string, name: string, description?: string | null, version?: string | null, applicationRegistrationId?: string | null, applicationRegistration?: { __typename?: 'ApplicationRegistrationSummary', id: string, latestAvailableVersion?: string | null, sourceType: AppRegistrationSourceType } | null }> }; +export type FindManyApplicationsQuery = { __typename?: 'Query', findManyApplications: Array<{ __typename?: 'Application', id: string, name: string, description?: string | null, version?: string | null, universalIdentifier: string, applicationRegistrationId?: string | null, applicationRegistration?: { __typename?: 'ApplicationRegistrationSummary', id: string, latestAvailableVersion?: string | null, sourceType: ApplicationRegistrationSourceType } | null }> }; export type FindOneApplicationQueryVariables = Exact<{ id: Scalars['UUID']; }>; -export type FindOneApplicationQuery = { __typename?: 'Query', findOneApplication: { __typename?: 'Application', id: string, name: string, description?: string | null, version?: string | null, universalIdentifier: string, applicationRegistrationId?: string | null, canBeUninstalled: boolean, defaultRoleId?: string | null, settingsCustomTabFrontComponentId?: string | null, availablePackages: any, applicationRegistration?: { __typename?: 'ApplicationRegistrationSummary', id: string, latestAvailableVersion?: string | null, sourceType: AppRegistrationSourceType } | null, applicationVariables: Array<{ __typename?: 'ApplicationVariable', id: string, key: string, value: string, description: string, isSecret: boolean }>, agents: Array<{ __typename?: 'Agent', id: string, name: string, label: string, description?: string | null, icon?: string | null, prompt: string, modelId: string, responseFormat?: any | null, roleId?: string | null, isCustom: boolean, modelConfiguration?: any | null, evaluationInputs: Array, applicationId?: string | null, createdAt: string, updatedAt: string }>, objects: Array<{ __typename?: 'Object', id: string, universalIdentifier: string, nameSingular: string, namePlural: string, labelSingular: string, labelPlural: string, description?: string | null, icon?: string | null, isCustom: boolean, isRemote: boolean, isActive: boolean, isSystem: boolean, isUIReadOnly: boolean, createdAt: string, updatedAt: string, labelIdentifierFieldMetadataId?: string | null, imageIdentifierFieldMetadataId?: string | null, applicationId: string, shortcut?: string | null, isLabelSyncedWithName: boolean, isSearchable: boolean, duplicateCriteria?: Array> | null, indexMetadataList: Array<{ __typename?: 'Index', id: string, createdAt: string, updatedAt: string, name: string, indexWhereClause?: string | null, indexType: IndexType, isUnique: boolean, isCustom?: boolean | null, indexFieldMetadataList: Array<{ __typename?: 'IndexField', id: string, fieldMetadataId: string, createdAt: string, updatedAt: string, order: number }> }>, fieldsList: Array<{ __typename?: 'Field', id: string, universalIdentifier: string, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, isCustom?: boolean | null, isActive?: boolean | null, isSystem?: boolean | null, isUIReadOnly?: boolean | null, isNullable?: boolean | null, isUnique?: boolean | null, createdAt: string, updatedAt: string, defaultValue?: any | null, options?: any | null, settings?: any | null, isLabelSyncedWithName?: boolean | null, morphId?: string | null, applicationId: string, relation?: { __typename?: 'Relation', type: RelationType, sourceObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, targetObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'Field', id: string, name: string }, targetFieldMetadata: { __typename?: 'Field', id: string, name: string } } | null, morphRelations?: Array<{ __typename?: 'Relation', type: RelationType, sourceObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, targetObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'Field', id: string, name: string }, targetFieldMetadata: { __typename?: 'Field', id: string, name: string } }> | null }> }>, logicFunctions: Array<{ __typename?: 'LogicFunction', id: string, name: string, description?: string | null, runtime: string, timeoutSeconds: number, sourceHandlerPath: string, handlerName: string, toolInputSchema?: any | null, isTool: boolean, cronTriggerSettings?: any | null, databaseEventTriggerSettings?: any | null, httpRouteTriggerSettings?: any | null, applicationId?: string | null, createdAt: string, updatedAt: string }> } }; +export type FindOneApplicationQuery = { __typename?: 'Query', findOneApplication: { __typename?: 'Application', id: string, name: string, description?: string | null, version?: string | null, universalIdentifier: string, applicationRegistrationId?: string | null, canBeUninstalled: boolean, defaultRoleId?: string | null, settingsCustomTabFrontComponentId?: string | null, availablePackages: any, applicationRegistration?: { __typename?: 'ApplicationRegistrationSummary', id: string, latestAvailableVersion?: string | null, sourceType: ApplicationRegistrationSourceType } | null, applicationVariables: Array<{ __typename?: 'ApplicationVariable', id: string, key: string, value: string, description: string, isSecret: boolean }>, agents: Array<{ __typename?: 'Agent', id: string, name: string, label: string, description?: string | null, icon?: string | null, prompt: string, modelId: string, responseFormat?: any | null, roleId?: string | null, isCustom: boolean, modelConfiguration?: any | null, evaluationInputs: Array, applicationId?: string | null, createdAt: string, updatedAt: string }>, objects: Array<{ __typename?: 'Object', id: string, universalIdentifier: string, nameSingular: string, namePlural: string, labelSingular: string, labelPlural: string, description?: string | null, icon?: string | null, isCustom: boolean, isRemote: boolean, isActive: boolean, isSystem: boolean, isUIReadOnly: boolean, createdAt: string, updatedAt: string, labelIdentifierFieldMetadataId?: string | null, imageIdentifierFieldMetadataId?: string | null, applicationId: string, shortcut?: string | null, isLabelSyncedWithName: boolean, isSearchable: boolean, duplicateCriteria?: Array> | null, indexMetadataList: Array<{ __typename?: 'Index', id: string, createdAt: string, updatedAt: string, name: string, indexWhereClause?: string | null, indexType: IndexType, isUnique: boolean, isCustom?: boolean | null, indexFieldMetadataList: Array<{ __typename?: 'IndexField', id: string, fieldMetadataId: string, createdAt: string, updatedAt: string, order: number }> }>, fieldsList: Array<{ __typename?: 'Field', id: string, universalIdentifier: string, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, isCustom?: boolean | null, isActive?: boolean | null, isSystem?: boolean | null, isUIReadOnly?: boolean | null, isNullable?: boolean | null, isUnique?: boolean | null, createdAt: string, updatedAt: string, defaultValue?: any | null, options?: any | null, settings?: any | null, isLabelSyncedWithName?: boolean | null, morphId?: string | null, applicationId: string, relation?: { __typename?: 'Relation', type: RelationType, sourceObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, targetObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'Field', id: string, name: string }, targetFieldMetadata: { __typename?: 'Field', id: string, name: string } } | null, morphRelations?: Array<{ __typename?: 'Relation', type: RelationType, sourceObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, targetObjectMetadata: { __typename?: 'Object', id: string, nameSingular: string, namePlural: string }, sourceFieldMetadata: { __typename?: 'Field', id: string, name: string }, targetFieldMetadata: { __typename?: 'Field', id: string, name: string } }> | null }> }>, logicFunctions: Array<{ __typename?: 'LogicFunction', id: string, name: string, description?: string | null, runtime: string, timeoutSeconds: number, sourceHandlerPath: string, handlerName: string, toolInputSchema?: any | null, isTool: boolean, cronTriggerSettings?: any | null, databaseEventTriggerSettings?: any | null, httpRouteTriggerSettings?: any | null, applicationId?: string | null, createdAt: string, updatedAt: string }> } }; + +export type FindOneApplicationByUniversalIdentifierQueryVariables = Exact<{ + universalIdentifier: Scalars['UUID']; +}>; + + +export type FindOneApplicationByUniversalIdentifierQuery = { __typename?: 'Query', findOneApplication: { __typename?: 'Application', id: string } }; export type AuthTokenFragmentFragment = { __typename?: 'AuthToken', token: string, expiresAt: string }; @@ -6225,7 +6247,15 @@ export type GetLogicFunctionSourceCodeQueryVariables = Exact<{ export type GetLogicFunctionSourceCodeQuery = { __typename?: 'Query', getLogicFunctionSourceCode?: string | null }; -export type MarketplaceAppFieldsFragment = { __typename?: 'MarketplaceApp', id: string, name: string, description: string, icon: string, version: string, author: string, category: string, logo?: string | null, screenshots: Array, aboutDescription: string, providers: Array, websiteUrl?: string | null, termsUrl?: string | null, sourcePackage?: string | null, objects: Array<{ __typename?: 'MarketplaceAppObject', universalIdentifier: string, nameSingular: string, namePlural: string, labelSingular: string, labelPlural: string, description?: string | null, icon?: string | null, fields: Array<{ __typename?: 'MarketplaceAppField', universalIdentifier?: string | null, name: string, type: string, label: string, description?: string | null, icon?: string | null }> }>, fields: Array<{ __typename?: 'MarketplaceAppField', name: string, type: string, label: string, description?: string | null, icon?: string | null, objectUniversalIdentifier?: string | null }>, logicFunctions: Array<{ __typename?: 'MarketplaceAppLogicFunction', name: string, description?: string | null, timeoutSeconds?: number | null }>, frontComponents: Array<{ __typename?: 'MarketplaceAppFrontComponent', name: string, description?: string | null }>, defaultRole?: { __typename?: 'MarketplaceAppDefaultRole', id: string, label: string, description?: string | null, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean, canUpdateAllSettings: boolean, canAccessAllTools: boolean, permissionFlags: Array, objectPermissions: Array<{ __typename?: 'MarketplaceAppRoleObjectPermission', objectUniversalIdentifier: string, canReadObjectRecords?: boolean | null, canUpdateObjectRecords?: boolean | null, canSoftDeleteObjectRecords?: boolean | null, canDestroyObjectRecords?: boolean | null }>, fieldPermissions: Array<{ __typename?: 'MarketplaceAppRoleFieldPermission', objectUniversalIdentifier: string, fieldUniversalIdentifier: string, canReadFieldValue?: boolean | null, canUpdateFieldValue?: boolean | null }> } | null }; +export type MarketplaceAppFieldsFragment = { __typename?: 'MarketplaceApp', id: string, name: string, description: string, icon: string, version: string, author: string, category: string, logo?: string | null, screenshots: Array, aboutDescription: string, providers: Array, websiteUrl?: string | null, termsUrl?: string | null, sourcePackage?: string | null, isFeatured: boolean, objects: Array<{ __typename?: 'MarketplaceAppObject', universalIdentifier: string, nameSingular: string, namePlural: string, labelSingular: string, labelPlural: string, description?: string | null, icon?: string | null, fields: Array<{ __typename?: 'MarketplaceAppField', universalIdentifier?: string | null, name: string, type: string, label: string, description?: string | null, icon?: string | null }> }>, fields: Array<{ __typename?: 'MarketplaceAppField', name: string, type: string, label: string, description?: string | null, icon?: string | null, objectUniversalIdentifier?: string | null }>, logicFunctions: Array<{ __typename?: 'MarketplaceAppLogicFunction', name: string, description?: string | null, timeoutSeconds?: number | null }>, frontComponents: Array<{ __typename?: 'MarketplaceAppFrontComponent', name: string, description?: string | null }>, defaultRole?: { __typename?: 'MarketplaceAppDefaultRole', id: string, label: string, description?: string | null, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean, canUpdateAllSettings: boolean, canAccessAllTools: boolean, permissionFlags: Array, objectPermissions: Array<{ __typename?: 'MarketplaceAppRoleObjectPermission', objectUniversalIdentifier: string, canReadObjectRecords?: boolean | null, canUpdateObjectRecords?: boolean | null, canSoftDeleteObjectRecords?: boolean | null, canDestroyObjectRecords?: boolean | null }>, fieldPermissions: Array<{ __typename?: 'MarketplaceAppRoleFieldPermission', objectUniversalIdentifier: string, fieldUniversalIdentifier: string, canReadFieldValue?: boolean | null, canUpdateFieldValue?: boolean | null }> } | null }; + +export type InstallApplicationMutationVariables = Exact<{ + appRegistrationId: Scalars['String']; + version?: InputMaybe; +}>; + + +export type InstallApplicationMutation = { __typename?: 'Mutation', installApplication: boolean }; export type InstallMarketplaceAppMutationVariables = Exact<{ universalIdentifier: Scalars['String']; @@ -6235,13 +6265,12 @@ export type InstallMarketplaceAppMutationVariables = Exact<{ export type InstallMarketplaceAppMutation = { __typename?: 'Mutation', installMarketplaceApp: boolean }; -export type InstallNpmAppMutationVariables = Exact<{ +export type RegisterNpmPackageMutationVariables = Exact<{ packageName: Scalars['String']; - version?: InputMaybe; }>; -export type InstallNpmAppMutation = { __typename?: 'Mutation', installNpmApp: boolean }; +export type RegisterNpmPackageMutation = { __typename?: 'Mutation', registerNpmPackage: { __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string } }; export type UpgradeApplicationMutationVariables = Exact<{ appRegistrationId: Scalars['String']; @@ -6262,7 +6291,14 @@ export type UploadAppTarballMutation = { __typename?: 'Mutation', uploadAppTarba export type FindManyMarketplaceAppsQueryVariables = Exact<{ [key: string]: never; }>; -export type FindManyMarketplaceAppsQuery = { __typename?: 'Query', findManyMarketplaceApps: Array<{ __typename?: 'MarketplaceApp', id: string, name: string, description: string, icon: string, version: string, author: string, category: string, logo?: string | null, screenshots: Array, aboutDescription: string, providers: Array, websiteUrl?: string | null, termsUrl?: string | null, sourcePackage?: string | null, objects: Array<{ __typename?: 'MarketplaceAppObject', universalIdentifier: string, nameSingular: string, namePlural: string, labelSingular: string, labelPlural: string, description?: string | null, icon?: string | null, fields: Array<{ __typename?: 'MarketplaceAppField', universalIdentifier?: string | null, name: string, type: string, label: string, description?: string | null, icon?: string | null }> }>, fields: Array<{ __typename?: 'MarketplaceAppField', name: string, type: string, label: string, description?: string | null, icon?: string | null, objectUniversalIdentifier?: string | null }>, logicFunctions: Array<{ __typename?: 'MarketplaceAppLogicFunction', name: string, description?: string | null, timeoutSeconds?: number | null }>, frontComponents: Array<{ __typename?: 'MarketplaceAppFrontComponent', name: string, description?: string | null }>, defaultRole?: { __typename?: 'MarketplaceAppDefaultRole', id: string, label: string, description?: string | null, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean, canUpdateAllSettings: boolean, canAccessAllTools: boolean, permissionFlags: Array, objectPermissions: Array<{ __typename?: 'MarketplaceAppRoleObjectPermission', objectUniversalIdentifier: string, canReadObjectRecords?: boolean | null, canUpdateObjectRecords?: boolean | null, canSoftDeleteObjectRecords?: boolean | null, canDestroyObjectRecords?: boolean | null }>, fieldPermissions: Array<{ __typename?: 'MarketplaceAppRoleFieldPermission', objectUniversalIdentifier: string, fieldUniversalIdentifier: string, canReadFieldValue?: boolean | null, canUpdateFieldValue?: boolean | null }> } | null }> }; +export type FindManyMarketplaceAppsQuery = { __typename?: 'Query', findManyMarketplaceApps: Array<{ __typename?: 'MarketplaceApp', id: string, name: string, description: string, icon: string, version: string, author: string, category: string, logo?: string | null, screenshots: Array, aboutDescription: string, providers: Array, websiteUrl?: string | null, termsUrl?: string | null, sourcePackage?: string | null, isFeatured: boolean, objects: Array<{ __typename?: 'MarketplaceAppObject', universalIdentifier: string, nameSingular: string, namePlural: string, labelSingular: string, labelPlural: string, description?: string | null, icon?: string | null, fields: Array<{ __typename?: 'MarketplaceAppField', universalIdentifier?: string | null, name: string, type: string, label: string, description?: string | null, icon?: string | null }> }>, fields: Array<{ __typename?: 'MarketplaceAppField', name: string, type: string, label: string, description?: string | null, icon?: string | null, objectUniversalIdentifier?: string | null }>, logicFunctions: Array<{ __typename?: 'MarketplaceAppLogicFunction', name: string, description?: string | null, timeoutSeconds?: number | null }>, frontComponents: Array<{ __typename?: 'MarketplaceAppFrontComponent', name: string, description?: string | null }>, defaultRole?: { __typename?: 'MarketplaceAppDefaultRole', id: string, label: string, description?: string | null, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean, canUpdateAllSettings: boolean, canAccessAllTools: boolean, permissionFlags: Array, objectPermissions: Array<{ __typename?: 'MarketplaceAppRoleObjectPermission', objectUniversalIdentifier: string, canReadObjectRecords?: boolean | null, canUpdateObjectRecords?: boolean | null, canSoftDeleteObjectRecords?: boolean | null, canDestroyObjectRecords?: boolean | null }>, fieldPermissions: Array<{ __typename?: 'MarketplaceAppRoleFieldPermission', objectUniversalIdentifier: string, fieldUniversalIdentifier: string, canReadFieldValue?: boolean | null, canUpdateFieldValue?: boolean | null }> } | null }> }; + +export type FindOneMarketplaceAppQueryVariables = Exact<{ + universalIdentifier: Scalars['String']; +}>; + + +export type FindOneMarketplaceAppQuery = { __typename?: 'Query', findOneMarketplaceApp: { __typename?: 'MarketplaceApp', id: string, name: string, description: string, icon: string, version: string, author: string, category: string, logo?: string | null, screenshots: Array, aboutDescription: string, providers: Array, websiteUrl?: string | null, termsUrl?: string | null, sourcePackage?: string | null, isFeatured: boolean, objects: Array<{ __typename?: 'MarketplaceAppObject', universalIdentifier: string, nameSingular: string, namePlural: string, labelSingular: string, labelPlural: string, description?: string | null, icon?: string | null, fields: Array<{ __typename?: 'MarketplaceAppField', universalIdentifier?: string | null, name: string, type: string, label: string, description?: string | null, icon?: string | null }> }>, fields: Array<{ __typename?: 'MarketplaceAppField', name: string, type: string, label: string, description?: string | null, icon?: string | null, objectUniversalIdentifier?: string | null }>, logicFunctions: Array<{ __typename?: 'MarketplaceAppLogicFunction', name: string, description?: string | null, timeoutSeconds?: number | null }>, frontComponents: Array<{ __typename?: 'MarketplaceAppFrontComponent', name: string, description?: string | null }>, defaultRole?: { __typename?: 'MarketplaceAppDefaultRole', id: string, label: string, description?: string | null, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean, canUpdateAllSettings: boolean, canAccessAllTools: boolean, permissionFlags: Array, objectPermissions: Array<{ __typename?: 'MarketplaceAppRoleObjectPermission', objectUniversalIdentifier: string, canReadObjectRecords?: boolean | null, canUpdateObjectRecords?: boolean | null, canSoftDeleteObjectRecords?: boolean | null, canDestroyObjectRecords?: boolean | null }>, fieldPermissions: Array<{ __typename?: 'MarketplaceAppRoleFieldPermission', objectUniversalIdentifier: string, fieldUniversalIdentifier: string, canReadFieldValue?: boolean | null, canUpdateFieldValue?: boolean | null }> } | null } }; export type NavigationMenuItemFieldsFragment = { __typename?: 'NavigationMenuItem', id: string, userWorkspaceId?: string | null, targetRecordId?: string | null, targetObjectMetadataId?: string | null, viewId?: string | null, folderId?: string | null, name?: string | null, link?: string | null, icon?: string | null, color?: string | null, position: number, applicationId?: string | null, createdAt: string, updatedAt: string }; @@ -6452,6 +6488,11 @@ export type GetAdminAiModelsQueryVariables = Exact<{ [key: string]: never; }>; export type GetAdminAiModelsQuery = { __typename?: 'Query', getAdminAiModels: { __typename?: 'AdminAIModels', autoEnableNewModels: boolean, models: Array<{ __typename?: 'AdminAIModelConfig', modelId: string, label: string, modelFamily?: ModelFamily | null, inferenceProvider: InferenceProvider, isAvailable: boolean, isAdminEnabled: boolean, deprecated?: boolean | null, isRecommended?: boolean | null }> } }; +export type FindAllApplicationRegistrationsQueryVariables = Exact<{ [key: string]: never; }>; + + +export type FindAllApplicationRegistrationsQuery = { __typename?: 'Query', findAllApplicationRegistrations: Array<{ __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, description?: string | null, logoUrl?: string | null, author?: string | null, oAuthClientId: string, oAuthRedirectUris: Array, oAuthScopes: Array, sourceType: ApplicationRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, websiteUrl?: string | null, termsUrl?: string | null, isListed: boolean, isFeatured: boolean, ownerWorkspaceId?: string | null, createdAt: string, updatedAt: string }> }; + export type CreateDatabaseConfigVariableMutationVariables = Exact<{ key: Scalars['String']; value: Scalars['JSON']; @@ -6554,7 +6595,7 @@ export type GetSystemHealthStatusQueryVariables = Exact<{ [key: string]: never; export type GetSystemHealthStatusQuery = { __typename?: 'Query', getSystemHealthStatus: { __typename?: 'SystemHealth', services: Array<{ __typename?: 'SystemHealthService', id: HealthIndicatorId, label: string, status: AdminPanelHealthServiceStatus }> } }; -export type ApplicationRegistrationFragmentFragment = { __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, description?: string | null, logoUrl?: string | null, author?: string | null, oAuthClientId: string, oAuthRedirectUris: Array, oAuthScopes: Array, sourceType: AppRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, websiteUrl?: string | null, termsUrl?: string | null, createdAt: string, updatedAt: string }; +export type ApplicationRegistrationFragmentFragment = { __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, description?: string | null, logoUrl?: string | null, author?: string | null, oAuthClientId: string, oAuthRedirectUris: Array, oAuthScopes: Array, sourceType: ApplicationRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, websiteUrl?: string | null, termsUrl?: string | null, isListed: boolean, isFeatured: boolean, ownerWorkspaceId?: string | null, createdAt: string, updatedAt: string }; export type DeleteApplicationRegistrationMutationVariables = Exact<{ id: Scalars['String']; @@ -6570,12 +6611,20 @@ export type RotateApplicationRegistrationClientSecretMutationVariables = Exact<{ export type RotateApplicationRegistrationClientSecretMutation = { __typename?: 'Mutation', rotateApplicationRegistrationClientSecret: { __typename?: 'RotateClientSecret', clientSecret: string } }; +export type TransferApplicationRegistrationOwnershipMutationVariables = Exact<{ + applicationRegistrationId: Scalars['String']; + targetWorkspaceSubdomain: Scalars['String']; +}>; + + +export type TransferApplicationRegistrationOwnershipMutation = { __typename?: 'Mutation', transferApplicationRegistrationOwnership: { __typename?: 'ApplicationRegistration', id: string, name: string } }; + export type UpdateApplicationRegistrationMutationVariables = Exact<{ input: UpdateApplicationRegistrationInput; }>; -export type UpdateApplicationRegistrationMutation = { __typename?: 'Mutation', updateApplicationRegistration: { __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, description?: string | null, logoUrl?: string | null, author?: string | null, oAuthClientId: string, oAuthRedirectUris: Array, oAuthScopes: Array, sourceType: AppRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, websiteUrl?: string | null, termsUrl?: string | null, createdAt: string, updatedAt: string } }; +export type UpdateApplicationRegistrationMutation = { __typename?: 'Mutation', updateApplicationRegistration: { __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, description?: string | null, logoUrl?: string | null, author?: string | null, oAuthClientId: string, oAuthRedirectUris: Array, oAuthScopes: Array, sourceType: ApplicationRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, websiteUrl?: string | null, termsUrl?: string | null, isListed: boolean, isFeatured: boolean, ownerWorkspaceId?: string | null, createdAt: string, updatedAt: string } }; export type UpdateApplicationRegistrationVariableMutationVariables = Exact<{ input: UpdateApplicationRegistrationVariableInput; @@ -6584,6 +6633,13 @@ export type UpdateApplicationRegistrationVariableMutationVariables = Exact<{ export type UpdateApplicationRegistrationVariableMutation = { __typename?: 'Mutation', updateApplicationRegistrationVariable: { __typename?: 'ApplicationRegistrationVariable', id: string, key: string, description: string, isSecret: boolean, isRequired: boolean, isFilled: boolean, createdAt: string, updatedAt: string } }; +export type ApplicationRegistrationTarballUrlQueryVariables = Exact<{ + id: Scalars['String']; +}>; + + +export type ApplicationRegistrationTarballUrlQuery = { __typename?: 'Query', applicationRegistrationTarballUrl?: string | null }; + export type FindApplicationRegistrationByClientIdQueryVariables = Exact<{ clientId: Scalars['String']; }>; @@ -6608,14 +6664,14 @@ export type FindApplicationRegistrationVariablesQuery = { __typename?: 'Query', export type FindManyApplicationRegistrationsQueryVariables = Exact<{ [key: string]: never; }>; -export type FindManyApplicationRegistrationsQuery = { __typename?: 'Query', findManyApplicationRegistrations: Array<{ __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, description?: string | null, logoUrl?: string | null, author?: string | null, oAuthClientId: string, oAuthRedirectUris: Array, oAuthScopes: Array, sourceType: AppRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, websiteUrl?: string | null, termsUrl?: string | null, createdAt: string, updatedAt: string }> }; +export type FindManyApplicationRegistrationsQuery = { __typename?: 'Query', findManyApplicationRegistrations: Array<{ __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, description?: string | null, logoUrl?: string | null, author?: string | null, oAuthClientId: string, oAuthRedirectUris: Array, oAuthScopes: Array, sourceType: ApplicationRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, websiteUrl?: string | null, termsUrl?: string | null, isListed: boolean, isFeatured: boolean, ownerWorkspaceId?: string | null, createdAt: string, updatedAt: string }> }; export type FindOneApplicationRegistrationQueryVariables = Exact<{ id: Scalars['String']; }>; -export type FindOneApplicationRegistrationQuery = { __typename?: 'Query', findOneApplicationRegistration: { __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, description?: string | null, logoUrl?: string | null, author?: string | null, oAuthClientId: string, oAuthRedirectUris: Array, oAuthScopes: Array, sourceType: AppRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, websiteUrl?: string | null, termsUrl?: string | null, createdAt: string, updatedAt: string } }; +export type FindOneApplicationRegistrationQuery = { __typename?: 'Query', findOneApplicationRegistration: { __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, description?: string | null, logoUrl?: string | null, author?: string | null, oAuthClientId: string, oAuthRedirectUris: Array, oAuthScopes: Array, sourceType: ApplicationRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, websiteUrl?: string | null, termsUrl?: string | null, isListed: boolean, isFeatured: boolean, ownerWorkspaceId?: string | null, createdAt: string, updatedAt: string } }; export type UninstallApplicationMutationVariables = Exact<{ universalIdentifier: Scalars['String']; @@ -7889,6 +7945,7 @@ export const MarketplaceAppFieldsFragmentDoc = gql` description } sourcePackage + isFeatured defaultRole { id label @@ -7960,6 +8017,9 @@ export const ApplicationRegistrationFragmentFragmentDoc = gql` latestAvailableVersion websiteUrl termsUrl + isListed + isFeatured + ownerWorkspaceId createdAt updatedAt } @@ -9385,6 +9445,7 @@ export const FindManyApplicationsDocument = gql` name description version + universalIdentifier applicationRegistrationId applicationRegistration { id @@ -9456,6 +9517,41 @@ export function useFindOneApplicationLazyQuery(baseOptions?: Apollo.LazyQueryHoo export type FindOneApplicationQueryHookResult = ReturnType; export type FindOneApplicationLazyQueryHookResult = ReturnType; export type FindOneApplicationQueryResult = Apollo.QueryResult; +export const FindOneApplicationByUniversalIdentifierDocument = gql` + query FindOneApplicationByUniversalIdentifier($universalIdentifier: UUID!) { + findOneApplication(universalIdentifier: $universalIdentifier) { + id + } +} + `; + +/** + * __useFindOneApplicationByUniversalIdentifierQuery__ + * + * To run a query within a React component, call `useFindOneApplicationByUniversalIdentifierQuery` and pass it any options that fit your needs. + * When your component renders, `useFindOneApplicationByUniversalIdentifierQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useFindOneApplicationByUniversalIdentifierQuery({ + * variables: { + * universalIdentifier: // value for 'universalIdentifier' + * }, + * }); + */ +export function useFindOneApplicationByUniversalIdentifierQuery(baseOptions: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(FindOneApplicationByUniversalIdentifierDocument, options); + } +export function useFindOneApplicationByUniversalIdentifierLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(FindOneApplicationByUniversalIdentifierDocument, options); + } +export type FindOneApplicationByUniversalIdentifierQueryHookResult = ReturnType; +export type FindOneApplicationByUniversalIdentifierLazyQueryHookResult = ReturnType; +export type FindOneApplicationByUniversalIdentifierQueryResult = Apollo.QueryResult; export const AuthorizeAppDocument = gql` mutation authorizeApp($clientId: String!, $codeChallenge: String, $redirectUrl: String!) { authorizeApp( @@ -11437,6 +11533,38 @@ export function useGetLogicFunctionSourceCodeLazyQuery(baseOptions?: Apollo.Lazy export type GetLogicFunctionSourceCodeQueryHookResult = ReturnType; export type GetLogicFunctionSourceCodeLazyQueryHookResult = ReturnType; export type GetLogicFunctionSourceCodeQueryResult = Apollo.QueryResult; +export const InstallApplicationDocument = gql` + mutation InstallApplication($appRegistrationId: String!, $version: String) { + installApplication(appRegistrationId: $appRegistrationId, version: $version) +} + `; +export type InstallApplicationMutationFn = Apollo.MutationFunction; + +/** + * __useInstallApplicationMutation__ + * + * To run a mutation, you first call `useInstallApplicationMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useInstallApplicationMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [installApplicationMutation, { data, loading, error }] = useInstallApplicationMutation({ + * variables: { + * appRegistrationId: // value for 'appRegistrationId' + * version: // value for 'version' + * }, + * }); + */ +export function useInstallApplicationMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(InstallApplicationDocument, options); + } +export type InstallApplicationMutationHookResult = ReturnType; +export type InstallApplicationMutationResult = Apollo.MutationResult; +export type InstallApplicationMutationOptions = Apollo.BaseMutationOptions; export const InstallMarketplaceAppDocument = gql` mutation InstallMarketplaceApp($universalIdentifier: String!, $version: String) { installMarketplaceApp( @@ -11472,38 +11600,41 @@ export function useInstallMarketplaceAppMutation(baseOptions?: Apollo.MutationHo export type InstallMarketplaceAppMutationHookResult = ReturnType; export type InstallMarketplaceAppMutationResult = Apollo.MutationResult; export type InstallMarketplaceAppMutationOptions = Apollo.BaseMutationOptions; -export const InstallNpmAppDocument = gql` - mutation InstallNpmApp($packageName: String!, $version: String) { - installNpmApp(packageName: $packageName, version: $version) +export const RegisterNpmPackageDocument = gql` + mutation RegisterNpmPackage($packageName: String!) { + registerNpmPackage(packageName: $packageName) { + id + universalIdentifier + name + } } `; -export type InstallNpmAppMutationFn = Apollo.MutationFunction; +export type RegisterNpmPackageMutationFn = Apollo.MutationFunction; /** - * __useInstallNpmAppMutation__ + * __useRegisterNpmPackageMutation__ * - * To run a mutation, you first call `useInstallNpmAppMutation` within a React component and pass it any options that fit your needs. - * When your component renders, `useInstallNpmAppMutation` returns a tuple that includes: + * To run a mutation, you first call `useRegisterNpmPackageMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useRegisterNpmPackageMutation` returns a tuple that includes: * - A mutate function that you can call at any time to execute the mutation * - An object with fields that represent the current status of the mutation's execution * * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; * * @example - * const [installNpmAppMutation, { data, loading, error }] = useInstallNpmAppMutation({ + * const [registerNpmPackageMutation, { data, loading, error }] = useRegisterNpmPackageMutation({ * variables: { * packageName: // value for 'packageName' - * version: // value for 'version' * }, * }); */ -export function useInstallNpmAppMutation(baseOptions?: Apollo.MutationHookOptions) { +export function useRegisterNpmPackageMutation(baseOptions?: Apollo.MutationHookOptions) { const options = {...defaultOptions, ...baseOptions} - return Apollo.useMutation(InstallNpmAppDocument, options); + return Apollo.useMutation(RegisterNpmPackageDocument, options); } -export type InstallNpmAppMutationHookResult = ReturnType; -export type InstallNpmAppMutationResult = Apollo.MutationResult; -export type InstallNpmAppMutationOptions = Apollo.BaseMutationOptions; +export type RegisterNpmPackageMutationHookResult = ReturnType; +export type RegisterNpmPackageMutationResult = Apollo.MutationResult; +export type RegisterNpmPackageMutationOptions = Apollo.BaseMutationOptions; export const UpgradeApplicationDocument = gql` mutation UpgradeApplication($appRegistrationId: String!, $targetVersion: String!) { upgradeApplication( @@ -11609,6 +11740,41 @@ export function useFindManyMarketplaceAppsLazyQuery(baseOptions?: Apollo.LazyQue export type FindManyMarketplaceAppsQueryHookResult = ReturnType; export type FindManyMarketplaceAppsLazyQueryHookResult = ReturnType; export type FindManyMarketplaceAppsQueryResult = Apollo.QueryResult; +export const FindOneMarketplaceAppDocument = gql` + query FindOneMarketplaceApp($universalIdentifier: String!) { + findOneMarketplaceApp(universalIdentifier: $universalIdentifier) { + ...MarketplaceAppFields + } +} + ${MarketplaceAppFieldsFragmentDoc}`; + +/** + * __useFindOneMarketplaceAppQuery__ + * + * To run a query within a React component, call `useFindOneMarketplaceAppQuery` and pass it any options that fit your needs. + * When your component renders, `useFindOneMarketplaceAppQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useFindOneMarketplaceAppQuery({ + * variables: { + * universalIdentifier: // value for 'universalIdentifier' + * }, + * }); + */ +export function useFindOneMarketplaceAppQuery(baseOptions: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(FindOneMarketplaceAppDocument, options); + } +export function useFindOneMarketplaceAppLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(FindOneMarketplaceAppDocument, options); + } +export type FindOneMarketplaceAppQueryHookResult = ReturnType; +export type FindOneMarketplaceAppLazyQueryHookResult = ReturnType; +export type FindOneMarketplaceAppQueryResult = Apollo.QueryResult; export const CreateNavigationMenuItemDocument = gql` mutation CreateNavigationMenuItem($input: CreateNavigationMenuItemInput!) { createNavigationMenuItem(input: $input) { @@ -12709,6 +12875,40 @@ export function useGetAdminAiModelsLazyQuery(baseOptions?: Apollo.LazyQueryHookO export type GetAdminAiModelsQueryHookResult = ReturnType; export type GetAdminAiModelsLazyQueryHookResult = ReturnType; export type GetAdminAiModelsQueryResult = Apollo.QueryResult; +export const FindAllApplicationRegistrationsDocument = gql` + query FindAllApplicationRegistrations { + findAllApplicationRegistrations { + ...ApplicationRegistrationFragment + } +} + ${ApplicationRegistrationFragmentFragmentDoc}`; + +/** + * __useFindAllApplicationRegistrationsQuery__ + * + * To run a query within a React component, call `useFindAllApplicationRegistrationsQuery` and pass it any options that fit your needs. + * When your component renders, `useFindAllApplicationRegistrationsQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useFindAllApplicationRegistrationsQuery({ + * variables: { + * }, + * }); + */ +export function useFindAllApplicationRegistrationsQuery(baseOptions?: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(FindAllApplicationRegistrationsDocument, options); + } +export function useFindAllApplicationRegistrationsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(FindAllApplicationRegistrationsDocument, options); + } +export type FindAllApplicationRegistrationsQueryHookResult = ReturnType; +export type FindAllApplicationRegistrationsLazyQueryHookResult = ReturnType; +export type FindAllApplicationRegistrationsQueryResult = Apollo.QueryResult; export const CreateDatabaseConfigVariableDocument = gql` mutation CreateDatabaseConfigVariable($key: String!, $value: JSON!) { createDatabaseConfigVariable(key: $key, value: $value) @@ -13368,6 +13568,44 @@ export function useRotateApplicationRegistrationClientSecretMutation(baseOptions export type RotateApplicationRegistrationClientSecretMutationHookResult = ReturnType; export type RotateApplicationRegistrationClientSecretMutationResult = Apollo.MutationResult; export type RotateApplicationRegistrationClientSecretMutationOptions = Apollo.BaseMutationOptions; +export const TransferApplicationRegistrationOwnershipDocument = gql` + mutation TransferApplicationRegistrationOwnership($applicationRegistrationId: String!, $targetWorkspaceSubdomain: String!) { + transferApplicationRegistrationOwnership( + applicationRegistrationId: $applicationRegistrationId + targetWorkspaceSubdomain: $targetWorkspaceSubdomain + ) { + id + name + } +} + `; +export type TransferApplicationRegistrationOwnershipMutationFn = Apollo.MutationFunction; + +/** + * __useTransferApplicationRegistrationOwnershipMutation__ + * + * To run a mutation, you first call `useTransferApplicationRegistrationOwnershipMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useTransferApplicationRegistrationOwnershipMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [transferApplicationRegistrationOwnershipMutation, { data, loading, error }] = useTransferApplicationRegistrationOwnershipMutation({ + * variables: { + * applicationRegistrationId: // value for 'applicationRegistrationId' + * targetWorkspaceSubdomain: // value for 'targetWorkspaceSubdomain' + * }, + * }); + */ +export function useTransferApplicationRegistrationOwnershipMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(TransferApplicationRegistrationOwnershipDocument, options); + } +export type TransferApplicationRegistrationOwnershipMutationHookResult = ReturnType; +export type TransferApplicationRegistrationOwnershipMutationResult = Apollo.MutationResult; +export type TransferApplicationRegistrationOwnershipMutationOptions = Apollo.BaseMutationOptions; export const UpdateApplicationRegistrationDocument = gql` mutation UpdateApplicationRegistration($input: UpdateApplicationRegistrationInput!) { updateApplicationRegistration(input: $input) { @@ -13441,6 +13679,39 @@ export function useUpdateApplicationRegistrationVariableMutation(baseOptions?: A export type UpdateApplicationRegistrationVariableMutationHookResult = ReturnType; export type UpdateApplicationRegistrationVariableMutationResult = Apollo.MutationResult; export type UpdateApplicationRegistrationVariableMutationOptions = Apollo.BaseMutationOptions; +export const ApplicationRegistrationTarballUrlDocument = gql` + query ApplicationRegistrationTarballUrl($id: String!) { + applicationRegistrationTarballUrl(id: $id) +} + `; + +/** + * __useApplicationRegistrationTarballUrlQuery__ + * + * To run a query within a React component, call `useApplicationRegistrationTarballUrlQuery` and pass it any options that fit your needs. + * When your component renders, `useApplicationRegistrationTarballUrlQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useApplicationRegistrationTarballUrlQuery({ + * variables: { + * id: // value for 'id' + * }, + * }); + */ +export function useApplicationRegistrationTarballUrlQuery(baseOptions: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(ApplicationRegistrationTarballUrlDocument, options); + } +export function useApplicationRegistrationTarballUrlLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(ApplicationRegistrationTarballUrlDocument, options); + } +export type ApplicationRegistrationTarballUrlQueryHookResult = ReturnType; +export type ApplicationRegistrationTarballUrlLazyQueryHookResult = ReturnType; +export type ApplicationRegistrationTarballUrlQueryResult = Apollo.QueryResult; export const FindApplicationRegistrationByClientIdDocument = gql` query FindApplicationRegistrationByClientId($clientId: String!) { findApplicationRegistrationByClientId(clientId: $clientId) { diff --git a/packages/twenty-front/src/modules/applications/graphql/queries/findManyApplications.ts b/packages/twenty-front/src/modules/applications/graphql/queries/findManyApplications.ts index 5144c9c928b..d663753866d 100644 --- a/packages/twenty-front/src/modules/applications/graphql/queries/findManyApplications.ts +++ b/packages/twenty-front/src/modules/applications/graphql/queries/findManyApplications.ts @@ -7,6 +7,7 @@ export const FIND_MANY_APPLICATIONS = gql` name description version + universalIdentifier applicationRegistrationId applicationRegistration { id diff --git a/packages/twenty-front/src/modules/applications/graphql/queries/findOneApplicationByUniversalIdentifier.ts b/packages/twenty-front/src/modules/applications/graphql/queries/findOneApplicationByUniversalIdentifier.ts new file mode 100644 index 00000000000..d914982a872 --- /dev/null +++ b/packages/twenty-front/src/modules/applications/graphql/queries/findOneApplicationByUniversalIdentifier.ts @@ -0,0 +1,9 @@ +import { gql } from '@apollo/client'; + +export const FIND_ONE_APPLICATION_BY_UNIVERSAL_IDENTIFIER = gql` + query FindOneApplicationByUniversalIdentifier($universalIdentifier: UUID!) { + findOneApplication(universalIdentifier: $universalIdentifier) { + id + } + } +`; diff --git a/packages/twenty-front/src/modules/marketplace/graphql/fragments/marketplaceAppFragment.ts b/packages/twenty-front/src/modules/marketplace/graphql/fragments/marketplaceAppFragment.ts index 6ebbe4afdb1..d3fa666561f 100644 --- a/packages/twenty-front/src/modules/marketplace/graphql/fragments/marketplaceAppFragment.ts +++ b/packages/twenty-front/src/modules/marketplace/graphql/fragments/marketplaceAppFragment.ts @@ -50,6 +50,7 @@ export const MARKETPLACE_APP_FRAGMENT = gql` description } sourcePackage + isFeatured defaultRole { id label diff --git a/packages/twenty-front/src/modules/marketplace/graphql/mutations/installApplication.ts b/packages/twenty-front/src/modules/marketplace/graphql/mutations/installApplication.ts new file mode 100644 index 00000000000..e7731d94a75 --- /dev/null +++ b/packages/twenty-front/src/modules/marketplace/graphql/mutations/installApplication.ts @@ -0,0 +1,7 @@ +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/installNpmApp.ts b/packages/twenty-front/src/modules/marketplace/graphql/mutations/installNpmApp.ts deleted file mode 100644 index 575a7dea763..00000000000 --- a/packages/twenty-front/src/modules/marketplace/graphql/mutations/installNpmApp.ts +++ /dev/null @@ -1,7 +0,0 @@ -import gql from 'graphql-tag'; - -export const INSTALL_NPM_APP = gql` - mutation InstallNpmApp($packageName: String!, $version: String) { - installNpmApp(packageName: $packageName, version: $version) - } -`; diff --git a/packages/twenty-front/src/modules/marketplace/graphql/mutations/registerNpmPackage.ts b/packages/twenty-front/src/modules/marketplace/graphql/mutations/registerNpmPackage.ts new file mode 100644 index 00000000000..9b4009d1591 --- /dev/null +++ b/packages/twenty-front/src/modules/marketplace/graphql/mutations/registerNpmPackage.ts @@ -0,0 +1,11 @@ +import { gql } from '@apollo/client'; + +export const REGISTER_NPM_PACKAGE = gql` + mutation RegisterNpmPackage($packageName: String!) { + registerNpmPackage(packageName: $packageName) { + id + universalIdentifier + name + } + } +`; diff --git a/packages/twenty-front/src/modules/marketplace/graphql/queries/findOneMarketplaceApp.ts b/packages/twenty-front/src/modules/marketplace/graphql/queries/findOneMarketplaceApp.ts new file mode 100644 index 00000000000..913fb4927b8 --- /dev/null +++ b/packages/twenty-front/src/modules/marketplace/graphql/queries/findOneMarketplaceApp.ts @@ -0,0 +1,12 @@ +import gql from 'graphql-tag'; + +import { MARKETPLACE_APP_FRAGMENT } from '@/marketplace/graphql/fragments/marketplaceAppFragment'; + +export const FIND_ONE_MARKETPLACE_APP = gql` + ${MARKETPLACE_APP_FRAGMENT} + query FindOneMarketplaceApp($universalIdentifier: String!) { + findOneMarketplaceApp(universalIdentifier: $universalIdentifier) { + ...MarketplaceAppFields + } + } +`; diff --git a/packages/twenty-front/src/modules/marketplace/hooks/useInstallApp.ts b/packages/twenty-front/src/modules/marketplace/hooks/useInstallApp.ts index 31570c632fd..211c90e034d 100644 --- a/packages/twenty-front/src/modules/marketplace/hooks/useInstallApp.ts +++ b/packages/twenty-front/src/modules/marketplace/hooks/useInstallApp.ts @@ -26,9 +26,11 @@ export const useInstallApp = >( } return false; - } catch { + } catch (error) { + const graphqlMessage = error instanceof Error ? error.message : undefined; + enqueueErrorSnackBar({ - message: t`Failed to install the application.`, + message: graphqlMessage ?? t`Failed to install the application.`, }); return false; diff --git a/packages/twenty-front/src/modules/marketplace/hooks/useInstallNpmApp.ts b/packages/twenty-front/src/modules/marketplace/hooks/useInstallNpmApp.ts deleted file mode 100644 index 9168b8a596f..00000000000 --- a/packages/twenty-front/src/modules/marketplace/hooks/useInstallNpmApp.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { useMutation } from '@apollo/client'; - -import { useInstallApp } from '~/modules/marketplace/hooks/useInstallApp'; -import { INSTALL_NPM_APP } from '~/modules/marketplace/graphql/mutations/installNpmApp'; - -export const useInstallNpmApp = () => { - const [installNpmAppMutation] = useMutation(INSTALL_NPM_APP); - - return useInstallApp<{ - packageName: string; - version?: string; - }>(installNpmAppMutation); -}; diff --git a/packages/twenty-front/src/modules/marketplace/hooks/useRegisterNpmPackage.ts b/packages/twenty-front/src/modules/marketplace/hooks/useRegisterNpmPackage.ts new file mode 100644 index 00000000000..11b3aaa0f4e --- /dev/null +++ b/packages/twenty-front/src/modules/marketplace/hooks/useRegisterNpmPackage.ts @@ -0,0 +1,50 @@ +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 { REGISTER_NPM_PACKAGE } from '~/modules/marketplace/graphql/mutations/registerNpmPackage'; + +export const useRegisterNpmPackage = () => { + const [registerNpmPackageMutation] = useMutation(REGISTER_NPM_PACKAGE); + const { enqueueErrorSnackBar, enqueueSuccessSnackBar } = useSnackBar(); + const [isRegistering, setIsRegistering] = useState(false); + + const register = async (params: { + packageName: string; + }): Promise => { + setIsRegistering(true); + + try { + const result = await registerNpmPackageMutation({ + variables: { packageName: params.packageName }, + }); + + const registration = result.data?.registerNpmPackage; + + if (!isDefined(registration)) { + enqueueErrorSnackBar({ message: t`Registration failed.` }); + + return false; + } + + enqueueSuccessSnackBar({ + message: t`Package registered successfully.`, + }); + + return true; + } catch (error) { + const graphqlMessage = error instanceof Error ? error.message : undefined; + + enqueueErrorSnackBar({ + message: graphqlMessage ?? t`Failed to register npm package.`, + }); + + return false; + } finally { + setIsRegistering(false); + } + }; + + return { register, isRegistering }; +}; diff --git a/packages/twenty-front/src/modules/marketplace/hooks/useUpgradeApplication.ts b/packages/twenty-front/src/modules/marketplace/hooks/useUpgradeApplication.ts index af1ff1e9027..7f270421501 100644 --- a/packages/twenty-front/src/modules/marketplace/hooks/useUpgradeApplication.ts +++ b/packages/twenty-front/src/modules/marketplace/hooks/useUpgradeApplication.ts @@ -29,9 +29,11 @@ export const useUpgradeApplication = () => { } return false; - } catch { + } catch (error) { + const graphqlMessage = error instanceof Error ? error.message : undefined; + enqueueErrorSnackBar({ - message: t`Failed to upgrade the application.`, + message: graphqlMessage ?? t`Failed to upgrade the application.`, }); return false; diff --git a/packages/twenty-front/src/modules/marketplace/hooks/useUploadAppTarball.ts b/packages/twenty-front/src/modules/marketplace/hooks/useUploadAppTarball.ts index dc96f5713d5..87ed302d9c2 100644 --- a/packages/twenty-front/src/modules/marketplace/hooks/useUploadAppTarball.ts +++ b/packages/twenty-front/src/modules/marketplace/hooks/useUploadAppTarball.ts @@ -8,6 +8,7 @@ import { UPLOAD_APP_TARBALL } from '~/modules/marketplace/graphql/mutations/uplo type UploadResult = | { success: true; + registrationId: string; universalIdentifier: string; } | { @@ -29,7 +30,10 @@ export const useUploadAppTarball = () => { const registration = result.data?.uploadAppTarball; - if (!isDefined(registration?.universalIdentifier)) { + if ( + !isDefined(registration?.id) || + !isDefined(registration?.universalIdentifier) + ) { enqueueErrorSnackBar({ message: t`Upload failed.` }); return { success: false }; @@ -37,11 +41,14 @@ export const useUploadAppTarball = () => { return { success: true, + registrationId: registration.id, universalIdentifier: registration.universalIdentifier, }; - } catch { + } catch (error) { + const graphqlMessage = error instanceof Error ? error.message : undefined; + enqueueErrorSnackBar({ - message: t`Failed to upload tarball.`, + message: graphqlMessage ?? t`Failed to upload tarball.`, }); return { success: false }; diff --git a/packages/twenty-front/src/modules/settings/admin-panel/ai/components/SettingsAdminAI.tsx b/packages/twenty-front/src/modules/settings/admin-panel/ai/components/SettingsAdminAI.tsx index f17364b4808..3a7a1cbfdac 100644 --- a/packages/twenty-front/src/modules/settings/admin-panel/ai/components/SettingsAdminAI.tsx +++ b/packages/twenty-front/src/modules/settings/admin-panel/ai/components/SettingsAdminAI.tsx @@ -1,27 +1,17 @@ import { useState } from 'react'; -import { styled } from '@linaria/react'; import { useClientConfig } from '@/client-config/hooks/useClientConfig'; import { GET_ADMIN_AI_MODELS } from '@/settings/admin-panel/ai/graphql/queries/getAdminAiModels'; import { SettingsOptionCardContentToggle } from '@/settings/components/SettingsOptions/SettingsOptionCardContentToggle'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; -import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { t } from '@lingui/core/macro'; -import { - H2Title, - IconArchive, - IconFilter, - IconPlug, - IconRobot, - IconSearch, -} from 'twenty-ui/display'; -import { Button } from 'twenty-ui/input'; +import { H2Title, IconArchive, IconPlug, IconRobot } from 'twenty-ui/display'; +import { SearchInput } from 'twenty-ui/input'; import { Card, Section } from 'twenty-ui/layout'; import { MenuItemToggle } from 'twenty-ui/navigation'; -import { themeCssVariables } from 'twenty-ui/theme-constants'; import { useCreateDatabaseConfigVariableMutation, useGetAdminAiModelsQuery, @@ -30,17 +20,6 @@ import { import { getModelIcon } from '~/pages/settings/ai/utils/getModelIcon'; import { getModelProviderLabel } from '~/pages/settings/ai/utils/getModelProviderLabel'; -const StyledSearchAndFilterContainer = styled.div` - display: flex; - gap: ${themeCssVariables.spacing[2]}; - margin-bottom: ${themeCssVariables.spacing[2]}; - width: 100%; -`; - -const StyledSearchInputContainer = styled.div` - flex: 1; -`; - export const SettingsAdminAI = () => { const { enqueueErrorSnackBar } = useSnackBar(); const [searchQuery, setSearchQuery] = useState(''); @@ -162,53 +141,41 @@ export const SettingsAdminAI = () => { description={t`Toggle model availability across all workspaces`} /> - - - ( + + + + setShowUnconfigured(!showUnconfigured) + } + toggled={showUnconfigured} + text={t`Unconfigured models`} + toggleSize="small" + /> + setShowDeprecated(!showDeprecated)} + toggled={showDeprecated} + text={t`Deprecated models`} + toggleSize="small" + /> + + + } /> - - - } - dropdownComponents={ - - - - setShowUnconfigured(!showUnconfigured) - } - toggled={showUnconfigured} - text={t`Unconfigured models`} - toggleSize="small" - /> - setShowDeprecated(!showDeprecated)} - toggled={showDeprecated} - text={t`Deprecated models`} - toggleSize="small" - /> - - - } - /> - + )} + /> {filteredModels.map((model, index) => ( diff --git a/packages/twenty-front/src/modules/settings/admin-panel/apps/components/SettingsAdminApps.tsx b/packages/twenty-front/src/modules/settings/admin-panel/apps/components/SettingsAdminApps.tsx new file mode 100644 index 00000000000..dbdc935e39d --- /dev/null +++ b/packages/twenty-front/src/modules/settings/admin-panel/apps/components/SettingsAdminApps.tsx @@ -0,0 +1,107 @@ +import { FIND_ALL_APPLICATION_REGISTRATIONS } from '@/settings/admin-panel/apps/graphql/queries/findAllApplicationRegistrations'; +import { Table } from '@/ui/layout/table/components/Table'; +import { TableBody } from '@/ui/layout/table/components/TableBody'; +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 { useQuery } from '@apollo/client'; +import { styled } from '@linaria/react'; +import { t } from '@lingui/core/macro'; +import { useState } from 'react'; +import { getSettingsPath } from 'twenty-shared/utils'; +import { SettingsPath } from 'twenty-shared/types'; +import { H2Title, Status } from 'twenty-ui/display'; +import { SearchInput } from 'twenty-ui/input'; +import { Section } from 'twenty-ui/layout'; +import { UndecoratedLink } from 'twenty-ui/navigation'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { type ApplicationRegistrationFragmentFragment } from '~/generated-metadata/graphql'; + +const StyledTableContainer = styled.div` + margin-top: ${themeCssVariables.spacing[3]}; +`; + +const StyledTableHeaderRowContainer = styled.div` + margin-bottom: ${themeCssVariables.spacing[2]}; +`; + +const TABLE_GRID = '1fr 1fr 100px 80px'; + +export const SettingsAdminApps = () => { + const [searchQuery, setSearchQuery] = useState(''); + + const { data } = useQuery(FIND_ALL_APPLICATION_REGISTRATIONS); + + const registrations: ApplicationRegistrationFragmentFragment[] = + data?.findAllApplicationRegistrations ?? []; + + const filtered = + searchQuery.trim().length === 0 + ? registrations + : registrations.filter((registration) => { + const query = searchQuery.toLowerCase(); + + return ( + registration.name.toLowerCase().includes(query) || + (registration.sourcePackage ?? '').toLowerCase().includes(query) || + registration.universalIdentifier.toLowerCase().includes(query) + ); + }); + + return ( +
+ + + + + + + {t`Name`} + {t`Source`} + {t`Listed`} + {t`Featured`} + + + + {filtered.map((registration) => ( + + + {registration.name} + + {registration.sourcePackage ?? registration.sourceType} + + + + + + + + + + ))} + +
+
+
+ ); +}; diff --git a/packages/twenty-front/src/modules/settings/admin-panel/apps/graphql/queries/findAllApplicationRegistrations.ts b/packages/twenty-front/src/modules/settings/admin-panel/apps/graphql/queries/findAllApplicationRegistrations.ts new file mode 100644 index 00000000000..82e35e01ebf --- /dev/null +++ b/packages/twenty-front/src/modules/settings/admin-panel/apps/graphql/queries/findAllApplicationRegistrations.ts @@ -0,0 +1,12 @@ +import { gql } from '@apollo/client'; + +import { APPLICATION_REGISTRATION_FRAGMENT } from '@/settings/application-registrations/graphql/fragments/applicationRegistrationFragment'; + +export const FIND_ALL_APPLICATION_REGISTRATIONS = gql` + query FindAllApplicationRegistrations { + findAllApplicationRegistrations { + ...ApplicationRegistrationFragment + } + } + ${APPLICATION_REGISTRATION_FRAGMENT} +`; diff --git a/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminContent.tsx b/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminContent.tsx index bc522ff7696..7ca51933284 100644 --- a/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminContent.tsx +++ b/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminContent.tsx @@ -5,6 +5,7 @@ import { SETTINGS_ADMIN_TABS_ID } from '@/settings/admin-panel/constants/Setting import { TabList } from '@/ui/layout/tab-list/components/TabList'; import { t } from '@lingui/core/macro'; import { + IconApps, IconHeart, IconSettings2, IconSparkles, @@ -24,6 +25,12 @@ export const SettingsAdminContent = () => { Icon: IconSettings2, disabled: !canAccessFullAdminPanel && !canImpersonate, }, + { + id: SETTINGS_ADMIN_TABS.APPS, + title: t`Apps`, + Icon: IconApps, + disabled: !canAccessFullAdminPanel, + }, { id: SETTINGS_ADMIN_TABS.AI, title: t`AI`, diff --git a/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminTabContent.tsx b/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminTabContent.tsx index 6387007601f..2063680883d 100644 --- a/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminTabContent.tsx +++ b/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminTabContent.tsx @@ -1,4 +1,5 @@ import { SettingsAdminAI } from '@/settings/admin-panel/ai/components/SettingsAdminAI'; +import { SettingsAdminApps } from '@/settings/admin-panel/apps/components/SettingsAdminApps'; import { SettingsAdminGeneral } from '@/settings/admin-panel/components/SettingsAdminGeneral'; import { SettingsAdminConfigVariables } from '@/settings/admin-panel/config-variables/components/SettingsAdminConfigVariables'; import { SETTINGS_ADMIN_TABS } from '@/settings/admin-panel/constants/SettingsAdminTabs'; @@ -16,6 +17,8 @@ export const SettingsAdminTabContent = () => { switch (activeTabId) { case SETTINGS_ADMIN_TABS.GENERAL: return ; + case SETTINGS_ADMIN_TABS.APPS: + return ; case SETTINGS_ADMIN_TABS.AI: return ; case SETTINGS_ADMIN_TABS.CONFIG_VARIABLES: diff --git a/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminTableCard.tsx b/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminTableCard.tsx index 9d3b7fe11dc..22479fc44a0 100644 --- a/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminTableCard.tsx +++ b/packages/twenty-front/src/modules/settings/admin-panel/components/SettingsAdminTableCard.tsx @@ -45,13 +45,13 @@ export const SettingsAdminTableCard = ({ {item.Icon && } {item.label} @@ -59,9 +59,10 @@ export const SettingsAdminTableCard = ({ {item.value} diff --git a/packages/twenty-front/src/modules/settings/admin-panel/config-variables/components/ConfigVariableSearchInput.tsx b/packages/twenty-front/src/modules/settings/admin-panel/config-variables/components/ConfigVariableSearchInput.tsx index 89abbea65e0..d73e7bbc233 100644 --- a/packages/twenty-front/src/modules/settings/admin-panel/config-variables/components/ConfigVariableSearchInput.tsx +++ b/packages/twenty-front/src/modules/settings/admin-panel/config-variables/components/ConfigVariableSearchInput.tsx @@ -1,11 +1,5 @@ -import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput'; -import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; -import { IconSearch } from 'twenty-ui/display'; - -const StyledSearchInputContainer = styled.div` - width: 100%; -`; +import { SearchInput } from 'twenty-ui/input'; type ConfigVariableSearchInputProps = { value: string; @@ -17,15 +11,10 @@ export const ConfigVariableSearchInput = ({ onChange, }: ConfigVariableSearchInputProps) => { return ( - - - + ); }; diff --git a/packages/twenty-front/src/modules/settings/admin-panel/constants/SettingsAdminTabs.ts b/packages/twenty-front/src/modules/settings/admin-panel/constants/SettingsAdminTabs.ts index 4aa7bd6e46c..3cf4c9d64a4 100644 --- a/packages/twenty-front/src/modules/settings/admin-panel/constants/SettingsAdminTabs.ts +++ b/packages/twenty-front/src/modules/settings/admin-panel/constants/SettingsAdminTabs.ts @@ -1,5 +1,6 @@ export const SETTINGS_ADMIN_TABS = { GENERAL: 'general', + APPS: 'apps', AI: 'ai', CONFIG_VARIABLES: 'config-variables', HEALTH_STATUS: 'health-status', diff --git a/packages/twenty-front/src/modules/settings/application-registrations/graphql/fragments/applicationRegistrationFragment.ts b/packages/twenty-front/src/modules/settings/application-registrations/graphql/fragments/applicationRegistrationFragment.ts index f129e72cecb..87ff0263cf7 100644 --- a/packages/twenty-front/src/modules/settings/application-registrations/graphql/fragments/applicationRegistrationFragment.ts +++ b/packages/twenty-front/src/modules/settings/application-registrations/graphql/fragments/applicationRegistrationFragment.ts @@ -16,6 +16,9 @@ export const APPLICATION_REGISTRATION_FRAGMENT = gql` latestAvailableVersion websiteUrl termsUrl + isListed + isFeatured + ownerWorkspaceId createdAt updatedAt } diff --git a/packages/twenty-front/src/modules/settings/application-registrations/graphql/mutations/transferApplicationRegistrationOwnership.ts b/packages/twenty-front/src/modules/settings/application-registrations/graphql/mutations/transferApplicationRegistrationOwnership.ts new file mode 100644 index 00000000000..d0f74374cfe --- /dev/null +++ b/packages/twenty-front/src/modules/settings/application-registrations/graphql/mutations/transferApplicationRegistrationOwnership.ts @@ -0,0 +1,16 @@ +import { gql } from '@apollo/client'; + +export const TRANSFER_APPLICATION_REGISTRATION_OWNERSHIP = gql` + mutation TransferApplicationRegistrationOwnership( + $applicationRegistrationId: String! + $targetWorkspaceSubdomain: String! + ) { + transferApplicationRegistrationOwnership( + applicationRegistrationId: $applicationRegistrationId + targetWorkspaceSubdomain: $targetWorkspaceSubdomain + ) { + id + name + } + } +`; diff --git a/packages/twenty-front/src/modules/settings/application-registrations/graphql/queries/applicationRegistrationTarballUrl.ts b/packages/twenty-front/src/modules/settings/application-registrations/graphql/queries/applicationRegistrationTarballUrl.ts new file mode 100644 index 00000000000..a20ee989a74 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/application-registrations/graphql/queries/applicationRegistrationTarballUrl.ts @@ -0,0 +1,7 @@ +import { gql } from '@apollo/client'; + +export const APPLICATION_REGISTRATION_TARBALL_URL = gql` + query ApplicationRegistrationTarballUrl($id: String!) { + applicationRegistrationTarballUrl(id: $id) + } +`; diff --git a/packages/twenty-front/src/pages/settings/applications/SettingsApplicationRegistrationDetails.tsx b/packages/twenty-front/src/pages/settings/applications/SettingsApplicationRegistrationDetails.tsx index 90f8f529560..bcf711a6cbb 100644 --- a/packages/twenty-front/src/pages/settings/applications/SettingsApplicationRegistrationDetails.tsx +++ b/packages/twenty-front/src/pages/settings/applications/SettingsApplicationRegistrationDetails.tsx @@ -1,8 +1,10 @@ import { SettingsAdminTableCard } from '@/settings/admin-panel/components/SettingsAdminTableCard'; import { DELETE_APPLICATION_REGISTRATION } from '@/settings/application-registrations/graphql/mutations/deleteApplicationRegistration'; import { ROTATE_APPLICATION_REGISTRATION_CLIENT_SECRET } from '@/settings/application-registrations/graphql/mutations/rotateApplicationRegistrationClientSecret'; +import { TRANSFER_APPLICATION_REGISTRATION_OWNERSHIP } from '@/settings/application-registrations/graphql/mutations/transferApplicationRegistrationOwnership'; import { UPDATE_APPLICATION_REGISTRATION } from '@/settings/application-registrations/graphql/mutations/updateApplicationRegistration'; import { UPDATE_APPLICATION_REGISTRATION_VARIABLE } from '@/settings/application-registrations/graphql/mutations/updateApplicationRegistrationVariable'; +import { APPLICATION_REGISTRATION_TARBALL_URL } from '@/settings/application-registrations/graphql/queries/applicationRegistrationTarballUrl'; import { FIND_APPLICATION_REGISTRATION_STATS } from '@/settings/application-registrations/graphql/queries/findApplicationRegistrationStats'; import { FIND_APPLICATION_REGISTRATION_VARIABLES } from '@/settings/application-registrations/graphql/queries/findApplicationRegistrationVariables'; import { FIND_MANY_APPLICATION_REGISTRATIONS } from '@/settings/application-registrations/graphql/queries/findManyApplicationRegistrations'; @@ -16,6 +18,7 @@ import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModa import { useModal } from '@/ui/layout/modal/hooks/useModal'; import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer'; import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue'; +import { useInstallMarketplaceApp } from '~/modules/marketplace/hooks/useInstallMarketplaceApp'; import { useMutation, useQuery } from '@apollo/client'; import { styled } from '@linaria/react'; import { Trans, useLingui } from '@lingui/react/macro'; @@ -25,10 +28,15 @@ import { useParams } from 'react-router-dom'; import { SettingsPath } from 'twenty-shared/types'; import { getSettingsPath, isDefined, isValidUrl } from 'twenty-shared/utils'; import { + H1Title, + H1TitleFontColor, H2Title, + IconArrowRight, IconChartBar, IconCheck, + IconBox, IconDownload, + IconExternalLink, IconKey, IconRefresh, IconShield, @@ -38,15 +46,33 @@ import { IconWorld, Status, } from 'twenty-ui/display'; +import { SettingsOptionCardContentToggle } from '@/settings/components/SettingsOptions/SettingsOptionCardContentToggle'; import { Button } from 'twenty-ui/input'; -import { Section } from 'twenty-ui/layout'; +import { + Card, + Section, + SectionAlignment, + SectionFontColor, +} from 'twenty-ui/layout'; import { useCopyToClipboard } from '~/hooks/useCopyToClipboard'; +import { + ApplicationRegistrationSourceType, + useFindManyApplicationsQuery, +} from '~/generated-metadata/graphql'; import { useNavigateSettings } from '~/hooks/useNavigateSettings'; import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { + StyledAppModal, + StyledAppModalButton, + StyledAppModalSection, + StyledAppModalTitle, +} from '~/pages/settings/applications/components/SettingsAppModalLayout'; import { applicationRegistrationClientSecretFamilyState } from '~/pages/settings/applications/states/applicationRegistrationClientSecretFamilyState'; const DELETE_REGISTRATION_MODAL_ID = 'delete-application-registration-modal'; const ROTATE_SECRET_MODAL_ID = 'rotate-application-registration-secret-modal'; +const TRANSFER_OWNERSHIP_MODAL_ID = + 'transfer-application-registration-ownership-modal'; const StyledInputContainer = styled.div` align-items: center; @@ -99,6 +125,32 @@ const StyledRotateContainer = styled.div` padding-top: ${themeCssVariables.spacing[2]}; `; +const StyledDangerButtonGroup = styled.div` + display: flex; + gap: ${themeCssVariables.spacing[2]}; +`; + +const StyledSourceRow = styled.div` + align-items: center; + display: flex; + gap: ${themeCssVariables.spacing[2]}; +`; + +const StyledDownloadLink = styled.a` + color: ${themeCssVariables.font.color.secondary}; + cursor: pointer; + text-decoration: underline; + &:hover { + color: ${themeCssVariables.font.color.primary}; + } +`; + +const StyledMarketplaceActions = styled.div` + display: flex; + gap: ${themeCssVariables.spacing[2]}; + padding-top: ${themeCssVariables.spacing[2]}; +`; + type ServerVariable = { id: string; key: string; @@ -113,7 +165,7 @@ export const SettingsApplicationRegistrationDetails = () => { const navigate = useNavigateSettings(); const { copyToClipboard } = useCopyToClipboard(); const { enqueueSuccessSnackBar, enqueueErrorSnackBar } = useSnackBar(); - const { openModal } = useModal(); + const { openModal, closeModal } = useModal(); const { applicationRegistrationId = '' } = useParams<{ applicationRegistrationId: string; }>(); @@ -123,11 +175,14 @@ export const SettingsApplicationRegistrationDetails = () => { applicationRegistrationId, ); + const [isInstalling, setIsInstalling] = useState(false); const [isLoading, setIsLoading] = useState(false); const [formRedirectUris, setFormRedirectUris] = useState([]); const [newRedirectUri, setNewRedirectUri] = useState(''); const [hasChanges, setHasChanges] = useState(false); const [rotatedSecret, setRotatedSecret] = useState(null); + const [transferSubdomain, setTransferSubdomain] = useState(''); + const [isTransferring, setIsTransferring] = useState(false); const [variableValues, setVariableValues] = useState>( {}, @@ -158,6 +213,14 @@ export const SettingsApplicationRegistrationDetails = () => { skip: !applicationRegistrationId, }); + const { data: tarballUrlData } = useQuery( + APPLICATION_REGISTRATION_TARBALL_URL, + { + variables: { id: applicationRegistrationId }, + skip: !applicationRegistrationId, + }, + ); + const [updateRegistration] = useMutation(UPDATE_APPLICATION_REGISTRATION, { refetchQueries: [ FIND_ONE_APPLICATION_REGISTRATION, @@ -176,15 +239,120 @@ export const SettingsApplicationRegistrationDetails = () => { refetchQueries: [FIND_APPLICATION_REGISTRATION_VARIABLES], }, ); + const [transferOwnership] = useMutation( + TRANSFER_APPLICATION_REGISTRATION_OWNERSHIP, + { + refetchQueries: [ + FIND_ONE_APPLICATION_REGISTRATION, + FIND_MANY_APPLICATION_REGISTRATIONS, + ], + }, + ); + + const { install } = useInstallMarketplaceApp(); + const { data: applicationsData, refetch: refetchApplications } = + useFindManyApplicationsQuery(); const registration = data?.findOneApplicationRegistration; const variables: ServerVariable[] = variablesData?.findApplicationRegistrationVariables ?? []; + const isNpmSource = + registration?.sourceType === ApplicationRegistrationSourceType.NPM; + if (loading || !registration) { return null; } + const isInstalledOnWorkspace = ( + applicationsData?.findManyApplications ?? [] + ).some( + (application) => + application.universalIdentifier === registration.universalIdentifier, + ); + + const handleToggleListed = async () => { + try { + await updateRegistration({ + variables: { + input: { + id: applicationRegistrationId, + update: { + isListed: !registration.isListed, + }, + }, + }, + }); + enqueueSuccessSnackBar({ + message: registration.isListed + ? t`App removed from marketplace` + : t`App listed on marketplace`, + }); + } catch { + enqueueErrorSnackBar({ + message: t`Error updating marketplace listing`, + }); + } + }; + + const marketplacePageUrl = getSettingsPath( + SettingsPath.AvailableApplicationDetail, + { + availableApplicationId: registration.universalIdentifier, + }, + ); + + const handleInstallOnWorkspace = async () => { + setIsInstalling(true); + try { + const success = await install({ + universalIdentifier: registration.universalIdentifier, + }); + + if (success) { + await refetchApplications(); + enqueueSuccessSnackBar({ + message: t`App installed on this workspace`, + }); + } + } catch { + enqueueErrorSnackBar({ + message: t`Error installing app`, + }); + } finally { + setIsInstalling(false); + } + }; + + const handleTransferOwnership = async () => { + const trimmed = transferSubdomain.trim(); + + if (!isNonEmptyString(trimmed)) { + return; + } + + setIsTransferring(true); + try { + await transferOwnership({ + variables: { + applicationRegistrationId, + targetWorkspaceSubdomain: trimmed, + }, + }); + enqueueSuccessSnackBar({ + message: t`Ownership transferred successfully`, + }); + setTransferSubdomain(''); + navigate(SettingsPath.Applications); + } catch { + enqueueErrorSnackBar({ + message: t`Failed to transfer ownership. Check that the subdomain is correct.`, + }); + } finally { + setIsTransferring(false); + } + }; + const markDirty = () => setHasChanges(true); const handleSave = async () => { @@ -364,6 +532,47 @@ export const SettingsApplicationRegistrationDetails = () => { t`Universal identifier copied`, ), }, + ...(isNpmSource && isNonEmptyString(registration.sourcePackage) + ? [ + { + Icon: IconBox, + label: t`Package`, + value: registration.sourcePackage, + }, + ] + : registration.sourceType === ApplicationRegistrationSourceType.TARBALL + ? [ + { + Icon: IconBox, + label: t`Source`, + value: isNonEmptyString( + tarballUrlData?.applicationRegistrationTarballUrl, + ) ? ( + + + Tarball upload + + + Download + + + ) : ( + t`Tarball upload` + ), + }, + ] + : registration.sourceType === ApplicationRegistrationSourceType.LOCAL + ? [ + { + Icon: IconBox, + label: t`Source`, + value: t`Local development`, + }, + ] + : []), ]; const stats = statsData?.findApplicationRegistrationStats; @@ -447,6 +656,61 @@ export const SettingsApplicationRegistrationDetails = () => { /> +
+ + + + {}} + disabled + /> + + +
+ +
+ +
+
{ description={ hasActiveInstalls ? t`Uninstall this app from all workspaces before deleting it` - : t`Delete this app` + : t`Delete or transfer this app registration` } /> -
@@ -622,6 +895,58 @@ export const SettingsApplicationRegistrationDetails = () => { confirmButtonText={t`Delete`} loading={isLoading} /> + + setTransferSubdomain('')} + padding="large" + dataGloballyPreventClickOutside + > + + + + + {t`Enter the workspace subdomain to transfer this app to. You will lose access to manage it.`} + +
+ +
+ { + closeModal(TRANSFER_OWNERSHIP_MODAL_ID); + setTransferSubdomain(''); + }} + variant="secondary" + title={t`Cancel`} + fullWidth + /> + +
); }; diff --git a/packages/twenty-front/src/pages/settings/applications/SettingsAvailableApplicationDetails.tsx b/packages/twenty-front/src/pages/settings/applications/SettingsAvailableApplicationDetails.tsx index 96fb23b0d16..c8639e6fd9d 100644 --- a/packages/twenty-front/src/pages/settings/applications/SettingsAvailableApplicationDetails.tsx +++ b/packages/twenty-front/src/pages/settings/applications/SettingsAvailableApplicationDetails.tsx @@ -7,16 +7,18 @@ import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTab import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue'; import { styled } from '@linaria/react'; import { t } from '@lingui/core/macro'; -import { useMemo, useState } from 'react'; +import { useState } from 'react'; import { useParams } from 'react-router-dom'; import { SettingsPath } from 'twenty-shared/types'; import { getSettingsPath, isDefined } from 'twenty-shared/utils'; import { IconApps, IconBox, + IconCheck, IconColumns, IconCommand, IconDownload, + IconEyeOff, IconFileText, IconInfoCircle, IconLayoutGrid, @@ -27,7 +29,11 @@ import { import { Button } from 'twenty-ui/input'; import { Section } from 'twenty-ui/layout'; import { themeCssVariables } from 'twenty-ui/theme-constants'; -import { PermissionFlagType } from '~/generated-metadata/graphql'; +import { + PermissionFlagType, + useFindOneApplicationByUniversalIdentifierQuery, + useFindOneMarketplaceAppQuery, +} from '~/generated-metadata/graphql'; import { useMarketplaceApps } from '~/modules/marketplace/hooks/useMarketplaceApps'; import { SettingsApplicationPermissionsTab } from '~/pages/settings/applications/tabs/SettingsApplicationPermissionsTab'; import { SettingsAvailableApplicationDetailContentTab } from '~/pages/settings/applications/tabs/SettingsAvailableApplicationDetailContentTab'; @@ -240,6 +246,19 @@ const StyledProviderItem = styled.li` margin-bottom: ${themeCssVariables.spacing[1]}; `; +const StyledUnlistedBanner = styled.div` + align-items: center; + background-color: ${themeCssVariables.background.transparent.lighter}; + border: 1px solid ${themeCssVariables.border.color.medium}; + border-radius: ${themeCssVariables.border.radius.sm}; + color: ${themeCssVariables.font.color.secondary}; + display: flex; + font-size: ${themeCssVariables.font.size.md}; + gap: ${themeCssVariables.spacing[2]}; + margin-bottom: ${themeCssVariables.spacing[4]}; + padding: ${themeCssVariables.spacing[3]} ${themeCssVariables.spacing[4]}; +`; + export const SettingsAvailableApplicationDetails = () => { const { availableApplicationId = '' } = useParams<{ availableApplicationId: string; @@ -252,10 +271,44 @@ export const SettingsAvailableApplicationDetails = () => { const canInstallMarketplaceApps = useHasPermissionFlag( PermissionFlagType.MARKETPLACE_APPS, ); + const { data: installedAppData } = + useFindOneApplicationByUniversalIdentifierQuery({ + variables: { universalIdentifier: availableApplicationId }, + skip: !availableApplicationId, + }); - const application = useMemo(() => { - return marketplaceApps?.find((app) => app.id === availableApplicationId); - }, [availableApplicationId, marketplaceApps]); + const listedApp = marketplaceApps?.find( + (app) => app.id === availableApplicationId, + ); + + const { data: singleAppData } = useFindOneMarketplaceAppQuery({ + variables: { universalIdentifier: availableApplicationId }, + skip: isDefined(listedApp) || !availableApplicationId, + }); + + const singleApp = singleAppData?.findOneMarketplaceApp; + + const application = isDefined(listedApp) + ? listedApp + : isDefined(singleApp) + ? { + ...singleApp, + content: { + objects: (singleApp.objects ?? []).length, + fields: + (singleApp.objects ?? []).reduce( + (count, appObject) => count + appObject.fields.length, + 0, + ) + (singleApp.fields ?? []).length, + functions: (singleApp.logicFunctions ?? []).length, + frontComponents: (singleApp.frontComponents ?? []).length, + }, + } + : undefined; + + const isUnlisted = !isDefined(listedApp) && isDefined(application); + + const isAlreadyInstalled = isDefined(installedAppData?.findOneApplication); const handleInstall = async () => { if (isDefined(application)) { @@ -438,6 +491,12 @@ export const SettingsAvailableApplicationDetails = () => { ]} > + {isUnlisted && ( + + + {t`This application is not listed on the marketplace. It was shared via a direct link.`} + + )} @@ -461,12 +520,18 @@ export const SettingsAvailableApplicationDetails = () => { {canInstallMarketplaceApps && (