From 3901ff3207a806e9fa79406000a9f3f000f2e425 Mon Sep 17 00:00:00 2001 From: Charles Bochet Date: Thu, 13 Mar 2025 19:18:34 +0100 Subject: [PATCH] Fix Side Panel v2 bugs (#10865) Fixing: - Export as PDF on empty note - Command O (sub commands) not using the right contextStore - BelongsToOne Field input triggering an error on open if no existing relation record is pre-selected --- .../RecordActionMenuEntriesSetter.tsx | 23 ++- ...onsConfigV2.ts => DefaultActionsConfig.ts} | 2 +- .../constants/DefaultActionsConfigV1.ts | 188 ------------------ .../hooks/useExportNoteAction.ts | 8 +- .../actions/utils/getActionConfig.ts | 4 +- ...ptionsDropdownRecordGroupFieldsContent.tsx | 2 +- .../RecordDetailRelationSection.tsx | 4 +- ...ttingsServerlessFunctionDetail.stories.tsx | 4 +- 8 files changed, 34 insertions(+), 201 deletions(-) rename packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/{DefaultActionsConfigV2.ts => DefaultActionsConfig.ts} (99%) delete mode 100644 packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV1.ts diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter.tsx index 9ed6235c0..c7c527c2c 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter.tsx @@ -2,7 +2,7 @@ import { RegisterRecordActionEffect } from '@/action-menu/actions/record-actions import { WorkflowRunRecordActionMenuEntrySetterEffect } from '@/action-menu/actions/record-actions/workflow-run-record-actions/components/WorkflowRunRecordActionMenuEntrySetter'; import { getActionConfig } from '@/action-menu/actions/utils/getActionConfig'; import { getActionViewType } from '@/action-menu/actions/utils/getActionViewType'; -import { COMMAND_MENU_COMPONENT_INSTANCE_ID } from '@/command-menu/constants/CommandMenuComponentInstanceId'; +import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; @@ -14,18 +14,31 @@ import { isDefined } from 'twenty-shared'; import { FeatureFlagKey } from '~/generated/graphql'; export const RecordActionMenuEntriesSetter = () => { - const contextStoreCurrentObjectMetadataItemId = useRecoilComponentValueV2( + const localContextStoreCurrentObjectMetadataItemId = + useRecoilComponentValueV2( + contextStoreCurrentObjectMetadataItemIdComponentState, + ); + + const mainContextStoreCurrentObjectMetadataItemId = useRecoilComponentValueV2( contextStoreCurrentObjectMetadataItemIdComponentState, - COMMAND_MENU_COMPONENT_INSTANCE_ID, + MAIN_CONTEXT_STORE_INSTANCE_ID, ); const objectMetadataItems = useRecoilValue(objectMetadataItemsState); - const objectMetadataItem = objectMetadataItems.find( + const localContextStoreObjectMetadataItem = objectMetadataItems.find( (objectMetadataItem) => - objectMetadataItem.id === contextStoreCurrentObjectMetadataItemId, + objectMetadataItem.id === localContextStoreCurrentObjectMetadataItemId, ); + const mainContextStoreObjectMetadataItem = objectMetadataItems.find( + (objectMetadataItem) => + objectMetadataItem.id === mainContextStoreCurrentObjectMetadataItemId, + ); + + const objectMetadataItem = + localContextStoreObjectMetadataItem ?? mainContextStoreObjectMetadataItem; + const contextStoreTargetedRecordsRule = useRecoilComponentValueV2( contextStoreTargetedRecordsRuleComponentState, ); diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV2.ts b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfig.ts similarity index 99% rename from packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV2.ts rename to packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfig.ts index 1ff94fd43..52803a836 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV2.ts +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfig.ts @@ -39,7 +39,7 @@ import { IconTrashX, } from 'twenty-ui'; -export const DEFAULT_ACTIONS_CONFIG_V2: Record< +export const DEFAULT_ACTIONS_CONFIG: Record< string, ActionMenuEntry & { useAction: ActionHook; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV1.ts b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV1.ts deleted file mode 100644 index 2580fa5f1..000000000 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV1.ts +++ /dev/null @@ -1,188 +0,0 @@ -import { useDeleteMultipleRecordsAction } from '@/action-menu/actions/record-actions/multiple-records/hooks/useDeleteMultipleRecordsAction'; -import { useExportMultipleRecordsAction } from '@/action-menu/actions/record-actions/multiple-records/hooks/useExportMultipleRecordsAction'; -import { useRestoreMultipleRecordsAction } from '@/action-menu/actions/record-actions/multiple-records/hooks/useRestoreMultipleRecordsAction'; -import { MultipleRecordsActionKeys } from '@/action-menu/actions/record-actions/multiple-records/types/MultipleRecordsActionKeys'; -import { useImportRecordsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useImportRecordsNoSelectionRecordAction'; -import { useSeeDeletedRecordsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useSeeDeletedRecordsNoSelectionRecordAction'; -import { NoSelectionRecordActionKeys } from '@/action-menu/actions/record-actions/no-selection/types/NoSelectionRecordActionsKey'; -import { useAddToFavoritesSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useAddToFavoritesSingleRecordAction'; -import { useDeleteSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useDeleteSingleRecordAction'; -import { useRemoveFromFavoritesSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useRemoveFromFavoritesSingleRecordAction'; -import { useRestoreSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useRestoreSingleRecordAction'; -import { SingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/types/SingleRecordActionsKey'; -import { ActionHook } from '@/action-menu/actions/types/ActionHook'; -import { ActionViewType } from '@/action-menu/actions/types/ActionViewType'; -import { - ActionMenuEntry, - ActionMenuEntryScope, - ActionMenuEntryType, -} from '@/action-menu/types/ActionMenuEntry'; -import { msg } from '@lingui/core/macro'; -import { - IconDatabaseExport, - IconFileImport, - IconHeart, - IconHeartOff, - IconRefresh, - IconRotate2, - IconTrash, -} from 'twenty-ui'; - -export const DEFAULT_ACTIONS_CONFIG_V1: Record< - string, - ActionMenuEntry & { - useAction: ActionHook; - } -> = { - addToFavoritesSingleRecord: { - type: ActionMenuEntryType.Standard, - scope: ActionMenuEntryScope.RecordSelection, - key: SingleRecordActionKeys.ADD_TO_FAVORITES, - label: msg`Add to favorites`, - position: 0, - Icon: IconHeart, - availableOn: [ - ActionViewType.SHOW_PAGE, - ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, - ], - useAction: useAddToFavoritesSingleRecordAction, - }, - removeFromFavoritesSingleRecord: { - type: ActionMenuEntryType.Standard, - scope: ActionMenuEntryScope.RecordSelection, - key: SingleRecordActionKeys.REMOVE_FROM_FAVORITES, - label: msg`Remove from favorites`, - position: 1, - Icon: IconHeartOff, - availableOn: [ - ActionViewType.SHOW_PAGE, - ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, - ], - useAction: useRemoveFromFavoritesSingleRecordAction, - }, - deleteSingleRecord: { - type: ActionMenuEntryType.Standard, - scope: ActionMenuEntryScope.RecordSelection, - key: SingleRecordActionKeys.DELETE, - label: msg`Delete`, - position: 2, - Icon: IconTrash, - accent: 'danger', - isPinned: true, - availableOn: [ - ActionViewType.SHOW_PAGE, - ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, - ], - useAction: useDeleteSingleRecordAction, - }, - deleteMultipleRecords: { - type: ActionMenuEntryType.Standard, - scope: ActionMenuEntryScope.RecordSelection, - key: MultipleRecordsActionKeys.DELETE, - label: msg`Delete records`, - shortLabel: msg`Delete`, - position: 3, - Icon: IconTrash, - accent: 'danger', - isPinned: true, - availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION], - useAction: useDeleteMultipleRecordsAction, - }, - exportSingleRecord: { - type: ActionMenuEntryType.Standard, - scope: ActionMenuEntryScope.RecordSelection, - key: SingleRecordActionKeys.EXPORT, - label: msg`Export record`, - shortLabel: msg`Export`, - position: 4, - Icon: IconDatabaseExport, - accent: 'default', - isPinned: false, - availableOn: [ - ActionViewType.SHOW_PAGE, - ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, - ], - useAction: useExportMultipleRecordsAction, - }, - exportMultipleRecords: { - type: ActionMenuEntryType.Standard, - scope: ActionMenuEntryScope.RecordSelection, - key: MultipleRecordsActionKeys.EXPORT, - label: msg`Export records`, - shortLabel: msg`Export`, - position: 5, - Icon: IconDatabaseExport, - accent: 'default', - isPinned: false, - availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION], - useAction: useExportMultipleRecordsAction, - }, - exportView: { - type: ActionMenuEntryType.Standard, - scope: ActionMenuEntryScope.Object, - key: NoSelectionRecordActionKeys.EXPORT_VIEW, - label: msg`Export view`, - shortLabel: msg`Export`, - position: 6, - Icon: IconDatabaseExport, - accent: 'default', - isPinned: false, - availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], - useAction: useExportMultipleRecordsAction, - }, - restoreSingleRecord: { - type: ActionMenuEntryType.Standard, - scope: ActionMenuEntryScope.RecordSelection, - key: SingleRecordActionKeys.RESTORE, - label: msg`Restore record`, - shortLabel: msg`Restore`, - position: 7, - Icon: IconRefresh, - accent: 'default', - isPinned: true, - availableOn: [ - ActionViewType.SHOW_PAGE, - ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, - ], - useAction: useRestoreSingleRecordAction, - }, - restoreMultipleRecords: { - type: ActionMenuEntryType.Standard, - scope: ActionMenuEntryScope.RecordSelection, - key: MultipleRecordsActionKeys.RESTORE, - label: msg`Restore records`, - shortLabel: msg`Restore`, - position: 8, - Icon: IconRefresh, - accent: 'default', - isPinned: true, - availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION], - useAction: useRestoreMultipleRecordsAction, - }, - seeDeletedRecords: { - type: ActionMenuEntryType.Standard, - scope: ActionMenuEntryScope.Object, - key: NoSelectionRecordActionKeys.SEE_DELETED_RECORDS, - label: msg`See deleted records`, - shortLabel: msg`Deleted records`, - position: 9, - Icon: IconRotate2, - accent: 'default', - isPinned: false, - availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], - useAction: useSeeDeletedRecordsNoSelectionRecordAction, - }, - importRecords: { - type: ActionMenuEntryType.Standard, - scope: ActionMenuEntryScope.Object, - key: NoSelectionRecordActionKeys.IMPORT_RECORDS, - label: msg`Import records`, - shortLabel: msg`Import`, - position: 10, - Icon: IconFileImport, - accent: 'default', - isPinned: false, - availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], - useAction: useImportRecordsNoSelectionRecordAction, - }, -}; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useExportNoteAction.ts b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useExportNoteAction.ts index abeb3d5b3..e32c37db8 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useExportNoteAction.ts +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useExportNoteAction.ts @@ -3,6 +3,7 @@ import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/Ac import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { BlockNoteEditor } from '@blocknote/core'; +import { isNonEmptyString } from '@sniptt/guards'; import { useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared'; @@ -20,10 +21,13 @@ export const useExportNoteAction: ActionHookWithObjectMetadataItem = ({ objectMetadataItem?.nameSingular === CoreObjectNameSingular.Task; const shouldBeRegistered = - isDefined(objectMetadataItem) && isDefined(selectedRecord) && isNoteOrTask; + isDefined(objectMetadataItem) && + isDefined(selectedRecord) && + isNoteOrTask && + isNonEmptyString(selectedRecord.bodyV2?.blocknote); const onClick = async () => { - if (!shouldBeRegistered || !selectedRecord?.body) { + if (!shouldBeRegistered || !selectedRecord.bodyV2.blocknote) { return; } diff --git a/packages/twenty-front/src/modules/action-menu/actions/utils/getActionConfig.ts b/packages/twenty-front/src/modules/action-menu/actions/utils/getActionConfig.ts index a7df5d492..3ab53f1d0 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/utils/getActionConfig.ts +++ b/packages/twenty-front/src/modules/action-menu/actions/utils/getActionConfig.ts @@ -1,4 +1,4 @@ -import { DEFAULT_ACTIONS_CONFIG_V2 } from '@/action-menu/actions/record-actions/constants/DefaultActionsConfigV2'; +import { DEFAULT_ACTIONS_CONFIG } from '@/action-menu/actions/record-actions/constants/DefaultActionsConfig'; import { WORKFLOW_ACTIONS_CONFIG } from '@/action-menu/actions/record-actions/constants/WorkflowActionsConfig'; import { WORKFLOW_RUNS_ACTIONS_CONFIG } from '@/action-menu/actions/record-actions/constants/WorkflowRunsActionsConfig'; import { WORKFLOW_VERSIONS_ACTIONS_CONFIG } from '@/action-menu/actions/record-actions/constants/WorkflowVersionsActionsConfig'; @@ -14,6 +14,6 @@ export const getActionConfig = (objectMetadataItem: ObjectMetadataItem) => { case CoreObjectNameSingular.WorkflowRun: return WORKFLOW_RUNS_ACTIONS_CONFIG; default: - return DEFAULT_ACTIONS_CONFIG_V2; + return DEFAULT_ACTIONS_CONFIG; } }; diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupFieldsContent.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupFieldsContent.tsx index 5cdfebfe0..1287b0e99 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupFieldsContent.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownRecordGroupFieldsContent.tsx @@ -140,7 +140,7 @@ export const ObjectOptionsDropdownRecordGroupFieldsContent = () => { ))} - + { diff --git a/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/RecordDetailRelationSection.tsx b/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/RecordDetailRelationSection.tsx index bccdd865f..5cad617bf 100644 --- a/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/RecordDetailRelationSection.tsx +++ b/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/RecordDetailRelationSection.tsx @@ -197,7 +197,9 @@ export const RecordDetailRelationSection = ({ const handleOpenRelationPickerDropdown = () => { if (isToOneObject) { setSingleRecordPickerSearchFilter(''); - setSingleRecordPickerSelectedId(relationRecords[0].id); + if (relationRecords.length > 0) { + setSingleRecordPickerSelectedId(relationRecords[0].id); + } } if (isToManyObjects) { diff --git a/packages/twenty-front/src/pages/settings/serverless-functions/__stories__/SettingsServerlessFunctionDetail.stories.tsx b/packages/twenty-front/src/pages/settings/serverless-functions/__stories__/SettingsServerlessFunctionDetail.stories.tsx index 5a0fcf25d..7a9a1cb36 100644 --- a/packages/twenty-front/src/pages/settings/serverless-functions/__stories__/SettingsServerlessFunctionDetail.stories.tsx +++ b/packages/twenty-front/src/pages/settings/serverless-functions/__stories__/SettingsServerlessFunctionDetail.stories.tsx @@ -65,6 +65,8 @@ export const Default: Story = { play: async ({ canvasElement }) => { const canvas = within(canvasElement); await sleep(100); - await canvas.findByText('Code your function'); + await canvas.findByText('Code your function', undefined, { + timeout: 3000, + }); }, };