diff --git a/packages/twenty-server/src/database/commands/compute-twenty-standard-workspace-migration.command.ts b/packages/twenty-server/src/database/commands/compute-twenty-standard-workspace-migration.command.ts new file mode 100644 index 00000000000..93defc7bcfc --- /dev/null +++ b/packages/twenty-server/src/database/commands/compute-twenty-standard-workspace-migration.command.ts @@ -0,0 +1,79 @@ +import { Logger } from '@nestjs/common'; + +import { writeFileSync } from 'fs'; + +import { Command, CommandRunner } from 'nest-commander'; +import { WorkspaceMigrationV2ExceptionCode } from 'twenty-shared/metadata'; + +import { createEmptyFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/constant/create-empty-flat-entity-maps.constant'; +import { computeTwentyStandardApplicationAllFlatEntityMaps } from 'src/engine/workspace-manager/twenty-standard-application/utils/twenty-standard-application-all-flat-entity-maps.constant'; +import { WorkspaceMigrationBuildOrchestratorService } from 'src/engine/workspace-manager/workspace-migration-v2/services/workspace-migration-build-orchestrator.service'; +import { WorkspaceMigrationV2Exception } from 'src/engine/workspace-manager/workspace-migration.exception'; + +@Command({ + name: 'workspace:compute-twenty-standard-migration', + description: 'Compute Twenty standard workspace migration.', +}) +export class ComputeTwentyStandardWorkspaceMigrationCommand extends CommandRunner { + private readonly logger = new Logger( + ComputeTwentyStandardWorkspaceMigrationCommand.name, + ); + + constructor( + private readonly workspaceMigrationBuildOrchestratorService: WorkspaceMigrationBuildOrchestratorService, + ) { + super(); + } + + async run(): Promise { + this.logger.log('Starting compute Twenty standard workspace migration...'); + + // TODO: Implement migration logic here + const workspaceId = '20202020-ef6f-4118-953c-2b027324b54a'; + const twentyStandardAllFlatEntityMaps = + computeTwentyStandardApplicationAllFlatEntityMaps({ + createdAt: new Date(), + workspaceId, + }); + + writeFileSync( + `${Date.now()}-all-flat-entity-maps.json`, + JSON.stringify(twentyStandardAllFlatEntityMaps, null, 2), + ); + + const validateAndBuildResult = + await this.workspaceMigrationBuildOrchestratorService + .buildWorkspaceMigration({ + buildOptions: { + isSystemBuild: true, + }, + fromToAllFlatEntityMaps: { + flatObjectMetadataMaps: { + from: createEmptyFlatEntityMaps(), + to: twentyStandardAllFlatEntityMaps.flatObjectMetadataMaps, + }, + flatFieldMetadataMaps: { + from: createEmptyFlatEntityMaps(), + to: twentyStandardAllFlatEntityMaps.flatFieldMetadataMaps, + }, + }, + workspaceId, + }) + .catch((error) => { + this.logger.error(error); + throw new WorkspaceMigrationV2Exception( + WorkspaceMigrationV2ExceptionCode.BUILDER_INTERNAL_SERVER_ERROR, + error.message, + ); + }); + + writeFileSync( + `${Date.now()}validate-and-build-result.json`, + JSON.stringify(validateAndBuildResult, null, 2), + ); + + this.logger.log( + 'Compute Twenty standard workspace migration completed successfully.', + ); + } +} diff --git a/packages/twenty-server/src/database/commands/database-command.module.ts b/packages/twenty-server/src/database/commands/database-command.module.ts index 2b59ea5e21f..16f0cbfd493 100644 --- a/packages/twenty-server/src/database/commands/database-command.module.ts +++ b/packages/twenty-server/src/database/commands/database-command.module.ts @@ -1,6 +1,7 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; +import { ComputeTwentyStandardWorkspaceMigrationCommand } from 'src/database/commands/compute-twenty-standard-workspace-migration.command'; import { CronRegisterAllCommand } from 'src/database/commands/cron-register-all.command'; import { DataSeedWorkspaceCommand } from 'src/database/commands/data-seed-dev-workspace.command'; import { ConfirmationQuestion } from 'src/database/commands/questions/confirmation.question'; @@ -22,6 +23,7 @@ import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/ import { DevSeederModule } from 'src/engine/workspace-manager/dev-seeder/dev-seeder.module'; import { WorkspaceCleanerModule } from 'src/engine/workspace-manager/workspace-cleaner/workspace-cleaner.module'; import { WorkspaceManagerModule } from 'src/engine/workspace-manager/workspace-manager.module'; +import { WorkspaceMigrationV2Module } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-v2.module'; import { CalendarEventImportManagerModule } from 'src/modules/calendar/calendar-event-import-manager/calendar-event-import-manager.module'; import { MessagingImportManagerModule } from 'src/modules/messaging/message-import-manager/messaging-import-manager.module'; import { WorkflowRunQueueModule } from 'src/modules/workflow/workflow-runner/workflow-run-queue/workflow-run-queue.module'; @@ -51,10 +53,12 @@ import { AutomatedTriggerModule } from 'src/modules/workflow/workflow-trigger/au CronTriggerModule, DatabaseEventTriggerModule, WorkspaceCleanerModule, + WorkspaceMigrationV2Module, TrashCleanupModule, PublicDomainModule, ], providers: [ + ComputeTwentyStandardWorkspaceMigrationCommand, DataSeedWorkspaceCommand, ConfirmationQuestion, CronRegisterAllCommand, diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-11/1-11-create-twenty-standard-application.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-11/1-11-create-twenty-standard-application.command.ts index 78f4312f0ce..2c464eb6131 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-11/1-11-create-twenty-standard-application.command.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/1-11/1-11-create-twenty-standard-application.command.ts @@ -7,10 +7,10 @@ import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/ import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity'; import { ApplicationService } from 'src/engine/core-modules/application/application.service'; -import { TWENTY_STANDARD_APPLICATION } from 'src/engine/core-modules/application/constants/twenty-standard-applications'; import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; +import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications'; @Command({ name: 'upgrade:1-11:create-twenty-standard-application', diff --git a/packages/twenty-server/src/engine/core-modules/application/application.service.ts b/packages/twenty-server/src/engine/core-modules/application/application.service.ts index 619aac3032c..dabd0524a2d 100644 --- a/packages/twenty-server/src/engine/core-modules/application/application.service.ts +++ b/packages/twenty-server/src/engine/core-modules/application/application.service.ts @@ -10,10 +10,10 @@ import { ApplicationException, ApplicationExceptionCode, } from 'src/engine/core-modules/application/application.exception'; -import { TWENTY_STANDARD_APPLICATION } from 'src/engine/core-modules/application/constants/twenty-standard-applications'; import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; import { ALL_FLAT_ENTITY_MAPS_PROPERTIES } from 'src/engine/metadata-modules/flat-entity/constant/all-flat-entity-maps-properties.constant'; import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; +import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications'; @Injectable() export class ApplicationService { diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/run-flat-field-metadata-validators.util.ts b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/run-flat-field-metadata-validators.util.ts deleted file mode 100644 index 7887b347125..00000000000 --- a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/run-flat-field-metadata-validators.util.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { t } from '@lingui/core/macro'; - -import { FieldMetadataExceptionCode } from 'src/engine/metadata-modules/field-metadata/field-metadata.exception'; -import { type FlatFieldMetadataValidationError } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-validation-error.type'; -import { type FlatMetadataValidator } from 'src/engine/metadata-modules/types/flat-metadata-validator.type'; - -export const runFlatFieldMetadataValidators = ({ - elementToValidate, - validators, -}: { - elementToValidate: T; - validators: FlatMetadataValidator[]; -}): FlatFieldMetadataValidationError[] => { - return validators.flatMap(({ validator, message }) => { - const isInvalid = validator(elementToValidate); - - if (isInvalid) { - return { - code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, - message: t(message), - value: elementToValidate, - }; - } - - return []; - }); -}; diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-enum-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-enum-flat-field-metadata.util.ts index d96826fbcaa..e0782da2cbc 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-enum-flat-field-metadata.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-enum-flat-field-metadata.util.ts @@ -4,8 +4,8 @@ import { QUOTED_STRING_REGEX } from 'twenty-shared/constants'; import { FieldMetadataType, type EnumFieldMetadataType, - type NonNullableRequired, type FieldMetadataOptions, + type NonNullableRequired, } from 'twenty-shared/types'; import { assertUnreachable, isDefined } from 'twenty-shared/utils'; import { z } from 'zod'; @@ -18,128 +18,159 @@ import { FieldMetadataExceptionCode } from 'src/engine/metadata-modules/field-me import { type FlatFieldMetadataTypeValidationArgs } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-type-validator.type'; import { type FlatFieldMetadataValidationError } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-validation-error.type'; import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; -import { runFlatFieldMetadataValidators } from 'src/engine/metadata-modules/flat-field-metadata/utils/run-flat-field-metadata-validators.util'; -import { type FlatMetadataValidator } from 'src/engine/metadata-modules/types/flat-metadata-validator.type'; -import { - beneathDatabaseIdentifierMinimumLength, - exceedsDatabaseIdentifierMaximumLength, -} from 'src/engine/metadata-modules/utils/validate-database-identifier-length.utils'; +import { IDENTIFIER_MAX_CHAR_LENGTH } from 'src/engine/metadata-modules/utils/constants/identifier-max-char-length.constants'; +import { IDENTIFIER_MIN_CHAR_LENGTH } from 'src/engine/metadata-modules/utils/constants/identifier-min-char-length.constants'; import { isSnakeCaseString } from 'src/utils/is-snake-case-string'; const validateMetadataOptionId = (sanitizedId?: string) => { - const validators: FlatMetadataValidator[] = [ - { - validator: (id) => !isDefined(id), - message: msg`Option id is required`, - }, - { - validator: (id) => !z.string().uuid().safeParse(id).success, - message: msg`Option id is invalid`, - }, - ]; + const errors: FlatFieldMetadataValidationError[] = []; - return runFlatFieldMetadataValidators({ - elementToValidate: sanitizedId, - validators, - }); + if (!isDefined(sanitizedId)) { + errors.push({ + code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + message: t`Option id is required`, + userFriendlyMessage: msg`Option id is required`, + }); + } + + if (!z.string().uuid().safeParse(sanitizedId).success) { + errors.push({ + code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + message: t`Option id is invalid`, + userFriendlyMessage: msg`Option id is invalid`, + value: sanitizedId, + }); + } + + return errors; }; const validateMetadataOptionLabel = ( sanitizedLabel: string, ): FlatFieldMetadataValidationError[] => { + const errors: FlatFieldMetadataValidationError[] = []; + if (!isDefined(sanitizedLabel)) { - return [ - { - code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, - message: t`Option label is required`, - userFriendlyMessage: msg`Option label is required`, - }, - ]; + errors.push({ + code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + message: t`Option label is required`, + userFriendlyMessage: msg`Option label is required`, + }); + + return errors; } if (!isNonEmptyString(sanitizedLabel)) { - return [ - { - code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, - message: t`Option label must be a string of at least one character`, - userFriendlyMessage: msg`Option label format not supported`, - value: sanitizedLabel, - }, - ]; + errors.push({ + code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + message: t`Option label must be a string of at least one character`, + userFriendlyMessage: msg`Option label format not supported`, + value: sanitizedLabel, + }); + + return errors; } - const validators: FlatMetadataValidator[] = [ - { - validator: exceedsDatabaseIdentifierMaximumLength, - message: msg`Option label exceeds 63 characters`, - }, - { - validator: beneathDatabaseIdentifierMinimumLength, - message: msg`Option label "${sanitizedLabel}" is beneath 1 character`, - }, - { - validator: (label) => label.includes(','), - message: msg`Label must not contain a comma`, - }, - { - validator: (label) => !isNonEmptyString(label) || label === ' ', - message: msg`Label must not be empty`, - }, - ]; + if (sanitizedLabel.length > IDENTIFIER_MAX_CHAR_LENGTH) { + errors.push({ + code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + message: t`Option label exceeds 63 characters`, + userFriendlyMessage: msg`Option label exceeds 63 characters`, + value: sanitizedLabel, + }); + } - return runFlatFieldMetadataValidators({ - elementToValidate: sanitizedLabel, - validators, - }); + if (sanitizedLabel.length < IDENTIFIER_MIN_CHAR_LENGTH) { + errors.push({ + code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + message: t`Option label "${sanitizedLabel}" is beneath 1 character`, + userFriendlyMessage: msg`Option label "${sanitizedLabel}" is beneath 1 character`, + value: sanitizedLabel, + }); + } + + if (sanitizedLabel.includes(',')) { + errors.push({ + code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + message: t`Label must not contain a comma`, + userFriendlyMessage: msg`Label must not contain a comma`, + value: sanitizedLabel, + }); + } + + if (!isNonEmptyString(sanitizedLabel) || sanitizedLabel === ' ') { + errors.push({ + code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + message: t`Label must not be empty`, + userFriendlyMessage: msg`Label must not be empty`, + value: sanitizedLabel, + }); + } + + return errors; }; const validateMetadataOptionValue = ( sanitizedValue: string, ): FlatFieldMetadataValidationError[] => { + const errors: FlatFieldMetadataValidationError[] = []; + if (!isDefined(sanitizedValue)) { - return [ - { - code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, - message: t`Option value is required`, - userFriendlyMessage: msg`Option value is required`, - }, - ]; + errors.push({ + code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + message: t`Option value is required`, + userFriendlyMessage: msg`Option value is required`, + }); + + return errors; } if (!isNonEmptyString(sanitizedValue)) { - return [ - { - code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, - message: t`Option value must be a string of at least one character`, - userFriendlyMessage: msg`Option value format not supported`, - }, - ]; + errors.push({ + code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + message: t`Option value must be a string of at least one character`, + userFriendlyMessage: msg`Option value format not supported`, + value: sanitizedValue, + }); + + return errors; } - const validators: FlatMetadataValidator[] = [ - { - validator: exceedsDatabaseIdentifierMaximumLength, - message: msg`Option value exceeds 63 characters`, - }, - { - validator: beneathDatabaseIdentifierMinimumLength, - message: msg`Option value "${sanitizedValue}" is beneath 1 character`, - }, - { - validator: (value) => !isSnakeCaseString(value), - message: msg`Value must be in UPPER_CASE and follow snake_case "${sanitizedValue}"`, - }, - ]; + if (sanitizedValue.length > IDENTIFIER_MAX_CHAR_LENGTH) { + errors.push({ + code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + message: t`Option value exceeds 63 characters`, + userFriendlyMessage: msg`Option value exceeds 63 characters`, + value: sanitizedValue, + }); + } - return runFlatFieldMetadataValidators({ - elementToValidate: sanitizedValue, - validators, - }); + if (sanitizedValue.length < IDENTIFIER_MIN_CHAR_LENGTH) { + errors.push({ + code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + message: t`Option value "${sanitizedValue}" is beneath 1 character`, + userFriendlyMessage: msg`Option value "${sanitizedValue}" is beneath 1 character`, + value: sanitizedValue, + }); + } + + if (!isSnakeCaseString(sanitizedValue)) { + errors.push({ + code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + message: t`Value must be in UPPER_CASE and follow snake_case "${sanitizedValue}"`, + userFriendlyMessage: msg`Value must be in UPPER_CASE and follow snake_case "${sanitizedValue}"`, + value: sanitizedValue, + }); + } + + return errors; }; const validateDuplicates = ( options: FieldMetadataOptions, ) => { + const errors: FlatFieldMetadataValidationError[] = []; + const fieldsToCheckForDuplicates = [ 'position', 'id', @@ -148,20 +179,22 @@ const validateDuplicates = ( | FieldMetadataDefaultOption[] | FieldMetadataComplexOption[] )[number])[]; - const duplicatedValidators = fieldsToCheckForDuplicates.map< - FlatMetadataValidator< - FieldMetadataDefaultOption[] | FieldMetadataComplexOption[] - > - >((field) => ({ - message: msg`Duplicated option ${field}`, - validator: () => - new Set(options.map((option) => option[field])).size !== options.length, - })); - return runFlatFieldMetadataValidators({ - elementToValidate: options, - validators: duplicatedValidators, - }); + for (const field of fieldsToCheckForDuplicates) { + const hasDuplicates = + new Set(options.map((option) => option[field])).size !== options.length; + + if (hasDuplicates) { + errors.push({ + code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + message: t`Duplicated option ${field}`, + userFriendlyMessage: msg`Duplicated option ${field}`, + value: options, + }); + } + } + + return errors; }; const validateFieldMetadataInputOptions = ( @@ -200,35 +233,43 @@ const validateSelectDefaultValue = ({ options: FieldMetadataOptions; defaultValue: string | string[]; }): FlatFieldMetadataValidationError[] => { + const errors: FlatFieldMetadataValidationError[] = []; + if (typeof defaultValue !== 'string') { - return [ - { - code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, - message: `Default value for select must be a string got ${defaultValue}`, - userFriendlyMessage: msg`Default value must be a string`, - value: defaultValue, - }, - ]; + errors.push({ + code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + message: `Default value for select must be a string got ${defaultValue}`, + userFriendlyMessage: msg`Default value must be a string`, + value: defaultValue, + }); + + return errors; } - const validators: FlatMetadataValidator[] = [ - { - validator: (value: string) => !QUOTED_STRING_REGEX.test(value), - message: msg`Default value should be as quoted string`, - }, - { - validator: (value: string) => - !options.some( - (option) => option.value === value.replace(QUOTED_STRING_REGEX, '$1'), - ), - message: msg`Default value "${defaultValue}" must be one of the option values`, - }, - ]; + if (!QUOTED_STRING_REGEX.test(defaultValue)) { + errors.push({ + code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + message: t`Default value should be as quoted string`, + userFriendlyMessage: msg`Default value should be as quoted string`, + value: defaultValue, + }); + } - return runFlatFieldMetadataValidators({ - elementToValidate: defaultValue, - validators, - }); + const matchesOptionValue = options.some( + (option) => + option.value === defaultValue.replace(QUOTED_STRING_REGEX, '$1'), + ); + + if (!matchesOptionValue) { + errors.push({ + code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + message: t`Default value "${defaultValue}" must be one of the option values`, + userFriendlyMessage: msg`Default value "${defaultValue}" must be one of the option values`, + value: defaultValue, + }); + } + + return errors; }; const validateMultiSelectDefaultValue = ({ @@ -238,40 +279,49 @@ const validateMultiSelectDefaultValue = ({ options: FieldMetadataOptions; multiSelectDefaultValue: unknown; }): FlatFieldMetadataValidationError[] => { + const errors: FlatFieldMetadataValidationError[] = []; + if (!Array.isArray(multiSelectDefaultValue)) { - return [ - { - code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, - userFriendlyMessage: msg`Multi-select field default value must be an array`, - message: `Default value for multi-select must be an array got ${multiSelectDefaultValue}`, - value: multiSelectDefaultValue, - }, - ]; + errors.push({ + code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + userFriendlyMessage: msg`Multi-select field default value must be an array`, + message: `Default value for multi-select must be an array got ${multiSelectDefaultValue}`, + value: multiSelectDefaultValue, + }); + + return errors; } - const validators: FlatMetadataValidator[] = [ - { - validator: (values) => values.length === 0, - message: msg`If defined default value must contain at least one value`, - }, - { - validator: (values) => new Set(values).size !== values.length, - message: msg`Default values must be unique`, - }, - ]; + if (multiSelectDefaultValue.length === 0) { + errors.push({ + code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + message: t`If defined default value must contain at least one value`, + userFriendlyMessage: msg`If defined default value must contain at least one value`, + value: multiSelectDefaultValue, + }); + } - return [ - runFlatFieldMetadataValidators({ - elementToValidate: multiSelectDefaultValue, - validators, - }), - multiSelectDefaultValue.flatMap((defaultValue) => - validateSelectDefaultValue({ + if ( + new Set(multiSelectDefaultValue).size !== multiSelectDefaultValue.length + ) { + errors.push({ + code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + message: t`Default values must be unique`, + userFriendlyMessage: msg`Default values must be unique`, + value: multiSelectDefaultValue, + }); + } + + for (const defaultValue of multiSelectDefaultValue) { + errors.push( + ...validateSelectDefaultValue({ defaultValue, options, }), - ), - ].flat(); + ); + } + + return errors; }; const validateFieldMetadataDefaultValue = ({ diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-flat-field-metadata-name-availability.util.ts b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-flat-field-metadata-name-availability.util.ts index af9b4bc430f..7458455059a 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-flat-field-metadata-name-availability.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-flat-field-metadata-name-availability.util.ts @@ -11,6 +11,7 @@ import { type FlatFieldMetadataValidationError } from 'src/engine/metadata-modul import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; import { getObjectFieldNamesAndJoinColumnNames } from 'src/engine/metadata-modules/flat-field-metadata/utils/get-object-field-names-and-join-column-names.util'; import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; +import { type WorkspaceMigrationBuilderOptions } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-builder-options.type'; const getReservedCompositeFieldNames = ( objectFlatFieldMetadatas: FlatFieldMetadata[], @@ -39,7 +40,9 @@ export const validateFlatFieldMetadataNameAvailability = ({ name, flatFieldMetadataMaps, flatObjectMetadata, + buildOptions, }: { + buildOptions: WorkspaceMigrationBuilderOptions; name: string; flatObjectMetadata: FlatObjectMetadata; flatFieldMetadataMaps: FlatEntityMaps; @@ -54,7 +57,10 @@ export const validateFlatFieldMetadataNameAvailability = ({ objectFlatFieldMetadatas, ); - if (reservedCompositeFieldsNames.includes(name)) { + if ( + !buildOptions.isSystemBuild && + reservedCompositeFieldsNames.includes(name) + ) { errors.push({ code: FieldMetadataExceptionCode.RESERVED_KEYWORD, message: `Name "${name}" is reserved composite field name`, diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-flat-field-metadata-name.util.ts b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-flat-field-metadata-name.util.ts index 8a169397e1c..d6618275ac9 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-flat-field-metadata-name.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-flat-field-metadata-name.util.ts @@ -1,21 +1,76 @@ +import { msg, t } from '@lingui/core/macro'; +import camelCase from 'lodash.camelcase'; +import { RESERVED_METADATA_NAME_KEYWORDS } from 'twenty-shared/metadata'; + import { FieldMetadataExceptionCode } from 'src/engine/metadata-modules/field-metadata/field-metadata.exception'; import { type FlatFieldMetadataValidationError } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-validation-error.type'; -import { METADATA_NAME_VALIDATORS } from 'src/engine/metadata-modules/utils/constants/metadata-name-flat-metadata-validators.constants'; +import { IDENTIFIER_MAX_CHAR_LENGTH } from 'src/engine/metadata-modules/utils/constants/identifier-max-char-length.constants'; +import { IDENTIFIER_MIN_CHAR_LENGTH } from 'src/engine/metadata-modules/utils/constants/identifier-min-char-length.constants'; +import { type WorkspaceMigrationBuilderOptions } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-builder-options.type'; -export const validateFlatFieldMetadataName = ( - name: string, -): FlatFieldMetadataValidationError[] => - METADATA_NAME_VALIDATORS.flatMap(({ validator, message }) => { - const isInvalid = validator(name); +const STARTS_WITH_LOWER_CASE_AND_CONTAINS_ONLY_CAPS_AND_LOWER_LETTERS_AND_NUMBER_STRING_REGEX = + /^[a-z][a-zA-Z0-9]*$/; - if (isInvalid) { - return { - code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, - message: message.message ?? '', - userFriendlyMessage: message, - value: name, - }; - } +export const validateFlatFieldMetadataName = ({ + buildOptions, + name, +}: { + name: string; + buildOptions: WorkspaceMigrationBuilderOptions; +}): FlatFieldMetadataValidationError[] => { + const errors: FlatFieldMetadataValidationError[] = []; - return []; - }); + if (name.length > IDENTIFIER_MAX_CHAR_LENGTH) { + errors.push({ + code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + message: t`Name is too long`, + userFriendlyMessage: msg`Name is too long`, + value: name, + }); + } + + if (name.length < IDENTIFIER_MIN_CHAR_LENGTH) { + errors.push({ + code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + message: t`Name is too short`, + userFriendlyMessage: msg`Name is too short`, + value: name, + }); + } + + if (name !== camelCase(name)) { + errors.push({ + code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + message: t`Name should be in camelCase`, + userFriendlyMessage: msg`Name should be in camelCase`, + value: name, + }); + } + + if ( + !name.match( + STARTS_WITH_LOWER_CASE_AND_CONTAINS_ONLY_CAPS_AND_LOWER_LETTERS_AND_NUMBER_STRING_REGEX, + ) + ) { + errors.push({ + code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + message: t`Name is not valid: it must start with lowercase letter and contain only alphanumeric letters`, + userFriendlyMessage: msg`Name is not valid: it must start with lowercase letter and contain only alphanumeric letters`, + value: name, + }); + } + + if ( + !buildOptions.isSystemBuild && + RESERVED_METADATA_NAME_KEYWORDS.includes(name) + ) { + errors.push({ + code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT, + message: t`This name is reserved. Use a different name or the system will add "Custom" suffix.`, + userFriendlyMessage: msg`This name is reserved. Use a different name or the system will add "Custom" suffix.`, + value: name, + }); + } + + return errors; +}; diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-morph-or-relation-flat-field-join-column-name.util.ts b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-morph-or-relation-flat-field-join-column-name.util.ts index 8eb68de1618..59a9ce69690 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-morph-or-relation-flat-field-join-column-name.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-morph-or-relation-flat-field-join-column-name.util.ts @@ -9,6 +9,7 @@ import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/ import { type FlatFieldMetadataValidationError } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-validation-error.type'; import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; import { validateFlatFieldMetadataNameAvailability } from 'src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-flat-field-metadata-name-availability.util'; +import { type WorkspaceMigrationBuilderOptions } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-builder-options.type'; export const validateMorphOrRelationFlatFieldJoinColumName = ({ flatFieldMetadata, @@ -16,7 +17,9 @@ export const validateMorphOrRelationFlatFieldJoinColumName = ({ flatFieldMetadataMaps, flatObjectMetadataMaps, }, + buildOptions, }: { + buildOptions: WorkspaceMigrationBuilderOptions; flatFieldMetadata: FlatFieldMetadata; optimisticFlatEntityMapsAndRelatedFlatEntityMaps: MetadataFlatEntityAndRelatedFlatEntityMapsForValidation<'fieldMetadata'>; }): FlatFieldMetadataValidationError[] => { @@ -55,6 +58,7 @@ export const validateMorphOrRelationFlatFieldJoinColumName = ({ name: flatFieldMetadata.settings.joinColumnName, flatFieldMetadataMaps, flatObjectMetadata, + buildOptions, }), ); break; diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-morph-or-relation-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-morph-or-relation-flat-field-metadata.util.ts index 8e38ca121d3..391bcb5d3f2 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-morph-or-relation-flat-field-metadata.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-morph-or-relation-flat-field-metadata.util.ts @@ -18,6 +18,7 @@ export const validateMorphOrRelationFlatFieldMetadata = ({ }, updates, remainingFlatEntityMapsToValidate, + buildOptions, }: FlatFieldMetadataTypeValidationArgs): FlatFieldMetadataValidationError[] => { const { relationTargetFieldMetadataId, relationTargetObjectMetadataId } = flatFieldMetadataToValidate; @@ -92,6 +93,7 @@ export const validateMorphOrRelationFlatFieldMetadata = ({ ) errors.push( ...validateMorphOrRelationFlatFieldJoinColumName({ + buildOptions, flatFieldMetadata: flatFieldMetadataToValidate, optimisticFlatEntityMapsAndRelatedFlatEntityMaps: { flatFieldMetadataMaps, diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/utils/run-flat-object-metadata-validators.util.ts b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/utils/run-flat-object-metadata-validators.util.ts deleted file mode 100644 index c3fc5fa9ede..00000000000 --- a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/utils/run-flat-object-metadata-validators.util.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { t } from '@lingui/core/macro'; - -import { type FlatObjectMetadataValidationError } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata-validation-error.type'; -import { ObjectMetadataExceptionCode } from 'src/engine/metadata-modules/object-metadata/object-metadata.exception'; -import { type FlatMetadataValidator } from 'src/engine/metadata-modules/types/flat-metadata-validator.type'; - -export const runFlatObjectMetadataValidators = ({ - elementToValidate, - validators, -}: { - elementToValidate: T; - validators: FlatMetadataValidator[]; -}): FlatObjectMetadataValidationError[] => { - return validators.flatMap(({ validator, message }) => { - const isInvalid = validator(elementToValidate); - - if (isInvalid) { - return { - code: ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT, - message: t(message), - value: elementToValidate, - }; - } - - return []; - }); -}; diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/validators/utils/validate-flat-object-metadata-identifiers.util.ts b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/validators/utils/validate-flat-object-metadata-identifiers.util.ts index ab0e2c35153..09486a787f4 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/validators/utils/validate-flat-object-metadata-identifiers.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/validators/utils/validate-flat-object-metadata-identifiers.util.ts @@ -3,23 +3,28 @@ import { isDefined, isLabelIdentifierFieldMetadataTypes, } from 'twenty-shared/utils'; +import { FieldMetadataType } from 'twenty-shared/types'; import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type'; import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util'; import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { isFlatFieldMetadataOfType } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-flat-field-metadata-of-type.util'; import { type FlatObjectMetadataValidationError } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata-validation-error.type'; import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; import { ObjectMetadataExceptionCode } from 'src/engine/metadata-modules/object-metadata/object-metadata.exception'; +import { type WorkspaceMigrationBuilderOptions } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-builder-options.type'; export const validateFlatObjectMetadataIdentifiers = ({ flatObjectMetadata, flatFieldMetadataMaps, + buildOptions, }: { flatObjectMetadata: Pick< FlatObjectMetadata, 'labelIdentifierFieldMetadataId' | 'imageIdentifierFieldMetadataId' >; flatFieldMetadataMaps: FlatEntityMaps; + buildOptions: WorkspaceMigrationBuilderOptions; }) => { const errors: FlatObjectMetadataValidationError[] = []; @@ -40,13 +45,27 @@ export const validateFlatObjectMetadataIdentifiers = ({ 'labelIdentifierFieldMetadataId validation failed: related field metadata not found', userFriendlyMessage: msg`Field declared as label identifier not found`, }); - } else if (!isLabelIdentifierFieldMetadataTypes(flatFieldMetadata.type)) { - errors.push({ - code: ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT, - message: - 'labelIdentifierFieldMetadataId validation failed: field type not compatible', - userFriendlyMessage: msg`Field cannot be used as label identifier`, - }); + } else { + if (!isLabelIdentifierFieldMetadataTypes(flatFieldMetadata.type)) { + errors.push({ + code: ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT, + message: + 'labelIdentifierFieldMetadataId validation failed: field type not compatible', + userFriendlyMessage: msg`Field cannot be used as label identifier`, + }); + } + + if ( + !buildOptions.isSystemBuild && + isFlatFieldMetadataOfType(flatFieldMetadata, FieldMetadataType.UUID) + ) { + errors.push({ + code: ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT, + message: + 'labelIdentifierFieldMetadataId validation failed: field type uuid is reserved for system object metadata', + userFriendlyMessage: msg`Field cannot be used as label identifier`, + }); + } } } diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/validators/utils/validate-flat-object-metadata-label.util.ts b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/validators/utils/validate-flat-object-metadata-label.util.ts index e18f52b76a2..b796533661a 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/validators/utils/validate-flat-object-metadata-label.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/validators/utils/validate-flat-object-metadata-label.util.ts @@ -3,13 +3,9 @@ import { msg } from '@lingui/core/macro'; import { type FlatObjectMetadataValidationError } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata-validation-error.type'; import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; import { type ObjectMetadataMinimalInformation } from 'src/engine/metadata-modules/flat-object-metadata/types/object-metadata-minimal-information.type'; -import { runFlatObjectMetadataValidators } from 'src/engine/metadata-modules/flat-object-metadata/utils/run-flat-object-metadata-validators.util'; import { ObjectMetadataExceptionCode } from 'src/engine/metadata-modules/object-metadata/object-metadata.exception'; -import { type FlatMetadataValidator } from 'src/engine/metadata-modules/types/flat-metadata-validator.type'; -import { - beneathDatabaseIdentifierMinimumLength, - exceedsDatabaseIdentifierMaximumLength, -} from 'src/engine/metadata-modules/utils/validate-database-identifier-length.utils'; +import { IDENTIFIER_MAX_CHAR_LENGTH } from 'src/engine/metadata-modules/utils/constants/identifier-max-char-length.constants'; +import { IDENTIFIER_MIN_CHAR_LENGTH } from 'src/engine/metadata-modules/utils/constants/identifier-min-char-length.constants'; export const validateFlatObjectMetadataLabel = ({ labelPlural, @@ -17,26 +13,31 @@ export const validateFlatObjectMetadataLabel = ({ }: Pick & ObjectMetadataMinimalInformation): FlatObjectMetadataValidationError[] => { const errors: FlatObjectMetadataValidationError[] = []; - const validators: FlatMetadataValidator[] = [ - { - validator: (label) => beneathDatabaseIdentifierMinimumLength(label), - message: msg`Object label is too short`, - }, - { - validator: (label) => exceedsDatabaseIdentifierMaximumLength(label), - message: msg`Object label is too long`, - }, - ]; - errors.push( - ...[labelSingular, labelPlural].flatMap((label) => - runFlatObjectMetadataValidators({ - elementToValidate: label, - validators, - }), - ), - ); + // Validate both labelSingular and labelPlural + for (const label of [labelSingular, labelPlural]) { + // Length too short check + if (label.length < IDENTIFIER_MIN_CHAR_LENGTH) { + errors.push({ + code: ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT, + message: `Object label is too short`, + userFriendlyMessage: msg`Object label is too short`, + value: label, + }); + } + // Length too long check + if (label.length > IDENTIFIER_MAX_CHAR_LENGTH) { + errors.push({ + code: ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT, + message: `Object label is too long`, + userFriendlyMessage: msg`Object label is too long`, + value: label, + }); + } + } + + // Check if labels are identical const labelsAreIdentical = labelSingular.trim().toLowerCase() === labelPlural.trim().toLowerCase(); diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/validators/utils/validate-flat-object-metadata-name.util.ts b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/validators/utils/validate-flat-object-metadata-name.util.ts index 2decbc1245d..162b6dcba24 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/validators/utils/validate-flat-object-metadata-name.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-object-metadata/validators/utils/validate-flat-object-metadata-name.util.ts @@ -1,11 +1,16 @@ import { msg } from '@lingui/core/macro'; +import camelCase from 'lodash.camelcase'; +import { RESERVED_METADATA_NAME_KEYWORDS } from 'twenty-shared/metadata'; import { type FlatObjectMetadataValidationError } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata-validation-error.type'; import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; import { type ObjectMetadataMinimalInformation } from 'src/engine/metadata-modules/flat-object-metadata/types/object-metadata-minimal-information.type'; -import { runFlatObjectMetadataValidators } from 'src/engine/metadata-modules/flat-object-metadata/utils/run-flat-object-metadata-validators.util'; import { ObjectMetadataExceptionCode } from 'src/engine/metadata-modules/object-metadata/object-metadata.exception'; -import { METADATA_NAME_VALIDATORS } from 'src/engine/metadata-modules/utils/constants/metadata-name-flat-metadata-validators.constants'; +import { IDENTIFIER_MAX_CHAR_LENGTH } from 'src/engine/metadata-modules/utils/constants/identifier-max-char-length.constants'; +import { IDENTIFIER_MIN_CHAR_LENGTH } from 'src/engine/metadata-modules/utils/constants/identifier-min-char-length.constants'; + +const STARTS_WITH_LOWER_CASE_AND_CONTAINS_ONLY_CAPS_AND_LOWER_LETTERS_AND_NUMBER_STRING_REGEX = + /^[a-z][a-zA-Z0-9]*$/; export const validateFlatObjectMetadataNames = ({ namePlural, @@ -14,15 +19,64 @@ export const validateFlatObjectMetadataNames = ({ ObjectMetadataMinimalInformation) => { const errors: FlatObjectMetadataValidationError[] = []; - errors.push( - ...[nameSingular, namePlural].flatMap((name) => - runFlatObjectMetadataValidators({ - elementToValidate: name, - validators: METADATA_NAME_VALIDATORS, - }), - ), - ); + // Validate both nameSingular and namePlural + for (const name of [nameSingular, namePlural]) { + // Length too long check + if (name.length > IDENTIFIER_MAX_CHAR_LENGTH) { + errors.push({ + code: ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT, + message: `Name is too long`, + userFriendlyMessage: msg`Name is too long`, + value: name, + }); + } + // Length too short check + if (name.length < IDENTIFIER_MIN_CHAR_LENGTH) { + errors.push({ + code: ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT, + message: `Name is too short`, + userFriendlyMessage: msg`Name is too short`, + value: name, + }); + } + + // CamelCase check + if (name !== camelCase(name)) { + errors.push({ + code: ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT, + message: `Name should be in camelCase`, + userFriendlyMessage: msg`Name should be in camelCase`, + value: name, + }); + } + + // Format check + if ( + !name.match( + STARTS_WITH_LOWER_CASE_AND_CONTAINS_ONLY_CAPS_AND_LOWER_LETTERS_AND_NUMBER_STRING_REGEX, + ) + ) { + errors.push({ + code: ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT, + message: `Name is not valid: it must start with lowercase letter and contain only alphanumeric letters`, + userFriendlyMessage: msg`Name is not valid: it must start with lowercase letter and contain only alphanumeric letters`, + value: name, + }); + } + + // Reserved keywords check + if (RESERVED_METADATA_NAME_KEYWORDS.includes(name)) { + errors.push({ + code: ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT, + message: `This name is reserved. Use a different name or the system will add "Custom" suffix.`, + userFriendlyMessage: msg`This name is reserved. Use a different name or the system will add "Custom" suffix.`, + value: name, + }); + } + } + + // Check if names are identical const namesAreIdentical = namePlural.trim().toLowerCase() === nameSingular.trim().toLowerCase(); diff --git a/packages/twenty-server/src/engine/metadata-modules/types/flat-metadata-validator.type.ts b/packages/twenty-server/src/engine/metadata-modules/types/flat-metadata-validator.type.ts deleted file mode 100644 index 7c5c3ad1877..00000000000 --- a/packages/twenty-server/src/engine/metadata-modules/types/flat-metadata-validator.type.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { type MessageDescriptor } from '@lingui/core'; - -export type FlatMetadataValidator = { - validator: (value: T) => boolean; - message: MessageDescriptor; -}; diff --git a/packages/twenty-server/src/engine/metadata-modules/utils/constants/metadata-name-flat-metadata-validators.constants.ts b/packages/twenty-server/src/engine/metadata-modules/utils/constants/metadata-name-flat-metadata-validators.constants.ts deleted file mode 100644 index 0a0d5940a11..00000000000 --- a/packages/twenty-server/src/engine/metadata-modules/utils/constants/metadata-name-flat-metadata-validators.constants.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { msg } from '@lingui/core/macro'; -import camelCase from 'lodash.camelcase'; -import { RESERVED_METADATA_NAME_KEYWORDS } from 'twenty-shared/metadata'; - -import { type FlatMetadataValidator } from 'src/engine/metadata-modules/types/flat-metadata-validator.type'; -import { - beneathDatabaseIdentifierMinimumLength, - exceedsDatabaseIdentifierMaximumLength, -} from 'src/engine/metadata-modules/utils/validate-database-identifier-length.utils'; - -const STARTS_WITH_LOWER_CASE_AND_CONTAINS_ONLY_CAPS_AND_LOWER_LETTERS_AND_NUMBER_STRING_REGEX = - /^[a-z][a-zA-Z0-9]*$/; - -export const METADATA_NAME_VALIDATORS: FlatMetadataValidator[] = [ - { - message: msg`Name is too long`, - validator: (name) => exceedsDatabaseIdentifierMaximumLength(name), - }, - { - message: msg`Name is too short`, - validator: (name) => beneathDatabaseIdentifierMinimumLength(name), - }, - { - message: msg`Name should be in camelCase`, - validator: (name) => name !== camelCase(name), - }, - { - message: msg`Name is not valid: it must start with lowercase letter and contain only alphanumeric letters`, - validator: (name) => - !name.match( - STARTS_WITH_LOWER_CASE_AND_CONTAINS_ONLY_CAPS_AND_LOWER_LETTERS_AND_NUMBER_STRING_REGEX, - ), - }, - { - // Safety net: Catch any reserved keywords that bypass frontend sanitization - // (e.g., programmatic API access, old clients) - // Frontend auto-adds "Custom" suffix, so properly formed requests will pass - message: msg`This name is reserved. Use a different name or the system will add "Custom" suffix.`, - validator: (name) => RESERVED_METADATA_NAME_KEYWORDS.includes(name), - }, -]; diff --git a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/services/dev-seeder.service.ts b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/services/dev-seeder.service.ts index 39627d3a01c..bbc40dee35d 100644 --- a/packages/twenty-server/src/engine/workspace-manager/dev-seeder/services/dev-seeder.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/dev-seeder/services/dev-seeder.service.ts @@ -5,7 +5,6 @@ import { isDefined } from 'twenty-shared/utils'; import { DataSource } from 'typeorm'; import { ApplicationService } from 'src/engine/core-modules/application/application.service'; -import { TWENTY_STANDARD_APPLICATION } from 'src/engine/core-modules/application/constants/twenty-standard-applications'; import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service'; import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service'; @@ -23,6 +22,7 @@ import { seedPageLayoutWidgets } from 'src/engine/workspace-manager/dev-seeder/c import { seedPageLayouts } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-page-layouts.util'; import { DevSeederDataService } from 'src/engine/workspace-manager/dev-seeder/data/services/dev-seeder-data.service'; import { DevSeederMetadataService } from 'src/engine/workspace-manager/dev-seeder/metadata/services/dev-seeder-metadata.service'; +import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications'; import { WorkspaceSyncMetadataService } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.service'; @Injectable() diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/calendar-events-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/calendar-events-all.view.ts index df26bd59dad..e470ed90025 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/calendar-events-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/calendar-events-all.view.ts @@ -2,11 +2,11 @@ import { msg } from '@lingui/core/macro'; import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { v4 } from 'uuid'; -import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; import { DEFAULT_VIEW_FIELD_SIZE } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/constants/DEFAULT_VIEW_FIELD_SIZE'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; import { BASE_OBJECT_STANDARD_FIELD_IDS, CALENDAR_EVENT_STANDARD_FIELD_IDS, diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/companies-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/companies-all.view.ts index 1965ab72992..69dbcdd2425 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/companies-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/companies-all.view.ts @@ -3,11 +3,11 @@ import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { v4 } from 'uuid'; import { AggregateOperations } from 'src/engine/api/graphql/graphql-query-runner/constants/aggregate-operations.constant'; -import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; import { DEFAULT_VIEW_FIELD_SIZE } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/constants/DEFAULT_VIEW_FIELD_SIZE'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; import { BASE_OBJECT_STANDARD_FIELD_IDS, COMPANY_STANDARD_FIELD_IDS, diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/dashboards-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/dashboards-all.view.ts index 199fa25aaca..3b6159c568d 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/dashboards-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/dashboards-all.view.ts @@ -2,11 +2,11 @@ import { msg } from '@lingui/core/macro'; import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { v4 } from 'uuid'; -import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { ViewOpenRecordInType } from 'src/engine/metadata-modules/view/types/view-open-record-in-type.type'; import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; import { BASE_OBJECT_STANDARD_FIELD_IDS, DASHBOARD_STANDARD_FIELD_IDS, diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/message-threads-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/message-threads-all.view.ts index e39299c4eb1..07263ddb530 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/message-threads-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/message-threads-all.view.ts @@ -2,11 +2,11 @@ import { msg } from '@lingui/core/macro'; import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { v4 } from 'uuid'; -import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; import { DEFAULT_VIEW_FIELD_SIZE } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/constants/DEFAULT_VIEW_FIELD_SIZE'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; import { BASE_OBJECT_STANDARD_FIELD_IDS, MESSAGE_THREAD_STANDARD_FIELD_IDS, diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/messages-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/messages-all.view.ts index 207b8b5f803..7c479f68d1e 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/messages-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/messages-all.view.ts @@ -2,11 +2,11 @@ import { msg } from '@lingui/core/macro'; import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { v4 } from 'uuid'; -import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; import { DEFAULT_VIEW_FIELD_SIZE } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/constants/DEFAULT_VIEW_FIELD_SIZE'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; import { BASE_OBJECT_STANDARD_FIELD_IDS, MESSAGE_STANDARD_FIELD_IDS, diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/notes-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/notes-all.view.ts index f53b136173f..49efbd40bab 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/notes-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/notes-all.view.ts @@ -2,10 +2,10 @@ import { msg } from '@lingui/core/macro'; import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { v4 } from 'uuid'; -import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; import { BASE_OBJECT_STANDARD_FIELD_IDS, NOTE_STANDARD_FIELD_IDS, diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/opportunities-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/opportunities-all.view.ts index 2f1c0d3b329..b06ab6e0f85 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/opportunities-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/opportunities-all.view.ts @@ -3,10 +3,10 @@ import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { v4 } from 'uuid'; import { AggregateOperations } from 'src/engine/api/graphql/graphql-query-runner/constants/aggregate-operations.constant'; -import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; import { OPPORTUNITY_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; export const opportunitiesAllView = ({ diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/opportunity-by-stage.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/opportunity-by-stage.view.ts index f11b6ede32a..8d7f72950bc 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/opportunity-by-stage.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/opportunity-by-stage.view.ts @@ -3,10 +3,10 @@ import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { v4 } from 'uuid'; import { AggregateOperations } from 'src/engine/api/graphql/graphql-query-runner/constants/aggregate-operations.constant'; -import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; import { OPPORTUNITY_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; export const opportunitiesByStageView = ({ diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/people-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/people-all.view.ts index ca70c4bb70f..df1c5f4d483 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/people-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/people-all.view.ts @@ -3,10 +3,10 @@ import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { v4 } from 'uuid'; import { AggregateOperations } from 'src/engine/api/graphql/graphql-query-runner/constants/aggregate-operations.constant'; -import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; import { BASE_OBJECT_STANDARD_FIELD_IDS, PERSON_STANDARD_FIELD_IDS, diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-all.view.ts index e941be78d99..e9b6cc0491d 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-all.view.ts @@ -2,10 +2,10 @@ import { msg } from '@lingui/core/macro'; import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { v4 } from 'uuid'; -import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; import { BASE_OBJECT_STANDARD_FIELD_IDS, TASK_STANDARD_FIELD_IDS, diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-assigned-to-me.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-assigned-to-me.ts index e4c061f421c..eff9814fdde 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-assigned-to-me.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-assigned-to-me.ts @@ -3,10 +3,10 @@ import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { ViewFilterOperand } from 'twenty-shared/types'; import { v4 } from 'uuid'; -import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; import { BASE_OBJECT_STANDARD_FIELD_IDS, TASK_STANDARD_FIELD_IDS, diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-by-status.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-by-status.view.ts index 654cb12189f..438bd0f2f7a 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-by-status.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-by-status.view.ts @@ -2,10 +2,10 @@ import { msg } from '@lingui/core/macro'; import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { v4 } from 'uuid'; -import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; import { BASE_OBJECT_STANDARD_FIELD_IDS, TASK_STANDARD_FIELD_IDS, diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/timeline-activities-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/timeline-activities-all.view.ts index e70afdd47e9..7b5040c9899 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/timeline-activities-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/timeline-activities-all.view.ts @@ -2,12 +2,12 @@ import { msg } from '@lingui/core/macro'; import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { v4 } from 'uuid'; -import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { ViewOpenRecordInType } from 'src/engine/metadata-modules/view/types/view-open-record-in-type.type'; import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; import { DEFAULT_VIEW_FIELD_SIZE } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/constants/DEFAULT_VIEW_FIELD_SIZE'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; import { TIMELINE_ACTIVITY_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; export const timelineActivitiesAllView = ({ diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workflow-runs-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workflow-runs-all.view.ts index d01ebc510c9..bf1338ef9a2 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workflow-runs-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workflow-runs-all.view.ts @@ -2,11 +2,11 @@ import { msg } from '@lingui/core/macro'; import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { v4 } from 'uuid'; -import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { ViewOpenRecordInType } from 'src/engine/metadata-modules/view/types/view-open-record-in-type.type'; import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; import { WORKFLOW_RUN_STANDARD_FIELD_IDS } from 'src/engine/workspace-manager/workspace-sync-metadata/constants/standard-field-ids'; export const workflowRunsAllView = ({ diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workflow-versions-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workflow-versions-all.view.ts index 68be7c95fc8..061f37423a3 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workflow-versions-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workflow-versions-all.view.ts @@ -2,11 +2,11 @@ import { msg } from '@lingui/core/macro'; import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { v4 } from 'uuid'; -import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { ViewOpenRecordInType } from 'src/engine/metadata-modules/view/types/view-open-record-in-type.type'; import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; import { BASE_OBJECT_STANDARD_FIELD_IDS, WORKFLOW_VERSION_STANDARD_FIELD_IDS, diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workflows-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workflows-all.view.ts index 53243dcdd19..949d8b69f27 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workflows-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workflows-all.view.ts @@ -2,11 +2,11 @@ import { msg } from '@lingui/core/macro'; import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { v4 } from 'uuid'; -import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { ViewOpenRecordInType } from 'src/engine/metadata-modules/view/types/view-open-record-in-type.type'; import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; import { BASE_OBJECT_STANDARD_FIELD_IDS, WORKFLOW_STANDARD_FIELD_IDS, diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workspace-members-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workspace-members-all.view.ts index 74c6ccefbe5..f47a7f0157b 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workspace-members-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/workspace-members-all.view.ts @@ -2,11 +2,11 @@ import { msg } from '@lingui/core/macro'; import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { v4 } from 'uuid'; -import { STANDARD_OBJECTS } from 'src/engine/core-modules/application/constants/standard-object.constant'; import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { type ViewDefinition } from 'src/engine/workspace-manager/standard-objects-prefill-data/types/view-definition.interface'; import { DEFAULT_VIEW_FIELD_SIZE } from 'src/engine/workspace-manager/standard-objects-prefill-data/views/constants/DEFAULT_VIEW_FIELD_SIZE'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; import { BASE_OBJECT_STANDARD_FIELD_IDS, WORKSPACE_MEMBER_STANDARD_FIELD_IDS, diff --git a/packages/twenty-server/src/engine/core-modules/application/constants/standard-object.constant.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant.ts similarity index 91% rename from packages/twenty-server/src/engine/core-modules/application/constants/standard-object.constant.ts rename to packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant.ts index 7a5fdadd937..839aeab20cd 100644 --- a/packages/twenty-server/src/engine/core-modules/application/constants/standard-object.constant.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant.ts @@ -25,12 +25,6 @@ import { TASK_STANDARD_FIELD_IDS, TASK_TARGET_STANDARD_FIELD_IDS, TIMELINE_ACTIVITY_STANDARD_FIELD_IDS, - VIEW_FIELD_STANDARD_FIELD_IDS, - VIEW_FILTER_GROUP_STANDARD_FIELD_IDS, - VIEW_FILTER_STANDARD_FIELD_IDS, - VIEW_GROUP_STANDARD_FIELD_IDS, - VIEW_SORT_STANDARD_FIELD_IDS, - VIEW_STANDARD_FIELD_IDS, WORKFLOW_AUTOMATED_TRIGGER_STANDARD_FIELD_IDS, WORKFLOW_RUN_STANDARD_FIELD_IDS, WORKFLOW_STANDARD_FIELD_IDS, @@ -630,6 +624,9 @@ export const STANDARD_OBJECTS = { universalIdentifier: MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_STANDARD_FIELD_IDS.messageThreadExternalId, }, + direction: { + universalIdentifier: '75c9b0f7-9e76-44d4-a2f9-47051e61eec7', + }, }, views: {}, }, @@ -808,10 +805,6 @@ export const STANDARD_OBJECTS = { universalIdentifier: MESSAGE_THREAD_STANDARD_FIELD_IDS.messageChannelMessageAssociations, }, - messageThreadSubscribers: { - universalIdentifier: - MESSAGE_THREAD_STANDARD_FIELD_IDS.messageThreadSubscribers, - }, }, views: { allMessageThreads: { @@ -1351,7 +1344,6 @@ export const STANDARD_OBJECTS = { happensAt: { universalIdentifier: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.happensAt, }, - type: { universalIdentifier: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.type }, name: { universalIdentifier: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.name }, properties: { universalIdentifier: TIMELINE_ACTIVITY_STANDARD_FIELD_IDS.properties, @@ -1423,140 +1415,6 @@ export const STANDARD_OBJECTS = { }, }, }, - view: { - universalIdentifier: STANDARD_OBJECT_IDS.view, - fields: { - name: { universalIdentifier: VIEW_STANDARD_FIELD_IDS.name }, - objectMetadataId: { - universalIdentifier: VIEW_STANDARD_FIELD_IDS.objectMetadataId, - }, - type: { universalIdentifier: VIEW_STANDARD_FIELD_IDS.type }, - key: { universalIdentifier: VIEW_STANDARD_FIELD_IDS.key }, - icon: { universalIdentifier: VIEW_STANDARD_FIELD_IDS.icon }, - kanbanFieldMetadataId: { - universalIdentifier: VIEW_STANDARD_FIELD_IDS.kanbanFieldMetadataId, - }, - kanbanAggregateOperation: { - universalIdentifier: VIEW_STANDARD_FIELD_IDS.kanbanAggregateOperation, - }, - kanbanAggregateOperationFieldMetadataId: { - universalIdentifier: - VIEW_STANDARD_FIELD_IDS.kanbanAggregateOperationFieldMetadataId, - }, - mainGroupByFieldMetadataId: { - universalIdentifier: VIEW_STANDARD_FIELD_IDS.mainGroupByFieldMetadataId, - }, - position: { universalIdentifier: VIEW_STANDARD_FIELD_IDS.position }, - isCompact: { universalIdentifier: VIEW_STANDARD_FIELD_IDS.isCompact }, - openRecordIn: { - universalIdentifier: VIEW_STANDARD_FIELD_IDS.openRecordIn, - }, - viewFields: { universalIdentifier: VIEW_STANDARD_FIELD_IDS.viewFields }, - viewGroups: { universalIdentifier: VIEW_STANDARD_FIELD_IDS.viewGroups }, - viewFilters: { universalIdentifier: VIEW_STANDARD_FIELD_IDS.viewFilters }, - viewFilterGroups: { - universalIdentifier: VIEW_STANDARD_FIELD_IDS.viewFilterGroups, - }, - viewSorts: { universalIdentifier: VIEW_STANDARD_FIELD_IDS.viewSorts }, - favorites: { universalIdentifier: VIEW_STANDARD_FIELD_IDS.favorites }, - anyFieldFilterValue: { - universalIdentifier: VIEW_STANDARD_FIELD_IDS.anyFieldFilterValue, - }, - }, - views: {}, - }, - viewField: { - universalIdentifier: STANDARD_OBJECT_IDS.viewField, - fields: { - fieldMetadataId: { - universalIdentifier: VIEW_FIELD_STANDARD_FIELD_IDS.fieldMetadataId, - }, - isVisible: { - universalIdentifier: VIEW_FIELD_STANDARD_FIELD_IDS.isVisible, - }, - size: { universalIdentifier: VIEW_FIELD_STANDARD_FIELD_IDS.size }, - position: { universalIdentifier: VIEW_FIELD_STANDARD_FIELD_IDS.position }, - view: { universalIdentifier: VIEW_FIELD_STANDARD_FIELD_IDS.view }, - aggregateOperation: { - universalIdentifier: VIEW_FIELD_STANDARD_FIELD_IDS.aggregateOperation, - }, - }, - views: {}, - }, - viewFilter: { - universalIdentifier: STANDARD_OBJECT_IDS.viewFilter, - fields: { - fieldMetadataId: { - universalIdentifier: VIEW_FILTER_STANDARD_FIELD_IDS.fieldMetadataId, - }, - operand: { universalIdentifier: VIEW_FILTER_STANDARD_FIELD_IDS.operand }, - value: { universalIdentifier: VIEW_FILTER_STANDARD_FIELD_IDS.value }, - displayValue: { - universalIdentifier: VIEW_FILTER_STANDARD_FIELD_IDS.displayValue, - }, - view: { universalIdentifier: VIEW_FILTER_STANDARD_FIELD_IDS.view }, - viewFilterGroupId: { - universalIdentifier: VIEW_FILTER_STANDARD_FIELD_IDS.viewFilterGroupId, - }, - positionInViewFilterGroup: { - universalIdentifier: - VIEW_FILTER_STANDARD_FIELD_IDS.positionInViewFilterGroup, - }, - subFieldName: { - universalIdentifier: VIEW_FILTER_STANDARD_FIELD_IDS.subFieldName, - }, - }, - views: {}, - }, - viewFilterGroup: { - universalIdentifier: STANDARD_OBJECT_IDS.viewFilterGroup, - fields: { - view: { universalIdentifier: VIEW_FILTER_GROUP_STANDARD_FIELD_IDS.view }, - parentViewFilterGroupId: { - universalIdentifier: - VIEW_FILTER_GROUP_STANDARD_FIELD_IDS.parentViewFilterGroupId, - }, - logicalOperator: { - universalIdentifier: - VIEW_FILTER_GROUP_STANDARD_FIELD_IDS.logicalOperator, - }, - positionInViewFilterGroup: { - universalIdentifier: - VIEW_FILTER_GROUP_STANDARD_FIELD_IDS.positionInViewFilterGroup, - }, - }, - views: {}, - }, - viewGroup: { - universalIdentifier: STANDARD_OBJECT_IDS.viewGroup, - fields: { - fieldMetadataId: { - universalIdentifier: VIEW_GROUP_STANDARD_FIELD_IDS.fieldMetadataId, - }, - fieldValue: { - universalIdentifier: VIEW_GROUP_STANDARD_FIELD_IDS.fieldValue, - }, - isVisible: { - universalIdentifier: VIEW_GROUP_STANDARD_FIELD_IDS.isVisible, - }, - position: { universalIdentifier: VIEW_GROUP_STANDARD_FIELD_IDS.position }, - view: { universalIdentifier: VIEW_GROUP_STANDARD_FIELD_IDS.view }, - }, - views: {}, - }, - viewSort: { - universalIdentifier: STANDARD_OBJECT_IDS.viewSort, - fields: { - fieldMetadataId: { - universalIdentifier: VIEW_SORT_STANDARD_FIELD_IDS.fieldMetadataId, - }, - direction: { - universalIdentifier: VIEW_SORT_STANDARD_FIELD_IDS.direction, - }, - view: { universalIdentifier: VIEW_SORT_STANDARD_FIELD_IDS.view }, - }, - views: {}, - }, workflow: { universalIdentifier: STANDARD_OBJECT_IDS.workflow, fields: { @@ -1818,14 +1676,6 @@ export const STANDARD_OBJECTS = { userId: { universalIdentifier: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.userId, }, - authoredActivities: { - universalIdentifier: - WORKSPACE_MEMBER_STANDARD_FIELD_IDS.authoredActivities, - }, - assignedActivities: { - universalIdentifier: - WORKSPACE_MEMBER_STANDARD_FIELD_IDS.assignedActivities, - }, assignedTasks: { universalIdentifier: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.assignedTasks, }, @@ -1840,10 +1690,6 @@ export const STANDARD_OBJECTS = { universalIdentifier: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.authoredAttachments, }, - authoredComments: { - universalIdentifier: - WORKSPACE_MEMBER_STANDARD_FIELD_IDS.authoredComments, - }, connectedAccounts: { universalIdentifier: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.connectedAccounts, @@ -1863,13 +1709,6 @@ export const STANDARD_OBJECTS = { universalIdentifier: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.timelineActivities, }, - auditLogs: { - universalIdentifier: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.auditLogs, - }, - messageThreadSubscribers: { - universalIdentifier: - WORKSPACE_MEMBER_STANDARD_FIELD_IDS.messageThreadSubscribers, - }, timeZone: { universalIdentifier: WORKSPACE_MEMBER_STANDARD_FIELD_IDS.timeZone, }, diff --git a/packages/twenty-server/src/engine/core-modules/application/constants/twenty-standard-applications.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications.ts similarity index 100% rename from packages/twenty-server/src/engine/core-modules/application/constants/twenty-standard-applications.ts rename to packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications.ts diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type.ts new file mode 100644 index 00000000000..d8ece89bded --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type.ts @@ -0,0 +1,5 @@ +import { type STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; +import { type AllStandardObjectName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-name.type'; + +export type AllStandardObjectFieldName = + keyof (typeof STANDARD_OBJECTS)[T]['fields']; diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-name.type.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-name.type.ts new file mode 100644 index 00000000000..c91ae13ce5b --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-name.type.ts @@ -0,0 +1,3 @@ +import { type STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; + +export type AllStandardObjectName = keyof typeof STANDARD_OBJECTS; diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/build-standard-flat-field-metadata-maps.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/build-standard-flat-field-metadata-maps.util.ts new file mode 100644 index 00000000000..97caabd0262 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/build-standard-flat-field-metadata-maps.util.ts @@ -0,0 +1,116 @@ +import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type'; +import { addFlatEntityToFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/add-flat-entity-to-flat-entity-maps-or-throw.util'; +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-name.type'; +import { buildAttachmentStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-attachment-standard-flat-field-metadata.util'; +import { buildBlocklistStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-blocklist-standard-flat-field-metadata.util'; +import { buildCalendarChannelEventAssociationStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-calendar-channel-event-association-standard-flat-field-metadata.util'; +import { buildCalendarChannelStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-calendar-channel-standard-flat-field-metadata.util'; +import { buildCalendarEventParticipantStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-calendar-event-participant-standard-flat-field-metadata.util'; +import { buildCalendarEventStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-calendar-event-standard-flat-field-metadata.util'; +import { buildCompanyStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-company-standard-flat-field-metadata.util'; +import { buildConnectedAccountStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-connected-account-standard-flat-field-metadata.util'; +import { buildDashboardStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-dashboard-standard-flat-field-metadata.util'; +import { buildFavoriteFolderStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-favorite-folder-standard-flat-field-metadata.util'; +import { buildFavoriteStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-favorite-standard-flat-field-metadata.util'; +import { buildMessageChannelMessageAssociationStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-message-channel-message-association-standard-flat-field-metadata.util'; +import { buildMessageChannelStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-message-channel-standard-flat-field-metadata.util'; +import { buildMessageFolderStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-message-folder-standard-flat-field-metadata.util'; +import { buildMessageParticipantStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-message-participant-standard-flat-field-metadata.util'; +import { buildMessageStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-message-standard-flat-field-metadata.util'; +import { buildMessageThreadStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-message-thread-standard-flat-field-metadata.util'; +import { buildNoteStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-note-standard-flat-field-metadata.util'; +import { buildNoteTargetStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-note-target-standard-flat-field-metadata.util'; +import { buildOpportunityStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-opportunity-standard-flat-field-metadata.util'; +import { buildPersonStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-person-standard-flat-field-metadata.util'; +import { buildTaskStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-task-standard-flat-field-metadata.util'; +import { buildTaskTargetStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-task-target-standard-flat-field-metadata.util'; +import { buildTimelineActivityStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-timeline-activity-standard-flat-field-metadata.util'; +import { buildWorkflowAutomatedTriggerStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-workflow-automated-trigger-standard-flat-field-metadata.util'; +import { buildWorkflowRunStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-workflow-run-standard-flat-field-metadata.util'; +import { buildWorkflowStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-workflow-standard-flat-field-metadata.util'; +import { buildWorkflowVersionStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-workflow-version-standard-flat-field-metadata.util'; +import { buildWorkspaceMemberStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/compute-workspace-member-standard-flat-field-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +type BuildStandardFlatFieldMetadataMapsArgs = { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}; + +type StandardFlatFieldMetadataBuilder = ( + args: BuildStandardFlatFieldMetadataMapsArgs, +) => Record; + +const STANDARD_FLAT_FIELD_METADATA_BUILDERS_BY_OBJECT_NAME = { + attachment: buildAttachmentStandardFlatFieldMetadatas, + blocklist: buildBlocklistStandardFlatFieldMetadatas, + calendarChannelEventAssociation: + buildCalendarChannelEventAssociationStandardFlatFieldMetadatas, + calendarChannel: buildCalendarChannelStandardFlatFieldMetadatas, + calendarEventParticipant: + buildCalendarEventParticipantStandardFlatFieldMetadatas, + calendarEvent: buildCalendarEventStandardFlatFieldMetadatas, + company: buildCompanyStandardFlatFieldMetadatas, + connectedAccount: buildConnectedAccountStandardFlatFieldMetadatas, + dashboard: buildDashboardStandardFlatFieldMetadatas, + favorite: buildFavoriteStandardFlatFieldMetadatas, + favoriteFolder: buildFavoriteFolderStandardFlatFieldMetadatas, + message: buildMessageStandardFlatFieldMetadatas, + messageChannel: buildMessageChannelStandardFlatFieldMetadatas, + messageChannelMessageAssociation: + buildMessageChannelMessageAssociationStandardFlatFieldMetadatas, + messageFolder: buildMessageFolderStandardFlatFieldMetadatas, + messageParticipant: buildMessageParticipantStandardFlatFieldMetadatas, + messageThread: buildMessageThreadStandardFlatFieldMetadatas, + note: buildNoteStandardFlatFieldMetadatas, + noteTarget: buildNoteTargetStandardFlatFieldMetadatas, + opportunity: buildOpportunityStandardFlatFieldMetadatas, + person: buildPersonStandardFlatFieldMetadatas, + task: buildTaskStandardFlatFieldMetadatas, + taskTarget: buildTaskTargetStandardFlatFieldMetadatas, + timelineActivity: buildTimelineActivityStandardFlatFieldMetadatas, + workflow: buildWorkflowStandardFlatFieldMetadatas, + workflowAutomatedTrigger: + buildWorkflowAutomatedTriggerStandardFlatFieldMetadatas, + workflowRun: buildWorkflowRunStandardFlatFieldMetadatas, + workflowVersion: buildWorkflowVersionStandardFlatFieldMetadatas, + workspaceMember: buildWorkspaceMemberStandardFlatFieldMetadatas, +} satisfies Record; + +const createEmptyFlatFieldMetadataMaps = + (): FlatEntityMaps => ({ + byId: {}, + idByUniversalIdentifier: {}, + universalIdentifiersByApplicationId: {}, + }); + +export const buildStandardFlatFieldMetadataMaps = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: BuildStandardFlatFieldMetadataMapsArgs): FlatEntityMaps => { + const builderArgs = { + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, + }; + + // Collect all field metadatas from all standard objects + const allFieldMetadatas: FlatFieldMetadata[] = Object.values( + STANDARD_FLAT_FIELD_METADATA_BUILDERS_BY_OBJECT_NAME, + ).flatMap((builder) => Object.values(builder(builderArgs))); + + // Build maps using addFlatEntityToFlatEntityMapsOrThrow to prevent duplicate IDs + let flatFieldMetadataMaps = createEmptyFlatFieldMetadataMaps(); + + for (const fieldMetadata of allFieldMetadatas) { + flatFieldMetadataMaps = addFlatEntityToFlatEntityMapsOrThrow({ + flatEntity: fieldMetadata, + flatEntityMaps: flatFieldMetadataMaps, + }); + } + + return flatFieldMetadataMaps; +}; diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/build-standard-flat-object-metadata-maps.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/build-standard-flat-object-metadata-maps.util.ts new file mode 100644 index 00000000000..2059ba6e304 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/build-standard-flat-object-metadata-maps.util.ts @@ -0,0 +1,35 @@ +import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type'; +import { addFlatEntityToFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/add-flat-entity-to-flat-entity-maps-or-throw.util'; +import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; +import { + type BuildStandardFlatObjectMetadatasArgs, + STANDARD_FLAT_OBJECT_METADATA_BUILDERS_BY_OBJECT_NAME, +} from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-flat-object-metadata.util'; + +const createEmptyFlatObjectMetadataMaps = + (): FlatEntityMaps => ({ + byId: {}, + idByUniversalIdentifier: {}, + universalIdentifiersByApplicationId: {}, + }); + +export const buildStandardFlatObjectMetadataMaps = ( + args: BuildStandardFlatObjectMetadatasArgs, +): FlatEntityMaps => { + // Collect all object metadatas from all standard objects + const allObjectMetadatas: FlatObjectMetadata[] = Object.values( + STANDARD_FLAT_OBJECT_METADATA_BUILDERS_BY_OBJECT_NAME, + ).map((builder) => builder(args)); + + // Build maps using addFlatEntityToFlatEntityMapsOrThrow to prevent duplicate IDs + let flatObjectMetadataMaps = createEmptyFlatObjectMetadataMaps(); + + for (const objectMetadata of allObjectMetadatas) { + flatObjectMetadataMaps = addFlatEntityToFlatEntityMapsOrThrow({ + flatEntity: objectMetadata, + flatEntityMaps: flatObjectMetadataMaps, + }); + } + + return flatObjectMetadataMaps; +}; diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-attachment-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-attachment-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..7e5498ce2ed --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-attachment-standard-flat-field-metadata.util.ts @@ -0,0 +1,399 @@ +import { + FieldMetadataType, + RelationOnDeleteAction, + RelationType, +} from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildAttachmentStandardFlatFieldMetadatas = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): Record, FlatFieldMetadata> => ({ + // Base fields from BaseWorkspaceEntity + id: createStandardFieldFlatMetadata({ + objectName: 'attachment', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'attachment', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { + displayFormat: 'RELATIVE', + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'attachment', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { + displayFormat: 'RELATIVE', + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'attachment', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { + displayFormat: 'RELATIVE', + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + + // Attachment-specific fields + name: createStandardFieldFlatMetadata({ + objectName: 'attachment', + workspaceId, + options: { + fieldName: 'name', + type: FieldMetadataType.TEXT, + label: 'Name', + description: 'Attachment name', + icon: 'IconFileUpload', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + fullPath: createStandardFieldFlatMetadata({ + objectName: 'attachment', + workspaceId, + options: { + fieldName: 'fullPath', + type: FieldMetadataType.TEXT, + label: 'Full path', + description: 'Attachment full path', + icon: 'IconLink', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + type: createStandardFieldFlatMetadata({ + objectName: 'attachment', + workspaceId, + options: { + fieldName: 'type', + type: FieldMetadataType.TEXT, + label: 'Type (deprecated)', + description: 'Attachment type (deprecated - use fileCategory)', + icon: 'IconList', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + fileCategory: createStandardFieldFlatMetadata({ + objectName: 'attachment', + workspaceId, + options: { + fieldName: 'fileCategory', + type: FieldMetadataType.SELECT, + label: 'File category', + description: 'Attachment file category', + icon: 'IconList', + isNullable: false, + defaultValue: "'OTHER'", + options: [ + { value: 'ARCHIVE', label: 'Archive', position: 0, color: 'gray' }, + { value: 'AUDIO', label: 'Audio', position: 1, color: 'pink' }, + { value: 'IMAGE', label: 'Image', position: 2, color: 'yellow' }, + { + value: 'PRESENTATION', + label: 'Presentation', + position: 3, + color: 'orange', + }, + { + value: 'SPREADSHEET', + label: 'Spreadsheet', + position: 4, + color: 'turquoise', + }, + { + value: 'TEXT_DOCUMENT', + label: 'Text Document', + position: 5, + color: 'blue', + }, + { value: 'VIDEO', label: 'Video', position: 6, color: 'purple' }, + { value: 'OTHER', label: 'Other', position: 7, color: 'gray' }, + ], + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdBy: createStandardFieldFlatMetadata({ + objectName: 'attachment', + workspaceId, + options: { + fieldName: 'createdBy', + type: FieldMetadataType.ACTOR, + label: 'Created by', + description: 'The creator of the record', + icon: 'IconCreativeCommonsSa', + isUIReadOnly: true, + isNullable: false, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + + // Relation fields + author: createStandardRelationFieldFlatMetadata({ + objectName: 'attachment', + workspaceId, + options: { + fieldName: 'author', + label: 'Author', + description: 'Attachment author (deprecated - use createdBy)', + icon: 'IconCircleUser', + isNullable: true, + createdAt, + targetObjectName: 'workspaceMember', + targetFieldName: 'authoredAttachments', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.SET_NULL, + joinColumnName: 'authorId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + activity: createStandardRelationFieldFlatMetadata({ + objectName: 'attachment', + workspaceId, + options: { + fieldName: 'activity', + label: 'Activity', + description: 'Attachment activity', + icon: 'IconNotes', + isNullable: true, + createdAt, + // Activity is deprecated, pointing to a non-existent target + targetObjectName: 'note', + targetFieldName: 'attachments', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.SET_NULL, + joinColumnName: 'activityId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + task: createStandardRelationFieldFlatMetadata({ + objectName: 'attachment', + workspaceId, + options: { + fieldName: 'task', + label: 'Task', + description: 'Attachment task', + icon: 'IconNotes', + isNullable: true, + createdAt, + targetObjectName: 'task', + targetFieldName: 'attachments', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.SET_NULL, + joinColumnName: 'taskId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + note: createStandardRelationFieldFlatMetadata({ + objectName: 'attachment', + workspaceId, + options: { + fieldName: 'note', + label: 'Note', + description: 'Attachment note', + icon: 'IconNotes', + isNullable: true, + createdAt, + targetObjectName: 'note', + targetFieldName: 'attachments', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.SET_NULL, + joinColumnName: 'noteId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + person: createStandardRelationFieldFlatMetadata({ + objectName: 'attachment', + workspaceId, + options: { + fieldName: 'person', + label: 'Person', + description: 'Attachment person', + icon: 'IconUser', + isNullable: true, + createdAt, + targetObjectName: 'person', + targetFieldName: 'attachments', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'personId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + company: createStandardRelationFieldFlatMetadata({ + objectName: 'attachment', + workspaceId, + options: { + fieldName: 'company', + label: 'Company', + description: 'Attachment company', + icon: 'IconBuildingSkyscraper', + isNullable: true, + createdAt, + targetObjectName: 'company', + targetFieldName: 'attachments', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'companyId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + opportunity: createStandardRelationFieldFlatMetadata({ + objectName: 'attachment', + workspaceId, + options: { + fieldName: 'opportunity', + label: 'Opportunity', + description: 'Attachment opportunity', + icon: 'IconBuildingSkyscraper', + isNullable: true, + createdAt, + targetObjectName: 'opportunity', + targetFieldName: 'attachments', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'opportunityId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + dashboard: createStandardRelationFieldFlatMetadata({ + objectName: 'attachment', + workspaceId, + options: { + fieldName: 'dashboard', + label: 'Dashboard', + description: 'Attachment dashboard', + icon: 'IconLayout', + isNullable: true, + createdAt, + targetObjectName: 'dashboard', + targetFieldName: 'attachments', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'dashboardId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + workflow: createStandardRelationFieldFlatMetadata({ + objectName: 'attachment', + workspaceId, + options: { + fieldName: 'workflow', + label: 'Workflow', + description: 'Attachment workflow', + icon: 'IconSettingsAutomation', + isNullable: true, + createdAt, + targetObjectName: 'workflow', + targetFieldName: 'attachments', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'workflowId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + custom: createStandardRelationFieldFlatMetadata({ + objectName: 'attachment', + workspaceId, + options: { + fieldName: 'custom', + label: 'Custom', + description: 'Attachment custom object', + icon: 'IconBuildingSkyscraper', + isNullable: true, + createdAt, + // Custom is a dynamic relation, pointing to custom objects + targetObjectName: 'note', + targetFieldName: 'attachments', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'customId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-blocklist-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-blocklist-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..93afcb0369c --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-blocklist-standard-flat-field-metadata.util.ts @@ -0,0 +1,134 @@ +import { + FieldMetadataType, + RelationOnDeleteAction, + RelationType, +} from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildBlocklistStandardFlatFieldMetadatas = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): Record, FlatFieldMetadata> => ({ + // Base fields from BaseWorkspaceEntity + id: createStandardFieldFlatMetadata({ + objectName: 'blocklist', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'blocklist', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { + displayFormat: 'RELATIVE', + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'blocklist', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { + displayFormat: 'RELATIVE', + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'blocklist', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { + displayFormat: 'RELATIVE', + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + + // Blocklist-specific fields + handle: createStandardFieldFlatMetadata({ + objectName: 'blocklist', + workspaceId, + options: { + fieldName: 'handle', + type: FieldMetadataType.TEXT, + label: 'Handle', + description: 'Handle', + icon: 'IconAt', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + + // Relation fields + workspaceMember: createStandardRelationFieldFlatMetadata({ + objectName: 'blocklist', + workspaceId, + options: { + fieldName: 'workspaceMember', + label: 'WorkspaceMember', + description: 'WorkspaceMember', + icon: 'IconCircleUser', + isNullable: false, + createdAt, + targetObjectName: 'workspaceMember', + targetFieldName: 'blocklist', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.SET_NULL, + joinColumnName: 'workspaceMemberId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-calendar-channel-event-association-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-calendar-channel-event-association-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..f196f40c53b --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-calendar-channel-event-association-standard-flat-field-metadata.util.ts @@ -0,0 +1,160 @@ +import { + FieldMetadataType, + RelationOnDeleteAction, + RelationType, +} from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildCalendarChannelEventAssociationStandardFlatFieldMetadatas = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): Record< + AllStandardObjectFieldName<'calendarChannelEventAssociation'>, + FlatFieldMetadata +> => ({ + id: createStandardFieldFlatMetadata({ + objectName: 'calendarChannelEventAssociation', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'calendarChannelEventAssociation', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'calendarChannelEventAssociation', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'calendarChannelEventAssociation', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + eventExternalId: createStandardFieldFlatMetadata({ + objectName: 'calendarChannelEventAssociation', + workspaceId, + options: { + fieldName: 'eventExternalId', + type: FieldMetadataType.TEXT, + label: 'Event external ID', + description: 'Event external ID', + icon: 'IconCalendar', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + recurringEventExternalId: createStandardFieldFlatMetadata({ + objectName: 'calendarChannelEventAssociation', + workspaceId, + options: { + fieldName: 'recurringEventExternalId', + type: FieldMetadataType.TEXT, + label: 'Recurring Event ID', + description: 'Recurring Event ID', + icon: 'IconHistory', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + calendarChannel: createStandardRelationFieldFlatMetadata({ + objectName: 'calendarChannelEventAssociation', + workspaceId, + options: { + fieldName: 'calendarChannel', + label: 'Channel ID', + description: 'Channel ID', + icon: 'IconCalendar', + isNullable: false, + createdAt, + targetObjectName: 'calendarChannel', + targetFieldName: 'calendarChannelEventAssociations', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'calendarChannelId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + calendarEvent: createStandardRelationFieldFlatMetadata({ + objectName: 'calendarChannelEventAssociation', + workspaceId, + options: { + fieldName: 'calendarEvent', + label: 'Event ID', + description: 'Event ID', + icon: 'IconCalendar', + isNullable: false, + createdAt, + targetObjectName: 'calendarEvent', + targetFieldName: 'calendarChannelEventAssociations', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'calendarEventId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-calendar-channel-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-calendar-channel-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..00d6b16c682 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-calendar-channel-standard-flat-field-metadata.util.ts @@ -0,0 +1,389 @@ +import { + FieldMetadataType, + RelationOnDeleteAction, + RelationType, +} from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildCalendarChannelStandardFlatFieldMetadatas = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): Record< + AllStandardObjectFieldName<'calendarChannel'>, + FlatFieldMetadata +> => ({ + id: createStandardFieldFlatMetadata({ + objectName: 'calendarChannel', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'calendarChannel', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'calendarChannel', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'calendarChannel', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + handle: createStandardFieldFlatMetadata({ + objectName: 'calendarChannel', + workspaceId, + options: { + fieldName: 'handle', + type: FieldMetadataType.TEXT, + label: 'Handle', + description: 'Handle', + icon: 'IconAt', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + visibility: createStandardFieldFlatMetadata({ + objectName: 'calendarChannel', + workspaceId, + options: { + fieldName: 'visibility', + type: FieldMetadataType.SELECT, + label: 'Visibility', + description: 'Visibility', + icon: 'IconEyeglass', + isNullable: false, + defaultValue: "'SHARE_EVERYTHING'", + options: [ + { value: 'METADATA', label: 'Metadata', position: 0, color: 'green' }, + { + value: 'SHARE_EVERYTHING', + label: 'Share Everything', + position: 1, + color: 'orange', + }, + ], + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + isContactAutoCreationEnabled: createStandardFieldFlatMetadata({ + objectName: 'calendarChannel', + workspaceId, + options: { + fieldName: 'isContactAutoCreationEnabled', + type: FieldMetadataType.BOOLEAN, + label: 'Is Contact Auto Creation Enabled', + description: 'Is Contact Auto Creation Enabled', + icon: 'IconUserCircle', + isNullable: false, + defaultValue: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + contactAutoCreationPolicy: createStandardFieldFlatMetadata({ + objectName: 'calendarChannel', + workspaceId, + options: { + fieldName: 'contactAutoCreationPolicy', + type: FieldMetadataType.SELECT, + label: 'Contact auto creation policy', + description: + 'Automatically create records for people you participated with in an event.', + icon: 'IconUserCircle', + isNullable: false, + defaultValue: "'AS_PARTICIPANT_AND_ORGANIZER'", + options: [ + { + value: 'AS_PARTICIPANT_AND_ORGANIZER', + label: 'As Participant and Organizer', + color: 'green', + position: 0, + }, + { + value: 'AS_PARTICIPANT', + label: 'As Participant', + color: 'orange', + position: 1, + }, + { + value: 'AS_ORGANIZER', + label: 'As Organizer', + color: 'blue', + position: 2, + }, + { value: 'NONE', label: 'None', color: 'red', position: 3 }, + ], + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + isSyncEnabled: createStandardFieldFlatMetadata({ + objectName: 'calendarChannel', + workspaceId, + options: { + fieldName: 'isSyncEnabled', + type: FieldMetadataType.BOOLEAN, + label: 'Is Sync Enabled', + description: 'Is Sync Enabled', + icon: 'IconRefresh', + isNullable: false, + defaultValue: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + syncCursor: createStandardFieldFlatMetadata({ + objectName: 'calendarChannel', + workspaceId, + options: { + fieldName: 'syncCursor', + type: FieldMetadataType.TEXT, + label: 'Sync Cursor', + description: + 'Sync Cursor. Used for syncing events from the calendar provider', + icon: 'IconReload', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + syncStatus: createStandardFieldFlatMetadata({ + objectName: 'calendarChannel', + workspaceId, + options: { + fieldName: 'syncStatus', + type: FieldMetadataType.SELECT, + label: 'Sync status', + description: 'Sync status', + icon: 'IconStatusChange', + isNullable: true, + options: [ + { value: 'ONGOING', label: 'Ongoing', position: 1, color: 'yellow' }, + { + value: 'NOT_SYNCED', + label: 'Not Synced', + position: 2, + color: 'blue', + }, + { value: 'ACTIVE', label: 'Active', position: 3, color: 'green' }, + { + value: 'FAILED_INSUFFICIENT_PERMISSIONS', + label: 'Failed Insufficient Permissions', + position: 4, + color: 'red', + }, + { + value: 'FAILED_UNKNOWN', + label: 'Failed Unknown', + position: 5, + color: 'red', + }, + ], + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + syncStage: createStandardFieldFlatMetadata({ + objectName: 'calendarChannel', + workspaceId, + options: { + fieldName: 'syncStage', + type: FieldMetadataType.SELECT, + label: 'Sync stage', + description: 'Sync stage', + icon: 'IconStatusChange', + isNullable: false, + defaultValue: "'PENDING_CONFIGURATION'", + options: [ + { + value: 'CALENDAR_EVENT_LIST_FETCH_PENDING', + label: 'Calendar event list fetch pending', + position: 0, + color: 'blue', + }, + { + value: 'CALENDAR_EVENT_LIST_FETCH_SCHEDULED', + label: 'Calendar event list fetch scheduled', + position: 1, + color: 'green', + }, + { + value: 'CALENDAR_EVENT_LIST_FETCH_ONGOING', + label: 'Calendar event list fetch ongoing', + position: 2, + color: 'orange', + }, + { + value: 'CALENDAR_EVENTS_IMPORT_PENDING', + label: 'Calendar events import pending', + position: 3, + color: 'blue', + }, + { + value: 'CALENDAR_EVENTS_IMPORT_SCHEDULED', + label: 'Calendar events import scheduled', + position: 4, + color: 'green', + }, + { + value: 'CALENDAR_EVENTS_IMPORT_ONGOING', + label: 'Calendar events import ongoing', + position: 5, + color: 'orange', + }, + { value: 'FAILED', label: 'Failed', position: 6, color: 'red' }, + { + value: 'PENDING_CONFIGURATION', + label: 'Pending configuration', + position: 9, + color: 'gray', + }, + ], + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + syncStageStartedAt: createStandardFieldFlatMetadata({ + objectName: 'calendarChannel', + workspaceId, + options: { + fieldName: 'syncStageStartedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Sync stage started at', + description: 'Sync stage started at', + icon: 'IconHistory', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + syncedAt: createStandardFieldFlatMetadata({ + objectName: 'calendarChannel', + workspaceId, + options: { + fieldName: 'syncedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last sync date', + description: 'Last sync date', + icon: 'IconHistory', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + throttleFailureCount: createStandardFieldFlatMetadata({ + objectName: 'calendarChannel', + workspaceId, + options: { + fieldName: 'throttleFailureCount', + type: FieldMetadataType.NUMBER, + label: 'Throttle Failure Count', + description: 'Throttle Failure Count', + icon: 'IconX', + isNullable: false, + defaultValue: 0, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + connectedAccount: createStandardRelationFieldFlatMetadata({ + objectName: 'calendarChannel', + workspaceId, + options: { + fieldName: 'connectedAccount', + label: 'Connected Account', + description: 'Connected Account', + icon: 'IconUserCircle', + isNullable: false, + createdAt, + targetObjectName: 'connectedAccount', + targetFieldName: 'calendarChannels', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'connectedAccountId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + calendarChannelEventAssociations: createStandardRelationFieldFlatMetadata({ + objectName: 'calendarChannel', + workspaceId, + options: { + fieldName: 'calendarChannelEventAssociations', + label: 'Calendar Channel Event Associations', + description: 'Calendar Channel Event Associations', + icon: 'IconCalendar', + isNullable: false, + createdAt, + targetObjectName: 'calendarChannelEventAssociation', + targetFieldName: 'calendarChannel', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-calendar-event-participant-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-calendar-event-participant-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..87b0948f35e --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-calendar-event-participant-standard-flat-field-metadata.util.ts @@ -0,0 +1,226 @@ +import { + FieldMetadataType, + RelationOnDeleteAction, + RelationType, +} from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildCalendarEventParticipantStandardFlatFieldMetadatas = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): Record< + AllStandardObjectFieldName<'calendarEventParticipant'>, + FlatFieldMetadata +> => ({ + id: createStandardFieldFlatMetadata({ + objectName: 'calendarEventParticipant', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'calendarEventParticipant', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'calendarEventParticipant', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'calendarEventParticipant', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + handle: createStandardFieldFlatMetadata({ + objectName: 'calendarEventParticipant', + workspaceId, + options: { + fieldName: 'handle', + type: FieldMetadataType.TEXT, + label: 'Handle', + description: 'Handle', + icon: 'IconMail', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + displayName: createStandardFieldFlatMetadata({ + objectName: 'calendarEventParticipant', + workspaceId, + options: { + fieldName: 'displayName', + type: FieldMetadataType.TEXT, + label: 'Display Name', + description: 'Display Name', + icon: 'IconUser', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + isOrganizer: createStandardFieldFlatMetadata({ + objectName: 'calendarEventParticipant', + workspaceId, + options: { + fieldName: 'isOrganizer', + type: FieldMetadataType.BOOLEAN, + label: 'Is Organizer', + description: 'Is Organizer', + icon: 'IconUser', + isNullable: false, + defaultValue: false, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + responseStatus: createStandardFieldFlatMetadata({ + objectName: 'calendarEventParticipant', + workspaceId, + options: { + fieldName: 'responseStatus', + type: FieldMetadataType.SELECT, + label: 'Response Status', + description: 'Response Status', + icon: 'IconUser', + isNullable: false, + defaultValue: "'NEEDS_ACTION'", + options: [ + { + value: 'NEEDS_ACTION', + label: 'Needs Action', + position: 0, + color: 'orange', + }, + { value: 'DECLINED', label: 'Declined', position: 1, color: 'red' }, + { + value: 'TENTATIVE', + label: 'Tentative', + position: 2, + color: 'yellow', + }, + { value: 'ACCEPTED', label: 'Accepted', position: 3, color: 'green' }, + ], + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + calendarEvent: createStandardRelationFieldFlatMetadata({ + objectName: 'calendarEventParticipant', + workspaceId, + options: { + fieldName: 'calendarEvent', + label: 'Event ID', + description: 'Event ID', + icon: 'IconCalendar', + isNullable: false, + createdAt, + targetObjectName: 'calendarEvent', + targetFieldName: 'calendarEventParticipants', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'calendarEventId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + person: createStandardRelationFieldFlatMetadata({ + objectName: 'calendarEventParticipant', + workspaceId, + options: { + fieldName: 'person', + label: 'Person', + description: 'Person', + icon: 'IconUser', + isNullable: true, + createdAt, + targetObjectName: 'person', + targetFieldName: 'calendarEventParticipants', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.SET_NULL, + joinColumnName: 'personId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + workspaceMember: createStandardRelationFieldFlatMetadata({ + objectName: 'calendarEventParticipant', + workspaceId, + options: { + fieldName: 'workspaceMember', + label: 'Workspace Member', + description: 'Workspace Member', + icon: 'IconUser', + isNullable: true, + createdAt, + targetObjectName: 'workspaceMember', + targetFieldName: 'calendarEventParticipants', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.SET_NULL, + joinColumnName: 'workspaceMemberId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-calendar-event-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-calendar-event-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..09b5e893d08 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-calendar-event-standard-flat-field-metadata.util.ts @@ -0,0 +1,291 @@ +import { FieldMetadataType, RelationType } from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildCalendarEventStandardFlatFieldMetadatas = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): Record, FlatFieldMetadata> => ({ + id: createStandardFieldFlatMetadata({ + objectName: 'calendarEvent', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'calendarEvent', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'calendarEvent', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'calendarEvent', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + title: createStandardFieldFlatMetadata({ + objectName: 'calendarEvent', + workspaceId, + options: { + fieldName: 'title', + type: FieldMetadataType.TEXT, + label: 'Title', + description: 'Title', + icon: 'IconH1', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + isCanceled: createStandardFieldFlatMetadata({ + objectName: 'calendarEvent', + workspaceId, + options: { + fieldName: 'isCanceled', + type: FieldMetadataType.BOOLEAN, + label: 'Is canceled', + description: 'Is canceled', + icon: 'IconCalendarCancel', + isNullable: false, + defaultValue: false, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + isFullDay: createStandardFieldFlatMetadata({ + objectName: 'calendarEvent', + workspaceId, + options: { + fieldName: 'isFullDay', + type: FieldMetadataType.BOOLEAN, + label: 'Is Full Day', + description: 'Is Full Day', + icon: 'IconHours24', + isNullable: false, + defaultValue: false, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + startsAt: createStandardFieldFlatMetadata({ + objectName: 'calendarEvent', + workspaceId, + options: { + fieldName: 'startsAt', + type: FieldMetadataType.DATE_TIME, + label: 'Start Date', + description: 'Start Date', + icon: 'IconCalendarClock', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + endsAt: createStandardFieldFlatMetadata({ + objectName: 'calendarEvent', + workspaceId, + options: { + fieldName: 'endsAt', + type: FieldMetadataType.DATE_TIME, + label: 'End Date', + description: 'End Date', + icon: 'IconCalendarClock', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + externalCreatedAt: createStandardFieldFlatMetadata({ + objectName: 'calendarEvent', + workspaceId, + options: { + fieldName: 'externalCreatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation DateTime', + description: 'Creation DateTime', + icon: 'IconCalendarPlus', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + externalUpdatedAt: createStandardFieldFlatMetadata({ + objectName: 'calendarEvent', + workspaceId, + options: { + fieldName: 'externalUpdatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Update DateTime', + description: 'Update DateTime', + icon: 'IconCalendarCog', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + description: createStandardFieldFlatMetadata({ + objectName: 'calendarEvent', + workspaceId, + options: { + fieldName: 'description', + type: FieldMetadataType.TEXT, + label: 'Description', + description: 'Description', + icon: 'IconFileDescription', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + location: createStandardFieldFlatMetadata({ + objectName: 'calendarEvent', + workspaceId, + options: { + fieldName: 'location', + type: FieldMetadataType.TEXT, + label: 'Location', + description: 'Location', + icon: 'IconMapPin', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + iCalUID: createStandardFieldFlatMetadata({ + objectName: 'calendarEvent', + workspaceId, + options: { + fieldName: 'iCalUID', + type: FieldMetadataType.TEXT, + label: 'iCal UID', + description: 'iCal UID', + icon: 'IconKey', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + conferenceSolution: createStandardFieldFlatMetadata({ + objectName: 'calendarEvent', + workspaceId, + options: { + fieldName: 'conferenceSolution', + type: FieldMetadataType.TEXT, + label: 'Conference Solution', + description: 'Conference Solution', + icon: 'IconScreenShare', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + conferenceLink: createStandardFieldFlatMetadata({ + objectName: 'calendarEvent', + workspaceId, + options: { + fieldName: 'conferenceLink', + type: FieldMetadataType.LINKS, + label: 'Meet Link', + description: 'Meet Link', + icon: 'IconLink', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + calendarChannelEventAssociations: createStandardRelationFieldFlatMetadata({ + objectName: 'calendarEvent', + workspaceId, + options: { + fieldName: 'calendarChannelEventAssociations', + label: 'Calendar Channel Event Associations', + description: 'Calendar Channel Event Associations', + icon: 'IconCalendar', + isNullable: false, + createdAt, + targetObjectName: 'calendarChannelEventAssociation', + targetFieldName: 'calendarEvent', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + calendarEventParticipants: createStandardRelationFieldFlatMetadata({ + objectName: 'calendarEvent', + workspaceId, + options: { + fieldName: 'calendarEventParticipants', + label: 'Event Participants', + description: 'Event Participants', + icon: 'IconUserCircle', + isNullable: false, + createdAt, + targetObjectName: 'calendarEventParticipant', + targetFieldName: 'calendarEvent', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-company-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-company-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..34076976141 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-company-standard-flat-field-metadata.util.ts @@ -0,0 +1,433 @@ +import { + FieldMetadataType, + RelationOnDeleteAction, + RelationType, +} from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildCompanyStandardFlatFieldMetadatas = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): Record, FlatFieldMetadata> => ({ + // Base fields from BaseWorkspaceEntity + id: createStandardFieldFlatMetadata({ + objectName: 'company', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'company', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { + displayFormat: 'RELATIVE', + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'company', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { + displayFormat: 'RELATIVE', + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'company', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { + displayFormat: 'RELATIVE', + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + + // Company-specific fields + name: createStandardFieldFlatMetadata({ + objectName: 'company', + workspaceId, + options: { + fieldName: 'name', + type: FieldMetadataType.TEXT, + label: 'Name', + description: 'The company name', + icon: 'IconBuildingSkyscraper', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + domainName: createStandardFieldFlatMetadata({ + objectName: 'company', + workspaceId, + options: { + fieldName: 'domainName', + type: FieldMetadataType.LINKS, + label: 'Domain Name', + description: + 'The company website URL. We use this url to fetch the company icon', + icon: 'IconLink', + isNullable: true, + isUnique: true, + settings: { + maxNumberOfValues: 1, + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + address: createStandardFieldFlatMetadata({ + objectName: 'company', + workspaceId, + options: { + fieldName: 'address', + type: FieldMetadataType.ADDRESS, + label: 'Address', + description: 'Address of the company', + icon: 'IconMap', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + addressOld: createStandardFieldFlatMetadata({ + objectName: 'company', + workspaceId, + options: { + fieldName: 'addressOld', + type: FieldMetadataType.TEXT, + label: 'Address (deprecated)', + description: + 'Address of the company - deprecated in favor of new address field', + icon: 'IconMap', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + employees: createStandardFieldFlatMetadata({ + objectName: 'company', + workspaceId, + options: { + fieldName: 'employees', + type: FieldMetadataType.NUMBER, + label: 'Employees', + description: 'Number of employees in the company', + icon: 'IconUsers', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + linkedinLink: createStandardFieldFlatMetadata({ + objectName: 'company', + workspaceId, + options: { + fieldName: 'linkedinLink', + type: FieldMetadataType.LINKS, + label: 'Linkedin', + description: 'The company Linkedin account', + icon: 'IconBrandLinkedin', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + xLink: createStandardFieldFlatMetadata({ + objectName: 'company', + workspaceId, + options: { + fieldName: 'xLink', + type: FieldMetadataType.LINKS, + label: 'X', + description: 'The company Twitter/X account', + icon: 'IconBrandX', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + annualRecurringRevenue: createStandardFieldFlatMetadata({ + objectName: 'company', + workspaceId, + options: { + fieldName: 'annualRecurringRevenue', + type: FieldMetadataType.CURRENCY, + label: 'ARR', + description: + 'Annual Recurring Revenue: The actual or estimated annual revenue of the company', + icon: 'IconMoneybag', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + idealCustomerProfile: createStandardFieldFlatMetadata({ + objectName: 'company', + workspaceId, + options: { + fieldName: 'idealCustomerProfile', + type: FieldMetadataType.BOOLEAN, + label: 'ICP', + description: + 'Ideal Customer Profile: Indicates whether the company is the most suitable and valuable customer for you', + icon: 'IconTarget', + isNullable: false, + defaultValue: false, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + position: createStandardFieldFlatMetadata({ + objectName: 'company', + workspaceId, + options: { + fieldName: 'position', + type: FieldMetadataType.POSITION, + label: 'Position', + description: 'Company record position', + icon: 'IconHierarchy2', + isSystem: true, + isNullable: false, + defaultValue: 0, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdBy: createStandardFieldFlatMetadata({ + objectName: 'company', + workspaceId, + options: { + fieldName: 'createdBy', + type: FieldMetadataType.ACTOR, + label: 'Created by', + description: 'The creator of the record', + icon: 'IconCreativeCommonsSa', + isUIReadOnly: true, + isNullable: false, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + searchVector: createStandardFieldFlatMetadata({ + objectName: 'company', + workspaceId, + options: { + fieldName: 'searchVector', + type: FieldMetadataType.TS_VECTOR, + label: 'Search vector', + description: 'Field used for full-text search', + icon: 'IconUser', + isSystem: true, + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + + // Relation fields + people: createStandardRelationFieldFlatMetadata({ + objectName: 'company', + workspaceId, + options: { + fieldName: 'people', + label: 'People', + description: 'People linked to the company.', + icon: 'IconUsers', + isNullable: true, + createdAt, + targetObjectName: 'person', + targetFieldName: 'company', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + accountOwner: createStandardRelationFieldFlatMetadata({ + objectName: 'company', + workspaceId, + options: { + fieldName: 'accountOwner', + label: 'Account Owner', + description: + 'Your team member responsible for managing the company account', + icon: 'IconUserCircle', + isNullable: true, + createdAt, + targetObjectName: 'workspaceMember', + targetFieldName: 'accountOwnerForCompanies', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.SET_NULL, + joinColumnName: 'accountOwnerId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + taskTargets: createStandardRelationFieldFlatMetadata({ + objectName: 'company', + workspaceId, + options: { + fieldName: 'taskTargets', + label: 'Tasks', + description: 'Tasks tied to the company', + icon: 'IconCheckbox', + isUIReadOnly: true, + isNullable: true, + createdAt, + targetObjectName: 'taskTarget', + targetFieldName: 'company', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + noteTargets: createStandardRelationFieldFlatMetadata({ + objectName: 'company', + workspaceId, + options: { + fieldName: 'noteTargets', + label: 'Notes', + description: 'Notes tied to the company', + icon: 'IconNotes', + isUIReadOnly: true, + isNullable: true, + createdAt, + targetObjectName: 'noteTarget', + targetFieldName: 'company', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + opportunities: createStandardRelationFieldFlatMetadata({ + objectName: 'company', + workspaceId, + options: { + fieldName: 'opportunities', + label: 'Opportunities', + description: 'Opportunities linked to the company.', + icon: 'IconTargetArrow', + isNullable: true, + createdAt, + targetObjectName: 'opportunity', + targetFieldName: 'company', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + favorites: createStandardRelationFieldFlatMetadata({ + objectName: 'company', + workspaceId, + options: { + fieldName: 'favorites', + label: 'Favorites', + description: 'Favorites linked to the company', + icon: 'IconHeart', + isSystem: true, + isNullable: true, + createdAt, + targetObjectName: 'favorite', + targetFieldName: 'company', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + attachments: createStandardRelationFieldFlatMetadata({ + objectName: 'company', + workspaceId, + options: { + fieldName: 'attachments', + label: 'Attachments', + description: 'Attachments linked to the company', + icon: 'IconFileImport', + isSystem: true, + isNullable: true, + createdAt, + targetObjectName: 'attachment', + targetFieldName: 'company', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + timelineActivities: createStandardRelationFieldFlatMetadata({ + objectName: 'company', + workspaceId, + options: { + fieldName: 'timelineActivities', + label: 'Timeline Activities', + description: 'Timeline Activities linked to the company', + icon: 'IconIconTimelineEvent', + isSystem: true, + isNullable: true, + createdAt, + targetObjectName: 'timelineActivity', + targetFieldName: 'company', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-connected-account-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-connected-account-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..609d9a8b058 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-connected-account-standard-flat-field-metadata.util.ts @@ -0,0 +1,289 @@ +import { + FieldMetadataType, + RelationOnDeleteAction, + RelationType, +} from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildConnectedAccountStandardFlatFieldMetadatas = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): Record< + AllStandardObjectFieldName<'connectedAccount'>, + FlatFieldMetadata +> => ({ + id: createStandardFieldFlatMetadata({ + objectName: 'connectedAccount', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'connectedAccount', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'connectedAccount', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'connectedAccount', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + handle: createStandardFieldFlatMetadata({ + objectName: 'connectedAccount', + workspaceId, + options: { + fieldName: 'handle', + type: FieldMetadataType.TEXT, + label: 'handle', + description: 'The account handle (email, username, phone number, etc.)', + icon: 'IconMail', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + provider: createStandardFieldFlatMetadata({ + objectName: 'connectedAccount', + workspaceId, + options: { + fieldName: 'provider', + type: FieldMetadataType.TEXT, + label: 'provider', + description: 'The account provider', + icon: 'IconSettings', + isNullable: false, + defaultValue: "'google'", + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + accessToken: createStandardFieldFlatMetadata({ + objectName: 'connectedAccount', + workspaceId, + options: { + fieldName: 'accessToken', + type: FieldMetadataType.TEXT, + label: 'Access Token', + description: 'Messaging provider access token', + icon: 'IconKey', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + refreshToken: createStandardFieldFlatMetadata({ + objectName: 'connectedAccount', + workspaceId, + options: { + fieldName: 'refreshToken', + type: FieldMetadataType.TEXT, + label: 'Refresh Token', + description: 'Messaging provider refresh token', + icon: 'IconKey', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + lastSyncHistoryId: createStandardFieldFlatMetadata({ + objectName: 'connectedAccount', + workspaceId, + options: { + fieldName: 'lastSyncHistoryId', + type: FieldMetadataType.TEXT, + label: 'Last sync history ID', + description: 'Last sync history ID', + icon: 'IconHistory', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + authFailedAt: createStandardFieldFlatMetadata({ + objectName: 'connectedAccount', + workspaceId, + options: { + fieldName: 'authFailedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Auth failed at', + description: 'Auth failed at', + icon: 'IconX', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + lastCredentialsRefreshedAt: createStandardFieldFlatMetadata({ + objectName: 'connectedAccount', + workspaceId, + options: { + fieldName: 'lastCredentialsRefreshedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last credentials refreshed at', + description: 'Last credentials refreshed at', + icon: 'IconHistory', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + handleAliases: createStandardFieldFlatMetadata({ + objectName: 'connectedAccount', + workspaceId, + options: { + fieldName: 'handleAliases', + type: FieldMetadataType.TEXT, + label: 'Handle Aliases', + description: 'Handle Aliases', + icon: 'IconMail', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + scopes: createStandardFieldFlatMetadata({ + objectName: 'connectedAccount', + workspaceId, + options: { + fieldName: 'scopes', + type: FieldMetadataType.ARRAY, + label: 'Scopes', + description: 'Scopes', + icon: 'IconSettings', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + connectionParameters: createStandardFieldFlatMetadata({ + objectName: 'connectedAccount', + workspaceId, + options: { + fieldName: 'connectionParameters', + type: FieldMetadataType.RAW_JSON, + label: 'Custom Connection Parameters', + description: 'JSON object containing custom connection parameters', + icon: 'IconSettings', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + accountOwner: createStandardRelationFieldFlatMetadata({ + objectName: 'connectedAccount', + workspaceId, + options: { + fieldName: 'accountOwner', + label: 'Account Owner', + description: 'Account Owner', + icon: 'IconUserCircle', + isNullable: false, + createdAt, + targetObjectName: 'workspaceMember', + targetFieldName: 'connectedAccounts', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'accountOwnerId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + messageChannels: createStandardRelationFieldFlatMetadata({ + objectName: 'connectedAccount', + workspaceId, + options: { + fieldName: 'messageChannels', + label: 'Message Channels', + description: 'Message Channels', + icon: 'IconMessage', + isNullable: false, + createdAt, + targetObjectName: 'messageChannel', + targetFieldName: 'connectedAccount', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + calendarChannels: createStandardRelationFieldFlatMetadata({ + objectName: 'connectedAccount', + workspaceId, + options: { + fieldName: 'calendarChannels', + label: 'Calendar Channels', + description: 'Calendar Channels', + icon: 'IconCalendar', + isNullable: false, + createdAt, + targetObjectName: 'calendarChannel', + targetFieldName: 'connectedAccount', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-dashboard-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-dashboard-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..8e52f9320f1 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-dashboard-standard-flat-field-metadata.util.ts @@ -0,0 +1,222 @@ +import { FieldMetadataType, RelationType } from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildDashboardStandardFlatFieldMetadatas = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): Record, FlatFieldMetadata> => ({ + // Base fields from BaseWorkspaceEntity + id: createStandardFieldFlatMetadata({ + objectName: 'dashboard', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'dashboard', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'dashboard', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'dashboard', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + + // Dashboard-specific fields + title: createStandardFieldFlatMetadata({ + objectName: 'dashboard', + workspaceId, + options: { + fieldName: 'title', + type: FieldMetadataType.TEXT, + label: 'Title', + description: 'Dashboard title', + icon: 'IconNotes', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + position: createStandardFieldFlatMetadata({ + objectName: 'dashboard', + workspaceId, + options: { + fieldName: 'position', + type: FieldMetadataType.POSITION, + label: 'Position', + description: 'Dashboard record Position', + icon: 'IconHierarchy2', + isSystem: true, + isNullable: false, + defaultValue: 0, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + pageLayoutId: createStandardFieldFlatMetadata({ + objectName: 'dashboard', + workspaceId, + options: { + fieldName: 'pageLayoutId', + type: FieldMetadataType.UUID, + label: 'Page Layout ID', + description: 'Dashboard page layout', + icon: 'IconLayout', + isNullable: true, + isUIReadOnly: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdBy: createStandardFieldFlatMetadata({ + objectName: 'dashboard', + workspaceId, + options: { + fieldName: 'createdBy', + type: FieldMetadataType.ACTOR, + label: 'Created by', + description: 'The creator of the record', + icon: 'IconCreativeCommonsSa', + isUIReadOnly: true, + isNullable: false, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + searchVector: createStandardFieldFlatMetadata({ + objectName: 'dashboard', + workspaceId, + options: { + fieldName: 'searchVector', + type: FieldMetadataType.TS_VECTOR, + label: 'Search vector', + description: 'Field used for full-text search', + icon: 'IconUser', + isSystem: true, + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + + // Relation fields + timelineActivities: createStandardRelationFieldFlatMetadata({ + objectName: 'dashboard', + workspaceId, + options: { + fieldName: 'timelineActivities', + label: 'Timeline Activities', + description: 'Timeline activities linked to the dashboard', + icon: 'IconTimelineEvent', + isSystem: true, + isNullable: true, + createdAt, + targetObjectName: 'timelineActivity', + targetFieldName: 'dashboard', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + favorites: createStandardRelationFieldFlatMetadata({ + objectName: 'dashboard', + workspaceId, + options: { + fieldName: 'favorites', + label: 'Favorites', + description: 'Favorites linked to the dashboard', + icon: 'IconHeart', + isSystem: true, + isNullable: false, + createdAt, + targetObjectName: 'favorite', + targetFieldName: 'dashboard', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + attachments: createStandardRelationFieldFlatMetadata({ + objectName: 'dashboard', + workspaceId, + options: { + fieldName: 'attachments', + label: 'Attachments', + description: 'Attachments linked to the dashboard', + icon: 'IconFileImport', + isSystem: true, + isNullable: true, + createdAt, + targetObjectName: 'attachment', + targetFieldName: 'dashboard', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-favorite-folder-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-favorite-folder-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..a57d51ff1ec --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-favorite-folder-standard-flat-field-metadata.util.ts @@ -0,0 +1,141 @@ +import { FieldMetadataType, RelationType } from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildFavoriteFolderStandardFlatFieldMetadatas = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): Record< + AllStandardObjectFieldName<'favoriteFolder'>, + FlatFieldMetadata +> => ({ + // Base fields from BaseWorkspaceEntity + id: createStandardFieldFlatMetadata({ + objectName: 'favoriteFolder', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'favoriteFolder', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'favoriteFolder', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'favoriteFolder', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + + // FavoriteFolder-specific fields + position: createStandardFieldFlatMetadata({ + objectName: 'favoriteFolder', + workspaceId, + options: { + fieldName: 'position', + type: FieldMetadataType.NUMBER, + label: 'Position', + description: 'Favorite folder position', + icon: 'IconList', + isSystem: true, + isNullable: false, + defaultValue: 0, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + name: createStandardFieldFlatMetadata({ + objectName: 'favoriteFolder', + workspaceId, + options: { + fieldName: 'name', + type: FieldMetadataType.TEXT, + label: 'Name', + description: 'Name of the favorite folder', + icon: 'IconText', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + + // Relation fields + favorites: createStandardRelationFieldFlatMetadata({ + objectName: 'favoriteFolder', + workspaceId, + options: { + fieldName: 'favorites', + label: 'Favorites', + description: 'Favorites in this folder', + icon: 'IconHeart', + isNullable: false, + createdAt, + targetObjectName: 'favorite', + targetFieldName: 'favoriteFolder', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-favorite-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-favorite-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..2f7d90b4177 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-favorite-standard-flat-field-metadata.util.ts @@ -0,0 +1,364 @@ +import { + FieldMetadataType, + RelationOnDeleteAction, + RelationType, +} from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildFavoriteStandardFlatFieldMetadatas = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): Record, FlatFieldMetadata> => ({ + // Base fields from BaseWorkspaceEntity + id: createStandardFieldFlatMetadata({ + objectName: 'favorite', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'favorite', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'favorite', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'favorite', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + + // Favorite-specific fields + position: createStandardFieldFlatMetadata({ + objectName: 'favorite', + workspaceId, + options: { + fieldName: 'position', + type: FieldMetadataType.NUMBER, + label: 'Position', + description: 'Favorite position', + icon: 'IconList', + isSystem: true, + isNullable: false, + defaultValue: 0, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + view: createStandardFieldFlatMetadata({ + objectName: 'favorite', + workspaceId, + options: { + fieldName: 'view', + type: FieldMetadataType.UUID, + label: 'ViewId', + description: 'ViewId', + icon: 'IconView', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + + // Relation fields + forWorkspaceMember: createStandardRelationFieldFlatMetadata({ + objectName: 'favorite', + workspaceId, + options: { + fieldName: 'forWorkspaceMember', + label: 'Workspace Member', + description: 'Favorite workspace member', + icon: 'IconCircleUser', + isNullable: true, + createdAt, + targetObjectName: 'workspaceMember', + targetFieldName: 'favorites', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'forWorkspaceMemberId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + person: createStandardRelationFieldFlatMetadata({ + objectName: 'favorite', + workspaceId, + options: { + fieldName: 'person', + label: 'Person', + description: 'Favorite person', + icon: 'IconUser', + isNullable: true, + createdAt, + targetObjectName: 'person', + targetFieldName: 'favorites', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'personId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + company: createStandardRelationFieldFlatMetadata({ + objectName: 'favorite', + workspaceId, + options: { + fieldName: 'company', + label: 'Company', + description: 'Favorite company', + icon: 'IconBuildingSkyscraper', + isNullable: true, + createdAt, + targetObjectName: 'company', + targetFieldName: 'favorites', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'companyId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + opportunity: createStandardRelationFieldFlatMetadata({ + objectName: 'favorite', + workspaceId, + options: { + fieldName: 'opportunity', + label: 'Opportunity', + description: 'Favorite opportunity', + icon: 'IconTargetArrow', + isNullable: true, + createdAt, + targetObjectName: 'opportunity', + targetFieldName: 'favorites', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'opportunityId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + workflow: createStandardRelationFieldFlatMetadata({ + objectName: 'favorite', + workspaceId, + options: { + fieldName: 'workflow', + label: 'Workflow', + description: 'Favorite workflow', + icon: 'IconSettingsAutomation', + isNullable: true, + createdAt, + targetObjectName: 'workflow', + targetFieldName: 'favorites', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'workflowId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + workflowVersion: createStandardRelationFieldFlatMetadata({ + objectName: 'favorite', + workspaceId, + options: { + fieldName: 'workflowVersion', + label: 'Workflow', + description: 'Favorite workflow version', + icon: 'IconSettingsAutomation', + isNullable: true, + createdAt, + targetObjectName: 'workflowVersion', + targetFieldName: 'favorites', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'workflowVersionId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + workflowRun: createStandardRelationFieldFlatMetadata({ + objectName: 'favorite', + workspaceId, + options: { + fieldName: 'workflowRun', + label: 'Workflow', + description: 'Favorite workflow run', + icon: 'IconSettingsAutomation', + isNullable: true, + createdAt, + targetObjectName: 'workflowRun', + targetFieldName: 'favorites', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'workflowRunId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + task: createStandardRelationFieldFlatMetadata({ + objectName: 'favorite', + workspaceId, + options: { + fieldName: 'task', + label: 'Task', + description: 'Favorite task', + icon: 'IconCheckbox', + isNullable: true, + createdAt, + targetObjectName: 'task', + targetFieldName: 'favorites', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'taskId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + note: createStandardRelationFieldFlatMetadata({ + objectName: 'favorite', + workspaceId, + options: { + fieldName: 'note', + label: 'Note', + description: 'Favorite note', + icon: 'IconNotes', + isNullable: true, + createdAt, + targetObjectName: 'note', + targetFieldName: 'favorites', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'noteId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + dashboard: createStandardRelationFieldFlatMetadata({ + objectName: 'favorite', + workspaceId, + options: { + fieldName: 'dashboard', + label: 'Dashboard', + description: 'Favorite dashboard', + icon: 'IconLayoutDashboard', + isNullable: true, + createdAt, + targetObjectName: 'dashboard', + targetFieldName: 'favorites', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'dashboardId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + favoriteFolder: createStandardRelationFieldFlatMetadata({ + objectName: 'favorite', + workspaceId, + options: { + fieldName: 'favoriteFolder', + label: 'Favorite Folder', + description: 'The folder this favorite belongs to', + icon: 'IconFolder', + isNullable: true, + createdAt, + targetObjectName: 'favoriteFolder', + targetFieldName: 'favorites', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.SET_NULL, + joinColumnName: 'favoriteFolderId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + custom: createStandardRelationFieldFlatMetadata({ + objectName: 'favorite', + workspaceId, + options: { + fieldName: 'custom', + label: 'Custom', + description: 'Favorite custom object', + icon: 'IconHeart', + isNullable: true, + createdAt, + targetObjectName: 'note', + targetFieldName: 'favorites', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'customId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-message-channel-message-association-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-message-channel-message-association-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..065b7fc882e --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-message-channel-message-association-standard-flat-field-metadata.util.ts @@ -0,0 +1,200 @@ +import { + FieldMetadataType, + RelationOnDeleteAction, + RelationType, +} from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildMessageChannelMessageAssociationStandardFlatFieldMetadatas = + ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, + }: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; + }): Record< + AllStandardObjectFieldName<'messageChannelMessageAssociation'>, + FlatFieldMetadata + > => ({ + id: createStandardFieldFlatMetadata({ + objectName: 'messageChannelMessageAssociation', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'messageChannelMessageAssociation', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'messageChannelMessageAssociation', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'messageChannelMessageAssociation', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + messageExternalId: createStandardFieldFlatMetadata({ + objectName: 'messageChannelMessageAssociation', + workspaceId, + options: { + fieldName: 'messageExternalId', + type: FieldMetadataType.TEXT, + label: 'Message External Id', + description: 'Message id from the messaging provider', + icon: 'IconHash', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + messageThreadExternalId: createStandardFieldFlatMetadata({ + objectName: 'messageChannelMessageAssociation', + workspaceId, + options: { + fieldName: 'messageThreadExternalId', + type: FieldMetadataType.TEXT, + label: 'Thread External Id', + description: 'Thread id from the messaging provider', + icon: 'IconHash', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + direction: createStandardFieldFlatMetadata({ + objectName: 'messageChannelMessageAssociation', + workspaceId, + options: { + fieldName: 'direction', + type: FieldMetadataType.SELECT, + label: 'Direction', + description: 'Message Direction', + icon: 'IconDirection', + isNullable: false, + defaultValue: "'incoming'", + options: [ + { value: 'incoming', label: 'Incoming', position: 0, color: 'green' }, + { value: 'outgoing', label: 'Outgoing', position: 1, color: 'blue' }, + ], + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + messageChannel: createStandardRelationFieldFlatMetadata({ + objectName: 'messageChannelMessageAssociation', + workspaceId, + options: { + fieldName: 'messageChannel', + label: 'Message Channel Id', + description: 'Message Channel Id', + icon: 'IconHash', + isNullable: true, + createdAt, + targetObjectName: 'messageChannel', + targetFieldName: 'messageChannelMessageAssociations', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'messageChannelId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + messageThread: createStandardRelationFieldFlatMetadata({ + objectName: 'messageChannelMessageAssociation', + workspaceId, + options: { + fieldName: 'messageThread', + label: 'Message Thread Id', + description: 'Message Thread Id', + icon: 'IconHash', + isNullable: true, + createdAt, + targetObjectName: 'messageThread', + targetFieldName: 'messageChannelMessageAssociations', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'messageThreadId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + message: createStandardRelationFieldFlatMetadata({ + objectName: 'messageChannelMessageAssociation', + workspaceId, + options: { + fieldName: 'message', + label: 'Message Id', + description: 'Message Id', + icon: 'IconHash', + isNullable: true, + createdAt, + targetObjectName: 'message', + targetFieldName: 'messageChannelMessageAssociations', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'messageId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + }); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-message-channel-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-message-channel-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..f9e638577bc --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-message-channel-standard-flat-field-metadata.util.ts @@ -0,0 +1,504 @@ +import { + FieldMetadataType, + RelationOnDeleteAction, + RelationType, +} from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildMessageChannelStandardFlatFieldMetadatas = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): Record< + AllStandardObjectFieldName<'messageChannel'>, + FlatFieldMetadata +> => ({ + id: createStandardFieldFlatMetadata({ + objectName: 'messageChannel', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'messageChannel', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'messageChannel', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'messageChannel', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + visibility: createStandardFieldFlatMetadata({ + objectName: 'messageChannel', + workspaceId, + options: { + fieldName: 'visibility', + type: FieldMetadataType.SELECT, + label: 'Visibility', + description: 'Visibility', + icon: 'IconEyeglass', + isNullable: false, + defaultValue: "'SHARE_EVERYTHING'", + options: [ + { value: 'METADATA', label: 'Metadata', position: 0, color: 'green' }, + { value: 'SUBJECT', label: 'Subject', position: 1, color: 'blue' }, + { + value: 'SHARE_EVERYTHING', + label: 'Share Everything', + position: 2, + color: 'orange', + }, + ], + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + handle: createStandardFieldFlatMetadata({ + objectName: 'messageChannel', + workspaceId, + options: { + fieldName: 'handle', + type: FieldMetadataType.TEXT, + label: 'Handle', + description: 'Handle', + icon: 'IconAt', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + type: createStandardFieldFlatMetadata({ + objectName: 'messageChannel', + workspaceId, + options: { + fieldName: 'type', + type: FieldMetadataType.SELECT, + label: 'Type', + description: 'Channel Type', + icon: 'IconMessage', + isNullable: false, + defaultValue: "'email'", + options: [ + { value: 'email', label: 'Email', position: 0, color: 'green' }, + { value: 'sms', label: 'SMS', position: 1, color: 'blue' }, + ], + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + isContactAutoCreationEnabled: createStandardFieldFlatMetadata({ + objectName: 'messageChannel', + workspaceId, + options: { + fieldName: 'isContactAutoCreationEnabled', + type: FieldMetadataType.BOOLEAN, + label: 'Is Contact Auto Creation Enabled', + description: 'Is Contact Auto Creation Enabled', + icon: 'IconUserCircle', + isNullable: false, + defaultValue: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + contactAutoCreationPolicy: createStandardFieldFlatMetadata({ + objectName: 'messageChannel', + workspaceId, + options: { + fieldName: 'contactAutoCreationPolicy', + type: FieldMetadataType.SELECT, + label: 'Contact auto creation policy', + description: + 'Automatically create People records when receiving or sending emails', + icon: 'IconUserCircle', + isNullable: false, + defaultValue: "'SENT'", + options: [ + { + value: 'SENT_AND_RECEIVED', + label: 'Sent and Received', + position: 0, + color: 'green', + }, + { value: 'SENT', label: 'Sent', position: 1, color: 'blue' }, + { value: 'NONE', label: 'None', position: 2, color: 'red' }, + ], + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + messageFolderImportPolicy: createStandardFieldFlatMetadata({ + objectName: 'messageChannel', + workspaceId, + options: { + fieldName: 'messageFolderImportPolicy', + type: FieldMetadataType.SELECT, + label: 'Message folder import policy', + description: 'Message folder import policy', + icon: 'IconFolder', + isNullable: false, + defaultValue: "'ALL_FOLDERS'", + options: [ + { + value: 'ALL_FOLDERS', + label: 'All folders', + position: 0, + color: 'green', + }, + { + value: 'SELECTED_FOLDERS', + label: 'Selected folders', + position: 1, + color: 'blue', + }, + ], + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + excludeNonProfessionalEmails: createStandardFieldFlatMetadata({ + objectName: 'messageChannel', + workspaceId, + options: { + fieldName: 'excludeNonProfessionalEmails', + type: FieldMetadataType.BOOLEAN, + label: 'Exclude non professional emails', + description: 'Exclude non professional emails', + icon: 'IconBriefcase', + isNullable: false, + defaultValue: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + excludeGroupEmails: createStandardFieldFlatMetadata({ + objectName: 'messageChannel', + workspaceId, + options: { + fieldName: 'excludeGroupEmails', + type: FieldMetadataType.BOOLEAN, + label: 'Exclude group emails', + description: 'Exclude group emails', + icon: 'IconUsersGroup', + isNullable: false, + defaultValue: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + pendingGroupEmailsAction: createStandardFieldFlatMetadata({ + objectName: 'messageChannel', + workspaceId, + options: { + fieldName: 'pendingGroupEmailsAction', + type: FieldMetadataType.SELECT, + label: 'Pending group emails action', + description: 'Pending action for group emails', + icon: 'IconUsersGroup', + isNullable: false, + defaultValue: "'NONE'", + options: [ + { + value: 'GROUP_EMAILS_DELETION', + label: 'Group emails deletion', + position: 0, + color: 'red', + }, + { + value: 'GROUP_EMAILS_IMPORT', + label: 'Group emails import', + position: 1, + color: 'green', + }, + { value: 'NONE', label: 'None', position: 2, color: 'blue' }, + ], + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + isSyncEnabled: createStandardFieldFlatMetadata({ + objectName: 'messageChannel', + workspaceId, + options: { + fieldName: 'isSyncEnabled', + type: FieldMetadataType.BOOLEAN, + label: 'Is Sync Enabled', + description: 'Is Sync Enabled', + icon: 'IconRefresh', + isNullable: false, + defaultValue: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + syncCursor: createStandardFieldFlatMetadata({ + objectName: 'messageChannel', + workspaceId, + options: { + fieldName: 'syncCursor', + type: FieldMetadataType.TEXT, + label: 'Last sync cursor', + description: 'Last sync cursor', + icon: 'IconHistory', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + syncedAt: createStandardFieldFlatMetadata({ + objectName: 'messageChannel', + workspaceId, + options: { + fieldName: 'syncedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last sync date', + description: 'Last sync date', + icon: 'IconHistory', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + syncStatus: createStandardFieldFlatMetadata({ + objectName: 'messageChannel', + workspaceId, + options: { + fieldName: 'syncStatus', + type: FieldMetadataType.SELECT, + label: 'Sync status', + description: 'Sync status', + icon: 'IconStatusChange', + isNullable: true, + options: [ + { value: 'ONGOING', label: 'Ongoing', position: 1, color: 'yellow' }, + { + value: 'NOT_SYNCED', + label: 'Not Synced', + position: 2, + color: 'blue', + }, + { value: 'ACTIVE', label: 'Active', position: 3, color: 'green' }, + { + value: 'FAILED_INSUFFICIENT_PERMISSIONS', + label: 'Failed Insufficient Permissions', + position: 4, + color: 'red', + }, + { + value: 'FAILED_UNKNOWN', + label: 'Failed Unknown', + position: 5, + color: 'red', + }, + ], + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + syncStage: createStandardFieldFlatMetadata({ + objectName: 'messageChannel', + workspaceId, + options: { + fieldName: 'syncStage', + type: FieldMetadataType.SELECT, + label: 'Sync stage', + description: 'Sync stage', + icon: 'IconStatusChange', + isNullable: false, + defaultValue: "'PENDING_CONFIGURATION'", + options: [ + { + value: 'MESSAGE_LIST_FETCH_PENDING', + label: 'Messages list fetch pending', + position: 0, + color: 'blue', + }, + { + value: 'MESSAGE_LIST_FETCH_SCHEDULED', + label: 'Messages list fetch scheduled', + position: 1, + color: 'green', + }, + { + value: 'MESSAGE_LIST_FETCH_ONGOING', + label: 'Messages list fetch ongoing', + position: 2, + color: 'orange', + }, + { + value: 'MESSAGES_IMPORT_PENDING', + label: 'Messages import pending', + position: 3, + color: 'blue', + }, + { + value: 'MESSAGES_IMPORT_SCHEDULED', + label: 'Messages import scheduled', + position: 4, + color: 'green', + }, + { + value: 'MESSAGES_IMPORT_ONGOING', + label: 'Messages import ongoing', + position: 5, + color: 'orange', + }, + { value: 'FAILED', label: 'Failed', position: 6, color: 'red' }, + { + value: 'PENDING_CONFIGURATION', + label: 'Pending configuration', + position: 7, + color: 'gray', + }, + ], + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + syncStageStartedAt: createStandardFieldFlatMetadata({ + objectName: 'messageChannel', + workspaceId, + options: { + fieldName: 'syncStageStartedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Sync stage started at', + description: 'Sync stage started at', + icon: 'IconHistory', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + throttleFailureCount: createStandardFieldFlatMetadata({ + objectName: 'messageChannel', + workspaceId, + options: { + fieldName: 'throttleFailureCount', + type: FieldMetadataType.NUMBER, + label: 'Throttle Failure Count', + description: 'Throttle Failure Count', + icon: 'IconX', + isNullable: false, + defaultValue: 0, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + connectedAccount: createStandardRelationFieldFlatMetadata({ + objectName: 'messageChannel', + workspaceId, + options: { + fieldName: 'connectedAccount', + label: 'Connected Account', + description: 'Connected Account', + icon: 'IconUserCircle', + isNullable: false, + createdAt, + targetObjectName: 'connectedAccount', + targetFieldName: 'messageChannels', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'connectedAccountId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + messageChannelMessageAssociations: createStandardRelationFieldFlatMetadata({ + objectName: 'messageChannel', + workspaceId, + options: { + fieldName: 'messageChannelMessageAssociations', + label: 'Message Channel Association', + description: 'Messages from the channel.', + icon: 'IconMessage', + isNullable: true, + createdAt, + targetObjectName: 'messageChannelMessageAssociation', + targetFieldName: 'messageChannel', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + messageFolders: createStandardRelationFieldFlatMetadata({ + objectName: 'messageChannel', + workspaceId, + options: { + fieldName: 'messageFolders', + label: 'Message Folders', + description: 'Message Folders', + icon: 'IconFolder', + isNullable: true, + createdAt, + targetObjectName: 'messageFolder', + targetFieldName: 'messageChannel', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-message-folder-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-message-folder-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..cd9df8f5247 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-message-folder-standard-flat-field-metadata.util.ts @@ -0,0 +1,219 @@ +import { + FieldMetadataType, + RelationOnDeleteAction, + RelationType, +} from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildMessageFolderStandardFlatFieldMetadatas = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): Record, FlatFieldMetadata> => ({ + id: createStandardFieldFlatMetadata({ + objectName: 'messageFolder', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'messageFolder', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'messageFolder', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'messageFolder', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + name: createStandardFieldFlatMetadata({ + objectName: 'messageFolder', + workspaceId, + options: { + fieldName: 'name', + type: FieldMetadataType.TEXT, + label: 'Name', + description: 'Folder name', + icon: 'IconFolder', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + syncCursor: createStandardFieldFlatMetadata({ + objectName: 'messageFolder', + workspaceId, + options: { + fieldName: 'syncCursor', + type: FieldMetadataType.TEXT, + label: 'Sync Cursor', + description: 'Sync Cursor', + icon: 'IconHash', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + isSentFolder: createStandardFieldFlatMetadata({ + objectName: 'messageFolder', + workspaceId, + options: { + fieldName: 'isSentFolder', + type: FieldMetadataType.BOOLEAN, + label: 'Is Sent Folder', + description: 'Is Sent Folder', + icon: 'IconCheck', + isNullable: false, + defaultValue: false, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + isSynced: createStandardFieldFlatMetadata({ + objectName: 'messageFolder', + workspaceId, + options: { + fieldName: 'isSynced', + type: FieldMetadataType.BOOLEAN, + label: 'Is Synced', + description: 'Is Synced', + icon: 'IconCheck', + isNullable: false, + defaultValue: false, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + parentFolderId: createStandardFieldFlatMetadata({ + objectName: 'messageFolder', + workspaceId, + options: { + fieldName: 'parentFolderId', + type: FieldMetadataType.TEXT, + label: 'Parent Folder ID', + description: 'Parent Folder ID', + icon: 'IconFolder', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + externalId: createStandardFieldFlatMetadata({ + objectName: 'messageFolder', + workspaceId, + options: { + fieldName: 'externalId', + type: FieldMetadataType.TEXT, + label: 'External ID', + description: 'External ID', + icon: 'IconHash', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + pendingSyncAction: createStandardFieldFlatMetadata({ + objectName: 'messageFolder', + workspaceId, + options: { + fieldName: 'pendingSyncAction', + type: FieldMetadataType.SELECT, + label: 'Pending Sync Action', + description: 'Pending action for folder sync', + icon: 'IconReload', + isNullable: false, + defaultValue: "'NONE'", + options: [ + { + value: 'FOLDER_DELETION', + label: 'Folder deletion', + position: 0, + color: 'red', + }, + { value: 'NONE', label: 'None', position: 1, color: 'blue' }, + ], + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + messageChannel: createStandardRelationFieldFlatMetadata({ + objectName: 'messageFolder', + workspaceId, + options: { + fieldName: 'messageChannel', + label: 'Message Channel', + description: 'Message Channel', + icon: 'IconMessage', + isNullable: false, + createdAt, + targetObjectName: 'messageChannel', + targetFieldName: 'messageFolders', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'messageChannelId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-message-participant-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-message-participant-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..83ebc1671f8 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-message-participant-standard-flat-field-metadata.util.ts @@ -0,0 +1,201 @@ +import { + FieldMetadataType, + RelationOnDeleteAction, + RelationType, +} from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildMessageParticipantStandardFlatFieldMetadatas = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): Record< + AllStandardObjectFieldName<'messageParticipant'>, + FlatFieldMetadata +> => ({ + id: createStandardFieldFlatMetadata({ + objectName: 'messageParticipant', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'messageParticipant', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'messageParticipant', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'messageParticipant', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + role: createStandardFieldFlatMetadata({ + objectName: 'messageParticipant', + workspaceId, + options: { + fieldName: 'role', + type: FieldMetadataType.SELECT, + label: 'Role', + description: 'Role', + icon: 'IconAt', + isNullable: false, + defaultValue: "'from'", + options: [ + { value: 'from', label: 'From', position: 0, color: 'green' }, + { value: 'to', label: 'To', position: 1, color: 'blue' }, + { value: 'cc', label: 'Cc', position: 2, color: 'orange' }, + { value: 'bcc', label: 'Bcc', position: 3, color: 'red' }, + ], + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + handle: createStandardFieldFlatMetadata({ + objectName: 'messageParticipant', + workspaceId, + options: { + fieldName: 'handle', + type: FieldMetadataType.TEXT, + label: 'Handle', + description: 'Handle', + icon: 'IconAt', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + displayName: createStandardFieldFlatMetadata({ + objectName: 'messageParticipant', + workspaceId, + options: { + fieldName: 'displayName', + type: FieldMetadataType.TEXT, + label: 'Display Name', + description: 'Display Name', + icon: 'IconUser', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + message: createStandardRelationFieldFlatMetadata({ + objectName: 'messageParticipant', + workspaceId, + options: { + fieldName: 'message', + label: 'Message', + description: 'Message', + icon: 'IconMessage', + isNullable: false, + createdAt, + targetObjectName: 'message', + targetFieldName: 'messageParticipants', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'messageId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + person: createStandardRelationFieldFlatMetadata({ + objectName: 'messageParticipant', + workspaceId, + options: { + fieldName: 'person', + label: 'Person', + description: 'Person', + icon: 'IconUser', + isNullable: true, + createdAt, + targetObjectName: 'person', + targetFieldName: 'messageParticipants', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.SET_NULL, + joinColumnName: 'personId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + workspaceMember: createStandardRelationFieldFlatMetadata({ + objectName: 'messageParticipant', + workspaceId, + options: { + fieldName: 'workspaceMember', + label: 'Workspace Member', + description: 'Workspace member', + icon: 'IconCircleUser', + isNullable: true, + createdAt, + targetObjectName: 'workspaceMember', + targetFieldName: 'messageParticipants', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.SET_NULL, + joinColumnName: 'workspaceMemberId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-message-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-message-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..32206e94d15 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-message-standard-flat-field-metadata.util.ts @@ -0,0 +1,220 @@ +import { + FieldMetadataType, + RelationOnDeleteAction, + RelationType, +} from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildMessageStandardFlatFieldMetadatas = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): Record, FlatFieldMetadata> => ({ + id: createStandardFieldFlatMetadata({ + objectName: 'message', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'message', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'message', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'message', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + headerMessageId: createStandardFieldFlatMetadata({ + objectName: 'message', + workspaceId, + options: { + fieldName: 'headerMessageId', + type: FieldMetadataType.TEXT, + label: 'Header message Id', + description: 'Message id from the message header', + icon: 'IconHash', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + direction: createStandardFieldFlatMetadata({ + objectName: 'message', + workspaceId, + options: { + fieldName: 'direction', + type: FieldMetadataType.SELECT, + label: 'Direction', + description: 'Message Direction', + icon: 'IconDirection', + isNullable: false, + defaultValue: "'INCOMING'", + options: [ + { value: 'INCOMING', label: 'Incoming', position: 0, color: 'green' }, + { value: 'OUTGOING', label: 'Outgoing', position: 1, color: 'blue' }, + ], + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + subject: createStandardFieldFlatMetadata({ + objectName: 'message', + workspaceId, + options: { + fieldName: 'subject', + type: FieldMetadataType.TEXT, + label: 'Subject', + description: 'Subject', + icon: 'IconMessage', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + text: createStandardFieldFlatMetadata({ + objectName: 'message', + workspaceId, + options: { + fieldName: 'text', + type: FieldMetadataType.TEXT, + label: 'Text', + description: 'Text', + icon: 'IconMessage', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + receivedAt: createStandardFieldFlatMetadata({ + objectName: 'message', + workspaceId, + options: { + fieldName: 'receivedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Received At', + description: 'The date the message was received', + icon: 'IconCalendar', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + messageThread: createStandardRelationFieldFlatMetadata({ + objectName: 'message', + workspaceId, + options: { + fieldName: 'messageThread', + label: 'Message Thread Id', + description: 'Message Thread Id', + icon: 'IconHash', + isNullable: true, + createdAt, + targetObjectName: 'messageThread', + targetFieldName: 'messages', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'messageThreadId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + messageParticipants: createStandardRelationFieldFlatMetadata({ + objectName: 'message', + workspaceId, + options: { + fieldName: 'messageParticipants', + label: 'Message Participants', + description: 'Message Participants', + icon: 'IconUserCircle', + isNullable: true, + createdAt, + targetObjectName: 'messageParticipant', + targetFieldName: 'message', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + messageChannelMessageAssociations: createStandardRelationFieldFlatMetadata({ + objectName: 'message', + workspaceId, + options: { + fieldName: 'messageChannelMessageAssociations', + label: 'Message Channel Association', + description: 'Messages from the channel.', + icon: 'IconMessage', + isNullable: true, + createdAt, + targetObjectName: 'messageChannelMessageAssociation', + targetFieldName: 'message', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-message-thread-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-message-thread-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..2dc23a23ef1 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-message-thread-standard-flat-field-metadata.util.ts @@ -0,0 +1,121 @@ +import { FieldMetadataType, RelationType } from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildMessageThreadStandardFlatFieldMetadatas = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): Record, FlatFieldMetadata> => ({ + id: createStandardFieldFlatMetadata({ + objectName: 'messageThread', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'messageThread', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'messageThread', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'messageThread', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + messages: createStandardRelationFieldFlatMetadata({ + objectName: 'messageThread', + workspaceId, + options: { + fieldName: 'messages', + label: 'Messages', + description: 'Messages from the thread.', + icon: 'IconMessage', + isNullable: true, + createdAt, + targetObjectName: 'message', + targetFieldName: 'messageThread', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + messageChannelMessageAssociations: createStandardRelationFieldFlatMetadata({ + objectName: 'messageThread', + workspaceId, + options: { + fieldName: 'messageChannelMessageAssociations', + label: 'Message Channel Association', + description: 'Messages from the channel.', + icon: 'IconMessage', + isNullable: true, + createdAt, + targetObjectName: 'messageChannelMessageAssociation', + targetFieldName: 'messageThread', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-note-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-note-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..eae7ca09ed0 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-note-standard-flat-field-metadata.util.ts @@ -0,0 +1,260 @@ +import { FieldMetadataType, RelationType } from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildNoteStandardFlatFieldMetadatas = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): Record, FlatFieldMetadata> => ({ + // Base fields from BaseWorkspaceEntity + id: createStandardFieldFlatMetadata({ + objectName: 'note', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'note', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { + displayFormat: 'RELATIVE', + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'note', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { + displayFormat: 'RELATIVE', + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'note', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { + displayFormat: 'RELATIVE', + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + + // Note-specific fields + position: createStandardFieldFlatMetadata({ + objectName: 'note', + workspaceId, + options: { + fieldName: 'position', + type: FieldMetadataType.POSITION, + label: 'Position', + description: 'Note record position', + icon: 'IconHierarchy2', + isSystem: true, + isNullable: false, + defaultValue: 0, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + title: createStandardFieldFlatMetadata({ + objectName: 'note', + workspaceId, + options: { + fieldName: 'title', + type: FieldMetadataType.TEXT, + label: 'Title', + description: 'Note title', + icon: 'IconNotes', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + body: createStandardFieldFlatMetadata({ + objectName: 'note', + workspaceId, + options: { + fieldName: 'body', + type: FieldMetadataType.TEXT, + label: 'Body (deprecated)', + description: 'Note body (deprecated - use bodyV2)', + icon: 'IconFilePencil', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + bodyV2: createStandardFieldFlatMetadata({ + objectName: 'note', + workspaceId, + options: { + fieldName: 'bodyV2', + type: FieldMetadataType.RICH_TEXT_V2, + label: 'Body', + description: 'Note body', + icon: 'IconFilePencil', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdBy: createStandardFieldFlatMetadata({ + objectName: 'note', + workspaceId, + options: { + fieldName: 'createdBy', + type: FieldMetadataType.ACTOR, + label: 'Created by', + description: 'The creator of the record', + icon: 'IconCreativeCommonsSa', + isUIReadOnly: true, + isNullable: false, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + searchVector: createStandardFieldFlatMetadata({ + objectName: 'note', + workspaceId, + options: { + fieldName: 'searchVector', + type: FieldMetadataType.TS_VECTOR, + label: 'Search vector', + description: 'Field used for full-text search', + icon: 'IconUser', + isSystem: true, + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + + // Relation fields + noteTargets: createStandardRelationFieldFlatMetadata({ + objectName: 'note', + workspaceId, + options: { + fieldName: 'noteTargets', + label: 'Relations', + description: 'Note targets', + icon: 'IconArrowUpRight', + isSystem: true, + isNullable: true, + createdAt, + targetObjectName: 'noteTarget', + targetFieldName: 'note', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + attachments: createStandardRelationFieldFlatMetadata({ + objectName: 'note', + workspaceId, + options: { + fieldName: 'attachments', + label: 'Attachments', + description: 'Note attachments', + icon: 'IconFileImport', + isSystem: true, + isNullable: true, + createdAt, + targetObjectName: 'attachment', + targetFieldName: 'note', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + timelineActivities: createStandardRelationFieldFlatMetadata({ + objectName: 'note', + workspaceId, + options: { + fieldName: 'timelineActivities', + label: 'Timeline Activities', + description: 'Timeline Activities linked to the note.', + icon: 'IconTimelineEvent', + isSystem: true, + isNullable: true, + createdAt, + targetObjectName: 'timelineActivity', + targetFieldName: 'note', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + favorites: createStandardRelationFieldFlatMetadata({ + objectName: 'note', + workspaceId, + options: { + fieldName: 'favorites', + label: 'Favorites', + description: 'Favorites linked to the note', + icon: 'IconHeart', + isSystem: true, + isNullable: false, + createdAt, + targetObjectName: 'favorite', + targetFieldName: 'note', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-note-target-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-note-target-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..36e6fe64943 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-note-target-standard-flat-field-metadata.util.ts @@ -0,0 +1,199 @@ +import { + FieldMetadataType, + RelationOnDeleteAction, + RelationType, +} from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildNoteTargetStandardFlatFieldMetadatas = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): Record, FlatFieldMetadata> => ({ + // Base fields from BaseWorkspaceEntity + id: createStandardFieldFlatMetadata({ + objectName: 'noteTarget', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'noteTarget', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { + displayFormat: 'RELATIVE', + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'noteTarget', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { + displayFormat: 'RELATIVE', + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'noteTarget', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { + displayFormat: 'RELATIVE', + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + + // Relation fields + note: createStandardRelationFieldFlatMetadata({ + objectName: 'noteTarget', + workspaceId, + options: { + fieldName: 'note', + label: 'Note', + description: 'NoteTarget note', + icon: 'IconNotes', + isNullable: true, + createdAt, + targetObjectName: 'note', + targetFieldName: 'noteTargets', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'noteId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + person: createStandardRelationFieldFlatMetadata({ + objectName: 'noteTarget', + workspaceId, + options: { + fieldName: 'person', + label: 'Person', + description: 'NoteTarget person', + icon: 'IconUser', + isNullable: true, + createdAt, + targetObjectName: 'person', + targetFieldName: 'noteTargets', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'personId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + company: createStandardRelationFieldFlatMetadata({ + objectName: 'noteTarget', + workspaceId, + options: { + fieldName: 'company', + label: 'Company', + description: 'NoteTarget company', + icon: 'IconBuildingSkyscraper', + isNullable: true, + createdAt, + targetObjectName: 'company', + targetFieldName: 'noteTargets', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'companyId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + opportunity: createStandardRelationFieldFlatMetadata({ + objectName: 'noteTarget', + workspaceId, + options: { + fieldName: 'opportunity', + label: 'Opportunity', + description: 'NoteTarget opportunity', + icon: 'IconTargetArrow', + isNullable: true, + createdAt, + targetObjectName: 'opportunity', + targetFieldName: 'noteTargets', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'opportunityId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + custom: createStandardRelationFieldFlatMetadata({ + objectName: 'noteTarget', + workspaceId, + options: { + fieldName: 'custom', + label: 'Custom', + description: 'NoteTarget custom object', + icon: 'IconBuildingSkyscraper', + isNullable: true, + createdAt, + // Custom is a dynamic relation + targetObjectName: 'note', + targetFieldName: 'noteTargets', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'customId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-opportunity-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-opportunity-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..05f40531d7c --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-opportunity-standard-flat-field-metadata.util.ts @@ -0,0 +1,355 @@ +import { + FieldMetadataType, + RelationOnDeleteAction, + RelationType, +} from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildOpportunityStandardFlatFieldMetadatas = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): Record, FlatFieldMetadata> => ({ + // Base fields from BaseWorkspaceEntity + id: createStandardFieldFlatMetadata({ + objectName: 'opportunity', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'opportunity', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { + displayFormat: 'RELATIVE', + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'opportunity', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { + displayFormat: 'RELATIVE', + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'opportunity', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { + displayFormat: 'RELATIVE', + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + + // Opportunity-specific fields + name: createStandardFieldFlatMetadata({ + objectName: 'opportunity', + workspaceId, + options: { + fieldName: 'name', + type: FieldMetadataType.TEXT, + label: 'Name', + description: 'The opportunity name', + icon: 'IconTargetArrow', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + amount: createStandardFieldFlatMetadata({ + objectName: 'opportunity', + workspaceId, + options: { + fieldName: 'amount', + type: FieldMetadataType.CURRENCY, + label: 'Amount', + description: 'Opportunity amount', + icon: 'IconCurrencyDollar', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + closeDate: createStandardFieldFlatMetadata({ + objectName: 'opportunity', + workspaceId, + options: { + fieldName: 'closeDate', + type: FieldMetadataType.DATE_TIME, + label: 'Close date', + description: 'Opportunity close date', + icon: 'IconCalendarEvent', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + stage: createStandardFieldFlatMetadata({ + objectName: 'opportunity', + workspaceId, + options: { + fieldName: 'stage', + type: FieldMetadataType.SELECT, + label: 'Stage', + description: 'Opportunity stage', + icon: 'IconProgressCheck', + isNullable: false, + defaultValue: "'NEW'", + options: [ + { value: 'NEW', label: 'New', position: 0, color: 'red' }, + { + value: 'SCREENING', + label: 'Screening', + position: 1, + color: 'purple', + }, + { value: 'MEETING', label: 'Meeting', position: 2, color: 'sky' }, + { + value: 'PROPOSAL', + label: 'Proposal', + position: 3, + color: 'turquoise', + }, + { value: 'CUSTOMER', label: 'Customer', position: 4, color: 'yellow' }, + ], + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + position: createStandardFieldFlatMetadata({ + objectName: 'opportunity', + workspaceId, + options: { + fieldName: 'position', + type: FieldMetadataType.POSITION, + label: 'Position', + description: 'Opportunity record position', + icon: 'IconHierarchy2', + isSystem: true, + isNullable: false, + defaultValue: 0, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdBy: createStandardFieldFlatMetadata({ + objectName: 'opportunity', + workspaceId, + options: { + fieldName: 'createdBy', + type: FieldMetadataType.ACTOR, + label: 'Created by', + description: 'The creator of the record', + icon: 'IconCreativeCommonsSa', + isUIReadOnly: true, + isNullable: false, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + searchVector: createStandardFieldFlatMetadata({ + objectName: 'opportunity', + workspaceId, + options: { + fieldName: 'searchVector', + type: FieldMetadataType.TS_VECTOR, + label: 'Search vector', + description: 'Field used for full-text search', + icon: 'IconUser', + isSystem: true, + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + + // Relation fields + pointOfContact: createStandardRelationFieldFlatMetadata({ + objectName: 'opportunity', + workspaceId, + options: { + fieldName: 'pointOfContact', + label: 'Point of Contact', + description: 'Opportunity point of contact', + icon: 'IconUser', + isNullable: true, + createdAt, + targetObjectName: 'person', + targetFieldName: 'pointOfContactForOpportunities', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.SET_NULL, + joinColumnName: 'pointOfContactId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + company: createStandardRelationFieldFlatMetadata({ + objectName: 'opportunity', + workspaceId, + options: { + fieldName: 'company', + label: 'Company', + description: 'Opportunity company', + icon: 'IconBuildingSkyscraper', + isNullable: true, + createdAt, + targetObjectName: 'company', + targetFieldName: 'opportunities', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.SET_NULL, + joinColumnName: 'companyId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + favorites: createStandardRelationFieldFlatMetadata({ + objectName: 'opportunity', + workspaceId, + options: { + fieldName: 'favorites', + label: 'Favorites', + description: 'Favorites linked to the opportunity', + icon: 'IconHeart', + isSystem: true, + isNullable: true, + createdAt, + targetObjectName: 'favorite', + targetFieldName: 'opportunity', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + taskTargets: createStandardRelationFieldFlatMetadata({ + objectName: 'opportunity', + workspaceId, + options: { + fieldName: 'taskTargets', + label: 'Tasks', + description: 'Tasks tied to the opportunity', + icon: 'IconCheckbox', + isUIReadOnly: true, + isNullable: true, + createdAt, + targetObjectName: 'taskTarget', + targetFieldName: 'opportunity', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + noteTargets: createStandardRelationFieldFlatMetadata({ + objectName: 'opportunity', + workspaceId, + options: { + fieldName: 'noteTargets', + label: 'Notes', + description: 'Notes tied to the opportunity', + icon: 'IconNotes', + isUIReadOnly: true, + isNullable: true, + createdAt, + targetObjectName: 'noteTarget', + targetFieldName: 'opportunity', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + attachments: createStandardRelationFieldFlatMetadata({ + objectName: 'opportunity', + workspaceId, + options: { + fieldName: 'attachments', + label: 'Attachments', + description: 'Attachments linked to the opportunity', + icon: 'IconFileImport', + isSystem: true, + isNullable: true, + createdAt, + targetObjectName: 'attachment', + targetFieldName: 'opportunity', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + timelineActivities: createStandardRelationFieldFlatMetadata({ + objectName: 'opportunity', + workspaceId, + options: { + fieldName: 'timelineActivities', + label: 'Timeline Activities', + description: 'Timeline Activities linked to the opportunity.', + icon: 'IconTimelineEvent', + isSystem: true, + isNullable: true, + createdAt, + targetObjectName: 'timelineActivity', + targetFieldName: 'opportunity', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-person-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-person-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..4579c221038 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-person-standard-flat-field-metadata.util.ts @@ -0,0 +1,466 @@ +import { + FieldMetadataType, + RelationOnDeleteAction, + RelationType, +} from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildPersonStandardFlatFieldMetadatas = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): Record, FlatFieldMetadata> => ({ + // Base fields from BaseWorkspaceEntity + id: createStandardFieldFlatMetadata({ + objectName: 'person', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'person', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { + displayFormat: 'RELATIVE', + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'person', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { + displayFormat: 'RELATIVE', + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'person', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { + displayFormat: 'RELATIVE', + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + + // Person-specific fields + name: createStandardFieldFlatMetadata({ + objectName: 'person', + workspaceId, + options: { + fieldName: 'name', + type: FieldMetadataType.FULL_NAME, + label: 'Name', + description: "Contact's name", + icon: 'IconUser', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + email: createStandardFieldFlatMetadata({ + objectName: 'person', + workspaceId, + options: { + fieldName: 'email', + type: FieldMetadataType.TEXT, + label: 'Email', + description: "Contact's Email (deprecated)", + icon: 'IconMail', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + emails: createStandardFieldFlatMetadata({ + objectName: 'person', + workspaceId, + options: { + fieldName: 'emails', + type: FieldMetadataType.EMAILS, + label: 'Emails', + description: "Contact's Emails", + icon: 'IconMail', + isNullable: true, + isUnique: true, + settings: { + maxNumberOfValues: 1, + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + linkedinLink: createStandardFieldFlatMetadata({ + objectName: 'person', + workspaceId, + options: { + fieldName: 'linkedinLink', + type: FieldMetadataType.LINKS, + label: 'Linkedin', + description: "Contact's Linkedin account", + icon: 'IconBrandLinkedin', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + xLink: createStandardFieldFlatMetadata({ + objectName: 'person', + workspaceId, + options: { + fieldName: 'xLink', + type: FieldMetadataType.LINKS, + label: 'X', + description: "Contact's X/Twitter account", + icon: 'IconBrandX', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + jobTitle: createStandardFieldFlatMetadata({ + objectName: 'person', + workspaceId, + options: { + fieldName: 'jobTitle', + type: FieldMetadataType.TEXT, + label: 'Job Title', + description: "Contact's job title", + icon: 'IconBriefcase', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + phone: createStandardFieldFlatMetadata({ + objectName: 'person', + workspaceId, + options: { + fieldName: 'phone', + type: FieldMetadataType.TEXT, + label: 'Phone', + description: "Contact's phone number (deprecated)", + icon: 'IconPhone', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + phones: createStandardFieldFlatMetadata({ + objectName: 'person', + workspaceId, + options: { + fieldName: 'phones', + type: FieldMetadataType.PHONES, + label: 'Phones', + description: "Contact's phone numbers", + icon: 'IconPhone', + isNullable: true, + settings: { + maxNumberOfValues: 1, + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + city: createStandardFieldFlatMetadata({ + objectName: 'person', + workspaceId, + options: { + fieldName: 'city', + type: FieldMetadataType.TEXT, + label: 'City', + description: "Contact's city", + icon: 'IconMap', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + avatarUrl: createStandardFieldFlatMetadata({ + objectName: 'person', + workspaceId, + options: { + fieldName: 'avatarUrl', + type: FieldMetadataType.TEXT, + label: 'Avatar', + description: "Contact's avatar", + icon: 'IconFileUpload', + isSystem: true, + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + position: createStandardFieldFlatMetadata({ + objectName: 'person', + workspaceId, + options: { + fieldName: 'position', + type: FieldMetadataType.POSITION, + label: 'Position', + description: 'Person record Position', + icon: 'IconHierarchy2', + isSystem: true, + isNullable: false, + defaultValue: 0, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdBy: createStandardFieldFlatMetadata({ + objectName: 'person', + workspaceId, + options: { + fieldName: 'createdBy', + type: FieldMetadataType.ACTOR, + label: 'Created by', + description: 'The creator of the record', + icon: 'IconCreativeCommonsSa', + isUIReadOnly: true, + isNullable: false, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + + // Relation fields + company: createStandardRelationFieldFlatMetadata({ + objectName: 'person', + workspaceId, + options: { + fieldName: 'company', + label: 'Company', + description: "Contact's company", + icon: 'IconBuildingSkyscraper', + isNullable: true, + createdAt, + targetObjectName: 'company', + targetFieldName: 'people', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.SET_NULL, + joinColumnName: 'companyId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + pointOfContactForOpportunities: createStandardRelationFieldFlatMetadata({ + objectName: 'person', + workspaceId, + options: { + fieldName: 'pointOfContactForOpportunities', + label: 'Opportunities', + description: + 'List of opportunities for which that person is the point of contact', + icon: 'IconTargetArrow', + isNullable: true, + createdAt, + targetObjectName: 'opportunity', + targetFieldName: 'pointOfContact', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + taskTargets: createStandardRelationFieldFlatMetadata({ + objectName: 'person', + workspaceId, + options: { + fieldName: 'taskTargets', + label: 'Tasks', + description: 'Tasks tied to the contact', + icon: 'IconCheckbox', + isUIReadOnly: true, + isNullable: true, + createdAt, + targetObjectName: 'taskTarget', + targetFieldName: 'person', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + noteTargets: createStandardRelationFieldFlatMetadata({ + objectName: 'person', + workspaceId, + options: { + fieldName: 'noteTargets', + label: 'Notes', + description: 'Notes tied to the contact', + icon: 'IconNotes', + isUIReadOnly: true, + isNullable: true, + createdAt, + targetObjectName: 'noteTarget', + targetFieldName: 'person', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + favorites: createStandardRelationFieldFlatMetadata({ + objectName: 'person', + workspaceId, + options: { + fieldName: 'favorites', + label: 'Favorites', + description: 'Favorites linked to the contact', + icon: 'IconHeart', + isSystem: true, + isNullable: true, + createdAt, + targetObjectName: 'favorite', + targetFieldName: 'person', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + attachments: createStandardRelationFieldFlatMetadata({ + objectName: 'person', + workspaceId, + options: { + fieldName: 'attachments', + label: 'Attachments', + description: 'Attachments linked to the contact.', + icon: 'IconFileImport', + isSystem: true, + isNullable: true, + createdAt, + targetObjectName: 'attachment', + targetFieldName: 'person', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + messageParticipants: createStandardRelationFieldFlatMetadata({ + objectName: 'person', + workspaceId, + options: { + fieldName: 'messageParticipants', + label: 'Message Participants', + description: 'Message Participants', + icon: 'IconUserCircle', + isSystem: true, + isNullable: true, + createdAt, + targetObjectName: 'messageParticipant', + targetFieldName: 'person', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + calendarEventParticipants: createStandardRelationFieldFlatMetadata({ + objectName: 'person', + workspaceId, + options: { + fieldName: 'calendarEventParticipants', + label: 'Calendar Event Participants', + description: 'Calendar Event Participants', + icon: 'IconCalendar', + isSystem: true, + isNullable: true, + createdAt, + targetObjectName: 'calendarEventParticipant', + targetFieldName: 'person', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + timelineActivities: createStandardRelationFieldFlatMetadata({ + objectName: 'person', + workspaceId, + options: { + fieldName: 'timelineActivities', + label: 'Events', + description: 'Events linked to the person', + icon: 'IconTimelineEvent', + isSystem: true, + isNullable: true, + createdAt, + targetObjectName: 'timelineActivity', + targetFieldName: 'person', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + searchVector: createStandardFieldFlatMetadata({ + objectName: 'person', + workspaceId, + options: { + fieldName: 'searchVector', + type: FieldMetadataType.TS_VECTOR, + label: 'Search vector', + description: 'Field used for full-text search', + icon: 'IconUser', + isSystem: true, + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-task-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-task-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..1abf774b127 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-task-standard-flat-field-metadata.util.ts @@ -0,0 +1,323 @@ +import { + FieldMetadataType, + RelationOnDeleteAction, + RelationType, +} from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildTaskStandardFlatFieldMetadatas = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): Record, FlatFieldMetadata> => ({ + // Base fields from BaseWorkspaceEntity + id: createStandardFieldFlatMetadata({ + objectName: 'task', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'task', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { + displayFormat: 'RELATIVE', + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'task', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { + displayFormat: 'RELATIVE', + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'task', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { + displayFormat: 'RELATIVE', + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + + // Task-specific fields + position: createStandardFieldFlatMetadata({ + objectName: 'task', + workspaceId, + options: { + fieldName: 'position', + type: FieldMetadataType.POSITION, + label: 'Position', + description: 'Task record position', + icon: 'IconHierarchy2', + isSystem: true, + isNullable: false, + defaultValue: 0, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + title: createStandardFieldFlatMetadata({ + objectName: 'task', + workspaceId, + options: { + fieldName: 'title', + type: FieldMetadataType.TEXT, + label: 'Title', + description: 'Task title', + icon: 'IconNotes', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + body: createStandardFieldFlatMetadata({ + objectName: 'task', + workspaceId, + options: { + fieldName: 'body', + type: FieldMetadataType.TEXT, + label: 'Body (deprecated)', + description: 'Task body (deprecated - use bodyV2)', + icon: 'IconFilePencil', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + bodyV2: createStandardFieldFlatMetadata({ + objectName: 'task', + workspaceId, + options: { + fieldName: 'bodyV2', + type: FieldMetadataType.RICH_TEXT_V2, + label: 'Body', + description: 'Task body', + icon: 'IconFilePencil', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + dueAt: createStandardFieldFlatMetadata({ + objectName: 'task', + workspaceId, + options: { + fieldName: 'dueAt', + type: FieldMetadataType.DATE_TIME, + label: 'Due Date', + description: 'Task due date', + icon: 'IconCalendarEvent', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + status: createStandardFieldFlatMetadata({ + objectName: 'task', + workspaceId, + options: { + fieldName: 'status', + type: FieldMetadataType.SELECT, + label: 'Status', + description: 'Task status', + icon: 'IconCheck', + isNullable: true, + defaultValue: "'TODO'", + options: [ + { value: 'TODO', label: 'To do', position: 0, color: 'sky' }, + { + value: 'IN_PROGRESS', + label: 'In progress', + position: 1, + color: 'purple', + }, + { value: 'DONE', label: 'Done', position: 2, color: 'green' }, + ], + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdBy: createStandardFieldFlatMetadata({ + objectName: 'task', + workspaceId, + options: { + fieldName: 'createdBy', + type: FieldMetadataType.ACTOR, + label: 'Created by', + description: 'The creator of the record', + icon: 'IconCreativeCommonsSa', + isUIReadOnly: true, + isNullable: false, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + searchVector: createStandardFieldFlatMetadata({ + objectName: 'task', + workspaceId, + options: { + fieldName: 'searchVector', + type: FieldMetadataType.TS_VECTOR, + label: 'Search vector', + description: 'Field used for full-text search', + icon: 'IconUser', + isSystem: true, + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + + // Relation fields + taskTargets: createStandardRelationFieldFlatMetadata({ + objectName: 'task', + workspaceId, + options: { + fieldName: 'taskTargets', + label: 'Relations', + description: 'Task targets', + icon: 'IconArrowUpRight', + isSystem: true, + isNullable: true, + createdAt, + targetObjectName: 'taskTarget', + targetFieldName: 'task', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + attachments: createStandardRelationFieldFlatMetadata({ + objectName: 'task', + workspaceId, + options: { + fieldName: 'attachments', + label: 'Attachments', + description: 'Task attachments', + icon: 'IconFileImport', + isSystem: true, + isNullable: true, + createdAt, + targetObjectName: 'attachment', + targetFieldName: 'task', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + assignee: createStandardRelationFieldFlatMetadata({ + objectName: 'task', + workspaceId, + options: { + fieldName: 'assignee', + label: 'Assignee', + description: 'Task assignee', + icon: 'IconUserCircle', + isNullable: true, + createdAt, + targetObjectName: 'workspaceMember', + targetFieldName: 'assignedTasks', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.SET_NULL, + joinColumnName: 'assigneeId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + timelineActivities: createStandardRelationFieldFlatMetadata({ + objectName: 'task', + workspaceId, + options: { + fieldName: 'timelineActivities', + label: 'Timeline Activities', + description: 'Timeline Activities linked to the task.', + icon: 'IconTimelineEvent', + isSystem: true, + isNullable: true, + createdAt, + targetObjectName: 'timelineActivity', + targetFieldName: 'task', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + favorites: createStandardRelationFieldFlatMetadata({ + objectName: 'task', + workspaceId, + options: { + fieldName: 'favorites', + label: 'Favorites', + description: 'Favorites linked to the task', + icon: 'IconHeart', + isSystem: true, + isNullable: false, + createdAt, + targetObjectName: 'favorite', + targetFieldName: 'task', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-task-target-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-task-target-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..63e87a2765b --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-task-target-standard-flat-field-metadata.util.ts @@ -0,0 +1,199 @@ +import { + FieldMetadataType, + RelationOnDeleteAction, + RelationType, +} from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildTaskTargetStandardFlatFieldMetadatas = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): Record, FlatFieldMetadata> => ({ + // Base fields from BaseWorkspaceEntity + id: createStandardFieldFlatMetadata({ + objectName: 'taskTarget', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'taskTarget', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { + displayFormat: 'RELATIVE', + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'taskTarget', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { + displayFormat: 'RELATIVE', + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'taskTarget', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { + displayFormat: 'RELATIVE', + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + + // Relation fields + task: createStandardRelationFieldFlatMetadata({ + objectName: 'taskTarget', + workspaceId, + options: { + fieldName: 'task', + label: 'Task', + description: 'TaskTarget task', + icon: 'IconCheckbox', + isNullable: true, + createdAt, + targetObjectName: 'task', + targetFieldName: 'taskTargets', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.SET_NULL, + joinColumnName: 'taskId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + person: createStandardRelationFieldFlatMetadata({ + objectName: 'taskTarget', + workspaceId, + options: { + fieldName: 'person', + label: 'Person', + description: 'TaskTarget person', + icon: 'IconUser', + isNullable: true, + createdAt, + targetObjectName: 'person', + targetFieldName: 'taskTargets', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'personId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + company: createStandardRelationFieldFlatMetadata({ + objectName: 'taskTarget', + workspaceId, + options: { + fieldName: 'company', + label: 'Company', + description: 'TaskTarget company', + icon: 'IconBuildingSkyscraper', + isNullable: true, + createdAt, + targetObjectName: 'company', + targetFieldName: 'taskTargets', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'companyId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + opportunity: createStandardRelationFieldFlatMetadata({ + objectName: 'taskTarget', + workspaceId, + options: { + fieldName: 'opportunity', + label: 'Opportunity', + description: 'TaskTarget opportunity', + icon: 'IconTargetArrow', + isNullable: true, + createdAt, + targetObjectName: 'opportunity', + targetFieldName: 'taskTargets', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'opportunityId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + custom: createStandardRelationFieldFlatMetadata({ + objectName: 'taskTarget', + workspaceId, + options: { + fieldName: 'custom', + label: 'Custom', + description: 'TaskTarget custom object', + icon: 'IconBuildingSkyscraper', + isNullable: true, + createdAt, + // Custom is a dynamic relation + targetObjectName: 'task', + targetFieldName: 'taskTargets', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'customId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-timeline-activity-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-timeline-activity-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..f332fea36a3 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-timeline-activity-standard-flat-field-metadata.util.ts @@ -0,0 +1,402 @@ +import { + FieldMetadataType, + RelationOnDeleteAction, + RelationType, +} from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildTimelineActivityStandardFlatFieldMetadatas = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): Record< + AllStandardObjectFieldName<'timelineActivity'>, + FlatFieldMetadata +> => ({ + // Base fields from BaseWorkspaceEntity + id: createStandardFieldFlatMetadata({ + objectName: 'timelineActivity', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'timelineActivity', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'timelineActivity', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'timelineActivity', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + + // TimelineActivity-specific fields + happensAt: createStandardFieldFlatMetadata({ + objectName: 'timelineActivity', + workspaceId, + options: { + fieldName: 'happensAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + defaultValue: 'now', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + name: createStandardFieldFlatMetadata({ + objectName: 'timelineActivity', + workspaceId, + options: { + fieldName: 'name', + type: FieldMetadataType.TEXT, + label: 'Event name', + description: 'Event name', + icon: 'IconAbc', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + properties: createStandardFieldFlatMetadata({ + objectName: 'timelineActivity', + workspaceId, + options: { + fieldName: 'properties', + type: FieldMetadataType.RAW_JSON, + label: 'Event details', + description: 'Json value for event details', + icon: 'IconListDetails', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + linkedRecordCachedName: createStandardFieldFlatMetadata({ + objectName: 'timelineActivity', + workspaceId, + options: { + fieldName: 'linkedRecordCachedName', + type: FieldMetadataType.TEXT, + label: 'Linked Record cached name', + description: 'Cached record name', + icon: 'IconAbc', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + linkedRecordId: createStandardFieldFlatMetadata({ + objectName: 'timelineActivity', + workspaceId, + options: { + fieldName: 'linkedRecordId', + type: FieldMetadataType.UUID, + label: 'Linked Record id', + description: 'Linked Record id', + icon: 'IconAbc', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + linkedObjectMetadataId: createStandardFieldFlatMetadata({ + objectName: 'timelineActivity', + workspaceId, + options: { + fieldName: 'linkedObjectMetadataId', + type: FieldMetadataType.UUID, + label: 'Linked Object Metadata Id', + description: 'Linked Object Metadata Id', + icon: 'IconAbc', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + + // Relation fields + workspaceMember: createStandardRelationFieldFlatMetadata({ + objectName: 'timelineActivity', + workspaceId, + options: { + fieldName: 'workspaceMember', + label: 'Workspace Member', + description: 'Event workspace member', + icon: 'IconCircleUser', + isNullable: true, + createdAt, + targetObjectName: 'workspaceMember', + targetFieldName: 'timelineActivities', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'workspaceMemberId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + person: createStandardRelationFieldFlatMetadata({ + objectName: 'timelineActivity', + workspaceId, + options: { + fieldName: 'person', + label: 'Person', + description: 'Event person', + icon: 'IconUser', + isNullable: true, + createdAt, + targetObjectName: 'person', + targetFieldName: 'timelineActivities', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'personId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + company: createStandardRelationFieldFlatMetadata({ + objectName: 'timelineActivity', + workspaceId, + options: { + fieldName: 'company', + label: 'Company', + description: 'Event company', + icon: 'IconBuildingSkyscraper', + isNullable: true, + createdAt, + targetObjectName: 'company', + targetFieldName: 'timelineActivities', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'companyId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + opportunity: createStandardRelationFieldFlatMetadata({ + objectName: 'timelineActivity', + workspaceId, + options: { + fieldName: 'opportunity', + label: 'Opportunity', + description: 'Event opportunity', + icon: 'IconTargetArrow', + isNullable: true, + createdAt, + targetObjectName: 'opportunity', + targetFieldName: 'timelineActivities', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.SET_NULL, + joinColumnName: 'opportunityId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + note: createStandardRelationFieldFlatMetadata({ + objectName: 'timelineActivity', + workspaceId, + options: { + fieldName: 'note', + label: 'Note', + description: 'Event note', + icon: 'IconTargetArrow', + isNullable: true, + createdAt, + targetObjectName: 'note', + targetFieldName: 'timelineActivities', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.SET_NULL, + joinColumnName: 'noteId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + task: createStandardRelationFieldFlatMetadata({ + objectName: 'timelineActivity', + workspaceId, + options: { + fieldName: 'task', + label: 'Task', + description: 'Event task', + icon: 'IconTargetArrow', + isNullable: true, + createdAt, + targetObjectName: 'task', + targetFieldName: 'timelineActivities', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.SET_NULL, + joinColumnName: 'taskId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + workflow: createStandardRelationFieldFlatMetadata({ + objectName: 'timelineActivity', + workspaceId, + options: { + fieldName: 'workflow', + label: 'Workflow', + description: 'Event workflow', + icon: 'IconTargetArrow', + isNullable: true, + createdAt, + targetObjectName: 'workflow', + targetFieldName: 'timelineActivities', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'workflowId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + workflowVersion: createStandardRelationFieldFlatMetadata({ + objectName: 'timelineActivity', + workspaceId, + options: { + fieldName: 'workflowVersion', + label: 'WorkflowVersion', + description: 'Event workflow version', + icon: 'IconTargetArrow', + isNullable: true, + createdAt, + targetObjectName: 'workflowVersion', + targetFieldName: 'timelineActivities', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'workflowVersionId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + workflowRun: createStandardRelationFieldFlatMetadata({ + objectName: 'timelineActivity', + workspaceId, + options: { + fieldName: 'workflowRun', + label: 'Workflow Run', + description: 'Event workflow run', + icon: 'IconTargetArrow', + isNullable: true, + createdAt, + targetObjectName: 'workflowRun', + targetFieldName: 'timelineActivities', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'workflowRunId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + dashboard: createStandardRelationFieldFlatMetadata({ + objectName: 'timelineActivity', + workspaceId, + options: { + fieldName: 'dashboard', + label: 'Dashboard', + description: 'Event dashboard', + icon: 'IconTargetArrow', + isNullable: true, + createdAt, + targetObjectName: 'dashboard', + targetFieldName: 'timelineActivities', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.SET_NULL, + joinColumnName: 'dashboardId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + custom: createStandardRelationFieldFlatMetadata({ + objectName: 'timelineActivity', + workspaceId, + options: { + fieldName: 'custom', + label: 'Custom', + description: 'Timeline Activity custom object', + icon: 'IconTimeline', + isNullable: true, + createdAt, + targetObjectName: 'note', + targetFieldName: 'timelineActivities', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'customId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-workflow-automated-trigger-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-workflow-automated-trigger-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..2ff5c05e3f2 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-workflow-automated-trigger-standard-flat-field-metadata.util.ts @@ -0,0 +1,149 @@ +import { + FieldMetadataType, + RelationOnDeleteAction, + RelationType, +} from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildWorkflowAutomatedTriggerStandardFlatFieldMetadatas = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): Record< + AllStandardObjectFieldName<'workflowAutomatedTrigger'>, + FlatFieldMetadata +> => ({ + id: createStandardFieldFlatMetadata({ + objectName: 'workflowAutomatedTrigger', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'workflowAutomatedTrigger', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'workflowAutomatedTrigger', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'workflowAutomatedTrigger', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + type: createStandardFieldFlatMetadata({ + objectName: 'workflowAutomatedTrigger', + workspaceId, + options: { + fieldName: 'type', + type: FieldMetadataType.SELECT, + label: 'Automated Trigger Type', + description: 'The workflow automated trigger type', + icon: 'IconSettingsAutomation', + isNullable: false, + options: [ + { + value: 'DATABASE_EVENT', + label: 'Database Event', + position: 0, + color: 'green', + }, + { value: 'CRON', label: 'Cron', position: 1, color: 'blue' }, + ], + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + settings: createStandardFieldFlatMetadata({ + objectName: 'workflowAutomatedTrigger', + workspaceId, + options: { + fieldName: 'settings', + type: FieldMetadataType.RAW_JSON, + label: 'Settings', + description: 'The workflow automated trigger settings', + icon: 'IconSettings', + isNullable: false, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + workflow: createStandardRelationFieldFlatMetadata({ + objectName: 'workflowAutomatedTrigger', + workspaceId, + options: { + fieldName: 'workflow', + label: 'Workflow', + description: 'WorkflowAutomatedTrigger workflow', + icon: 'IconSettingsAutomation', + isNullable: false, + createdAt, + targetObjectName: 'workflow', + targetFieldName: 'automatedTriggers', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'workflowId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-workflow-run-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-workflow-run-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..0d33fe1b5c3 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-workflow-run-standard-flat-field-metadata.util.ts @@ -0,0 +1,339 @@ +import { + FieldMetadataType, + RelationOnDeleteAction, + RelationType, +} from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildWorkflowRunStandardFlatFieldMetadatas = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): Record, FlatFieldMetadata> => ({ + id: createStandardFieldFlatMetadata({ + objectName: 'workflowRun', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'workflowRun', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'workflowRun', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'workflowRun', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + name: createStandardFieldFlatMetadata({ + objectName: 'workflowRun', + workspaceId, + options: { + fieldName: 'name', + type: FieldMetadataType.TEXT, + label: 'Name', + description: 'Name of the workflow run', + icon: 'IconSettingsAutomation', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + enqueuedAt: createStandardFieldFlatMetadata({ + objectName: 'workflowRun', + workspaceId, + options: { + fieldName: 'enqueuedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Workflow run enqueued at', + description: 'Workflow run enqueued at', + icon: 'IconHistory', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + startedAt: createStandardFieldFlatMetadata({ + objectName: 'workflowRun', + workspaceId, + options: { + fieldName: 'startedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Workflow run started at', + description: 'Workflow run started at', + icon: 'IconHistory', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + endedAt: createStandardFieldFlatMetadata({ + objectName: 'workflowRun', + workspaceId, + options: { + fieldName: 'endedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Workflow run ended at', + description: 'Workflow run ended at', + icon: 'IconHistory', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + status: createStandardFieldFlatMetadata({ + objectName: 'workflowRun', + workspaceId, + options: { + fieldName: 'status', + type: FieldMetadataType.SELECT, + label: 'Workflow run status', + description: 'Workflow run status', + icon: 'IconStatusChange', + isNullable: false, + defaultValue: "'NOT_STARTED'", + options: [ + { + value: 'NOT_STARTED', + label: 'Not started', + position: 0, + color: 'gray', + }, + { value: 'RUNNING', label: 'Running', position: 1, color: 'yellow' }, + { value: 'COMPLETED', label: 'Completed', position: 2, color: 'green' }, + { value: 'FAILED', label: 'Failed', position: 3, color: 'red' }, + { value: 'ENQUEUED', label: 'Enqueued', position: 4, color: 'blue' }, + { value: 'STOPPING', label: 'Stopping', position: 5, color: 'orange' }, + { value: 'STOPPED', label: 'Stopped', position: 6, color: 'gray' }, + ], + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdBy: createStandardFieldFlatMetadata({ + objectName: 'workflowRun', + workspaceId, + options: { + fieldName: 'createdBy', + type: FieldMetadataType.ACTOR, + label: 'Executed by', + description: 'The executor of the workflow', + icon: 'IconCreativeCommonsSa', + isNullable: false, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + state: createStandardFieldFlatMetadata({ + objectName: 'workflowRun', + workspaceId, + options: { + fieldName: 'state', + type: FieldMetadataType.RAW_JSON, + label: 'State', + description: 'State of the workflow run', + icon: 'IconHierarchy2', + isNullable: false, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + context: createStandardFieldFlatMetadata({ + objectName: 'workflowRun', + workspaceId, + options: { + fieldName: 'context', + type: FieldMetadataType.RAW_JSON, + label: 'Context', + description: 'Context of the workflow run', + icon: 'IconHierarchy2', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + output: createStandardFieldFlatMetadata({ + objectName: 'workflowRun', + workspaceId, + options: { + fieldName: 'output', + type: FieldMetadataType.RAW_JSON, + label: 'Output', + description: 'Output of the workflow run', + icon: 'IconHierarchy2', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + position: createStandardFieldFlatMetadata({ + objectName: 'workflowRun', + workspaceId, + options: { + fieldName: 'position', + type: FieldMetadataType.POSITION, + label: 'Position', + description: 'Workflow run position', + icon: 'IconHierarchy2', + isSystem: true, + isNullable: false, + defaultValue: 0, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + searchVector: createStandardFieldFlatMetadata({ + objectName: 'workflowRun', + workspaceId, + options: { + fieldName: 'searchVector', + type: FieldMetadataType.TS_VECTOR, + label: 'Search vector', + description: 'Field used for full-text search', + icon: 'IconUser', + isSystem: true, + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + workflowVersion: createStandardRelationFieldFlatMetadata({ + objectName: 'workflowRun', + workspaceId, + options: { + fieldName: 'workflowVersion', + label: 'Workflow version', + description: 'Workflow version linked to the run.', + icon: 'IconVersions', + isNullable: false, + createdAt, + targetObjectName: 'workflowVersion', + targetFieldName: 'runs', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.SET_NULL, + joinColumnName: 'workflowVersionId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + workflow: createStandardRelationFieldFlatMetadata({ + objectName: 'workflowRun', + workspaceId, + options: { + fieldName: 'workflow', + label: 'Workflow', + description: 'Workflow linked to the run.', + icon: 'IconSettingsAutomation', + isNullable: false, + createdAt, + targetObjectName: 'workflow', + targetFieldName: 'runs', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'workflowId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + favorites: createStandardRelationFieldFlatMetadata({ + objectName: 'workflowRun', + workspaceId, + options: { + fieldName: 'favorites', + label: 'Favorites', + description: 'Favorites linked to the workflow run', + icon: 'IconHeart', + isSystem: true, + isNullable: false, + createdAt, + targetObjectName: 'favorite', + targetFieldName: 'workflowRun', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + timelineActivities: createStandardRelationFieldFlatMetadata({ + objectName: 'workflowRun', + workspaceId, + options: { + fieldName: 'timelineActivities', + label: 'Timeline Activities', + description: 'Timeline activities linked to the run', + icon: 'IconTimelineEvent', + isSystem: true, + isNullable: false, + createdAt, + targetObjectName: 'timelineActivity', + targetFieldName: 'workflowRun', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-workflow-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-workflow-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..028e20aba47 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-workflow-standard-flat-field-metadata.util.ts @@ -0,0 +1,320 @@ +import { FieldMetadataType, RelationType } from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildWorkflowStandardFlatFieldMetadatas = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): Record, FlatFieldMetadata> => ({ + id: createStandardFieldFlatMetadata({ + objectName: 'workflow', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'workflow', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'workflow', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'workflow', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + name: createStandardFieldFlatMetadata({ + objectName: 'workflow', + workspaceId, + options: { + fieldName: 'name', + type: FieldMetadataType.TEXT, + label: 'Name', + description: 'The workflow name', + icon: 'IconSettingsAutomation', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + lastPublishedVersionId: createStandardFieldFlatMetadata({ + objectName: 'workflow', + workspaceId, + options: { + fieldName: 'lastPublishedVersionId', + type: FieldMetadataType.TEXT, + label: 'Last published Version Id', + description: 'The workflow last published version id', + icon: 'IconVersions', + isNullable: true, + isUIReadOnly: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + statuses: createStandardFieldFlatMetadata({ + objectName: 'workflow', + workspaceId, + options: { + fieldName: 'statuses', + type: FieldMetadataType.MULTI_SELECT, + label: 'Statuses', + description: 'The current statuses of the workflow versions', + icon: 'IconStatusChange', + isNullable: true, + isUIReadOnly: true, + options: [ + { value: 'DRAFT', label: 'Draft', position: 0, color: 'yellow' }, + { value: 'ACTIVE', label: 'Active', position: 1, color: 'green' }, + { + value: 'DEACTIVATED', + label: 'Deactivated', + position: 2, + color: 'gray', + }, + ], + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + position: createStandardFieldFlatMetadata({ + objectName: 'workflow', + workspaceId, + options: { + fieldName: 'position', + type: FieldMetadataType.POSITION, + label: 'Position', + description: 'Workflow record position', + icon: 'IconHierarchy2', + isSystem: true, + isNullable: false, + defaultValue: 0, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdBy: createStandardFieldFlatMetadata({ + objectName: 'workflow', + workspaceId, + options: { + fieldName: 'createdBy', + type: FieldMetadataType.ACTOR, + label: 'Created by', + description: 'The creator of the record', + icon: 'IconCreativeCommonsSa', + isUIReadOnly: true, + isNullable: false, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + searchVector: createStandardFieldFlatMetadata({ + objectName: 'workflow', + workspaceId, + options: { + fieldName: 'searchVector', + type: FieldMetadataType.TS_VECTOR, + label: 'Search vector', + description: 'Field used for full-text search', + icon: 'IconUser', + isSystem: true, + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + versions: createStandardRelationFieldFlatMetadata({ + objectName: 'workflow', + workspaceId, + options: { + fieldName: 'versions', + label: 'Versions', + description: 'Workflow versions linked to the workflow.', + icon: 'IconVersions', + isUIReadOnly: true, + isNullable: false, + createdAt, + targetObjectName: 'workflowVersion', + targetFieldName: 'workflow', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + runs: createStandardRelationFieldFlatMetadata({ + objectName: 'workflow', + workspaceId, + options: { + fieldName: 'runs', + label: 'Runs', + description: 'Workflow runs linked to the workflow.', + icon: 'IconRun', + isUIReadOnly: true, + isNullable: false, + createdAt, + targetObjectName: 'workflowRun', + targetFieldName: 'workflow', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + eventListeners: createStandardRelationFieldFlatMetadata({ + objectName: 'workflow', + workspaceId, + options: { + fieldName: 'eventListeners', + label: 'Event Listeners', + description: 'Workflow event listeners linked to the workflow.', + icon: 'IconSettingsAutomation', + isSystem: true, + isUIReadOnly: true, + isNullable: false, + createdAt, + targetObjectName: 'workflowAutomatedTrigger', + targetFieldName: 'workflow', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + automatedTriggers: createStandardRelationFieldFlatMetadata({ + objectName: 'workflow', + workspaceId, + options: { + fieldName: 'automatedTriggers', + label: 'Automated Triggers', + description: 'Workflow automated triggers linked to the workflow.', + icon: 'IconSettingsAutomation', + isSystem: true, + isUIReadOnly: true, + isNullable: false, + createdAt, + targetObjectName: 'workflowAutomatedTrigger', + targetFieldName: 'workflow', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + favorites: createStandardRelationFieldFlatMetadata({ + objectName: 'workflow', + workspaceId, + options: { + fieldName: 'favorites', + label: 'Favorites', + description: 'Favorites linked to the workflow', + icon: 'IconHeart', + isSystem: true, + isNullable: false, + createdAt, + targetObjectName: 'favorite', + targetFieldName: 'workflow', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + timelineActivities: createStandardRelationFieldFlatMetadata({ + objectName: 'workflow', + workspaceId, + options: { + fieldName: 'timelineActivities', + label: 'Timeline Activities', + description: 'Timeline activities linked to the workflow', + icon: 'IconTimelineEvent', + isSystem: true, + isNullable: false, + createdAt, + targetObjectName: 'timelineActivity', + targetFieldName: 'workflow', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + attachments: createStandardRelationFieldFlatMetadata({ + objectName: 'workflow', + workspaceId, + options: { + fieldName: 'attachments', + label: 'Attachments', + description: 'Attachments linked to the workflow', + icon: 'IconFileUpload', + isSystem: true, + isNullable: false, + createdAt, + targetObjectName: 'attachment', + targetFieldName: 'workflow', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-workflow-version-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-workflow-version-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..5de787e94df --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-workflow-version-standard-flat-field-metadata.util.ts @@ -0,0 +1,267 @@ +import { + FieldMetadataType, + RelationOnDeleteAction, + RelationType, +} from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildWorkflowVersionStandardFlatFieldMetadatas = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): Record< + AllStandardObjectFieldName<'workflowVersion'>, + FlatFieldMetadata +> => ({ + id: createStandardFieldFlatMetadata({ + objectName: 'workflowVersion', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'workflowVersion', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'workflowVersion', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'workflowVersion', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + name: createStandardFieldFlatMetadata({ + objectName: 'workflowVersion', + workspaceId, + options: { + fieldName: 'name', + type: FieldMetadataType.TEXT, + label: 'Name', + description: 'The workflow version name', + icon: 'IconSettingsAutomation', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + trigger: createStandardFieldFlatMetadata({ + objectName: 'workflowVersion', + workspaceId, + options: { + fieldName: 'trigger', + type: FieldMetadataType.RAW_JSON, + label: 'Version trigger', + description: 'Json object to provide trigger', + icon: 'IconSettingsAutomation', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + steps: createStandardFieldFlatMetadata({ + objectName: 'workflowVersion', + workspaceId, + options: { + fieldName: 'steps', + type: FieldMetadataType.RAW_JSON, + label: 'Version steps', + description: 'Json object to provide steps', + icon: 'IconSettingsAutomation', + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + status: createStandardFieldFlatMetadata({ + objectName: 'workflowVersion', + workspaceId, + options: { + fieldName: 'status', + type: FieldMetadataType.SELECT, + label: 'Version status', + description: 'The workflow version status', + icon: 'IconStatusChange', + isNullable: false, + defaultValue: "'DRAFT'", + options: [ + { value: 'DRAFT', label: 'Draft', position: 0, color: 'yellow' }, + { value: 'ACTIVE', label: 'Active', position: 1, color: 'green' }, + { + value: 'DEACTIVATED', + label: 'Deactivated', + position: 2, + color: 'orange', + }, + { value: 'ARCHIVED', label: 'Archived', position: 3, color: 'gray' }, + ], + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + position: createStandardFieldFlatMetadata({ + objectName: 'workflowVersion', + workspaceId, + options: { + fieldName: 'position', + type: FieldMetadataType.POSITION, + label: 'Position', + description: 'Workflow version position', + icon: 'IconHierarchy2', + isSystem: true, + isNullable: false, + defaultValue: 0, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + searchVector: createStandardFieldFlatMetadata({ + objectName: 'workflowVersion', + workspaceId, + options: { + fieldName: 'searchVector', + type: FieldMetadataType.TS_VECTOR, + label: 'Search vector', + description: 'Field used for full-text search', + icon: 'IconUser', + isSystem: true, + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + workflow: createStandardRelationFieldFlatMetadata({ + objectName: 'workflowVersion', + workspaceId, + options: { + fieldName: 'workflow', + label: 'Workflow', + description: 'WorkflowVersion workflow', + icon: 'IconSettingsAutomation', + isNullable: true, + createdAt, + targetObjectName: 'workflow', + targetFieldName: 'versions', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.CASCADE, + joinColumnName: 'workflowId', + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + runs: createStandardRelationFieldFlatMetadata({ + objectName: 'workflowVersion', + workspaceId, + options: { + fieldName: 'runs', + label: 'Runs', + description: 'Workflow runs linked to the version.', + icon: 'IconRun', + isNullable: true, + createdAt, + targetObjectName: 'workflowRun', + targetFieldName: 'workflowVersion', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + favorites: createStandardRelationFieldFlatMetadata({ + objectName: 'workflowVersion', + workspaceId, + options: { + fieldName: 'favorites', + label: 'Favorites', + description: 'Favorites linked to the workflow version', + icon: 'IconHeart', + isSystem: true, + isNullable: false, + createdAt, + targetObjectName: 'favorite', + targetFieldName: 'workflowVersion', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + timelineActivities: createStandardRelationFieldFlatMetadata({ + objectName: 'workflowVersion', + workspaceId, + options: { + fieldName: 'timelineActivities', + label: 'Timeline Activities', + description: 'Timeline activities linked to the version', + icon: 'IconTimelineEvent', + isSystem: true, + isNullable: false, + createdAt, + targetObjectName: 'timelineActivity', + targetFieldName: 'workflowVersion', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-workspace-member-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-workspace-member-standard-flat-field-metadata.util.ts new file mode 100644 index 00000000000..ae310b2d095 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/compute-workspace-member-standard-flat-field-metadata.util.ts @@ -0,0 +1,510 @@ +import { + FieldMetadataType, + NumberDataType, + RelationType, +} from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { createStandardFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const buildWorkspaceMemberStandardFlatFieldMetadatas = ({ + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): Record< + AllStandardObjectFieldName<'workspaceMember'>, + FlatFieldMetadata +> => ({ + id: createStandardFieldFlatMetadata({ + objectName: 'workspaceMember', + workspaceId, + options: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: 'Id', + description: 'Id', + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName: 'workspaceMember', + workspaceId, + options: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Creation date', + description: 'Creation date', + icon: 'IconCalendar', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName: 'workspaceMember', + workspaceId, + options: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Last update', + description: 'Last time the record was changed', + icon: 'IconCalendarClock', + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName: 'workspaceMember', + workspaceId, + options: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted at', + description: 'Date when the record was deleted', + icon: 'IconCalendarMinus', + isNullable: true, + isUIReadOnly: true, + settings: { displayFormat: 'RELATIVE' }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + position: createStandardFieldFlatMetadata({ + objectName: 'workspaceMember', + workspaceId, + options: { + fieldName: 'position', + type: FieldMetadataType.POSITION, + label: 'Position', + description: 'Workspace member position', + icon: 'IconHierarchy2', + isSystem: true, + isNullable: false, + defaultValue: 0, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + name: createStandardFieldFlatMetadata({ + objectName: 'workspaceMember', + workspaceId, + options: { + fieldName: 'name', + type: FieldMetadataType.FULL_NAME, + label: 'Name', + description: 'Workspace member name', + icon: 'IconCircleUser', + isNullable: false, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + colorScheme: createStandardFieldFlatMetadata({ + objectName: 'workspaceMember', + workspaceId, + options: { + fieldName: 'colorScheme', + type: FieldMetadataType.TEXT, + label: 'Color Scheme', + description: 'Preferred color scheme', + icon: 'IconColorSwatch', + isSystem: true, + isNullable: false, + defaultValue: "'System'", + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + locale: createStandardFieldFlatMetadata({ + objectName: 'workspaceMember', + workspaceId, + options: { + fieldName: 'locale', + type: FieldMetadataType.TEXT, + label: 'Language', + description: 'Preferred language', + icon: 'IconLanguage', + isSystem: true, + isNullable: false, + defaultValue: "'en'", + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + avatarUrl: createStandardFieldFlatMetadata({ + objectName: 'workspaceMember', + workspaceId, + options: { + fieldName: 'avatarUrl', + type: FieldMetadataType.TEXT, + label: 'Avatar Url', + description: 'Workspace member avatar', + icon: 'IconFileUpload', + isSystem: true, + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + userEmail: createStandardFieldFlatMetadata({ + objectName: 'workspaceMember', + workspaceId, + options: { + fieldName: 'userEmail', + type: FieldMetadataType.TEXT, + label: 'User Email', + description: 'Related user email address', + icon: 'IconMail', + isSystem: true, + isNullable: true, + isUnique: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + calendarStartDay: createStandardFieldFlatMetadata({ + objectName: 'workspaceMember', + workspaceId, + options: { + fieldName: 'calendarStartDay', + type: FieldMetadataType.NUMBER, + label: 'Start of the week', + description: "User's preferred start day of the week", + icon: 'IconCalendar', + isSystem: true, + isNullable: false, + defaultValue: 7, + settings: { + dataType: NumberDataType.INT, + }, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + userId: createStandardFieldFlatMetadata({ + objectName: 'workspaceMember', + workspaceId, + options: { + fieldName: 'userId', + type: FieldMetadataType.UUID, + label: 'User Id', + description: 'Associated User Id', + icon: 'IconCircleUsers', + isSystem: true, + isNullable: false, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + timeZone: createStandardFieldFlatMetadata({ + objectName: 'workspaceMember', + workspaceId, + options: { + fieldName: 'timeZone', + type: FieldMetadataType.TEXT, + label: 'Time zone', + description: 'User time zone', + icon: 'IconTimezone', + isSystem: true, + isNullable: false, + defaultValue: "'system'", + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + dateFormat: createStandardFieldFlatMetadata({ + objectName: 'workspaceMember', + workspaceId, + options: { + fieldName: 'dateFormat', + type: FieldMetadataType.SELECT, + label: 'Date format', + description: "User's preferred date format", + icon: 'IconCalendarEvent', + isSystem: true, + isNullable: false, + defaultValue: "'SYSTEM'", + options: [ + { value: 'SYSTEM', label: 'System', position: 0, color: 'turquoise' }, + { + value: 'MONTH_FIRST', + label: 'Month First', + position: 1, + color: 'red', + }, + { + value: 'DAY_FIRST', + label: 'Day First', + position: 2, + color: 'purple', + }, + { value: 'YEAR_FIRST', label: 'Year First', position: 3, color: 'sky' }, + ], + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + timeFormat: createStandardFieldFlatMetadata({ + objectName: 'workspaceMember', + workspaceId, + options: { + fieldName: 'timeFormat', + type: FieldMetadataType.SELECT, + label: 'Time format', + description: "User's preferred time format", + icon: 'IconClock2', + isSystem: true, + isNullable: false, + defaultValue: "'SYSTEM'", + options: [ + { value: 'SYSTEM', label: 'System', position: 0, color: 'sky' }, + { value: 'HOUR_24', label: '24HRS', position: 1, color: 'red' }, + { value: 'HOUR_12', label: '12HRS', position: 2, color: 'purple' }, + ], + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + numberFormat: createStandardFieldFlatMetadata({ + objectName: 'workspaceMember', + workspaceId, + options: { + fieldName: 'numberFormat', + type: FieldMetadataType.SELECT, + label: 'Number format', + description: "User's preferred number format", + icon: 'IconNumbers', + isSystem: true, + isNullable: false, + defaultValue: "'SYSTEM'", + options: [ + { value: 'SYSTEM', label: 'System', position: 0, color: 'turquoise' }, + { + value: 'COMMAS_AND_DOT', + label: 'Commas and dot (1,234.56)', + position: 1, + color: 'blue', + }, + { + value: 'SPACES_AND_COMMA', + label: 'Spaces and comma (1 234,56)', + position: 2, + color: 'green', + }, + { + value: 'DOTS_AND_COMMA', + label: 'Dots and comma (1.234,56)', + position: 3, + color: 'orange', + }, + { + value: 'APOSTROPHE_AND_DOT', + label: "Apostrophe and dot (1'234.56)", + position: 4, + color: 'purple', + }, + ], + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + searchVector: createStandardFieldFlatMetadata({ + objectName: 'workspaceMember', + workspaceId, + options: { + fieldName: 'searchVector', + type: FieldMetadataType.TS_VECTOR, + label: 'Search vector', + description: 'Field used for full-text search', + icon: 'IconUser', + isSystem: true, + isNullable: true, + createdAt, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + assignedTasks: createStandardRelationFieldFlatMetadata({ + objectName: 'workspaceMember', + workspaceId, + options: { + fieldName: 'assignedTasks', + label: 'Assigned tasks', + description: 'Tasks assigned to the workspace member', + icon: 'IconCheckbox', + isNullable: false, + createdAt, + targetObjectName: 'task', + targetFieldName: 'assignee', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + favorites: createStandardRelationFieldFlatMetadata({ + objectName: 'workspaceMember', + workspaceId, + options: { + fieldName: 'favorites', + label: 'Favorites', + description: 'Favorites linked to the workspace member', + icon: 'IconHeart', + isNullable: false, + createdAt, + targetObjectName: 'favorite', + targetFieldName: 'forWorkspaceMember', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + accountOwnerForCompanies: createStandardRelationFieldFlatMetadata({ + objectName: 'workspaceMember', + workspaceId, + options: { + fieldName: 'accountOwnerForCompanies', + label: 'Account Owner For Companies', + description: 'Account owner for companies', + icon: 'IconBriefcase', + isNullable: false, + createdAt, + targetObjectName: 'company', + targetFieldName: 'accountOwner', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + authoredAttachments: createStandardRelationFieldFlatMetadata({ + objectName: 'workspaceMember', + workspaceId, + options: { + fieldName: 'authoredAttachments', + label: 'Authored attachments', + description: 'Attachments created by the workspace member', + icon: 'IconFileImport', + isSystem: true, + isNullable: false, + createdAt, + targetObjectName: 'attachment', + targetFieldName: 'author', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + connectedAccounts: createStandardRelationFieldFlatMetadata({ + objectName: 'workspaceMember', + workspaceId, + options: { + fieldName: 'connectedAccounts', + label: 'Connected accounts', + description: 'Connected accounts', + icon: 'IconAt', + isNullable: false, + createdAt, + targetObjectName: 'connectedAccount', + targetFieldName: 'accountOwner', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + messageParticipants: createStandardRelationFieldFlatMetadata({ + objectName: 'workspaceMember', + workspaceId, + options: { + fieldName: 'messageParticipants', + label: 'Message Participants', + description: 'Message Participants', + icon: 'IconUserCircle', + isNullable: false, + createdAt, + targetObjectName: 'messageParticipant', + targetFieldName: 'workspaceMember', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + blocklist: createStandardRelationFieldFlatMetadata({ + objectName: 'workspaceMember', + workspaceId, + options: { + fieldName: 'blocklist', + label: 'Blocklist', + description: 'Blocklisted handles', + icon: 'IconForbid2', + isNullable: false, + createdAt, + targetObjectName: 'blocklist', + targetFieldName: 'workspaceMember', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + calendarEventParticipants: createStandardRelationFieldFlatMetadata({ + objectName: 'workspaceMember', + workspaceId, + options: { + fieldName: 'calendarEventParticipants', + label: 'Calendar Event Participants', + description: 'Calendar Event Participants', + icon: 'IconCalendar', + isNullable: false, + createdAt, + targetObjectName: 'calendarEventParticipant', + targetFieldName: 'workspaceMember', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), + timelineActivities: createStandardRelationFieldFlatMetadata({ + objectName: 'workspaceMember', + workspaceId, + options: { + fieldName: 'timelineActivities', + label: 'Events', + description: 'Events linked to the workspace member', + icon: 'IconTimelineEvent', + isSystem: true, + isNullable: true, + createdAt, + targetObjectName: 'timelineActivity', + targetFieldName: 'workspaceMember', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardFieldMetadataIdByObjectAndFieldName, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util.ts new file mode 100644 index 00000000000..f469975849e --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/create-standard-field-flat-metadata.util.ts @@ -0,0 +1,109 @@ +import { + type FieldMetadataComplexOption, + type FieldMetadataDefaultOption, + type FieldMetadataDefaultValueForAnyType, + type FieldMetadataType, +} from 'twenty-shared/types'; +import { v4 } from 'uuid'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; +import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { type AllStandardObjectName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-name.type'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +const TWENTY_STANDARD_APPLICATION_ID = + TWENTY_STANDARD_APPLICATION.universalIdentifier; + +export type CreateStandardFieldOptions = { + fieldName: AllStandardObjectFieldName; + type: Exclude; + label: string; + description: string; + icon: string; + isSystem?: boolean; + isNullable?: boolean; + isUnique?: boolean; + isUIReadOnly?: boolean; + defaultValue?: FieldMetadataDefaultValueForAnyType; + settings?: Record | null; + options?: FieldMetadataDefaultOption[] | FieldMetadataComplexOption[] | null; + createdAt: Date; +}; + +export type CreateStandardFieldArgs = { + objectName: O; + workspaceId: string; + options: CreateStandardFieldOptions; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}; + +export const createStandardFieldFlatMetadata = < + O extends AllStandardObjectName, +>({ + objectName, + workspaceId, + options, + standardFieldMetadataIdByObjectAndFieldName, +}: CreateStandardFieldArgs): FlatFieldMetadata => { + const { + fieldName, + type, + label, + description, + icon, + isSystem = false, + isNullable = true, + isUnique = false, + isUIReadOnly = false, + defaultValue = null, + settings = null, + options: fieldOptions = null, + createdAt, + } = options; + + const objectFields = STANDARD_OBJECTS[objectName].fields; + const fieldDefinition = objectFields[fieldName as keyof typeof objectFields]; + const fieldIds = + standardFieldMetadataIdByObjectAndFieldName[objectName].fields; + + const name = fieldName.toString(); + + return { + id: fieldIds[fieldName], + universalIdentifier: fieldDefinition.universalIdentifier, + standardId: null, + applicationId: TWENTY_STANDARD_APPLICATION_ID, + workspaceId, + objectMetadataId: + standardFieldMetadataIdByObjectAndFieldName[objectName].id, + type, + name, + label, + description, + icon, + isCustom: false, + isActive: true, + isSystem, + isNullable, + isUnique, + isUIReadOnly, + isLabelSyncedWithName: false, + standardOverrides: null, + defaultValue, + settings, + options: fieldOptions?.map((option) => ({ ...option, id: v4() })) ?? null, + relationTargetFieldMetadataId: null, + relationTargetObjectMetadataId: null, + morphId: null, + viewFieldIds: [], + viewFilterIds: [], + viewGroupIds: [], + kanbanAggregateOperationViewIds: [], + calendarViewIds: [], + mainGroupByFieldMetadataViewIds: [], + createdAt, + updatedAt: createdAt, + }; +}; diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/create-standard-flat-object-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/create-standard-flat-object-metadata.util.ts new file mode 100644 index 00000000000..77f5b5b2504 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/create-standard-flat-object-metadata.util.ts @@ -0,0 +1,616 @@ +import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; +import { type AllStandardObjectName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-name.type'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; +import { createStandardObjectFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/create-standard-object-flat-metadata.util'; + +export type BuildStandardFlatObjectMetadatasArgs = { + createdAt: Date; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}; + +export type StandardFlatObjectMetadataBuilder = ( + args: BuildStandardFlatObjectMetadatasArgs, +) => FlatObjectMetadata; + +/** + * Record mapping each standard object name to its corresponding object metadata builder. + * Using `satisfies` ensures type safety: if a new standard object is added to STANDARD_OBJECTS, + * TypeScript will error until a builder is added here. + */ +export const STANDARD_FLAT_OBJECT_METADATA_BUILDERS_BY_OBJECT_NAME = { + attachment: (args: BuildStandardFlatObjectMetadatasArgs) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: STANDARD_OBJECTS.attachment.universalIdentifier, + standardId: STANDARD_OBJECTS.attachment.universalIdentifier, + nameSingular: 'attachment', + namePlural: 'attachments', + labelSingular: 'Attachment', + labelPlural: 'Attachments', + description: 'An attachment', + icon: 'IconFileImport', + isSystem: true, + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'name', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), + blocklist: (args: BuildStandardFlatObjectMetadatasArgs) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: STANDARD_OBJECTS.blocklist.universalIdentifier, + standardId: STANDARD_OBJECTS.blocklist.universalIdentifier, + nameSingular: 'blocklist', + namePlural: 'blocklists', + labelSingular: 'Blocklist', + labelPlural: 'Blocklists', + description: 'Blocklist', + icon: 'IconForbid2', + isSystem: true, + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'handle', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), + calendarChannelEventAssociation: ( + args: BuildStandardFlatObjectMetadatasArgs, + ) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: + STANDARD_OBJECTS.calendarChannelEventAssociation.universalIdentifier, + standardId: + STANDARD_OBJECTS.calendarChannelEventAssociation.universalIdentifier, + nameSingular: 'calendarChannelEventAssociation', + namePlural: 'calendarChannelEventAssociations', + labelSingular: 'Calendar Channel Event Association', + labelPlural: 'Calendar Channel Event Associations', + description: 'Calendar Channel Event Associations', + icon: 'IconCalendar', + isSystem: true, + isAuditLogged: false, + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'id', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), + calendarChannel: (args: BuildStandardFlatObjectMetadatasArgs) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: + STANDARD_OBJECTS.calendarChannel.universalIdentifier, + standardId: STANDARD_OBJECTS.calendarChannel.universalIdentifier, + nameSingular: 'calendarChannel', + namePlural: 'calendarChannels', + labelSingular: 'Calendar Channel', + labelPlural: 'Calendar Channels', + description: 'Calendar Channels', + icon: 'IconCalendar', + isSystem: true, + isAuditLogged: false, + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'handle', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), + calendarEventParticipant: (args: BuildStandardFlatObjectMetadatasArgs) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: + STANDARD_OBJECTS.calendarEventParticipant.universalIdentifier, + standardId: + STANDARD_OBJECTS.calendarEventParticipant.universalIdentifier, + nameSingular: 'calendarEventParticipant', + namePlural: 'calendarEventParticipants', + labelSingular: 'Calendar event participant', + labelPlural: 'Calendar event participants', + description: 'Calendar event participants', + icon: 'IconCalendar', + isSystem: true, + isAuditLogged: false, + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'handle', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), + calendarEvent: (args: BuildStandardFlatObjectMetadatasArgs) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: STANDARD_OBJECTS.calendarEvent.universalIdentifier, + standardId: STANDARD_OBJECTS.calendarEvent.universalIdentifier, + nameSingular: 'calendarEvent', + namePlural: 'calendarEvents', + labelSingular: 'Calendar event', + labelPlural: 'Calendar events', + description: 'Calendar events', + icon: 'IconCalendar', + isSystem: true, + isAuditLogged: false, + isUIReadOnly: true, + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'title', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), + company: (args: BuildStandardFlatObjectMetadatasArgs) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: STANDARD_OBJECTS.company.universalIdentifier, + standardId: STANDARD_OBJECTS.company.universalIdentifier, + nameSingular: 'company', + namePlural: 'companies', + labelSingular: 'Company', + labelPlural: 'Companies', + description: 'A company', + icon: 'IconBuildingSkyscraper', + isSearchable: true, + shortcut: 'C', + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'name', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), + connectedAccount: (args: BuildStandardFlatObjectMetadatasArgs) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: + STANDARD_OBJECTS.connectedAccount.universalIdentifier, + standardId: STANDARD_OBJECTS.connectedAccount.universalIdentifier, + nameSingular: 'connectedAccount', + namePlural: 'connectedAccounts', + labelSingular: 'Connected Account', + labelPlural: 'Connected Accounts', + description: 'A connected account', + icon: 'IconAt', + isSystem: true, + isAuditLogged: false, + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'handle', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), + dashboard: (args: BuildStandardFlatObjectMetadatasArgs) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: STANDARD_OBJECTS.dashboard.universalIdentifier, + standardId: STANDARD_OBJECTS.dashboard.universalIdentifier, + nameSingular: 'dashboard', + namePlural: 'dashboards', + labelSingular: 'Dashboard', + labelPlural: 'Dashboards', + description: 'A dashboard', + icon: 'IconLayoutDashboard', + isSearchable: true, + shortcut: 'D', + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'title', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), + favorite: (args: BuildStandardFlatObjectMetadatasArgs) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: STANDARD_OBJECTS.favorite.universalIdentifier, + standardId: STANDARD_OBJECTS.favorite.universalIdentifier, + nameSingular: 'favorite', + namePlural: 'favorites', + labelSingular: 'Favorite', + labelPlural: 'Favorites', + description: 'A favorite', + icon: 'IconHeart', + isSystem: true, + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'id', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), + favoriteFolder: (args: BuildStandardFlatObjectMetadatasArgs) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: + STANDARD_OBJECTS.favoriteFolder.universalIdentifier, + standardId: STANDARD_OBJECTS.favoriteFolder.universalIdentifier, + nameSingular: 'favoriteFolder', + namePlural: 'favoriteFolders', + labelSingular: 'Favorite Folder', + labelPlural: 'Favorite Folders', + description: 'A favorite folder', + icon: 'IconFolder', + isSystem: true, + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'id', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), + messageChannelMessageAssociation: ( + args: BuildStandardFlatObjectMetadatasArgs, + ) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: + STANDARD_OBJECTS.messageChannelMessageAssociation.universalIdentifier, + standardId: + STANDARD_OBJECTS.messageChannelMessageAssociation.universalIdentifier, + nameSingular: 'messageChannelMessageAssociation', + namePlural: 'messageChannelMessageAssociations', + labelSingular: 'Message Channel Message Association', + labelPlural: 'Message Channel Message Associations', + description: 'Message Synced with a Message Channel', + icon: 'IconMessage', + isSystem: true, + isAuditLogged: false, + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'id', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), + messageChannel: (args: BuildStandardFlatObjectMetadatasArgs) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: + STANDARD_OBJECTS.messageChannel.universalIdentifier, + standardId: STANDARD_OBJECTS.messageChannel.universalIdentifier, + nameSingular: 'messageChannel', + namePlural: 'messageChannels', + labelSingular: 'Message Channel', + labelPlural: 'Message Channels', + description: 'Message Channels', + icon: 'IconMessage', + isSystem: true, + isAuditLogged: false, + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'handle', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), + messageFolder: (args: BuildStandardFlatObjectMetadatasArgs) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: STANDARD_OBJECTS.messageFolder.universalIdentifier, + standardId: STANDARD_OBJECTS.messageFolder.universalIdentifier, + nameSingular: 'messageFolder', + namePlural: 'messageFolders', + labelSingular: 'Message Folder', + labelPlural: 'Message Folders', + description: 'Message Folders', + icon: 'IconFolder', + isSystem: true, + isAuditLogged: false, + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'id', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), + messageParticipant: (args: BuildStandardFlatObjectMetadatasArgs) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: + STANDARD_OBJECTS.messageParticipant.universalIdentifier, + standardId: STANDARD_OBJECTS.messageParticipant.universalIdentifier, + nameSingular: 'messageParticipant', + namePlural: 'messageParticipants', + labelSingular: 'Message Participant', + labelPlural: 'Message Participants', + description: 'Message Participants', + icon: 'IconUserCircle', + isSystem: true, + isAuditLogged: false, + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'handle', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), + messageThread: (args: BuildStandardFlatObjectMetadatasArgs) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: STANDARD_OBJECTS.messageThread.universalIdentifier, + standardId: STANDARD_OBJECTS.messageThread.universalIdentifier, + nameSingular: 'messageThread', + namePlural: 'messageThreads', + labelSingular: 'Message Thread', + labelPlural: 'Message Threads', + description: 'Message Thread', + icon: 'IconMessage', + isSystem: true, + isAuditLogged: false, + isUIReadOnly: true, + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'id', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), + message: (args: BuildStandardFlatObjectMetadatasArgs) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: STANDARD_OBJECTS.message.universalIdentifier, + standardId: STANDARD_OBJECTS.message.universalIdentifier, + nameSingular: 'message', + namePlural: 'messages', + labelSingular: 'Message', + labelPlural: 'Messages', + description: 'Message', + icon: 'IconMessage', + isSystem: true, + isAuditLogged: false, + isUIReadOnly: true, + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'subject', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), + note: (args: BuildStandardFlatObjectMetadatasArgs) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: STANDARD_OBJECTS.note.universalIdentifier, + standardId: STANDARD_OBJECTS.note.universalIdentifier, + nameSingular: 'note', + namePlural: 'notes', + labelSingular: 'Note', + labelPlural: 'Notes', + description: 'A note', + icon: 'IconNotes', + isSearchable: true, + shortcut: 'N', + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'title', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), + noteTarget: (args: BuildStandardFlatObjectMetadatasArgs) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: STANDARD_OBJECTS.noteTarget.universalIdentifier, + standardId: STANDARD_OBJECTS.noteTarget.universalIdentifier, + nameSingular: 'noteTarget', + namePlural: 'noteTargets', + labelSingular: 'Note Target', + labelPlural: 'Note Targets', + description: 'A note target', + icon: 'IconCheckbox', + isSystem: true, + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'id', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), + opportunity: (args: BuildStandardFlatObjectMetadatasArgs) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: STANDARD_OBJECTS.opportunity.universalIdentifier, + standardId: STANDARD_OBJECTS.opportunity.universalIdentifier, + nameSingular: 'opportunity', + namePlural: 'opportunities', + labelSingular: 'Opportunity', + labelPlural: 'Opportunities', + description: 'An opportunity', + icon: 'IconTargetArrow', + isSearchable: true, + shortcut: 'O', + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'name', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), + person: (args: BuildStandardFlatObjectMetadatasArgs) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: STANDARD_OBJECTS.person.universalIdentifier, + standardId: STANDARD_OBJECTS.person.universalIdentifier, + nameSingular: 'person', + namePlural: 'people', + labelSingular: 'Person', + labelPlural: 'People', + description: 'A person', + icon: 'IconUser', + isSearchable: true, + shortcut: 'P', + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'name', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), + task: (args: BuildStandardFlatObjectMetadatasArgs) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: STANDARD_OBJECTS.task.universalIdentifier, + standardId: STANDARD_OBJECTS.task.universalIdentifier, + nameSingular: 'task', + namePlural: 'tasks', + labelSingular: 'Task', + labelPlural: 'Tasks', + description: 'A task', + icon: 'IconCheckbox', + isSearchable: true, + shortcut: 'T', + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'title', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), + taskTarget: (args: BuildStandardFlatObjectMetadatasArgs) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: STANDARD_OBJECTS.taskTarget.universalIdentifier, + standardId: STANDARD_OBJECTS.taskTarget.universalIdentifier, + nameSingular: 'taskTarget', + namePlural: 'taskTargets', + labelSingular: 'Task Target', + labelPlural: 'Task Targets', + description: 'A task target', + icon: 'IconCheckbox', + isSystem: true, + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'id', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), + timelineActivity: (args: BuildStandardFlatObjectMetadatasArgs) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: + STANDARD_OBJECTS.timelineActivity.universalIdentifier, + standardId: STANDARD_OBJECTS.timelineActivity.universalIdentifier, + nameSingular: 'timelineActivity', + namePlural: 'timelineActivities', + labelSingular: 'Timeline Activity', + labelPlural: 'Timeline Activities', + description: + 'Aggregated / filtered event to be displayed on the timeline', + icon: 'IconTimelineEvent', + isSystem: true, + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'name', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), + workflow: (args: BuildStandardFlatObjectMetadatasArgs) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: STANDARD_OBJECTS.workflow.universalIdentifier, + standardId: STANDARD_OBJECTS.workflow.universalIdentifier, + nameSingular: 'workflow', + namePlural: 'workflows', + labelSingular: 'Workflow', + labelPlural: 'Workflows', + description: 'A workflow', + icon: 'IconSettingsAutomation', + isSearchable: true, + shortcut: 'W', + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'name', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), + workflowAutomatedTrigger: (args: BuildStandardFlatObjectMetadatasArgs) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: + STANDARD_OBJECTS.workflowAutomatedTrigger.universalIdentifier, + standardId: + STANDARD_OBJECTS.workflowAutomatedTrigger.universalIdentifier, + nameSingular: 'workflowAutomatedTrigger', + namePlural: 'workflowAutomatedTriggers', + labelSingular: 'Workflow Automated Trigger', + labelPlural: 'Workflow Automated Triggers', + description: 'A workflow automated trigger', + icon: 'IconSettingsAutomation', + isSystem: true, + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'id', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), + workflowRun: (args: BuildStandardFlatObjectMetadatasArgs) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: STANDARD_OBJECTS.workflowRun.universalIdentifier, + standardId: STANDARD_OBJECTS.workflowRun.universalIdentifier, + nameSingular: 'workflowRun', + namePlural: 'workflowRuns', + labelSingular: 'Workflow Run', + labelPlural: 'Workflow Runs', + description: 'A workflow run', + icon: 'IconHistoryToggle', + isSearchable: true, + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'name', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), + workflowVersion: (args: BuildStandardFlatObjectMetadatasArgs) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: + STANDARD_OBJECTS.workflowVersion.universalIdentifier, + standardId: STANDARD_OBJECTS.workflowVersion.universalIdentifier, + nameSingular: 'workflowVersion', + namePlural: 'workflowVersions', + labelSingular: 'Workflow Version', + labelPlural: 'Workflow Versions', + description: 'A workflow version', + icon: 'IconVersions', + isSearchable: true, + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'name', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), + workspaceMember: (args: BuildStandardFlatObjectMetadatasArgs) => + createStandardObjectFlatMetadata({ + options: { + universalIdentifier: + STANDARD_OBJECTS.workspaceMember.universalIdentifier, + standardId: STANDARD_OBJECTS.workspaceMember.universalIdentifier, + nameSingular: 'workspaceMember', + namePlural: 'workspaceMembers', + labelSingular: 'Workspace Member', + labelPlural: 'Workspace Members', + description: 'A workspace member', + icon: 'IconUserCircle', + isSystem: true, + createdAt: args.createdAt, + labelIdentifierFieldMetadataName: 'name', + }, + workspaceId: args.workspaceId, + standardFieldMetadataIdByObjectAndFieldName: + args.standardFieldMetadataIdByObjectAndFieldName, + }), +} satisfies Record; diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/create-standard-object-flat-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/create-standard-object-flat-metadata.util.ts new file mode 100644 index 00000000000..fc2910ab027 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/create-standard-object-flat-metadata.util.ts @@ -0,0 +1,86 @@ +import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; +import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { type AllStandardObjectName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-name.type'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +const TWENTY_STANDARD_APPLICATION_ID = + TWENTY_STANDARD_APPLICATION.universalIdentifier; + +export const createStandardObjectFlatMetadata = < + T extends AllStandardObjectName, +>({ + options: { + universalIdentifier, + standardId, + nameSingular, + namePlural, + labelSingular, + labelPlural, + description, + icon, + isSystem = false, + isSearchable = false, + isAuditLogged = true, + isUIReadOnly = false, + shortcut = null, + createdAt, + labelIdentifierFieldMetadataName, + }, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, +}: { + options: { + universalIdentifier: string; + standardId: string; + nameSingular: T; + namePlural: string; + labelSingular: string; + labelPlural: string; + description: string; + icon: string; + isSystem?: boolean; + isSearchable?: boolean; + isAuditLogged?: boolean; + isUIReadOnly?: boolean; + shortcut?: string | null; + createdAt: Date; + labelIdentifierFieldMetadataName: AllStandardObjectFieldName; + }; + workspaceId: string; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}): FlatObjectMetadata => ({ + universalIdentifier, + standardId, + applicationId: TWENTY_STANDARD_APPLICATION_ID, + workspaceId, + nameSingular, + namePlural, + labelSingular, + labelPlural, + description, + icon, + isCustom: false, + isRemote: false, + isActive: true, + isSystem, + isSearchable, + isAuditLogged, + isUIReadOnly, + isLabelSyncedWithName: false, + standardOverrides: null, + duplicateCriteria: null, + shortcut, + labelIdentifierFieldMetadataId: + standardFieldMetadataIdByObjectAndFieldName[nameSingular].fields[ + labelIdentifierFieldMetadataName + ], + imageIdentifierFieldMetadataId: null, + targetTableName: 'DEPRECATED', + fieldMetadataIds: [], + indexMetadataIds: [], + viewIds: [], + createdAt, + updatedAt: createdAt, + id: standardFieldMetadataIdByObjectAndFieldName[nameSingular].id, +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util.ts new file mode 100644 index 00000000000..3052cd0d01b --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/create-standard-relation-field-flat-metadata.util.ts @@ -0,0 +1,118 @@ +import { + type FieldMetadataComplexOption, + type FieldMetadataDefaultOption, + type FieldMetadataDefaultValueForAnyType, + type FieldMetadataSettings, + FieldMetadataType, +} from 'twenty-shared/types'; + +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; +import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { type AllStandardObjectName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-name.type'; +import { type StandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +const TWENTY_STANDARD_APPLICATION_ID = + TWENTY_STANDARD_APPLICATION.universalIdentifier; + +export type CreateStandardRelationFieldOptions< + O extends AllStandardObjectName, + T extends AllStandardObjectName, +> = { + fieldName: AllStandardObjectFieldName; + label: string; + description: string; + icon: string; + targetObjectName: T; + targetFieldName: AllStandardObjectFieldName; + isSystem?: boolean; + isNullable?: boolean; + isUIReadOnly?: boolean; + defaultValue?: FieldMetadataDefaultValueForAnyType; + settings: FieldMetadataSettings; + options?: FieldMetadataDefaultOption[] | FieldMetadataComplexOption[] | null; + createdAt: Date; +}; + +export type CreateStandardRelationFieldArgs< + O extends AllStandardObjectName, + T extends AllStandardObjectName, +> = { + objectName: O; + workspaceId: string; + options: CreateStandardRelationFieldOptions; + standardFieldMetadataIdByObjectAndFieldName: StandardFieldMetadataIdByObjectAndFieldName; +}; + +export const createStandardRelationFieldFlatMetadata = < + O extends AllStandardObjectName, + T extends AllStandardObjectName, +>({ + objectName, + workspaceId, + options, + standardFieldMetadataIdByObjectAndFieldName, +}: CreateStandardRelationFieldArgs): FlatFieldMetadata => { + const { + fieldName, + label, + description, + icon, + targetObjectName, + targetFieldName, + isSystem = false, + isNullable = true, + isUIReadOnly = false, + defaultValue = null, + settings, + options: fieldOptions = null, + createdAt, + } = options; + + const objectFields = STANDARD_OBJECTS[objectName].fields; + const fieldDefinition = objectFields[fieldName as keyof typeof objectFields]; + const fieldIds = + standardFieldMetadataIdByObjectAndFieldName[objectName].fields; + + const targetFieldIds = + standardFieldMetadataIdByObjectAndFieldName[targetObjectName].fields; + + return { + id: fieldIds[fieldName as keyof typeof fieldIds], + universalIdentifier: fieldDefinition.universalIdentifier, + standardId: null, + applicationId: TWENTY_STANDARD_APPLICATION_ID, + workspaceId, + objectMetadataId: + standardFieldMetadataIdByObjectAndFieldName[objectName].id, + type: FieldMetadataType.RELATION, + name: fieldName.toString(), + label, + description, + icon, + isCustom: false, + isActive: true, + isSystem, + isNullable, + isUnique: false, + isUIReadOnly, + isLabelSyncedWithName: false, + standardOverrides: null, + defaultValue, + settings, + options: fieldOptions, + relationTargetFieldMetadataId: targetFieldIds[targetFieldName], + relationTargetObjectMetadataId: + standardFieldMetadataIdByObjectAndFieldName[targetObjectName].id, + morphId: null, + viewFieldIds: [], + viewFilterIds: [], + viewGroupIds: [], + kanbanAggregateOperationViewIds: [], + calendarViewIds: [], + mainGroupByFieldMetadataViewIds: [], + createdAt, + updatedAt: createdAt, + }; +}; diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util.ts new file mode 100644 index 00000000000..a2389358671 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util.ts @@ -0,0 +1,43 @@ +import { v4 } from 'uuid'; + +import { STANDARD_OBJECTS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-object.constant'; +import { type AllStandardObjectFieldName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-field-name.type'; +import { type AllStandardObjectName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-name.type'; + +export type StandardFieldMetadataIdByObjectAndFieldName = { + [O in AllStandardObjectName]: { + id: string; + fields: Record, string>; + }; +}; + +// TODO remove once we have refactored the builder to iterate over universalIdentifier only +export const getStandardFieldMetadataIdByObjectAndFieldName = + (): StandardFieldMetadataIdByObjectAndFieldName => { + const result = {} as StandardFieldMetadataIdByObjectAndFieldName; + + for (const objectName of Object.keys( + STANDARD_OBJECTS, + ) as AllStandardObjectName[]) { + const fieldNames = Object.keys( + STANDARD_OBJECTS[objectName].fields, + ) as AllStandardObjectFieldName[]; + + const fieldIds = {} as Record< + AllStandardObjectFieldName, + string + >; + + for (const fieldName of fieldNames) { + fieldIds[fieldName] = v4(); + } + + result[objectName] = { + // @ts-expect-error ignore this + fields: fieldIds, + id: v4(), + }; + } + + return result; + }; diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/twenty-standard-application-all-flat-entity-maps.constant.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/twenty-standard-application-all-flat-entity-maps.constant.ts new file mode 100644 index 00000000000..379ef276c41 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/twenty-standard-application-all-flat-entity-maps.constant.ts @@ -0,0 +1,93 @@ +import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type'; +import { buildStandardFlatFieldMetadataMaps } from 'src/engine/workspace-manager/twenty-standard-application/utils/build-standard-flat-field-metadata-maps.util'; +import { buildStandardFlatObjectMetadataMaps } from 'src/engine/workspace-manager/twenty-standard-application/utils/build-standard-flat-object-metadata-maps.util'; +import { getStandardFieldMetadataIdByObjectAndFieldName } from 'src/engine/workspace-manager/twenty-standard-application/utils/get-standard-field-metadata-id-by-object-and-field-name.util'; + +export const computeTwentyStandardApplicationAllFlatEntityMaps = ({ + createdAt, + workspaceId, +}: { + createdAt: Date; + workspaceId: string; +}): AllFlatEntityMaps => { + const standardFieldMetadataIdByObjectAndFieldName = + getStandardFieldMetadataIdByObjectAndFieldName(); + + const builderArgs = { + createdAt, + workspaceId, + standardFieldMetadataIdByObjectAndFieldName, + }; + + // Build object metadata maps using addFlatEntityToFlatEntityMapsOrThrow to prevent duplicate IDs + const flatObjectMetadataMaps = + buildStandardFlatObjectMetadataMaps(builderArgs); + + // Build field metadata maps using addFlatEntityToFlatEntityMapsOrThrow to prevent duplicate IDs + const flatFieldMetadataMaps = buildStandardFlatFieldMetadataMaps(builderArgs); + + return { + flatAgentMaps: { + byId: {}, + idByUniversalIdentifier: {}, + universalIdentifiersByApplicationId: {}, + }, + flatCronTriggerMaps: { + byId: {}, + idByUniversalIdentifier: {}, + universalIdentifiersByApplicationId: {}, + }, + flatDatabaseEventTriggerMaps: { + byId: {}, + idByUniversalIdentifier: {}, + universalIdentifiersByApplicationId: {}, + }, + flatFieldMetadataMaps, + flatIndexMaps: { + byId: {}, + idByUniversalIdentifier: {}, + universalIdentifiersByApplicationId: {}, + }, + flatObjectMetadataMaps, + flatRoleMaps: { + byId: {}, + idByUniversalIdentifier: {}, + universalIdentifiersByApplicationId: {}, + }, + flatRoleTargetMaps: { + byId: {}, + idByUniversalIdentifier: {}, + universalIdentifiersByApplicationId: {}, + }, + flatRouteTriggerMaps: { + byId: {}, + idByUniversalIdentifier: {}, + universalIdentifiersByApplicationId: {}, + }, + flatServerlessFunctionMaps: { + byId: {}, + idByUniversalIdentifier: {}, + universalIdentifiersByApplicationId: {}, + }, + flatViewFieldMaps: { + byId: {}, + idByUniversalIdentifier: {}, + universalIdentifiersByApplicationId: {}, + }, + flatViewFilterMaps: { + byId: {}, + idByUniversalIdentifier: {}, + universalIdentifiersByApplicationId: {}, + }, + flatViewGroupMaps: { + byId: {}, + idByUniversalIdentifier: {}, + universalIdentifiersByApplicationId: {}, + }, + flatViewMaps: { + byId: {}, + idByUniversalIdentifier: {}, + universalIdentifiersByApplicationId: {}, + }, + }; +}; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/validators/services/flat-field-metadata-validator.service.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/validators/services/flat-field-metadata-validator.service.ts index 6e3d45f382c..5a230abcb3b 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/validators/services/flat-field-metadata-validator.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/validators/services/flat-field-metadata-validator.service.ts @@ -131,11 +131,15 @@ export class FlatFieldMetadataValidatorService { if (updates.some((update) => update.property === 'name')) { validationResult.errors.push( - ...validateFlatFieldMetadataName(flatFieldMetadataToValidate.name), + ...validateFlatFieldMetadataName({ + name: flatFieldMetadataToValidate.name, + buildOptions, + }), ...validateFlatFieldMetadataNameAvailability({ name: flatFieldMetadataToValidate.name, flatFieldMetadataMaps: optimisticFlatFieldMetadataMaps, flatObjectMetadata, + buildOptions, }), ); } @@ -307,6 +311,7 @@ export class FlatFieldMetadataValidatorService { name: flatFieldMetadataToValidate.name, flatFieldMetadataMaps: optimisticFlatFieldMetadataMaps, flatObjectMetadata: parentFlatObjectMetadata, + buildOptions, }), ); } @@ -324,7 +329,10 @@ export class FlatFieldMetadataValidatorService { } validationResult.errors.push( - ...validateFlatFieldMetadataName(flatFieldMetadataToValidate.name), + ...validateFlatFieldMetadataName({ + name: flatFieldMetadataToValidate.name, + buildOptions, + }), ); validationResult.errors.push( diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/validators/services/flat-object-metadata-validator.service.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/validators/services/flat-object-metadata-validator.service.ts index 1a49d705e6f..f0d15a9efc9 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/validators/services/flat-object-metadata-validator.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/validators/services/flat-object-metadata-validator.service.ts @@ -19,6 +19,7 @@ export class FlatObjectMetadataValidatorService { public validateFlatObjectMetadataUpdate({ flatEntityId, flatEntityUpdates, + buildOptions, optimisticFlatEntityMapsAndRelatedFlatEntityMaps: { flatObjectMetadataMaps: optimisticFlatObjectMetadataMaps, flatFieldMetadataMaps, @@ -85,6 +86,7 @@ export class FlatObjectMetadataValidatorService { ...validateFlatObjectMetadataIdentifiers({ flatObjectMetadata: updatedFlatObjectMetadata, flatFieldMetadataMaps, + buildOptions, }), ); } @@ -154,6 +156,7 @@ export class FlatObjectMetadataValidatorService { flatObjectMetadataMaps: optimisticFlatObjectMetadataMaps, flatFieldMetadataMaps, }, + buildOptions, }: FlatEntityValidationArgs< typeof ALL_METADATA_NAME.objectMetadata >): FailedFlatEntityValidation { @@ -192,6 +195,7 @@ export class FlatObjectMetadataValidatorService { ...validateFlatObjectMetadataIdentifiers({ flatObjectMetadata: flatObjectMetadataToValidate, flatFieldMetadataMaps, + buildOptions, }), ); objectValidationResult.errors.push( diff --git a/packages/twenty-server/test/integration/graphql/suites/workspace/successful-user-and-workspace-creation.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/workspace/successful-user-and-workspace-creation.integration-spec.ts index 3b62d125202..2fc70af8fbe 100644 --- a/packages/twenty-server/test/integration/graphql/suites/workspace/successful-user-and-workspace-creation.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/workspace/successful-user-and-workspace-creation.integration-spec.ts @@ -12,7 +12,7 @@ import { jestExpectToBeDefined } from 'test/utils/jest-expect-to-be-defined.util import { isDefined } from 'twenty-shared/utils'; import { WorkspaceActivationStatus } from 'twenty-shared/workspace'; -import { TWENTY_STANDARD_APPLICATION } from 'src/engine/core-modules/application/constants/twenty-standard-applications'; +import { TWENTY_STANDARD_APPLICATION } from 'src/engine/workspace-manager/twenty-standard-application/constants/twenty-standard-applications'; describe('Successful user and workspace creation', () => { let createdUserAccessToken: string | undefined; diff --git a/packages/twenty-server/test/integration/metadata/suites/field-metadata/enum/__snapshots__/failing-create-one-field-metadata-enum-v2.integration-spec.ts.snap b/packages/twenty-server/test/integration/metadata/suites/field-metadata/enum/__snapshots__/failing-create-one-field-metadata-enum-v2.integration-spec.ts.snap index 954f54fb52d..9410a84430f 100644 --- a/packages/twenty-server/test/integration/metadata/suites/field-metadata/enum/__snapshots__/failing-create-one-field-metadata-enum-v2.integration-spec.ts.snap +++ b/packages/twenty-server/test/integration/metadata/suites/field-metadata/enum/__snapshots__/failing-create-one-field-metadata-enum-v2.integration-spec.ts.snap @@ -149,6 +149,7 @@ exports[`Failing create field metadata MULTI_SELECT tests suite v2 Create should { "code": "INVALID_FIELD_INPUT", "message": "Label must not contain a comma", + "userFriendlyMessage": "Label must not contain a comma", "value": "Option ,1", }, ], @@ -215,6 +216,7 @@ exports[`Failing create field metadata MULTI_SELECT tests suite v2 Create should { "code": "INVALID_FIELD_INPUT", "message": "Duplicated option id", + "userFriendlyMessage": "Duplicated option id", "value": [ { "color": "green", @@ -296,6 +298,7 @@ exports[`Failing create field metadata MULTI_SELECT tests suite v2 Create should { "code": "INVALID_FIELD_INPUT", "message": "Duplicated option position", + "userFriendlyMessage": "Duplicated option position", "value": [ { "color": "green", @@ -377,6 +380,7 @@ exports[`Failing create field metadata MULTI_SELECT tests suite v2 Create should { "code": "INVALID_FIELD_INPUT", "message": "Duplicated option value", + "userFriendlyMessage": "Duplicated option value", "value": [ { "color": "green", @@ -458,6 +462,7 @@ exports[`Failing create field metadata MULTI_SELECT tests suite v2 Create should { "code": "INVALID_FIELD_INPUT", "message": "Duplicated option value", + "userFriendlyMessage": "Duplicated option value", "value": [ { "color": "green", @@ -539,6 +544,7 @@ exports[`Failing create field metadata MULTI_SELECT tests suite v2 Create should { "code": "INVALID_FIELD_INPUT", "message": "If defined default value must contain at least one value", + "userFriendlyMessage": "If defined default value must contain at least one value", "value": [], }, ], @@ -672,11 +678,13 @@ exports[`Failing create field metadata MULTI_SELECT tests suite v2 Create should { "code": "INVALID_FIELD_INPUT", "message": "Default value should be as quoted string", + "userFriendlyMessage": "Default value should be as quoted string", "value": "", }, { "code": "INVALID_FIELD_INPUT", "message": "Default value "" must be one of the option values", + "userFriendlyMessage": "Default value "" must be one of the option values", "value": "", }, ], @@ -743,6 +751,7 @@ exports[`Failing create field metadata MULTI_SELECT tests suite v2 Create should { "code": "INVALID_FIELD_INPUT", "message": "Option id is invalid", + "userFriendlyMessage": "Option id is invalid", "value": "", }, ], @@ -877,6 +886,7 @@ exports[`Failing create field metadata MULTI_SELECT tests suite v2 Create should "code": "INVALID_FIELD_INPUT", "message": "Option value must be a string of at least one character", "userFriendlyMessage": "Option value format not supported", + "value": "", }, ], "flatEntityMinimalInformation": { @@ -942,21 +952,25 @@ exports[`Failing create field metadata MULTI_SELECT tests suite v2 Create should { "code": "INVALID_FIELD_INPUT", "message": "Default value should be as quoted string", + "userFriendlyMessage": "Default value should be as quoted string", "value": "invalid", }, { "code": "INVALID_FIELD_INPUT", "message": "Default value "invalid" must be one of the option values", + "userFriendlyMessage": "Default value "invalid" must be one of the option values", "value": "invalid", }, { "code": "INVALID_FIELD_INPUT", "message": "Default value should be as quoted string", + "userFriendlyMessage": "Default value should be as quoted string", "value": "format", }, { "code": "INVALID_FIELD_INPUT", "message": "Default value "format" must be one of the option values", + "userFriendlyMessage": "Default value "format" must be one of the option values", "value": "format", }, ], @@ -1023,6 +1037,7 @@ exports[`Failing create field metadata MULTI_SELECT tests suite v2 Create should { "code": "INVALID_FIELD_INPUT", "message": "Option id is invalid", + "userFriendlyMessage": "Option id is invalid", "value": "not a uuid", }, ], @@ -1089,6 +1104,7 @@ exports[`Failing create field metadata MULTI_SELECT tests suite v2 Create should { "code": "INVALID_FIELD_INPUT", "message": "Value must be in UPPER_CASE and follow snake_case "Option 1 and some other things, /"", + "userFriendlyMessage": "Value must be in UPPER_CASE and follow snake_case "Option 1 and some other things, /"", "value": "Option 1 and some other things, /", }, ], @@ -1289,6 +1305,7 @@ exports[`Failing create field metadata MULTI_SELECT tests suite v2 Create should { "code": "INVALID_FIELD_INPUT", "message": "Option id is invalid", + "userFriendlyMessage": "Option id is invalid", "value": 22222, }, ], @@ -1423,6 +1440,7 @@ exports[`Failing create field metadata MULTI_SELECT tests suite v2 Create should "code": "INVALID_FIELD_INPUT", "message": "Option value must be a string of at least one character", "userFriendlyMessage": "Option value format not supported", + "value": 22222, }, ], "flatEntityMinimalInformation": { @@ -1488,11 +1506,12 @@ exports[`Failing create field metadata MULTI_SELECT tests suite v2 Create should { "code": "INVALID_FIELD_INPUT", "message": "Option id is required", - "value": null, + "userFriendlyMessage": "Option id is required", }, { "code": "INVALID_FIELD_INPUT", "message": "Option id is invalid", + "userFriendlyMessage": "Option id is invalid", "value": null, }, ], @@ -1758,11 +1777,13 @@ exports[`Failing create field metadata MULTI_SELECT tests suite v2 Create should { "code": "INVALID_FIELD_INPUT", "message": "Default value should be as quoted string", + "userFriendlyMessage": "Default value should be as quoted string", "value": "", }, { "code": "INVALID_FIELD_INPUT", "message": "Default value "" must be one of the option values", + "userFriendlyMessage": "Default value "" must be one of the option values", "value": "", }, ], @@ -1829,6 +1850,7 @@ exports[`Failing create field metadata MULTI_SELECT tests suite v2 Create should { "code": "INVALID_FIELD_INPUT", "message": "Option id is invalid", + "userFriendlyMessage": "Option id is invalid", "value": "", }, ], @@ -1963,6 +1985,7 @@ exports[`Failing create field metadata MULTI_SELECT tests suite v2 Create should "code": "INVALID_FIELD_INPUT", "message": "Option value must be a string of at least one character", "userFriendlyMessage": "Option value format not supported", + "value": "", }, ], "flatEntityMinimalInformation": { @@ -2028,11 +2051,13 @@ exports[`Failing create field metadata MULTI_SELECT tests suite v2 Create should { "code": "INVALID_FIELD_INPUT", "message": "Default value should be as quoted string", + "userFriendlyMessage": "Default value should be as quoted string", "value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", }, { "code": "INVALID_FIELD_INPUT", "message": "Default value "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" must be one of the option values", + "userFriendlyMessage": "Default value "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" must be one of the option values", "value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", }, ], @@ -2099,6 +2124,7 @@ exports[`Failing create field metadata MULTI_SELECT tests suite v2 Create should { "code": "INVALID_FIELD_INPUT", "message": "Option id is invalid", + "userFriendlyMessage": "Option id is invalid", "value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", }, ], @@ -2165,6 +2191,7 @@ exports[`Failing create field metadata MULTI_SELECT tests suite v2 Create should { "code": "INVALID_FIELD_INPUT", "message": "Option label exceeds 63 characters", + "userFriendlyMessage": "Option label exceeds 63 characters", "value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", }, ], @@ -2231,11 +2258,13 @@ exports[`Failing create field metadata MULTI_SELECT tests suite v2 Create should { "code": "INVALID_FIELD_INPUT", "message": "Option value exceeds 63 characters", + "userFriendlyMessage": "Option value exceeds 63 characters", "value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", }, { "code": "INVALID_FIELD_INPUT", "message": "Value must be in UPPER_CASE and follow snake_case "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"", + "userFriendlyMessage": "Value must be in UPPER_CASE and follow snake_case "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"", "value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", }, ], @@ -2501,6 +2530,7 @@ exports[`Failing create field metadata MULTI_SELECT tests suite v2 Create should { "code": "INVALID_FIELD_INPUT", "message": "Default value "'UNKNOWN_OPTION'" must be one of the option values", + "userFriendlyMessage": "Default value "'UNKNOWN_OPTION'" must be one of the option values", "value": "'UNKNOWN_OPTION'", }, ], @@ -2567,11 +2597,13 @@ exports[`Failing create field metadata SELECT tests suite v2 Create should fail { "code": "INVALID_FIELD_INPUT", "message": "Default value should be as quoted string", + "userFriendlyMessage": "Default value should be as quoted string", "value": "invalid", }, { "code": "INVALID_FIELD_INPUT", "message": "Default value "invalid" must be one of the option values", + "userFriendlyMessage": "Default value "invalid" must be one of the option values", "value": "invalid", }, ], @@ -2638,6 +2670,7 @@ exports[`Failing create field metadata SELECT tests suite v2 Create should fail { "code": "INVALID_FIELD_INPUT", "message": "Default value "'OPTION_424242'" must be one of the option values", + "userFriendlyMessage": "Default value "'OPTION_424242'" must be one of the option values", "value": "'OPTION_424242'", }, ], @@ -2704,6 +2737,7 @@ exports[`Failing create field metadata SELECT tests suite v2 Create should fail { "code": "INVALID_FIELD_INPUT", "message": "Label must not contain a comma", + "userFriendlyMessage": "Label must not contain a comma", "value": "Option ,1", }, ], @@ -2770,6 +2804,7 @@ exports[`Failing create field metadata SELECT tests suite v2 Create should fail { "code": "INVALID_FIELD_INPUT", "message": "Duplicated option id", + "userFriendlyMessage": "Duplicated option id", "value": [ { "color": "green", @@ -2851,6 +2886,7 @@ exports[`Failing create field metadata SELECT tests suite v2 Create should fail { "code": "INVALID_FIELD_INPUT", "message": "Duplicated option position", + "userFriendlyMessage": "Duplicated option position", "value": [ { "color": "green", @@ -2932,6 +2968,7 @@ exports[`Failing create field metadata SELECT tests suite v2 Create should fail { "code": "INVALID_FIELD_INPUT", "message": "Duplicated option value", + "userFriendlyMessage": "Duplicated option value", "value": [ { "color": "green", @@ -3013,6 +3050,7 @@ exports[`Failing create field metadata SELECT tests suite v2 Create should fail { "code": "INVALID_FIELD_INPUT", "message": "Duplicated option value", + "userFriendlyMessage": "Duplicated option value", "value": [ { "color": "green", @@ -3161,11 +3199,13 @@ exports[`Failing create field metadata SELECT tests suite v2 Create should fail { "code": "INVALID_FIELD_INPUT", "message": "Default value should be as quoted string", + "userFriendlyMessage": "Default value should be as quoted string", "value": "", }, { "code": "INVALID_FIELD_INPUT", "message": "Default value "" must be one of the option values", + "userFriendlyMessage": "Default value "" must be one of the option values", "value": "", }, ], @@ -3232,6 +3272,7 @@ exports[`Failing create field metadata SELECT tests suite v2 Create should fail { "code": "INVALID_FIELD_INPUT", "message": "Option id is invalid", + "userFriendlyMessage": "Option id is invalid", "value": "", }, ], @@ -3366,6 +3407,7 @@ exports[`Failing create field metadata SELECT tests suite v2 Create should fail "code": "INVALID_FIELD_INPUT", "message": "Option value must be a string of at least one character", "userFriendlyMessage": "Option value format not supported", + "value": "", }, ], "flatEntityMinimalInformation": { @@ -3431,6 +3473,7 @@ exports[`Failing create field metadata SELECT tests suite v2 Create should fail { "code": "INVALID_FIELD_INPUT", "message": "Option id is invalid", + "userFriendlyMessage": "Option id is invalid", "value": "not a uuid", }, ], @@ -3497,6 +3540,7 @@ exports[`Failing create field metadata SELECT tests suite v2 Create should fail { "code": "INVALID_FIELD_INPUT", "message": "Value must be in UPPER_CASE and follow snake_case "Option 1 and some other things, /"", + "userFriendlyMessage": "Value must be in UPPER_CASE and follow snake_case "Option 1 and some other things, /"", "value": "Option 1 and some other things, /", }, ], @@ -3630,6 +3674,7 @@ exports[`Failing create field metadata SELECT tests suite v2 Create should fail { "code": "INVALID_FIELD_INPUT", "message": "Option id is invalid", + "userFriendlyMessage": "Option id is invalid", "value": 22222, }, ], @@ -3764,6 +3809,7 @@ exports[`Failing create field metadata SELECT tests suite v2 Create should fail "code": "INVALID_FIELD_INPUT", "message": "Option value must be a string of at least one character", "userFriendlyMessage": "Option value format not supported", + "value": 22222, }, ], "flatEntityMinimalInformation": { @@ -3829,11 +3875,12 @@ exports[`Failing create field metadata SELECT tests suite v2 Create should fail { "code": "INVALID_FIELD_INPUT", "message": "Option id is required", - "value": null, + "userFriendlyMessage": "Option id is required", }, { "code": "INVALID_FIELD_INPUT", "message": "Option id is invalid", + "userFriendlyMessage": "Option id is invalid", "value": null, }, ], @@ -4099,11 +4146,13 @@ exports[`Failing create field metadata SELECT tests suite v2 Create should fail { "code": "INVALID_FIELD_INPUT", "message": "Default value should be as quoted string", + "userFriendlyMessage": "Default value should be as quoted string", "value": "", }, { "code": "INVALID_FIELD_INPUT", "message": "Default value "" must be one of the option values", + "userFriendlyMessage": "Default value "" must be one of the option values", "value": "", }, ], @@ -4170,6 +4219,7 @@ exports[`Failing create field metadata SELECT tests suite v2 Create should fail { "code": "INVALID_FIELD_INPUT", "message": "Option id is invalid", + "userFriendlyMessage": "Option id is invalid", "value": "", }, ], @@ -4304,6 +4354,7 @@ exports[`Failing create field metadata SELECT tests suite v2 Create should fail "code": "INVALID_FIELD_INPUT", "message": "Option value must be a string of at least one character", "userFriendlyMessage": "Option value format not supported", + "value": "", }, ], "flatEntityMinimalInformation": { @@ -4369,11 +4420,13 @@ exports[`Failing create field metadata SELECT tests suite v2 Create should fail { "code": "INVALID_FIELD_INPUT", "message": "Default value should be as quoted string", + "userFriendlyMessage": "Default value should be as quoted string", "value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", }, { "code": "INVALID_FIELD_INPUT", "message": "Default value "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" must be one of the option values", + "userFriendlyMessage": "Default value "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" must be one of the option values", "value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", }, ], @@ -4440,6 +4493,7 @@ exports[`Failing create field metadata SELECT tests suite v2 Create should fail { "code": "INVALID_FIELD_INPUT", "message": "Option id is invalid", + "userFriendlyMessage": "Option id is invalid", "value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", }, ], @@ -4506,6 +4560,7 @@ exports[`Failing create field metadata SELECT tests suite v2 Create should fail { "code": "INVALID_FIELD_INPUT", "message": "Option label exceeds 63 characters", + "userFriendlyMessage": "Option label exceeds 63 characters", "value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", }, ], @@ -4572,11 +4627,13 @@ exports[`Failing create field metadata SELECT tests suite v2 Create should fail { "code": "INVALID_FIELD_INPUT", "message": "Option value exceeds 63 characters", + "userFriendlyMessage": "Option value exceeds 63 characters", "value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", }, { "code": "INVALID_FIELD_INPUT", "message": "Value must be in UPPER_CASE and follow snake_case "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"", + "userFriendlyMessage": "Value must be in UPPER_CASE and follow snake_case "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"", "value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", }, ], diff --git a/packages/twenty-server/test/integration/metadata/suites/field-metadata/enum/__snapshots__/failing-update-one-enum-field-metadata-v2.integration-spec.ts.snap b/packages/twenty-server/test/integration/metadata/suites/field-metadata/enum/__snapshots__/failing-update-one-enum-field-metadata-v2.integration-spec.ts.snap index a89b01358ce..ddb8599f96d 100644 --- a/packages/twenty-server/test/integration/metadata/suites/field-metadata/enum/__snapshots__/failing-update-one-enum-field-metadata-v2.integration-spec.ts.snap +++ b/packages/twenty-server/test/integration/metadata/suites/field-metadata/enum/__snapshots__/failing-update-one-enum-field-metadata-v2.integration-spec.ts.snap @@ -149,6 +149,7 @@ exports[`Failing update field metadata MULTI_SELECT tests suite v2 Update should { "code": "INVALID_FIELD_INPUT", "message": "Label must not contain a comma", + "userFriendlyMessage": "Label must not contain a comma", "value": "Option ,1", }, ], @@ -215,6 +216,7 @@ exports[`Failing update field metadata MULTI_SELECT tests suite v2 Update should { "code": "INVALID_FIELD_INPUT", "message": "Duplicated option id", + "userFriendlyMessage": "Duplicated option id", "value": [ { "color": "green", @@ -296,6 +298,7 @@ exports[`Failing update field metadata MULTI_SELECT tests suite v2 Update should { "code": "INVALID_FIELD_INPUT", "message": "Duplicated option position", + "userFriendlyMessage": "Duplicated option position", "value": [ { "color": "green", @@ -377,6 +380,7 @@ exports[`Failing update field metadata MULTI_SELECT tests suite v2 Update should { "code": "INVALID_FIELD_INPUT", "message": "Duplicated option value", + "userFriendlyMessage": "Duplicated option value", "value": [ { "color": "green", @@ -458,6 +462,7 @@ exports[`Failing update field metadata MULTI_SELECT tests suite v2 Update should { "code": "INVALID_FIELD_INPUT", "message": "Duplicated option value", + "userFriendlyMessage": "Duplicated option value", "value": [ { "color": "green", @@ -539,6 +544,7 @@ exports[`Failing update field metadata MULTI_SELECT tests suite v2 Update should { "code": "INVALID_FIELD_INPUT", "message": "If defined default value must contain at least one value", + "userFriendlyMessage": "If defined default value must contain at least one value", "value": [], }, ], @@ -672,11 +678,13 @@ exports[`Failing update field metadata MULTI_SELECT tests suite v2 Update should { "code": "INVALID_FIELD_INPUT", "message": "Default value should be as quoted string", + "userFriendlyMessage": "Default value should be as quoted string", "value": "", }, { "code": "INVALID_FIELD_INPUT", "message": "Default value "" must be one of the option values", + "userFriendlyMessage": "Default value "" must be one of the option values", "value": "", }, ], @@ -743,6 +751,7 @@ exports[`Failing update field metadata MULTI_SELECT tests suite v2 Update should { "code": "INVALID_FIELD_INPUT", "message": "Option id is invalid", + "userFriendlyMessage": "Option id is invalid", "value": "", }, ], @@ -877,6 +886,7 @@ exports[`Failing update field metadata MULTI_SELECT tests suite v2 Update should "code": "INVALID_FIELD_INPUT", "message": "Option value must be a string of at least one character", "userFriendlyMessage": "Option value format not supported", + "value": "", }, ], "flatEntityMinimalInformation": { @@ -942,21 +952,25 @@ exports[`Failing update field metadata MULTI_SELECT tests suite v2 Update should { "code": "INVALID_FIELD_INPUT", "message": "Default value should be as quoted string", + "userFriendlyMessage": "Default value should be as quoted string", "value": "invalid", }, { "code": "INVALID_FIELD_INPUT", "message": "Default value "invalid" must be one of the option values", + "userFriendlyMessage": "Default value "invalid" must be one of the option values", "value": "invalid", }, { "code": "INVALID_FIELD_INPUT", "message": "Default value should be as quoted string", + "userFriendlyMessage": "Default value should be as quoted string", "value": "format", }, { "code": "INVALID_FIELD_INPUT", "message": "Default value "format" must be one of the option values", + "userFriendlyMessage": "Default value "format" must be one of the option values", "value": "format", }, ], @@ -1023,6 +1037,7 @@ exports[`Failing update field metadata MULTI_SELECT tests suite v2 Update should { "code": "INVALID_FIELD_INPUT", "message": "Option id is invalid", + "userFriendlyMessage": "Option id is invalid", "value": "not a uuid", }, ], @@ -1089,6 +1104,7 @@ exports[`Failing update field metadata MULTI_SELECT tests suite v2 Update should { "code": "INVALID_FIELD_INPUT", "message": "Value must be in UPPER_CASE and follow snake_case "Option 1 and some other things, /"", + "userFriendlyMessage": "Value must be in UPPER_CASE and follow snake_case "Option 1 and some other things, /"", "value": "Option 1 and some other things, /", }, ], @@ -1289,6 +1305,7 @@ exports[`Failing update field metadata MULTI_SELECT tests suite v2 Update should { "code": "INVALID_FIELD_INPUT", "message": "Option id is invalid", + "userFriendlyMessage": "Option id is invalid", "value": 22222, }, ], @@ -1423,6 +1440,7 @@ exports[`Failing update field metadata MULTI_SELECT tests suite v2 Update should "code": "INVALID_FIELD_INPUT", "message": "Option value must be a string of at least one character", "userFriendlyMessage": "Option value format not supported", + "value": 22222, }, ], "flatEntityMinimalInformation": { @@ -1488,11 +1506,12 @@ exports[`Failing update field metadata MULTI_SELECT tests suite v2 Update should { "code": "INVALID_FIELD_INPUT", "message": "Option id is required", - "value": null, + "userFriendlyMessage": "Option id is required", }, { "code": "INVALID_FIELD_INPUT", "message": "Option id is invalid", + "userFriendlyMessage": "Option id is invalid", "value": null, }, ], @@ -1691,11 +1710,13 @@ exports[`Failing update field metadata MULTI_SELECT tests suite v2 Update should { "code": "INVALID_FIELD_INPUT", "message": "Default value should be as quoted string", + "userFriendlyMessage": "Default value should be as quoted string", "value": "", }, { "code": "INVALID_FIELD_INPUT", "message": "Default value "" must be one of the option values", + "userFriendlyMessage": "Default value "" must be one of the option values", "value": "", }, ], @@ -1762,6 +1783,7 @@ exports[`Failing update field metadata MULTI_SELECT tests suite v2 Update should { "code": "INVALID_FIELD_INPUT", "message": "Option id is invalid", + "userFriendlyMessage": "Option id is invalid", "value": "", }, ], @@ -1896,6 +1918,7 @@ exports[`Failing update field metadata MULTI_SELECT tests suite v2 Update should "code": "INVALID_FIELD_INPUT", "message": "Option value must be a string of at least one character", "userFriendlyMessage": "Option value format not supported", + "value": "", }, ], "flatEntityMinimalInformation": { @@ -1961,11 +1984,13 @@ exports[`Failing update field metadata MULTI_SELECT tests suite v2 Update should { "code": "INVALID_FIELD_INPUT", "message": "Default value should be as quoted string", + "userFriendlyMessage": "Default value should be as quoted string", "value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", }, { "code": "INVALID_FIELD_INPUT", "message": "Default value "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" must be one of the option values", + "userFriendlyMessage": "Default value "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" must be one of the option values", "value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", }, ], @@ -2032,6 +2057,7 @@ exports[`Failing update field metadata MULTI_SELECT tests suite v2 Update should { "code": "INVALID_FIELD_INPUT", "message": "Option id is invalid", + "userFriendlyMessage": "Option id is invalid", "value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", }, ], @@ -2098,6 +2124,7 @@ exports[`Failing update field metadata MULTI_SELECT tests suite v2 Update should { "code": "INVALID_FIELD_INPUT", "message": "Option label exceeds 63 characters", + "userFriendlyMessage": "Option label exceeds 63 characters", "value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", }, ], @@ -2164,11 +2191,13 @@ exports[`Failing update field metadata MULTI_SELECT tests suite v2 Update should { "code": "INVALID_FIELD_INPUT", "message": "Option value exceeds 63 characters", + "userFriendlyMessage": "Option value exceeds 63 characters", "value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", }, { "code": "INVALID_FIELD_INPUT", "message": "Value must be in UPPER_CASE and follow snake_case "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"", + "userFriendlyMessage": "Value must be in UPPER_CASE and follow snake_case "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"", "value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", }, ], @@ -2367,6 +2396,7 @@ exports[`Failing update field metadata MULTI_SELECT tests suite v2 Update should { "code": "INVALID_FIELD_INPUT", "message": "Default value "'OPTION_42'" must be one of the option values", + "userFriendlyMessage": "Default value "'OPTION_42'" must be one of the option values", "value": "'OPTION_42'", }, ], @@ -2433,6 +2463,7 @@ exports[`Failing update field metadata MULTI_SELECT tests suite v2 Update should { "code": "INVALID_FIELD_INPUT", "message": "Default value "'UNKNOWN_OPTION'" must be one of the option values", + "userFriendlyMessage": "Default value "'UNKNOWN_OPTION'" must be one of the option values", "value": "'UNKNOWN_OPTION'", }, ], @@ -2499,11 +2530,13 @@ exports[`Failing update field metadata SELECT tests suite v2 Update should fail { "code": "INVALID_FIELD_INPUT", "message": "Default value should be as quoted string", + "userFriendlyMessage": "Default value should be as quoted string", "value": "invalid", }, { "code": "INVALID_FIELD_INPUT", "message": "Default value "invalid" must be one of the option values", + "userFriendlyMessage": "Default value "invalid" must be one of the option values", "value": "invalid", }, ], @@ -2570,6 +2603,7 @@ exports[`Failing update field metadata SELECT tests suite v2 Update should fail { "code": "INVALID_FIELD_INPUT", "message": "Default value "'OPTION_424242'" must be one of the option values", + "userFriendlyMessage": "Default value "'OPTION_424242'" must be one of the option values", "value": "'OPTION_424242'", }, ], @@ -2636,6 +2670,7 @@ exports[`Failing update field metadata SELECT tests suite v2 Update should fail { "code": "INVALID_FIELD_INPUT", "message": "Label must not contain a comma", + "userFriendlyMessage": "Label must not contain a comma", "value": "Option ,1", }, ], @@ -2702,6 +2737,7 @@ exports[`Failing update field metadata SELECT tests suite v2 Update should fail { "code": "INVALID_FIELD_INPUT", "message": "Duplicated option id", + "userFriendlyMessage": "Duplicated option id", "value": [ { "color": "green", @@ -2783,6 +2819,7 @@ exports[`Failing update field metadata SELECT tests suite v2 Update should fail { "code": "INVALID_FIELD_INPUT", "message": "Duplicated option position", + "userFriendlyMessage": "Duplicated option position", "value": [ { "color": "green", @@ -2864,6 +2901,7 @@ exports[`Failing update field metadata SELECT tests suite v2 Update should fail { "code": "INVALID_FIELD_INPUT", "message": "Duplicated option value", + "userFriendlyMessage": "Duplicated option value", "value": [ { "color": "green", @@ -2945,6 +2983,7 @@ exports[`Failing update field metadata SELECT tests suite v2 Update should fail { "code": "INVALID_FIELD_INPUT", "message": "Duplicated option value", + "userFriendlyMessage": "Duplicated option value", "value": [ { "color": "green", @@ -3093,11 +3132,13 @@ exports[`Failing update field metadata SELECT tests suite v2 Update should fail { "code": "INVALID_FIELD_INPUT", "message": "Default value should be as quoted string", + "userFriendlyMessage": "Default value should be as quoted string", "value": "", }, { "code": "INVALID_FIELD_INPUT", "message": "Default value "" must be one of the option values", + "userFriendlyMessage": "Default value "" must be one of the option values", "value": "", }, ], @@ -3164,6 +3205,7 @@ exports[`Failing update field metadata SELECT tests suite v2 Update should fail { "code": "INVALID_FIELD_INPUT", "message": "Option id is invalid", + "userFriendlyMessage": "Option id is invalid", "value": "", }, ], @@ -3298,6 +3340,7 @@ exports[`Failing update field metadata SELECT tests suite v2 Update should fail "code": "INVALID_FIELD_INPUT", "message": "Option value must be a string of at least one character", "userFriendlyMessage": "Option value format not supported", + "value": "", }, ], "flatEntityMinimalInformation": { @@ -3363,6 +3406,7 @@ exports[`Failing update field metadata SELECT tests suite v2 Update should fail { "code": "INVALID_FIELD_INPUT", "message": "Option id is invalid", + "userFriendlyMessage": "Option id is invalid", "value": "not a uuid", }, ], @@ -3429,6 +3473,7 @@ exports[`Failing update field metadata SELECT tests suite v2 Update should fail { "code": "INVALID_FIELD_INPUT", "message": "Value must be in UPPER_CASE and follow snake_case "Option 1 and some other things, /"", + "userFriendlyMessage": "Value must be in UPPER_CASE and follow snake_case "Option 1 and some other things, /"", "value": "Option 1 and some other things, /", }, ], @@ -3562,6 +3607,7 @@ exports[`Failing update field metadata SELECT tests suite v2 Update should fail { "code": "INVALID_FIELD_INPUT", "message": "Option id is invalid", + "userFriendlyMessage": "Option id is invalid", "value": 22222, }, ], @@ -3696,6 +3742,7 @@ exports[`Failing update field metadata SELECT tests suite v2 Update should fail "code": "INVALID_FIELD_INPUT", "message": "Option value must be a string of at least one character", "userFriendlyMessage": "Option value format not supported", + "value": 22222, }, ], "flatEntityMinimalInformation": { @@ -3761,11 +3808,12 @@ exports[`Failing update field metadata SELECT tests suite v2 Update should fail { "code": "INVALID_FIELD_INPUT", "message": "Option id is required", - "value": null, + "userFriendlyMessage": "Option id is required", }, { "code": "INVALID_FIELD_INPUT", "message": "Option id is invalid", + "userFriendlyMessage": "Option id is invalid", "value": null, }, ], @@ -3964,11 +4012,13 @@ exports[`Failing update field metadata SELECT tests suite v2 Update should fail { "code": "INVALID_FIELD_INPUT", "message": "Default value should be as quoted string", + "userFriendlyMessage": "Default value should be as quoted string", "value": "", }, { "code": "INVALID_FIELD_INPUT", "message": "Default value "" must be one of the option values", + "userFriendlyMessage": "Default value "" must be one of the option values", "value": "", }, ], @@ -4035,6 +4085,7 @@ exports[`Failing update field metadata SELECT tests suite v2 Update should fail { "code": "INVALID_FIELD_INPUT", "message": "Option id is invalid", + "userFriendlyMessage": "Option id is invalid", "value": "", }, ], @@ -4169,6 +4220,7 @@ exports[`Failing update field metadata SELECT tests suite v2 Update should fail "code": "INVALID_FIELD_INPUT", "message": "Option value must be a string of at least one character", "userFriendlyMessage": "Option value format not supported", + "value": "", }, ], "flatEntityMinimalInformation": { @@ -4234,11 +4286,13 @@ exports[`Failing update field metadata SELECT tests suite v2 Update should fail { "code": "INVALID_FIELD_INPUT", "message": "Default value should be as quoted string", + "userFriendlyMessage": "Default value should be as quoted string", "value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", }, { "code": "INVALID_FIELD_INPUT", "message": "Default value "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" must be one of the option values", + "userFriendlyMessage": "Default value "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" must be one of the option values", "value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", }, ], @@ -4305,6 +4359,7 @@ exports[`Failing update field metadata SELECT tests suite v2 Update should fail { "code": "INVALID_FIELD_INPUT", "message": "Option id is invalid", + "userFriendlyMessage": "Option id is invalid", "value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", }, ], @@ -4371,6 +4426,7 @@ exports[`Failing update field metadata SELECT tests suite v2 Update should fail { "code": "INVALID_FIELD_INPUT", "message": "Option label exceeds 63 characters", + "userFriendlyMessage": "Option label exceeds 63 characters", "value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", }, ], @@ -4437,11 +4493,13 @@ exports[`Failing update field metadata SELECT tests suite v2 Update should fail { "code": "INVALID_FIELD_INPUT", "message": "Option value exceeds 63 characters", + "userFriendlyMessage": "Option value exceeds 63 characters", "value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", }, { "code": "INVALID_FIELD_INPUT", "message": "Value must be in UPPER_CASE and follow snake_case "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"", + "userFriendlyMessage": "Value must be in UPPER_CASE and follow snake_case "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"", "value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", }, ], @@ -4640,6 +4698,7 @@ exports[`Failing update field metadata SELECT tests suite v2 Update should fail { "code": "INVALID_FIELD_INPUT", "message": "Default value "'OPTION_42'" must be one of the option values", + "userFriendlyMessage": "Default value "'OPTION_42'" must be one of the option values", "value": "'OPTION_42'", }, ], diff --git a/packages/twenty-server/test/integration/metadata/suites/object-metadata/__snapshots__/failing-create-one-object-metadata-v2.integration-spec.ts.snap b/packages/twenty-server/test/integration/metadata/suites/object-metadata/__snapshots__/failing-create-one-object-metadata-v2.integration-spec.ts.snap index c60a7bc1409..d1a5bcb4e85 100644 --- a/packages/twenty-server/test/integration/metadata/suites/object-metadata/__snapshots__/failing-create-one-object-metadata-v2.integration-spec.ts.snap +++ b/packages/twenty-server/test/integration/metadata/suites/object-metadata/__snapshots__/failing-create-one-object-metadata-v2.integration-spec.ts.snap @@ -326,6 +326,7 @@ exports[`Object metadata creation should fail v2 when labelPlural contains only { "code": "INVALID_OBJECT_INPUT", "message": "Object label is too short", + "userFriendlyMessage": "Object label is too short", "value": "", }, ], @@ -947,6 +948,7 @@ exports[`Object metadata creation should fail v2 when labelPlural exceeds maximu { "code": "INVALID_OBJECT_INPUT", "message": "Object label is too long", + "userFriendlyMessage": "Object label is too long", "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", }, ], @@ -1579,6 +1581,7 @@ exports[`Object metadata creation should fail v2 when labelSingular contains onl { "code": "INVALID_OBJECT_INPUT", "message": "Object label is too short", + "userFriendlyMessage": "Object label is too short", "value": "", }, ], @@ -2200,6 +2203,7 @@ exports[`Object metadata creation should fail v2 when labelSingular exceeds maxi { "code": "INVALID_OBJECT_INPUT", "message": "Object label is too long", + "userFriendlyMessage": "Object label is too long", "value": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", }, ], @@ -4106,6 +4110,7 @@ exports[`Object metadata creation should fail v2 when name exceeds maximum lengt { "code": "INVALID_OBJECT_INPUT", "message": "Name is too long", + "userFriendlyMessage": "Name is too long", "value": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", }, ], @@ -4727,6 +4732,7 @@ exports[`Object metadata creation should fail v2 when namePlural has invalid cha { "code": "INVALID_OBJECT_INPUT", "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", + "userFriendlyMessage": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", "value": "μ", }, ], @@ -5348,6 +5354,7 @@ exports[`Object metadata creation should fail v2 when namePlural is a reserved k { "code": "INVALID_OBJECT_INPUT", "message": "This name is reserved. Use a different name or the system will add "Custom" suffix.", + "userFriendlyMessage": "This name is reserved. Use a different name or the system will add "Custom" suffix.", "value": "users", }, ], @@ -5980,11 +5987,13 @@ exports[`Object metadata creation should fail v2 when namePlural is not camelCas { "code": "INVALID_OBJECT_INPUT", "message": "Name should be in camelCase", + "userFriendlyMessage": "Name should be in camelCase", "value": "Not_Camel_Case", }, { "code": "INVALID_OBJECT_INPUT", "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", + "userFriendlyMessage": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", "value": "Not_Camel_Case", }, ], @@ -6666,11 +6675,13 @@ exports[`Object metadata creation should fail v2 when nameSingular contains only { "code": "INVALID_OBJECT_INPUT", "message": "Name should be in camelCase", + "userFriendlyMessage": "Name should be in camelCase", "value": "a a", }, { "code": "INVALID_OBJECT_INPUT", "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", + "userFriendlyMessage": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", "value": "a a", }, ], @@ -7352,11 +7363,13 @@ exports[`Object metadata creation should fail v2 when nameSingular contains only { "code": "INVALID_OBJECT_INPUT", "message": "Name is too short", + "userFriendlyMessage": "Name is too short", "value": "", }, { "code": "INVALID_OBJECT_INPUT", "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", + "userFriendlyMessage": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", "value": "", }, ], @@ -8008,6 +8021,7 @@ exports[`Object metadata creation should fail v2 when nameSingular has invalid c { "code": "INVALID_OBJECT_INPUT", "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", + "userFriendlyMessage": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", "value": "μ", }, ], @@ -8659,6 +8673,7 @@ exports[`Object metadata creation should fail v2 when nameSingular is a reserved { "code": "INVALID_OBJECT_INPUT", "message": "This name is reserved. Use a different name or the system will add "Custom" suffix.", + "userFriendlyMessage": "This name is reserved. Use a different name or the system will add "Custom" suffix.", "value": "user", }, ], @@ -9351,11 +9366,13 @@ exports[`Object metadata creation should fail v2 when nameSingular is not camelC { "code": "INVALID_OBJECT_INPUT", "message": "Name should be in camelCase", + "userFriendlyMessage": "Name should be in camelCase", "value": "Not_Camel_Case", }, { "code": "INVALID_OBJECT_INPUT", "message": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", + "userFriendlyMessage": "Name is not valid: it must start with lowercase letter and contain only alphanumeric letters", "value": "Not_Camel_Case", }, ], diff --git a/packages/twenty-server/test/integration/metadata/suites/object-metadata/__snapshots__/failing-update-one-object-metadata.integration-spec.ts.snap b/packages/twenty-server/test/integration/metadata/suites/object-metadata/__snapshots__/failing-update-one-object-metadata.integration-spec.ts.snap index 62b705ab775..3c06f51ec2e 100644 --- a/packages/twenty-server/test/integration/metadata/suites/object-metadata/__snapshots__/failing-update-one-object-metadata.integration-spec.ts.snap +++ b/packages/twenty-server/test/integration/metadata/suites/object-metadata/__snapshots__/failing-update-one-object-metadata.integration-spec.ts.snap @@ -1,5 +1,86 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`Object metadata update should fail when labelIdentifier is a UUID field (reserved for system objects) 1`] = ` +[ + { + "extensions": { + "code": "METADATA_VALIDATION_FAILED", + "errors": { + "agent": [], + "cronTrigger": [], + "databaseEventTrigger": [], + "fieldMetadata": [], + "index": [], + "objectMetadata": [ + { + "errors": [ + { + "code": "INVALID_OBJECT_INPUT", + "message": "labelIdentifierFieldMetadataId validation failed: field type uuid is reserved for system object metadata", + "userFriendlyMessage": "Field cannot be used as label identifier", + }, + ], + "flatEntityMinimalInformation": { + "id": Any, + "namePlural": "whatevers", + "nameSingular": "whatever", + }, + "status": "fail", + "type": "update_object", + }, + ], + "role": [], + "roleTarget": [], + "routeTrigger": [], + "serverlessFunction": [], + "view": [], + "viewField": [ + { + "errors": [ + { + "code": "INVALID_VIEW_DATA", + "message": "View field position cannot be lower than label identifier view field position", + "userFriendlyMessage": "View field position cannot be lower than label identifier view field position", + }, + ], + "flatEntityMinimalInformation": { + "fieldMetadataId": Any, + "id": Any, + "viewId": Any, + }, + "status": "fail", + "type": "create_view_field", + }, + ], + "viewFilter": [], + "viewGroup": [], + }, + "message": "Validation failed for 0 object(s) and 0 field(s)", + "summary": { + "invalidAgent": 0, + "invalidCronTrigger": 0, + "invalidDatabaseEventTrigger": 0, + "invalidFieldMetadata": 0, + "invalidIndex": 0, + "invalidObjectMetadata": 0, + "invalidRole": 0, + "invalidRoleTarget": 0, + "invalidRouteTrigger": 0, + "invalidServerlessFunction": 0, + "invalidView": 0, + "invalidViewField": 0, + "invalidViewFilter": 0, + "invalidViewGroup": 0, + "totalErrors": 0, + }, + "userFriendlyMessage": "Validation failed for 0 object(s) and 0 field(s)", + }, + "message": "Multiple validation errors occurred while updating object", + "name": "GraphQLError", + }, +] +`; + exports[`Object metadata update should fail when labelIdentifier is not a TEXT or NAME field 1`] = ` [ { diff --git a/packages/twenty-server/test/integration/metadata/suites/object-metadata/failing-update-one-object-metadata.integration-spec.ts b/packages/twenty-server/test/integration/metadata/suites/object-metadata/failing-update-one-object-metadata.integration-spec.ts index ebbf8b23e6c..c7c24bf02d5 100644 --- a/packages/twenty-server/test/integration/metadata/suites/object-metadata/failing-update-one-object-metadata.integration-spec.ts +++ b/packages/twenty-server/test/integration/metadata/suites/object-metadata/failing-update-one-object-metadata.integration-spec.ts @@ -1,8 +1,10 @@ import { createOneFieldMetadata } from 'test/integration/metadata/suites/field-metadata/utils/create-one-field-metadata.util'; import { createOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/create-one-object-metadata.util'; import { deleteOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/delete-one-object-metadata.util'; +import { findManyObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/find-many-object-metadata.util'; import { updateOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/update-one-object-metadata.util'; import { extractRecordIdsAndDatesAsExpectAny } from 'test/utils/extract-record-ids-and-dates-as-expect-any'; +import { jestExpectToBeDefined } from 'test/utils/jest-expect-to-be-defined.util.test'; import { eachTestingContextFilter, type EachTestingContext, @@ -14,6 +16,7 @@ import { type UpdateObjectPayload } from 'src/engine/metadata-modules/object-met type TestingRuntimeContext = { objectMetadataId: string; numberFieldMetadataId: string; + uuidFieldMetadataId: string; }; type CreateOneObjectMetadataItemTestingContext = EachTestingContext< @@ -47,6 +50,13 @@ const labelIdentifierFailingTestsUseCase: CreateOneObjectMetadataItemTestingCont labelIdentifierFieldMetadataId: numberFieldMetadataId, }), }, + { + title: + 'when labelIdentifier is a UUID field (reserved for system objects)', + context: ({ uuidFieldMetadataId }) => ({ + labelIdentifierFieldMetadataId: uuidFieldMetadataId, + }), + }, ]; const allTestsUseCases = [...labelIdentifierFailingTestsUseCase]; @@ -54,6 +64,7 @@ const allTestsUseCases = [...labelIdentifierFailingTestsUseCase]; describe('Object metadata update should fail', () => { let objectMetadataId: string; let numberFieldMetadataId: string; + let uuidFieldMetadataId: string; beforeAll(async () => { const { data } = await createOneObjectMetadata({ @@ -82,6 +93,32 @@ describe('Object metadata update should fail', () => { }); numberFieldMetadataId = createOneField.id; + + const { objects } = await findManyObjectMetadata({ + expectToFail: false, + input: { + filter: { isCustom: { is: true } }, + paging: { first: 100 }, + }, + gqlFields: ` + id + fieldsList { + id + type + } + `, + }); + + const createdObject = objects.find((obj) => obj.id === objectMetadataId); + + jestExpectToBeDefined(createdObject); + + const uuidField = createdObject.fieldsList?.find( + (field) => field.type === FieldMetadataType.UUID, + ); + + jestExpectToBeDefined(uuidField); + uuidFieldMetadataId = uuidField.id; }); afterAll(async () => { @@ -106,7 +143,11 @@ describe('Object metadata update should fail', () => { async ({ context }) => { const updatePayload = typeof context === 'function' - ? context({ numberFieldMetadataId, objectMetadataId }) + ? context({ + numberFieldMetadataId, + objectMetadataId, + uuidFieldMetadataId, + }) : context; const { errors } = await updateOneObjectMetadata({ diff --git a/packages/twenty-shared/src/constants/LabelIdentifierFieldMetadataTypes.ts b/packages/twenty-shared/src/constants/LabelIdentifierFieldMetadataTypes.ts index 8bca62a8615..60c1c7a108a 100644 --- a/packages/twenty-shared/src/constants/LabelIdentifierFieldMetadataTypes.ts +++ b/packages/twenty-shared/src/constants/LabelIdentifierFieldMetadataTypes.ts @@ -3,4 +3,5 @@ import { FieldMetadataType } from '@/types'; export const LABEL_IDENTIFIER_FIELD_METADATA_TYPES = [ FieldMetadataType.TEXT, FieldMetadataType.FULL_NAME, + FieldMetadataType.UUID, ];