From efab98a8f8b120ab49b01bba23500e498625c8b7 Mon Sep 17 00:00:00 2001 From: Baptiste Devessier Date: Tue, 22 Apr 2025 16:45:36 +0200 Subject: [PATCH] Get all first depth fields in the table and the board (#11650) After discussing it with the team, we now want to query all fields in the table and the board by default. Feeding the cache with exhaustive data will make the side panel's life easier, as it needs all the record fields to determine the actions to enable. --- .../tests/workflow-run.spec.ts | 6 +-- ...OneWithoutRelationsRecordGqlFields.test.ts | 35 +++++++++++++++ .../utils/generateDepthOneRecordGqlFields.ts | 1 + ...DepthOneWithoutRelationsRecordGqlFields.ts | 19 ++++++++ .../useLazyLoadRecordIndexTable.test.tsx | 43 ++++++++++++++++++- .../hooks/useRecordBoardRecordGqlFields.ts | 28 +++--------- .../hooks/useRecordTableRecordGqlFields.ts | 26 +++-------- 7 files changed, 113 insertions(+), 45 deletions(-) create mode 100644 packages/twenty-front/src/modules/object-record/graphql/utils/__tests__/generateDepthOneWithoutRelationsRecordGqlFields.test.ts create mode 100644 packages/twenty-front/src/modules/object-record/graphql/utils/generateDepthOneWithoutRelationsRecordGqlFields.ts diff --git a/packages/twenty-e2e-testing/tests/workflow-run.spec.ts b/packages/twenty-e2e-testing/tests/workflow-run.spec.ts index 70635fa2710..21dccb66120 100644 --- a/packages/twenty-e2e-testing/tests/workflow-run.spec.ts +++ b/packages/twenty-e2e-testing/tests/workflow-run.spec.ts @@ -40,9 +40,9 @@ test('The workflow run visualizer shows the executed draft version without the l await page.goto(executionPageUrl!); - const workflowRunName = page.getByText( - `#1 - ${workflowVisualizer.workflowName}`, - ); + const workflowRunName = page + .getByText(`#1 - ${workflowVisualizer.workflowName}`) + .nth(1); await expect(workflowRunName).toBeVisible(); diff --git a/packages/twenty-front/src/modules/object-record/graphql/utils/__tests__/generateDepthOneWithoutRelationsRecordGqlFields.test.ts b/packages/twenty-front/src/modules/object-record/graphql/utils/__tests__/generateDepthOneWithoutRelationsRecordGqlFields.test.ts new file mode 100644 index 00000000000..8bae151e4d0 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/graphql/utils/__tests__/generateDepthOneWithoutRelationsRecordGqlFields.test.ts @@ -0,0 +1,35 @@ +import { generateDepthOneWithoutRelationsRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneWithoutRelationsRecordGqlFields'; +import { getMockPersonObjectMetadataItem } from '~/testing/mock-data/people'; + +describe('generateDepthOneWithoutRelationsRecordGqlFields', () => { + const objectMetadataItem = getMockPersonObjectMetadataItem(); + it('Should handle basic call with standalone objectMetadataItem', () => { + const result = generateDepthOneWithoutRelationsRecordGqlFields({ + objectMetadataItem, + }); + expect(result).toMatchInlineSnapshot(` +{ + "avatarUrl": true, + "city": true, + "companyId": true, + "createdAt": true, + "createdBy": true, + "deletedAt": true, + "emails": true, + "id": true, + "intro": true, + "jobTitle": true, + "linkedinLink": true, + "name": true, + "performanceRating": true, + "phones": true, + "position": true, + "searchVector": true, + "updatedAt": true, + "whatsapp": true, + "workPreference": true, + "xLink": true, +} +`); + }); +}); diff --git a/packages/twenty-front/src/modules/object-record/graphql/utils/generateDepthOneRecordGqlFields.ts b/packages/twenty-front/src/modules/object-record/graphql/utils/generateDepthOneRecordGqlFields.ts index 0c76661bd62..0e779f98844 100644 --- a/packages/twenty-front/src/modules/object-record/graphql/utils/generateDepthOneRecordGqlFields.ts +++ b/packages/twenty-front/src/modules/object-record/graphql/utils/generateDepthOneRecordGqlFields.ts @@ -3,6 +3,7 @@ import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; export type GenerateDepthOneRecordGqlFields = { objectMetadataItem: ObjectMetadataItem; }; + export const generateDepthOneRecordGqlFields = ({ objectMetadataItem, }: GenerateDepthOneRecordGqlFields) => diff --git a/packages/twenty-front/src/modules/object-record/graphql/utils/generateDepthOneWithoutRelationsRecordGqlFields.ts b/packages/twenty-front/src/modules/object-record/graphql/utils/generateDepthOneWithoutRelationsRecordGqlFields.ts new file mode 100644 index 00000000000..ff656176dea --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/graphql/utils/generateDepthOneWithoutRelationsRecordGqlFields.ts @@ -0,0 +1,19 @@ +import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; +import { FieldMetadataType } from '~/generated/graphql'; + +type GenerateDepthOneWithoutRelationsRecordGqlFields = { + objectMetadataItem: ObjectMetadataItem; +}; + +export const generateDepthOneWithoutRelationsRecordGqlFields = ({ + objectMetadataItem, +}: GenerateDepthOneWithoutRelationsRecordGqlFields) => { + return objectMetadataItem.fields + .filter((field) => field.type !== FieldMetadataType.RELATION) + .reduce>((acc, field) => { + return { + ...acc, + [field.name]: true, + }; + }, {}); +}; diff --git a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useLazyLoadRecordIndexTable.test.tsx b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useLazyLoadRecordIndexTable.test.tsx index f75cdb458cc..48d3354e2b4 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/__tests__/useLazyLoadRecordIndexTable.test.tsx +++ b/packages/twenty-front/src/modules/object-record/hooks/__tests__/useLazyLoadRecordIndexTable.test.tsx @@ -39,8 +39,28 @@ const mocks: MockedResponse[] = [ node { __typename avatarUrl + city + companyId + createdAt + createdBy { + source + workspaceMemberId + name + context + } deletedAt + emails { + primaryEmail + additionalEmails + } id + intro + jobTitle + linkedinLink { + primaryLinkUrl + primaryLinkLabel + secondaryLinks + } name { firstName lastName @@ -287,6 +307,13 @@ const mocks: MockedResponse[] = [ } } } + performanceRating + phones { + primaryPhoneNumber + primaryPhoneCountryCode + primaryPhoneCallingCode + additionalPhones + } position taskTargets { edges { @@ -533,6 +560,19 @@ const mocks: MockedResponse[] = [ } } } + updatedAt + whatsapp { + primaryPhoneNumber + primaryPhoneCountryCode + primaryPhoneCallingCode + additionalPhones + } + workPreference + xLink { + primaryLinkUrl + primaryLinkLabel + secondaryLinks + } } cursor } @@ -625,7 +665,6 @@ describe('useLazyLoadRecordIndexTable', () => { await result.current.findManyRecords(); }); - expect(Array.isArray(result.current.records)).toBe(true); - expect(result.current.records.length).toBe(16); + expect(result.current.records).toHaveLength(16); }); }); diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordBoardRecordGqlFields.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordBoardRecordGqlFields.ts index d7f5e70fce8..857350144d5 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordBoardRecordGqlFields.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordBoardRecordGqlFields.ts @@ -1,9 +1,8 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -import { getObjectMetadataIdentifierFields } from '@/object-metadata/utils/getObjectMetadataIdentifierFields'; -import { hasObjectMetadataItemPositionField } from '@/object-metadata/utils/hasObjectMetadataItemPositionField'; import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields'; +import { generateDepthOneWithoutRelationsRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneWithoutRelationsRecordGqlFields'; import { recordBoardVisibleFieldDefinitionsComponentSelector } from '@/object-record/record-board/states/selectors/recordBoardVisibleFieldDefinitionsComponentSelector'; import { recordGroupFieldMetadataComponentState } from '@/object-record/record-group/states/recordGroupFieldMetadataComponentState'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; @@ -21,24 +20,11 @@ export const useRecordBoardRecordGqlFields = ({ recordBoardId, ); - const { imageIdentifierFieldMetadataItem, labelIdentifierFieldMetadataItem } = - getObjectMetadataIdentifierFields({ objectMetadataItem }); - const recordGroupFieldMetadata = useRecoilComponentValueV2( recordGroupFieldMetadataComponentState, recordBoardId, ); - const identifierQueryFields: Record = {}; - - if (isDefined(labelIdentifierFieldMetadataItem)) { - identifierQueryFields[labelIdentifierFieldMetadataItem.name] = true; - } - - if (isDefined(imageIdentifierFieldMetadataItem)) { - identifierQueryFields[imageIdentifierFieldMetadataItem.name] = true; - } - const { objectMetadataItem: noteTargetObjectMetadataItem } = useObjectMetadataItem({ objectNameSingular: CoreObjectNameSingular.NoteTarget, @@ -49,19 +35,19 @@ export const useRecordBoardRecordGqlFields = ({ objectNameSingular: CoreObjectNameSingular.TaskTarget, }); + const allDepthOneWithoutRelationsRecordGqlFields = + generateDepthOneWithoutRelationsRecordGqlFields({ + objectMetadataItem, + }); + const recordGqlFields: Record = { - id: true, - deletedAt: true, + ...allDepthOneWithoutRelationsRecordGqlFields, ...Object.fromEntries( visibleFieldDefinitions.map((visibleFieldDefinition) => [ visibleFieldDefinition.metadata.fieldName, true, ]), ), - ...(hasObjectMetadataItemPositionField(objectMetadataItem) - ? { position: true } - : undefined), - ...identifierQueryFields, noteTargets: generateDepthOneRecordGqlFields({ objectMetadataItem: noteTargetObjectMetadataItem, }), diff --git a/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordTableRecordGqlFields.ts b/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordTableRecordGqlFields.ts index fcb9092cb24..fc25392e408 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordTableRecordGqlFields.ts +++ b/packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordTableRecordGqlFields.ts @@ -1,34 +1,20 @@ import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; -import { getObjectMetadataIdentifierFields } from '@/object-metadata/utils/getObjectMetadataIdentifierFields'; import { generateDepthOneRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneRecordGqlFields'; +import { generateDepthOneWithoutRelationsRecordGqlFields } from '@/object-record/graphql/utils/generateDepthOneWithoutRelationsRecordGqlFields'; import { visibleTableColumnsComponentSelector } from '@/object-record/record-table/states/selectors/visibleTableColumnsComponentSelector'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; -import { isDefined } from 'twenty-shared/utils'; export const useRecordTableRecordGqlFields = ({ objectMetadataItem, }: { objectMetadataItem: ObjectMetadataItem; }) => { - const { imageIdentifierFieldMetadataItem, labelIdentifierFieldMetadataItem } = - getObjectMetadataIdentifierFields({ objectMetadataItem }); - const visibleTableColumns = useRecoilComponentValueV2( visibleTableColumnsComponentSelector, ); - const identifierQueryFields: Record = {}; - - if (isDefined(labelIdentifierFieldMetadataItem)) { - identifierQueryFields[labelIdentifierFieldMetadataItem.name] = true; - } - - if (isDefined(imageIdentifierFieldMetadataItem)) { - identifierQueryFields[imageIdentifierFieldMetadataItem.name] = true; - } - const { objectMetadataItem: noteTargetObjectMetadataItem } = useObjectMetadataItem({ objectNameSingular: CoreObjectNameSingular.NoteTarget, @@ -39,14 +25,16 @@ export const useRecordTableRecordGqlFields = ({ objectNameSingular: CoreObjectNameSingular.TaskTarget, }); + const allDepthOneWithoutRelationsRecordGqlFields = + generateDepthOneWithoutRelationsRecordGqlFields({ + objectMetadataItem, + }); + const recordGqlFields: Record = { - id: true, - deletedAt: true, + ...allDepthOneWithoutRelationsRecordGqlFields, ...Object.fromEntries( visibleTableColumns.map((column) => [column.metadata.fieldName, true]), ), - ...identifierQueryFields, - position: true, noteTargets: generateDepthOneRecordGqlFields({ objectMetadataItem: noteTargetObjectMetadataItem, }),