From 3c3d837cb7caad6ebc67598a48aab66ec44ac510 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Bosi?= <71827178+bosiraphael@users.noreply.github.com> Date: Thu, 20 Nov 2025 10:57:33 +0100 Subject: [PATCH] Introduce primary actions (#15826) - These actions are displayed in the accent color - Added new context store state `contextStoreIsPageInEditModeComponentState` - Reverted the order in which the actions are displayed (the first action should appear to the right of the top bar action menu) https://github.com/user-attachments/assets/3a0769cf-61ed-4619-8c4d-e3a01765b63c --- .../display/components/ActionButton.tsx | 6 +- .../display/components/ActionDisplay.tsx | 1 + .../constants/DashboardActionsConfig.tsx | 126 ++-- .../constants/DefaultRecordActionsConfig.tsx | 597 +++++++++--------- .../RecordPageLayoutActionsConfig.tsx | 8 +- .../constants/WorkflowActionsConfig.tsx | 229 +++---- .../constants/WorkflowRunsActionsConfig.tsx | 67 +- .../WorkflowVersionsActionsConfig.tsx | 52 +- .../action-menu/actions/types/ActionConfig.ts | 1 + .../actions/types/ActionViewType.ts | 1 + .../PageHeaderActionMenuButtons.tsx | 2 +- .../action-menu/hooks/useRegisteredActions.ts | 29 +- .../useExecuteTasksOnAnyLocationChange.ts | 18 + .../useCopyContextStoreAndActionMenuStates.ts | 16 + .../hooks/useOpenRecordInCommandMenu.ts | 14 + ...textStoreIsPageInEditModeComponentState.ts | 9 + .../hooks/useSetIsPageLayoutInEditMode.ts | 26 +- 17 files changed, 633 insertions(+), 569 deletions(-) create mode 100644 packages/twenty-front/src/modules/context-store/states/contextStoreIsPageInEditModeComponentState.ts diff --git a/packages/twenty-front/src/modules/action-menu/actions/display/components/ActionButton.tsx b/packages/twenty-front/src/modules/action-menu/actions/display/components/ActionButton.tsx index 97904db1a29..3a3fd0296f7 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/display/components/ActionButton.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/display/components/ActionButton.tsx @@ -24,6 +24,8 @@ export const ActionButton = ({ ? getActionLabel(action.shortLabel) : undefined; + const buttonAccent = action.isPrimaryCTA ? 'blue' : 'default'; + return ( <> {action.shortLabel ? ( @@ -31,7 +33,7 @@ export const ActionButton = ({ Icon={action.Icon} size="small" variant="secondary" - accent="default" + accent={buttonAccent} to={to} onClick={onClick} title={shortLabel} @@ -43,7 +45,7 @@ export const ActionButton = ({ Icon={action.Icon} size="small" variant="secondary" - accent="default" + accent={buttonAccent} to={to} onClick={onClick} ariaLabel={label} diff --git a/packages/twenty-front/src/modules/action-menu/actions/display/components/ActionDisplay.tsx b/packages/twenty-front/src/modules/action-menu/actions/display/components/ActionDisplay.tsx index 1d851151b3c..0676f813329 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/display/components/ActionDisplay.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/display/components/ActionDisplay.tsx @@ -15,6 +15,7 @@ export type ActionDisplayProps = { shortLabel?: MessageDescriptor | string; description?: MessageDescriptor | string; Icon: IconComponent; + isPrimaryCTA?: boolean; accent?: MenuItemAccent; hotKeys?: string[]; }; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DashboardActionsConfig.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DashboardActionsConfig.tsx index 590520b063c..229a345f2a3 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DashboardActionsConfig.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DashboardActionsConfig.tsx @@ -1,5 +1,4 @@ import { NoSelectionRecordActionKeys } from '@/action-menu/actions/record-actions/no-selection/types/NoSelectionRecordActionsKeys'; -import { AddToFavoritesSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/components/AddToFavoritesSingleRecordAction'; import { CancelDashboardSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/dashboard-actions/components/CancelDashboardSingleRecordAction'; import { EditDashboardSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/dashboard-actions/components/EditDashboardSingleRecordAction'; import { SaveDashboardSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/dashboard-actions/components/SaveDashboardSingleRecordAction'; @@ -11,37 +10,16 @@ import { ActionViewType } from '@/action-menu/actions/types/ActionViewType'; import { PageLayoutSingleRecordActionKeys } from '@/page-layout/actions/PageLayoutSingleRecordActionKeys'; import { msg } from '@lingui/core/macro'; import { isDefined } from 'twenty-shared/utils'; -import { - IconDeviceFloppy, - IconHeart, - IconPencil, - IconX, -} from 'twenty-ui/display'; +import { IconDeviceFloppy, IconPencil, IconX } from 'twenty-ui/display'; export const DASHBOARD_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({ config: { - [PageLayoutSingleRecordActionKeys.ADD_TO_FAVORITES_READ_MODE]: { - key: PageLayoutSingleRecordActionKeys.ADD_TO_FAVORITES_READ_MODE, - label: msg`Add to favorites`, - shortLabel: msg`Add to favorites`, - isPinned: true, - position: 0, - Icon: IconHeart, - type: ActionType.Standard, - scope: ActionScope.RecordSelection, - shouldBeRegistered: ({ selectedRecord }) => - isDefined(selectedRecord) && - !selectedRecord?.isRemote && - !isDefined(selectedRecord?.deletedAt), - availableOn: [ActionViewType.SHOW_PAGE], - component: , - }, [PageLayoutSingleRecordActionKeys.EDIT_LAYOUT]: { key: PageLayoutSingleRecordActionKeys.EDIT_LAYOUT, label: msg`Edit Dashboard`, shortLabel: msg`Edit`, isPinned: true, - position: 1, + position: 3, Icon: IconPencil, type: ActionType.Standard, scope: ActionScope.RecordSelection, @@ -53,29 +31,13 @@ export const DASHBOARD_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({ availableOn: [ActionViewType.SHOW_PAGE], component: , }, - [PageLayoutSingleRecordActionKeys.CANCEL_LAYOUT_EDITION]: { - key: PageLayoutSingleRecordActionKeys.CANCEL_LAYOUT_EDITION, - label: msg`Cancel Edition`, - shortLabel: msg`Cancel`, - isPinned: true, - position: 0, - Icon: IconX, - type: ActionType.Standard, - scope: ActionScope.RecordSelection, - shouldBeRegistered: ({ selectedRecord }) => - isDefined(selectedRecord) && - !selectedRecord?.isRemote && - !isDefined(selectedRecord?.deletedAt) && - isDefined(selectedRecord?.pageLayoutId), - availableOn: [ActionViewType.SHOW_PAGE], - component: , - }, [PageLayoutSingleRecordActionKeys.SAVE_LAYOUT]: { key: PageLayoutSingleRecordActionKeys.SAVE_LAYOUT, label: msg`Save Dashboard`, shortLabel: msg`Save`, isPinned: true, - position: 1, + isPrimaryCTA: true, + position: 4, Icon: IconDeviceFloppy, type: ActionType.Standard, scope: ActionScope.RecordSelection, @@ -84,9 +46,26 @@ export const DASHBOARD_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({ !selectedRecord?.isRemote && !isDefined(selectedRecord?.deletedAt) && isDefined(selectedRecord?.pageLayoutId), - availableOn: [ActionViewType.SHOW_PAGE], + availableOn: [ActionViewType.PAGE_EDIT_MODE], component: , }, + [PageLayoutSingleRecordActionKeys.CANCEL_LAYOUT_EDITION]: { + key: PageLayoutSingleRecordActionKeys.CANCEL_LAYOUT_EDITION, + label: msg`Cancel Edition`, + shortLabel: msg`Cancel`, + isPinned: true, + position: 5, + Icon: IconX, + type: ActionType.Standard, + scope: ActionScope.RecordSelection, + shouldBeRegistered: ({ selectedRecord }) => + isDefined(selectedRecord) && + !selectedRecord?.isRemote && + !isDefined(selectedRecord?.deletedAt) && + isDefined(selectedRecord?.pageLayoutId), + availableOn: [ActionViewType.PAGE_EDIT_MODE], + component: , + }, }, actionKeys: [ NoSelectionRecordActionKeys.CREATE_NEW_RECORD, @@ -107,61 +86,62 @@ export const DASHBOARD_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({ NoSelectionRecordActionKeys.GO_TO_NOTES, ], propertiesToOverwrite: { - [NoSelectionRecordActionKeys.CREATE_NEW_RECORD]: { + [SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD]: { position: 0, + label: msg`Navigate to next dashboard`, + }, + [SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD]: { + position: 1, + label: msg`Navigate to previous dashboard`, + }, + [NoSelectionRecordActionKeys.CREATE_NEW_RECORD]: { + position: 2, label: msg`Create new dashboard`, }, - [SingleRecordActionKeys.ADD_TO_FAVORITES]: { - position: 3, - isPinned: false, - }, - [SingleRecordActionKeys.REMOVE_FROM_FAVORITES]: { - position: 4, - }, [SingleRecordActionKeys.DELETE]: { - position: 2, + position: 6, label: msg`Delete dashboard`, }, + [SingleRecordActionKeys.ADD_TO_FAVORITES]: { + position: 7, + isPinned: true, + }, + [SingleRecordActionKeys.REMOVE_FROM_FAVORITES]: { + position: 8, + isPinned: true, + }, [SingleRecordActionKeys.EXPORT_FROM_RECORD_SHOW]: { - position: 5, + position: 9, label: msg`Export dashboard`, }, [SingleRecordActionKeys.DESTROY]: { - position: 6, + position: 10, label: msg`Permanently destroy dashboard`, }, [SingleRecordActionKeys.RESTORE]: { - position: 7, + position: 11, label: msg`Restore dashboard`, }, - [SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD]: { - position: 8, - label: msg`Navigate to previous dashboard`, - }, - [SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD]: { - position: 9, - label: msg`Navigate to next dashboard`, - }, [NoSelectionRecordActionKeys.GO_TO_WORKFLOWS]: { - position: 10, - }, - [NoSelectionRecordActionKeys.GO_TO_PEOPLE]: { - position: 11, - }, - [NoSelectionRecordActionKeys.GO_TO_COMPANIES]: { position: 12, }, - [NoSelectionRecordActionKeys.GO_TO_OPPORTUNITIES]: { + [NoSelectionRecordActionKeys.GO_TO_PEOPLE]: { position: 13, }, - [NoSelectionRecordActionKeys.GO_TO_SETTINGS]: { + [NoSelectionRecordActionKeys.GO_TO_COMPANIES]: { position: 14, }, - [NoSelectionRecordActionKeys.GO_TO_TASKS]: { + [NoSelectionRecordActionKeys.GO_TO_OPPORTUNITIES]: { position: 15, }, - [NoSelectionRecordActionKeys.GO_TO_NOTES]: { + [NoSelectionRecordActionKeys.GO_TO_SETTINGS]: { position: 16, }, + [NoSelectionRecordActionKeys.GO_TO_TASKS]: { + position: 17, + }, + [NoSelectionRecordActionKeys.GO_TO_NOTES]: { + position: 18, + }, }, }); diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultRecordActionsConfig.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultRecordActionsConfig.tsx index 026b85cd052..7aafd48006b 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultRecordActionsConfig.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultRecordActionsConfig.tsx @@ -65,13 +65,37 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record< | MultipleRecordsActionKeys, ActionConfig > = { + [SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD]: { + type: ActionType.Standard, + scope: ActionScope.RecordSelection, + key: SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD, + label: msg`Navigate to next record`, + position: 0, + isPinned: true, + Icon: IconChevronDown, + shouldBeRegistered: ({ isInRightDrawer }) => !isInRightDrawer, + availableOn: [ActionViewType.SHOW_PAGE], + component: , + }, + [SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD]: { + type: ActionType.Standard, + scope: ActionScope.RecordSelection, + key: SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD, + label: msg`Navigate to previous record`, + position: 1, + isPinned: true, + Icon: IconChevronUp, + shouldBeRegistered: ({ isInRightDrawer }) => !isInRightDrawer, + availableOn: [ActionViewType.SHOW_PAGE], + component: , + }, [NoSelectionRecordActionKeys.CREATE_NEW_RECORD]: { type: ActionType.Standard, scope: ActionScope.Object, key: NoSelectionRecordActionKeys.CREATE_NEW_RECORD, label: msg`Create new record`, shortLabel: msg`New record`, - position: 0, + position: 2, isPinned: true, Icon: IconPlus, shouldBeRegistered: ({ objectPermissions, hasAnySoftDeleteFilterOnView }) => @@ -81,180 +105,13 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record< availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], component: , }, - [SingleRecordActionKeys.EXPORT_NOTE_TO_PDF]: { - type: ActionType.Standard, - scope: ActionScope.RecordSelection, - key: SingleRecordActionKeys.EXPORT_NOTE_TO_PDF, - label: msg`Export to PDF`, - shortLabel: msg`Export`, - position: 1, - isPinned: false, - Icon: IconFileExport, - shouldBeRegistered: ({ selectedRecord, isNoteOrTask }) => - isDefined(isNoteOrTask) && - isNoteOrTask && - isNonEmptyString(selectedRecord?.bodyV2?.blocknote), - availableOn: [ActionViewType.SHOW_PAGE], - component: , - }, - [SingleRecordActionKeys.ADD_TO_FAVORITES]: { - type: ActionType.Standard, - scope: ActionScope.RecordSelection, - key: SingleRecordActionKeys.ADD_TO_FAVORITES, - label: msg`Add to favorites`, - shortLabel: msg`Add to favorites`, - position: 2, - isPinned: true, - Icon: IconHeart, - shouldBeRegistered: ({ - selectedRecord, - isFavorite, - hasAnySoftDeleteFilterOnView, - }) => - !selectedRecord?.isRemote && - !isFavorite && - !isDefined(selectedRecord?.deletedAt) && - !hasAnySoftDeleteFilterOnView, - availableOn: [ - ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, - ActionViewType.SHOW_PAGE, - ], - component: , - }, - [SingleRecordActionKeys.REMOVE_FROM_FAVORITES]: { - type: ActionType.Standard, - scope: ActionScope.RecordSelection, - key: SingleRecordActionKeys.REMOVE_FROM_FAVORITES, - label: msg`Remove from favorites`, - shortLabel: msg`Remove from favorites`, - isPinned: true, - position: 3, - Icon: IconHeartOff, - shouldBeRegistered: ({ - selectedRecord, - isFavorite, - hasAnySoftDeleteFilterOnView, - }) => - isDefined(selectedRecord) && - !selectedRecord?.isRemote && - isDefined(isFavorite) && - isFavorite && - !isDefined(selectedRecord?.deletedAt) && - !hasAnySoftDeleteFilterOnView, - availableOn: [ - ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, - ActionViewType.SHOW_PAGE, - ], - component: , - }, - [SingleRecordActionKeys.EXPORT_FROM_RECORD_INDEX]: { - type: ActionType.Standard, - scope: ActionScope.RecordSelection, - key: SingleRecordActionKeys.EXPORT_FROM_RECORD_INDEX, - label: msg`Export`, - shortLabel: msg`Export`, - position: 4, - Icon: IconFileExport, - accent: 'default', - isPinned: false, - shouldBeRegistered: ({ selectedRecord }) => - isDefined(selectedRecord) && !selectedRecord.isRemote, - availableOn: [ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION], - component: , - requiredPermissionFlag: PermissionFlagType.EXPORT_CSV, - }, - [SingleRecordActionKeys.EXPORT_FROM_RECORD_SHOW]: { - type: ActionType.Standard, - scope: ActionScope.RecordSelection, - key: SingleRecordActionKeys.EXPORT_FROM_RECORD_SHOW, - label: msg`Export`, - shortLabel: msg`Export`, - position: 4, - Icon: IconFileExport, - accent: 'default', - isPinned: false, - shouldBeRegistered: ({ selectedRecord }) => - isDefined(selectedRecord) && !selectedRecord.isRemote, - availableOn: [ActionViewType.SHOW_PAGE], - component: , - requiredPermissionFlag: PermissionFlagType.EXPORT_CSV, - }, - [MultipleRecordsActionKeys.MERGE]: { - type: ActionType.Standard, - scope: ActionScope.RecordSelection, - key: MultipleRecordsActionKeys.MERGE, - label: msg`Merge records`, - shortLabel: msg`Merge`, - position: 5, - Icon: IconArrowMerge, - accent: 'default', - isPinned: false, - shouldBeRegistered: ({ - objectMetadataItem, - numberOfSelectedRecords, - objectPermissions, - }) => - isDefined(objectMetadataItem?.duplicateCriteria) && - isDefined(numberOfSelectedRecords) && - Boolean(objectPermissions.canUpdateObjectRecords) && - Boolean(objectPermissions.canDestroyObjectRecords) && - numberOfSelectedRecords <= MUTATION_MAX_MERGE_RECORDS, - availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION], - component: , - }, - [MultipleRecordsActionKeys.EXPORT]: { - type: ActionType.Standard, - scope: ActionScope.RecordSelection, - key: MultipleRecordsActionKeys.EXPORT, - label: msg`Export records`, - shortLabel: msg`Export`, - position: 6, - Icon: IconFileExport, - accent: 'default', - isPinned: false, - shouldBeRegistered: () => true, - availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION], - component: , - requiredPermissionFlag: PermissionFlagType.EXPORT_CSV, - }, - [NoSelectionRecordActionKeys.IMPORT_RECORDS]: { - type: ActionType.Standard, - scope: ActionScope.Object, - key: NoSelectionRecordActionKeys.IMPORT_RECORDS, - label: msg`Import records`, - shortLabel: msg`Import`, - position: 7, - Icon: IconFileImport, - accent: 'default', - isPinned: false, - shouldBeRegistered: ({ hasAnySoftDeleteFilterOnView }) => - !hasAnySoftDeleteFilterOnView, - availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], - component: , - requiredPermissionFlag: PermissionFlagType.IMPORT_CSV, - }, - [NoSelectionRecordActionKeys.EXPORT_VIEW]: { - type: ActionType.Standard, - scope: ActionScope.Object, - key: NoSelectionRecordActionKeys.EXPORT_VIEW, - label: msg`Export view`, - shortLabel: msg`Export`, - position: 8, - Icon: IconFileExport, - accent: 'default', - isPinned: false, - shouldBeRegistered: () => true, - availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], - component: , - requiredPermissionFlag: PermissionFlagType.EXPORT_CSV, - }, [SingleRecordActionKeys.DELETE]: { type: ActionType.Standard, scope: ActionScope.RecordSelection, key: SingleRecordActionKeys.DELETE, label: msg`Delete`, shortLabel: msg`Delete`, - position: 9, + position: 3, Icon: IconTrash, accent: 'default', isPinned: true, @@ -281,7 +138,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record< key: MultipleRecordsActionKeys.DELETE, label: msg`Delete records`, shortLabel: msg`Delete`, - position: 10, + position: 4, Icon: IconTrash, accent: 'default', isPinned: true, @@ -300,129 +157,13 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record< availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION], component: , }, - [NoSelectionRecordActionKeys.SEE_DELETED_RECORDS]: { - type: ActionType.Standard, - scope: ActionScope.Object, - key: NoSelectionRecordActionKeys.SEE_DELETED_RECORDS, - label: msg`See deleted records`, - shortLabel: msg`Deleted records`, - position: 11, - Icon: IconRotate2, - accent: 'default', - isPinned: false, - shouldBeRegistered: ({ hasAnySoftDeleteFilterOnView }) => - !hasAnySoftDeleteFilterOnView, - availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], - component: , - }, - [NoSelectionRecordActionKeys.CREATE_NEW_VIEW]: { - type: ActionType.Standard, - scope: ActionScope.Object, - key: NoSelectionRecordActionKeys.CREATE_NEW_VIEW, - label: msg`Create View`, - shortLabel: msg`Create View`, - position: 12, - Icon: IconLayout, - accent: 'default', - isPinned: false, - shouldBeRegistered: ({ hasAnySoftDeleteFilterOnView }) => - !hasAnySoftDeleteFilterOnView, - availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], - component: , - }, - [NoSelectionRecordActionKeys.HIDE_DELETED_RECORDS]: { - type: ActionType.Standard, - scope: ActionScope.Object, - key: NoSelectionRecordActionKeys.HIDE_DELETED_RECORDS, - label: msg`Hide deleted records`, - shortLabel: msg`Hide deleted`, - position: 13, - Icon: IconEyeOff, - accent: 'default', - isPinned: false, - shouldBeRegistered: ({ hasAnySoftDeleteFilterOnView }) => - isDefined(hasAnySoftDeleteFilterOnView) && hasAnySoftDeleteFilterOnView, - availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], - component: , - }, - [SingleRecordActionKeys.DESTROY]: { - type: ActionType.Standard, - scope: ActionScope.RecordSelection, - key: SingleRecordActionKeys.DESTROY, - label: msg`Permanently destroy record`, - shortLabel: msg`Destroy`, - position: 14, - Icon: IconTrashX, - accent: 'danger', - isPinned: true, - shouldBeRegistered: ({ selectedRecord, objectPermissions, isRemote }) => - (objectPermissions.canDestroyObjectRecords && - !isRemote && - isDefined(selectedRecord?.deletedAt)) ?? - false, - availableOn: [ - ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, - ActionViewType.SHOW_PAGE, - ], - component: , - }, - [SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD]: { - type: ActionType.Standard, - scope: ActionScope.RecordSelection, - key: SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD, - label: msg`Navigate to previous record`, - position: 15, - isPinned: true, - Icon: IconChevronUp, - shouldBeRegistered: ({ isInRightDrawer }) => !isInRightDrawer, - availableOn: [ActionViewType.SHOW_PAGE], - component: , - }, - [SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD]: { - type: ActionType.Standard, - scope: ActionScope.RecordSelection, - key: SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD, - label: msg`Navigate to next record`, - position: 16, - isPinned: true, - Icon: IconChevronDown, - shouldBeRegistered: ({ isInRightDrawer }) => !isInRightDrawer, - availableOn: [ActionViewType.SHOW_PAGE], - component: , - }, - [MultipleRecordsActionKeys.DESTROY]: { - type: ActionType.Standard, - scope: ActionScope.RecordSelection, - key: MultipleRecordsActionKeys.DESTROY, - label: msg`Permanently destroy records`, - shortLabel: msg`Destroy`, - position: 17, - Icon: IconTrashX, - accent: 'danger', - isPinned: true, - shouldBeRegistered: ({ - objectPermissions, - isRemote, - hasAnySoftDeleteFilterOnView, - numberOfSelectedRecords, - }) => - (objectPermissions.canDestroyObjectRecords && - !isRemote && - isDefined(hasAnySoftDeleteFilterOnView) && - hasAnySoftDeleteFilterOnView && - isDefined(numberOfSelectedRecords) && - numberOfSelectedRecords < BACKEND_BATCH_REQUEST_MAX_COUNT) ?? - false, - availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION], - component: , - }, [SingleRecordActionKeys.RESTORE]: { type: ActionType.Standard, scope: ActionScope.RecordSelection, key: SingleRecordActionKeys.RESTORE, label: msg`Restore record`, shortLabel: msg`Restore`, - position: 18, + position: 5, Icon: IconRefresh, accent: 'default', isPinned: true, @@ -452,7 +193,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record< key: MultipleRecordsActionKeys.RESTORE, label: msg`Restore records`, shortLabel: msg`Restore`, - position: 19, + position: 6, Icon: IconRefresh, accent: 'default', isPinned: true, @@ -472,13 +213,273 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record< availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION], component: , }, + [SingleRecordActionKeys.DESTROY]: { + type: ActionType.Standard, + scope: ActionScope.RecordSelection, + key: SingleRecordActionKeys.DESTROY, + label: msg`Permanently destroy record`, + shortLabel: msg`Destroy`, + position: 7, + Icon: IconTrashX, + accent: 'danger', + isPinned: true, + shouldBeRegistered: ({ selectedRecord, objectPermissions, isRemote }) => + (objectPermissions.canDestroyObjectRecords && + !isRemote && + isDefined(selectedRecord?.deletedAt)) ?? + false, + availableOn: [ + ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, + ActionViewType.SHOW_PAGE, + ], + component: , + }, + [MultipleRecordsActionKeys.DESTROY]: { + type: ActionType.Standard, + scope: ActionScope.RecordSelection, + key: MultipleRecordsActionKeys.DESTROY, + label: msg`Permanently destroy records`, + shortLabel: msg`Destroy`, + position: 8, + Icon: IconTrashX, + accent: 'danger', + isPinned: true, + shouldBeRegistered: ({ + objectPermissions, + isRemote, + hasAnySoftDeleteFilterOnView, + numberOfSelectedRecords, + }) => + (objectPermissions.canDestroyObjectRecords && + !isRemote && + isDefined(hasAnySoftDeleteFilterOnView) && + hasAnySoftDeleteFilterOnView && + isDefined(numberOfSelectedRecords) && + numberOfSelectedRecords < BACKEND_BATCH_REQUEST_MAX_COUNT) ?? + false, + availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION], + component: , + }, + + [SingleRecordActionKeys.ADD_TO_FAVORITES]: { + type: ActionType.Standard, + scope: ActionScope.RecordSelection, + key: SingleRecordActionKeys.ADD_TO_FAVORITES, + label: msg`Add to favorites`, + shortLabel: msg`Add to favorites`, + position: 9, + isPinned: true, + Icon: IconHeart, + shouldBeRegistered: ({ + selectedRecord, + isFavorite, + hasAnySoftDeleteFilterOnView, + }) => + !selectedRecord?.isRemote && + !isFavorite && + !isDefined(selectedRecord?.deletedAt) && + !hasAnySoftDeleteFilterOnView, + availableOn: [ + ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, + ActionViewType.SHOW_PAGE, + ], + component: , + }, + [SingleRecordActionKeys.REMOVE_FROM_FAVORITES]: { + type: ActionType.Standard, + scope: ActionScope.RecordSelection, + key: SingleRecordActionKeys.REMOVE_FROM_FAVORITES, + label: msg`Remove from favorites`, + shortLabel: msg`Remove from favorites`, + isPinned: true, + position: 10, + Icon: IconHeartOff, + shouldBeRegistered: ({ + selectedRecord, + isFavorite, + hasAnySoftDeleteFilterOnView, + }) => + isDefined(selectedRecord) && + !selectedRecord?.isRemote && + isDefined(isFavorite) && + isFavorite && + !isDefined(selectedRecord?.deletedAt) && + !hasAnySoftDeleteFilterOnView, + availableOn: [ + ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, + ActionViewType.SHOW_PAGE, + ], + component: , + }, + [SingleRecordActionKeys.EXPORT_NOTE_TO_PDF]: { + type: ActionType.Standard, + scope: ActionScope.RecordSelection, + key: SingleRecordActionKeys.EXPORT_NOTE_TO_PDF, + label: msg`Export to PDF`, + shortLabel: msg`Export`, + position: 11, + isPinned: false, + Icon: IconFileExport, + shouldBeRegistered: ({ selectedRecord, isNoteOrTask }) => + isDefined(isNoteOrTask) && + isNoteOrTask && + isNonEmptyString(selectedRecord?.bodyV2?.blocknote), + availableOn: [ActionViewType.SHOW_PAGE], + component: , + }, + [SingleRecordActionKeys.EXPORT_FROM_RECORD_INDEX]: { + type: ActionType.Standard, + scope: ActionScope.RecordSelection, + key: SingleRecordActionKeys.EXPORT_FROM_RECORD_INDEX, + label: msg`Export`, + shortLabel: msg`Export`, + position: 12, + Icon: IconFileExport, + accent: 'default', + isPinned: false, + shouldBeRegistered: ({ selectedRecord }) => + isDefined(selectedRecord) && !selectedRecord.isRemote, + availableOn: [ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION], + component: , + requiredPermissionFlag: PermissionFlagType.EXPORT_CSV, + }, + [SingleRecordActionKeys.EXPORT_FROM_RECORD_SHOW]: { + type: ActionType.Standard, + scope: ActionScope.RecordSelection, + key: SingleRecordActionKeys.EXPORT_FROM_RECORD_SHOW, + label: msg`Export`, + shortLabel: msg`Export`, + position: 13, + Icon: IconFileExport, + accent: 'default', + isPinned: false, + shouldBeRegistered: ({ selectedRecord }) => + isDefined(selectedRecord) && !selectedRecord.isRemote, + availableOn: [ActionViewType.SHOW_PAGE], + component: , + requiredPermissionFlag: PermissionFlagType.EXPORT_CSV, + }, + [MultipleRecordsActionKeys.MERGE]: { + type: ActionType.Standard, + scope: ActionScope.RecordSelection, + key: MultipleRecordsActionKeys.MERGE, + label: msg`Merge records`, + shortLabel: msg`Merge`, + position: 14, + Icon: IconArrowMerge, + accent: 'default', + isPinned: false, + shouldBeRegistered: ({ + objectMetadataItem, + numberOfSelectedRecords, + objectPermissions, + }) => + isDefined(objectMetadataItem?.duplicateCriteria) && + isDefined(numberOfSelectedRecords) && + Boolean(objectPermissions.canUpdateObjectRecords) && + Boolean(objectPermissions.canDestroyObjectRecords) && + numberOfSelectedRecords <= MUTATION_MAX_MERGE_RECORDS, + availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION], + component: , + }, + [MultipleRecordsActionKeys.EXPORT]: { + type: ActionType.Standard, + scope: ActionScope.RecordSelection, + key: MultipleRecordsActionKeys.EXPORT, + label: msg`Export records`, + shortLabel: msg`Export`, + position: 15, + Icon: IconFileExport, + accent: 'default', + isPinned: false, + shouldBeRegistered: () => true, + availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION], + component: , + requiredPermissionFlag: PermissionFlagType.EXPORT_CSV, + }, + [NoSelectionRecordActionKeys.IMPORT_RECORDS]: { + type: ActionType.Standard, + scope: ActionScope.Object, + key: NoSelectionRecordActionKeys.IMPORT_RECORDS, + label: msg`Import records`, + shortLabel: msg`Import`, + position: 16, + Icon: IconFileImport, + accent: 'default', + isPinned: false, + shouldBeRegistered: ({ hasAnySoftDeleteFilterOnView }) => + !hasAnySoftDeleteFilterOnView, + availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], + component: , + requiredPermissionFlag: PermissionFlagType.IMPORT_CSV, + }, + [NoSelectionRecordActionKeys.EXPORT_VIEW]: { + type: ActionType.Standard, + scope: ActionScope.Object, + key: NoSelectionRecordActionKeys.EXPORT_VIEW, + label: msg`Export view`, + shortLabel: msg`Export`, + position: 17, + Icon: IconFileExport, + accent: 'default', + isPinned: false, + shouldBeRegistered: () => true, + availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], + component: , + requiredPermissionFlag: PermissionFlagType.EXPORT_CSV, + }, + [NoSelectionRecordActionKeys.SEE_DELETED_RECORDS]: { + type: ActionType.Standard, + scope: ActionScope.Object, + key: NoSelectionRecordActionKeys.SEE_DELETED_RECORDS, + label: msg`See deleted records`, + shortLabel: msg`Deleted records`, + position: 18, + Icon: IconRotate2, + accent: 'default', + isPinned: false, + shouldBeRegistered: ({ hasAnySoftDeleteFilterOnView }) => + !hasAnySoftDeleteFilterOnView, + availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], + component: , + }, + [NoSelectionRecordActionKeys.CREATE_NEW_VIEW]: { + type: ActionType.Standard, + scope: ActionScope.Object, + key: NoSelectionRecordActionKeys.CREATE_NEW_VIEW, + label: msg`Create View`, + shortLabel: msg`Create View`, + position: 19, + Icon: IconLayout, + accent: 'default', + isPinned: false, + shouldBeRegistered: ({ hasAnySoftDeleteFilterOnView }) => + !hasAnySoftDeleteFilterOnView, + availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], + component: , + }, + [NoSelectionRecordActionKeys.HIDE_DELETED_RECORDS]: { + type: ActionType.Standard, + scope: ActionScope.Object, + key: NoSelectionRecordActionKeys.HIDE_DELETED_RECORDS, + label: msg`Hide deleted records`, + shortLabel: msg`Hide deleted`, + position: 20, + Icon: IconEyeOff, + accent: 'default', + isPinned: false, + shouldBeRegistered: ({ hasAnySoftDeleteFilterOnView }) => + isDefined(hasAnySoftDeleteFilterOnView) && hasAnySoftDeleteFilterOnView, + availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], + component: , + }, [NoSelectionRecordActionKeys.GO_TO_WORKFLOWS]: { type: ActionType.Navigation, scope: ActionScope.Global, key: NoSelectionRecordActionKeys.GO_TO_WORKFLOWS, label: msg`Go to Workflows`, shortLabel: msg`See Workflows`, - position: 20, + position: 21, Icon: IconSettingsAutomation, accent: 'default', isPinned: false, @@ -495,6 +496,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record< ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, ActionViewType.INDEX_PAGE_BULK_SELECTION, ActionViewType.SHOW_PAGE, + ActionViewType.PAGE_EDIT_MODE, ], component: ( , }, [PageLayoutSingleRecordActionKeys.CANCEL_LAYOUT_EDITION]: { @@ -55,7 +55,7 @@ export const RECORD_PAGE_LAYOUT_ACTIONS_CONFIG = label: msg`Cancel Edition`, shortLabel: msg`Cancel`, isPinned: true, - position: 2, + position: 0, Icon: IconX, type: ActionType.Standard, scope: ActionScope.RecordSelection, @@ -65,7 +65,7 @@ export const RECORD_PAGE_LAYOUT_ACTIONS_CONFIG = !isDefined(selectedRecord?.deletedAt), // TODO: Once backend is ready, uncomment the line below // isDefined(selectedRecord?.pageLayoutId), - availableOn: [ActionViewType.SHOW_PAGE], + availableOn: [ActionViewType.PAGE_EDIT_MODE], component: , }, }, diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.tsx index c9e9cd401dc..0ac014ac62a 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.tsx @@ -28,6 +28,7 @@ import { msg } from '@lingui/core/macro'; import { AppPath } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { + IconCopy, IconHistoryToggle, IconNoteOff, IconPlayerPause, @@ -36,7 +37,6 @@ import { IconPower, IconReorder, IconVersions, - IconCopy, } from 'twenty-ui/display'; const areWorkflowTriggerAndStepsDefined = ( @@ -61,7 +61,8 @@ export const WORKFLOW_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({ label: msg`Activate Workflow`, shortLabel: msg`Activate`, isPinned: true, - position: 1, + isPrimaryCTA: true, + position: 3, Icon: IconPower, type: ActionType.Standard, scope: ActionScope.RecordSelection, @@ -83,7 +84,7 @@ export const WORKFLOW_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({ label: msg`Deactivate Workflow`, shortLabel: msg`Deactivate`, isPinned: true, - position: 2, + position: 4, Icon: IconPlayerPause, type: ActionType.Standard, scope: ActionScope.RecordSelection, @@ -102,7 +103,7 @@ export const WORKFLOW_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({ label: msg`Discard Draft`, shortLabel: msg`Discard Draft`, isPinned: true, - position: 3, + position: 5, Icon: IconNoteOff, type: ActionType.Standard, scope: ActionScope.RecordSelection, @@ -117,86 +118,12 @@ export const WORKFLOW_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({ ], component: , }, - [WorkflowSingleRecordActionKeys.DUPLICATE_WORKFLOW]: { - key: WorkflowSingleRecordActionKeys.DUPLICATE_WORKFLOW, - label: msg`Duplicate Workflow`, - shortLabel: msg`Duplicate`, - isPinned: false, - position: 10, - Icon: IconCopy, - type: ActionType.Standard, - scope: ActionScope.RecordSelection, - shouldBeRegistered: ({ selectedRecord, workflowWithCurrentVersion }) => - isDefined(workflowWithCurrentVersion) && - isDefined(workflowWithCurrentVersion.currentVersion) && - !isDefined(selectedRecord?.deletedAt), - availableOn: [ - ActionViewType.SHOW_PAGE, - ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, - ], - component: , - }, - [WorkflowSingleRecordActionKeys.SEE_ACTIVE_VERSION]: { - key: WorkflowSingleRecordActionKeys.SEE_ACTIVE_VERSION, - label: msg`See active version`, - shortLabel: msg`See active version`, - isPinned: false, - position: 4, - Icon: IconVersions, - type: ActionType.Standard, - scope: ActionScope.RecordSelection, - shouldBeRegistered: ({ workflowWithCurrentVersion, selectedRecord }) => - (workflowWithCurrentVersion?.statuses?.includes('ACTIVE') || false) && - (workflowWithCurrentVersion?.statuses?.includes('DRAFT') || false) && - !isDefined(selectedRecord?.deletedAt), - availableOn: [ - ActionViewType.SHOW_PAGE, - ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, - ], - component: , - }, - [WorkflowSingleRecordActionKeys.SEE_RUNS]: { - key: WorkflowSingleRecordActionKeys.SEE_RUNS, - label: msg`See runs`, - shortLabel: msg`See runs`, - isPinned: true, - position: 5, - Icon: IconHistoryToggle, - type: ActionType.Standard, - scope: ActionScope.RecordSelection, - shouldBeRegistered: ({ selectedRecord, workflowWithCurrentVersion }) => - isDefined(workflowWithCurrentVersion) && - !isDefined(selectedRecord?.deletedAt), - availableOn: [ - ActionViewType.SHOW_PAGE, - ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, - ], - component: , - }, - [WorkflowSingleRecordActionKeys.SEE_VERSIONS]: { - key: WorkflowSingleRecordActionKeys.SEE_VERSIONS, - label: msg`See versions history`, - shortLabel: msg`See versions`, - isPinned: false, - position: 6, - Icon: IconVersions, - type: ActionType.Standard, - scope: ActionScope.RecordSelection, - shouldBeRegistered: ({ selectedRecord, workflowWithCurrentVersion }) => - isDefined(workflowWithCurrentVersion) && - !isDefined(selectedRecord?.deletedAt), - availableOn: [ - ActionViewType.SHOW_PAGE, - ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, - ], - component: , - }, [WorkflowSingleRecordActionKeys.TEST]: { key: WorkflowSingleRecordActionKeys.TEST, label: msg`Test Workflow`, shortLabel: msg`Test`, isPinned: true, - position: 7, + position: 6, Icon: IconPlayerPlay, type: ActionType.Standard, scope: ActionScope.RecordSelection, @@ -217,12 +144,69 @@ export const WORKFLOW_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({ ], component: , }, + + [WorkflowSingleRecordActionKeys.SEE_ACTIVE_VERSION]: { + key: WorkflowSingleRecordActionKeys.SEE_ACTIVE_VERSION, + label: msg`See active version`, + shortLabel: msg`See active version`, + isPinned: false, + position: 7, + Icon: IconVersions, + type: ActionType.Standard, + scope: ActionScope.RecordSelection, + shouldBeRegistered: ({ workflowWithCurrentVersion, selectedRecord }) => + (workflowWithCurrentVersion?.statuses?.includes('ACTIVE') || false) && + (workflowWithCurrentVersion?.statuses?.includes('DRAFT') || false) && + !isDefined(selectedRecord?.deletedAt), + availableOn: [ + ActionViewType.SHOW_PAGE, + ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, + ], + component: , + }, + [WorkflowSingleRecordActionKeys.SEE_RUNS]: { + key: WorkflowSingleRecordActionKeys.SEE_RUNS, + label: msg`See runs`, + shortLabel: msg`See runs`, + isPinned: true, + position: 8, + Icon: IconHistoryToggle, + type: ActionType.Standard, + scope: ActionScope.RecordSelection, + shouldBeRegistered: ({ selectedRecord, workflowWithCurrentVersion }) => + isDefined(workflowWithCurrentVersion) && + !isDefined(selectedRecord?.deletedAt), + availableOn: [ + ActionViewType.SHOW_PAGE, + ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, + ], + component: , + }, + [WorkflowSingleRecordActionKeys.SEE_VERSIONS]: { + key: WorkflowSingleRecordActionKeys.SEE_VERSIONS, + label: msg`See versions history`, + shortLabel: msg`See versions`, + isPinned: false, + position: 9, + Icon: IconVersions, + type: ActionType.Standard, + scope: ActionScope.RecordSelection, + shouldBeRegistered: ({ selectedRecord, workflowWithCurrentVersion }) => + isDefined(workflowWithCurrentVersion) && + !isDefined(selectedRecord?.deletedAt), + availableOn: [ + ActionViewType.SHOW_PAGE, + ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, + ], + component: , + }, + [WorkflowSingleRecordActionKeys.ADD_NODE]: { key: WorkflowSingleRecordActionKeys.ADD_NODE, label: msg`Add a node`, shortLabel: msg`Add a node`, isPinned: false, - position: 8, + position: 10, Icon: IconPlus, type: ActionType.Standard, scope: ActionScope.RecordSelection, @@ -237,7 +221,7 @@ export const WORKFLOW_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({ label: msg`Tidy up workflow`, shortLabel: msg`Tidy up`, isPinned: false, - position: 9, + position: 11, Icon: IconReorder, type: ActionType.Standard, scope: ActionScope.RecordSelection, @@ -247,6 +231,25 @@ export const WORKFLOW_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({ availableOn: [ActionViewType.SHOW_PAGE], component: , }, + [WorkflowSingleRecordActionKeys.DUPLICATE_WORKFLOW]: { + key: WorkflowSingleRecordActionKeys.DUPLICATE_WORKFLOW, + label: msg`Duplicate Workflow`, + shortLabel: msg`Duplicate`, + isPinned: false, + position: 12, + Icon: IconCopy, + type: ActionType.Standard, + scope: ActionScope.RecordSelection, + shouldBeRegistered: ({ selectedRecord, workflowWithCurrentVersion }) => + isDefined(workflowWithCurrentVersion) && + isDefined(workflowWithCurrentVersion.currentVersion) && + !isDefined(selectedRecord?.deletedAt), + availableOn: [ + ActionViewType.SHOW_PAGE, + ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, + ], + component: , + }, [NoSelectionWorkflowRecordActionKeys.GO_TO_RUNS]: { type: ActionType.Navigation, scope: ActionScope.Global, @@ -294,16 +297,18 @@ export const WORKFLOW_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({ NoSelectionRecordActionKeys.GO_TO_NOTES, ], propertiesToOverwrite: { - [NoSelectionRecordActionKeys.CREATE_NEW_RECORD]: { + [SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD]: { position: 0, + label: msg`Navigate to next workflow`, + }, + [SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD]: { + position: 1, + label: msg`Navigate to previous workflow`, + }, + [NoSelectionRecordActionKeys.CREATE_NEW_RECORD]: { + position: 2, label: msg`Create new workflow`, }, - [SingleRecordActionKeys.ADD_TO_FAVORITES]: { - position: 10, - }, - [SingleRecordActionKeys.REMOVE_FROM_FAVORITES]: { - position: 11, - }, [SingleRecordActionKeys.DELETE]: { position: 12, label: msg`Delete workflow`, @@ -312,72 +317,70 @@ export const WORKFLOW_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({ position: 13, label: msg`Delete workflows`, }, - [SingleRecordActionKeys.DESTROY]: { + [SingleRecordActionKeys.ADD_TO_FAVORITES]: { position: 14, + }, + [SingleRecordActionKeys.REMOVE_FROM_FAVORITES]: { + position: 15, + }, + [SingleRecordActionKeys.DESTROY]: { + position: 16, label: msg`Permanently destroy workflow`, }, [SingleRecordActionKeys.EXPORT_FROM_RECORD_INDEX]: { - position: 15, + position: 17, label: msg`Export workflow`, shouldBeRegistered: ({ selectedRecord }) => !isDefined(selectedRecord?.deletedAt), }, [SingleRecordActionKeys.EXPORT_FROM_RECORD_SHOW]: { - position: 16, + position: 18, label: msg`Export workflow`, }, [MultipleRecordsActionKeys.EXPORT]: { - position: 17, + position: 19, label: msg`Export workflows`, }, [NoSelectionRecordActionKeys.EXPORT_VIEW]: { - position: 17, + position: 20, label: msg`Export view`, }, [MultipleRecordsActionKeys.DESTROY]: { - position: 18, + position: 21, label: msg`Permanently destroy workflows`, }, - [SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD]: { - position: 19, - label: msg`Navigate to previous workflow`, - }, - [SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD]: { - position: 20, - label: msg`Navigate to next workflow`, - }, [NoSelectionRecordActionKeys.SEE_DELETED_RECORDS]: { - position: 21, + position: 22, label: msg`See deleted workflows`, }, [NoSelectionRecordActionKeys.HIDE_DELETED_RECORDS]: { - position: 22, + position: 23, label: msg`Hide deleted workflows`, }, [NoSelectionRecordActionKeys.IMPORT_RECORDS]: { - position: 23, + position: 24, label: msg`Import workflows`, }, [NoSelectionRecordActionKeys.GO_TO_PEOPLE]: { - position: 24, - }, - [NoSelectionRecordActionKeys.GO_TO_COMPANIES]: { position: 25, }, - [NoSelectionRecordActionKeys.GO_TO_OPPORTUNITIES]: { + [NoSelectionRecordActionKeys.GO_TO_COMPANIES]: { position: 26, }, - [NoSelectionRecordActionKeys.GO_TO_DASHBOARDS]: { + [NoSelectionRecordActionKeys.GO_TO_OPPORTUNITIES]: { position: 27, }, - [NoSelectionRecordActionKeys.GO_TO_SETTINGS]: { + [NoSelectionRecordActionKeys.GO_TO_DASHBOARDS]: { position: 28, }, - [NoSelectionRecordActionKeys.GO_TO_TASKS]: { + [NoSelectionRecordActionKeys.GO_TO_SETTINGS]: { position: 29, }, - [NoSelectionRecordActionKeys.GO_TO_NOTES]: { + [NoSelectionRecordActionKeys.GO_TO_TASKS]: { position: 30, }, + [NoSelectionRecordActionKeys.GO_TO_NOTES]: { + position: 31, + }, }, }); diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowRunsActionsConfig.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowRunsActionsConfig.tsx index 2323879eda9..9266a35e0dd 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowRunsActionsConfig.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowRunsActionsConfig.tsx @@ -18,11 +18,44 @@ import { export const WORKFLOW_RUNS_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({ config: { + [WorkflowRunSingleRecordActionKeys.SEE_VERSION]: { + key: WorkflowRunSingleRecordActionKeys.SEE_VERSION, + label: msg`See version`, + shortLabel: msg`See version`, + position: 0, + isPinned: true, + type: ActionType.Standard, + scope: ActionScope.RecordSelection, + Icon: IconVersions, + shouldBeRegistered: () => true, + availableOn: [ + ActionViewType.SHOW_PAGE, + ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, + ], + component: , + }, + + [WorkflowRunSingleRecordActionKeys.SEE_WORKFLOW]: { + key: WorkflowRunSingleRecordActionKeys.SEE_WORKFLOW, + label: msg`See workflow`, + shortLabel: msg`See workflow`, + position: 1, + isPinned: true, + type: ActionType.Standard, + scope: ActionScope.RecordSelection, + Icon: IconSettingsAutomation, + shouldBeRegistered: () => true, + availableOn: [ + ActionViewType.SHOW_PAGE, + ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, + ], + component: , + }, [WorkflowRunSingleRecordActionKeys.STOP]: { key: WorkflowRunSingleRecordActionKeys.STOP, label: msg`Stop`, shortLabel: msg`Stop`, - position: 0, + position: 2, isPinned: true, type: ActionType.Standard, scope: ActionScope.RecordSelection, @@ -42,38 +75,6 @@ export const WORKFLOW_RUNS_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({ ], component: , }, - [WorkflowRunSingleRecordActionKeys.SEE_WORKFLOW]: { - key: WorkflowRunSingleRecordActionKeys.SEE_WORKFLOW, - label: msg`See workflow`, - shortLabel: msg`See workflow`, - position: 1, - isPinned: true, - type: ActionType.Standard, - scope: ActionScope.RecordSelection, - Icon: IconSettingsAutomation, - shouldBeRegistered: () => true, - availableOn: [ - ActionViewType.SHOW_PAGE, - ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, - ], - component: , - }, - [WorkflowRunSingleRecordActionKeys.SEE_VERSION]: { - key: WorkflowRunSingleRecordActionKeys.SEE_VERSION, - label: msg`See version`, - shortLabel: msg`See version`, - position: 2, - isPinned: true, - type: ActionType.Standard, - scope: ActionScope.RecordSelection, - Icon: IconVersions, - shouldBeRegistered: () => true, - availableOn: [ - ActionViewType.SHOW_PAGE, - ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, - ], - component: , - }, }, actionKeys: [ SingleRecordActionKeys.ADD_TO_FAVORITES, diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowVersionsActionsConfig.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowVersionsActionsConfig.tsx index c2e57129414..5f7e1e17d28 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowVersionsActionsConfig.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowVersionsActionsConfig.tsx @@ -26,22 +26,22 @@ import { export const WORKFLOW_VERSIONS_ACTIONS_CONFIG = inheritActionsFromDefaultConfig( { config: { - [WorkflowVersionSingleRecordActionKeys.USE_AS_DRAFT]: { - key: WorkflowVersionSingleRecordActionKeys.USE_AS_DRAFT, - label: msg`Use as draft`, - shortLabel: msg`Use as draft`, + [WorkflowVersionSingleRecordActionKeys.SEE_RUNS]: { + key: WorkflowVersionSingleRecordActionKeys.SEE_RUNS, + label: msg`See runs`, + shortLabel: msg`See runs`, position: 1, isPinned: true, type: ActionType.Standard, scope: ActionScope.RecordSelection, - Icon: IconPencil, - shouldBeRegistered: ({ selectedRecord }) => - isDefined(selectedRecord) && selectedRecord.status !== 'DRAFT', + Icon: IconHistoryToggle, + shouldBeRegistered: ({ workflowWithCurrentVersion }) => + isDefined(workflowWithCurrentVersion), availableOn: [ ActionViewType.SHOW_PAGE, ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, ], - component: , + component: , }, [WorkflowVersionSingleRecordActionKeys.SEE_WORKFLOW]: { key: WorkflowVersionSingleRecordActionKeys.SEE_WORKFLOW, @@ -60,22 +60,22 @@ export const WORKFLOW_VERSIONS_ACTIONS_CONFIG = inheritActionsFromDefaultConfig( ], component: , }, - [WorkflowVersionSingleRecordActionKeys.SEE_RUNS]: { - key: WorkflowVersionSingleRecordActionKeys.SEE_RUNS, - label: msg`See runs`, - shortLabel: msg`See runs`, + [WorkflowVersionSingleRecordActionKeys.USE_AS_DRAFT]: { + key: WorkflowVersionSingleRecordActionKeys.USE_AS_DRAFT, + label: msg`Use as draft`, + shortLabel: msg`Use as draft`, position: 3, isPinned: true, type: ActionType.Standard, scope: ActionScope.RecordSelection, - Icon: IconHistoryToggle, - shouldBeRegistered: ({ workflowWithCurrentVersion }) => - isDefined(workflowWithCurrentVersion), + Icon: IconPencil, + shouldBeRegistered: ({ selectedRecord }) => + isDefined(selectedRecord) && selectedRecord.status !== 'DRAFT', availableOn: [ ActionViewType.SHOW_PAGE, ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, ], - component: , + component: , }, [WorkflowVersionSingleRecordActionKeys.SEE_VERSIONS]: { key: WorkflowVersionSingleRecordActionKeys.SEE_VERSIONS, @@ -99,7 +99,7 @@ export const WORKFLOW_VERSIONS_ACTIONS_CONFIG = inheritActionsFromDefaultConfig( key: NoSelectionWorkflowRecordActionKeys.GO_TO_RUNS, label: msg`Go to runs`, shortLabel: msg`See runs`, - position: 15, + position: 14, Icon: IconHistoryToggle, accent: 'default', isPinned: true, @@ -172,30 +172,30 @@ export const WORKFLOW_VERSIONS_ACTIONS_CONFIG = inheritActionsFromDefaultConfig( label: msg`Navigate to next version`, }, [NoSelectionRecordActionKeys.GO_TO_WORKFLOWS]: { - position: 14, + position: 15, isPinned: true, }, [NoSelectionRecordActionKeys.GO_TO_PEOPLE]: { - position: 15, - }, - [NoSelectionRecordActionKeys.GO_TO_COMPANIES]: { position: 16, }, - [NoSelectionRecordActionKeys.GO_TO_OPPORTUNITIES]: { + [NoSelectionRecordActionKeys.GO_TO_COMPANIES]: { position: 17, }, - [NoSelectionRecordActionKeys.GO_TO_DASHBOARDS]: { + [NoSelectionRecordActionKeys.GO_TO_OPPORTUNITIES]: { position: 18, }, - [NoSelectionRecordActionKeys.GO_TO_SETTINGS]: { + [NoSelectionRecordActionKeys.GO_TO_DASHBOARDS]: { position: 19, }, - [NoSelectionRecordActionKeys.GO_TO_TASKS]: { + [NoSelectionRecordActionKeys.GO_TO_SETTINGS]: { position: 20, }, - [NoSelectionRecordActionKeys.GO_TO_NOTES]: { + [NoSelectionRecordActionKeys.GO_TO_TASKS]: { position: 21, }, + [NoSelectionRecordActionKeys.GO_TO_NOTES]: { + position: 22, + }, }, }, ); diff --git a/packages/twenty-front/src/modules/action-menu/actions/types/ActionConfig.ts b/packages/twenty-front/src/modules/action-menu/actions/types/ActionConfig.ts index c6db06d5709..a4ae40fc102 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/types/ActionConfig.ts +++ b/packages/twenty-front/src/modules/action-menu/actions/types/ActionConfig.ts @@ -17,6 +17,7 @@ export type ActionConfig = { position: number; Icon: IconComponent; isPinned?: boolean; + isPrimaryCTA?: boolean; accent?: MenuItemAccent; availableOn?: ActionViewType[]; shouldBeRegistered: (params: ShouldBeRegisteredFunctionParams) => boolean; diff --git a/packages/twenty-front/src/modules/action-menu/actions/types/ActionViewType.ts b/packages/twenty-front/src/modules/action-menu/actions/types/ActionViewType.ts index db450f084fb..19fd1d2d222 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/types/ActionViewType.ts +++ b/packages/twenty-front/src/modules/action-menu/actions/types/ActionViewType.ts @@ -4,4 +4,5 @@ export enum ActionViewType { INDEX_PAGE_SINGLE_RECORD_SELECTION = 'INDEX_PAGE_SINGLE_RECORD_SELECTION', INDEX_PAGE_NO_SELECTION = 'INDEX_PAGE_NO_SELECTION', SHOW_PAGE = 'SHOW_PAGE', + PAGE_EDIT_MODE = 'PAGE_EDIT_MODE', } diff --git a/packages/twenty-front/src/modules/action-menu/components/PageHeaderActionMenuButtons.tsx b/packages/twenty-front/src/modules/action-menu/components/PageHeaderActionMenuButtons.tsx index 7f34f05e0e0..7e7d4830fcb 100644 --- a/packages/twenty-front/src/modules/action-menu/components/PageHeaderActionMenuButtons.tsx +++ b/packages/twenty-front/src/modules/action-menu/components/PageHeaderActionMenuButtons.tsx @@ -15,7 +15,7 @@ export const PageHeaderActionMenuButtons = () => { const { actions } = useContext(ActionMenuContext); const theme = useTheme(); - const pinnedActions = actions.filter((entry) => entry.isPinned); + const pinnedActions = actions.filter((entry) => entry.isPinned).toReversed(); const actionsWithPositionForAnimation = pinnedActions.map( (action, index) => ({ diff --git a/packages/twenty-front/src/modules/action-menu/hooks/useRegisteredActions.ts b/packages/twenty-front/src/modules/action-menu/hooks/useRegisteredActions.ts index da16ffc8689..1a0e214bb1e 100644 --- a/packages/twenty-front/src/modules/action-menu/hooks/useRegisteredActions.ts +++ b/packages/twenty-front/src/modules/action-menu/hooks/useRegisteredActions.ts @@ -5,6 +5,7 @@ import { type ShouldBeRegisteredFunctionParams } from '@/action-menu/actions/typ import { getActionConfig } from '@/action-menu/actions/utils/getActionConfig'; import { getActionViewType } from '@/action-menu/actions/utils/getActionViewType'; import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState'; +import { contextStoreIsPageInEditModeComponentState } from '@/context-store/states/contextStoreIsPageInEditModeComponentState'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { usePermissionFlagMap } from '@/settings/roles/hooks/usePermissionFlagMap'; import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue'; @@ -29,6 +30,10 @@ export const useRegisteredActions = ( contextStoreCurrentViewTypeComponentState, ); + const isFullTabWidgetInEditMode = useRecoilComponentValue( + contextStoreIsPageInEditModeComponentState, + ); + const isRecordPageLayoutEnabled = useIsFeatureEnabled( FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_ENABLED, ); @@ -59,13 +64,23 @@ export const useRegisteredActions = ( const permissionMap = usePermissionFlagMap(); - const actionsToRegister = isDefined(viewType) - ? Object.values(actionsConfig).filter( - (action) => - action.availableOn?.includes(viewType) || - action.availableOn?.includes(ActionViewType.GLOBAL), - ) - : []; + const actionsToRegister = Object.values(actionsConfig).filter((action) => { + if (isFullTabWidgetInEditMode) { + return ( + isDefined(action.availableOn) && + action.availableOn.includes(ActionViewType.PAGE_EDIT_MODE) + ); + } + + if (isDefined(viewType)) { + return ( + action.availableOn?.includes(viewType) || + action.availableOn?.includes(ActionViewType.GLOBAL) + ); + } + + return action.availableOn?.includes(ActionViewType.GLOBAL); + }); const actions = actionsToRegister .filter((action) => { diff --git a/packages/twenty-front/src/modules/app/hooks/useExecuteTasksOnAnyLocationChange.ts b/packages/twenty-front/src/modules/app/hooks/useExecuteTasksOnAnyLocationChange.ts index a4f1e54d3bb..a028fbf8d45 100644 --- a/packages/twenty-front/src/modules/app/hooks/useExecuteTasksOnAnyLocationChange.ts +++ b/packages/twenty-front/src/modules/app/hooks/useExecuteTasksOnAnyLocationChange.ts @@ -1,8 +1,25 @@ +import { useRecoilCallback } from 'recoil'; + +import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; +import { contextStoreIsPageInEditModeComponentState } from '@/context-store/states/contextStoreIsPageInEditModeComponentState'; import { useCloseAnyOpenDropdown } from '@/ui/layout/dropdown/hooks/useCloseAnyOpenDropdown'; export const useExecuteTasksOnAnyLocationChange = () => { const { closeAnyOpenDropdown } = useCloseAnyOpenDropdown(); + const resetIsPageInEditMode = useRecoilCallback( + ({ set }) => + () => { + set( + contextStoreIsPageInEditModeComponentState.atomFamily({ + instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID, + }), + false, + ); + }, + [], + ); + /** * Be careful to put idempotent tasks here. * @@ -10,6 +27,7 @@ export const useExecuteTasksOnAnyLocationChange = () => { */ const executeTasksOnAnyLocationChange = () => { closeAnyOpenDropdown(); + resetIsPageInEditMode(); }; return { executeTasksOnAnyLocationChange }; diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useCopyContextStoreAndActionMenuStates.ts b/packages/twenty-front/src/modules/command-menu/hooks/useCopyContextStoreAndActionMenuStates.ts index 3f34a8a20d2..d96badef654 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useCopyContextStoreAndActionMenuStates.ts +++ b/packages/twenty-front/src/modules/command-menu/hooks/useCopyContextStoreAndActionMenuStates.ts @@ -4,6 +4,7 @@ import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/ import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState'; import { contextStoreFilterGroupsComponentState } from '@/context-store/states/contextStoreFilterGroupsComponentState'; import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState'; +import { contextStoreIsPageInEditModeComponentState } from '@/context-store/states/contextStoreIsPageInEditModeComponentState'; import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { useRecoilCallback } from 'recoil'; @@ -137,6 +138,21 @@ export const useCopyContextStoreStates = () => { }), contextStoreCurrentViewType, ); + + const contextStoreIsFullTabWidgetInEditMode = snapshot + .getLoadable( + contextStoreIsPageInEditModeComponentState.atomFamily({ + instanceId: instanceIdToCopyFrom, + }), + ) + .getValue(); + + set( + contextStoreIsPageInEditModeComponentState.atomFamily({ + instanceId: instanceIdToCopyTo, + }), + contextStoreIsFullTabWidgetInEditMode, + ); }, [], ); diff --git a/packages/twenty-front/src/modules/command-menu/hooks/useOpenRecordInCommandMenu.ts b/packages/twenty-front/src/modules/command-menu/hooks/useOpenRecordInCommandMenu.ts index 8d0a66392b8..c881ba9e2e6 100644 --- a/packages/twenty-front/src/modules/command-menu/hooks/useOpenRecordInCommandMenu.ts +++ b/packages/twenty-front/src/modules/command-menu/hooks/useOpenRecordInCommandMenu.ts @@ -8,6 +8,7 @@ import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainCo import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState'; import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState'; +import { contextStoreIsPageInEditModeComponentState } from '@/context-store/states/contextStoreIsPageInEditModeComponentState'; import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType'; @@ -141,6 +142,19 @@ export const useOpenRecordInCommandMenu = () => { .getValue(), ); + set( + contextStoreIsPageInEditModeComponentState.atomFamily({ + instanceId: pageComponentInstanceId, + }), + snapshot + .getLoadable( + contextStoreIsPageInEditModeComponentState.atomFamily({ + instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID, + }), + ) + .getValue(), + ); + const currentMorphItems = snapshot .getLoadable(commandMenuNavigationMorphItemsByPageState) .getValue(); diff --git a/packages/twenty-front/src/modules/context-store/states/contextStoreIsPageInEditModeComponentState.ts b/packages/twenty-front/src/modules/context-store/states/contextStoreIsPageInEditModeComponentState.ts new file mode 100644 index 00000000000..2a9b86c817d --- /dev/null +++ b/packages/twenty-front/src/modules/context-store/states/contextStoreIsPageInEditModeComponentState.ts @@ -0,0 +1,9 @@ +import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; +import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; + +export const contextStoreIsPageInEditModeComponentState = + createComponentState({ + key: 'contextStoreIsPageInEditModeComponentState', + defaultValue: false, + componentInstanceContext: ContextStoreComponentInstanceContext, + }); diff --git a/packages/twenty-front/src/modules/page-layout/hooks/useSetIsPageLayoutInEditMode.ts b/packages/twenty-front/src/modules/page-layout/hooks/useSetIsPageLayoutInEditMode.ts index 3c6eb022e04..9b9beeb0131 100644 --- a/packages/twenty-front/src/modules/page-layout/hooks/useSetIsPageLayoutInEditMode.ts +++ b/packages/twenty-front/src/modules/page-layout/hooks/useSetIsPageLayoutInEditMode.ts @@ -1,6 +1,5 @@ -import { SingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/types/SingleRecordActionsKey'; -import { forceRegisteredActionsByKeyState } from '@/action-menu/actions/states/forceRegisteredActionsMapComponentState'; -import { PageLayoutSingleRecordActionKeys } from '@/page-layout/actions/PageLayoutSingleRecordActionKeys'; +import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; +import { contextStoreIsPageInEditModeComponentState } from '@/context-store/states/contextStoreIsPageInEditModeComponentState'; import { PageLayoutComponentInstanceContext } from '@/page-layout/states/contexts/PageLayoutComponentInstanceContext'; import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState'; import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow'; @@ -18,23 +17,20 @@ export const useSetIsPageLayoutInEditMode = (pageLayoutIdFromProps: string) => { pageLayoutId, ); + const contextStoreIsFullTabWidgetInEditModeState = + useRecoilComponentCallbackState( + contextStoreIsPageInEditModeComponentState, + MAIN_CONTEXT_STORE_INSTANCE_ID, + ); + const setIsPageLayoutInEditMode = useRecoilCallback( ({ set }) => (value: boolean) => { set(isPageLayoutInEditModeState, value); - set(forceRegisteredActionsByKeyState, (prev) => ({ - ...prev, - [PageLayoutSingleRecordActionKeys.EDIT_LAYOUT]: !value, - [PageLayoutSingleRecordActionKeys.SAVE_LAYOUT]: value, - [PageLayoutSingleRecordActionKeys.CANCEL_LAYOUT_EDITION]: value, - [PageLayoutSingleRecordActionKeys.ADD_TO_FAVORITES_READ_MODE]: !value, - [SingleRecordActionKeys.ADD_TO_FAVORITES]: value, - [SingleRecordActionKeys.DELETE]: !value, - [SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD]: !value, - [SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD]: !value, - })); + + set(contextStoreIsFullTabWidgetInEditModeState, value); }, - [isPageLayoutInEditModeState], + [isPageLayoutInEditModeState, contextStoreIsFullTabWidgetInEditModeState], ); return { setIsPageLayoutInEditMode };