From 1128331cc10e38f90c1d78fcb9d1858b61615741 Mon Sep 17 00:00:00 2001 From: Paul Rastoin <45004772+prastoin@users.noreply.github.com> Date: Tue, 30 Dec 2025 16:02:07 +0100 Subject: [PATCH] Fix field item type tag (#16860) # Introduction This has been fixed on main already 1 hour ago, this PR now only passes the field application id instead of the object applicationId that could be different for example when creating a custom field on a standard object For the moment not introducing any logic around application integrity directly and still relying on the isCustom and standardId definition This will have to be refactored once we deprecate the standardId --- .../src/generated-metadata/graphql.ts | 19 +++--- .../twenty-front/src/generated/graphql.ts | 1 + .../object-metadata/graphql/fragment.ts | 1 + .../object-metadata/graphql/mutations.ts | 3 + .../hooks/__mocks__/useFieldMetadataItem.ts | 4 ++ .../__tests__/useFieldMetadataItem.test.tsx | 8 +-- .../isObjectMetadataSettingsReadOnly.test.ts | 62 ------------------- .../utils/isObjectMetadataSettingsReadOnly.ts | 17 ----- .../components/SettingsItemTypeTag.tsx | 2 +- .../SettingsObjectFieldItemTableRow.tsx | 7 +-- .../SettingsObjectRelationItemTableRow.tsx | 4 +- ...SettingsUpdateDataModelObjectAboutForm.tsx | 4 +- .../components/tabs/ObjectFields.tsx | 6 +- .../components/tabs/ObjectSettings.tsx | 9 ++- ...SettingsDataModelObjectIdentifiersForm.tsx | 4 +- .../data-model/utils/getItemTagInfo.ts | 4 +- .../data-model/SettingsObjectDetailPage.tsx | 4 +- .../data-model/SettingsObjectFieldEdit.tsx | 4 +- .../data-model/SettingsObjectTable.tsx | 2 +- .../field-metadata/dtos/create-field.input.ts | 8 ++- .../field-metadata/dtos/field-metadata.dto.ts | 3 + .../field-metadata/dtos/update-field.input.ts | 1 + ...adata-entity-to-field-metadata-dto.util.ts | 30 --------- ...eld-metadata-to-field-metadata-dto.util.ts | 2 + 24 files changed, 62 insertions(+), 147 deletions(-) delete mode 100644 packages/twenty-front/src/modules/object-record/read-only/utils/__tests__/isObjectMetadataSettingsReadOnly.test.ts delete mode 100644 packages/twenty-front/src/modules/object-record/read-only/utils/isObjectMetadataSettingsReadOnly.ts delete mode 100644 packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/from-field-metadata-entity-to-field-metadata-dto.util.ts diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index b1f717055c..01093fd44a 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -1330,6 +1330,7 @@ export enum FeatureFlagKey { export type Field = { __typename?: 'Field'; + applicationId?: Maybe; createdAt: Scalars['DateTime']; defaultValue?: Maybe; description?: Maybe; @@ -5174,7 +5175,7 @@ export type UpdateOneApplicationVariableMutationVariables = Exact<{ export type UpdateOneApplicationVariableMutation = { __typename?: 'Mutation', updateOneApplicationVariable: boolean }; -export type ApplicationFieldsFragment = { __typename?: 'Application', id: string, name: string, description: string, version: string, universalIdentifier: string, canBeUninstalled: boolean, 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, 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 | null, 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, 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, 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 }> }>, serverlessFunctions: Array<{ __typename?: 'ServerlessFunction', id: string, name: string, description?: string | null, runtime: string, timeoutSeconds: number, latestVersion?: string | null, publishedVersions: Array, handlerPath: string, handlerName: string, createdAt: string, updatedAt: string, cronTriggers?: Array<{ __typename?: 'CronTrigger', id: string, settings: any, createdAt: string, updatedAt: string }> | null, databaseEventTriggers?: Array<{ __typename?: 'DatabaseEventTrigger', id: string, settings: any, createdAt: string, updatedAt: string }> | null, routeTriggers?: Array<{ __typename?: 'RouteTrigger', id: string, path: string, isAuthRequired: boolean, httpMethod: HttpMethod, createdAt: string, updatedAt: string }> | null }> }; +export type ApplicationFieldsFragment = { __typename?: 'Application', id: string, name: string, description: string, version: string, universalIdentifier: string, canBeUninstalled: boolean, 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, 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 | null, 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, 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, applicationId?: string | null, 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 }> }>, serverlessFunctions: Array<{ __typename?: 'ServerlessFunction', id: string, name: string, description?: string | null, runtime: string, timeoutSeconds: number, latestVersion?: string | null, publishedVersions: Array, handlerPath: string, handlerName: string, createdAt: string, updatedAt: string, cronTriggers?: Array<{ __typename?: 'CronTrigger', id: string, settings: any, createdAt: string, updatedAt: string }> | null, databaseEventTriggers?: Array<{ __typename?: 'DatabaseEventTrigger', id: string, settings: any, createdAt: string, updatedAt: string }> | null, routeTriggers?: Array<{ __typename?: 'RouteTrigger', id: string, path: string, isAuthRequired: boolean, httpMethod: HttpMethod, createdAt: string, updatedAt: string }> | null }> }; export type FindManyApplicationsQueryVariables = Exact<{ [key: string]: never; }>; @@ -5186,7 +5187,7 @@ export type FindOneApplicationQueryVariables = Exact<{ }>; -export type FindOneApplicationQuery = { __typename?: 'Query', findOneApplication: { __typename?: 'Application', id: string, name: string, description: string, version: string, universalIdentifier: string, canBeUninstalled: boolean, 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, 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 | null, 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, 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, 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 }> }>, serverlessFunctions: Array<{ __typename?: 'ServerlessFunction', id: string, name: string, description?: string | null, runtime: string, timeoutSeconds: number, latestVersion?: string | null, publishedVersions: Array, handlerPath: string, handlerName: string, createdAt: string, updatedAt: string, cronTriggers?: Array<{ __typename?: 'CronTrigger', id: string, settings: any, createdAt: string, updatedAt: string }> | null, databaseEventTriggers?: Array<{ __typename?: 'DatabaseEventTrigger', id: string, settings: any, createdAt: string, updatedAt: string }> | null, routeTriggers?: Array<{ __typename?: 'RouteTrigger', id: string, path: string, isAuthRequired: boolean, httpMethod: HttpMethod, createdAt: string, updatedAt: string }> | null }> } }; +export type FindOneApplicationQuery = { __typename?: 'Query', findOneApplication: { __typename?: 'Application', id: string, name: string, description: string, version: string, universalIdentifier: string, canBeUninstalled: boolean, 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, 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 | null, 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, 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, applicationId?: string | null, 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 }> }>, serverlessFunctions: Array<{ __typename?: 'ServerlessFunction', id: string, name: string, description?: string | null, runtime: string, timeoutSeconds: number, latestVersion?: string | null, publishedVersions: Array, handlerPath: string, handlerName: string, createdAt: string, updatedAt: string, cronTriggers?: Array<{ __typename?: 'CronTrigger', id: string, settings: any, createdAt: string, updatedAt: string }> | null, databaseEventTriggers?: Array<{ __typename?: 'DatabaseEventTrigger', id: string, settings: any, createdAt: string, updatedAt: string }> | null, routeTriggers?: Array<{ __typename?: 'RouteTrigger', id: string, path: string, isAuthRequired: boolean, httpMethod: HttpMethod, createdAt: string, updatedAt: string }> | null }> } }; export type UploadFileMutationVariables = Exact<{ file: Scalars['Upload']; @@ -5563,7 +5564,7 @@ export type DeleteFileMutationVariables = Exact<{ export type DeleteFileMutation = { __typename?: 'Mutation', deleteFile: { __typename?: 'File', id: string, name: string, fullPath: string, size: number, type: string, createdAt: string } }; -export type ObjectMetadataFieldsFragment = { __typename?: 'Object', id: 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 | null, 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, 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, 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 }> }; +export type ObjectMetadataFieldsFragment = { __typename?: 'Object', id: 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 | null, 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, 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, applicationId?: string | null, 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 }> }; export type CreateOneObjectMetadataItemMutationVariables = Exact<{ input: CreateOneObjectInput; @@ -5577,7 +5578,7 @@ export type CreateOneFieldMetadataItemMutationVariables = Exact<{ }>; -export type CreateOneFieldMetadataItemMutation = { __typename?: 'Mutation', createOneField: { __typename?: 'Field', id: string, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, isCustom?: boolean | null, isActive?: boolean | null, isUnique?: boolean | null, isNullable?: boolean | null, createdAt: string, updatedAt: string, settings?: any | null, defaultValue?: any | null, options?: any | null, isLabelSyncedWithName?: boolean | null, object?: { __typename?: 'Object', id: string } | null } }; +export type CreateOneFieldMetadataItemMutation = { __typename?: 'Mutation', createOneField: { __typename?: 'Field', id: string, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, isCustom?: boolean | null, isActive?: boolean | null, isUnique?: boolean | null, isNullable?: boolean | null, createdAt: string, updatedAt: string, settings?: any | null, defaultValue?: any | null, options?: any | null, isLabelSyncedWithName?: boolean | null, applicationId?: string | null, object?: { __typename?: 'Object', id: string } | null } }; export type UpdateOneFieldMetadataItemMutationVariables = Exact<{ idToUpdate: Scalars['UUID']; @@ -5585,7 +5586,7 @@ export type UpdateOneFieldMetadataItemMutationVariables = Exact<{ }>; -export type UpdateOneFieldMetadataItemMutation = { __typename?: 'Mutation', updateOneField: { __typename?: 'Field', id: string, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, isCustom?: boolean | null, isActive?: boolean | null, isUnique?: boolean | null, isNullable?: boolean | null, createdAt: string, updatedAt: string, settings?: any | null, isLabelSyncedWithName?: boolean | null, object?: { __typename?: 'Object', id: string } | null } }; +export type UpdateOneFieldMetadataItemMutation = { __typename?: 'Mutation', updateOneField: { __typename?: 'Field', id: string, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, isCustom?: boolean | null, isActive?: boolean | null, isUnique?: boolean | null, isNullable?: boolean | null, createdAt: string, updatedAt: string, settings?: any | null, isLabelSyncedWithName?: boolean | null, applicationId?: string | null, object?: { __typename?: 'Object', id: string } | null } }; export type UpdateOneObjectMetadataItemMutationVariables = Exact<{ idToUpdate: Scalars['UUID']; @@ -5607,12 +5608,12 @@ export type DeleteOneFieldMetadataItemMutationVariables = Exact<{ }>; -export type DeleteOneFieldMetadataItemMutation = { __typename?: 'Mutation', deleteOneField: { __typename?: 'Field', id: string, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, isCustom?: boolean | null, isActive?: boolean | null, isUnique?: boolean | null, isNullable?: boolean | null, createdAt: string, updatedAt: string, settings?: any | null, object?: { __typename?: 'Object', id: string } | null } }; +export type DeleteOneFieldMetadataItemMutation = { __typename?: 'Mutation', deleteOneField: { __typename?: 'Field', id: string, type: FieldMetadataType, name: string, label: string, description?: string | null, icon?: string | null, isCustom?: boolean | null, isActive?: boolean | null, isUnique?: boolean | null, isNullable?: boolean | null, createdAt: string, updatedAt: string, settings?: any | null, applicationId?: string | null, object?: { __typename?: 'Object', id: string } | null } }; export type ObjectMetadataItemsQueryVariables = Exact<{ [key: string]: never; }>; -export type ObjectMetadataItemsQuery = { __typename?: 'Query', objects: { __typename?: 'ObjectConnection', edges: Array<{ __typename?: 'ObjectEdge', node: { __typename?: 'Object', id: 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 | null, 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, 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, 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 }> } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage?: boolean | null, hasPreviousPage?: boolean | null, startCursor?: any | null, endCursor?: any | null } } }; +export type ObjectMetadataItemsQuery = { __typename?: 'Query', objects: { __typename?: 'ObjectConnection', edges: Array<{ __typename?: 'ObjectEdge', node: { __typename?: 'Object', id: 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 | null, 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, 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, applicationId?: string | null, 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 }> } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage?: boolean | null, hasPreviousPage?: boolean | null, startCursor?: any | null, endCursor?: any | null } } }; export type SkipBookOnboardingStepMutationVariables = Exact<{ [key: string]: never; }>; @@ -6684,6 +6685,7 @@ export const ObjectMetadataFieldsFragmentDoc = gql` options settings isLabelSyncedWithName + applicationId relation { type sourceObjectMetadata { @@ -9856,6 +9858,7 @@ export const CreateOneFieldMetadataItemDocument = gql` defaultValue options isLabelSyncedWithName + applicationId object { id } @@ -9905,6 +9908,7 @@ export const UpdateOneFieldMetadataItemDocument = gql` updatedAt settings isLabelSyncedWithName + applicationId object { id } @@ -10049,6 +10053,7 @@ export const DeleteOneFieldMetadataItemDocument = gql` createdAt updatedAt settings + applicationId object { id } diff --git a/packages/twenty-front/src/generated/graphql.ts b/packages/twenty-front/src/generated/graphql.ts index e842270dd1..c2dcfa75b5 100644 --- a/packages/twenty-front/src/generated/graphql.ts +++ b/packages/twenty-front/src/generated/graphql.ts @@ -1313,6 +1313,7 @@ export enum FeatureFlagKey { export type Field = { __typename?: 'Field'; + applicationId?: Maybe; createdAt: Scalars['DateTime']; defaultValue?: Maybe; description?: Maybe; diff --git a/packages/twenty-front/src/modules/object-metadata/graphql/fragment.ts b/packages/twenty-front/src/modules/object-metadata/graphql/fragment.ts index 3d92f6d76c..de7547e96b 100644 --- a/packages/twenty-front/src/modules/object-metadata/graphql/fragment.ts +++ b/packages/twenty-front/src/modules/object-metadata/graphql/fragment.ts @@ -59,6 +59,7 @@ export const OBJECT_METADATA_FRAGMENT = gql` options settings isLabelSyncedWithName + applicationId relation { type sourceObjectMetadata { diff --git a/packages/twenty-front/src/modules/object-metadata/graphql/mutations.ts b/packages/twenty-front/src/modules/object-metadata/graphql/mutations.ts index 1dddfab5e6..180594d390 100644 --- a/packages/twenty-front/src/modules/object-metadata/graphql/mutations.ts +++ b/packages/twenty-front/src/modules/object-metadata/graphql/mutations.ts @@ -41,6 +41,7 @@ export const CREATE_ONE_FIELD_METADATA_ITEM = gql` defaultValue options isLabelSyncedWithName + applicationId object { id } @@ -68,6 +69,7 @@ export const UPDATE_ONE_FIELD_METADATA_ITEM = gql` updatedAt settings isLabelSyncedWithName + applicationId object { id } @@ -138,6 +140,7 @@ export const DELETE_ONE_FIELD_METADATA_ITEM = gql` createdAt updatedAt settings + applicationId object { id } diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/__mocks__/useFieldMetadataItem.ts b/packages/twenty-front/src/modules/object-metadata/hooks/__mocks__/useFieldMetadataItem.ts index dffde5a6b3..563829e196 100644 --- a/packages/twenty-front/src/modules/object-metadata/hooks/__mocks__/useFieldMetadataItem.ts +++ b/packages/twenty-front/src/modules/object-metadata/hooks/__mocks__/useFieldMetadataItem.ts @@ -22,6 +22,7 @@ export const queries = { createdAt updatedAt settings + applicationId object { id } @@ -47,6 +48,7 @@ export const queries = { updatedAt settings isLabelSyncedWithName + applicationId object { id } @@ -72,6 +74,7 @@ export const queries = { defaultValue options isLabelSyncedWithName + applicationId object { id } @@ -125,6 +128,7 @@ const defaultResponseData = { createdAt: '1977-09-28T13:56:55.157Z', updatedAt: '1996-10-10T08:27:57.117Z', settings: undefined, + applicationId: null, }; const fieldRelationResponseData = { diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useFieldMetadataItem.test.tsx b/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useFieldMetadataItem.test.tsx index eb98ee7643..6f4a8cd4b4 100644 --- a/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useFieldMetadataItem.test.tsx +++ b/packages/twenty-front/src/modules/object-metadata/hooks/__tests__/useFieldMetadataItem.test.tsx @@ -5,7 +5,6 @@ import { useFieldMetadataItem } from '@/object-metadata/hooks/useFieldMetadataIt import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { FieldMetadataType, RelationType } from '~/generated-metadata/graphql'; -import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper'; import { FIELD_METADATA_ID, FIELD_RELATION_METADATA_ID, @@ -14,14 +13,15 @@ import { responseData, variables, } from '@/object-metadata/hooks/__mocks__/useFieldMetadataItem'; +import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper'; -import { jestExpectSuccessfulMetadataRequestResult } from '@/object-metadata/hooks/__tests__/utils/jest-expect-metadata-request-status.util'; -import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser'; -import { mockedUserData } from '~/testing/mock-data/users'; import { query as findManyObjectMetadataItemsQuery, responseData as findManyObjectMetadataItemsResponseData, } from '@/object-metadata/hooks/__mocks__/useFindManyObjectMetadataItems'; +import { jestExpectSuccessfulMetadataRequestResult } from '@/object-metadata/hooks/__tests__/utils/jest-expect-metadata-request-status.util'; +import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser'; +import { mockedUserData } from '~/testing/mock-data/users'; jest.mock('@/object-metadata/hooks/useUpdateOneFieldMetadataItem', () => ({ useUpdateOneFieldMetadataItem: () => ({ diff --git a/packages/twenty-front/src/modules/object-record/read-only/utils/__tests__/isObjectMetadataSettingsReadOnly.test.ts b/packages/twenty-front/src/modules/object-record/read-only/utils/__tests__/isObjectMetadataSettingsReadOnly.test.ts deleted file mode 100644 index 9586d60a9b..0000000000 --- a/packages/twenty-front/src/modules/object-record/read-only/utils/__tests__/isObjectMetadataSettingsReadOnly.test.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { isObjectMetadataSettingsReadOnly } from '@/object-record/read-only/utils/isObjectMetadataSettingsReadOnly'; - -describe('isObjectMetadataSettingsReadOnly', () => { - it('should return false if object can be updated and is not UI read only and is not remote', () => { - const result = isObjectMetadataSettingsReadOnly({ - objectPermissions: { - canUpdateObjectRecords: true, - objectMetadataId: '123', - restrictedFields: {}, - }, - objectMetadataItem: { - isUIReadOnly: false, - isRemote: false, - }, - }); - - expect(result).toBe(false); - }); - - it('should return true if object is remote', () => { - const result = isObjectMetadataSettingsReadOnly({ - objectPermissions: { - canUpdateObjectRecords: true, - objectMetadataId: '123', - restrictedFields: {}, - }, - objectMetadataItem: { - isUIReadOnly: false, - isRemote: true, - }, - }); - - expect(result).toBe(true); - }); - - it('should return true if object is UI read only', () => { - const result = isObjectMetadataSettingsReadOnly({ - objectMetadataItem: { - isUIReadOnly: true, - isRemote: false, - }, - }); - - expect(result).toBe(true); - }); - - it('should return false for standard/third-party objects (they are editable via standardOverrides)', () => { - const result = isObjectMetadataSettingsReadOnly({ - objectPermissions: { - canUpdateObjectRecords: true, - objectMetadataId: '123', - restrictedFields: {}, - }, - objectMetadataItem: { - isUIReadOnly: false, - isRemote: false, - }, - }); - - expect(result).toBe(false); - }); -}); diff --git a/packages/twenty-front/src/modules/object-record/read-only/utils/isObjectMetadataSettingsReadOnly.ts b/packages/twenty-front/src/modules/object-record/read-only/utils/isObjectMetadataSettingsReadOnly.ts deleted file mode 100644 index 3700aedd7f..0000000000 --- a/packages/twenty-front/src/modules/object-record/read-only/utils/isObjectMetadataSettingsReadOnly.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -import { isObjectMetadataReadOnly } from '@/object-record/read-only/utils/isObjectMetadataReadOnly'; -import { type ObjectPermission } from '~/generated/graphql'; - -type IsObjectMetadataSettingsReadOnlyParams = { - objectPermissions?: ObjectPermission; - objectMetadataItem?: Pick; -}; - -// Returns true only for remote or UI read-only objects -// Standard and third-party app objects are editable (label/icon/description via standardOverrides) -export const isObjectMetadataSettingsReadOnly = ({ - objectPermissions, - objectMetadataItem, -}: IsObjectMetadataSettingsReadOnlyParams) => { - return isObjectMetadataReadOnly({ objectPermissions, objectMetadataItem }); -}; diff --git a/packages/twenty-front/src/modules/settings/components/SettingsItemTypeTag.tsx b/packages/twenty-front/src/modules/settings/components/SettingsItemTypeTag.tsx index 2ed9f6b4b9..586f9124f8 100644 --- a/packages/twenty-front/src/modules/settings/components/SettingsItemTypeTag.tsx +++ b/packages/twenty-front/src/modules/settings/components/SettingsItemTypeTag.tsx @@ -28,7 +28,7 @@ export const SettingsItemTypeTag = ({ const theme = useTheme(); const currentWorkspace = useRecoilValue(currentWorkspaceState); const itemTagInfo = getItemTagInfo({ - objectMetadataItem: { isCustom, isRemote, applicationId }, + item: { isCustom, isRemote, applicationId }, workspaceCustomApplicationId: currentWorkspace?.workspaceCustomApplication?.id, }); diff --git a/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx b/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx index 9a87ef2eee..16ce5d8c18 100644 --- a/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectFieldItemTableRow.tsx @@ -2,7 +2,7 @@ import { useDeleteOneFieldMetadataItem } from '@/object-metadata/hooks/useDelete import { useFieldMetadataItem } from '@/object-metadata/hooks/useFieldMetadataItem'; import { useGetRelationMetadata } from '@/object-metadata/hooks/useGetRelationMetadata'; import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField'; -import { isObjectMetadataSettingsReadOnly } from '@/object-record/read-only/utils/isObjectMetadataSettingsReadOnly'; +import { isObjectMetadataReadOnly } from '@/object-record/read-only/utils/isObjectMetadataReadOnly'; import { SettingsItemTypeTag } from '@/settings/components/SettingsItemTypeTag'; import { RELATION_TYPES } from '@/settings/data-model/constants/RelationTypes'; import { SettingsObjectFieldInactiveActionDropdown } from '@/settings/data-model/object-details/components/SettingsObjectFieldDisabledActionDropdown'; @@ -92,7 +92,7 @@ export const SettingsObjectFieldItemTableRow = ({ const { fieldMetadataItem, objectMetadataItem } = settingsObjectDetailTableItem; - const readonly = isObjectMetadataSettingsReadOnly({ + const readonly = isObjectMetadataReadOnly({ objectMetadataItem, }); @@ -204,9 +204,8 @@ export const SettingsObjectFieldItemTableRow = ({ diff --git a/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx b/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx index 4d24f027a3..90efd9d27e 100644 --- a/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsObjectRelationItemTableRow.tsx @@ -3,7 +3,7 @@ import { useFieldMetadataItem } from '@/object-metadata/hooks/useFieldMetadataIt import { useGetRelationMetadata } from '@/object-metadata/hooks/useGetRelationMetadata'; import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -import { isObjectMetadataSettingsReadOnly } from '@/object-record/read-only/utils/isObjectMetadataSettingsReadOnly'; +import { isObjectMetadataReadOnly } from '@/object-record/read-only/utils/isObjectMetadataReadOnly'; import { SettingsItemTypeTag } from '@/settings/components/SettingsItemTypeTag'; import { RELATION_TYPES } from '@/settings/data-model/constants/RelationTypes'; import { SettingsObjectFieldInactiveActionDropdown } from '@/settings/data-model/object-details/components/SettingsObjectFieldDisabledActionDropdown'; @@ -112,7 +112,7 @@ export const SettingsObjectRelationItemTableRow = ({ [fieldMetadataItem, getRelationMetadata], ) ?? {}; - const readonly = isObjectMetadataSettingsReadOnly({ + const readonly = isObjectMetadataReadOnly({ objectMetadataItem, }); diff --git a/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsUpdateDataModelObjectAboutForm.tsx b/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsUpdateDataModelObjectAboutForm.tsx index 1047b4dba1..485f8f4682 100644 --- a/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsUpdateDataModelObjectAboutForm.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/object-details/components/SettingsUpdateDataModelObjectAboutForm.tsx @@ -1,5 +1,6 @@ import { useUpdateOneObjectMetadataItem } from '@/object-metadata/hooks/useUpdateOneObjectMetadataItem'; import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { isObjectMetadataReadOnly } from '@/object-record/read-only/utils/isObjectMetadataReadOnly'; import { SettingsDataModelObjectAboutForm } from '@/settings/data-model/objects/forms/components/SettingsDataModelObjectAboutForm'; import { type SettingsDataModelObjectAboutFormValues, @@ -11,7 +12,6 @@ import { useSetRecoilState } from 'recoil'; import { SettingsPath } from 'twenty-shared/types'; import { useNavigateSettings } from '~/hooks/useNavigateSettings'; import { updatedObjectNamePluralState } from '~/pages/settings/data-model/states/updatedObjectNamePluralState'; -import { isObjectMetadataSettingsReadOnly } from '@/object-record/read-only/utils/isObjectMetadataSettingsReadOnly'; type SettingsUpdateDataModelObjectAboutFormProps = { objectMetadataItem: ObjectMetadataItem; @@ -20,7 +20,7 @@ type SettingsUpdateDataModelObjectAboutFormProps = { export const SettingsUpdateDataModelObjectAboutForm = ({ objectMetadataItem, }: SettingsUpdateDataModelObjectAboutFormProps) => { - const readonly = isObjectMetadataSettingsReadOnly({ + const readonly = isObjectMetadataReadOnly({ objectMetadataItem, }); const navigate = useNavigateSettings(); diff --git a/packages/twenty-front/src/modules/settings/data-model/object-details/components/tabs/ObjectFields.tsx b/packages/twenty-front/src/modules/settings/data-model/object-details/components/tabs/ObjectFields.tsx index 7e5e051c54..aec0ef2a0e 100644 --- a/packages/twenty-front/src/modules/settings/data-model/object-details/components/tabs/ObjectFields.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/object-details/components/tabs/ObjectFields.tsx @@ -1,5 +1,5 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -import { isObjectMetadataSettingsReadOnly } from '@/object-record/read-only/utils/isObjectMetadataSettingsReadOnly'; +import { isObjectMetadataReadOnly } from '@/object-record/read-only/utils/isObjectMetadataReadOnly'; import { SettingsObjectRelationsTable } from '@/settings/data-model/object-details/components/SettingsObjectRelationsTable'; import styled from '@emotion/styled'; import { useLingui } from '@lingui/react/macro'; @@ -22,11 +22,11 @@ type ObjectFieldsProps = { }; export const ObjectFields = ({ objectMetadataItem }: ObjectFieldsProps) => { - const readonly = isObjectMetadataSettingsReadOnly({ + const { t } = useLingui(); + const readonly = isObjectMetadataReadOnly({ objectMetadataItem, }); - const { t } = useLingui(); const objectLabelSingular = objectMetadataItem.labelSingular; const hasRelations = objectMetadataItem.fields.some( diff --git a/packages/twenty-front/src/modules/settings/data-model/object-details/components/tabs/ObjectSettings.tsx b/packages/twenty-front/src/modules/settings/data-model/object-details/components/tabs/ObjectSettings.tsx index 60adcc7538..6f1966fb3a 100644 --- a/packages/twenty-front/src/modules/settings/data-model/object-details/components/tabs/ObjectSettings.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/object-details/components/tabs/ObjectSettings.tsx @@ -2,7 +2,7 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataI import { useDeleteOneObjectMetadataItem } from '@/object-metadata/hooks/useDeleteOneObjectMetadataItem'; import { useUpdateOneObjectMetadataItem } from '@/object-metadata/hooks/useUpdateOneObjectMetadataItem'; -import { isObjectMetadataSettingsReadOnly } from '@/object-record/read-only/utils/isObjectMetadataSettingsReadOnly'; +import { isObjectMetadataReadOnly } from '@/object-record/read-only/utils/isObjectMetadataReadOnly'; import { SettingsUpdateDataModelObjectAboutForm } from '@/settings/data-model/object-details/components/SettingsUpdateDataModelObjectAboutForm'; import { SettingsDataModelObjectSettingsFormCard } from '@/settings/data-model/objects/forms/components/SettingsDataModelObjectSettingsFormCard'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; @@ -45,15 +45,14 @@ export const ObjectSettings = ({ setIsDeleting, }: ObjectSettingsProps) => { const { t } = useLingui(); - const readonly = isObjectMetadataSettingsReadOnly({ - objectMetadataItem, - }); const navigate = useNavigateSettings(); const { updateOneObjectMetadataItem } = useUpdateOneObjectMetadataItem(); const { deleteOneObjectMetadataItem } = useDeleteOneObjectMetadataItem(); const { enqueueSuccessSnackBar } = useSnackBar(); const { openModal, closeModal } = useModal(); + const isReadOnly = isObjectMetadataReadOnly({ objectMetadataItem }); + const handleDisable = async () => { const result = await updateOneObjectMetadataItem({ idToUpdate: objectMetadataItem.id, @@ -110,7 +109,7 @@ export const ObjectSettings = ({ /> - {!readonly && ( + {!isReadOnly && (
{ - const readonly = isObjectMetadataSettingsReadOnly({ + const readonly = isObjectMetadataReadOnly({ objectMetadataItem, }); const formConfig = useForm({ diff --git a/packages/twenty-front/src/modules/settings/data-model/utils/getItemTagInfo.ts b/packages/twenty-front/src/modules/settings/data-model/utils/getItemTagInfo.ts index a07208003c..93fac339f2 100644 --- a/packages/twenty-front/src/modules/settings/data-model/utils/getItemTagInfo.ts +++ b/packages/twenty-front/src/modules/settings/data-model/utils/getItemTagInfo.ts @@ -27,10 +27,10 @@ type ManagedItemTagInfo = { }; export const getItemTagInfo = ({ - objectMetadataItem: { isCustom, isRemote, applicationId }, + item: { isCustom, isRemote, applicationId }, workspaceCustomApplicationId, }: { - objectMetadataItem: { + item: { isCustom?: boolean; isRemote?: boolean; applicationId?: string | null; diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetailPage.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetailPage.tsx index 53e23f437d..d3d250fec5 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetailPage.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectDetailPage.tsx @@ -14,7 +14,7 @@ import styled from '@emotion/styled'; import { useRecoilState, useRecoilValue } from 'recoil'; import { AppPath, SettingsPath } from 'twenty-shared/types'; -import { isObjectMetadataSettingsReadOnly } from '@/object-record/read-only/utils/isObjectMetadataSettingsReadOnly'; +import { isObjectMetadataReadOnly } from '@/object-record/read-only/utils/isObjectMetadataReadOnly'; import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; import { useTheme } from '@emotion/react'; @@ -57,7 +57,7 @@ export const SettingsObjectDetailPage = () => { findObjectMetadataItemByNamePlural(objectNamePlural) ?? findObjectMetadataItemByNamePlural(updatedObjectNamePlural); - const readonly = isObjectMetadataSettingsReadOnly({ + const readonly = isObjectMetadataReadOnly({ objectMetadataItem, }); diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldEdit.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldEdit.tsx index bc795c557a..9b6f921c66 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldEdit.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectFieldEdit.tsx @@ -12,7 +12,7 @@ import { useUpdateOneFieldMetadataItem } from '@/object-metadata/hooks/useUpdate import { CoreObjectNamePlural } from '@/object-metadata/types/CoreObjectNamePlural'; import { formatFieldMetadataItemInput } from '@/object-metadata/utils/formatFieldMetadataItemInput'; import { isLabelIdentifierField } from '@/object-metadata/utils/isLabelIdentifierField'; -import { isObjectMetadataSettingsReadOnly } from '@/object-record/read-only/utils/isObjectMetadataSettingsReadOnly'; +import { isObjectMetadataReadOnly } from '@/object-record/read-only/utils/isObjectMetadataReadOnly'; import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons'; import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; import { FIELD_NAME_MAXIMUM_LENGTH } from '@/settings/data-model/constants/FieldNameMaximumLength'; @@ -83,7 +83,7 @@ export const SettingsObjectFieldEdit = () => { const objectMetadataItem = findObjectMetadataItemByNamePlural(objectNamePlural); - const readonly = isObjectMetadataSettingsReadOnly({ + const readonly = isObjectMetadataReadOnly({ objectMetadataItem, }); diff --git a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectTable.tsx b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectTable.tsx index 3a842afeb9..d18324504c 100644 --- a/packages/twenty-front/src/pages/settings/data-model/SettingsObjectTable.tsx +++ b/packages/twenty-front/src/pages/settings/data-model/SettingsObjectTable.tsx @@ -91,7 +91,7 @@ export const SettingsObjectTable = ({ objectMetadataItem, labelPlural: objectMetadataItem.labelPlural, objectTypeLabel: getItemTagInfo({ - objectMetadataItem, + item: objectMetadataItem, workspaceCustomApplicationId: currentWorkspace?.workspaceCustomApplication?.id, }).labelText, diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/dtos/create-field.input.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/dtos/create-field.input.ts index 21c2698a32..72fb803530 100644 --- a/packages/twenty-server/src/engine/metadata-modules/field-metadata/dtos/create-field.input.ts +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/dtos/create-field.input.ts @@ -11,7 +11,13 @@ import { FieldMetadataDTO } from 'src/engine/metadata-modules/field-metadata/dto @InputType() export class CreateFieldInput extends OmitType( FieldMetadataDTO, - ['id', 'createdAt', 'updatedAt', 'standardOverrides'] as const, + [ + 'id', + 'createdAt', + 'updatedAt', + 'standardOverrides', + 'applicationId', + ] as const, InputType, ) { @IsUUID() diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/dtos/field-metadata.dto.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/dtos/field-metadata.dto.ts index 97e5e66105..7c7abf5670 100644 --- a/packages/twenty-server/src/engine/metadata-modules/field-metadata/dtos/field-metadata.dto.ts +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/dtos/field-metadata.dto.ts @@ -160,4 +160,7 @@ export class FieldMetadataDTO { @IsDateString() @Field() updatedAt: Date; + + @Field(() => UUIDScalarType, { nullable: true }) + applicationId?: string; } diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/dtos/update-field.input.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/dtos/update-field.input.ts index 43679b99c6..f309b08bdd 100644 --- a/packages/twenty-server/src/engine/metadata-modules/field-metadata/dtos/update-field.input.ts +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/dtos/update-field.input.ts @@ -29,6 +29,7 @@ export class UpdateFieldInput extends OmitType( 'updatedAt', 'isCustom', 'standardOverrides', + 'applicationId', ] as const, ) { @HideField() diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/from-field-metadata-entity-to-field-metadata-dto.util.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/from-field-metadata-entity-to-field-metadata-dto.util.ts deleted file mode 100644 index d41f35e76f..0000000000 --- a/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/from-field-metadata-entity-to-field-metadata-dto.util.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { type FieldMetadataDTO } from 'src/engine/metadata-modules/field-metadata/dtos/field-metadata.dto'; -import { type FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; - -export const fromFieldMetadataEntityToFieldMetadataDto = ( - fieldMetadataEntity: FieldMetadataEntity, -): FieldMetadataDTO => { - const { - createdAt, - updatedAt, - description, - icon, - standardOverrides, - isNullable, - isUnique, - settings, - ...rest - } = fieldMetadataEntity; - - return { - ...rest, - createdAt: new Date(createdAt), - updatedAt: new Date(updatedAt), - description: description ?? undefined, - icon: icon ?? undefined, - standardOverrides: standardOverrides ?? undefined, - isNullable: isNullable ?? false, - isUnique: isUnique ?? false, - settings: settings ?? undefined, - }; -}; diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/from-flat-field-metadata-to-field-metadata-dto.util.ts b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/from-flat-field-metadata-to-field-metadata-dto.util.ts index 849ac77425..dcc6b80c2c 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/from-flat-field-metadata-to-field-metadata-dto.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/from-flat-field-metadata-to-field-metadata-dto.util.ts @@ -26,6 +26,7 @@ export const fromFlatFieldMetadataToFieldMetadataDto = ( isSystem, isUIReadOnly, options, + applicationId, } = flatFieldMetadata; return { @@ -50,5 +51,6 @@ export const fromFlatFieldMetadataToFieldMetadataDto = ( isNullable: isNullable ?? false, isUnique: isUnique ?? false, settings: settings ?? undefined, + applicationId: applicationId ?? undefined, }; };