From 06ebdc631c732a9f6f7736416c07f0187c0f0df9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Malfait?= Date: Sat, 7 Sep 2024 17:41:09 +0200 Subject: [PATCH 1/5] start playing around --- .../useActivityTargetObjectRecords.test.tsx | 2 - .../hooks/useActivityTargetObjectRecords.ts | 43 +++++++--------- .../components/ActivityTargetsInlineCell.tsx | 1 - .../utils/getLabelIdentifierFieldValue.ts | 8 --- .../RelationFromManyFieldDisplay.tsx | 49 +++++++++++++++---- .../hooks/useRecordTableRecordGqlFields.ts | 25 +++++----- .../views/notes-all.view.ts | 15 ++++-- .../views/tasks-all.view.ts | 19 +++++-- .../standard-objects/note.workspace-entity.ts | 5 +- .../standard-objects/task.workspace-entity.ts | 5 +- 10 files changed, 100 insertions(+), 72 deletions(-) diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetObjectRecords.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetObjectRecords.test.tsx index 15b40d17f5fe..5931ebfe8977 100644 --- a/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetObjectRecords.test.tsx +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetObjectRecords.test.tsx @@ -7,7 +7,6 @@ import { RecoilRoot, useSetRecoilState } from 'recoil'; import { useActivityTargetObjectRecords } from '@/activities/hooks/useActivityTargetObjectRecords'; import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; -import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { getObjectMetadataItemsMock } from '@/object-metadata/utils/getObjectMetadataItemsMock'; import { SnackBarProviderScope } from '@/ui/feedback/snack-bar-manager/scopes/SnackBarProviderScope'; import { JestObjectMetadataItemSetter } from '~/testing/jest/JestObjectMetadataItemSetter'; @@ -130,7 +129,6 @@ describe('useActivityTargetObjectRecords', () => { const { activityTargetObjectRecords } = useActivityTargetObjectRecords( task, - CoreObjectNameSingular.Task, ); return { diff --git a/packages/twenty-front/src/modules/activities/hooks/useActivityTargetObjectRecords.ts b/packages/twenty-front/src/modules/activities/hooks/useActivityTargetObjectRecords.ts index 2fe34d8c2f5e..3eef4a961c6e 100644 --- a/packages/twenty-front/src/modules/activities/hooks/useActivityTargetObjectRecords.ts +++ b/packages/twenty-front/src/modules/activities/hooks/useActivityTargetObjectRecords.ts @@ -1,4 +1,3 @@ -import { useApolloClient } from '@apollo/client'; import { useRecoilValue } from 'recoil'; import { Nullable } from 'twenty-ui'; @@ -7,46 +6,40 @@ import { Note } from '@/activities/types/Note'; import { NoteTarget } from '@/activities/types/NoteTarget'; import { Task } from '@/activities/types/Task'; import { TaskTarget } from '@/activities/types/TaskTarget'; -import { getJoinObjectNameSingular } from '@/activities/utils/getJoinObjectNameSingular'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; -import { useGetRecordFromCache } from '@/object-record/cache/hooks/useGetRecordFromCache'; import { isDefined } from '~/utils/isDefined'; export const useActivityTargetObjectRecords = ( - activity: Task | Note, - objectNameSingular: CoreObjectNameSingular, + activity?: Task | Note, + activityTargets?: NoteTarget[] | TaskTarget[], ) => { const objectMetadataItems = useRecoilValue(objectMetadataItemsState); - const activityTargets = - 'noteTargets' in activity && activity.noteTargets + if(!isDefined(activity) && !isDefined(activityTargets)) { + throw new Error( + `No activity or activity targets`, + ); + } + + const targets = activityTargets ? activityTargets : + (activity && 'noteTargets' in activity && activity.noteTargets ? activity.noteTargets - : 'taskTargets' in activity && activity.taskTargets + : activity && 'taskTargets' in activity && activity.taskTargets ? activity.taskTargets - : []; - - const getRecordFromCache = useGetRecordFromCache({ - objectNameSingular: getJoinObjectNameSingular(objectNameSingular), - }); + : []); - const apolloClient = useApolloClient(); - - const activityTargetObjectRecords = activityTargets + const activityTargetObjectRecords = targets .map>((activityTarget) => { - const activityTargetFromCache = getRecordFromCache< - NoteTarget | TaskTarget - >(activityTarget.id, apolloClient.cache); - - if (!isDefined(activityTargetFromCache)) { + if (!isDefined(activityTarget)) { throw new Error( - `Cannot find activity target ${activityTarget.id} in cache, this shouldn't happen.`, + `Cannot find activity target`, ); } const correspondingObjectMetadataItem = objectMetadataItems.find( (objectMetadataItem) => - isDefined(activityTargetFromCache[objectMetadataItem.nameSingular]) && + isDefined(activityTarget[objectMetadataItem.nameSingular]) && ![CoreObjectNameSingular.Note, CoreObjectNameSingular.Task].includes( objectMetadataItem.nameSingular as CoreObjectNameSingular, ), @@ -57,7 +50,7 @@ export const useActivityTargetObjectRecords = ( } const targetObjectRecord = - activityTargetFromCache[correspondingObjectMetadataItem.nameSingular]; + activityTarget[correspondingObjectMetadataItem.nameSingular]; if (!targetObjectRecord) { throw new Error( @@ -66,7 +59,7 @@ export const useActivityTargetObjectRecords = ( } return { - activityTarget: activityTargetFromCache ?? activityTarget, + activityTarget, targetObject: targetObjectRecord ?? undefined, targetObjectMetadataItem: correspondingObjectMetadataItem, }; diff --git a/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetsInlineCell.tsx b/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetsInlineCell.tsx index 60494d98bd20..f5f287427369 100644 --- a/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetsInlineCell.tsx +++ b/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetsInlineCell.tsx @@ -37,7 +37,6 @@ export const ActivityTargetsInlineCell = ({ }: ActivityTargetsInlineCellProps) => { const { activityTargetObjectRecords } = useActivityTargetObjectRecords( activity, - activityObjectNameSingular, ); const { closeInlineCell } = useInlineCell(); diff --git a/packages/twenty-front/src/modules/object-metadata/utils/getLabelIdentifierFieldValue.ts b/packages/twenty-front/src/modules/object-metadata/utils/getLabelIdentifierFieldValue.ts index d63ff4c20758..001cf4ecb06b 100644 --- a/packages/twenty-front/src/modules/object-metadata/utils/getLabelIdentifierFieldValue.ts +++ b/packages/twenty-front/src/modules/object-metadata/utils/getLabelIdentifierFieldValue.ts @@ -16,14 +16,6 @@ export const getLabelIdentifierFieldValue = ( return `${record.name?.firstName ?? ''} ${record.name?.lastName ?? ''}`; } - if (objectNameSingular === CoreObjectNameSingular.NoteTarget) { - return record.note?.title ?? ''; - } - - if (objectNameSingular === CoreObjectNameSingular.TaskTarget) { - return record.task?.title ?? ''; - } - if (isDefined(labelIdentifierFieldMetadataItem?.name)) { return String(record[labelIdentifierFieldMetadataItem.name]); } diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationFromManyFieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationFromManyFieldDisplay.tsx index adfaea988958..939377c971a5 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationFromManyFieldDisplay.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationFromManyFieldDisplay.tsx @@ -1,6 +1,11 @@ +import { useActivityTargetObjectRecords } from '@/activities/hooks/useActivityTargetObjectRecords'; +import { NoteTarget } from '@/activities/types/NoteTarget'; +import { TaskTarget } from '@/activities/types/TaskTarget'; +import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { RecordChip } from '@/object-record/components/RecordChip'; import { useFieldFocus } from '@/object-record/record-field/hooks/useFieldFocus'; import { useRelationFromManyFieldDisplay } from '@/object-record/record-field/meta-types/hooks/useRelationFromManyFieldDisplay'; +import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { ExpandableList } from '@/ui/layout/expandable-list/components/ExpandableList'; export const RelationFromManyFieldDisplay = () => { @@ -14,17 +19,41 @@ export const RelationFromManyFieldDisplay = () => { return null; } - return ( + const { fieldName, objectMetadataNameSingular } = fieldDefinition.metadata; + + const renderExpandableList = (records: ObjectRecord[], objectNameSingular: string, recordProp = '') => ( - {fieldValue.map((record) => { - return ( - - ); - })} + {records.map((record) => ( + + ))} ); + + if ((fieldName === 'noteTargets' && objectMetadataNameSingular !== CoreObjectNameSingular.Note) || + (fieldName === 'taskTargets' && objectMetadataNameSingular !== CoreObjectNameSingular.Task)) { + const objectNameSingular = fieldName === 'noteTargets' ? CoreObjectNameSingular.Note : CoreObjectNameSingular.Task; + const recordProp = fieldName === 'noteTargets' ? 'note' : 'task'; + return renderExpandableList(fieldValue, objectNameSingular, recordProp); + } + + if ((fieldName === 'taskTargets' && objectMetadataNameSingular === CoreObjectNameSingular.Task) || + (fieldName === 'noteTargets' && objectMetadataNameSingular === CoreObjectNameSingular.Note)) { + const { activityTargetObjectRecords } = useActivityTargetObjectRecords(undefined, fieldValue as NoteTarget[] | TaskTarget[]); + return + {activityTargetObjectRecords.map((record) => ( + + ))} + + + } + + return renderExpandableList(fieldValue, relationObjectNameSingular); }; 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 b9b3e12e8d5b..3948c8a9a0f1 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,7 +1,10 @@ import { useRecoilValue } from 'recoil'; +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 { useRecordTableStates } from '@/object-record/record-table/hooks/internal/useRecordTableStates'; import { isDefined } from '~/utils/isDefined'; @@ -26,6 +29,14 @@ export const useRecordTableRecordGqlFields = ({ if (isDefined(imageIdentifierFieldMetadataItem)) { identifierQueryFields[imageIdentifierFieldMetadataItem.name] = true; } + + const { objectMetadataItem: noteTargetObjectMetadataItem } = useObjectMetadataItem({ + objectNameSingular: CoreObjectNameSingular.NoteTarget, + }); + + const { objectMetadataItem: taskTargetObjectMetadataItem } = useObjectMetadataItem({ + objectNameSingular: CoreObjectNameSingular.TaskTarget, + }); const recordGqlFields: Record = { id: true, @@ -34,18 +45,8 @@ export const useRecordTableRecordGqlFields = ({ ), ...identifierQueryFields, position: true, - noteTargets: { - note: { - id: true, - title: true, - }, - }, - taskTargets: { - task: { - id: true, - title: true, - }, - }, + noteTargets: generateDepthOneRecordGqlFields({ objectMetadataItem: noteTargetObjectMetadataItem }), + taskTargets: generateDepthOneRecordGqlFields({ objectMetadataItem: taskTargetObjectMetadataItem }), }; return recordGqlFields; diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/notes-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/notes-all.view.ts index 658c15cce0dc..97354aa1f2ff 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/notes-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/notes-all.view.ts @@ -30,7 +30,7 @@ export const notesAllView = async ( { fieldMetadataId: objectMetadataMap[STANDARD_OBJECT_IDS.note].fields[ - NOTE_STANDARD_FIELD_IDS.body + NOTE_STANDARD_FIELD_IDS.noteTargets ], position: 1, isVisible: true, @@ -39,7 +39,7 @@ export const notesAllView = async ( { fieldMetadataId: objectMetadataMap[STANDARD_OBJECT_IDS.note].fields[ - NOTE_STANDARD_FIELD_IDS.createdBy + NOTE_STANDARD_FIELD_IDS.body ], position: 2, isVisible: true, @@ -48,12 +48,21 @@ export const notesAllView = async ( { fieldMetadataId: objectMetadataMap[STANDARD_OBJECT_IDS.note].fields[ - BASE_OBJECT_STANDARD_FIELD_IDS.createdAt + NOTE_STANDARD_FIELD_IDS.createdBy ], position: 3, isVisible: true, size: 150, }, + { + fieldMetadataId: + objectMetadataMap[STANDARD_OBJECT_IDS.note].fields[ + BASE_OBJECT_STANDARD_FIELD_IDS.createdAt + ], + position: 4, + isVisible: true, + size: 150, + }, /* TODO: Add later, since we don't have real-time it probably doesn't work well? { diff --git a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-all.view.ts b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-all.view.ts index dc6f5fe5ce25..3d9a0ffadf71 100644 --- a/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-all.view.ts +++ b/packages/twenty-server/src/engine/workspace-manager/standard-objects-prefill-data/views/tasks-all.view.ts @@ -49,7 +49,7 @@ export const tasksAllView = async ( { fieldMetadataId: objectMetadataMap[STANDARD_OBJECT_IDS.task].fields[ - TASK_STANDARD_FIELD_IDS.createdBy + TASK_STANDARD_FIELD_IDS.taskTargets ], position: 3, isVisible: true, @@ -58,7 +58,7 @@ export const tasksAllView = async ( { fieldMetadataId: objectMetadataMap[STANDARD_OBJECT_IDS.task].fields[ - TASK_STANDARD_FIELD_IDS.dueAt + TASK_STANDARD_FIELD_IDS.createdBy ], position: 4, isVisible: true, @@ -67,7 +67,7 @@ export const tasksAllView = async ( { fieldMetadataId: objectMetadataMap[STANDARD_OBJECT_IDS.task].fields[ - TASK_STANDARD_FIELD_IDS.assignee + TASK_STANDARD_FIELD_IDS.dueAt ], position: 5, isVisible: true, @@ -76,7 +76,7 @@ export const tasksAllView = async ( { fieldMetadataId: objectMetadataMap[STANDARD_OBJECT_IDS.task].fields[ - TASK_STANDARD_FIELD_IDS.body + TASK_STANDARD_FIELD_IDS.assignee ], position: 6, isVisible: true, @@ -85,12 +85,21 @@ export const tasksAllView = async ( { fieldMetadataId: objectMetadataMap[STANDARD_OBJECT_IDS.task].fields[ - BASE_OBJECT_STANDARD_FIELD_IDS.createdAt + TASK_STANDARD_FIELD_IDS.body ], position: 7, isVisible: true, size: 150, }, + { + fieldMetadataId: + objectMetadataMap[STANDARD_OBJECT_IDS.task].fields[ + BASE_OBJECT_STANDARD_FIELD_IDS.createdAt + ], + position: 8, + isVisible: true, + size: 150, + }, /* TODO: Add later, since we don't have real-time it probably doesn't work well? { diff --git a/packages/twenty-server/src/modules/note/standard-objects/note.workspace-entity.ts b/packages/twenty-server/src/modules/note/standard-objects/note.workspace-entity.ts index a8aa5b9342c4..e6de81454b3f 100644 --- a/packages/twenty-server/src/modules/note/standard-objects/note.workspace-entity.ts +++ b/packages/twenty-server/src/modules/note/standard-objects/note.workspace-entity.ts @@ -78,15 +78,14 @@ export class NoteWorkspaceEntity extends BaseWorkspaceEntity { @WorkspaceRelation({ standardId: NOTE_STANDARD_FIELD_IDS.noteTargets, - label: 'Targets', + label: 'Relations', description: 'Note targets', - icon: 'IconCheckbox', + icon: 'IconArrowUpRight', type: RelationMetadataType.ONE_TO_MANY, inverseSideTarget: () => NoteTargetWorkspaceEntity, onDelete: RelationOnDeleteAction.SET_NULL, }) @WorkspaceIsNullable() - @WorkspaceIsSystem() noteTargets: Relation; @WorkspaceRelation({ diff --git a/packages/twenty-server/src/modules/task/standard-objects/task.workspace-entity.ts b/packages/twenty-server/src/modules/task/standard-objects/task.workspace-entity.ts index d087d69c6fbd..7ace998603ce 100644 --- a/packages/twenty-server/src/modules/task/standard-objects/task.workspace-entity.ts +++ b/packages/twenty-server/src/modules/task/standard-objects/task.workspace-entity.ts @@ -116,15 +116,14 @@ export class TaskWorkspaceEntity extends BaseWorkspaceEntity { @WorkspaceRelation({ standardId: TASK_STANDARD_FIELD_IDS.taskTargets, - label: 'Targets', + label: 'Relations', description: 'Task targets', - icon: 'IconCheckbox', + icon: 'IconArrowUpRight', type: RelationMetadataType.ONE_TO_MANY, inverseSideTarget: () => TaskTargetWorkspaceEntity, onDelete: RelationOnDeleteAction.SET_NULL, }) @WorkspaceIsNullable() - @WorkspaceIsSystem() taskTargets: Relation; @WorkspaceRelation({ From ca59503edab6e2e9840912d54f03159747288436 Mon Sep 17 00:00:00 2001 From: Lucas Bordeau Date: Wed, 11 Sep 2024 11:08:18 +0200 Subject: [PATCH 2/5] Minor fixes --- .../useActivityTargetObjectRecords.test.tsx | 5 +- .../hooks/useActivityTargetObjectRecords.ts | 19 ++--- .../components/ActivityTargetsInlineCell.tsx | 5 +- .../RelationFromManyFieldDisplay.tsx | 82 ++++++++++++++----- .../hooks/useRecordTableRecordGqlFields.ts | 24 ++++-- .../src/modules/view/services/view.service.ts | 2 +- 6 files changed, 91 insertions(+), 46 deletions(-) diff --git a/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetObjectRecords.test.tsx b/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetObjectRecords.test.tsx index 5931ebfe8977..aa8f2461208d 100644 --- a/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetObjectRecords.test.tsx +++ b/packages/twenty-front/src/modules/activities/hooks/__tests__/useActivityTargetObjectRecords.test.tsx @@ -127,9 +127,8 @@ describe('useActivityTargetObjectRecords', () => { objectMetadataItemsState, ); - const { activityTargetObjectRecords } = useActivityTargetObjectRecords( - task, - ); + const { activityTargetObjectRecords } = + useActivityTargetObjectRecords(task); return { activityTargetObjectRecords, diff --git a/packages/twenty-front/src/modules/activities/hooks/useActivityTargetObjectRecords.ts b/packages/twenty-front/src/modules/activities/hooks/useActivityTargetObjectRecords.ts index 3eef4a961c6e..5671eae34590 100644 --- a/packages/twenty-front/src/modules/activities/hooks/useActivityTargetObjectRecords.ts +++ b/packages/twenty-front/src/modules/activities/hooks/useActivityTargetObjectRecords.ts @@ -16,25 +16,22 @@ export const useActivityTargetObjectRecords = ( ) => { const objectMetadataItems = useRecoilValue(objectMetadataItemsState); - if(!isDefined(activity) && !isDefined(activityTargets)) { - throw new Error( - `No activity or activity targets`, - ); + if (!isDefined(activity) && !isDefined(activityTargets)) { + throw new Error(`No activity or activity targets`); } - const targets = activityTargets ? activityTargets : - (activity && 'noteTargets' in activity && activity.noteTargets + const targets = activityTargets + ? activityTargets + : activity && 'noteTargets' in activity && activity.noteTargets ? activity.noteTargets : activity && 'taskTargets' in activity && activity.taskTargets ? activity.taskTargets - : []); + : []; const activityTargetObjectRecords = targets .map>((activityTarget) => { if (!isDefined(activityTarget)) { - throw new Error( - `Cannot find activity target`, - ); + throw new Error(`Cannot find activity target`); } const correspondingObjectMetadataItem = objectMetadataItems.find( @@ -50,7 +47,7 @@ export const useActivityTargetObjectRecords = ( } const targetObjectRecord = - activityTarget[correspondingObjectMetadataItem.nameSingular]; + activityTarget[correspondingObjectMetadataItem.nameSingular]; if (!targetObjectRecord) { throw new Error( diff --git a/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetsInlineCell.tsx b/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetsInlineCell.tsx index f5f287427369..9f56a3c0ceef 100644 --- a/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetsInlineCell.tsx +++ b/packages/twenty-front/src/modules/activities/inline-cell/components/ActivityTargetsInlineCell.tsx @@ -35,9 +35,8 @@ export const ActivityTargetsInlineCell = ({ readonly, activityObjectNameSingular, }: ActivityTargetsInlineCellProps) => { - const { activityTargetObjectRecords } = useActivityTargetObjectRecords( - activity, - ); + const { activityTargetObjectRecords } = + useActivityTargetObjectRecords(activity); const { closeInlineCell } = useInlineCell(); diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationFromManyFieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationFromManyFieldDisplay.tsx index 939377c971a5..c71e184d3949 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationFromManyFieldDisplay.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationFromManyFieldDisplay.tsx @@ -12,16 +12,25 @@ export const RelationFromManyFieldDisplay = () => { const { fieldValue, fieldDefinition } = useRelationFromManyFieldDisplay(); const { isFocused } = useFieldFocus(); + const { fieldName, objectMetadataNameSingular } = fieldDefinition.metadata; + const relationObjectNameSingular = fieldDefinition?.metadata.relationObjectMetadataNameSingular; + const { activityTargetObjectRecords } = useActivityTargetObjectRecords( + undefined, + fieldValue as NoteTarget[] | TaskTarget[], + ); + if (!fieldValue || !relationObjectNameSingular) { return null; } - const { fieldName, objectMetadataNameSingular } = fieldDefinition.metadata; - - const renderExpandableList = (records: ObjectRecord[], objectNameSingular: string, recordProp = '') => ( + const renderExpandableList = ( + records: ObjectRecord[], + objectNameSingular: string, + recordProp = '', + ) => ( {records.map((record) => ( { ); - if ((fieldName === 'noteTargets' && objectMetadataNameSingular !== CoreObjectNameSingular.Note) || - (fieldName === 'taskTargets' && objectMetadataNameSingular !== CoreObjectNameSingular.Task)) { - const objectNameSingular = fieldName === 'noteTargets' ? CoreObjectNameSingular.Note : CoreObjectNameSingular.Task; + const isRelationFromActivityTargets = + (fieldName === 'noteTargets' && + objectMetadataNameSingular === CoreObjectNameSingular.Note) || + (fieldName === 'taskTargets' && + objectMetadataNameSingular === CoreObjectNameSingular.Task); + + const isRelationFromManyActivities = + (fieldName === 'noteTargets' && + objectMetadataNameSingular !== CoreObjectNameSingular.Note) || + (fieldName === 'taskTargets' && + objectMetadataNameSingular !== CoreObjectNameSingular.Task); + + const isRelationFromManyObjects = + !isRelationFromActivityTargets && !isRelationFromManyActivities; + + console.log({ + fieldName, + objectMetadataNameSingular, + relationObjectNameSingular, + isRelationFromActivityTargets, + isRelationFromManyActivities, + isRelationFromManyObjects, + }); + + if ( + (fieldName === 'noteTargets' && + objectMetadataNameSingular !== CoreObjectNameSingular.Note) || + (fieldName === 'taskTargets' && + objectMetadataNameSingular !== CoreObjectNameSingular.Task) + ) { + const objectNameSingular = + fieldName === 'noteTargets' + ? CoreObjectNameSingular.Note + : CoreObjectNameSingular.Task; const recordProp = fieldName === 'noteTargets' ? 'note' : 'task'; return renderExpandableList(fieldValue, objectNameSingular, recordProp); } - if ((fieldName === 'taskTargets' && objectMetadataNameSingular === CoreObjectNameSingular.Task) || - (fieldName === 'noteTargets' && objectMetadataNameSingular === CoreObjectNameSingular.Note)) { - const { activityTargetObjectRecords } = useActivityTargetObjectRecords(undefined, fieldValue as NoteTarget[] | TaskTarget[]); - return - {activityTargetObjectRecords.map((record) => ( - - ))} - - + if ( + (fieldName === 'taskTargets' && + objectMetadataNameSingular === CoreObjectNameSingular.Task) || + (fieldName === 'noteTargets' && + objectMetadataNameSingular === CoreObjectNameSingular.Note) + ) { + return ( + + {activityTargetObjectRecords.map((record) => ( + + ))} + + ); } return renderExpandableList(fieldValue, relationObjectNameSingular); 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 3948c8a9a0f1..6e9661a120a2 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 @@ -29,14 +29,16 @@ export const useRecordTableRecordGqlFields = ({ if (isDefined(imageIdentifierFieldMetadataItem)) { identifierQueryFields[imageIdentifierFieldMetadataItem.name] = true; } - - const { objectMetadataItem: noteTargetObjectMetadataItem } = useObjectMetadataItem({ - objectNameSingular: CoreObjectNameSingular.NoteTarget, - }); - const { objectMetadataItem: taskTargetObjectMetadataItem } = useObjectMetadataItem({ - objectNameSingular: CoreObjectNameSingular.TaskTarget, - }); + const { objectMetadataItem: noteTargetObjectMetadataItem } = + useObjectMetadataItem({ + objectNameSingular: CoreObjectNameSingular.NoteTarget, + }); + + const { objectMetadataItem: taskTargetObjectMetadataItem } = + useObjectMetadataItem({ + objectNameSingular: CoreObjectNameSingular.TaskTarget, + }); const recordGqlFields: Record = { id: true, @@ -45,8 +47,12 @@ export const useRecordTableRecordGqlFields = ({ ), ...identifierQueryFields, position: true, - noteTargets: generateDepthOneRecordGqlFields({ objectMetadataItem: noteTargetObjectMetadataItem }), - taskTargets: generateDepthOneRecordGqlFields({ objectMetadataItem: taskTargetObjectMetadataItem }), + noteTargets: generateDepthOneRecordGqlFields({ + objectMetadataItem: noteTargetObjectMetadataItem, + }), + taskTargets: generateDepthOneRecordGqlFields({ + objectMetadataItem: taskTargetObjectMetadataItem, + }), }; return recordGqlFields; diff --git a/packages/twenty-server/src/modules/view/services/view.service.ts b/packages/twenty-server/src/modules/view/services/view.service.ts index ed34f8e81dc4..e889db41d112 100644 --- a/packages/twenty-server/src/modules/view/services/view.service.ts +++ b/packages/twenty-server/src/modules/view/services/view.service.ts @@ -23,7 +23,7 @@ export class ViewService { fieldId: string; viewsIds: string[]; positions?: { - [key: string]: number; + [viewId: string]: number; }[]; size?: number; }) { From 6e663e3884d4b51c9c1077078b4f0f8b684bc876 Mon Sep 17 00:00:00 2001 From: Lucas Bordeau Date: Wed, 11 Sep 2024 15:36:25 +0200 Subject: [PATCH 3/5] Refactored display --- .../RelationFromManyFieldDisplay.tsx | 73 +++++++------------ 1 file changed, 27 insertions(+), 46 deletions(-) diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationFromManyFieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationFromManyFieldDisplay.tsx index c71e184d3949..086fe6b33677 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationFromManyFieldDisplay.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/RelationFromManyFieldDisplay.tsx @@ -5,7 +5,6 @@ import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSi import { RecordChip } from '@/object-record/components/RecordChip'; import { useFieldFocus } from '@/object-record/record-field/hooks/useFieldFocus'; import { useRelationFromManyFieldDisplay } from '@/object-record/record-field/meta-types/hooks/useRelationFromManyFieldDisplay'; -import { ObjectRecord } from '@/object-record/types/ObjectRecord'; import { ExpandableList } from '@/ui/layout/expandable-list/components/ExpandableList'; export const RelationFromManyFieldDisplay = () => { @@ -26,22 +25,6 @@ export const RelationFromManyFieldDisplay = () => { return null; } - const renderExpandableList = ( - records: ObjectRecord[], - objectNameSingular: string, - recordProp = '', - ) => ( - - {records.map((record) => ( - - ))} - - ); - const isRelationFromActivityTargets = (fieldName === 'noteTargets' && objectMetadataNameSingular === CoreObjectNameSingular.Note) || @@ -54,38 +37,26 @@ export const RelationFromManyFieldDisplay = () => { (fieldName === 'taskTargets' && objectMetadataNameSingular !== CoreObjectNameSingular.Task); - const isRelationFromManyObjects = - !isRelationFromActivityTargets && !isRelationFromManyActivities; - - console.log({ - fieldName, - objectMetadataNameSingular, - relationObjectNameSingular, - isRelationFromActivityTargets, - isRelationFromManyActivities, - isRelationFromManyObjects, - }); - - if ( - (fieldName === 'noteTargets' && - objectMetadataNameSingular !== CoreObjectNameSingular.Note) || - (fieldName === 'taskTargets' && - objectMetadataNameSingular !== CoreObjectNameSingular.Task) - ) { + if (isRelationFromManyActivities) { const objectNameSingular = fieldName === 'noteTargets' ? CoreObjectNameSingular.Note : CoreObjectNameSingular.Task; - const recordProp = fieldName === 'noteTargets' ? 'note' : 'task'; - return renderExpandableList(fieldValue, objectNameSingular, recordProp); - } - if ( - (fieldName === 'taskTargets' && - objectMetadataNameSingular === CoreObjectNameSingular.Task) || - (fieldName === 'noteTargets' && - objectMetadataNameSingular === CoreObjectNameSingular.Note) - ) { + const relationFieldName = fieldName === 'noteTargets' ? 'note' : 'task'; + + return ( + + {fieldValue.map((record) => ( + + ))} + + ); + } else if (isRelationFromActivityTargets) { return ( {activityTargetObjectRecords.map((record) => ( @@ -97,7 +68,17 @@ export const RelationFromManyFieldDisplay = () => { ))} ); + } else { + return ( + + {fieldValue.map((record) => ( + + ))} + + ); } - - return renderExpandableList(fieldValue, relationObjectNameSingular); }; From 49cf0b84676c5d6a2b6e88316284848e9ac18742 Mon Sep 17 00:00:00 2001 From: Lucas Bordeau Date: Wed, 11 Sep 2024 16:35:24 +0200 Subject: [PATCH 4/5] Fixed story bug --- .../modules/activities/hooks/useActivityTargetObjectRecords.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/twenty-front/src/modules/activities/hooks/useActivityTargetObjectRecords.ts b/packages/twenty-front/src/modules/activities/hooks/useActivityTargetObjectRecords.ts index 5671eae34590..4b8edec3a2a3 100644 --- a/packages/twenty-front/src/modules/activities/hooks/useActivityTargetObjectRecords.ts +++ b/packages/twenty-front/src/modules/activities/hooks/useActivityTargetObjectRecords.ts @@ -17,7 +17,7 @@ export const useActivityTargetObjectRecords = ( const objectMetadataItems = useRecoilValue(objectMetadataItemsState); if (!isDefined(activity) && !isDefined(activityTargets)) { - throw new Error(`No activity or activity targets`); + return { activityTargetObjectRecords: [] }; } const targets = activityTargets From 6e091e424083b7b1219f39bfdd9cacd8776b4fa0 Mon Sep 17 00:00:00 2001 From: Lucas Bordeau Date: Wed, 11 Sep 2024 16:36:16 +0200 Subject: [PATCH 5/5] Added TODO --- .../perf/RelationFromManyFieldDisplay.perf.stories.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RelationFromManyFieldDisplay.perf.stories.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RelationFromManyFieldDisplay.perf.stories.tsx index 96054d36a118..2c6b1977a80e 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RelationFromManyFieldDisplay.perf.stories.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/__stories__/perf/RelationFromManyFieldDisplay.perf.stories.tsx @@ -1,5 +1,5 @@ -import { useEffect } from 'react'; import { Meta, StoryObj } from '@storybook/react'; +import { useEffect } from 'react'; import { useSetRecoilState } from 'recoil'; import { ComponentDecorator } from 'twenty-ui'; @@ -94,9 +94,10 @@ type Story = StoryObj; export const Default: Story = {}; +// TODO: optimize this component once we have morph many export const Performance = getProfilingStory({ componentName: 'RelationFromManyFieldDisplay', - averageThresholdInMs: 0.5, + averageThresholdInMs: 1, numberOfRuns: 20, numberOfTestsPerRun: 100, });