diff --git a/packages/twenty-client-sdk/src/metadata/generated/schema.graphql b/packages/twenty-client-sdk/src/metadata/generated/schema.graphql index 5bfc1853a5..8da058591b 100644 --- a/packages/twenty-client-sdk/src/metadata/generated/schema.graphql +++ b/packages/twenty-client-sdk/src/metadata/generated/schema.graphql @@ -1787,6 +1787,7 @@ enum FeatureFlagKey { IS_REST_METADATA_API_NEW_FORMAT_DIRECT IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED IS_SETTINGS_DISCOVERY_HERO_ENABLED + IS_CALL_RECORDING_ENABLED IS_WORKFLOW_RUN_STEP_LOGS_ENABLED } diff --git a/packages/twenty-client-sdk/src/metadata/generated/schema.ts b/packages/twenty-client-sdk/src/metadata/generated/schema.ts index bd7d9ebf4a..a77795ab26 100644 --- a/packages/twenty-client-sdk/src/metadata/generated/schema.ts +++ b/packages/twenty-client-sdk/src/metadata/generated/schema.ts @@ -1414,7 +1414,7 @@ export interface FeatureFlag { __typename: 'FeatureFlag' } -export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAIL_GROUP_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT' | 'IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED' | 'IS_SETTINGS_DISCOVERY_HERO_ENABLED' | 'IS_WORKFLOW_RUN_STEP_LOGS_ENABLED' +export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAIL_GROUP_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT' | 'IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED' | 'IS_SETTINGS_DISCOVERY_HERO_ENABLED' | 'IS_CALL_RECORDING_ENABLED' | 'IS_WORKFLOW_RUN_STEP_LOGS_ENABLED' export interface WorkspaceUrls { customUrl?: Scalars['String'] @@ -8812,6 +8812,7 @@ export const enumFeatureFlagKey = { IS_REST_METADATA_API_NEW_FORMAT_DIRECT: 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT' as const, IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED: 'IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED' as const, IS_SETTINGS_DISCOVERY_HERO_ENABLED: 'IS_SETTINGS_DISCOVERY_HERO_ENABLED' as const, + IS_CALL_RECORDING_ENABLED: 'IS_CALL_RECORDING_ENABLED' as const, IS_WORKFLOW_RUN_STEP_LOGS_ENABLED: 'IS_WORKFLOW_RUN_STEP_LOGS_ENABLED' as const } diff --git a/packages/twenty-front/src/generated-admin/graphql.ts b/packages/twenty-front/src/generated-admin/graphql.ts index 51ddbd712c..4c8785b04c 100644 --- a/packages/twenty-front/src/generated-admin/graphql.ts +++ b/packages/twenty-front/src/generated-admin/graphql.ts @@ -283,6 +283,7 @@ export type FeatureFlag = { }; export enum FeatureFlagKey { + IS_CALL_RECORDING_ENABLED = 'IS_CALL_RECORDING_ENABLED', IS_EMAIL_GROUP_ENABLED = 'IS_EMAIL_GROUP_ENABLED', IS_JSON_FILTER_ENABLED = 'IS_JSON_FILTER_ENABLED', IS_JUNCTION_RELATIONS_ENABLED = 'IS_JUNCTION_RELATIONS_ENABLED', diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index 6f8c442351..9bee2cdcb2 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -1648,6 +1648,7 @@ export type FeatureFlag = { }; export enum FeatureFlagKey { + IS_CALL_RECORDING_ENABLED = 'IS_CALL_RECORDING_ENABLED', IS_EMAIL_GROUP_ENABLED = 'IS_EMAIL_GROUP_ENABLED', IS_JSON_FILTER_ENABLED = 'IS_JSON_FILTER_ENABLED', IS_JUNCTION_RELATIONS_ENABLED = 'IS_JUNCTION_RELATIONS_ENABLED', diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/2-10/2-10-upgrade-version-command.module.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/2-10/2-10-upgrade-version-command.module.ts index c36ee294d8..466a349c07 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/2-10/2-10-upgrade-version-command.module.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/2-10/2-10-upgrade-version-command.module.ts @@ -5,6 +5,7 @@ import { WorkspaceIteratorModule } from 'src/database/commands/command-runners/w import { AddInactiveGenericStandardFieldsCommand } from 'src/database/commands/upgrade-version-command/2-10/2-10-workspace-command-1799000050000-add-inactive-generic-standard-fields.command'; import { MoveDemotedStandardFieldsToCustomApplicationCommand } from 'src/database/commands/upgrade-version-command/2-10/2-10-workspace-command-1799000040000-move-demoted-standard-fields-to-custom-application.command'; import { RenameConflictingCustomFieldsCommand } from 'src/database/commands/upgrade-version-command/2-10/2-10-workspace-command-1799000045000-rename-conflicting-custom-fields.command'; +import { SyncCallRecordingStandardObjectsCommand } from 'src/database/commands/upgrade-version-command/2-10/2-10-workspace-command-1799000055000-sync-call-recording-standard-objects.command'; import { ApplicationModule } from 'src/engine/core-modules/application/application.module'; import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; import { WorkspaceMetadataVersionModule } from 'src/engine/metadata-modules/workspace-metadata-version/workspace-metadata-version.module'; @@ -24,6 +25,7 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace MoveDemotedStandardFieldsToCustomApplicationCommand, RenameConflictingCustomFieldsCommand, AddInactiveGenericStandardFieldsCommand, + SyncCallRecordingStandardObjectsCommand, ], }) export class V2_10_UpgradeVersionCommandModule {} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/2-10/2-10-workspace-command-1799000055000-sync-call-recording-standard-objects.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/2-10/2-10-workspace-command-1799000055000-sync-call-recording-standard-objects.command.ts new file mode 100644 index 0000000000..80d8455222 --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/2-10/2-10-workspace-command-1799000055000-sync-call-recording-standard-objects.command.ts @@ -0,0 +1,425 @@ +import { Command } from 'nest-commander'; +import { + STANDARD_OBJECTS, + STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS, +} from 'twenty-shared/metadata'; +import { isDefined } from 'twenty-shared/utils'; + +import { ActiveOrSuspendedWorkspaceCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspace.command-runner'; +import { WorkspaceIteratorService } from 'src/database/commands/command-runners/workspace-iterator.service'; +import { type RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspace.command-runner'; +import { buildNavigationCommandMenuItemOperationsOrThrow } from 'src/database/commands/upgrade-version-command/2-10/utils/build-navigation-command-menu-item-operations-or-throw.util'; +import { + buildCalendarEventFieldRenameUpdates, + buildCallRecordingObjectRenameUpdates, +} from 'src/database/commands/upgrade-version-command/2-10/utils/call-recording-name-collision.util'; +import { + getExistingOrStandardFlatEntityOrThrow, + getStandardFlatEntitiesToCreateOrThrow, +} from 'src/database/commands/upgrade-version-command/2-10/utils/get-standard-flat-entities-to-create-or-throw.util'; +import { ApplicationService } from 'src/engine/core-modules/application/application.service'; +import { RegisteredWorkspaceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-workspace-command.decorator'; +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/types/flat-index-metadata.type'; +import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; +import { type FlatPageLayoutTab } from 'src/engine/metadata-modules/flat-page-layout-tab/types/flat-page-layout-tab.type'; +import { type FlatPageLayoutWidget } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget.type'; +import { type FlatPageLayout } from 'src/engine/metadata-modules/flat-page-layout/types/flat-page-layout.type'; +import { type FlatViewFieldGroup } from 'src/engine/metadata-modules/flat-view-field-group/types/flat-view-field-group.type'; +import { type FlatViewField } from 'src/engine/metadata-modules/flat-view-field/types/flat-view-field.type'; +import { type FlatView } from 'src/engine/metadata-modules/flat-view/types/flat-view.type'; +import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; +import { computeTwentyStandardApplicationAllFlatEntityMaps } from 'src/engine/workspace-manager/twenty-standard-application/utils/twenty-standard-application-all-flat-entity-maps.constant'; +import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service'; + +const getUniversalIdentifiers = ( + entitiesByName: Record, +): string[] => + Object.values(entitiesByName).map((entity) => entity.universalIdentifier); + +const CALL_RECORDING_OBJECT_METADATA_UNIVERSAL_IDENTIFIERS = [ + STANDARD_OBJECTS.callRecording.universalIdentifier, +]; + +const CALL_RECORDING_FIELD_METADATA_UNIVERSAL_IDENTIFIERS = [ + ...getUniversalIdentifiers(STANDARD_OBJECTS.callRecording.fields), + STANDARD_OBJECTS.calendarEvent.fields.recordingPreference.universalIdentifier, + STANDARD_OBJECTS.calendarEvent.fields.callRecordings.universalIdentifier, +]; + +const CALL_RECORDING_INDEX_UNIVERSAL_IDENTIFIERS = getUniversalIdentifiers( + STANDARD_OBJECTS.callRecording.indexes, +); + +const CALL_RECORDING_VIEW_UNIVERSAL_IDENTIFIERS = [ + STANDARD_OBJECTS.callRecording.views.allCallRecordings.universalIdentifier, + STANDARD_OBJECTS.callRecording.views.callRecordingRecordPageFields + .universalIdentifier, +]; + +const CALL_RECORDING_VIEW_FIELD_GROUP_UNIVERSAL_IDENTIFIERS = + getUniversalIdentifiers( + STANDARD_OBJECTS.callRecording.views.callRecordingRecordPageFields + .viewFieldGroups, + ); + +const CALL_RECORDING_VIEW_FIELD_UNIVERSAL_IDENTIFIERS = [ + ...getUniversalIdentifiers( + STANDARD_OBJECTS.callRecording.views.allCallRecordings.viewFields, + ), + ...getUniversalIdentifiers( + STANDARD_OBJECTS.callRecording.views.callRecordingRecordPageFields + .viewFields, + ), +]; + +const CALL_RECORDING_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS = [ + STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.callRecordingRecordPage + .universalIdentifier, +]; + +const CALL_RECORDING_PAGE_LAYOUT_TAB_UNIVERSAL_IDENTIFIERS = [ + STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.callRecordingRecordPage.tabs.home + .universalIdentifier, + STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.callRecordingRecordPage.tabs + .timeline.universalIdentifier, +]; + +const CALL_RECORDING_PAGE_LAYOUT_WIDGET_UNIVERSAL_IDENTIFIERS = [ + STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.callRecordingRecordPage.tabs.home + .widgets.fields.universalIdentifier, + STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.callRecordingRecordPage.tabs + .timeline.widgets.timeline.universalIdentifier, +]; + +@RegisteredWorkspaceCommand('2.10.0', 1799000055000) +@Command({ + name: 'upgrade:2-10:sync-call-recording-standard-objects', + description: + 'Create the CallRecording standard metadata in existing workspaces', +}) +export class SyncCallRecordingStandardObjectsCommand extends ActiveOrSuspendedWorkspaceCommandRunner { + constructor( + protected readonly workspaceIteratorService: WorkspaceIteratorService, + private readonly applicationService: ApplicationService, + private readonly workspaceCacheService: WorkspaceCacheService, + private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService, + ) { + super(workspaceIteratorService); + } + + override async runOnWorkspace({ + workspaceId, + options, + }: RunOnWorkspaceArgs): Promise { + const isDryRun = options.dryRun ?? false; + + const { + flatObjectMetadataMaps, + flatFieldMetadataMaps, + flatIndexMaps, + flatViewMaps, + flatViewFieldMaps, + flatViewFieldGroupMaps, + flatPageLayoutMaps, + flatPageLayoutTabMaps, + flatPageLayoutWidgetMaps, + flatCommandMenuItemMaps, + } = await this.workspaceCacheService.getOrRecompute(workspaceId, [ + 'flatObjectMetadataMaps', + 'flatFieldMetadataMaps', + 'flatIndexMaps', + 'flatViewMaps', + 'flatViewFieldMaps', + 'flatViewFieldGroupMaps', + 'flatPageLayoutMaps', + 'flatPageLayoutTabMaps', + 'flatPageLayoutWidgetMaps', + 'flatCommandMenuItemMaps', + ]); + + const calendarEventObjectMetadata = + flatObjectMetadataMaps.byUniversalIdentifier[ + STANDARD_OBJECTS.calendarEvent.universalIdentifier + ]; + + if (!isDefined(calendarEventObjectMetadata)) { + throw new Error( + `calendarEvent object not found for workspace ${workspaceId}`, + ); + } + + const { twentyStandardFlatApplication } = + await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( + { workspaceId }, + ); + + const now = new Date().toISOString(); + + const { allFlatEntityMaps: standardAllFlatEntityMaps } = + computeTwentyStandardApplicationAllFlatEntityMaps({ + now, + workspaceId, + twentyStandardApplicationId: twentyStandardFlatApplication.id, + }); + + const objectMetadataRenameUpdates = buildCallRecordingObjectRenameUpdates({ + flatObjectMetadataMaps, + now, + }); + const fieldMetadataRenameUpdates = buildCalendarEventFieldRenameUpdates({ + flatFieldMetadataMaps, + now, + }); + const renamedCollisionObjectMetadatas = objectMetadataRenameUpdates.map( + (objectMetadata) => ({ + universalIdentifier: objectMetadata.universalIdentifier, + nameSingular: objectMetadata.nameSingular, + }), + ); + + const callRecordingObjectMetadataForNavigation = + getExistingOrStandardFlatEntityOrThrow({ + standardFlatEntityMaps: + standardAllFlatEntityMaps.flatObjectMetadataMaps, + existingFlatEntityMaps: flatObjectMetadataMaps, + universalIdentifier: STANDARD_OBJECTS.callRecording.universalIdentifier, + }); + + const navigationCommandMenuItemOperations = + buildNavigationCommandMenuItemOperationsOrThrow({ + existingFlatCommandMenuItemMaps: flatCommandMenuItemMaps, + objectMetadatasForNavigation: [ + callRecordingObjectMetadataForNavigation, + ], + applicationId: twentyStandardFlatApplication.id, + workspaceId, + now, + renamedCollisionObjectMetadatas, + }); + + const allFlatEntityOperationByMetadataName = { + objectMetadata: { + flatEntityToCreate: + getStandardFlatEntitiesToCreateOrThrow({ + standardFlatEntityMaps: + standardAllFlatEntityMaps.flatObjectMetadataMaps, + existingFlatEntityMaps: flatObjectMetadataMaps, + universalIdentifiers: + CALL_RECORDING_OBJECT_METADATA_UNIVERSAL_IDENTIFIERS, + }), + flatEntityToDelete: [], + flatEntityToUpdate: [], + }, + fieldMetadata: { + flatEntityToCreate: + getStandardFlatEntitiesToCreateOrThrow({ + standardFlatEntityMaps: + standardAllFlatEntityMaps.flatFieldMetadataMaps, + existingFlatEntityMaps: flatFieldMetadataMaps, + universalIdentifiers: + CALL_RECORDING_FIELD_METADATA_UNIVERSAL_IDENTIFIERS, + }), + flatEntityToDelete: [], + flatEntityToUpdate: [], + }, + index: { + flatEntityToCreate: + getStandardFlatEntitiesToCreateOrThrow({ + standardFlatEntityMaps: standardAllFlatEntityMaps.flatIndexMaps, + existingFlatEntityMaps: flatIndexMaps, + universalIdentifiers: CALL_RECORDING_INDEX_UNIVERSAL_IDENTIFIERS, + }), + flatEntityToDelete: [], + flatEntityToUpdate: [], + }, + view: { + flatEntityToCreate: getStandardFlatEntitiesToCreateOrThrow({ + standardFlatEntityMaps: standardAllFlatEntityMaps.flatViewMaps, + existingFlatEntityMaps: flatViewMaps, + universalIdentifiers: CALL_RECORDING_VIEW_UNIVERSAL_IDENTIFIERS, + }), + flatEntityToDelete: [], + flatEntityToUpdate: [], + }, + viewFieldGroup: { + flatEntityToCreate: + getStandardFlatEntitiesToCreateOrThrow({ + standardFlatEntityMaps: + standardAllFlatEntityMaps.flatViewFieldGroupMaps, + existingFlatEntityMaps: flatViewFieldGroupMaps, + universalIdentifiers: + CALL_RECORDING_VIEW_FIELD_GROUP_UNIVERSAL_IDENTIFIERS, + }), + flatEntityToDelete: [], + flatEntityToUpdate: [], + }, + viewField: { + flatEntityToCreate: + getStandardFlatEntitiesToCreateOrThrow({ + standardFlatEntityMaps: standardAllFlatEntityMaps.flatViewFieldMaps, + existingFlatEntityMaps: flatViewFieldMaps, + universalIdentifiers: + CALL_RECORDING_VIEW_FIELD_UNIVERSAL_IDENTIFIERS, + }), + flatEntityToDelete: [], + flatEntityToUpdate: [], + }, + pageLayout: { + flatEntityToCreate: + getStandardFlatEntitiesToCreateOrThrow({ + standardFlatEntityMaps: + standardAllFlatEntityMaps.flatPageLayoutMaps, + existingFlatEntityMaps: flatPageLayoutMaps, + universalIdentifiers: + CALL_RECORDING_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS, + }), + flatEntityToDelete: [], + flatEntityToUpdate: [], + }, + pageLayoutTab: { + flatEntityToCreate: + getStandardFlatEntitiesToCreateOrThrow({ + standardFlatEntityMaps: + standardAllFlatEntityMaps.flatPageLayoutTabMaps, + existingFlatEntityMaps: flatPageLayoutTabMaps, + universalIdentifiers: + CALL_RECORDING_PAGE_LAYOUT_TAB_UNIVERSAL_IDENTIFIERS, + }), + flatEntityToDelete: [], + flatEntityToUpdate: [], + }, + pageLayoutWidget: { + flatEntityToCreate: + getStandardFlatEntitiesToCreateOrThrow({ + standardFlatEntityMaps: + standardAllFlatEntityMaps.flatPageLayoutWidgetMaps, + existingFlatEntityMaps: flatPageLayoutWidgetMaps, + universalIdentifiers: + CALL_RECORDING_PAGE_LAYOUT_WIDGET_UNIVERSAL_IDENTIFIERS, + }), + flatEntityToDelete: [], + flatEntityToUpdate: [], + }, + commandMenuItem: navigationCommandMenuItemOperations, + }; + + const totalOperationCount = + objectMetadataRenameUpdates.length + + fieldMetadataRenameUpdates.length + + Object.values(allFlatEntityOperationByMetadataName).reduce( + (total, operations) => + total + + operations.flatEntityToCreate.length + + operations.flatEntityToUpdate.length, + 0, + ); + + if (totalOperationCount === 0) { + this.logger.log( + `CallRecording standard metadata already exists for workspace ${workspaceId}, skipping`, + ); + + return; + } + + if (isDryRun) { + if (objectMetadataRenameUpdates.length > 0) { + this.logger.log( + `[DRY RUN] Would rename ${objectMetadataRenameUpdates.length} CallRecording object name collision(s) for workspace ${workspaceId}`, + ); + } + + if (fieldMetadataRenameUpdates.length > 0) { + this.logger.log( + `[DRY RUN] Would rename ${fieldMetadataRenameUpdates.length} calendarEvent field name collision(s) for workspace ${workspaceId}`, + ); + } + + this.logger.log( + `[DRY RUN] Would apply ${totalOperationCount} CallRecording standard metadata operations for workspace ${workspaceId}`, + ); + + return; + } + + // Renames must commit before the create: a combined create + rename + // migration trips the namePlural unique index. + const collisionRenameMigrations = [ + ...objectMetadataRenameUpdates.map((flatObjectMetadata) => ({ + applicationUniversalIdentifier: + flatObjectMetadata.applicationUniversalIdentifier, + allFlatEntityOperationByMetadataName: { + objectMetadata: { + flatEntityToCreate: [], + flatEntityToDelete: [], + flatEntityToUpdate: [flatObjectMetadata], + }, + }, + })), + ...fieldMetadataRenameUpdates.map((flatFieldMetadata) => ({ + applicationUniversalIdentifier: + flatFieldMetadata.applicationUniversalIdentifier, + allFlatEntityOperationByMetadataName: { + fieldMetadata: { + flatEntityToCreate: [], + flatEntityToDelete: [], + flatEntityToUpdate: [flatFieldMetadata], + }, + }, + })), + ]; + + // Collisions can belong to different applications, so each rename runs as + // its own migration scoped to the colliding entity's application. + for (const { + applicationUniversalIdentifier, + allFlatEntityOperationByMetadataName, + } of collisionRenameMigrations) { + const renameResult = + await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration( + { + isSystemBuild: true, + applicationUniversalIdentifier, + workspaceId, + allFlatEntityOperationByMetadataName, + }, + ); + + if (renameResult.status === 'fail') { + throw new Error( + `Failed to rename CallRecording name collision for workspace ${workspaceId}: ${JSON.stringify( + renameResult, + null, + 2, + )}`, + ); + } + } + + const validateAndBuildResult = + await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration( + { + isSystemBuild: true, + applicationUniversalIdentifier: + twentyStandardFlatApplication.universalIdentifier, + workspaceId, + allFlatEntityOperationByMetadataName, + }, + ); + + if (validateAndBuildResult.status === 'fail') { + throw new Error( + `Failed to create CallRecording standard objects for workspace ${workspaceId}: ${JSON.stringify( + validateAndBuildResult, + null, + 2, + )}`, + ); + } + + this.logger.log( + `Applied ${totalOperationCount} CallRecording standard metadata operations for workspace ${workspaceId}`, + ); + } +} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/2-10/utils/__tests__/build-navigation-command-menu-item-operations-or-throw.util.spec.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/2-10/utils/__tests__/build-navigation-command-menu-item-operations-or-throw.util.spec.ts new file mode 100644 index 0000000000..f2a0153e5c --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/2-10/utils/__tests__/build-navigation-command-menu-item-operations-or-throw.util.spec.ts @@ -0,0 +1,241 @@ +import { v5 } from 'uuid'; + +import { buildNavigationCommandMenuItemOperationsOrThrow } from 'src/database/commands/upgrade-version-command/2-10/utils/build-navigation-command-menu-item-operations-or-throw.util'; +import { type FlatCommandMenuItem } from 'src/engine/metadata-modules/flat-command-menu-item/types/flat-command-menu-item.type'; +import { + buildNavigationFlatCommandMenuItem, + NAVIGATION_COMMAND_UUID_NAMESPACE, +} from 'src/engine/metadata-modules/flat-command-menu-item/utils/build-navigation-flat-command-menu-item.util'; +import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type'; +import { getFlatObjectMetadataMock } from 'src/engine/metadata-modules/flat-object-metadata/__mocks__/get-flat-object-metadata.mock'; + +const APPLICATION_ID = 'application-id'; +const WORKSPACE_ID = 'workspace-id'; +const NOW = '2026-06-04T00:00:00.000Z'; + +const buildFlatCommandMenuItemMaps = ( + flatCommandMenuItems: FlatCommandMenuItem[], +): FlatEntityMaps => ({ + byUniversalIdentifier: Object.fromEntries( + flatCommandMenuItems.map((flatCommandMenuItem) => [ + flatCommandMenuItem.universalIdentifier, + flatCommandMenuItem, + ]), + ), + universalIdentifierById: Object.fromEntries( + flatCommandMenuItems.map((flatCommandMenuItem) => [ + flatCommandMenuItem.id, + flatCommandMenuItem.universalIdentifier, + ]), + ), + universalIdentifiersByApplicationId: {}, +}); + +const buildExistingNavigationItem = ({ + objectId, + objectUniversalIdentifier, + nameSingular, + position, +}: { + objectId: string; + objectUniversalIdentifier: string; + nameSingular: string; + position: number; +}): FlatCommandMenuItem => + buildNavigationFlatCommandMenuItem({ + objectMetadata: { + id: objectId, + universalIdentifier: objectUniversalIdentifier, + nameSingular, + shortcut: null, + }, + commandMenuItemId: `command-menu-item-${objectUniversalIdentifier}`, + applicationId: APPLICATION_ID, + workspaceId: WORKSPACE_ID, + position, + now: NOW, + }); + +describe('buildNavigationCommandMenuItemOperationsOrThrow', () => { + it('creates a navigation item for an active object that has no existing navigation', () => { + const objectMetadata = getFlatObjectMetadataMock({ + universalIdentifier: 'call-recording', + nameSingular: 'callRecording', + namePlural: 'callRecordings', + }); + + const result = buildNavigationCommandMenuItemOperationsOrThrow({ + existingFlatCommandMenuItemMaps: buildFlatCommandMenuItemMaps([]), + objectMetadatasForNavigation: [objectMetadata], + applicationId: APPLICATION_ID, + workspaceId: WORKSPACE_ID, + now: NOW, + renamedCollisionObjectMetadatas: [], + }); + + expect(result.flatEntityToCreate).toHaveLength(1); + expect(result.flatEntityToCreate[0].universalIdentifier).toBe( + v5('call-recording', NAVIGATION_COMMAND_UUID_NAMESPACE), + ); + expect(result.flatEntityToCreate[0].position).toBe(0); + expect(result.flatEntityToCreate[0].payload).toEqual({ + objectMetadataItemId: objectMetadata.id, + }); + expect(result.flatEntityToUpdate).toHaveLength(0); + expect(result.flatEntityToDelete).toHaveLength(0); + }); + + it('uses the provided object id in the navigation payload', () => { + const objectMetadata = getFlatObjectMetadataMock({ + id: 'existing-call-recording-object-id', + universalIdentifier: 'call-recording', + nameSingular: 'callRecording', + namePlural: 'callRecordings', + }); + + const result = buildNavigationCommandMenuItemOperationsOrThrow({ + existingFlatCommandMenuItemMaps: buildFlatCommandMenuItemMaps([]), + objectMetadatasForNavigation: [objectMetadata], + applicationId: APPLICATION_ID, + workspaceId: WORKSPACE_ID, + now: NOW, + renamedCollisionObjectMetadatas: [], + }); + + expect(result.flatEntityToCreate[0].payload).toEqual({ + objectMetadataItemId: 'existing-call-recording-object-id', + }); + }); + + it('does not create a navigation item for an inactive object', () => { + const objectMetadata = getFlatObjectMetadataMock({ + universalIdentifier: 'call-recording', + nameSingular: 'callRecording', + namePlural: 'callRecordings', + isActive: false, + }); + + const result = buildNavigationCommandMenuItemOperationsOrThrow({ + existingFlatCommandMenuItemMaps: buildFlatCommandMenuItemMaps([]), + objectMetadatasForNavigation: [objectMetadata], + applicationId: APPLICATION_ID, + workspaceId: WORKSPACE_ID, + now: NOW, + renamedCollisionObjectMetadatas: [], + }); + + expect(result.flatEntityToCreate).toHaveLength(0); + }); + + it('does not recreate a navigation item that already exists (idempotent)', () => { + const objectMetadata = getFlatObjectMetadataMock({ + universalIdentifier: 'call-recording', + nameSingular: 'callRecording', + namePlural: 'callRecordings', + }); + const existingNavigationItem = buildExistingNavigationItem({ + objectId: objectMetadata.id, + objectUniversalIdentifier: 'call-recording', + nameSingular: 'callRecording', + position: 0, + }); + + const result = buildNavigationCommandMenuItemOperationsOrThrow({ + existingFlatCommandMenuItemMaps: buildFlatCommandMenuItemMaps([ + existingNavigationItem, + ]), + objectMetadatasForNavigation: [objectMetadata], + applicationId: APPLICATION_ID, + workspaceId: WORKSPACE_ID, + now: NOW, + renamedCollisionObjectMetadatas: [], + }); + + expect(result.flatEntityToCreate).toHaveLength(0); + }); + + it('positions the new navigation item after the highest existing position', () => { + const objectMetadata = getFlatObjectMetadataMock({ + universalIdentifier: 'call-recording', + nameSingular: 'callRecording', + namePlural: 'callRecordings', + }); + const existingNavigationItems = [ + buildExistingNavigationItem({ + objectId: 'other-object-1-id', + objectUniversalIdentifier: 'other-object-1', + nameSingular: 'otherObjectOne', + position: 0, + }), + buildExistingNavigationItem({ + objectId: 'other-object-2-id', + objectUniversalIdentifier: 'other-object-2', + nameSingular: 'otherObjectTwo', + position: 5, + }), + ]; + + const result = buildNavigationCommandMenuItemOperationsOrThrow({ + existingFlatCommandMenuItemMaps: buildFlatCommandMenuItemMaps( + existingNavigationItems, + ), + objectMetadatasForNavigation: [objectMetadata], + applicationId: APPLICATION_ID, + workspaceId: WORKSPACE_ID, + now: NOW, + renamedCollisionObjectMetadatas: [], + }); + + expect(result.flatEntityToCreate[0].position).toBe(6); + }); + + it('rewrites the stale availability expression of a renamed object navigation item', () => { + const existingNavigationItem = buildExistingNavigationItem({ + objectId: 'colliding-object-id', + objectUniversalIdentifier: 'colliding-object', + nameSingular: 'callRecording', + position: 0, + }); + + const result = buildNavigationCommandMenuItemOperationsOrThrow({ + existingFlatCommandMenuItemMaps: buildFlatCommandMenuItemMaps([ + existingNavigationItem, + ]), + objectMetadatasForNavigation: [], + applicationId: APPLICATION_ID, + workspaceId: WORKSPACE_ID, + now: NOW, + renamedCollisionObjectMetadatas: [ + { + universalIdentifier: 'colliding-object', + nameSingular: 'callRecordingOld', + }, + ], + }); + + expect(result.flatEntityToUpdate).toHaveLength(1); + expect(result.flatEntityToUpdate[0].conditionalAvailabilityExpression).toBe( + 'targetObjectReadPermissions.callRecordingOld', + ); + expect(result.flatEntityToUpdate[0].updatedAt).toBe(NOW); + expect(result.flatEntityToCreate).toHaveLength(0); + }); + + it('does not produce an update when a renamed object has no existing navigation item', () => { + const result = buildNavigationCommandMenuItemOperationsOrThrow({ + existingFlatCommandMenuItemMaps: buildFlatCommandMenuItemMaps([]), + objectMetadatasForNavigation: [], + applicationId: APPLICATION_ID, + workspaceId: WORKSPACE_ID, + now: NOW, + renamedCollisionObjectMetadatas: [ + { + universalIdentifier: 'colliding-object', + nameSingular: 'callRecordingOld', + }, + ], + }); + + expect(result.flatEntityToUpdate).toHaveLength(0); + }); +}); diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/2-10/utils/__tests__/call-recording-name-collision.util.spec.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/2-10/utils/__tests__/call-recording-name-collision.util.spec.ts new file mode 100644 index 0000000000..07de873525 --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/2-10/utils/__tests__/call-recording-name-collision.util.spec.ts @@ -0,0 +1,467 @@ +import { STANDARD_OBJECTS } from 'twenty-shared/metadata'; +import { FieldMetadataType } from 'twenty-shared/types'; + +import { + buildCalendarEventFieldRenameUpdates, + buildCallRecordingObjectRenameUpdates, + findCalendarEventFieldNameCollisionsForCallRecording, + findCallRecordingObjectNameCollisions, + resolveAvailableOldCalendarEventFieldName, + resolveAvailableOldCallRecordingObjectNames, +} from 'src/database/commands/upgrade-version-command/2-10/utils/call-recording-name-collision.util'; +import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type'; +import { getFlatFieldMetadataMock } from 'src/engine/metadata-modules/flat-field-metadata/__mocks__/get-flat-field-metadata.mock'; +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { getFlatObjectMetadataMock } from 'src/engine/metadata-modules/flat-object-metadata/__mocks__/get-flat-object-metadata.mock'; +import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; + +const NOW = '2026-06-04T00:00:00.000Z'; +const CALENDAR_EVENT_OBJECT_METADATA_ID = 'calendar-event-object-metadata-id'; + +const buildFlatObjectMetadataMaps = ( + flatObjectMetadatas: FlatObjectMetadata[], +): FlatEntityMaps => ({ + byUniversalIdentifier: Object.fromEntries( + flatObjectMetadatas.map((flatObjectMetadata) => [ + flatObjectMetadata.universalIdentifier, + flatObjectMetadata, + ]), + ), + universalIdentifierById: Object.fromEntries( + flatObjectMetadatas.map((flatObjectMetadata) => [ + flatObjectMetadata.id, + flatObjectMetadata.universalIdentifier, + ]), + ), + universalIdentifiersByApplicationId: {}, +}); + +const buildFlatFieldMetadataMaps = ( + flatFieldMetadatas: FlatFieldMetadata[], +): FlatEntityMaps => ({ + byUniversalIdentifier: Object.fromEntries( + flatFieldMetadatas.map((flatFieldMetadata) => [ + flatFieldMetadata.universalIdentifier, + flatFieldMetadata, + ]), + ), + universalIdentifierById: Object.fromEntries( + flatFieldMetadatas.map((flatFieldMetadata) => [ + flatFieldMetadata.id, + flatFieldMetadata.universalIdentifier, + ]), + ), + universalIdentifiersByApplicationId: {}, +}); + +const getCalendarEventFieldMetadataMock = ( + overrides: Pick & + Partial, +): FlatFieldMetadata => + getFlatFieldMetadataMock({ + objectMetadataId: CALENDAR_EVENT_OBJECT_METADATA_ID, + objectMetadataUniversalIdentifier: + STANDARD_OBJECTS.calendarEvent.universalIdentifier, + type: FieldMetadataType.TEXT, + label: overrides.name, + ...overrides, + }); + +describe('findCallRecordingObjectNameCollisions', () => { + it('returns an empty array when no object uses the callRecording name', () => { + const maps = buildFlatObjectMetadataMaps([ + getFlatObjectMetadataMock({ + universalIdentifier: 'unrelated-object', + nameSingular: 'invoice', + namePlural: 'invoices', + }), + ]); + + expect(findCallRecordingObjectNameCollisions(maps)).toEqual([]); + }); + + it('returns the custom object whose singular name collides', () => { + const maps = buildFlatObjectMetadataMaps([ + getFlatObjectMetadataMock({ + universalIdentifier: 'colliding-singular', + nameSingular: 'callRecording', + namePlural: 'myRecordings', + }), + ]); + + expect( + findCallRecordingObjectNameCollisions(maps).map( + (object) => object.universalIdentifier, + ), + ).toEqual(['colliding-singular']); + }); + + it('returns the custom object whose plural name collides', () => { + const maps = buildFlatObjectMetadataMaps([ + getFlatObjectMetadataMock({ + universalIdentifier: 'colliding-plural', + nameSingular: 'myRecording', + namePlural: 'callRecordings', + }), + ]); + + expect( + findCallRecordingObjectNameCollisions(maps).map( + (object) => object.universalIdentifier, + ), + ).toEqual(['colliding-plural']); + }); + + it('returns every colliding object when singular and plural collide on different objects', () => { + const maps = buildFlatObjectMetadataMaps([ + getFlatObjectMetadataMock({ + universalIdentifier: 'colliding-singular', + nameSingular: 'callRecording', + namePlural: 'myRecordings', + }), + getFlatObjectMetadataMock({ + universalIdentifier: 'colliding-plural', + nameSingular: 'myRecording', + namePlural: 'callRecordings', + }), + ]); + + expect( + findCallRecordingObjectNameCollisions(maps) + .map((object) => object.universalIdentifier) + .sort(), + ).toEqual(['colliding-plural', 'colliding-singular']); + }); + + it('excludes the standard callRecording object itself', () => { + const maps = buildFlatObjectMetadataMaps([ + getFlatObjectMetadataMock({ + universalIdentifier: STANDARD_OBJECTS.callRecording.universalIdentifier, + nameSingular: 'callRecording', + namePlural: 'callRecordings', + isCustom: false, + isSystem: true, + }), + ]); + + expect(findCallRecordingObjectNameCollisions(maps)).toEqual([]); + }); +}); + +describe('resolveAvailableOldCallRecordingObjectNames', () => { + it('returns the unsuffixed Old names when none are taken', () => { + const maps = buildFlatObjectMetadataMaps([ + getFlatObjectMetadataMock({ + universalIdentifier: 'colliding', + nameSingular: 'callRecording', + namePlural: 'callRecordings', + }), + ]); + + expect(resolveAvailableOldCallRecordingObjectNames(maps)).toEqual({ + nameSingular: 'callRecordingOld', + namePlural: 'callRecordingsOld', + labelSingular: 'Call Recording (Old)', + labelPlural: 'Call Recordings (Old)', + }); + }); + + it('advances to the next discriminator when the Old name is already taken', () => { + const maps = buildFlatObjectMetadataMaps([ + getFlatObjectMetadataMock({ + universalIdentifier: 'colliding', + nameSingular: 'callRecording', + namePlural: 'callRecordings', + }), + getFlatObjectMetadataMock({ + universalIdentifier: 'old-already-taken', + nameSingular: 'callRecordingOld', + namePlural: 'callRecordingsOld', + }), + ]); + + expect(resolveAvailableOldCallRecordingObjectNames(maps)).toEqual({ + nameSingular: 'callRecordingOld2', + namePlural: 'callRecordingsOld2', + labelSingular: 'Call Recording (Old) 2', + labelPlural: 'Call Recordings (Old) 2', + }); + }); + + it('skips Old names provided as already reserved', () => { + const maps = buildFlatObjectMetadataMaps([ + getFlatObjectMetadataMock({ + universalIdentifier: 'colliding', + nameSingular: 'callRecording', + namePlural: 'callRecordings', + }), + ]); + + expect( + resolveAvailableOldCallRecordingObjectNames( + maps, + new Set(['callRecordingOld', 'callRecordingsOld']), + ), + ).toEqual({ + nameSingular: 'callRecordingOld2', + namePlural: 'callRecordingsOld2', + labelSingular: 'Call Recording (Old) 2', + labelPlural: 'Call Recordings (Old) 2', + }); + }); + + it('skips a discriminator when only the plural Old name is taken', () => { + const maps = buildFlatObjectMetadataMaps([ + getFlatObjectMetadataMock({ + universalIdentifier: 'plural-old-taken', + nameSingular: 'unrelatedSingular', + namePlural: 'callRecordingsOld', + }), + ]); + + expect(resolveAvailableOldCallRecordingObjectNames(maps)).toEqual({ + nameSingular: 'callRecordingOld2', + namePlural: 'callRecordingsOld2', + labelSingular: 'Call Recording (Old) 2', + labelPlural: 'Call Recordings (Old) 2', + }); + }); + + it('throws when every candidate Old name is taken', () => { + const blockedSingularNames = Array.from({ length: 100 }, (_, attempt) => { + const discriminator = attempt === 0 ? '' : `${attempt + 1}`; + + return `callRecordingOld${discriminator}`; + }); + + const maps = buildFlatObjectMetadataMaps( + blockedSingularNames.map((nameSingular, index) => + getFlatObjectMetadataMock({ + universalIdentifier: `taken-${index}`, + nameSingular, + namePlural: `${nameSingular}Filler`, + }), + ), + ); + + expect(() => resolveAvailableOldCallRecordingObjectNames(maps)).toThrow( + 'Could not find an available callRecordingOld name after 100 attempts', + ); + }); +}); + +describe('buildCallRecordingObjectRenameUpdates', () => { + it('builds a migration update for a colliding object name', () => { + const maps = buildFlatObjectMetadataMaps([ + getFlatObjectMetadataMock({ + universalIdentifier: 'colliding', + nameSingular: 'callRecording', + namePlural: 'callRecordings', + }), + ]); + + expect( + buildCallRecordingObjectRenameUpdates({ + flatObjectMetadataMaps: maps, + now: NOW, + }), + ).toMatchObject([ + { + universalIdentifier: 'colliding', + nameSingular: 'callRecordingOld', + namePlural: 'callRecordingsOld', + labelSingular: 'Call Recording (Old)', + labelPlural: 'Call Recordings (Old)', + isLabelSyncedWithName: false, + updatedAt: NOW, + }, + ]); + }); + + it('reserves generated names across multiple object updates', () => { + const maps = buildFlatObjectMetadataMaps([ + getFlatObjectMetadataMock({ + universalIdentifier: 'colliding-singular', + nameSingular: 'callRecording', + namePlural: 'myRecordings', + }), + getFlatObjectMetadataMock({ + universalIdentifier: 'colliding-plural', + nameSingular: 'myRecording', + namePlural: 'callRecordings', + }), + ]); + + expect( + buildCallRecordingObjectRenameUpdates({ + flatObjectMetadataMaps: maps, + now: NOW, + }).map((objectMetadata) => objectMetadata.nameSingular), + ).toEqual(['callRecordingOld', 'callRecordingOld2']); + }); +}); + +describe('findCalendarEventFieldNameCollisionsForCallRecording', () => { + it('finds calendarEvent fields that use a name reserved by CallRecording', () => { + const maps = buildFlatFieldMetadataMaps([ + getCalendarEventFieldMetadataMock({ + universalIdentifier: 'colliding-recording-preference', + name: 'recordingPreference', + label: 'Recording Preference', + }), + getCalendarEventFieldMetadataMock({ + universalIdentifier: 'colliding-call-recordings', + name: 'callRecordings', + label: 'Call Recordings', + }), + ]); + + expect( + findCalendarEventFieldNameCollisionsForCallRecording(maps).map( + (fieldMetadata) => fieldMetadata.universalIdentifier, + ), + ).toEqual(['colliding-recording-preference', 'colliding-call-recordings']); + }); + + it('excludes the CallRecording standard calendarEvent fields', () => { + const maps = buildFlatFieldMetadataMaps([ + getCalendarEventFieldMetadataMock({ + universalIdentifier: + STANDARD_OBJECTS.calendarEvent.fields.recordingPreference + .universalIdentifier, + name: 'recordingPreference', + }), + getCalendarEventFieldMetadataMock({ + universalIdentifier: + STANDARD_OBJECTS.calendarEvent.fields.callRecordings + .universalIdentifier, + name: 'callRecordings', + }), + ]); + + expect(findCalendarEventFieldNameCollisionsForCallRecording(maps)).toEqual( + [], + ); + }); + + it('excludes fields on objects other than calendarEvent', () => { + const maps = buildFlatFieldMetadataMaps([ + getFlatFieldMetadataMock({ + universalIdentifier: 'other-object-field', + objectMetadataId: 'other-object-id', + objectMetadataUniversalIdentifier: 'other-object', + type: FieldMetadataType.TEXT, + name: 'recordingPreference', + label: 'Recording Preference', + }), + ]); + + expect(findCalendarEventFieldNameCollisionsForCallRecording(maps)).toEqual( + [], + ); + }); +}); + +describe('resolveAvailableOldCalendarEventFieldName', () => { + it('returns the unsuffixed Old field name when it is available', () => { + const maps = buildFlatFieldMetadataMaps([ + getCalendarEventFieldMetadataMock({ + universalIdentifier: 'colliding-field', + name: 'recordingPreference', + }), + ]); + + expect( + resolveAvailableOldCalendarEventFieldName({ + flatFieldMetadataMaps: maps, + originalFieldName: 'recordingPreference', + }), + ).toBe('recordingPreferenceOld'); + }); + + it('advances to the next discriminator when the Old field name is taken', () => { + const maps = buildFlatFieldMetadataMaps([ + getCalendarEventFieldMetadataMock({ + universalIdentifier: 'colliding-field', + name: 'recordingPreference', + }), + getCalendarEventFieldMetadataMock({ + universalIdentifier: 'old-field-name-taken', + name: 'recordingPreferenceOld', + }), + ]); + + expect( + resolveAvailableOldCalendarEventFieldName({ + flatFieldMetadataMaps: maps, + originalFieldName: 'recordingPreference', + }), + ).toBe('recordingPreferenceOld2'); + }); + + it('skips Old field names provided as already reserved', () => { + const maps = buildFlatFieldMetadataMaps([ + getCalendarEventFieldMetadataMock({ + universalIdentifier: 'colliding-field', + name: 'callRecordings', + }), + ]); + + expect( + resolveAvailableOldCalendarEventFieldName({ + flatFieldMetadataMaps: maps, + originalFieldName: 'callRecordings', + additionalTakenNames: new Set(['callRecordingsOld']), + }), + ).toBe('callRecordingsOld2'); + }); +}); + +describe('buildCalendarEventFieldRenameUpdates', () => { + it('builds a migration update for a colliding calendarEvent field name', () => { + const maps = buildFlatFieldMetadataMaps([ + getCalendarEventFieldMetadataMock({ + universalIdentifier: 'colliding-field', + name: 'recordingPreference', + label: 'Recording Preference', + }), + ]); + + expect( + buildCalendarEventFieldRenameUpdates({ + flatFieldMetadataMaps: maps, + now: NOW, + }), + ).toMatchObject([ + { + universalIdentifier: 'colliding-field', + name: 'recordingPreferenceOld', + label: 'Recording Preference (Old)', + isLabelSyncedWithName: false, + updatedAt: NOW, + }, + ]); + }); + + it('reserves generated names across multiple field updates', () => { + const maps = buildFlatFieldMetadataMaps([ + getCalendarEventFieldMetadataMock({ + universalIdentifier: 'colliding-field-one', + name: 'recordingPreference', + label: 'Recording Preference', + }), + getCalendarEventFieldMetadataMock({ + universalIdentifier: 'colliding-field-two', + name: 'recordingPreference', + label: 'Recording Preference', + }), + ]); + + expect( + buildCalendarEventFieldRenameUpdates({ + flatFieldMetadataMaps: maps, + now: NOW, + }).map((fieldMetadata) => fieldMetadata.name), + ).toEqual(['recordingPreferenceOld', 'recordingPreferenceOld2']); + }); +}); diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/2-10/utils/__tests__/get-standard-flat-entities-to-create-or-throw.util.spec.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/2-10/utils/__tests__/get-standard-flat-entities-to-create-or-throw.util.spec.ts new file mode 100644 index 0000000000..4f2ba05aa5 --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/2-10/utils/__tests__/get-standard-flat-entities-to-create-or-throw.util.spec.ts @@ -0,0 +1,177 @@ +import { + getExistingOrStandardFlatEntityOrThrow, + getStandardFlatEntitiesToCreateOrThrow, +} from 'src/database/commands/upgrade-version-command/2-10/utils/get-standard-flat-entities-to-create-or-throw.util'; +import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type'; +import { getFlatObjectMetadataMock } from 'src/engine/metadata-modules/flat-object-metadata/__mocks__/get-flat-object-metadata.mock'; +import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; + +const buildFlatObjectMetadataMaps = ( + flatObjectMetadatas: FlatObjectMetadata[], +): FlatEntityMaps => ({ + byUniversalIdentifier: Object.fromEntries( + flatObjectMetadatas.map((flatObjectMetadata) => [ + flatObjectMetadata.universalIdentifier, + flatObjectMetadata, + ]), + ), + universalIdentifierById: Object.fromEntries( + flatObjectMetadatas.map((flatObjectMetadata) => [ + flatObjectMetadata.id, + flatObjectMetadata.universalIdentifier, + ]), + ), + universalIdentifiersByApplicationId: {}, +}); + +describe('getStandardFlatEntitiesToCreateOrThrow', () => { + it('returns the standard entity when it is absent from the existing maps', () => { + const standardEntity = getFlatObjectMetadataMock({ + universalIdentifier: 'call-recording', + nameSingular: 'callRecording', + namePlural: 'callRecordings', + }); + const standardFlatEntityMaps = buildFlatObjectMetadataMaps([ + standardEntity, + ]); + const existingFlatEntityMaps = buildFlatObjectMetadataMaps([]); + + expect( + getStandardFlatEntitiesToCreateOrThrow({ + standardFlatEntityMaps, + existingFlatEntityMaps, + universalIdentifiers: ['call-recording'], + }), + ).toEqual([standardEntity]); + }); + + it('skips an entity that already exists in the existing maps (idempotent re-run)', () => { + const standardEntity = getFlatObjectMetadataMock({ + universalIdentifier: 'call-recording', + nameSingular: 'callRecording', + namePlural: 'callRecordings', + }); + const standardFlatEntityMaps = buildFlatObjectMetadataMaps([ + standardEntity, + ]); + const existingFlatEntityMaps = buildFlatObjectMetadataMaps([ + standardEntity, + ]); + + expect( + getStandardFlatEntitiesToCreateOrThrow({ + standardFlatEntityMaps, + existingFlatEntityMaps, + universalIdentifiers: ['call-recording'], + }), + ).toEqual([]); + }); + + it('returns only the entities missing from the existing maps', () => { + const existingEntity = getFlatObjectMetadataMock({ + universalIdentifier: 'already-synced', + nameSingular: 'alreadySynced', + namePlural: 'alreadySynceds', + }); + const missingEntity = getFlatObjectMetadataMock({ + universalIdentifier: 'not-yet-synced', + nameSingular: 'notYetSynced', + namePlural: 'notYetSynceds', + }); + const standardFlatEntityMaps = buildFlatObjectMetadataMaps([ + existingEntity, + missingEntity, + ]); + const existingFlatEntityMaps = buildFlatObjectMetadataMaps([ + existingEntity, + ]); + + expect( + getStandardFlatEntitiesToCreateOrThrow({ + standardFlatEntityMaps, + existingFlatEntityMaps, + universalIdentifiers: ['already-synced', 'not-yet-synced'], + }), + ).toEqual([missingEntity]); + }); + + it('returns an empty array when no universal identifiers are requested', () => { + const standardFlatEntityMaps = buildFlatObjectMetadataMaps([ + getFlatObjectMetadataMock({ + universalIdentifier: 'call-recording', + nameSingular: 'callRecording', + namePlural: 'callRecordings', + }), + ]); + + expect( + getStandardFlatEntitiesToCreateOrThrow({ + standardFlatEntityMaps, + existingFlatEntityMaps: buildFlatObjectMetadataMaps([]), + universalIdentifiers: [], + }), + ).toEqual([]); + }); + + it('throws when a requested identifier is missing from the standard maps', () => { + expect(() => + getStandardFlatEntitiesToCreateOrThrow({ + standardFlatEntityMaps: buildFlatObjectMetadataMaps([]), + existingFlatEntityMaps: buildFlatObjectMetadataMaps([]), + universalIdentifiers: ['missing-from-standard'], + }), + ).toThrow('Could not find standard entity missing-from-standard'); + }); +}); + +describe('getExistingOrStandardFlatEntityOrThrow', () => { + it('returns the existing entity when one already exists', () => { + const standardEntity = getFlatObjectMetadataMock({ + id: 'standard-id', + universalIdentifier: 'call-recording', + nameSingular: 'callRecording', + namePlural: 'callRecordings', + }); + const existingEntity = getFlatObjectMetadataMock({ + id: 'existing-id', + universalIdentifier: 'call-recording', + nameSingular: 'callRecording', + namePlural: 'callRecordings', + }); + + expect( + getExistingOrStandardFlatEntityOrThrow({ + standardFlatEntityMaps: buildFlatObjectMetadataMaps([standardEntity]), + existingFlatEntityMaps: buildFlatObjectMetadataMaps([existingEntity]), + universalIdentifier: 'call-recording', + }), + ).toBe(existingEntity); + }); + + it('returns the standard entity when the entity is missing from existing maps', () => { + const standardEntity = getFlatObjectMetadataMock({ + id: 'standard-id', + universalIdentifier: 'call-recording', + nameSingular: 'callRecording', + namePlural: 'callRecordings', + }); + + expect( + getExistingOrStandardFlatEntityOrThrow({ + standardFlatEntityMaps: buildFlatObjectMetadataMaps([standardEntity]), + existingFlatEntityMaps: buildFlatObjectMetadataMaps([]), + universalIdentifier: 'call-recording', + }), + ).toBe(standardEntity); + }); + + it('throws when the entity is absent from both maps', () => { + expect(() => + getExistingOrStandardFlatEntityOrThrow({ + standardFlatEntityMaps: buildFlatObjectMetadataMaps([]), + existingFlatEntityMaps: buildFlatObjectMetadataMaps([]), + universalIdentifier: 'missing-from-standard', + }), + ).toThrow('Could not find standard entity missing-from-standard'); + }); +}); diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/2-10/utils/build-navigation-command-menu-item-operations-or-throw.util.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/2-10/utils/build-navigation-command-menu-item-operations-or-throw.util.ts new file mode 100644 index 0000000000..b3b62de7c5 --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/2-10/utils/build-navigation-command-menu-item-operations-or-throw.util.ts @@ -0,0 +1,98 @@ +import { isDefined } from 'twenty-shared/utils'; +import { v4, v5 } from 'uuid'; + +import { type FlatCommandMenuItem } from 'src/engine/metadata-modules/flat-command-menu-item/types/flat-command-menu-item.type'; +import { + buildNavigationConditionalAvailabilityExpression, + buildNavigationFlatCommandMenuItem, + NAVIGATION_COMMAND_UUID_NAMESPACE, +} from 'src/engine/metadata-modules/flat-command-menu-item/utils/build-navigation-flat-command-menu-item.util'; +import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type'; +import { type FlatEntityToCreateDeleteUpdate } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-to-create-delete-update.type'; +import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; + +export const buildNavigationCommandMenuItemOperationsOrThrow = ({ + existingFlatCommandMenuItemMaps, + objectMetadatasForNavigation, + applicationId, + workspaceId, + now, + renamedCollisionObjectMetadatas, +}: { + existingFlatCommandMenuItemMaps: FlatEntityMaps; + objectMetadatasForNavigation: FlatObjectMetadata[]; + applicationId: string; + workspaceId: string; + now: string; + renamedCollisionObjectMetadatas: { + universalIdentifier: string; + nameSingular: string; + }[]; +}): FlatEntityToCreateDeleteUpdate<'commandMenuItem'> => { + const flatEntityToCreate: FlatCommandMenuItem[] = []; + const flatEntityToUpdate: FlatCommandMenuItem[] = []; + + let nextPosition = + Object.values(existingFlatCommandMenuItemMaps.byUniversalIdentifier) + .filter(isDefined) + .reduce( + (maxPosition, commandMenuItem) => + Math.max(maxPosition, commandMenuItem.position), + -1, + ) + 1; + + for (const objectMetadata of objectMetadatasForNavigation) { + const commandMenuItemUniversalIdentifier = v5( + objectMetadata.universalIdentifier, + NAVIGATION_COMMAND_UUID_NAMESPACE, + ); + + if ( + !objectMetadata.isActive || + isDefined( + existingFlatCommandMenuItemMaps.byUniversalIdentifier[ + commandMenuItemUniversalIdentifier + ], + ) + ) { + continue; + } + + flatEntityToCreate.push( + buildNavigationFlatCommandMenuItem({ + objectMetadata, + commandMenuItemId: v4(), + applicationId, + workspaceId, + position: nextPosition++, + now, + }), + ); + } + + for (const renamedCollisionObjectMetadata of renamedCollisionObjectMetadatas) { + const renamedNavigationCommandMenuItemUniversalIdentifier = v5( + renamedCollisionObjectMetadata.universalIdentifier, + NAVIGATION_COMMAND_UUID_NAMESPACE, + ); + const staleNavigationCommandMenuItem = + existingFlatCommandMenuItemMaps.byUniversalIdentifier[ + renamedNavigationCommandMenuItemUniversalIdentifier + ]; + + if (isDefined(staleNavigationCommandMenuItem)) { + flatEntityToUpdate.push({ + ...staleNavigationCommandMenuItem, + conditionalAvailabilityExpression: + buildNavigationConditionalAvailabilityExpression({ + universalIdentifier: + renamedCollisionObjectMetadata.universalIdentifier, + nameSingular: renamedCollisionObjectMetadata.nameSingular, + }), + updatedAt: now, + }); + } + } + + return { flatEntityToCreate, flatEntityToDelete: [], flatEntityToUpdate }; +}; diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/2-10/utils/call-recording-name-collision.util.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/2-10/utils/call-recording-name-collision.util.ts new file mode 100644 index 0000000000..39ed382e38 --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/2-10/utils/call-recording-name-collision.util.ts @@ -0,0 +1,204 @@ +import { STANDARD_OBJECTS } from 'twenty-shared/metadata'; +import { isDefined } from 'twenty-shared/utils'; + +import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type'; +import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; + +const CALL_RECORDING_NAME_SINGULAR = 'callRecording'; +const CALL_RECORDING_NAME_PLURAL = 'callRecordings'; +const CALL_RECORDING_OLD_NAME_SINGULAR = 'callRecordingOld'; +const CALL_RECORDING_OLD_NAME_PLURAL = 'callRecordingsOld'; +const CALENDAR_EVENT_RECORDING_PREFERENCE_FIELD_NAME = 'recordingPreference'; +const CALENDAR_EVENT_CALL_RECORDINGS_FIELD_NAME = 'callRecordings'; +const FIELD_OLD_NAME_SUFFIX = 'Old'; +const FIELD_OLD_LABEL_SUFFIX = ' (Old)'; +const MAX_OLD_NAME_ATTEMPTS = 100; + +const CALL_RECORDING_CALENDAR_EVENT_FIELD_NAMES = [ + CALENDAR_EVENT_RECORDING_PREFERENCE_FIELD_NAME, + CALENDAR_EVENT_CALL_RECORDINGS_FIELD_NAME, +]; + +const CALL_RECORDING_CALENDAR_EVENT_FIELD_UNIVERSAL_IDENTIFIERS = + new Set([ + STANDARD_OBJECTS.calendarEvent.fields.recordingPreference + .universalIdentifier, + STANDARD_OBJECTS.calendarEvent.fields.callRecordings.universalIdentifier, + ]); + +export const findCallRecordingObjectNameCollisions = ( + flatObjectMetadataMaps: FlatEntityMaps, +): FlatObjectMetadata[] => + Object.values(flatObjectMetadataMaps.byUniversalIdentifier).filter( + (flatObjectMetadata): flatObjectMetadata is FlatObjectMetadata => + isDefined(flatObjectMetadata) && + flatObjectMetadata.universalIdentifier !== + STANDARD_OBJECTS.callRecording.universalIdentifier && + [flatObjectMetadata.nameSingular, flatObjectMetadata.namePlural].some( + (name) => + name === CALL_RECORDING_NAME_SINGULAR || + name === CALL_RECORDING_NAME_PLURAL, + ), + ); + +export const resolveAvailableOldCallRecordingObjectNames = ( + flatObjectMetadataMaps: FlatEntityMaps, + additionalTakenNames: ReadonlySet = new Set(), +): { + nameSingular: string; + namePlural: string; + labelSingular: string; + labelPlural: string; +} => { + const takenNames = new Set([ + ...Object.values(flatObjectMetadataMaps.byUniversalIdentifier) + .filter(isDefined) + .flatMap((flatObjectMetadata) => [ + flatObjectMetadata.nameSingular, + flatObjectMetadata.namePlural, + ]), + ...additionalTakenNames, + ]); + + for (let attempt = 0; attempt < MAX_OLD_NAME_ATTEMPTS; attempt++) { + const discriminator = attempt === 0 ? '' : `${attempt + 1}`; + const nameSingular = `${CALL_RECORDING_OLD_NAME_SINGULAR}${discriminator}`; + const namePlural = `${CALL_RECORDING_OLD_NAME_PLURAL}${discriminator}`; + + if (!takenNames.has(nameSingular) && !takenNames.has(namePlural)) { + const labelSuffix = discriminator === '' ? '' : ` ${discriminator}`; + + return { + nameSingular, + namePlural, + labelSingular: `Call Recording (Old)${labelSuffix}`, + labelPlural: `Call Recordings (Old)${labelSuffix}`, + }; + } + } + + throw new Error( + `Could not find an available callRecordingOld name after ${MAX_OLD_NAME_ATTEMPTS} attempts`, + ); +}; + +export const buildCallRecordingObjectRenameUpdates = ({ + flatObjectMetadataMaps, + now, +}: { + flatObjectMetadataMaps: FlatEntityMaps; + now: string; +}): FlatObjectMetadata[] => { + const reservedOldNames = new Set(); + + return findCallRecordingObjectNameCollisions(flatObjectMetadataMaps).map( + (collidingObjectMetadata) => { + const { nameSingular, namePlural, labelSingular, labelPlural } = + resolveAvailableOldCallRecordingObjectNames( + flatObjectMetadataMaps, + reservedOldNames, + ); + + reservedOldNames.add(nameSingular); + reservedOldNames.add(namePlural); + + return { + ...collidingObjectMetadata, + nameSingular, + namePlural, + labelSingular, + labelPlural, + isLabelSyncedWithName: false, + updatedAt: now, + }; + }, + ); +}; + +export const findCalendarEventFieldNameCollisionsForCallRecording = ( + flatFieldMetadataMaps: FlatEntityMaps, +): FlatFieldMetadata[] => + Object.values(flatFieldMetadataMaps.byUniversalIdentifier).filter( + (flatFieldMetadata): flatFieldMetadata is FlatFieldMetadata => + isDefined(flatFieldMetadata) && + flatFieldMetadata.objectMetadataUniversalIdentifier === + STANDARD_OBJECTS.calendarEvent.universalIdentifier && + !CALL_RECORDING_CALENDAR_EVENT_FIELD_UNIVERSAL_IDENTIFIERS.has( + flatFieldMetadata.universalIdentifier, + ) && + CALL_RECORDING_CALENDAR_EVENT_FIELD_NAMES.includes( + flatFieldMetadata.name, + ), + ); + +export const resolveAvailableOldCalendarEventFieldName = ({ + flatFieldMetadataMaps, + originalFieldName, + additionalTakenNames = new Set(), +}: { + flatFieldMetadataMaps: FlatEntityMaps; + originalFieldName: string; + additionalTakenNames?: ReadonlySet; +}): string => { + const takenFieldNames = new Set([ + ...Object.values(flatFieldMetadataMaps.byUniversalIdentifier) + .filter(isDefined) + .filter( + (flatFieldMetadata) => + flatFieldMetadata.objectMetadataUniversalIdentifier === + STANDARD_OBJECTS.calendarEvent.universalIdentifier, + ) + .map((flatFieldMetadata) => flatFieldMetadata.name), + ...additionalTakenNames, + ]); + + for (let attempt = 0; attempt < MAX_OLD_NAME_ATTEMPTS; attempt++) { + const discriminator = attempt === 0 ? '' : `${attempt + 1}`; + const candidateName = `${originalFieldName}${FIELD_OLD_NAME_SUFFIX}${discriminator}`; + + if (!takenFieldNames.has(candidateName)) { + return candidateName; + } + } + + throw new Error( + `Could not find an available ${originalFieldName}Old name after ${MAX_OLD_NAME_ATTEMPTS} attempts`, + ); +}; + +export const buildCalendarEventFieldRenameUpdates = ({ + flatFieldMetadataMaps, + now, +}: { + flatFieldMetadataMaps: FlatEntityMaps; + now: string; +}): FlatFieldMetadata[] => { + const reservedOldFieldNames = new Set(); + + return findCalendarEventFieldNameCollisionsForCallRecording( + flatFieldMetadataMaps, + ).map((collidingFieldMetadata) => { + const name = resolveAvailableOldCalendarEventFieldName({ + flatFieldMetadataMaps, + originalFieldName: collidingFieldMetadata.name, + additionalTakenNames: reservedOldFieldNames, + }); + const oldNamePrefix = `${collidingFieldMetadata.name}${FIELD_OLD_NAME_SUFFIX}`; + const discriminator = name.slice(oldNamePrefix.length); + const labelSuffix = + discriminator === '' + ? FIELD_OLD_LABEL_SUFFIX + : `${FIELD_OLD_LABEL_SUFFIX} ${discriminator}`; + + reservedOldFieldNames.add(name); + + return { + ...collidingFieldMetadata, + name, + label: `${collidingFieldMetadata.label}${labelSuffix}`, + isLabelSyncedWithName: false, + updatedAt: now, + }; + }); +}; diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/2-10/utils/get-standard-flat-entities-to-create-or-throw.util.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/2-10/utils/get-standard-flat-entities-to-create-or-throw.util.ts new file mode 100644 index 0000000000..44bef3a3dc --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/2-10/utils/get-standard-flat-entities-to-create-or-throw.util.ts @@ -0,0 +1,62 @@ +import { isDefined } from 'twenty-shared/utils'; + +import { type SyncableFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-from.type'; +import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type'; + +export const getStandardFlatEntitiesToCreateOrThrow = < + T extends SyncableFlatEntity, +>({ + standardFlatEntityMaps, + existingFlatEntityMaps, + universalIdentifiers, +}: { + standardFlatEntityMaps: FlatEntityMaps; + existingFlatEntityMaps: FlatEntityMaps; + universalIdentifiers: string[]; +}): T[] => + universalIdentifiers.flatMap((universalIdentifier) => { + const standardFlatEntity = + standardFlatEntityMaps.byUniversalIdentifier[universalIdentifier]; + + if (!isDefined(standardFlatEntity)) { + throw new Error(`Could not find standard entity ${universalIdentifier}`); + } + + if ( + isDefined( + existingFlatEntityMaps.byUniversalIdentifier[universalIdentifier], + ) + ) { + return []; + } + + return [standardFlatEntity]; + }); + +export const getExistingOrStandardFlatEntityOrThrow = < + T extends SyncableFlatEntity, +>({ + standardFlatEntityMaps, + existingFlatEntityMaps, + universalIdentifier, +}: { + standardFlatEntityMaps: FlatEntityMaps; + existingFlatEntityMaps: FlatEntityMaps; + universalIdentifier: string; +}): T => { + const existingFlatEntity = + existingFlatEntityMaps.byUniversalIdentifier[universalIdentifier]; + + if (isDefined(existingFlatEntity)) { + return existingFlatEntity; + } + + const standardFlatEntity = + standardFlatEntityMaps.byUniversalIdentifier[universalIdentifier]; + + if (!isDefined(standardFlatEntity)) { + throw new Error(`Could not find standard entity ${universalIdentifier}`); + } + + return standardFlatEntity; +}; diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-command-menu-item/utils/__tests__/build-navigation-flat-command-menu-item.util.test.ts b/packages/twenty-server/src/engine/metadata-modules/flat-command-menu-item/utils/__tests__/build-navigation-flat-command-menu-item.util.spec.ts similarity index 73% rename from packages/twenty-server/src/engine/metadata-modules/flat-command-menu-item/utils/__tests__/build-navigation-flat-command-menu-item.util.test.ts rename to packages/twenty-server/src/engine/metadata-modules/flat-command-menu-item/utils/__tests__/build-navigation-flat-command-menu-item.util.spec.ts index 96bfdc5c75..c6d9da6ab4 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-command-menu-item/utils/__tests__/build-navigation-flat-command-menu-item.util.test.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-command-menu-item/utils/__tests__/build-navigation-flat-command-menu-item.util.spec.ts @@ -1,8 +1,10 @@ +import { STANDARD_OBJECTS } from 'twenty-shared/metadata'; import { v5 } from 'uuid'; import { CommandMenuItemAvailabilityType } from 'src/engine/metadata-modules/command-menu-item/enums/command-menu-item-availability-type.enum'; import { EngineComponentKey } from 'src/engine/metadata-modules/command-menu-item/enums/engine-component-key.enum'; import { + buildNavigationConditionalAvailabilityExpression, buildNavigationFlatCommandMenuItem, NAVIGATION_INTERPOLATED_ICON, NAVIGATION_INTERPOLATED_LABEL, @@ -114,6 +116,21 @@ describe('buildNavigationFlatCommandMenuItem', () => { ); }); + it('should additionally gate conditionalAvailabilityExpression behind the feature flag for feature-flagged objects', () => { + const result = buildNavigationFlatCommandMenuItem({ + ...baseArgs, + objectMetadata: { + ...baseObjectMetadata, + universalIdentifier: STANDARD_OBJECTS.callRecording.universalIdentifier, + nameSingular: 'callRecording', + }, + }); + + expect(result.conditionalAvailabilityExpression).toBe( + 'featureFlags.IS_CALL_RECORDING_ENABLED and targetObjectReadPermissions.callRecording', + ); + }); + it('should set isPinned to false', () => { const result = buildNavigationFlatCommandMenuItem(baseArgs); @@ -137,3 +154,34 @@ describe('buildNavigationFlatCommandMenuItem', () => { expect(result.updatedAt).toBe('2026-01-01T00:00:00.000Z'); }); }); + +describe('buildNavigationConditionalAvailabilityExpression', () => { + it('gates the standard call recording object behind both the flag and read permission', () => { + expect( + buildNavigationConditionalAvailabilityExpression({ + universalIdentifier: STANDARD_OBJECTS.callRecording.universalIdentifier, + nameSingular: 'callRecording', + }), + ).toBe( + 'featureFlags.IS_CALL_RECORDING_ENABLED and targetObjectReadPermissions.callRecording', + ); + }); + + it('returns only the read-permission expression for non-gated objects', () => { + expect( + buildNavigationConditionalAvailabilityExpression({ + universalIdentifier: 'obj-universal-1', + nameSingular: 'person', + }), + ).toBe('targetObjectReadPermissions.person'); + }); + + it('does not gate a custom object that reuses the callRecording name', () => { + expect( + buildNavigationConditionalAvailabilityExpression({ + universalIdentifier: 'custom-object-universal-id', + nameSingular: 'callRecording', + }), + ).toBe('targetObjectReadPermissions.callRecording'); + }); +}); diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-command-menu-item/utils/build-navigation-flat-command-menu-item.util.ts b/packages/twenty-server/src/engine/metadata-modules/flat-command-menu-item/utils/build-navigation-flat-command-menu-item.util.ts index e53c164c80..0db33f1013 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-command-menu-item/utils/build-navigation-flat-command-menu-item.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-command-menu-item/utils/build-navigation-flat-command-menu-item.util.ts @@ -1,3 +1,5 @@ +import { STANDARD_OBJECTS } from 'twenty-shared/metadata'; +import { FeatureFlagKey } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { v5 } from 'uuid'; @@ -16,6 +18,31 @@ export const NAVIGATION_INTERPOLATED_SHORT_LABEL = export const NAVIGATION_INTERPOLATED_ICON = '${navigateToObjectMetadataItem.icon}'; +const NAVIGATION_FEATURE_FLAG_GATE_BY_OBJECT_UNIVERSAL_IDENTIFIER: Partial< + Record +> = { + [STANDARD_OBJECTS.callRecording.universalIdentifier]: + FeatureFlagKey.IS_CALL_RECORDING_ENABLED, +}; + +export const buildNavigationConditionalAvailabilityExpression = ({ + universalIdentifier, + nameSingular, +}: { + universalIdentifier: string; + nameSingular: string; +}): string => { + const targetObjectReadPermissionExpression = `targetObjectReadPermissions.${nameSingular}`; + const featureFlagGate = + NAVIGATION_FEATURE_FLAG_GATE_BY_OBJECT_UNIVERSAL_IDENTIFIER[ + universalIdentifier + ]; + + return isDefined(featureFlagGate) + ? `featureFlags.${featureFlagGate} and ${targetObjectReadPermissionExpression}` + : targetObjectReadPermissionExpression; +}; + export const buildNavigationFlatCommandMenuItem = ({ objectMetadata, commandMenuItemId, @@ -41,6 +68,12 @@ export const buildNavigationFlatCommandMenuItem = ({ NAVIGATION_COMMAND_UUID_NAMESPACE, ); + const conditionalAvailabilityExpression = + buildNavigationConditionalAvailabilityExpression({ + universalIdentifier: objectMetadata.universalIdentifier, + nameSingular: objectMetadata.nameSingular, + }); + return { id: commandMenuItemId, universalIdentifier, @@ -54,7 +87,7 @@ export const buildNavigationFlatCommandMenuItem = ({ position, isPinned: false, availabilityType: CommandMenuItemAvailabilityType.GLOBAL, - conditionalAvailabilityExpression: `targetObjectReadPermissions.${objectMetadata.nameSingular}`, + conditionalAvailabilityExpression, frontComponentId: null, frontComponentUniversalIdentifier: null, engineComponentKey: EngineComponentKey.NAVIGATION, diff --git a/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts b/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts index 65d87046f5..1aeb324c57 100644 --- a/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts +++ b/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts @@ -239,6 +239,7 @@ describe('WorkspaceEntityManager', () => { IS_REST_METADATA_API_NEW_FORMAT_DIRECT: false, IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED: false, IS_SETTINGS_DISCOVERY_HERO_ENABLED: false, + IS_CALL_RECORDING_ENABLED: false, IS_WORKFLOW_RUN_STEP_LOGS_ENABLED: false, }, userWorkspaceRoleMap: {}, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/constants/standard-page-layout.constant.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/constants/standard-page-layout.constant.ts index 35feded6cf..2b2a68ac74 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/constants/standard-page-layout.constant.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/constants/standard-page-layout.constant.ts @@ -2,6 +2,7 @@ import { STANDARD_BLOCKLIST_PAGE_LAYOUT_CONFIG, STANDARD_CALENDAR_CHANNEL_EVENT_ASSOCIATION_PAGE_LAYOUT_CONFIG, STANDARD_CALENDAR_EVENT_PARTICIPANT_PAGE_LAYOUT_CONFIG, + STANDARD_CALL_RECORDING_PAGE_LAYOUT_CONFIG, STANDARD_COMPANY_PAGE_LAYOUT_CONFIG, STANDARD_DASHBOARD_PAGE_LAYOUT_CONFIG, STANDARD_MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_MESSAGE_FOLDER_PAGE_LAYOUT_CONFIG, @@ -26,6 +27,7 @@ export const STANDARD_PAGE_LAYOUTS = { STANDARD_CALENDAR_CHANNEL_EVENT_ASSOCIATION_PAGE_LAYOUT_CONFIG, calendarEventParticipantRecordPage: STANDARD_CALENDAR_EVENT_PARTICIPANT_PAGE_LAYOUT_CONFIG, + callRecordingRecordPage: STANDARD_CALL_RECORDING_PAGE_LAYOUT_CONFIG, companyRecordPage: STANDARD_COMPANY_PAGE_LAYOUT_CONFIG, messageChannelMessageAssociationRecordPage: STANDARD_MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_PAGE_LAYOUT_CONFIG, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/__tests__/__snapshots__/get-standard-object-metadata-related-entity-ids.util.spec.ts.snap b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/__tests__/__snapshots__/get-standard-object-metadata-related-entity-ids.util.spec.ts.snap index e0344fb079..c8ca5d6a0a 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/__tests__/__snapshots__/get-standard-object-metadata-related-entity-ids.util.spec.ts.snap +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/__tests__/__snapshots__/get-standard-object-metadata-related-entity-ids.util.spec.ts.snap @@ -281,6 +281,9 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "calendarEventParticipants": { "id": "00000000-0000-0000-0000-000000000134", }, + "callRecordings": { + "id": "00000000-0000-0000-0000-000000000136", + }, "conferenceLink": { "id": "00000000-0000-0000-0000-000000000132", }, @@ -291,7 +294,7 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "id": "00000000-0000-0000-0000-000000000118", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000135", + "id": "00000000-0000-0000-0000-000000000137", }, "deletedAt": { "id": "00000000-0000-0000-0000-000000000120", @@ -324,10 +327,13 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "id": "00000000-0000-0000-0000-000000000129", }, "position": { - "id": "00000000-0000-0000-0000-000000000137", + "id": "00000000-0000-0000-0000-000000000139", + }, + "recordingPreference": { + "id": "00000000-0000-0000-0000-000000000135", }, "searchVector": { - "id": "00000000-0000-0000-0000-000000000138", + "id": "00000000-0000-0000-0000-000000000140", }, "startsAt": { "id": "00000000-0000-0000-0000-000000000124", @@ -339,38 +345,38 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "id": "00000000-0000-0000-0000-000000000119", }, "updatedBy": { - "id": "00000000-0000-0000-0000-000000000136", + "id": "00000000-0000-0000-0000-000000000138", }, }, - "id": "00000000-0000-0000-0000-000000000148", + "id": "00000000-0000-0000-0000-000000000150", "views": { "allCalendarEvents": { - "id": "00000000-0000-0000-0000-000000000147", + "id": "00000000-0000-0000-0000-000000000149", "viewFieldGroups": {}, "viewFields": { "conferenceLink": { - "id": "00000000-0000-0000-0000-000000000144", - }, - "createdAt": { "id": "00000000-0000-0000-0000-000000000146", }, + "createdAt": { + "id": "00000000-0000-0000-0000-000000000148", + }, "endsAt": { - "id": "00000000-0000-0000-0000-000000000141", - }, - "isCanceled": { - "id": "00000000-0000-0000-0000-000000000145", - }, - "isFullDay": { - "id": "00000000-0000-0000-0000-000000000142", - }, - "location": { "id": "00000000-0000-0000-0000-000000000143", }, + "isCanceled": { + "id": "00000000-0000-0000-0000-000000000147", + }, + "isFullDay": { + "id": "00000000-0000-0000-0000-000000000144", + }, + "location": { + "id": "00000000-0000-0000-0000-000000000145", + }, "startsAt": { - "id": "00000000-0000-0000-0000-000000000140", + "id": "00000000-0000-0000-0000-000000000142", }, "title": { - "id": "00000000-0000-0000-0000-000000000139", + "id": "00000000-0000-0000-0000-000000000141", }, }, "viewGroups": {}, @@ -501,160 +507,278 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object }, }, }, - "company": { + "callRecording": { "fields": { - "accountOwner": { - "id": "00000000-0000-0000-0000-000000000162", - }, - "address": { - "id": "00000000-0000-0000-0000-000000000155", - }, - "annualRevenue": { + "applicationId": { "id": "00000000-0000-0000-0000-000000000157", }, - "attachments": { + "audio": { + "id": "00000000-0000-0000-0000-000000000163", + }, + "calendarEvent": { "id": "00000000-0000-0000-0000-000000000166", }, "createdAt": { - "id": "00000000-0000-0000-0000-000000000150", - }, - "createdBy": { - "id": "00000000-0000-0000-0000-000000000159", - }, - "deletedAt": { "id": "00000000-0000-0000-0000-000000000152", }, - "domainName": { - "id": "00000000-0000-0000-0000-000000000154", - }, - "id": { - "id": "00000000-0000-0000-0000-000000000149", - }, - "linkedinLink": { - "id": "00000000-0000-0000-0000-000000000156", - }, - "name": { - "id": "00000000-0000-0000-0000-000000000153", - }, - "noteTargets": { - "id": "00000000-0000-0000-0000-000000000164", - }, - "opportunities": { - "id": "00000000-0000-0000-0000-000000000165", - }, - "people": { - "id": "00000000-0000-0000-0000-000000000161", - }, - "position": { - "id": "00000000-0000-0000-0000-000000000158", - }, - "searchVector": { - "id": "00000000-0000-0000-0000-000000000168", - }, - "taskTargets": { - "id": "00000000-0000-0000-0000-000000000163", - }, - "timelineActivities": { + "createdBy": { "id": "00000000-0000-0000-0000-000000000167", }, - "updatedAt": { + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000154", + }, + "endedAt": { + "id": "00000000-0000-0000-0000-000000000161", + }, + "externalBotId": { + "id": "00000000-0000-0000-0000-000000000158", + }, + "externalRecordingId": { + "id": "00000000-0000-0000-0000-000000000159", + }, + "id": { "id": "00000000-0000-0000-0000-000000000151", }, - "updatedBy": { + "position": { + "id": "00000000-0000-0000-0000-000000000169", + }, + "searchVector": { + "id": "00000000-0000-0000-0000-000000000170", + }, + "startedAt": { "id": "00000000-0000-0000-0000-000000000160", }, + "status": { + "id": "00000000-0000-0000-0000-000000000156", + }, + "summary": { + "id": "00000000-0000-0000-0000-000000000165", + }, + "title": { + "id": "00000000-0000-0000-0000-000000000155", + }, + "transcript": { + "id": "00000000-0000-0000-0000-000000000164", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000153", + }, + "updatedBy": { + "id": "00000000-0000-0000-0000-000000000168", + }, + "video": { + "id": "00000000-0000-0000-0000-000000000162", + }, }, - "id": "00000000-0000-0000-0000-000000000197", + "id": "00000000-0000-0000-0000-000000000185", + "views": { + "allCallRecordings": { + "id": "00000000-0000-0000-0000-000000000174", + "viewFieldGroups": {}, + "viewFields": { + "startedAt": { + "id": "00000000-0000-0000-0000-000000000173", + }, + "status": { + "id": "00000000-0000-0000-0000-000000000171", + }, + "title": { + "id": "00000000-0000-0000-0000-000000000172", + }, + }, + "viewGroups": {}, + }, + "callRecordingRecordPageFields": { + "id": "00000000-0000-0000-0000-000000000184", + "viewFieldGroups": { + "general": { + "id": "00000000-0000-0000-0000-000000000183", + }, + }, + "viewFields": { + "audio": { + "id": "00000000-0000-0000-0000-000000000180", + }, + "endedAt": { + "id": "00000000-0000-0000-0000-000000000178", + }, + "startedAt": { + "id": "00000000-0000-0000-0000-000000000177", + }, + "status": { + "id": "00000000-0000-0000-0000-000000000176", + }, + "summary": { + "id": "00000000-0000-0000-0000-000000000182", + }, + "title": { + "id": "00000000-0000-0000-0000-000000000175", + }, + "transcript": { + "id": "00000000-0000-0000-0000-000000000181", + }, + "video": { + "id": "00000000-0000-0000-0000-000000000179", + }, + }, + "viewGroups": {}, + }, + }, + }, + "company": { + "fields": { + "accountOwner": { + "id": "00000000-0000-0000-0000-000000000199", + }, + "address": { + "id": "00000000-0000-0000-0000-000000000192", + }, + "annualRevenue": { + "id": "00000000-0000-0000-0000-000000000194", + }, + "attachments": { + "id": "00000000-0000-0000-0000-000000000203", + }, + "createdAt": { + "id": "00000000-0000-0000-0000-000000000187", + }, + "createdBy": { + "id": "00000000-0000-0000-0000-000000000196", + }, + "deletedAt": { + "id": "00000000-0000-0000-0000-000000000189", + }, + "domainName": { + "id": "00000000-0000-0000-0000-000000000191", + }, + "id": { + "id": "00000000-0000-0000-0000-000000000186", + }, + "linkedinLink": { + "id": "00000000-0000-0000-0000-000000000193", + }, + "name": { + "id": "00000000-0000-0000-0000-000000000190", + }, + "noteTargets": { + "id": "00000000-0000-0000-0000-000000000201", + }, + "opportunities": { + "id": "00000000-0000-0000-0000-000000000202", + }, + "people": { + "id": "00000000-0000-0000-0000-000000000198", + }, + "position": { + "id": "00000000-0000-0000-0000-000000000195", + }, + "searchVector": { + "id": "00000000-0000-0000-0000-000000000205", + }, + "taskTargets": { + "id": "00000000-0000-0000-0000-000000000200", + }, + "timelineActivities": { + "id": "00000000-0000-0000-0000-000000000204", + }, + "updatedAt": { + "id": "00000000-0000-0000-0000-000000000188", + }, + "updatedBy": { + "id": "00000000-0000-0000-0000-000000000197", + }, + }, + "id": "00000000-0000-0000-0000-000000000234", "views": { "allCompanies": { - "id": "00000000-0000-0000-0000-000000000176", + "id": "00000000-0000-0000-0000-000000000213", "viewFieldGroups": {}, "viewFields": { "accountOwner": { - "id": "00000000-0000-0000-0000-000000000172", + "id": "00000000-0000-0000-0000-000000000209", }, "address": { - "id": "00000000-0000-0000-0000-000000000175", + "id": "00000000-0000-0000-0000-000000000212", }, "createdAt": { - "id": "00000000-0000-0000-0000-000000000173", + "id": "00000000-0000-0000-0000-000000000210", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000171", + "id": "00000000-0000-0000-0000-000000000208", }, "domainName": { - "id": "00000000-0000-0000-0000-000000000170", + "id": "00000000-0000-0000-0000-000000000207", }, "linkedinLink": { - "id": "00000000-0000-0000-0000-000000000174", + "id": "00000000-0000-0000-0000-000000000211", }, "name": { - "id": "00000000-0000-0000-0000-000000000169", + "id": "00000000-0000-0000-0000-000000000206", }, }, "viewGroups": {}, }, "companyRecordPageFields": { - "id": "00000000-0000-0000-0000-000000000196", + "id": "00000000-0000-0000-0000-000000000233", "viewFieldGroups": { "business": { - "id": "00000000-0000-0000-0000-000000000193", + "id": "00000000-0000-0000-0000-000000000230", }, "contact": { - "id": "00000000-0000-0000-0000-000000000194", + "id": "00000000-0000-0000-0000-000000000231", }, "general": { - "id": "00000000-0000-0000-0000-000000000192", + "id": "00000000-0000-0000-0000-000000000229", }, "system": { - "id": "00000000-0000-0000-0000-000000000195", + "id": "00000000-0000-0000-0000-000000000232", }, }, "viewFields": { "accountOwner": { - "id": "00000000-0000-0000-0000-000000000178", + "id": "00000000-0000-0000-0000-000000000215", }, "address": { - "id": "00000000-0000-0000-0000-000000000181", + "id": "00000000-0000-0000-0000-000000000218", }, "annualRevenue": { - "id": "00000000-0000-0000-0000-000000000179", + "id": "00000000-0000-0000-0000-000000000216", }, "attachments": { - "id": "00000000-0000-0000-0000-000000000190", + "id": "00000000-0000-0000-0000-000000000227", }, "createdAt": { - "id": "00000000-0000-0000-0000-000000000182", + "id": "00000000-0000-0000-0000-000000000219", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000183", + "id": "00000000-0000-0000-0000-000000000220", }, "domainName": { - "id": "00000000-0000-0000-0000-000000000177", + "id": "00000000-0000-0000-0000-000000000214", }, "linkedinLink": { - "id": "00000000-0000-0000-0000-000000000180", + "id": "00000000-0000-0000-0000-000000000217", }, "noteTargets": { - "id": "00000000-0000-0000-0000-000000000188", + "id": "00000000-0000-0000-0000-000000000225", }, "opportunities": { - "id": "00000000-0000-0000-0000-000000000189", + "id": "00000000-0000-0000-0000-000000000226", }, "people": { - "id": "00000000-0000-0000-0000-000000000186", + "id": "00000000-0000-0000-0000-000000000223", }, "taskTargets": { - "id": "00000000-0000-0000-0000-000000000187", + "id": "00000000-0000-0000-0000-000000000224", }, "timelineActivities": { - "id": "00000000-0000-0000-0000-000000000191", + "id": "00000000-0000-0000-0000-000000000228", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000184", + "id": "00000000-0000-0000-0000-000000000221", }, "updatedBy": { - "id": "00000000-0000-0000-0000-000000000185", + "id": "00000000-0000-0000-0000-000000000222", }, }, "viewGroups": {}, @@ -664,59 +788,59 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "dashboard": { "fields": { "attachments": { - "id": "00000000-0000-0000-0000-000000000208", + "id": "00000000-0000-0000-0000-000000000245", }, "createdAt": { - "id": "00000000-0000-0000-0000-000000000199", + "id": "00000000-0000-0000-0000-000000000236", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000205", + "id": "00000000-0000-0000-0000-000000000242", }, "deletedAt": { - "id": "00000000-0000-0000-0000-000000000201", + "id": "00000000-0000-0000-0000-000000000238", }, "id": { - "id": "00000000-0000-0000-0000-000000000198", + "id": "00000000-0000-0000-0000-000000000235", }, "pageLayoutId": { - "id": "00000000-0000-0000-0000-000000000204", + "id": "00000000-0000-0000-0000-000000000241", }, "position": { - "id": "00000000-0000-0000-0000-000000000203", + "id": "00000000-0000-0000-0000-000000000240", }, "searchVector": { - "id": "00000000-0000-0000-0000-000000000209", + "id": "00000000-0000-0000-0000-000000000246", }, "timelineActivities": { - "id": "00000000-0000-0000-0000-000000000207", + "id": "00000000-0000-0000-0000-000000000244", }, "title": { - "id": "00000000-0000-0000-0000-000000000202", + "id": "00000000-0000-0000-0000-000000000239", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000200", + "id": "00000000-0000-0000-0000-000000000237", }, "updatedBy": { - "id": "00000000-0000-0000-0000-000000000206", + "id": "00000000-0000-0000-0000-000000000243", }, }, - "id": "00000000-0000-0000-0000-000000000215", + "id": "00000000-0000-0000-0000-000000000252", "views": { "allDashboards": { - "id": "00000000-0000-0000-0000-000000000214", + "id": "00000000-0000-0000-0000-000000000251", "viewFieldGroups": {}, "viewFields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000212", + "id": "00000000-0000-0000-0000-000000000249", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000211", + "id": "00000000-0000-0000-0000-000000000248", }, "title": { - "id": "00000000-0000-0000-0000-000000000210", + "id": "00000000-0000-0000-0000-000000000247", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000213", + "id": "00000000-0000-0000-0000-000000000250", }, }, "viewGroups": {}, @@ -726,77 +850,77 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "message": { "fields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000320", + "id": "00000000-0000-0000-0000-000000000357", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000330", + "id": "00000000-0000-0000-0000-000000000367", }, "deletedAt": { - "id": "00000000-0000-0000-0000-000000000322", + "id": "00000000-0000-0000-0000-000000000359", }, "headerMessageId": { - "id": "00000000-0000-0000-0000-000000000323", + "id": "00000000-0000-0000-0000-000000000360", }, "id": { - "id": "00000000-0000-0000-0000-000000000319", + "id": "00000000-0000-0000-0000-000000000356", }, "messageChannelMessageAssociations": { - "id": "00000000-0000-0000-0000-000000000329", + "id": "00000000-0000-0000-0000-000000000366", }, "messageParticipants": { - "id": "00000000-0000-0000-0000-000000000328", + "id": "00000000-0000-0000-0000-000000000365", }, "messageThread": { - "id": "00000000-0000-0000-0000-000000000324", + "id": "00000000-0000-0000-0000-000000000361", }, "position": { - "id": "00000000-0000-0000-0000-000000000332", + "id": "00000000-0000-0000-0000-000000000369", }, "receivedAt": { - "id": "00000000-0000-0000-0000-000000000327", + "id": "00000000-0000-0000-0000-000000000364", }, "searchVector": { - "id": "00000000-0000-0000-0000-000000000333", + "id": "00000000-0000-0000-0000-000000000370", }, "subject": { - "id": "00000000-0000-0000-0000-000000000325", + "id": "00000000-0000-0000-0000-000000000362", }, "text": { - "id": "00000000-0000-0000-0000-000000000326", + "id": "00000000-0000-0000-0000-000000000363", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000321", + "id": "00000000-0000-0000-0000-000000000358", }, "updatedBy": { - "id": "00000000-0000-0000-0000-000000000331", + "id": "00000000-0000-0000-0000-000000000368", }, }, - "id": "00000000-0000-0000-0000-000000000342", + "id": "00000000-0000-0000-0000-000000000379", "views": { "allMessages": { - "id": "00000000-0000-0000-0000-000000000341", + "id": "00000000-0000-0000-0000-000000000378", "viewFieldGroups": {}, "viewFields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000340", + "id": "00000000-0000-0000-0000-000000000377", }, "headerMessageId": { - "id": "00000000-0000-0000-0000-000000000338", + "id": "00000000-0000-0000-0000-000000000375", }, "messageParticipants": { - "id": "00000000-0000-0000-0000-000000000336", + "id": "00000000-0000-0000-0000-000000000373", }, "messageThread": { - "id": "00000000-0000-0000-0000-000000000335", + "id": "00000000-0000-0000-0000-000000000372", }, "receivedAt": { - "id": "00000000-0000-0000-0000-000000000337", + "id": "00000000-0000-0000-0000-000000000374", }, "subject": { - "id": "00000000-0000-0000-0000-000000000334", + "id": "00000000-0000-0000-0000-000000000371", }, "text": { - "id": "00000000-0000-0000-0000-000000000339", + "id": "00000000-0000-0000-0000-000000000376", }, }, "viewGroups": {}, @@ -806,103 +930,103 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "messageChannelMessageAssociation": { "fields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000217", + "id": "00000000-0000-0000-0000-000000000254", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000226", + "id": "00000000-0000-0000-0000-000000000263", }, "deletedAt": { - "id": "00000000-0000-0000-0000-000000000219", + "id": "00000000-0000-0000-0000-000000000256", }, "direction": { - "id": "00000000-0000-0000-0000-000000000225", + "id": "00000000-0000-0000-0000-000000000262", }, "id": { - "id": "00000000-0000-0000-0000-000000000216", + "id": "00000000-0000-0000-0000-000000000253", }, "message": { - "id": "00000000-0000-0000-0000-000000000221", + "id": "00000000-0000-0000-0000-000000000258", }, "messageChannelId": { - "id": "00000000-0000-0000-0000-000000000220", + "id": "00000000-0000-0000-0000-000000000257", }, "messageExternalId": { - "id": "00000000-0000-0000-0000-000000000222", + "id": "00000000-0000-0000-0000-000000000259", }, "messageFolders": { - "id": "00000000-0000-0000-0000-000000000230", + "id": "00000000-0000-0000-0000-000000000267", }, "messageThread": { - "id": "00000000-0000-0000-0000-000000000223", + "id": "00000000-0000-0000-0000-000000000260", }, "messageThreadExternalId": { - "id": "00000000-0000-0000-0000-000000000224", + "id": "00000000-0000-0000-0000-000000000261", }, "position": { - "id": "00000000-0000-0000-0000-000000000228", + "id": "00000000-0000-0000-0000-000000000265", }, "searchVector": { - "id": "00000000-0000-0000-0000-000000000229", + "id": "00000000-0000-0000-0000-000000000266", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000218", + "id": "00000000-0000-0000-0000-000000000255", }, "updatedBy": { - "id": "00000000-0000-0000-0000-000000000227", + "id": "00000000-0000-0000-0000-000000000264", }, }, - "id": "00000000-0000-0000-0000-000000000246", + "id": "00000000-0000-0000-0000-000000000283", "views": { "allMessageChannelMessageAssociations": { - "id": "00000000-0000-0000-0000-000000000236", + "id": "00000000-0000-0000-0000-000000000273", "viewFieldGroups": {}, "viewFields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000235", + "id": "00000000-0000-0000-0000-000000000272", }, "direction": { - "id": "00000000-0000-0000-0000-000000000234", + "id": "00000000-0000-0000-0000-000000000271", }, "message": { - "id": "00000000-0000-0000-0000-000000000232", + "id": "00000000-0000-0000-0000-000000000269", }, "messageChannelId": { - "id": "00000000-0000-0000-0000-000000000231", + "id": "00000000-0000-0000-0000-000000000268", }, "messageExternalId": { - "id": "00000000-0000-0000-0000-000000000233", + "id": "00000000-0000-0000-0000-000000000270", }, }, "viewGroups": {}, }, "messageChannelMessageAssociationRecordPageFields": { - "id": "00000000-0000-0000-0000-000000000245", + "id": "00000000-0000-0000-0000-000000000282", "viewFieldGroups": { "general": { - "id": "00000000-0000-0000-0000-000000000243", + "id": "00000000-0000-0000-0000-000000000280", }, "system": { - "id": "00000000-0000-0000-0000-000000000244", + "id": "00000000-0000-0000-0000-000000000281", }, }, "viewFields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000241", + "id": "00000000-0000-0000-0000-000000000278", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000242", + "id": "00000000-0000-0000-0000-000000000279", }, "direction": { - "id": "00000000-0000-0000-0000-000000000240", + "id": "00000000-0000-0000-0000-000000000277", }, "message": { - "id": "00000000-0000-0000-0000-000000000238", + "id": "00000000-0000-0000-0000-000000000275", }, "messageChannelId": { - "id": "00000000-0000-0000-0000-000000000237", + "id": "00000000-0000-0000-0000-000000000274", }, "messageExternalId": { - "id": "00000000-0000-0000-0000-000000000239", + "id": "00000000-0000-0000-0000-000000000276", }, }, "viewGroups": {}, @@ -912,76 +1036,76 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "messageChannelMessageAssociationMessageFolder": { "fields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000248", + "id": "00000000-0000-0000-0000-000000000285", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000251", + "id": "00000000-0000-0000-0000-000000000288", }, "deletedAt": { - "id": "00000000-0000-0000-0000-000000000250", + "id": "00000000-0000-0000-0000-000000000287", }, "id": { - "id": "00000000-0000-0000-0000-000000000247", + "id": "00000000-0000-0000-0000-000000000284", }, "messageChannelMessageAssociation": { - "id": "00000000-0000-0000-0000-000000000255", + "id": "00000000-0000-0000-0000-000000000292", }, "messageFolderId": { - "id": "00000000-0000-0000-0000-000000000256", + "id": "00000000-0000-0000-0000-000000000293", }, "position": { - "id": "00000000-0000-0000-0000-000000000253", + "id": "00000000-0000-0000-0000-000000000290", }, "searchVector": { - "id": "00000000-0000-0000-0000-000000000254", + "id": "00000000-0000-0000-0000-000000000291", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000249", + "id": "00000000-0000-0000-0000-000000000286", }, "updatedBy": { - "id": "00000000-0000-0000-0000-000000000252", + "id": "00000000-0000-0000-0000-000000000289", }, }, - "id": "00000000-0000-0000-0000-000000000268", + "id": "00000000-0000-0000-0000-000000000305", "views": { "allMessageChannelMessageAssociationMessageFolders": { - "id": "00000000-0000-0000-0000-000000000260", + "id": "00000000-0000-0000-0000-000000000297", "viewFieldGroups": {}, "viewFields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000259", + "id": "00000000-0000-0000-0000-000000000296", }, "messageChannelMessageAssociation": { - "id": "00000000-0000-0000-0000-000000000257", + "id": "00000000-0000-0000-0000-000000000294", }, "messageFolderId": { - "id": "00000000-0000-0000-0000-000000000258", + "id": "00000000-0000-0000-0000-000000000295", }, }, "viewGroups": {}, }, "messageChannelMessageAssociationMessageFolderRecordPageFields": { - "id": "00000000-0000-0000-0000-000000000267", + "id": "00000000-0000-0000-0000-000000000304", "viewFieldGroups": { "general": { - "id": "00000000-0000-0000-0000-000000000265", + "id": "00000000-0000-0000-0000-000000000302", }, "system": { - "id": "00000000-0000-0000-0000-000000000266", + "id": "00000000-0000-0000-0000-000000000303", }, }, "viewFields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000263", + "id": "00000000-0000-0000-0000-000000000300", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000264", + "id": "00000000-0000-0000-0000-000000000301", }, "messageChannelMessageAssociation": { - "id": "00000000-0000-0000-0000-000000000261", + "id": "00000000-0000-0000-0000-000000000298", }, "messageFolderId": { - "id": "00000000-0000-0000-0000-000000000262", + "id": "00000000-0000-0000-0000-000000000299", }, }, "viewGroups": {}, @@ -991,109 +1115,109 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "messageParticipant": { "fields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000270", + "id": "00000000-0000-0000-0000-000000000307", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000279", + "id": "00000000-0000-0000-0000-000000000316", }, "deletedAt": { - "id": "00000000-0000-0000-0000-000000000272", + "id": "00000000-0000-0000-0000-000000000309", }, "displayName": { - "id": "00000000-0000-0000-0000-000000000276", + "id": "00000000-0000-0000-0000-000000000313", }, "handle": { - "id": "00000000-0000-0000-0000-000000000275", + "id": "00000000-0000-0000-0000-000000000312", }, "id": { - "id": "00000000-0000-0000-0000-000000000269", + "id": "00000000-0000-0000-0000-000000000306", }, "message": { - "id": "00000000-0000-0000-0000-000000000273", + "id": "00000000-0000-0000-0000-000000000310", }, "person": { - "id": "00000000-0000-0000-0000-000000000277", + "id": "00000000-0000-0000-0000-000000000314", }, "position": { - "id": "00000000-0000-0000-0000-000000000281", + "id": "00000000-0000-0000-0000-000000000318", }, "role": { - "id": "00000000-0000-0000-0000-000000000274", + "id": "00000000-0000-0000-0000-000000000311", }, "searchVector": { - "id": "00000000-0000-0000-0000-000000000282", + "id": "00000000-0000-0000-0000-000000000319", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000271", + "id": "00000000-0000-0000-0000-000000000308", }, "updatedBy": { - "id": "00000000-0000-0000-0000-000000000280", + "id": "00000000-0000-0000-0000-000000000317", }, "workspaceMember": { - "id": "00000000-0000-0000-0000-000000000278", + "id": "00000000-0000-0000-0000-000000000315", }, }, - "id": "00000000-0000-0000-0000-000000000301", + "id": "00000000-0000-0000-0000-000000000338", "views": { "allMessageParticipants": { - "id": "00000000-0000-0000-0000-000000000290", + "id": "00000000-0000-0000-0000-000000000327", "viewFieldGroups": {}, "viewFields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000289", + "id": "00000000-0000-0000-0000-000000000326", }, "displayName": { - "id": "00000000-0000-0000-0000-000000000286", + "id": "00000000-0000-0000-0000-000000000323", }, "handle": { - "id": "00000000-0000-0000-0000-000000000285", + "id": "00000000-0000-0000-0000-000000000322", }, "message": { - "id": "00000000-0000-0000-0000-000000000283", + "id": "00000000-0000-0000-0000-000000000320", }, "person": { - "id": "00000000-0000-0000-0000-000000000287", + "id": "00000000-0000-0000-0000-000000000324", }, "role": { - "id": "00000000-0000-0000-0000-000000000284", + "id": "00000000-0000-0000-0000-000000000321", }, "workspaceMember": { - "id": "00000000-0000-0000-0000-000000000288", + "id": "00000000-0000-0000-0000-000000000325", }, }, "viewGroups": {}, }, "messageParticipantRecordPageFields": { - "id": "00000000-0000-0000-0000-000000000300", + "id": "00000000-0000-0000-0000-000000000337", "viewFieldGroups": { "general": { - "id": "00000000-0000-0000-0000-000000000298", + "id": "00000000-0000-0000-0000-000000000335", }, "system": { - "id": "00000000-0000-0000-0000-000000000299", + "id": "00000000-0000-0000-0000-000000000336", }, }, "viewFields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000296", + "id": "00000000-0000-0000-0000-000000000333", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000297", + "id": "00000000-0000-0000-0000-000000000334", }, "displayName": { - "id": "00000000-0000-0000-0000-000000000293", + "id": "00000000-0000-0000-0000-000000000330", }, "message": { - "id": "00000000-0000-0000-0000-000000000291", + "id": "00000000-0000-0000-0000-000000000328", }, "person": { - "id": "00000000-0000-0000-0000-000000000294", + "id": "00000000-0000-0000-0000-000000000331", }, "role": { - "id": "00000000-0000-0000-0000-000000000292", + "id": "00000000-0000-0000-0000-000000000329", }, "workspaceMember": { - "id": "00000000-0000-0000-0000-000000000295", + "id": "00000000-0000-0000-0000-000000000332", }, }, "viewGroups": {}, @@ -1103,56 +1227,56 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "messageThread": { "fields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000303", + "id": "00000000-0000-0000-0000-000000000340", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000308", + "id": "00000000-0000-0000-0000-000000000345", }, "deletedAt": { - "id": "00000000-0000-0000-0000-000000000305", + "id": "00000000-0000-0000-0000-000000000342", }, "id": { - "id": "00000000-0000-0000-0000-000000000302", + "id": "00000000-0000-0000-0000-000000000339", }, "messageChannelMessageAssociations": { - "id": "00000000-0000-0000-0000-000000000307", + "id": "00000000-0000-0000-0000-000000000344", }, "messages": { - "id": "00000000-0000-0000-0000-000000000306", + "id": "00000000-0000-0000-0000-000000000343", }, "position": { - "id": "00000000-0000-0000-0000-000000000310", + "id": "00000000-0000-0000-0000-000000000347", }, "searchVector": { - "id": "00000000-0000-0000-0000-000000000311", + "id": "00000000-0000-0000-0000-000000000348", }, "subject": { - "id": "00000000-0000-0000-0000-000000000312", + "id": "00000000-0000-0000-0000-000000000349", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000304", + "id": "00000000-0000-0000-0000-000000000341", }, "updatedBy": { - "id": "00000000-0000-0000-0000-000000000309", + "id": "00000000-0000-0000-0000-000000000346", }, }, - "id": "00000000-0000-0000-0000-000000000318", + "id": "00000000-0000-0000-0000-000000000355", "views": { "allMessageThreads": { - "id": "00000000-0000-0000-0000-000000000317", + "id": "00000000-0000-0000-0000-000000000354", "viewFieldGroups": {}, "viewFields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000316", + "id": "00000000-0000-0000-0000-000000000353", }, "messages": { - "id": "00000000-0000-0000-0000-000000000314", + "id": "00000000-0000-0000-0000-000000000351", }, "subject": { - "id": "00000000-0000-0000-0000-000000000313", + "id": "00000000-0000-0000-0000-000000000350", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000315", + "id": "00000000-0000-0000-0000-000000000352", }, }, "viewGroups": {}, @@ -1162,103 +1286,103 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "note": { "fields": { "attachments": { - "id": "00000000-0000-0000-0000-000000000353", + "id": "00000000-0000-0000-0000-000000000390", }, "bodyV2": { - "id": "00000000-0000-0000-0000-000000000349", + "id": "00000000-0000-0000-0000-000000000386", }, "createdAt": { - "id": "00000000-0000-0000-0000-000000000344", + "id": "00000000-0000-0000-0000-000000000381", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000350", + "id": "00000000-0000-0000-0000-000000000387", }, "deletedAt": { - "id": "00000000-0000-0000-0000-000000000346", + "id": "00000000-0000-0000-0000-000000000383", }, "id": { - "id": "00000000-0000-0000-0000-000000000343", + "id": "00000000-0000-0000-0000-000000000380", }, "noteTargets": { - "id": "00000000-0000-0000-0000-000000000352", + "id": "00000000-0000-0000-0000-000000000389", }, "position": { - "id": "00000000-0000-0000-0000-000000000347", + "id": "00000000-0000-0000-0000-000000000384", }, "searchVector": { - "id": "00000000-0000-0000-0000-000000000355", + "id": "00000000-0000-0000-0000-000000000392", }, "timelineActivities": { - "id": "00000000-0000-0000-0000-000000000354", + "id": "00000000-0000-0000-0000-000000000391", }, "title": { - "id": "00000000-0000-0000-0000-000000000348", + "id": "00000000-0000-0000-0000-000000000385", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000345", + "id": "00000000-0000-0000-0000-000000000382", }, "updatedBy": { - "id": "00000000-0000-0000-0000-000000000351", + "id": "00000000-0000-0000-0000-000000000388", }, }, - "id": "00000000-0000-0000-0000-000000000373", + "id": "00000000-0000-0000-0000-000000000410", "views": { "allNotes": { - "id": "00000000-0000-0000-0000-000000000361", + "id": "00000000-0000-0000-0000-000000000398", "viewFieldGroups": {}, "viewFields": { "bodyV2": { - "id": "00000000-0000-0000-0000-000000000358", + "id": "00000000-0000-0000-0000-000000000395", }, "createdAt": { - "id": "00000000-0000-0000-0000-000000000360", + "id": "00000000-0000-0000-0000-000000000397", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000359", + "id": "00000000-0000-0000-0000-000000000396", }, "noteTargets": { - "id": "00000000-0000-0000-0000-000000000357", + "id": "00000000-0000-0000-0000-000000000394", }, "title": { - "id": "00000000-0000-0000-0000-000000000356", + "id": "00000000-0000-0000-0000-000000000393", }, }, "viewGroups": {}, }, "noteRecordPageFields": { - "id": "00000000-0000-0000-0000-000000000372", + "id": "00000000-0000-0000-0000-000000000409", "viewFieldGroups": { "general": { - "id": "00000000-0000-0000-0000-000000000370", + "id": "00000000-0000-0000-0000-000000000407", }, "system": { - "id": "00000000-0000-0000-0000-000000000371", + "id": "00000000-0000-0000-0000-000000000408", }, }, "viewFields": { "attachments": { - "id": "00000000-0000-0000-0000-000000000368", + "id": "00000000-0000-0000-0000-000000000405", }, "bodyV2": { - "id": "00000000-0000-0000-0000-000000000365", + "id": "00000000-0000-0000-0000-000000000402", }, "createdAt": { - "id": "00000000-0000-0000-0000-000000000362", + "id": "00000000-0000-0000-0000-000000000399", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000363", + "id": "00000000-0000-0000-0000-000000000400", }, "noteTargets": { - "id": "00000000-0000-0000-0000-000000000364", + "id": "00000000-0000-0000-0000-000000000401", }, "timelineActivities": { - "id": "00000000-0000-0000-0000-000000000369", + "id": "00000000-0000-0000-0000-000000000406", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000366", + "id": "00000000-0000-0000-0000-000000000403", }, "updatedBy": { - "id": "00000000-0000-0000-0000-000000000367", + "id": "00000000-0000-0000-0000-000000000404", }, }, "viewGroups": {}, @@ -1268,62 +1392,62 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "noteTarget": { "fields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000375", + "id": "00000000-0000-0000-0000-000000000412", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000382", + "id": "00000000-0000-0000-0000-000000000419", }, "deletedAt": { - "id": "00000000-0000-0000-0000-000000000377", + "id": "00000000-0000-0000-0000-000000000414", }, "id": { - "id": "00000000-0000-0000-0000-000000000374", + "id": "00000000-0000-0000-0000-000000000411", }, "note": { - "id": "00000000-0000-0000-0000-000000000378", + "id": "00000000-0000-0000-0000-000000000415", }, "position": { - "id": "00000000-0000-0000-0000-000000000384", + "id": "00000000-0000-0000-0000-000000000421", }, "searchVector": { - "id": "00000000-0000-0000-0000-000000000385", + "id": "00000000-0000-0000-0000-000000000422", }, "targetCompany": { - "id": "00000000-0000-0000-0000-000000000380", + "id": "00000000-0000-0000-0000-000000000417", }, "targetOpportunity": { - "id": "00000000-0000-0000-0000-000000000381", + "id": "00000000-0000-0000-0000-000000000418", }, "targetPerson": { - "id": "00000000-0000-0000-0000-000000000379", + "id": "00000000-0000-0000-0000-000000000416", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000376", + "id": "00000000-0000-0000-0000-000000000413", }, "updatedBy": { - "id": "00000000-0000-0000-0000-000000000383", + "id": "00000000-0000-0000-0000-000000000420", }, }, - "id": "00000000-0000-0000-0000-000000000392", + "id": "00000000-0000-0000-0000-000000000429", "views": { "allNoteTargets": { - "id": "00000000-0000-0000-0000-000000000391", + "id": "00000000-0000-0000-0000-000000000428", "viewFieldGroups": {}, "viewFields": { "id": { - "id": "00000000-0000-0000-0000-000000000386", + "id": "00000000-0000-0000-0000-000000000423", }, "note": { - "id": "00000000-0000-0000-0000-000000000387", + "id": "00000000-0000-0000-0000-000000000424", }, "targetCompany": { - "id": "00000000-0000-0000-0000-000000000389", + "id": "00000000-0000-0000-0000-000000000426", }, "targetOpportunity": { - "id": "00000000-0000-0000-0000-000000000390", + "id": "00000000-0000-0000-0000-000000000427", }, "targetPerson": { - "id": "00000000-0000-0000-0000-000000000388", + "id": "00000000-0000-0000-0000-000000000425", }, }, "viewGroups": {}, @@ -1333,186 +1457,186 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "opportunity": { "fields": { "amount": { - "id": "00000000-0000-0000-0000-000000000398", + "id": "00000000-0000-0000-0000-000000000435", }, "attachments": { - "id": "00000000-0000-0000-0000-000000000409", + "id": "00000000-0000-0000-0000-000000000446", }, "closeDate": { - "id": "00000000-0000-0000-0000-000000000399", + "id": "00000000-0000-0000-0000-000000000436", }, "company": { - "id": "00000000-0000-0000-0000-000000000405", + "id": "00000000-0000-0000-0000-000000000442", }, "createdAt": { - "id": "00000000-0000-0000-0000-000000000394", + "id": "00000000-0000-0000-0000-000000000431", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000402", + "id": "00000000-0000-0000-0000-000000000439", }, "deletedAt": { - "id": "00000000-0000-0000-0000-000000000396", + "id": "00000000-0000-0000-0000-000000000433", }, "id": { - "id": "00000000-0000-0000-0000-000000000393", + "id": "00000000-0000-0000-0000-000000000430", }, "name": { - "id": "00000000-0000-0000-0000-000000000397", + "id": "00000000-0000-0000-0000-000000000434", }, "noteTargets": { - "id": "00000000-0000-0000-0000-000000000408", + "id": "00000000-0000-0000-0000-000000000445", }, "owner": { - "id": "00000000-0000-0000-0000-000000000406", + "id": "00000000-0000-0000-0000-000000000443", }, "pointOfContact": { - "id": "00000000-0000-0000-0000-000000000404", + "id": "00000000-0000-0000-0000-000000000441", }, "position": { - "id": "00000000-0000-0000-0000-000000000401", + "id": "00000000-0000-0000-0000-000000000438", }, "searchVector": { - "id": "00000000-0000-0000-0000-000000000411", + "id": "00000000-0000-0000-0000-000000000448", }, "stage": { - "id": "00000000-0000-0000-0000-000000000400", + "id": "00000000-0000-0000-0000-000000000437", }, "taskTargets": { - "id": "00000000-0000-0000-0000-000000000407", + "id": "00000000-0000-0000-0000-000000000444", }, "timelineActivities": { - "id": "00000000-0000-0000-0000-000000000410", + "id": "00000000-0000-0000-0000-000000000447", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000395", + "id": "00000000-0000-0000-0000-000000000432", }, "updatedBy": { - "id": "00000000-0000-0000-0000-000000000403", + "id": "00000000-0000-0000-0000-000000000440", }, }, - "id": "00000000-0000-0000-0000-000000000449", + "id": "00000000-0000-0000-0000-000000000486", "views": { "allOpportunities": { - "id": "00000000-0000-0000-0000-000000000418", + "id": "00000000-0000-0000-0000-000000000455", "viewFieldGroups": {}, "viewFields": { "amount": { - "id": "00000000-0000-0000-0000-000000000413", + "id": "00000000-0000-0000-0000-000000000450", }, "closeDate": { - "id": "00000000-0000-0000-0000-000000000415", + "id": "00000000-0000-0000-0000-000000000452", }, "company": { - "id": "00000000-0000-0000-0000-000000000416", + "id": "00000000-0000-0000-0000-000000000453", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000414", + "id": "00000000-0000-0000-0000-000000000451", }, "name": { - "id": "00000000-0000-0000-0000-000000000412", + "id": "00000000-0000-0000-0000-000000000449", }, "pointOfContact": { - "id": "00000000-0000-0000-0000-000000000417", + "id": "00000000-0000-0000-0000-000000000454", }, }, "viewGroups": {}, }, "byStage": { - "id": "00000000-0000-0000-0000-000000000430", + "id": "00000000-0000-0000-0000-000000000467", "viewFieldGroups": {}, "viewFields": { "amount": { - "id": "00000000-0000-0000-0000-000000000420", + "id": "00000000-0000-0000-0000-000000000457", }, "closeDate": { - "id": "00000000-0000-0000-0000-000000000422", + "id": "00000000-0000-0000-0000-000000000459", }, "company": { - "id": "00000000-0000-0000-0000-000000000423", + "id": "00000000-0000-0000-0000-000000000460", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000421", + "id": "00000000-0000-0000-0000-000000000458", }, "name": { - "id": "00000000-0000-0000-0000-000000000419", + "id": "00000000-0000-0000-0000-000000000456", }, "pointOfContact": { - "id": "00000000-0000-0000-0000-000000000424", + "id": "00000000-0000-0000-0000-000000000461", }, }, "viewGroups": { "customer": { - "id": "00000000-0000-0000-0000-000000000429", + "id": "00000000-0000-0000-0000-000000000466", }, "meeting": { - "id": "00000000-0000-0000-0000-000000000427", + "id": "00000000-0000-0000-0000-000000000464", }, "new": { - "id": "00000000-0000-0000-0000-000000000425", + "id": "00000000-0000-0000-0000-000000000462", }, "proposal": { - "id": "00000000-0000-0000-0000-000000000428", + "id": "00000000-0000-0000-0000-000000000465", }, "screening": { - "id": "00000000-0000-0000-0000-000000000426", + "id": "00000000-0000-0000-0000-000000000463", }, }, }, "opportunityRecordPageFields": { - "id": "00000000-0000-0000-0000-000000000448", + "id": "00000000-0000-0000-0000-000000000485", "viewFieldGroups": { "deal": { - "id": "00000000-0000-0000-0000-000000000445", + "id": "00000000-0000-0000-0000-000000000482", }, "relations": { - "id": "00000000-0000-0000-0000-000000000446", + "id": "00000000-0000-0000-0000-000000000483", }, "system": { - "id": "00000000-0000-0000-0000-000000000447", + "id": "00000000-0000-0000-0000-000000000484", }, }, "viewFields": { "amount": { - "id": "00000000-0000-0000-0000-000000000431", + "id": "00000000-0000-0000-0000-000000000468", }, "attachments": { - "id": "00000000-0000-0000-0000-000000000443", + "id": "00000000-0000-0000-0000-000000000480", }, "closeDate": { - "id": "00000000-0000-0000-0000-000000000432", + "id": "00000000-0000-0000-0000-000000000469", }, "company": { - "id": "00000000-0000-0000-0000-000000000434", + "id": "00000000-0000-0000-0000-000000000471", }, "createdAt": { - "id": "00000000-0000-0000-0000-000000000437", + "id": "00000000-0000-0000-0000-000000000474", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000438", + "id": "00000000-0000-0000-0000-000000000475", }, "noteTargets": { - "id": "00000000-0000-0000-0000-000000000442", + "id": "00000000-0000-0000-0000-000000000479", }, "owner": { - "id": "00000000-0000-0000-0000-000000000436", + "id": "00000000-0000-0000-0000-000000000473", }, "pointOfContact": { - "id": "00000000-0000-0000-0000-000000000435", + "id": "00000000-0000-0000-0000-000000000472", }, "stage": { - "id": "00000000-0000-0000-0000-000000000433", + "id": "00000000-0000-0000-0000-000000000470", }, "taskTargets": { - "id": "00000000-0000-0000-0000-000000000441", + "id": "00000000-0000-0000-0000-000000000478", }, "timelineActivities": { - "id": "00000000-0000-0000-0000-000000000444", + "id": "00000000-0000-0000-0000-000000000481", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000439", + "id": "00000000-0000-0000-0000-000000000476", }, "updatedBy": { - "id": "00000000-0000-0000-0000-000000000440", + "id": "00000000-0000-0000-0000-000000000477", }, }, "viewGroups": {}, @@ -1522,178 +1646,178 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "person": { "fields": { "attachments": { - "id": "00000000-0000-0000-0000-000000000468", + "id": "00000000-0000-0000-0000-000000000505", }, "avatarFile": { - "id": "00000000-0000-0000-0000-000000000460", + "id": "00000000-0000-0000-0000-000000000497", }, "avatarUrl": { - "id": "00000000-0000-0000-0000-000000000459", + "id": "00000000-0000-0000-0000-000000000496", }, "calendarEventParticipants": { - "id": "00000000-0000-0000-0000-000000000470", + "id": "00000000-0000-0000-0000-000000000507", }, "company": { - "id": "00000000-0000-0000-0000-000000000464", + "id": "00000000-0000-0000-0000-000000000501", }, "createdAt": { - "id": "00000000-0000-0000-0000-000000000451", + "id": "00000000-0000-0000-0000-000000000488", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000462", + "id": "00000000-0000-0000-0000-000000000499", }, "deletedAt": { - "id": "00000000-0000-0000-0000-000000000453", + "id": "00000000-0000-0000-0000-000000000490", }, "emails": { - "id": "00000000-0000-0000-0000-000000000455", + "id": "00000000-0000-0000-0000-000000000492", }, "id": { - "id": "00000000-0000-0000-0000-000000000450", + "id": "00000000-0000-0000-0000-000000000487", }, "jobTitle": { - "id": "00000000-0000-0000-0000-000000000457", + "id": "00000000-0000-0000-0000-000000000494", }, "linkedinLink": { - "id": "00000000-0000-0000-0000-000000000456", + "id": "00000000-0000-0000-0000-000000000493", }, "messageParticipants": { - "id": "00000000-0000-0000-0000-000000000469", + "id": "00000000-0000-0000-0000-000000000506", }, "name": { - "id": "00000000-0000-0000-0000-000000000454", + "id": "00000000-0000-0000-0000-000000000491", }, "noteTargets": { - "id": "00000000-0000-0000-0000-000000000467", + "id": "00000000-0000-0000-0000-000000000504", }, "phones": { - "id": "00000000-0000-0000-0000-000000000458", + "id": "00000000-0000-0000-0000-000000000495", }, "pointOfContactForOpportunities": { - "id": "00000000-0000-0000-0000-000000000465", + "id": "00000000-0000-0000-0000-000000000502", }, "position": { - "id": "00000000-0000-0000-0000-000000000461", + "id": "00000000-0000-0000-0000-000000000498", }, "searchVector": { - "id": "00000000-0000-0000-0000-000000000472", + "id": "00000000-0000-0000-0000-000000000509", }, "taskTargets": { - "id": "00000000-0000-0000-0000-000000000466", + "id": "00000000-0000-0000-0000-000000000503", }, "timelineActivities": { - "id": "00000000-0000-0000-0000-000000000471", + "id": "00000000-0000-0000-0000-000000000508", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000452", + "id": "00000000-0000-0000-0000-000000000489", }, "updatedBy": { - "id": "00000000-0000-0000-0000-000000000463", + "id": "00000000-0000-0000-0000-000000000500", }, }, - "id": "00000000-0000-0000-0000-000000000505", + "id": "00000000-0000-0000-0000-000000000542", "views": { "allPeople": { - "id": "00000000-0000-0000-0000-000000000481", + "id": "00000000-0000-0000-0000-000000000518", "viewFieldGroups": {}, "viewFields": { "company": { - "id": "00000000-0000-0000-0000-000000000476", + "id": "00000000-0000-0000-0000-000000000513", }, "createdAt": { - "id": "00000000-0000-0000-0000-000000000478", + "id": "00000000-0000-0000-0000-000000000515", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000475", + "id": "00000000-0000-0000-0000-000000000512", }, "emails": { - "id": "00000000-0000-0000-0000-000000000474", + "id": "00000000-0000-0000-0000-000000000511", }, "jobTitle": { - "id": "00000000-0000-0000-0000-000000000479", + "id": "00000000-0000-0000-0000-000000000516", }, "linkedinLink": { - "id": "00000000-0000-0000-0000-000000000480", + "id": "00000000-0000-0000-0000-000000000517", }, "name": { - "id": "00000000-0000-0000-0000-000000000473", + "id": "00000000-0000-0000-0000-000000000510", }, "phones": { - "id": "00000000-0000-0000-0000-000000000477", + "id": "00000000-0000-0000-0000-000000000514", }, }, "viewGroups": {}, }, "personRecordPageFields": { - "id": "00000000-0000-0000-0000-000000000504", + "id": "00000000-0000-0000-0000-000000000541", "viewFieldGroups": { "general": { - "id": "00000000-0000-0000-0000-000000000500", + "id": "00000000-0000-0000-0000-000000000537", }, "social": { - "id": "00000000-0000-0000-0000-000000000502", + "id": "00000000-0000-0000-0000-000000000539", }, "system": { - "id": "00000000-0000-0000-0000-000000000503", + "id": "00000000-0000-0000-0000-000000000540", }, "work": { - "id": "00000000-0000-0000-0000-000000000501", + "id": "00000000-0000-0000-0000-000000000538", }, }, "viewFields": { "attachments": { - "id": "00000000-0000-0000-0000-000000000496", + "id": "00000000-0000-0000-0000-000000000533", }, "avatarFile": { - "id": "00000000-0000-0000-0000-000000000492", + "id": "00000000-0000-0000-0000-000000000529", }, "avatarUrl": { - "id": "00000000-0000-0000-0000-000000000487", + "id": "00000000-0000-0000-0000-000000000524", }, "calendarEventParticipants": { - "id": "00000000-0000-0000-0000-000000000498", + "id": "00000000-0000-0000-0000-000000000535", }, "company": { - "id": "00000000-0000-0000-0000-000000000484", + "id": "00000000-0000-0000-0000-000000000521", }, "createdAt": { - "id": "00000000-0000-0000-0000-000000000488", + "id": "00000000-0000-0000-0000-000000000525", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000489", + "id": "00000000-0000-0000-0000-000000000526", }, "emails": { - "id": "00000000-0000-0000-0000-000000000482", + "id": "00000000-0000-0000-0000-000000000519", }, "jobTitle": { - "id": "00000000-0000-0000-0000-000000000485", + "id": "00000000-0000-0000-0000-000000000522", }, "linkedinLink": { - "id": "00000000-0000-0000-0000-000000000486", + "id": "00000000-0000-0000-0000-000000000523", }, "messageParticipants": { - "id": "00000000-0000-0000-0000-000000000497", + "id": "00000000-0000-0000-0000-000000000534", }, "noteTargets": { - "id": "00000000-0000-0000-0000-000000000495", + "id": "00000000-0000-0000-0000-000000000532", }, "phones": { - "id": "00000000-0000-0000-0000-000000000483", + "id": "00000000-0000-0000-0000-000000000520", }, "pointOfContactForOpportunities": { - "id": "00000000-0000-0000-0000-000000000493", + "id": "00000000-0000-0000-0000-000000000530", }, "taskTargets": { - "id": "00000000-0000-0000-0000-000000000494", + "id": "00000000-0000-0000-0000-000000000531", }, "timelineActivities": { - "id": "00000000-0000-0000-0000-000000000499", + "id": "00000000-0000-0000-0000-000000000536", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000490", + "id": "00000000-0000-0000-0000-000000000527", }, "updatedBy": { - "id": "00000000-0000-0000-0000-000000000491", + "id": "00000000-0000-0000-0000-000000000528", }, }, "viewGroups": {}, @@ -1703,203 +1827,203 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "task": { "fields": { "assignee": { - "id": "00000000-0000-0000-0000-000000000519", + "id": "00000000-0000-0000-0000-000000000556", }, "attachments": { - "id": "00000000-0000-0000-0000-000000000518", + "id": "00000000-0000-0000-0000-000000000555", }, "bodyV2": { - "id": "00000000-0000-0000-0000-000000000512", + "id": "00000000-0000-0000-0000-000000000549", }, "createdAt": { - "id": "00000000-0000-0000-0000-000000000507", + "id": "00000000-0000-0000-0000-000000000544", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000515", + "id": "00000000-0000-0000-0000-000000000552", }, "deletedAt": { - "id": "00000000-0000-0000-0000-000000000509", + "id": "00000000-0000-0000-0000-000000000546", }, "dueAt": { - "id": "00000000-0000-0000-0000-000000000513", + "id": "00000000-0000-0000-0000-000000000550", }, "id": { - "id": "00000000-0000-0000-0000-000000000506", + "id": "00000000-0000-0000-0000-000000000543", }, "position": { - "id": "00000000-0000-0000-0000-000000000510", + "id": "00000000-0000-0000-0000-000000000547", }, "searchVector": { - "id": "00000000-0000-0000-0000-000000000521", + "id": "00000000-0000-0000-0000-000000000558", }, "status": { - "id": "00000000-0000-0000-0000-000000000514", + "id": "00000000-0000-0000-0000-000000000551", }, "taskTargets": { - "id": "00000000-0000-0000-0000-000000000517", + "id": "00000000-0000-0000-0000-000000000554", }, "timelineActivities": { - "id": "00000000-0000-0000-0000-000000000520", + "id": "00000000-0000-0000-0000-000000000557", }, "title": { - "id": "00000000-0000-0000-0000-000000000511", + "id": "00000000-0000-0000-0000-000000000548", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000508", + "id": "00000000-0000-0000-0000-000000000545", }, "updatedBy": { - "id": "00000000-0000-0000-0000-000000000516", + "id": "00000000-0000-0000-0000-000000000553", }, }, - "id": "00000000-0000-0000-0000-000000000566", + "id": "00000000-0000-0000-0000-000000000603", "views": { "allTasks": { - "id": "00000000-0000-0000-0000-000000000530", + "id": "00000000-0000-0000-0000-000000000567", "viewFieldGroups": {}, "viewFields": { "assignee": { - "id": "00000000-0000-0000-0000-000000000527", + "id": "00000000-0000-0000-0000-000000000564", }, "bodyV2": { - "id": "00000000-0000-0000-0000-000000000528", + "id": "00000000-0000-0000-0000-000000000565", }, "createdAt": { - "id": "00000000-0000-0000-0000-000000000529", + "id": "00000000-0000-0000-0000-000000000566", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000525", + "id": "00000000-0000-0000-0000-000000000562", }, "dueAt": { - "id": "00000000-0000-0000-0000-000000000526", + "id": "00000000-0000-0000-0000-000000000563", }, "status": { - "id": "00000000-0000-0000-0000-000000000523", + "id": "00000000-0000-0000-0000-000000000560", }, "taskTargets": { - "id": "00000000-0000-0000-0000-000000000524", + "id": "00000000-0000-0000-0000-000000000561", }, "title": { - "id": "00000000-0000-0000-0000-000000000522", + "id": "00000000-0000-0000-0000-000000000559", }, }, "viewGroups": {}, }, "assignedToMe": { - "id": "00000000-0000-0000-0000-000000000542", + "id": "00000000-0000-0000-0000-000000000579", "viewFieldGroups": {}, "viewFields": { "assignee": { - "id": "00000000-0000-0000-0000-000000000535", + "id": "00000000-0000-0000-0000-000000000572", }, "bodyV2": { - "id": "00000000-0000-0000-0000-000000000536", + "id": "00000000-0000-0000-0000-000000000573", }, "createdAt": { - "id": "00000000-0000-0000-0000-000000000537", + "id": "00000000-0000-0000-0000-000000000574", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000533", + "id": "00000000-0000-0000-0000-000000000570", }, "dueAt": { - "id": "00000000-0000-0000-0000-000000000534", + "id": "00000000-0000-0000-0000-000000000571", }, "taskTargets": { - "id": "00000000-0000-0000-0000-000000000532", + "id": "00000000-0000-0000-0000-000000000569", }, "title": { - "id": "00000000-0000-0000-0000-000000000531", + "id": "00000000-0000-0000-0000-000000000568", }, }, "viewGroups": { "done": { - "id": "00000000-0000-0000-0000-000000000540", + "id": "00000000-0000-0000-0000-000000000577", }, "empty": { - "id": "00000000-0000-0000-0000-000000000541", + "id": "00000000-0000-0000-0000-000000000578", }, "inProgress": { - "id": "00000000-0000-0000-0000-000000000539", + "id": "00000000-0000-0000-0000-000000000576", }, "todo": { - "id": "00000000-0000-0000-0000-000000000538", + "id": "00000000-0000-0000-0000-000000000575", }, }, }, "byStatus": { - "id": "00000000-0000-0000-0000-000000000551", + "id": "00000000-0000-0000-0000-000000000588", "viewFieldGroups": {}, "viewFields": { "assignee": { - "id": "00000000-0000-0000-0000-000000000546", + "id": "00000000-0000-0000-0000-000000000583", }, "createdAt": { - "id": "00000000-0000-0000-0000-000000000547", + "id": "00000000-0000-0000-0000-000000000584", }, "dueAt": { - "id": "00000000-0000-0000-0000-000000000545", + "id": "00000000-0000-0000-0000-000000000582", }, "status": { - "id": "00000000-0000-0000-0000-000000000544", + "id": "00000000-0000-0000-0000-000000000581", }, "title": { - "id": "00000000-0000-0000-0000-000000000543", + "id": "00000000-0000-0000-0000-000000000580", }, }, "viewGroups": { "done": { - "id": "00000000-0000-0000-0000-000000000550", + "id": "00000000-0000-0000-0000-000000000587", }, "inProgress": { - "id": "00000000-0000-0000-0000-000000000549", + "id": "00000000-0000-0000-0000-000000000586", }, "todo": { - "id": "00000000-0000-0000-0000-000000000548", + "id": "00000000-0000-0000-0000-000000000585", }, }, }, "taskRecordPageFields": { - "id": "00000000-0000-0000-0000-000000000565", + "id": "00000000-0000-0000-0000-000000000602", "viewFieldGroups": { "general": { - "id": "00000000-0000-0000-0000-000000000563", + "id": "00000000-0000-0000-0000-000000000600", }, "system": { - "id": "00000000-0000-0000-0000-000000000564", + "id": "00000000-0000-0000-0000-000000000601", }, }, "viewFields": { "assignee": { - "id": "00000000-0000-0000-0000-000000000554", + "id": "00000000-0000-0000-0000-000000000591", }, "attachments": { - "id": "00000000-0000-0000-0000-000000000561", + "id": "00000000-0000-0000-0000-000000000598", }, "bodyV2": { - "id": "00000000-0000-0000-0000-000000000558", + "id": "00000000-0000-0000-0000-000000000595", }, "createdAt": { - "id": "00000000-0000-0000-0000-000000000555", + "id": "00000000-0000-0000-0000-000000000592", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000556", + "id": "00000000-0000-0000-0000-000000000593", }, "dueAt": { - "id": "00000000-0000-0000-0000-000000000552", + "id": "00000000-0000-0000-0000-000000000589", }, "status": { - "id": "00000000-0000-0000-0000-000000000553", + "id": "00000000-0000-0000-0000-000000000590", }, "taskTargets": { - "id": "00000000-0000-0000-0000-000000000557", + "id": "00000000-0000-0000-0000-000000000594", }, "timelineActivities": { - "id": "00000000-0000-0000-0000-000000000562", + "id": "00000000-0000-0000-0000-000000000599", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000559", + "id": "00000000-0000-0000-0000-000000000596", }, "updatedBy": { - "id": "00000000-0000-0000-0000-000000000560", + "id": "00000000-0000-0000-0000-000000000597", }, }, "viewGroups": {}, @@ -1909,62 +2033,62 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "taskTarget": { "fields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000568", + "id": "00000000-0000-0000-0000-000000000605", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000575", + "id": "00000000-0000-0000-0000-000000000612", }, "deletedAt": { - "id": "00000000-0000-0000-0000-000000000570", + "id": "00000000-0000-0000-0000-000000000607", }, "id": { - "id": "00000000-0000-0000-0000-000000000567", + "id": "00000000-0000-0000-0000-000000000604", }, "position": { - "id": "00000000-0000-0000-0000-000000000577", + "id": "00000000-0000-0000-0000-000000000614", }, "searchVector": { - "id": "00000000-0000-0000-0000-000000000578", + "id": "00000000-0000-0000-0000-000000000615", }, "targetCompany": { - "id": "00000000-0000-0000-0000-000000000573", + "id": "00000000-0000-0000-0000-000000000610", }, "targetOpportunity": { - "id": "00000000-0000-0000-0000-000000000574", + "id": "00000000-0000-0000-0000-000000000611", }, "targetPerson": { - "id": "00000000-0000-0000-0000-000000000572", + "id": "00000000-0000-0000-0000-000000000609", }, "task": { - "id": "00000000-0000-0000-0000-000000000571", + "id": "00000000-0000-0000-0000-000000000608", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000569", + "id": "00000000-0000-0000-0000-000000000606", }, "updatedBy": { - "id": "00000000-0000-0000-0000-000000000576", + "id": "00000000-0000-0000-0000-000000000613", }, }, - "id": "00000000-0000-0000-0000-000000000585", + "id": "00000000-0000-0000-0000-000000000622", "views": { "allTaskTargets": { - "id": "00000000-0000-0000-0000-000000000584", + "id": "00000000-0000-0000-0000-000000000621", "viewFieldGroups": {}, "viewFields": { "id": { - "id": "00000000-0000-0000-0000-000000000579", + "id": "00000000-0000-0000-0000-000000000616", }, "targetCompany": { - "id": "00000000-0000-0000-0000-000000000582", + "id": "00000000-0000-0000-0000-000000000619", }, "targetOpportunity": { - "id": "00000000-0000-0000-0000-000000000583", + "id": "00000000-0000-0000-0000-000000000620", }, "targetPerson": { - "id": "00000000-0000-0000-0000-000000000581", + "id": "00000000-0000-0000-0000-000000000618", }, "task": { - "id": "00000000-0000-0000-0000-000000000580", + "id": "00000000-0000-0000-0000-000000000617", }, }, "viewGroups": {}, @@ -1974,125 +2098,125 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "timelineActivity": { "fields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000587", + "id": "00000000-0000-0000-0000-000000000624", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000606", + "id": "00000000-0000-0000-0000-000000000643", }, "deletedAt": { - "id": "00000000-0000-0000-0000-000000000589", + "id": "00000000-0000-0000-0000-000000000626", }, "happensAt": { - "id": "00000000-0000-0000-0000-000000000590", + "id": "00000000-0000-0000-0000-000000000627", }, "id": { - "id": "00000000-0000-0000-0000-000000000586", + "id": "00000000-0000-0000-0000-000000000623", }, "linkedObjectMetadataId": { - "id": "00000000-0000-0000-0000-000000000605", + "id": "00000000-0000-0000-0000-000000000642", }, "linkedRecordCachedName": { - "id": "00000000-0000-0000-0000-000000000603", + "id": "00000000-0000-0000-0000-000000000640", }, "linkedRecordId": { - "id": "00000000-0000-0000-0000-000000000604", + "id": "00000000-0000-0000-0000-000000000641", }, "name": { - "id": "00000000-0000-0000-0000-000000000591", + "id": "00000000-0000-0000-0000-000000000628", }, "position": { - "id": "00000000-0000-0000-0000-000000000608", + "id": "00000000-0000-0000-0000-000000000645", }, "properties": { - "id": "00000000-0000-0000-0000-000000000592", + "id": "00000000-0000-0000-0000-000000000629", }, "searchVector": { - "id": "00000000-0000-0000-0000-000000000609", + "id": "00000000-0000-0000-0000-000000000646", }, "targetCompany": { - "id": "00000000-0000-0000-0000-000000000595", + "id": "00000000-0000-0000-0000-000000000632", }, "targetDashboard": { - "id": "00000000-0000-0000-0000-000000000602", + "id": "00000000-0000-0000-0000-000000000639", }, "targetNote": { - "id": "00000000-0000-0000-0000-000000000598", + "id": "00000000-0000-0000-0000-000000000635", }, "targetOpportunity": { - "id": "00000000-0000-0000-0000-000000000596", + "id": "00000000-0000-0000-0000-000000000633", }, "targetPerson": { - "id": "00000000-0000-0000-0000-000000000594", + "id": "00000000-0000-0000-0000-000000000631", }, "targetTask": { - "id": "00000000-0000-0000-0000-000000000597", + "id": "00000000-0000-0000-0000-000000000634", }, "targetWorkflow": { - "id": "00000000-0000-0000-0000-000000000599", + "id": "00000000-0000-0000-0000-000000000636", }, "targetWorkflowRun": { - "id": "00000000-0000-0000-0000-000000000601", + "id": "00000000-0000-0000-0000-000000000638", }, "targetWorkflowVersion": { - "id": "00000000-0000-0000-0000-000000000600", + "id": "00000000-0000-0000-0000-000000000637", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000588", + "id": "00000000-0000-0000-0000-000000000625", }, "updatedBy": { - "id": "00000000-0000-0000-0000-000000000607", + "id": "00000000-0000-0000-0000-000000000644", }, "workspaceMember": { - "id": "00000000-0000-0000-0000-000000000593", + "id": "00000000-0000-0000-0000-000000000630", }, }, - "id": "00000000-0000-0000-0000-000000000625", + "id": "00000000-0000-0000-0000-000000000662", "views": { "allTimelineActivities": { - "id": "00000000-0000-0000-0000-000000000624", + "id": "00000000-0000-0000-0000-000000000661", "viewFieldGroups": {}, "viewFields": { "happensAt": { - "id": "00000000-0000-0000-0000-000000000611", + "id": "00000000-0000-0000-0000-000000000648", }, "linkedRecordCachedName": { - "id": "00000000-0000-0000-0000-000000000614", + "id": "00000000-0000-0000-0000-000000000651", }, "name": { - "id": "00000000-0000-0000-0000-000000000610", + "id": "00000000-0000-0000-0000-000000000647", }, "properties": { - "id": "00000000-0000-0000-0000-000000000612", + "id": "00000000-0000-0000-0000-000000000649", }, "targetCompany": { - "id": "00000000-0000-0000-0000-000000000616", + "id": "00000000-0000-0000-0000-000000000653", }, "targetDashboard": { - "id": "00000000-0000-0000-0000-000000000623", + "id": "00000000-0000-0000-0000-000000000660", }, "targetNote": { - "id": "00000000-0000-0000-0000-000000000619", + "id": "00000000-0000-0000-0000-000000000656", }, "targetOpportunity": { - "id": "00000000-0000-0000-0000-000000000617", + "id": "00000000-0000-0000-0000-000000000654", }, "targetPerson": { - "id": "00000000-0000-0000-0000-000000000615", + "id": "00000000-0000-0000-0000-000000000652", }, "targetTask": { - "id": "00000000-0000-0000-0000-000000000618", + "id": "00000000-0000-0000-0000-000000000655", }, "targetWorkflow": { - "id": "00000000-0000-0000-0000-000000000620", + "id": "00000000-0000-0000-0000-000000000657", }, "targetWorkflowRun": { - "id": "00000000-0000-0000-0000-000000000622", + "id": "00000000-0000-0000-0000-000000000659", }, "targetWorkflowVersion": { - "id": "00000000-0000-0000-0000-000000000621", + "id": "00000000-0000-0000-0000-000000000658", }, "workspaceMember": { - "id": "00000000-0000-0000-0000-000000000613", + "id": "00000000-0000-0000-0000-000000000650", }, }, "viewGroups": {}, @@ -2102,77 +2226,77 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "workflow": { "fields": { "attachments": { - "id": "00000000-0000-0000-0000-000000000638", + "id": "00000000-0000-0000-0000-000000000675", }, "automatedTriggers": { - "id": "00000000-0000-0000-0000-000000000636", + "id": "00000000-0000-0000-0000-000000000673", }, "createdAt": { - "id": "00000000-0000-0000-0000-000000000627", + "id": "00000000-0000-0000-0000-000000000664", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000639", + "id": "00000000-0000-0000-0000-000000000676", }, "deletedAt": { - "id": "00000000-0000-0000-0000-000000000629", + "id": "00000000-0000-0000-0000-000000000666", }, "id": { - "id": "00000000-0000-0000-0000-000000000626", + "id": "00000000-0000-0000-0000-000000000663", }, "lastPublishedVersionId": { - "id": "00000000-0000-0000-0000-000000000631", + "id": "00000000-0000-0000-0000-000000000668", }, "name": { - "id": "00000000-0000-0000-0000-000000000630", + "id": "00000000-0000-0000-0000-000000000667", }, "position": { - "id": "00000000-0000-0000-0000-000000000633", + "id": "00000000-0000-0000-0000-000000000670", }, "runs": { - "id": "00000000-0000-0000-0000-000000000635", + "id": "00000000-0000-0000-0000-000000000672", }, "searchVector": { - "id": "00000000-0000-0000-0000-000000000641", + "id": "00000000-0000-0000-0000-000000000678", }, "statuses": { - "id": "00000000-0000-0000-0000-000000000632", + "id": "00000000-0000-0000-0000-000000000669", }, "timelineActivities": { - "id": "00000000-0000-0000-0000-000000000637", + "id": "00000000-0000-0000-0000-000000000674", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000628", + "id": "00000000-0000-0000-0000-000000000665", }, "updatedBy": { - "id": "00000000-0000-0000-0000-000000000640", + "id": "00000000-0000-0000-0000-000000000677", }, "versions": { - "id": "00000000-0000-0000-0000-000000000634", + "id": "00000000-0000-0000-0000-000000000671", }, }, - "id": "00000000-0000-0000-0000-000000000649", + "id": "00000000-0000-0000-0000-000000000686", "views": { "allWorkflows": { - "id": "00000000-0000-0000-0000-000000000648", + "id": "00000000-0000-0000-0000-000000000685", "viewFieldGroups": {}, "viewFields": { "createdBy": { - "id": "00000000-0000-0000-0000-000000000645", + "id": "00000000-0000-0000-0000-000000000682", }, "name": { - "id": "00000000-0000-0000-0000-000000000642", + "id": "00000000-0000-0000-0000-000000000679", }, "runs": { - "id": "00000000-0000-0000-0000-000000000647", + "id": "00000000-0000-0000-0000-000000000684", }, "statuses": { - "id": "00000000-0000-0000-0000-000000000643", + "id": "00000000-0000-0000-0000-000000000680", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000644", + "id": "00000000-0000-0000-0000-000000000681", }, "versions": { - "id": "00000000-0000-0000-0000-000000000646", + "id": "00000000-0000-0000-0000-000000000683", }, }, "viewGroups": {}, @@ -2182,79 +2306,79 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "workflowAutomatedTrigger": { "fields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000651", + "id": "00000000-0000-0000-0000-000000000688", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000657", + "id": "00000000-0000-0000-0000-000000000694", }, "deletedAt": { - "id": "00000000-0000-0000-0000-000000000653", + "id": "00000000-0000-0000-0000-000000000690", }, "id": { - "id": "00000000-0000-0000-0000-000000000650", + "id": "00000000-0000-0000-0000-000000000687", }, "position": { - "id": "00000000-0000-0000-0000-000000000659", + "id": "00000000-0000-0000-0000-000000000696", }, "searchVector": { - "id": "00000000-0000-0000-0000-000000000660", + "id": "00000000-0000-0000-0000-000000000697", }, "settings": { - "id": "00000000-0000-0000-0000-000000000655", + "id": "00000000-0000-0000-0000-000000000692", }, "type": { - "id": "00000000-0000-0000-0000-000000000654", + "id": "00000000-0000-0000-0000-000000000691", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000652", + "id": "00000000-0000-0000-0000-000000000689", }, "updatedBy": { - "id": "00000000-0000-0000-0000-000000000658", + "id": "00000000-0000-0000-0000-000000000695", }, "workflow": { - "id": "00000000-0000-0000-0000-000000000656", + "id": "00000000-0000-0000-0000-000000000693", }, }, - "id": "00000000-0000-0000-0000-000000000672", + "id": "00000000-0000-0000-0000-000000000709", "views": { "allWorkflowAutomatedTriggers": { - "id": "00000000-0000-0000-0000-000000000664", + "id": "00000000-0000-0000-0000-000000000701", "viewFieldGroups": {}, "viewFields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000663", + "id": "00000000-0000-0000-0000-000000000700", }, "type": { - "id": "00000000-0000-0000-0000-000000000661", + "id": "00000000-0000-0000-0000-000000000698", }, "workflow": { - "id": "00000000-0000-0000-0000-000000000662", + "id": "00000000-0000-0000-0000-000000000699", }, }, "viewGroups": {}, }, "workflowAutomatedTriggerRecordPageFields": { - "id": "00000000-0000-0000-0000-000000000671", + "id": "00000000-0000-0000-0000-000000000708", "viewFieldGroups": { "general": { - "id": "00000000-0000-0000-0000-000000000669", + "id": "00000000-0000-0000-0000-000000000706", }, "system": { - "id": "00000000-0000-0000-0000-000000000670", + "id": "00000000-0000-0000-0000-000000000707", }, }, "viewFields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000667", + "id": "00000000-0000-0000-0000-000000000704", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000668", + "id": "00000000-0000-0000-0000-000000000705", }, "type": { - "id": "00000000-0000-0000-0000-000000000665", + "id": "00000000-0000-0000-0000-000000000702", }, "workflow": { - "id": "00000000-0000-0000-0000-000000000666", + "id": "00000000-0000-0000-0000-000000000703", }, }, "viewGroups": {}, @@ -2264,133 +2388,133 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "workflowRun": { "fields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000674", + "id": "00000000-0000-0000-0000-000000000711", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000685", + "id": "00000000-0000-0000-0000-000000000722", }, "deletedAt": { - "id": "00000000-0000-0000-0000-000000000676", + "id": "00000000-0000-0000-0000-000000000713", }, "endedAt": { - "id": "00000000-0000-0000-0000-000000000682", + "id": "00000000-0000-0000-0000-000000000719", }, "enqueuedAt": { - "id": "00000000-0000-0000-0000-000000000680", + "id": "00000000-0000-0000-0000-000000000717", }, "id": { - "id": "00000000-0000-0000-0000-000000000673", + "id": "00000000-0000-0000-0000-000000000710", }, "name": { - "id": "00000000-0000-0000-0000-000000000677", + "id": "00000000-0000-0000-0000-000000000714", }, "position": { - "id": "00000000-0000-0000-0000-000000000684", + "id": "00000000-0000-0000-0000-000000000721", }, "searchVector": { - "id": "00000000-0000-0000-0000-000000000690", + "id": "00000000-0000-0000-0000-000000000727", }, "startedAt": { - "id": "00000000-0000-0000-0000-000000000681", + "id": "00000000-0000-0000-0000-000000000718", }, "state": { - "id": "00000000-0000-0000-0000-000000000687", + "id": "00000000-0000-0000-0000-000000000724", }, "status": { - "id": "00000000-0000-0000-0000-000000000683", + "id": "00000000-0000-0000-0000-000000000720", }, "stepLogs": { - "id": "00000000-0000-0000-0000-000000000688", + "id": "00000000-0000-0000-0000-000000000725", }, "timelineActivities": { - "id": "00000000-0000-0000-0000-000000000689", + "id": "00000000-0000-0000-0000-000000000726", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000675", + "id": "00000000-0000-0000-0000-000000000712", }, "updatedBy": { - "id": "00000000-0000-0000-0000-000000000686", + "id": "00000000-0000-0000-0000-000000000723", }, "workflow": { - "id": "00000000-0000-0000-0000-000000000679", + "id": "00000000-0000-0000-0000-000000000716", }, "workflowVersion": { - "id": "00000000-0000-0000-0000-000000000678", + "id": "00000000-0000-0000-0000-000000000715", }, }, - "id": "00000000-0000-0000-0000-000000000713", + "id": "00000000-0000-0000-0000-000000000750", "views": { "allWorkflowRuns": { - "id": "00000000-0000-0000-0000-000000000697", + "id": "00000000-0000-0000-0000-000000000734", "viewFieldGroups": {}, "viewFields": { "createdBy": { - "id": "00000000-0000-0000-0000-000000000695", + "id": "00000000-0000-0000-0000-000000000732", }, "name": { - "id": "00000000-0000-0000-0000-000000000691", + "id": "00000000-0000-0000-0000-000000000728", }, "startedAt": { - "id": "00000000-0000-0000-0000-000000000694", + "id": "00000000-0000-0000-0000-000000000731", }, "status": { - "id": "00000000-0000-0000-0000-000000000693", + "id": "00000000-0000-0000-0000-000000000730", }, "workflow": { - "id": "00000000-0000-0000-0000-000000000692", + "id": "00000000-0000-0000-0000-000000000729", }, "workflowVersion": { - "id": "00000000-0000-0000-0000-000000000696", + "id": "00000000-0000-0000-0000-000000000733", }, }, "viewGroups": {}, }, "workflowRunRecordPageFields": { - "id": "00000000-0000-0000-0000-000000000712", + "id": "00000000-0000-0000-0000-000000000749", "viewFieldGroups": { "general": { - "id": "00000000-0000-0000-0000-000000000710", + "id": "00000000-0000-0000-0000-000000000747", }, "system": { - "id": "00000000-0000-0000-0000-000000000711", + "id": "00000000-0000-0000-0000-000000000748", }, }, "viewFields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000703", + "id": "00000000-0000-0000-0000-000000000740", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000704", + "id": "00000000-0000-0000-0000-000000000741", }, "endedAt": { - "id": "00000000-0000-0000-0000-000000000702", + "id": "00000000-0000-0000-0000-000000000739", }, "enqueuedAt": { - "id": "00000000-0000-0000-0000-000000000705", + "id": "00000000-0000-0000-0000-000000000742", }, "startedAt": { - "id": "00000000-0000-0000-0000-000000000701", + "id": "00000000-0000-0000-0000-000000000738", }, "state": { - "id": "00000000-0000-0000-0000-000000000706", + "id": "00000000-0000-0000-0000-000000000743", }, "status": { - "id": "00000000-0000-0000-0000-000000000698", + "id": "00000000-0000-0000-0000-000000000735", }, "timelineActivities": { - "id": "00000000-0000-0000-0000-000000000709", + "id": "00000000-0000-0000-0000-000000000746", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000707", + "id": "00000000-0000-0000-0000-000000000744", }, "updatedBy": { - "id": "00000000-0000-0000-0000-000000000708", + "id": "00000000-0000-0000-0000-000000000745", }, "workflow": { - "id": "00000000-0000-0000-0000-000000000699", + "id": "00000000-0000-0000-0000-000000000736", }, "workflowVersion": { - "id": "00000000-0000-0000-0000-000000000700", + "id": "00000000-0000-0000-0000-000000000737", }, }, "viewGroups": {}, @@ -2400,115 +2524,115 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "workflowVersion": { "fields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000715", + "id": "00000000-0000-0000-0000-000000000752", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000727", + "id": "00000000-0000-0000-0000-000000000764", }, "deletedAt": { - "id": "00000000-0000-0000-0000-000000000717", + "id": "00000000-0000-0000-0000-000000000754", }, "id": { - "id": "00000000-0000-0000-0000-000000000714", + "id": "00000000-0000-0000-0000-000000000751", }, "name": { - "id": "00000000-0000-0000-0000-000000000718", + "id": "00000000-0000-0000-0000-000000000755", }, "position": { - "id": "00000000-0000-0000-0000-000000000722", + "id": "00000000-0000-0000-0000-000000000759", }, "runs": { - "id": "00000000-0000-0000-0000-000000000723", + "id": "00000000-0000-0000-0000-000000000760", }, "searchVector": { - "id": "00000000-0000-0000-0000-000000000726", + "id": "00000000-0000-0000-0000-000000000763", }, "status": { - "id": "00000000-0000-0000-0000-000000000721", + "id": "00000000-0000-0000-0000-000000000758", }, "steps": { - "id": "00000000-0000-0000-0000-000000000724", + "id": "00000000-0000-0000-0000-000000000761", }, "timelineActivities": { - "id": "00000000-0000-0000-0000-000000000725", + "id": "00000000-0000-0000-0000-000000000762", }, "trigger": { - "id": "00000000-0000-0000-0000-000000000720", + "id": "00000000-0000-0000-0000-000000000757", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000716", + "id": "00000000-0000-0000-0000-000000000753", }, "updatedBy": { - "id": "00000000-0000-0000-0000-000000000728", + "id": "00000000-0000-0000-0000-000000000765", }, "workflow": { - "id": "00000000-0000-0000-0000-000000000719", + "id": "00000000-0000-0000-0000-000000000756", }, }, - "id": "00000000-0000-0000-0000-000000000748", + "id": "00000000-0000-0000-0000-000000000785", "views": { "allWorkflowVersions": { - "id": "00000000-0000-0000-0000-000000000734", + "id": "00000000-0000-0000-0000-000000000771", "viewFieldGroups": {}, "viewFields": { "name": { - "id": "00000000-0000-0000-0000-000000000729", + "id": "00000000-0000-0000-0000-000000000766", }, "runs": { - "id": "00000000-0000-0000-0000-000000000733", + "id": "00000000-0000-0000-0000-000000000770", }, "status": { - "id": "00000000-0000-0000-0000-000000000731", + "id": "00000000-0000-0000-0000-000000000768", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000732", + "id": "00000000-0000-0000-0000-000000000769", }, "workflow": { - "id": "00000000-0000-0000-0000-000000000730", + "id": "00000000-0000-0000-0000-000000000767", }, }, "viewGroups": {}, }, "workflowVersionRecordPageFields": { - "id": "00000000-0000-0000-0000-000000000747", + "id": "00000000-0000-0000-0000-000000000784", "viewFieldGroups": { "general": { - "id": "00000000-0000-0000-0000-000000000745", + "id": "00000000-0000-0000-0000-000000000782", }, "system": { - "id": "00000000-0000-0000-0000-000000000746", + "id": "00000000-0000-0000-0000-000000000783", }, }, "viewFields": { "createdAt": { - "id": "00000000-0000-0000-0000-000000000738", + "id": "00000000-0000-0000-0000-000000000775", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000740", + "id": "00000000-0000-0000-0000-000000000777", }, "runs": { - "id": "00000000-0000-0000-0000-000000000743", + "id": "00000000-0000-0000-0000-000000000780", }, "status": { - "id": "00000000-0000-0000-0000-000000000735", + "id": "00000000-0000-0000-0000-000000000772", }, "steps": { - "id": "00000000-0000-0000-0000-000000000739", + "id": "00000000-0000-0000-0000-000000000776", }, "timelineActivities": { - "id": "00000000-0000-0000-0000-000000000744", + "id": "00000000-0000-0000-0000-000000000781", }, "trigger": { - "id": "00000000-0000-0000-0000-000000000737", + "id": "00000000-0000-0000-0000-000000000774", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000741", + "id": "00000000-0000-0000-0000-000000000778", }, "updatedBy": { - "id": "00000000-0000-0000-0000-000000000742", + "id": "00000000-0000-0000-0000-000000000779", }, "workflow": { - "id": "00000000-0000-0000-0000-000000000736", + "id": "00000000-0000-0000-0000-000000000773", }, }, "viewGroups": {}, @@ -2518,122 +2642,122 @@ exports[`getStandardObjectMetadataRelatedEntityIds should return standard object "workspaceMember": { "fields": { "accountOwnerForCompanies": { - "id": "00000000-0000-0000-0000-000000000762", + "id": "00000000-0000-0000-0000-000000000799", }, "assignedTasks": { - "id": "00000000-0000-0000-0000-000000000760", + "id": "00000000-0000-0000-0000-000000000797", }, "avatarUrl": { - "id": "00000000-0000-0000-0000-000000000757", + "id": "00000000-0000-0000-0000-000000000794", }, "blocklist": { - "id": "00000000-0000-0000-0000-000000000764", + "id": "00000000-0000-0000-0000-000000000801", }, "calendarEventParticipants": { - "id": "00000000-0000-0000-0000-000000000765", + "id": "00000000-0000-0000-0000-000000000802", }, "calendarStartDay": { - "id": "00000000-0000-0000-0000-000000000771", + "id": "00000000-0000-0000-0000-000000000808", }, "colorScheme": { - "id": "00000000-0000-0000-0000-000000000755", + "id": "00000000-0000-0000-0000-000000000792", }, "createdAt": { - "id": "00000000-0000-0000-0000-000000000750", + "id": "00000000-0000-0000-0000-000000000787", }, "createdBy": { - "id": "00000000-0000-0000-0000-000000000773", + "id": "00000000-0000-0000-0000-000000000810", }, "dateFormat": { - "id": "00000000-0000-0000-0000-000000000768", + "id": "00000000-0000-0000-0000-000000000805", }, "deletedAt": { - "id": "00000000-0000-0000-0000-000000000752", + "id": "00000000-0000-0000-0000-000000000789", }, "id": { - "id": "00000000-0000-0000-0000-000000000749", + "id": "00000000-0000-0000-0000-000000000786", }, "locale": { - "id": "00000000-0000-0000-0000-000000000756", + "id": "00000000-0000-0000-0000-000000000793", }, "messageParticipants": { - "id": "00000000-0000-0000-0000-000000000763", + "id": "00000000-0000-0000-0000-000000000800", }, "name": { - "id": "00000000-0000-0000-0000-000000000754", + "id": "00000000-0000-0000-0000-000000000791", }, "numberFormat": { - "id": "00000000-0000-0000-0000-000000000772", + "id": "00000000-0000-0000-0000-000000000809", }, "ownedOpportunities": { - "id": "00000000-0000-0000-0000-000000000761", + "id": "00000000-0000-0000-0000-000000000798", }, "position": { - "id": "00000000-0000-0000-0000-000000000753", + "id": "00000000-0000-0000-0000-000000000790", }, "searchVector": { - "id": "00000000-0000-0000-0000-000000000770", + "id": "00000000-0000-0000-0000-000000000807", }, "timeFormat": { - "id": "00000000-0000-0000-0000-000000000769", + "id": "00000000-0000-0000-0000-000000000806", }, "timeZone": { - "id": "00000000-0000-0000-0000-000000000767", + "id": "00000000-0000-0000-0000-000000000804", }, "timelineActivities": { - "id": "00000000-0000-0000-0000-000000000766", + "id": "00000000-0000-0000-0000-000000000803", }, "updatedAt": { - "id": "00000000-0000-0000-0000-000000000751", + "id": "00000000-0000-0000-0000-000000000788", }, "updatedBy": { - "id": "00000000-0000-0000-0000-000000000774", + "id": "00000000-0000-0000-0000-000000000811", }, "userEmail": { - "id": "00000000-0000-0000-0000-000000000758", + "id": "00000000-0000-0000-0000-000000000795", }, "userId": { - "id": "00000000-0000-0000-0000-000000000759", + "id": "00000000-0000-0000-0000-000000000796", }, }, - "id": "00000000-0000-0000-0000-000000000787", + "id": "00000000-0000-0000-0000-000000000824", "views": { "allWorkspaceMembers": { - "id": "00000000-0000-0000-0000-000000000786", + "id": "00000000-0000-0000-0000-000000000823", "viewFieldGroups": {}, "viewFields": { "assignedTasks": { - "id": "00000000-0000-0000-0000-000000000785", + "id": "00000000-0000-0000-0000-000000000822", }, "avatarUrl": { - "id": "00000000-0000-0000-0000-000000000777", + "id": "00000000-0000-0000-0000-000000000814", }, "colorScheme": { - "id": "00000000-0000-0000-0000-000000000778", + "id": "00000000-0000-0000-0000-000000000815", }, "createdAt": { - "id": "00000000-0000-0000-0000-000000000783", + "id": "00000000-0000-0000-0000-000000000820", }, "dateFormat": { - "id": "00000000-0000-0000-0000-000000000781", + "id": "00000000-0000-0000-0000-000000000818", }, "locale": { - "id": "00000000-0000-0000-0000-000000000779", + "id": "00000000-0000-0000-0000-000000000816", }, "name": { - "id": "00000000-0000-0000-0000-000000000775", + "id": "00000000-0000-0000-0000-000000000812", }, "ownedOpportunities": { - "id": "00000000-0000-0000-0000-000000000784", + "id": "00000000-0000-0000-0000-000000000821", }, "timeFormat": { - "id": "00000000-0000-0000-0000-000000000782", + "id": "00000000-0000-0000-0000-000000000819", }, "timeZone": { - "id": "00000000-0000-0000-0000-000000000780", + "id": "00000000-0000-0000-0000-000000000817", }, "userEmail": { - "id": "00000000-0000-0000-0000-000000000776", + "id": "00000000-0000-0000-0000-000000000813", }, }, "viewGroups": {}, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/__tests__/__snapshots__/get-standard-page-layout-metadata-related-entity-ids.util.spec.ts.snap b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/__tests__/__snapshots__/get-standard-page-layout-metadata-related-entity-ids.util.spec.ts.snap index f39aa81370..30db7ef3e7 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/__tests__/__snapshots__/get-standard-page-layout-metadata-related-entity-ids.util.spec.ts.snap +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/__tests__/__snapshots__/get-standard-page-layout-metadata-related-entity-ids.util.spec.ts.snap @@ -65,116 +65,95 @@ exports[`getStandardPageLayoutMetadataRelatedEntityIds should return standard pa }, }, }, - "companyRecordPage": { + "callRecordingRecordPage": { "id": "00000000-0000-0000-0000-000000000026", "tabs": { - "calendar": { - "id": "00000000-0000-0000-0000-000000000041", - "widgets": { - "calendar": { - "id": "00000000-0000-0000-0000-000000000042", - }, - }, - }, - "emails": { - "id": "00000000-0000-0000-0000-000000000039", - "widgets": { - "emails": { - "id": "00000000-0000-0000-0000-000000000040", - }, - }, - }, - "files": { - "id": "00000000-0000-0000-0000-000000000037", - "widgets": { - "files": { - "id": "00000000-0000-0000-0000-000000000038", - }, - }, - }, "home": { "id": "00000000-0000-0000-0000-000000000027", "widgets": { "fields": { "id": "00000000-0000-0000-0000-000000000028", }, - "opportunities": { + }, + }, + "timeline": { + "id": "00000000-0000-0000-0000-000000000029", + "widgets": { + "timeline": { "id": "00000000-0000-0000-0000-000000000030", }, + }, + }, + }, + }, + "companyRecordPage": { + "id": "00000000-0000-0000-0000-000000000031", + "tabs": { + "calendar": { + "id": "00000000-0000-0000-0000-000000000046", + "widgets": { + "calendar": { + "id": "00000000-0000-0000-0000-000000000047", + }, + }, + }, + "emails": { + "id": "00000000-0000-0000-0000-000000000044", + "widgets": { + "emails": { + "id": "00000000-0000-0000-0000-000000000045", + }, + }, + }, + "files": { + "id": "00000000-0000-0000-0000-000000000042", + "widgets": { + "files": { + "id": "00000000-0000-0000-0000-000000000043", + }, + }, + }, + "home": { + "id": "00000000-0000-0000-0000-000000000032", + "widgets": { + "fields": { + "id": "00000000-0000-0000-0000-000000000033", + }, + "opportunities": { + "id": "00000000-0000-0000-0000-000000000035", + }, "people": { - "id": "00000000-0000-0000-0000-000000000029", - }, - }, - }, - "notes": { - "id": "00000000-0000-0000-0000-000000000035", - "widgets": { - "notes": { - "id": "00000000-0000-0000-0000-000000000036", - }, - }, - }, - "tasks": { - "id": "00000000-0000-0000-0000-000000000033", - "widgets": { - "tasks": { "id": "00000000-0000-0000-0000-000000000034", }, }, }, + "notes": { + "id": "00000000-0000-0000-0000-000000000040", + "widgets": { + "notes": { + "id": "00000000-0000-0000-0000-000000000041", + }, + }, + }, + "tasks": { + "id": "00000000-0000-0000-0000-000000000038", + "widgets": { + "tasks": { + "id": "00000000-0000-0000-0000-000000000039", + }, + }, + }, "timeline": { - "id": "00000000-0000-0000-0000-000000000031", + "id": "00000000-0000-0000-0000-000000000036", "widgets": { "timeline": { - "id": "00000000-0000-0000-0000-000000000032", + "id": "00000000-0000-0000-0000-000000000037", }, }, }, }, }, "messageChannelMessageAssociationMessageFolderRecordPage": { - "id": "00000000-0000-0000-0000-000000000048", - "tabs": { - "home": { - "id": "00000000-0000-0000-0000-000000000049", - "widgets": { - "fields": { - "id": "00000000-0000-0000-0000-000000000050", - }, - }, - }, - "timeline": { - "id": "00000000-0000-0000-0000-000000000051", - "widgets": { - "timeline": { - "id": "00000000-0000-0000-0000-000000000052", - }, - }, - }, - }, - }, - "messageChannelMessageAssociationRecordPage": { - "id": "00000000-0000-0000-0000-000000000043", - "tabs": { - "home": { - "id": "00000000-0000-0000-0000-000000000044", - "widgets": { - "fields": { - "id": "00000000-0000-0000-0000-000000000045", - }, - }, - }, - "timeline": { - "id": "00000000-0000-0000-0000-000000000046", - "widgets": { - "timeline": { - "id": "00000000-0000-0000-0000-000000000047", - }, - }, - }, - }, - }, - "messageParticipantRecordPage": { "id": "00000000-0000-0000-0000-000000000053", "tabs": { "home": { @@ -195,17 +174,59 @@ exports[`getStandardPageLayoutMetadataRelatedEntityIds should return standard pa }, }, }, - "messageThreadRecordPage": { + "messageChannelMessageAssociationRecordPage": { + "id": "00000000-0000-0000-0000-000000000048", + "tabs": { + "home": { + "id": "00000000-0000-0000-0000-000000000049", + "widgets": { + "fields": { + "id": "00000000-0000-0000-0000-000000000050", + }, + }, + }, + "timeline": { + "id": "00000000-0000-0000-0000-000000000051", + "widgets": { + "timeline": { + "id": "00000000-0000-0000-0000-000000000052", + }, + }, + }, + }, + }, + "messageParticipantRecordPage": { "id": "00000000-0000-0000-0000-000000000058", "tabs": { "home": { "id": "00000000-0000-0000-0000-000000000059", "widgets": { - "emailThread": { + "fields": { "id": "00000000-0000-0000-0000-000000000060", }, }, }, + "timeline": { + "id": "00000000-0000-0000-0000-000000000061", + "widgets": { + "timeline": { + "id": "00000000-0000-0000-0000-000000000062", + }, + }, + }, + }, + }, + "messageThreadRecordPage": { + "id": "00000000-0000-0000-0000-000000000063", + "tabs": { + "home": { + "id": "00000000-0000-0000-0000-000000000064", + "widgets": { + "emailThread": { + "id": "00000000-0000-0000-0000-000000000065", + }, + }, + }, }, }, "myFirstDashboard": { @@ -243,299 +264,299 @@ exports[`getStandardPageLayoutMetadataRelatedEntityIds should return standard pa }, }, "noteRecordPage": { - "id": "00000000-0000-0000-0000-000000000061", + "id": "00000000-0000-0000-0000-000000000066", "tabs": { "files": { - "id": "00000000-0000-0000-0000-000000000069", + "id": "00000000-0000-0000-0000-000000000074", "widgets": { "files": { - "id": "00000000-0000-0000-0000-000000000070", + "id": "00000000-0000-0000-0000-000000000075", }, }, }, "home": { - "id": "00000000-0000-0000-0000-000000000062", + "id": "00000000-0000-0000-0000-000000000067", "widgets": { "fields": { - "id": "00000000-0000-0000-0000-000000000063", + "id": "00000000-0000-0000-0000-000000000068", }, "noteRichText": { - "id": "00000000-0000-0000-0000-000000000064", + "id": "00000000-0000-0000-0000-000000000069", }, }, }, "note": { - "id": "00000000-0000-0000-0000-000000000065", + "id": "00000000-0000-0000-0000-000000000070", "widgets": { "noteRichText": { - "id": "00000000-0000-0000-0000-000000000066", + "id": "00000000-0000-0000-0000-000000000071", }, }, }, "timeline": { - "id": "00000000-0000-0000-0000-000000000067", + "id": "00000000-0000-0000-0000-000000000072", "widgets": { "timeline": { - "id": "00000000-0000-0000-0000-000000000068", + "id": "00000000-0000-0000-0000-000000000073", }, }, }, }, }, "opportunityRecordPage": { - "id": "00000000-0000-0000-0000-000000000071", + "id": "00000000-0000-0000-0000-000000000076", "tabs": { "calendar": { - "id": "00000000-0000-0000-0000-000000000087", + "id": "00000000-0000-0000-0000-000000000092", "widgets": { "calendar": { - "id": "00000000-0000-0000-0000-000000000088", + "id": "00000000-0000-0000-0000-000000000093", }, }, }, "emails": { - "id": "00000000-0000-0000-0000-000000000085", + "id": "00000000-0000-0000-0000-000000000090", "widgets": { "emails": { - "id": "00000000-0000-0000-0000-000000000086", + "id": "00000000-0000-0000-0000-000000000091", }, }, }, "files": { - "id": "00000000-0000-0000-0000-000000000083", + "id": "00000000-0000-0000-0000-000000000088", "widgets": { "files": { - "id": "00000000-0000-0000-0000-000000000084", + "id": "00000000-0000-0000-0000-000000000089", }, }, }, "home": { - "id": "00000000-0000-0000-0000-000000000072", + "id": "00000000-0000-0000-0000-000000000077", "widgets": { "company": { - "id": "00000000-0000-0000-0000-000000000075", + "id": "00000000-0000-0000-0000-000000000080", }, "fields": { - "id": "00000000-0000-0000-0000-000000000073", + "id": "00000000-0000-0000-0000-000000000078", }, "owner": { - "id": "00000000-0000-0000-0000-000000000076", + "id": "00000000-0000-0000-0000-000000000081", }, "pointOfContact": { - "id": "00000000-0000-0000-0000-000000000074", + "id": "00000000-0000-0000-0000-000000000079", }, }, }, "notes": { - "id": "00000000-0000-0000-0000-000000000081", + "id": "00000000-0000-0000-0000-000000000086", "widgets": { "notes": { - "id": "00000000-0000-0000-0000-000000000082", + "id": "00000000-0000-0000-0000-000000000087", }, }, }, "tasks": { - "id": "00000000-0000-0000-0000-000000000079", + "id": "00000000-0000-0000-0000-000000000084", "widgets": { "tasks": { - "id": "00000000-0000-0000-0000-000000000080", + "id": "00000000-0000-0000-0000-000000000085", }, }, }, "timeline": { - "id": "00000000-0000-0000-0000-000000000077", + "id": "00000000-0000-0000-0000-000000000082", "widgets": { "timeline": { - "id": "00000000-0000-0000-0000-000000000078", + "id": "00000000-0000-0000-0000-000000000083", }, }, }, }, }, "personRecordPage": { - "id": "00000000-0000-0000-0000-000000000089", + "id": "00000000-0000-0000-0000-000000000094", "tabs": { "calendar": { - "id": "00000000-0000-0000-0000-000000000104", + "id": "00000000-0000-0000-0000-000000000109", "widgets": { "calendar": { - "id": "00000000-0000-0000-0000-000000000105", + "id": "00000000-0000-0000-0000-000000000110", }, }, }, "emails": { - "id": "00000000-0000-0000-0000-000000000102", + "id": "00000000-0000-0000-0000-000000000107", "widgets": { "emails": { - "id": "00000000-0000-0000-0000-000000000103", + "id": "00000000-0000-0000-0000-000000000108", }, }, }, "files": { - "id": "00000000-0000-0000-0000-000000000100", + "id": "00000000-0000-0000-0000-000000000105", "widgets": { "files": { - "id": "00000000-0000-0000-0000-000000000101", + "id": "00000000-0000-0000-0000-000000000106", }, }, }, "home": { - "id": "00000000-0000-0000-0000-000000000090", + "id": "00000000-0000-0000-0000-000000000095", "widgets": { "company": { - "id": "00000000-0000-0000-0000-000000000092", + "id": "00000000-0000-0000-0000-000000000097", }, "fields": { - "id": "00000000-0000-0000-0000-000000000091", + "id": "00000000-0000-0000-0000-000000000096", }, "pointOfContactForOpportunities": { - "id": "00000000-0000-0000-0000-000000000093", + "id": "00000000-0000-0000-0000-000000000098", }, }, }, "notes": { - "id": "00000000-0000-0000-0000-000000000098", + "id": "00000000-0000-0000-0000-000000000103", "widgets": { "notes": { - "id": "00000000-0000-0000-0000-000000000099", + "id": "00000000-0000-0000-0000-000000000104", }, }, }, "tasks": { - "id": "00000000-0000-0000-0000-000000000096", + "id": "00000000-0000-0000-0000-000000000101", "widgets": { "tasks": { - "id": "00000000-0000-0000-0000-000000000097", + "id": "00000000-0000-0000-0000-000000000102", }, }, }, "timeline": { - "id": "00000000-0000-0000-0000-000000000094", + "id": "00000000-0000-0000-0000-000000000099", "widgets": { "timeline": { - "id": "00000000-0000-0000-0000-000000000095", + "id": "00000000-0000-0000-0000-000000000100", }, }, }, }, }, "taskRecordPage": { - "id": "00000000-0000-0000-0000-000000000106", + "id": "00000000-0000-0000-0000-000000000111", "tabs": { "files": { - "id": "00000000-0000-0000-0000-000000000114", + "id": "00000000-0000-0000-0000-000000000119", "widgets": { "files": { - "id": "00000000-0000-0000-0000-000000000115", + "id": "00000000-0000-0000-0000-000000000120", }, }, }, "home": { - "id": "00000000-0000-0000-0000-000000000107", + "id": "00000000-0000-0000-0000-000000000112", "widgets": { "fields": { - "id": "00000000-0000-0000-0000-000000000108", + "id": "00000000-0000-0000-0000-000000000113", }, "taskRichText": { - "id": "00000000-0000-0000-0000-000000000109", + "id": "00000000-0000-0000-0000-000000000114", }, }, }, "note": { - "id": "00000000-0000-0000-0000-000000000110", + "id": "00000000-0000-0000-0000-000000000115", "widgets": { "taskRichText": { - "id": "00000000-0000-0000-0000-000000000111", + "id": "00000000-0000-0000-0000-000000000116", }, }, }, "timeline": { - "id": "00000000-0000-0000-0000-000000000112", - "widgets": { - "timeline": { - "id": "00000000-0000-0000-0000-000000000113", - }, - }, - }, - }, - }, - "workflowAutomatedTriggerRecordPage": { - "id": "00000000-0000-0000-0000-000000000119", - "tabs": { - "home": { - "id": "00000000-0000-0000-0000-000000000120", - "widgets": { - "fields": { - "id": "00000000-0000-0000-0000-000000000121", - }, - }, - }, - "timeline": { - "id": "00000000-0000-0000-0000-000000000122", - "widgets": { - "timeline": { - "id": "00000000-0000-0000-0000-000000000123", - }, - }, - }, - }, - }, - "workflowRecordPage": { - "id": "00000000-0000-0000-0000-000000000116", - "tabs": { - "flow": { "id": "00000000-0000-0000-0000-000000000117", "widgets": { - "workflow": { + "timeline": { "id": "00000000-0000-0000-0000-000000000118", }, }, }, }, }, - "workflowRunRecordPage": { - "id": "00000000-0000-0000-0000-000000000130", - "tabs": { - "flow": { - "id": "00000000-0000-0000-0000-000000000134", - "widgets": { - "workflowRun": { - "id": "00000000-0000-0000-0000-000000000135", - }, - }, - }, - "home": { - "id": "00000000-0000-0000-0000-000000000131", - "widgets": { - "fields": { - "id": "00000000-0000-0000-0000-000000000132", - }, - "workflow": { - "id": "00000000-0000-0000-0000-000000000133", - }, - }, - }, - }, - }, - "workflowVersionRecordPage": { + "workflowAutomatedTriggerRecordPage": { "id": "00000000-0000-0000-0000-000000000124", "tabs": { - "flow": { - "id": "00000000-0000-0000-0000-000000000128", - "widgets": { - "workflowVersion": { - "id": "00000000-0000-0000-0000-000000000129", - }, - }, - }, "home": { "id": "00000000-0000-0000-0000-000000000125", "widgets": { "fields": { "id": "00000000-0000-0000-0000-000000000126", }, + }, + }, + "timeline": { + "id": "00000000-0000-0000-0000-000000000127", + "widgets": { + "timeline": { + "id": "00000000-0000-0000-0000-000000000128", + }, + }, + }, + }, + }, + "workflowRecordPage": { + "id": "00000000-0000-0000-0000-000000000121", + "tabs": { + "flow": { + "id": "00000000-0000-0000-0000-000000000122", + "widgets": { "workflow": { - "id": "00000000-0000-0000-0000-000000000127", + "id": "00000000-0000-0000-0000-000000000123", + }, + }, + }, + }, + }, + "workflowRunRecordPage": { + "id": "00000000-0000-0000-0000-000000000135", + "tabs": { + "flow": { + "id": "00000000-0000-0000-0000-000000000139", + "widgets": { + "workflowRun": { + "id": "00000000-0000-0000-0000-000000000140", + }, + }, + }, + "home": { + "id": "00000000-0000-0000-0000-000000000136", + "widgets": { + "fields": { + "id": "00000000-0000-0000-0000-000000000137", + }, + "workflow": { + "id": "00000000-0000-0000-0000-000000000138", + }, + }, + }, + }, + }, + "workflowVersionRecordPage": { + "id": "00000000-0000-0000-0000-000000000129", + "tabs": { + "flow": { + "id": "00000000-0000-0000-0000-000000000133", + "widgets": { + "workflowVersion": { + "id": "00000000-0000-0000-0000-000000000134", + }, + }, + }, + "home": { + "id": "00000000-0000-0000-0000-000000000130", + "widgets": { + "fields": { + "id": "00000000-0000-0000-0000-000000000131", + }, + "workflow": { + "id": "00000000-0000-0000-0000-000000000132", }, }, }, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/__tests__/compute-call-recording-standard-metadata.spec.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/__tests__/compute-call-recording-standard-metadata.spec.ts new file mode 100644 index 0000000000..ad4b4ce4f9 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/__tests__/compute-call-recording-standard-metadata.spec.ts @@ -0,0 +1,139 @@ +import { + STANDARD_OBJECTS, + STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS, +} from 'twenty-shared/metadata'; +import { isDefined } from 'twenty-shared/utils'; + +import { WidgetConfigurationType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-configuration-type.type'; +import { computeTwentyStandardApplicationAllFlatEntityMaps } from 'src/engine/workspace-manager/twenty-standard-application/utils/twenty-standard-application-all-flat-entity-maps.constant'; + +const WORKSPACE_ID = '20202020-1111-4111-8111-111111111111'; +const TWENTY_STANDARD_APPLICATION_ID = '20202020-2222-4222-8222-222222222222'; +const NOW = '2024-01-01T00:00:00.000Z'; + +describe('CallRecording standard metadata build', () => { + const { allFlatEntityMaps } = + computeTwentyStandardApplicationAllFlatEntityMaps({ + now: NOW, + workspaceId: WORKSPACE_ID, + twentyStandardApplicationId: TWENTY_STANDARD_APPLICATION_ID, + }); + + it('builds the callRecording object', () => { + const { byUniversalIdentifier } = allFlatEntityMaps.flatObjectMetadataMaps; + + expect( + byUniversalIdentifier[STANDARD_OBJECTS.callRecording.universalIdentifier], + ).toBeDefined(); + }); + + it('marks the callRecording object as system', () => { + const callRecording = + allFlatEntityMaps.flatObjectMetadataMaps.byUniversalIdentifier[ + STANDARD_OBJECTS.callRecording.universalIdentifier + ]; + + expect(callRecording?.isSystem).toBe(true); + }); + + it('links callRecording to a calendarEvent through a direct relation', () => { + const calendarEventField = + allFlatEntityMaps.flatFieldMetadataMaps.byUniversalIdentifier[ + STANDARD_OBJECTS.callRecording.fields.calendarEvent.universalIdentifier + ]; + + expect(calendarEventField).toBeDefined(); + }); + + it('indexes the calendarEvent foreign key', () => { + const calendarEventIdIndex = + allFlatEntityMaps.flatIndexMaps.byUniversalIdentifier[ + STANDARD_OBJECTS.callRecording.indexes.calendarEventIdIndex + .universalIdentifier + ]; + + expect(calendarEventIdIndex).toBeDefined(); + }); + + it('stores the per-event recording preference on calendarEvent', () => { + const recordingPreferenceField = + allFlatEntityMaps.flatFieldMetadataMaps.byUniversalIdentifier[ + STANDARD_OBJECTS.calendarEvent.fields.recordingPreference + .universalIdentifier + ]; + + expect(recordingPreferenceField).toBeDefined(); + }); + + it('keeps the callRecording table view focused on its label identifier and status', () => { + const viewFieldFieldUniversalIdentifiers = Object.values( + allFlatEntityMaps.flatViewFieldMaps.byUniversalIdentifier, + ) + .filter(isDefined) + .filter( + (viewField) => + viewField.viewUniversalIdentifier === + STANDARD_OBJECTS.callRecording.views.allCallRecordings + .universalIdentifier, + ) + .map((viewField) => viewField.fieldMetadataUniversalIdentifier); + + expect(viewFieldFieldUniversalIdentifiers).toHaveLength(3); + expect(viewFieldFieldUniversalIdentifiers).toEqual( + expect.arrayContaining([ + STANDARD_OBJECTS.callRecording.fields.title.universalIdentifier, + STANDARD_OBJECTS.callRecording.fields.status.universalIdentifier, + STANDARD_OBJECTS.callRecording.fields.startedAt.universalIdentifier, + ]), + ); + }); + + it('uses the important callRecording detail fields on the record page', () => { + const viewFieldFieldUniversalIdentifiers = Object.values( + allFlatEntityMaps.flatViewFieldMaps.byUniversalIdentifier, + ) + .filter(isDefined) + .filter( + (viewField) => + viewField.viewUniversalIdentifier === + STANDARD_OBJECTS.callRecording.views.callRecordingRecordPageFields + .universalIdentifier, + ) + .map((viewField) => viewField.fieldMetadataUniversalIdentifier); + + expect(viewFieldFieldUniversalIdentifiers).toHaveLength(8); + expect(viewFieldFieldUniversalIdentifiers).toEqual( + expect.arrayContaining([ + STANDARD_OBJECTS.callRecording.fields.title.universalIdentifier, + STANDARD_OBJECTS.callRecording.fields.status.universalIdentifier, + STANDARD_OBJECTS.callRecording.fields.startedAt.universalIdentifier, + STANDARD_OBJECTS.callRecording.fields.endedAt.universalIdentifier, + STANDARD_OBJECTS.callRecording.fields.video.universalIdentifier, + STANDARD_OBJECTS.callRecording.fields.audio.universalIdentifier, + STANDARD_OBJECTS.callRecording.fields.transcript.universalIdentifier, + STANDARD_OBJECTS.callRecording.fields.summary.universalIdentifier, + ]), + ); + expect(viewFieldFieldUniversalIdentifiers).not.toContain( + STANDARD_OBJECTS.callRecording.fields.createdAt.universalIdentifier, + ); + expect(viewFieldFieldUniversalIdentifiers).not.toContain( + STANDARD_OBJECTS.callRecording.fields.createdBy.universalIdentifier, + ); + }); + + it('links the callRecording fields widget to its record-page fields view', () => { + const fieldsWidget = + allFlatEntityMaps.flatPageLayoutWidgetMaps.byUniversalIdentifier[ + STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.callRecordingRecordPage.tabs + .home.widgets.fields.universalIdentifier + ]; + + expect(fieldsWidget?.universalConfiguration).toMatchObject({ + configurationType: WidgetConfigurationType.FIELDS, + viewUniversalIdentifier: + STANDARD_OBJECTS.callRecording.views.callRecordingRecordPageFields + .universalIdentifier, + }); + }); +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/build-standard-flat-field-metadata-maps.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/build-standard-flat-field-metadata-maps.util.ts index 5e1f21ad29..cdc1558546 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/build-standard-flat-field-metadata-maps.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/build-standard-flat-field-metadata-maps.util.ts @@ -10,6 +10,7 @@ import { buildBlocklistStandardFlatFieldMetadatas } from 'src/engine/workspace-m import { buildCalendarChannelEventAssociationStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-calendar-channel-event-association-standard-flat-field-metadata.util'; import { buildCalendarEventParticipantStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-calendar-event-participant-standard-flat-field-metadata.util'; import { buildCalendarEventStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-calendar-event-standard-flat-field-metadata.util'; +import { buildCallRecordingStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-call-recording-standard-flat-field-metadata.util'; import { buildCompanyStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-company-standard-flat-field-metadata.util'; import { buildDashboardStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-dashboard-standard-flat-field-metadata.util'; import { buildMessageChannelMessageAssociationMessageFolderStandardFlatFieldMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-message-channel-message-association-message-folder-standard-flat-field-metadata.util'; @@ -43,6 +44,7 @@ const STANDARD_FLAT_FIELD_METADATA_BUILDERS_BY_OBJECT_NAME = { calendarEventParticipant: buildCalendarEventParticipantStandardFlatFieldMetadatas, calendarEvent: buildCalendarEventStandardFlatFieldMetadatas, + callRecording: buildCallRecordingStandardFlatFieldMetadatas, company: buildCompanyStandardFlatFieldMetadatas, dashboard: buildDashboardStandardFlatFieldMetadatas, message: buildMessageStandardFlatFieldMetadatas, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-calendar-event-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-calendar-event-standard-flat-field-metadata.util.ts index 734b6a0d15..8eda728f48 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-calendar-event-standard-flat-field-metadata.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-calendar-event-standard-flat-field-metadata.util.ts @@ -401,6 +401,48 @@ export const buildCalendarEventStandardFlatFieldMetadatas = ({ twentyStandardApplicationId, now, }), + recordingPreference: createStandardFieldFlatMetadata({ + objectName, + workspaceId, + context: { + fieldName: 'recordingPreference', + type: FieldMetadataType.SELECT, + label: i18nLabel(msg`Recording Preference`), + description: i18nLabel( + msg`Whether to record this event, applied on top of the workspace policy`, + ), + icon: 'IconSettingsAutomation', + isNullable: false, + defaultValue: "'AUTO'", + options: [ + { + id: '4c4761ce-ffbf-4176-be7f-5cf5257c8bff', + value: 'AUTO', + label: i18nLabel(msg`Auto`), + position: 0, + color: 'blue', + }, + { + id: '1ae19135-e1a1-4a96-b866-91643622e554', + value: 'ON', + label: i18nLabel(msg`On`), + position: 1, + color: 'green', + }, + { + id: '8c69a74f-2ab7-4c19-a813-eb0ea3533fd3', + value: 'OFF', + label: i18nLabel(msg`Off`), + position: 2, + color: 'gray', + }, + ], + }, + standardObjectMetadataRelatedEntityIds, + dependencyFlatEntityMaps, + twentyStandardApplicationId, + now, + }), calendarChannelEventAssociations: createStandardRelationFieldFlatMetadata({ objectName, workspaceId, @@ -447,4 +489,27 @@ export const buildCalendarEventStandardFlatFieldMetadatas = ({ twentyStandardApplicationId, now, }), + callRecordings: createStandardRelationFieldFlatMetadata({ + objectName, + workspaceId, + context: { + type: FieldMetadataType.RELATION, + morphId: null, + fieldName: 'callRecordings', + label: i18nLabel(msg`Call Recordings`), + description: i18nLabel(msg`Call Recordings`), + icon: 'IconPhone', + isNullable: false, + isUIReadOnly: true, + targetObjectName: 'callRecording', + targetFieldName: 'calendarEvent', + settings: { + relationType: RelationType.ONE_TO_MANY, + }, + }, + standardObjectMetadataRelatedEntityIds, + dependencyFlatEntityMaps, + twentyStandardApplicationId, + now, + }), }); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-call-recording-standard-flat-field-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-call-recording-standard-flat-field-metadata.util.ts new file mode 100644 index 0000000000..8dc6ad57da --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/compute-call-recording-standard-flat-field-metadata.util.ts @@ -0,0 +1,464 @@ +import { msg } from '@lingui/core/macro'; +import { i18nLabel } from 'src/engine/workspace-manager/twenty-standard-application/utils/i18n-label.util'; +import { + DateDisplayFormat, + 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 { + type CreateStandardFieldArgs, + createStandardFieldFlatMetadata, +} from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/create-standard-field-flat-metadata.util'; +import { createStandardRelationFieldFlatMetadata } from 'src/engine/workspace-manager/twenty-standard-application/utils/field-metadata/create-standard-relation-field-flat-metadata.util'; +import { getTsVectorColumnExpressionFromFields } from 'src/engine/workspace-manager/utils/get-ts-vector-column-expression.util'; + +export const buildCallRecordingStandardFlatFieldMetadatas = ({ + now, + objectName, + workspaceId, + standardObjectMetadataRelatedEntityIds, + dependencyFlatEntityMaps, + twentyStandardApplicationId, +}: Omit< + CreateStandardFieldArgs<'callRecording', FieldMetadataType>, + 'context' +>): Record, FlatFieldMetadata> => ({ + id: createStandardFieldFlatMetadata({ + objectName, + workspaceId, + context: { + fieldName: 'id', + type: FieldMetadataType.UUID, + label: i18nLabel(msg`Id`), + description: i18nLabel(msg`Id`), + icon: 'Icon123', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'uuid', + }, + standardObjectMetadataRelatedEntityIds, + dependencyFlatEntityMaps, + twentyStandardApplicationId, + now, + }), + createdAt: createStandardFieldFlatMetadata({ + objectName, + workspaceId, + context: { + fieldName: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: i18nLabel(msg`Creation date`), + description: i18nLabel(msg`Creation date`), + icon: 'IconCalendar', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: DateDisplayFormat.RELATIVE }, + }, + standardObjectMetadataRelatedEntityIds, + dependencyFlatEntityMaps, + twentyStandardApplicationId, + now, + }), + updatedAt: createStandardFieldFlatMetadata({ + objectName, + workspaceId, + context: { + fieldName: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: i18nLabel(msg`Last update`), + description: i18nLabel(msg`Last time the record was changed`), + icon: 'IconCalendarClock', + isSystem: true, + isNullable: false, + isUIReadOnly: true, + defaultValue: 'now', + settings: { displayFormat: DateDisplayFormat.RELATIVE }, + }, + standardObjectMetadataRelatedEntityIds, + dependencyFlatEntityMaps, + twentyStandardApplicationId, + now, + }), + deletedAt: createStandardFieldFlatMetadata({ + objectName, + workspaceId, + context: { + fieldName: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: i18nLabel(msg`Deleted at`), + description: i18nLabel(msg`Date when the record was deleted`), + icon: 'IconCalendarMinus', + isSystem: true, + isNullable: true, + isUIReadOnly: true, + settings: { displayFormat: DateDisplayFormat.RELATIVE }, + }, + standardObjectMetadataRelatedEntityIds, + dependencyFlatEntityMaps, + twentyStandardApplicationId, + now, + }), + title: createStandardFieldFlatMetadata({ + objectName, + workspaceId, + context: { + fieldName: 'title', + type: FieldMetadataType.TEXT, + label: i18nLabel(msg`Title`), + description: i18nLabel(msg`Meeting title from the calendar event`), + icon: 'IconNotes', + isNullable: true, + isUIReadOnly: true, + }, + standardObjectMetadataRelatedEntityIds, + dependencyFlatEntityMaps, + twentyStandardApplicationId, + now, + }), + status: createStandardFieldFlatMetadata({ + objectName, + workspaceId, + context: { + fieldName: 'status', + type: FieldMetadataType.SELECT, + label: i18nLabel(msg`Status`), + description: i18nLabel(msg`Recording lifecycle status`), + icon: 'IconProgress', + isNullable: false, + isUIReadOnly: true, + defaultValue: "'SCHEDULED'", + options: [ + { + id: '7fa515ba-e3cb-48f7-914f-e1f664d5d920', + value: 'SCHEDULED', + label: i18nLabel(msg`Scheduled`), + position: 0, + color: 'sky', + }, + { + id: '96844ba3-364b-4975-8abc-886cca92ec99', + value: 'JOINING', + label: i18nLabel(msg`Joining`), + position: 1, + color: 'blue', + }, + { + id: 'eccdad8b-8424-48ba-ad7f-f38517fa83fc', + value: 'RECORDING', + label: i18nLabel(msg`Recording`), + position: 2, + color: 'red', + }, + { + id: 'c8222203-5b44-4ac6-8142-0a7eb2074d7b', + value: 'PROCESSING', + label: i18nLabel(msg`Processing`), + position: 3, + color: 'orange', + }, + { + id: 'd17faf71-af3c-4260-9021-2ffaaa5648c4', + value: 'COMPLETED', + label: i18nLabel(msg`Completed`), + position: 4, + color: 'green', + }, + { + id: '4800777e-54a8-4464-9c01-07d6eefd04da', + value: 'FAILED_UNKNOWN', + label: i18nLabel(msg`Failed`), + position: 5, + color: 'gray', + }, + ], + }, + standardObjectMetadataRelatedEntityIds, + dependencyFlatEntityMaps, + twentyStandardApplicationId, + now, + }), + applicationId: createStandardFieldFlatMetadata({ + objectName, + workspaceId, + context: { + fieldName: 'applicationId', + type: FieldMetadataType.UUID, + label: i18nLabel(msg`Application ID`), + description: i18nLabel( + msg`Installed source app that manages or ingested this recording`, + ), + icon: 'IconApps', + isNullable: true, + isUIReadOnly: true, + }, + standardObjectMetadataRelatedEntityIds, + dependencyFlatEntityMaps, + twentyStandardApplicationId, + now, + }), + externalBotId: createStandardFieldFlatMetadata({ + objectName, + workspaceId, + context: { + fieldName: 'externalBotId', + type: FieldMetadataType.TEXT, + label: i18nLabel(msg`External Bot ID`), + description: i18nLabel( + msg`Source app bot/session id, when the source supports bots`, + ), + icon: 'IconRobot', + isNullable: true, + isUIReadOnly: true, + }, + standardObjectMetadataRelatedEntityIds, + dependencyFlatEntityMaps, + twentyStandardApplicationId, + now, + }), + externalRecordingId: createStandardFieldFlatMetadata({ + objectName, + workspaceId, + context: { + fieldName: 'externalRecordingId', + type: FieldMetadataType.TEXT, + label: i18nLabel(msg`External Recording ID`), + description: i18nLabel(msg`Source app recording id, when present`), + icon: 'IconId', + isNullable: true, + isUIReadOnly: true, + }, + standardObjectMetadataRelatedEntityIds, + dependencyFlatEntityMaps, + twentyStandardApplicationId, + now, + }), + startedAt: createStandardFieldFlatMetadata({ + objectName, + workspaceId, + context: { + fieldName: 'startedAt', + type: FieldMetadataType.DATE_TIME, + label: i18nLabel(msg`Started At`), + description: i18nLabel(msg`Actual recording start`), + icon: 'IconCalendarClock', + isNullable: true, + isUIReadOnly: true, + }, + standardObjectMetadataRelatedEntityIds, + dependencyFlatEntityMaps, + twentyStandardApplicationId, + now, + }), + endedAt: createStandardFieldFlatMetadata({ + objectName, + workspaceId, + context: { + fieldName: 'endedAt', + type: FieldMetadataType.DATE_TIME, + label: i18nLabel(msg`Ended At`), + description: i18nLabel(msg`Actual recording end`), + icon: 'IconCalendarClock', + isNullable: true, + isUIReadOnly: true, + }, + standardObjectMetadataRelatedEntityIds, + dependencyFlatEntityMaps, + twentyStandardApplicationId, + now, + }), + video: createStandardFieldFlatMetadata({ + objectName, + workspaceId, + context: { + fieldName: 'video', + type: FieldMetadataType.FILES, + label: i18nLabel(msg`Video`), + description: i18nLabel(msg`Video recording`), + icon: 'IconVideo', + isNullable: true, + isUIReadOnly: true, + settings: { + maxNumberOfValues: 1, + }, + }, + standardObjectMetadataRelatedEntityIds, + dependencyFlatEntityMaps, + twentyStandardApplicationId, + now, + }), + audio: createStandardFieldFlatMetadata({ + objectName, + workspaceId, + context: { + fieldName: 'audio', + type: FieldMetadataType.FILES, + label: i18nLabel(msg`Audio`), + description: i18nLabel(msg`Audio-only recording`), + icon: 'IconHeadphones', + isNullable: true, + isUIReadOnly: true, + settings: { + maxNumberOfValues: 1, + }, + }, + standardObjectMetadataRelatedEntityIds, + dependencyFlatEntityMaps, + twentyStandardApplicationId, + now, + }), + transcript: createStandardFieldFlatMetadata({ + objectName, + workspaceId, + context: { + fieldName: 'transcript', + type: FieldMetadataType.RAW_JSON, + label: i18nLabel(msg`Transcript`), + description: i18nLabel(msg`Normalized diarized transcript`), + icon: 'IconFileText', + isNullable: true, + isUIReadOnly: true, + }, + standardObjectMetadataRelatedEntityIds, + dependencyFlatEntityMaps, + twentyStandardApplicationId, + now, + }), + summary: createStandardFieldFlatMetadata({ + objectName, + workspaceId, + context: { + fieldName: 'summary', + type: FieldMetadataType.RICH_TEXT, + label: i18nLabel(msg`Summary`), + description: i18nLabel(msg`Recording summary`), + icon: 'IconFileText', + isNullable: true, + isUIReadOnly: true, + }, + standardObjectMetadataRelatedEntityIds, + dependencyFlatEntityMaps, + twentyStandardApplicationId, + now, + }), + calendarEvent: createStandardRelationFieldFlatMetadata({ + objectName, + workspaceId, + context: { + type: FieldMetadataType.RELATION, + morphId: null, + fieldName: 'calendarEvent', + label: i18nLabel(msg`Calendar Event`), + description: i18nLabel(msg`Calendar Event`), + icon: 'IconCalendar', + isNullable: true, + isUIReadOnly: true, + targetObjectName: 'calendarEvent', + targetFieldName: 'callRecordings', + settings: { + relationType: RelationType.MANY_TO_ONE, + onDelete: RelationOnDeleteAction.SET_NULL, + joinColumnName: 'calendarEventId', + }, + }, + standardObjectMetadataRelatedEntityIds, + dependencyFlatEntityMaps, + twentyStandardApplicationId, + now, + }), + createdBy: createStandardFieldFlatMetadata({ + objectName, + workspaceId, + context: { + fieldName: 'createdBy', + type: FieldMetadataType.ACTOR, + label: i18nLabel(msg`Created by`), + description: i18nLabel(msg`The creator of the record`), + icon: 'IconCreativeCommonsSa', + isSystem: true, + isUIReadOnly: true, + isNullable: false, + defaultValue: { + source: "'MANUAL'", + name: "'System'", + workspaceMemberId: null, + }, + }, + standardObjectMetadataRelatedEntityIds, + dependencyFlatEntityMaps, + twentyStandardApplicationId, + now, + }), + updatedBy: createStandardFieldFlatMetadata({ + objectName, + workspaceId, + context: { + fieldName: 'updatedBy', + type: FieldMetadataType.ACTOR, + label: i18nLabel(msg`Updated by`), + description: i18nLabel( + msg`The workspace member who last updated the record`, + ), + icon: 'IconUserCircle', + isSystem: true, + isUIReadOnly: true, + isNullable: false, + defaultValue: { + source: "'MANUAL'", + name: "'System'", + workspaceMemberId: null, + }, + }, + standardObjectMetadataRelatedEntityIds, + dependencyFlatEntityMaps, + twentyStandardApplicationId, + now, + }), + position: createStandardFieldFlatMetadata({ + objectName, + workspaceId, + context: { + fieldName: 'position', + type: FieldMetadataType.POSITION, + label: i18nLabel(msg`Position`), + description: i18nLabel(msg`Call recording record position`), + icon: 'IconHierarchy2', + isSystem: true, + isNullable: false, + defaultValue: 0, + }, + standardObjectMetadataRelatedEntityIds, + dependencyFlatEntityMaps, + twentyStandardApplicationId, + now, + }), + searchVector: createStandardFieldFlatMetadata({ + objectName, + workspaceId, + context: { + fieldName: 'searchVector', + type: FieldMetadataType.TS_VECTOR, + label: i18nLabel(msg`Search vector`), + description: i18nLabel(msg`Field used for full-text search`), + icon: 'IconUser', + isSystem: true, + isNullable: true, + settings: { + generatedType: 'STORED', + asExpression: getTsVectorColumnExpressionFromFields([ + { name: 'title', type: FieldMetadataType.TEXT }, + ]), + }, + }, + standardObjectMetadataRelatedEntityIds, + dependencyFlatEntityMaps, + twentyStandardApplicationId, + now, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/index/build-standard-flat-index-metadata-maps.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/index/build-standard-flat-index-metadata-maps.util.ts index 6ddd61865c..ca60f5c741 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/index/build-standard-flat-index-metadata-maps.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/index/build-standard-flat-index-metadata-maps.util.ts @@ -7,6 +7,7 @@ import { buildAttachmentStandardFlatIndexMetadatas } from 'src/engine/workspace- import { buildBlocklistStandardFlatIndexMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/index/compute-blocklist-standard-flat-index-metadata.util'; import { buildCalendarChannelEventAssociationStandardFlatIndexMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/index/compute-calendar-channel-event-association-standard-flat-index-metadata.util'; import { buildCalendarEventParticipantStandardFlatIndexMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/index/compute-calendar-event-participant-standard-flat-index-metadata.util'; +import { buildCallRecordingStandardFlatIndexMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/index/compute-call-recording-standard-flat-index-metadata.util'; import { buildCompanyStandardFlatIndexMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/index/compute-company-standard-flat-index-metadata.util'; import { buildDashboardStandardFlatIndexMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/index/compute-dashboard-standard-flat-index-metadata.util'; import { buildMessageChannelMessageAssociationMessageFolderStandardFlatIndexMetadatas } from 'src/engine/workspace-manager/twenty-standard-application/utils/index/compute-message-channel-message-association-message-folder-standard-flat-index-metadata.util'; @@ -38,6 +39,7 @@ const STANDARD_FLAT_INDEX_METADATA_BUILDERS_BY_OBJECT_NAME = { buildCalendarChannelEventAssociationStandardFlatIndexMetadatas, calendarEventParticipant: buildCalendarEventParticipantStandardFlatIndexMetadatas, + callRecording: buildCallRecordingStandardFlatIndexMetadatas, company: buildCompanyStandardFlatIndexMetadatas, dashboard: buildDashboardStandardFlatIndexMetadatas, message: buildMessageStandardFlatIndexMetadatas, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/index/compute-call-recording-standard-flat-index-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/index/compute-call-recording-standard-flat-index-metadata.util.ts new file mode 100644 index 0000000000..b48f3e686e --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/index/compute-call-recording-standard-flat-index-metadata.util.ts @@ -0,0 +1,31 @@ +import { type FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/types/flat-index-metadata.type'; +import { type AllStandardObjectIndexName } from 'src/engine/workspace-manager/twenty-standard-application/types/all-standard-object-index-name.type'; +import { + type CreateStandardIndexArgs, + createStandardIndexFlatMetadata, +} from 'src/engine/workspace-manager/twenty-standard-application/utils/index/create-standard-index-flat-metadata.util'; + +export const buildCallRecordingStandardFlatIndexMetadatas = ({ + now, + objectName, + workspaceId, + standardObjectMetadataRelatedEntityIds, + dependencyFlatEntityMaps, + twentyStandardApplicationId, +}: Omit, 'context'>): Record< + AllStandardObjectIndexName<'callRecording'>, + FlatIndexMetadata +> => ({ + calendarEventIdIndex: createStandardIndexFlatMetadata({ + objectName, + workspaceId, + context: { + indexName: 'calendarEventIdIndex', + relatedFieldNames: ['calendarEvent'], + }, + standardObjectMetadataRelatedEntityIds, + dependencyFlatEntityMaps, + twentyStandardApplicationId, + now, + }), +}); diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/object-metadata/create-standard-flat-object-metadata.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/object-metadata/create-standard-flat-object-metadata.util.ts index ef1e04f8a5..509b4de2b1 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/object-metadata/create-standard-flat-object-metadata.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/object-metadata/create-standard-flat-object-metadata.util.ts @@ -154,6 +154,36 @@ export const STANDARD_FLAT_OBJECT_METADATA_BUILDERS_BY_OBJECT_NAME = { twentyStandardApplicationId, now, }), + callRecording: ({ + now, + workspaceId, + standardObjectMetadataRelatedEntityIds, + twentyStandardApplicationId, + dependencyFlatEntityMaps, + }: Omit< + CreateStandardObjectArgs<'callRecording'>, + 'context' | 'objectName' + >) => + createStandardObjectFlatMetadata({ + objectName: 'callRecording', + dependencyFlatEntityMaps, + context: { + universalIdentifier: STANDARD_OBJECTS.callRecording.universalIdentifier, + nameSingular: 'callRecording', + namePlural: 'callRecordings', + labelSingular: i18nLabel(msg`Call Recording`), + labelPlural: i18nLabel(msg`Call Recordings`), + description: i18nLabel(msg`A recording of a meeting`), + icon: 'IconVideo', + isSystem: true, + isAuditLogged: false, + labelIdentifierFieldMetadataName: 'title', + }, + workspaceId, + standardObjectMetadataRelatedEntityIds, + twentyStandardApplicationId, + now, + }), company: ({ now, workspaceId, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/index.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/index.ts index 66188acbbc..3a8e5b3f3b 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/index.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/index.ts @@ -1,6 +1,7 @@ export { STANDARD_BLOCKLIST_PAGE_LAYOUT_CONFIG } from './standard-blocklist-page-layout.config'; export { STANDARD_CALENDAR_CHANNEL_EVENT_ASSOCIATION_PAGE_LAYOUT_CONFIG } from './standard-calendar-channel-event-association-page-layout.config'; export { STANDARD_CALENDAR_EVENT_PARTICIPANT_PAGE_LAYOUT_CONFIG } from './standard-calendar-event-participant-page-layout.config'; +export { STANDARD_CALL_RECORDING_PAGE_LAYOUT_CONFIG } from './standard-call-recording-page-layout.config'; export { STANDARD_COMPANY_PAGE_LAYOUT_CONFIG } from './standard-company-page-layout.config'; export { STANDARD_DASHBOARD_PAGE_LAYOUT_CONFIG } from './standard-dashboard-page-layout.config'; export { STANDARD_MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_MESSAGE_FOLDER_PAGE_LAYOUT_CONFIG } from './standard-message-channel-message-association-message-folder-page-layout.config'; diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-call-recording-page-layout.config.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-call-recording-page-layout.config.ts new file mode 100644 index 0000000000..8bd52f0972 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-call-recording-page-layout.config.ts @@ -0,0 +1,56 @@ +import { + STANDARD_OBJECTS, + STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS, +} from 'twenty-shared/metadata'; + +import { PageLayoutType } from 'src/engine/metadata-modules/page-layout/enums/page-layout-type.enum'; +import { + TAB_PROPS, + WIDGET_PROPS, +} from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-page-layout-tabs.template'; +import { + type StandardPageLayoutConfig, + type StandardPageLayoutTabConfig, +} from 'src/engine/workspace-manager/twenty-standard-application/utils/page-layout-config/standard-page-layout-config.type'; + +const CALL_RECORDING_PAGE_TABS = { + home: { + universalIdentifier: + STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.callRecordingRecordPage.tabs + .home.universalIdentifier, + ...TAB_PROPS.home, + widgets: { + fields: { + universalIdentifier: + STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.callRecordingRecordPage + .tabs.home.widgets.fields.universalIdentifier, + ...WIDGET_PROPS.fields, + }, + }, + }, + timeline: { + universalIdentifier: + STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.callRecordingRecordPage.tabs + .timeline.universalIdentifier, + ...TAB_PROPS.timeline, + widgets: { + timeline: { + universalIdentifier: + STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.callRecordingRecordPage + .tabs.timeline.widgets.timeline.universalIdentifier, + ...WIDGET_PROPS.timeline, + }, + }, + }, +} as const satisfies Record; + +export const STANDARD_CALL_RECORDING_PAGE_LAYOUT_CONFIG = { + name: 'Default Call Recording Layout', + type: PageLayoutType.RECORD_PAGE, + objectUniversalIdentifier: STANDARD_OBJECTS.callRecording.universalIdentifier, + universalIdentifier: + STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS.callRecordingRecordPage + .universalIdentifier, + defaultTabUniversalIdentifier: null, + tabs: CALL_RECORDING_PAGE_TABS, +} as const satisfies StandardPageLayoutConfig; diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-widget/build-standard-flat-page-layout-widget-metadata-maps.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-widget/build-standard-flat-page-layout-widget-metadata-maps.util.ts index 3379a86e79..36544b75ce 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-widget/build-standard-flat-page-layout-widget-metadata-maps.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/page-layout-widget/build-standard-flat-page-layout-widget-metadata-maps.util.ts @@ -69,6 +69,7 @@ const RECORD_PAGE_FIELDS_VIEW_NAME_BY_OBJECT: Partial< calendarChannelEventAssociation: 'calendarChannelEventAssociationRecordPageFields', calendarEventParticipant: 'calendarEventParticipantRecordPageFields', + callRecording: 'callRecordingRecordPageFields', company: 'companyRecordPageFields', messageChannelMessageAssociation: 'messageChannelMessageAssociationRecordPageFields', diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/view-field-group/build-standard-flat-view-field-group-metadata-maps.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/view-field-group/build-standard-flat-view-field-group-metadata-maps.util.ts index 7d1b2652fa..120d6408ee 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/view-field-group/build-standard-flat-view-field-group-metadata-maps.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/view-field-group/build-standard-flat-view-field-group-metadata-maps.util.ts @@ -6,6 +6,7 @@ import { type AllStandardObjectName } from 'src/engine/workspace-manager/twenty- import { computeStandardBlocklistViewFieldGroups } from 'src/engine/workspace-manager/twenty-standard-application/utils/view-field-group/compute-standard-blocklist-view-field-groups.util'; import { computeStandardCalendarChannelEventAssociationViewFieldGroups } from 'src/engine/workspace-manager/twenty-standard-application/utils/view-field-group/compute-standard-calendar-channel-event-association-view-field-groups.util'; import { computeStandardCalendarEventParticipantViewFieldGroups } from 'src/engine/workspace-manager/twenty-standard-application/utils/view-field-group/compute-standard-calendar-event-participant-view-field-groups.util'; +import { computeStandardCallRecordingViewFieldGroups } from 'src/engine/workspace-manager/twenty-standard-application/utils/view-field-group/compute-standard-call-recording-view-field-groups.util'; import { computeStandardCompanyViewFieldGroups } from 'src/engine/workspace-manager/twenty-standard-application/utils/view-field-group/compute-standard-company-view-field-groups.util'; import { computeStandardMessageChannelMessageAssociationViewFieldGroups } from 'src/engine/workspace-manager/twenty-standard-application/utils/view-field-group/compute-standard-message-channel-message-association-view-field-groups.util'; import { computeStandardMessageChannelMessageAssociationMessageFolderViewFieldGroups } from 'src/engine/workspace-manager/twenty-standard-application/utils/view-field-group/compute-standard-message-channel-message-association-message-folder-view-field-groups.util'; @@ -29,6 +30,7 @@ const STANDARD_FLAT_VIEW_FIELD_GROUP_METADATA_BUILDERS_BY_OBJECT_NAME = { computeStandardCalendarChannelEventAssociationViewFieldGroups, calendarEventParticipant: computeStandardCalendarEventParticipantViewFieldGroups, + callRecording: computeStandardCallRecordingViewFieldGroups, company: computeStandardCompanyViewFieldGroups, messageChannelMessageAssociation: computeStandardMessageChannelMessageAssociationViewFieldGroups, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/view-field-group/compute-standard-call-recording-view-field-groups.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/view-field-group/compute-standard-call-recording-view-field-groups.util.ts new file mode 100644 index 0000000000..5d7995fa59 --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/view-field-group/compute-standard-call-recording-view-field-groups.util.ts @@ -0,0 +1,24 @@ +import { type FlatViewFieldGroup } from 'src/engine/metadata-modules/flat-view-field-group/types/flat-view-field-group.type'; +import { + createStandardViewFieldGroupFlatMetadata, + type CreateStandardViewFieldGroupArgs, +} from 'src/engine/workspace-manager/twenty-standard-application/utils/view-field-group/create-standard-view-field-group-flat-metadata.util'; + +export const computeStandardCallRecordingViewFieldGroups = ( + args: Omit, 'context'>, +): Record => { + return { + callRecordingRecordPageFieldsGeneral: + createStandardViewFieldGroupFlatMetadata({ + ...args, + objectName: 'callRecording', + context: { + viewName: 'callRecordingRecordPageFields', + viewFieldGroupName: 'general', + name: 'General', + position: 0, + isVisible: true, + }, + }), + }; +}; diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/view-field/build-standard-flat-view-field-metadata-maps.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/view-field/build-standard-flat-view-field-metadata-maps.util.ts index 6376a9af8b..a175a75935 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/view-field/build-standard-flat-view-field-metadata-maps.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/view-field/build-standard-flat-view-field-metadata-maps.util.ts @@ -8,6 +8,7 @@ import { computeStandardBlocklistViewFields } from 'src/engine/workspace-manager import { computeStandardCalendarChannelEventAssociationViewFields } from 'src/engine/workspace-manager/twenty-standard-application/utils/view-field/compute-standard-calendar-channel-event-association-view-fields.util'; import { computeStandardCalendarEventParticipantViewFields } from 'src/engine/workspace-manager/twenty-standard-application/utils/view-field/compute-standard-calendar-event-participant-view-fields.util'; import { computeStandardCalendarEventViewFields } from 'src/engine/workspace-manager/twenty-standard-application/utils/view-field/compute-standard-calendar-event-view-fields.util'; +import { computeStandardCallRecordingViewFields } from 'src/engine/workspace-manager/twenty-standard-application/utils/view-field/compute-standard-call-recording-view-fields.util'; import { computeStandardCompanyViewFields } from 'src/engine/workspace-manager/twenty-standard-application/utils/view-field/compute-standard-company-view-fields.util'; import { computeStandardDashboardViewFields } from 'src/engine/workspace-manager/twenty-standard-application/utils/view-field/compute-standard-dashboard-view-fields.util'; import { computeStandardMessageChannelMessageAssociationMessageFolderViewFields } from 'src/engine/workspace-manager/twenty-standard-application/utils/view-field/compute-standard-message-channel-message-association-message-folder-view-fields.util'; @@ -40,6 +41,7 @@ const STANDARD_FLAT_VIEW_FIELD_METADATA_BUILDERS_BY_OBJECT_NAME = { computeStandardCalendarChannelEventAssociationViewFields, calendarEvent: computeStandardCalendarEventViewFields, calendarEventParticipant: computeStandardCalendarEventParticipantViewFields, + callRecording: computeStandardCallRecordingViewFields, company: computeStandardCompanyViewFields, dashboard: computeStandardDashboardViewFields, message: computeStandardMessageViewFields, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/view-field/compute-standard-call-recording-view-fields.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/view-field/compute-standard-call-recording-view-fields.util.ts new file mode 100644 index 0000000000..34e8d9d3ee --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/view-field/compute-standard-call-recording-view-fields.util.ts @@ -0,0 +1,156 @@ +import { type FlatViewField } from 'src/engine/metadata-modules/flat-view-field/types/flat-view-field.type'; +import { + createStandardViewFieldFlatMetadata, + type CreateStandardViewFieldArgs, +} from 'src/engine/workspace-manager/twenty-standard-application/utils/view-field/create-standard-view-field-flat-metadata.util'; + +export const computeStandardCallRecordingViewFields = ( + args: Omit, 'context'>, +): Record => { + return { + // title is the label identifier; it must hold the lowest position in non-widget views. + allCallRecordingsTitle: createStandardViewFieldFlatMetadata({ + ...args, + objectName: 'callRecording', + context: { + viewName: 'allCallRecordings', + viewFieldName: 'title', + fieldName: 'title', + position: 0, + isVisible: true, + size: 200, + }, + }), + allCallRecordingsStatus: createStandardViewFieldFlatMetadata({ + ...args, + objectName: 'callRecording', + context: { + viewName: 'allCallRecordings', + viewFieldName: 'status', + fieldName: 'status', + position: 1, + isVisible: true, + size: 150, + }, + }), + allCallRecordingsStartedAt: createStandardViewFieldFlatMetadata({ + ...args, + objectName: 'callRecording', + context: { + viewName: 'allCallRecordings', + viewFieldName: 'startedAt', + fieldName: 'startedAt', + position: 2, + isVisible: true, + size: 150, + }, + }), + callRecordingRecordPageFieldsTitle: createStandardViewFieldFlatMetadata({ + ...args, + objectName: 'callRecording', + context: { + viewName: 'callRecordingRecordPageFields', + viewFieldName: 'title', + fieldName: 'title', + position: 0, + isVisible: true, + size: 200, + viewFieldGroupName: 'general', + }, + }), + callRecordingRecordPageFieldsStatus: createStandardViewFieldFlatMetadata({ + ...args, + objectName: 'callRecording', + context: { + viewName: 'callRecordingRecordPageFields', + viewFieldName: 'status', + fieldName: 'status', + position: 1, + isVisible: true, + size: 150, + viewFieldGroupName: 'general', + }, + }), + callRecordingRecordPageFieldsStartedAt: createStandardViewFieldFlatMetadata( + { + ...args, + objectName: 'callRecording', + context: { + viewName: 'callRecordingRecordPageFields', + viewFieldName: 'startedAt', + fieldName: 'startedAt', + position: 2, + isVisible: true, + size: 150, + viewFieldGroupName: 'general', + }, + }, + ), + callRecordingRecordPageFieldsEndedAt: createStandardViewFieldFlatMetadata({ + ...args, + objectName: 'callRecording', + context: { + viewName: 'callRecordingRecordPageFields', + viewFieldName: 'endedAt', + fieldName: 'endedAt', + position: 3, + isVisible: true, + size: 150, + viewFieldGroupName: 'general', + }, + }), + callRecordingRecordPageFieldsVideo: createStandardViewFieldFlatMetadata({ + ...args, + objectName: 'callRecording', + context: { + viewName: 'callRecordingRecordPageFields', + viewFieldName: 'video', + fieldName: 'video', + position: 4, + isVisible: true, + size: 150, + viewFieldGroupName: 'general', + }, + }), + callRecordingRecordPageFieldsAudio: createStandardViewFieldFlatMetadata({ + ...args, + objectName: 'callRecording', + context: { + viewName: 'callRecordingRecordPageFields', + viewFieldName: 'audio', + fieldName: 'audio', + position: 5, + isVisible: true, + size: 150, + viewFieldGroupName: 'general', + }, + }), + callRecordingRecordPageFieldsTranscript: + createStandardViewFieldFlatMetadata({ + ...args, + objectName: 'callRecording', + context: { + viewName: 'callRecordingRecordPageFields', + viewFieldName: 'transcript', + fieldName: 'transcript', + position: 6, + isVisible: true, + size: 150, + viewFieldGroupName: 'general', + }, + }), + callRecordingRecordPageFieldsSummary: createStandardViewFieldFlatMetadata({ + ...args, + objectName: 'callRecording', + context: { + viewName: 'callRecordingRecordPageFields', + viewFieldName: 'summary', + fieldName: 'summary', + position: 7, + isVisible: true, + size: 200, + viewFieldGroupName: 'general', + }, + }), + }; +}; diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/view/build-standard-flat-view-metadata-maps.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/view/build-standard-flat-view-metadata-maps.util.ts index d8520c0514..9f519ae1b6 100644 --- a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/view/build-standard-flat-view-metadata-maps.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/view/build-standard-flat-view-metadata-maps.util.ts @@ -8,6 +8,7 @@ import { computeStandardBlocklistViews } from 'src/engine/workspace-manager/twen import { computeStandardCalendarChannelEventAssociationViews } from 'src/engine/workspace-manager/twenty-standard-application/utils/view/compute-standard-calendar-channel-event-association-views.util'; import { computeStandardCalendarEventParticipantViews } from 'src/engine/workspace-manager/twenty-standard-application/utils/view/compute-standard-calendar-event-participant-views.util'; import { computeStandardCalendarEventViews } from 'src/engine/workspace-manager/twenty-standard-application/utils/view/compute-standard-calendar-event-views.util'; +import { computeStandardCallRecordingViews } from 'src/engine/workspace-manager/twenty-standard-application/utils/view/compute-standard-call-recording-views.util'; import { computeStandardCompanyViews } from 'src/engine/workspace-manager/twenty-standard-application/utils/view/compute-standard-company-views.util'; import { computeStandardDashboardViews } from 'src/engine/workspace-manager/twenty-standard-application/utils/view/compute-standard-dashboard-views.util'; import { computeStandardMessageChannelMessageAssociationMessageFolderViews } from 'src/engine/workspace-manager/twenty-standard-application/utils/view/compute-standard-message-channel-message-association-message-folder-views.util'; @@ -40,6 +41,7 @@ const STANDARD_FLAT_VIEW_METADATA_BUILDERS_BY_OBJECT_NAME = { computeStandardCalendarChannelEventAssociationViews, calendarEvent: computeStandardCalendarEventViews, calendarEventParticipant: computeStandardCalendarEventParticipantViews, + callRecording: computeStandardCallRecordingViews, company: computeStandardCompanyViews, dashboard: computeStandardDashboardViews, message: computeStandardMessageViews, diff --git a/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/view/compute-standard-call-recording-views.util.ts b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/view/compute-standard-call-recording-views.util.ts new file mode 100644 index 0000000000..c1afb0c6fd --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/twenty-standard-application/utils/view/compute-standard-call-recording-views.util.ts @@ -0,0 +1,38 @@ +import { ViewKey, ViewType } from 'twenty-shared/types'; + +import { type FlatView } from 'src/engine/metadata-modules/flat-view/types/flat-view.type'; +import { + createStandardViewFlatMetadata, + type CreateStandardViewArgs, +} from 'src/engine/workspace-manager/twenty-standard-application/utils/view/create-standard-view-flat-metadata.util'; + +export const computeStandardCallRecordingViews = ( + args: Omit, 'context'>, +): Record => { + return { + allCallRecordings: createStandardViewFlatMetadata({ + ...args, + objectName: 'callRecording', + context: { + viewName: 'allCallRecordings', + name: 'All {objectLabelPlural}', + type: ViewType.TABLE, + key: ViewKey.INDEX, + position: 0, + icon: 'IconList', + }, + }), + callRecordingRecordPageFields: createStandardViewFlatMetadata({ + ...args, + objectName: 'callRecording', + context: { + viewName: 'callRecordingRecordPageFields', + name: 'Call Recording Record Page Fields', + type: ViewType.FIELDS_WIDGET, + key: null, + position: 0, + icon: 'IconList', + }, + }), + }; +}; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration/constant/standard-object-icons.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration/constant/standard-object-icons.ts index 274372dc62..8c31b79330 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration/constant/standard-object-icons.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration/constant/standard-object-icons.ts @@ -8,6 +8,7 @@ export const STANDARD_OBJECT_ICONS = { calendarChannelEventAssociation: 'IconCalendar', calendarEventParticipant: 'IconCalendar', calendarEvent: 'IconCalendar', + callRecording: 'IconVideo', comment: 'IconMessageCircle', company: 'IconBuildingSkyscraper', dashboard: 'IconLayoutDashboard', diff --git a/packages/twenty-server/src/modules/calendar/common/query-hooks/calendar-event/services/apply-calendar-events-visibility-restrictions.service.spec.ts b/packages/twenty-server/src/modules/calendar/common/query-hooks/calendar-event/services/apply-calendar-events-visibility-restrictions.service.spec.ts index a680d2c19f..5140089c08 100644 --- a/packages/twenty-server/src/modules/calendar/common/query-hooks/calendar-event/services/apply-calendar-events-visibility-restrictions.service.spec.ts +++ b/packages/twenty-server/src/modules/calendar/common/query-hooks/calendar-event/services/apply-calendar-events-visibility-restrictions.service.spec.ts @@ -37,6 +37,7 @@ const createMockCalendarEvent = ( updatedAt: '2024-03-20T09:00:00Z', iCalUid: '', conferenceSolution: '', + recordingPreference: 'AUTO', calendarChannelEventAssociations: [], calendarEventParticipants: [], }); diff --git a/packages/twenty-server/src/modules/calendar/common/standard-objects/calendar-event.workspace-entity.ts b/packages/twenty-server/src/modules/calendar/common/standard-objects/calendar-event.workspace-entity.ts index a8beb70bfa..d79555c29f 100644 --- a/packages/twenty-server/src/modules/calendar/common/standard-objects/calendar-event.workspace-entity.ts +++ b/packages/twenty-server/src/modules/calendar/common/standard-objects/calendar-event.workspace-entity.ts @@ -25,10 +25,14 @@ export class CalendarEventWorkspaceEntity extends BaseWorkspaceEntity { iCalUid: string | null; conferenceSolution: string | null; conferenceLink: LinksMetadata; + recordingPreference: string; calendarChannelEventAssociations: EntityRelation< CalendarChannelEventAssociationWorkspaceEntity[] >; calendarEventParticipants: EntityRelation< CalendarEventParticipantWorkspaceEntity[] >; + // callRecordings reverse relation intentionally omitted from the TypeScript workspace + // entity. It exists in standard metadata, but declaring a to-many relation here expands + // recursive nested insert types and tips Person past TS's instantiation-depth limit. } diff --git a/packages/twenty-server/src/modules/call-recording/standard-objects/call-recording.workspace-entity.ts b/packages/twenty-server/src/modules/call-recording/standard-objects/call-recording.workspace-entity.ts new file mode 100644 index 0000000000..a11a343f15 --- /dev/null +++ b/packages/twenty-server/src/modules/call-recording/standard-objects/call-recording.workspace-entity.ts @@ -0,0 +1,22 @@ +import { type RichTextMetadata } from 'twenty-shared/types'; + +import { type FileOutput } from 'src/engine/api/common/common-args-processors/data-arg-processor/types/file-item.type'; +import { BaseWorkspaceEntity } from 'src/engine/twenty-orm/base.workspace-entity'; +import { type EntityRelation } from 'src/engine/workspace-manager/workspace-migration/types/entity-relation.interface'; +import { type CalendarEventWorkspaceEntity } from 'src/modules/calendar/common/standard-objects/calendar-event.workspace-entity'; + +export class CallRecordingWorkspaceEntity extends BaseWorkspaceEntity { + title: string | null; + status: string; + applicationId: string | null; + externalBotId: string | null; + externalRecordingId: string | null; + startedAt: string | null; + endedAt: string | null; + video: FileOutput[] | null; + audio: FileOutput[] | null; + transcript: Record | null; + summary: RichTextMetadata | null; + calendarEvent: EntityRelation | null; + calendarEventId: string | null; +} diff --git a/packages/twenty-shared/src/metadata/constants/standard-object.constant.ts b/packages/twenty-shared/src/metadata/constants/standard-object.constant.ts index da8a1666c4..6e14e09dbf 100644 --- a/packages/twenty-shared/src/metadata/constants/standard-object.constant.ts +++ b/packages/twenty-shared/src/metadata/constants/standard-object.constant.ts @@ -480,6 +480,12 @@ export const STANDARD_OBJECTS = { calendarEventParticipants: { universalIdentifier: '20202020-e07e-4ccb-88f5-6f3d00458eec', }, + recordingPreference: { + universalIdentifier: '1d231e7e-9bbe-410b-8007-ea7678a83e58', + }, + callRecordings: { + universalIdentifier: '48d6d151-18e2-4111-b405-d85fb9d860d8', + }, createdBy: { universalIdentifier: '664a9500-2641-4caa-8d95-069807bb2eb4', }, @@ -526,6 +532,126 @@ export const STANDARD_OBJECTS = { }, }, }, + callRecording: { + universalIdentifier: 'ce19efb9-710f-45b2-b141-473abbeea60b', + fields: { + id: { + universalIdentifier: '9767180b-76c2-47d5-b7b9-5dc60f14391d', + }, + createdAt: { + universalIdentifier: 'd1adb2a9-9da3-4656-93b7-db79780b77eb', + }, + updatedAt: { + universalIdentifier: '5db0a477-5715-4ffd-bdbe-854dfaccfe22', + }, + deletedAt: { + universalIdentifier: 'cf22a652-390a-4f55-b3a0-615c8fd8c7ed', + }, + title: { + universalIdentifier: '4cff8863-a1d1-45fd-a370-4eb6aa1f2a5b', + }, + status: { + universalIdentifier: '3e617680-d93e-4309-a54f-90f69528bfd7', + }, + applicationId: { + universalIdentifier: '24ec1239-1240-42cb-8a2d-302632378e09', + }, + externalBotId: { + universalIdentifier: '0a2da128-9bcc-488b-bc31-65318c41bdf9', + }, + externalRecordingId: { + universalIdentifier: '6d17fb71-324b-4625-a5be-b3580607e2c7', + }, + startedAt: { + universalIdentifier: '6c56c23f-1987-410a-860a-df3b2b3f9a33', + }, + endedAt: { + universalIdentifier: '7a38a9cf-8424-4d6e-b80a-6883d3c662ef', + }, + video: { + universalIdentifier: 'bb9523d3-457e-4f4b-8c79-27a77afb87da', + }, + audio: { + universalIdentifier: '2eafc2d0-8fec-430c-a939-65ca5fbc0f08', + }, + transcript: { + universalIdentifier: '27b86d68-57d1-4607-aca0-191896b1ad43', + }, + summary: { + universalIdentifier: 'adb0f472-756b-4d3f-b21e-ea32bf73a5e4', + }, + calendarEvent: { + universalIdentifier: '49e64b28-bd98-4775-80ea-4781bdd45e35', + }, + createdBy: { + universalIdentifier: 'cb84ce87-ccd4-4901-9b9e-25e3cbfce3ba', + }, + updatedBy: { + universalIdentifier: '02309262-b6dc-4cbd-936b-d851a7deec79', + }, + position: { + universalIdentifier: 'eeae3145-3696-41ae-b0ed-1370ad35b33c', + }, + searchVector: { + universalIdentifier: 'd6fd4ad0-4aec-4969-bdb5-945fda0fcf45', + }, + }, + indexes: { + calendarEventIdIndex: { + universalIdentifier: '8be3cc47-9352-4a1b-ad19-bb186bc0865d', + }, + }, + views: { + allCallRecordings: { + universalIdentifier: 'c395b55e-88f0-4d5b-a1fb-0d38b50e0b19', + viewFields: { + status: { + universalIdentifier: '6c4a81a2-d9c1-4f82-984c-f97e083ca710', + }, + title: { + universalIdentifier: 'b1d5051b-071d-4514-93cf-704724cdc8f6', + }, + startedAt: { + universalIdentifier: '3b96351f-66ed-4fa6-acb6-698647573af7', + }, + }, + }, + callRecordingRecordPageFields: { + universalIdentifier: '99fa8b47-3b11-4f9b-8fbc-e67a9e1da682', + viewFieldGroups: { + general: { + universalIdentifier: '068426eb-dd20-49b0-ae9c-68727f3be2fb', + }, + }, + viewFields: { + title: { + universalIdentifier: '6308d574-8579-4cf2-a020-c208df97cf3e', + }, + status: { + universalIdentifier: '93483569-fcd2-46cf-b576-9f0318ad2b3b', + }, + startedAt: { + universalIdentifier: '3fd00fbb-c153-45e3-b6e6-43d18d34052a', + }, + endedAt: { + universalIdentifier: 'ba8c8d41-c112-4173-b927-5b5c5a5c047b', + }, + video: { + universalIdentifier: 'acc54ade-cd26-4be2-9391-a42715ad1523', + }, + audio: { + universalIdentifier: '9445a547-1d1e-4da3-916b-2c2269c951c9', + }, + transcript: { + universalIdentifier: '782c97f6-e6b1-472b-8992-bbb60d25791b', + }, + summary: { + universalIdentifier: 'a0ace064-cc72-4631-ade3-07cdded86b0e', + }, + }, + }, + }, + }, company: { universalIdentifier: '20202020-b374-4779-a561-80086cb2e17f', fields: { diff --git a/packages/twenty-shared/src/metadata/constants/standard-page-layout-universal-identifiers.constant.ts b/packages/twenty-shared/src/metadata/constants/standard-page-layout-universal-identifiers.constant.ts index 658ae97795..8966e49bb4 100644 --- a/packages/twenty-shared/src/metadata/constants/standard-page-layout-universal-identifiers.constant.ts +++ b/packages/twenty-shared/src/metadata/constants/standard-page-layout-universal-identifiers.constant.ts @@ -444,6 +444,27 @@ export const STANDARD_PAGE_LAYOUT_UNIVERSAL_IDENTIFIERS = { }, }, }, + callRecordingRecordPage: { + universalIdentifier: 'fa475fb3-3fe4-4ab8-8320-495eba5b2e58', + tabs: { + home: { + universalIdentifier: 'f61be659-f6f1-4f1f-b3f9-113370740f1b', + widgets: { + fields: { + universalIdentifier: 'e490d2dd-5b69-4518-b867-9dde815f9cb6', + }, + }, + }, + timeline: { + universalIdentifier: '9fb360fa-bc10-430c-8425-25d4e9da4386', + widgets: { + timeline: { + universalIdentifier: '9347305a-73de-4651-a116-c67b2706beda', + }, + }, + }, + }, + }, messageChannelMessageAssociationRecordPage: { universalIdentifier: '20202020-a111-4011-8011-a5c4a5110001', tabs: { diff --git a/packages/twenty-shared/src/types/FeatureFlagKey.ts b/packages/twenty-shared/src/types/FeatureFlagKey.ts index 937f3b12b7..6e417668c9 100644 --- a/packages/twenty-shared/src/types/FeatureFlagKey.ts +++ b/packages/twenty-shared/src/types/FeatureFlagKey.ts @@ -8,5 +8,6 @@ export enum FeatureFlagKey { IS_REST_METADATA_API_NEW_FORMAT_DIRECT = 'IS_REST_METADATA_API_NEW_FORMAT_DIRECT', IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED = 'IS_LOGIC_FUNCTION_PREBUILT_MODE_ENABLED', IS_SETTINGS_DISCOVERY_HERO_ENABLED = 'IS_SETTINGS_DISCOVERY_HERO_ENABLED', + IS_CALL_RECORDING_ENABLED = 'IS_CALL_RECORDING_ENABLED', IS_WORKFLOW_RUN_STEP_LOGS_ENABLED = 'IS_WORKFLOW_RUN_STEP_LOGS_ENABLED', }