diff --git a/packages/twenty-front/src/modules/workflow/workflow-variables/utils/__tests__/filterOutputSchema.test.ts b/packages/twenty-front/src/modules/workflow/workflow-variables/utils/__tests__/filterOutputSchema.test.ts index 84bd168551..4b5665f1a2 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-variables/utils/__tests__/filterOutputSchema.test.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-variables/utils/__tests__/filterOutputSchema.test.ts @@ -68,7 +68,7 @@ describe('filterOutputSchema', () => { }); }); - describe('shouldDisplayRecordObjects only (false, true)', () => { + describe('shouldDisplayRecordObjects and related fields only (false, true)', () => { describe('record schema', () => { it('should keep record schema with object and filter compatible fields', () => { const inputSchema = createRecordSchema('person', { @@ -78,9 +78,11 @@ describe('filterOutputSchema', () => { isLeaf: false, value: createRecordSchema('employee'), }, + domain: { isLeaf: true, type: FieldMetadataType.TEXT }, }); const expectedSchema = createRecordSchema('person', { + id: { isLeaf: true, type: FieldMetadataType.UUID }, name: { isLeaf: true, value: 'string' }, employee: { isLeaf: false, diff --git a/packages/twenty-front/src/modules/workflow/workflow-variables/utils/isFieldTypeCompatibleWithRecordId.ts b/packages/twenty-front/src/modules/workflow/workflow-variables/utils/isFieldTypeCompatibleWithRecordId.ts index cde265ed15..9324f7aa4c 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-variables/utils/isFieldTypeCompatibleWithRecordId.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-variables/utils/isFieldTypeCompatibleWithRecordId.ts @@ -1,7 +1,13 @@ import { type InputSchemaPropertyType } from '@/workflow/types/InputSchema'; +import { FieldMetadataType } from '~/generated-metadata/graphql'; export const isFieldTypeCompatibleWithRecordId = ( type?: InputSchemaPropertyType, ): boolean => { - return !type || type === 'string' || type === 'unknown'; + return ( + !type || + type === 'string' || + type === 'unknown' || + type === FieldMetadataType.UUID + ); }; diff --git a/packages/twenty-front/src/modules/workflow/workflow-variables/utils/searchVariableThroughRecordOutputSchema.ts b/packages/twenty-front/src/modules/workflow/workflow-variables/utils/searchVariableThroughRecordOutputSchema.ts index 0d8bf04cf9..0a0c98f809 100644 --- a/packages/twenty-front/src/modules/workflow/workflow-variables/utils/searchVariableThroughRecordOutputSchema.ts +++ b/packages/twenty-front/src/modules/workflow/workflow-variables/utils/searchVariableThroughRecordOutputSchema.ts @@ -34,6 +34,14 @@ const getCompositeSubFieldName = ( : undefined; }; +const isIdFieldName = (fieldName: string) => { + return ( + fieldName === 'id' || + // For database events, id field will have a prefix such as properties.after.id + fieldName.endsWith('.id') + ); +}; + const navigateToTargetField = ( startingSchema: RecordOutputSchemaV2, pathSegments: string[], @@ -73,7 +81,9 @@ const buildVariableResult = ( const targetField = getFieldFromSchema(targetFieldName, targetSchema); // Determine the variable label based on whether we want the full record or a specific field const variableLabel = - isFullRecord && isRecordOutputSchemaV2(targetSchema) + isFullRecord && + isRecordOutputSchemaV2(targetSchema) && + isIdFieldName(targetFieldName) ? getRecordObjectLabel(targetSchema) : targetField?.label; diff --git a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-schema/utils/__tests__/generate-fake-object-record.spec.ts b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-schema/utils/__tests__/generate-fake-object-record.spec.ts index d0b8eaa4a3..be6955fa16 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-schema/utils/__tests__/generate-fake-object-record.spec.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-schema/utils/__tests__/generate-fake-object-record.spec.ts @@ -58,6 +58,7 @@ describe('generateFakeObjectRecord', () => { expect(generateObjectRecordFields).toHaveBeenCalledWith({ objectMetadataInfo, depth: 0, + maxDepth: 1, }); }); }); diff --git a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-schema/utils/generate-fake-object-record.ts b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-schema/utils/generate-fake-object-record.ts index 1dcc8118fb..9ae8b62333 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-schema/utils/generate-fake-object-record.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-schema/utils/generate-fake-object-record.ts @@ -5,9 +5,11 @@ import { generateObjectRecordFields } from 'src/modules/workflow/workflow-builde export const generateFakeObjectRecord = ({ objectMetadataInfo, depth = 0, + maxDepth = 1, }: { objectMetadataInfo: ObjectMetadataInfo; depth?: number; + maxDepth?: number; }): RecordOutputSchema => { return { object: { @@ -22,6 +24,7 @@ export const generateFakeObjectRecord = ({ fields: generateObjectRecordFields({ objectMetadataInfo, depth, + maxDepth, }), _outputSchemaType: 'RECORD', }; diff --git a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-schema/utils/generate-object-record-fields.ts b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-schema/utils/generate-object-record-fields.ts index 59bf3fa9d6..cfea670362 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-schema/utils/generate-object-record-fields.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-schema/utils/generate-object-record-fields.ts @@ -6,15 +6,16 @@ import { type FieldOutputSchema } from 'src/modules/workflow/workflow-builder/wo import { generateFakeObjectRecord } from 'src/modules/workflow/workflow-builder/workflow-schema/utils/generate-fake-object-record'; import { generateFakeRecordField } from 'src/modules/workflow/workflow-builder/workflow-schema/utils/generate-fake-record-field'; import { shouldGenerateFieldFakeValue } from 'src/modules/workflow/workflow-builder/workflow-schema/utils/should-generate-field-fake-value'; - -const MAXIMUM_DEPTH = 1; +import { camelToTitleCase } from 'src/utils/camel-to-title-case'; export const generateObjectRecordFields = ({ objectMetadataInfo, depth = 0, + maxDepth = 1, }: { objectMetadataInfo: ObjectMetadataInfo; depth?: number; + maxDepth?: number; }): Record => { const objectMetadata = objectMetadataInfo.objectMetadataItemWithFieldsMaps; @@ -35,10 +36,11 @@ export const generateObjectRecordFields = ({ return acc; } - if ( - depth < MAXIMUM_DEPTH && - isDefined(field.relationTargetObjectMetadataId) - ) { + if (!isDefined(field.relationTargetObjectMetadataId)) { + return acc; + } + + if (depth < maxDepth) { const relationTargetObjectMetadata = objectMetadataInfo.objectMetadataMaps.byId[ field.relationTargetObjectMetadataId @@ -62,6 +64,16 @@ export const generateObjectRecordFields = ({ depth: depth + 1, }), }; + } else if (depth === maxDepth) { + const relationIdFieldName = `${field.name}Id`; + const relationIdFieldLabel = camelToTitleCase(relationIdFieldName); + + acc[relationIdFieldName] = generateFakeRecordField({ + type: FieldMetadataType.UUID, + label: relationIdFieldLabel, + icon: field.icon ?? undefined, + fieldMetadataId: field.id, + }); } return acc; diff --git a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-schema/workflow-schema.workspace-service.ts b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-schema/workflow-schema.workspace-service.ts index 74103d9455..a26f023371 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-schema/workflow-schema.workspace-service.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-schema/workflow-schema.workspace-service.ts @@ -117,6 +117,7 @@ export class WorkflowSchemaWorkspaceService { const recordOutputSchema = await this.computeRecordOutputSchema({ objectType, workspaceId, + maxDepth: 0, }); return { @@ -138,9 +139,11 @@ export class WorkflowSchemaWorkspaceService { private async computeRecordOutputSchema({ objectType, workspaceId, + maxDepth = 1, }: { objectType: string; workspaceId: string; + maxDepth?: number; }): Promise { const objectMetadataInfo = await this.workflowCommonWorkspaceService.getObjectMetadataItemWithFieldsMaps( @@ -148,7 +151,7 @@ export class WorkflowSchemaWorkspaceService { workspaceId, ); - return generateFakeObjectRecord({ objectMetadataInfo }); + return generateFakeObjectRecord({ objectMetadataInfo, maxDepth }); } private computeSendEmailActionOutputSchema(): OutputSchema {