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
This commit is contained in:
Raphaël Bosi
2025-11-20 10:57:33 +01:00
committed by GitHub
parent 3190ca5b9e
commit 3c3d837cb7
17 changed files with 633 additions and 569 deletions
@@ -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}
@@ -15,6 +15,7 @@ export type ActionDisplayProps = {
shortLabel?: MessageDescriptor | string;
description?: MessageDescriptor | string;
Icon: IconComponent;
isPrimaryCTA?: boolean;
accent?: MenuItemAccent;
hotKeys?: string[];
};
@@ -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: <AddToFavoritesSingleRecordAction />,
},
[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: <EditDashboardSingleRecordAction />,
},
[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: <CancelDashboardSingleRecordAction />,
},
[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: <SaveDashboardSingleRecordAction />,
},
[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: <CancelDashboardSingleRecordAction />,
},
},
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,
},
},
});
@@ -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: <NavigateToNextRecordSingleRecordAction />,
},
[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: <NavigateToPreviousRecordSingleRecordAction />,
},
[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: <CreateNewTableRecordNoSelectionRecordAction />,
},
[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: <ExportNoteActionSingleRecordAction />,
},
[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: <AddToFavoritesSingleRecordAction />,
},
[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: <RemoveFromFavoritesSingleRecordAction />,
},
[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: <ExportMultipleRecordsAction />,
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: <ExportSingleRecordAction />,
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: <MergeMultipleRecordsAction />,
},
[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: <ExportMultipleRecordsAction />,
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: <ImportRecordsNoSelectionRecordAction />,
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: <ExportMultipleRecordsAction />,
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: <DeleteMultipleRecordsAction />,
},
[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: <SeeDeletedRecordsNoSelectionRecordAction />,
},
[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: <CreateNewViewNoSelectionRecord />,
},
[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: <HideDeletedRecordsNoSelectionRecordAction />,
},
[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: <DestroySingleRecordAction />,
},
[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: <NavigateToPreviousRecordSingleRecordAction />,
},
[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: <NavigateToNextRecordSingleRecordAction />,
},
[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: <DestroyMultipleRecordsAction />,
},
[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: <RestoreMultipleRecordsAction />,
},
[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: <DestroySingleRecordAction />,
},
[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: <DestroyMultipleRecordsAction />,
},
[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: <AddToFavoritesSingleRecordAction />,
},
[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: <RemoveFromFavoritesSingleRecordAction />,
},
[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: <ExportNoteActionSingleRecordAction />,
},
[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: <ExportMultipleRecordsAction />,
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: <ExportSingleRecordAction />,
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: <MergeMultipleRecordsAction />,
},
[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: <ExportMultipleRecordsAction />,
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: <ImportRecordsNoSelectionRecordAction />,
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: <ExportMultipleRecordsAction />,
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: <SeeDeletedRecordsNoSelectionRecordAction />,
},
[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: <CreateNewViewNoSelectionRecord />,
},
[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: <HideDeletedRecordsNoSelectionRecordAction />,
},
[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: (
<ActionLink
@@ -510,7 +512,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
key: NoSelectionRecordActionKeys.GO_TO_PEOPLE,
label: msg`Go to People`,
shortLabel: msg`People`,
position: 21,
position: 22,
Icon: IconUser,
isPinned: false,
availableOn: [
@@ -518,6 +520,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,
],
shouldBeRegistered: ({
objectMetadataItem,
@@ -541,7 +544,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
key: NoSelectionRecordActionKeys.GO_TO_COMPANIES,
label: msg`Go to Companies`,
shortLabel: msg`Companies`,
position: 22,
position: 23,
Icon: IconBuildingSkyscraper,
isPinned: false,
availableOn: [
@@ -549,6 +552,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,
],
shouldBeRegistered: ({
objectMetadataItem,
@@ -603,7 +607,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
key: NoSelectionRecordActionKeys.GO_TO_OPPORTUNITIES,
label: msg`Go to Opportunities`,
shortLabel: msg`Opportunities`,
position: 23,
position: 25,
Icon: IconTargetArrow,
isPinned: false,
availableOn: [
@@ -611,6 +615,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,
],
shouldBeRegistered: ({
objectMetadataItem,
@@ -635,7 +640,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
key: NoSelectionRecordActionKeys.GO_TO_SETTINGS,
label: msg`Go to Settings`,
shortLabel: msg`Settings`,
position: 25,
position: 26,
Icon: IconSettings,
isPinned: false,
availableOn: [
@@ -661,7 +666,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
key: NoSelectionRecordActionKeys.GO_TO_TASKS,
label: msg`Go to Tasks`,
shortLabel: msg`Tasks`,
position: 26,
position: 27,
Icon: IconCheckbox,
isPinned: false,
availableOn: [
@@ -669,6 +674,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,
],
shouldBeRegistered: ({
objectMetadataItem,
@@ -692,7 +698,7 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
key: NoSelectionRecordActionKeys.GO_TO_NOTES,
label: msg`Go to Notes`,
shortLabel: msg`Notes`,
position: 27,
position: 28,
Icon: IconCheckbox,
isPinned: false,
availableOn: [
@@ -700,6 +706,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,
],
shouldBeRegistered: ({
objectMetadataItem,
@@ -19,7 +19,7 @@ export const RECORD_PAGE_LAYOUT_ACTIONS_CONFIG =
label: msg`Edit Layout`,
shortLabel: msg`Edit`,
isPinned: true,
position: 0,
position: 2,
Icon: IconPencil,
type: ActionType.Standard,
scope: ActionScope.RecordSelection,
@@ -47,7 +47,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: <SaveRecordPageLayoutSingleRecordAction />,
},
[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: <CancelRecordPageLayoutSingleRecordAction />,
},
},
@@ -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: <DiscardDraftWorkflowSingleRecordAction />,
},
[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: <DuplicateWorkflowSingleRecordAction />,
},
[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: <SeeActiveVersionWorkflowSingleRecordAction />,
},
[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: <SeeRunsWorkflowSingleRecordAction />,
},
[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: <SeeVersionsWorkflowSingleRecordAction />,
},
[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: <TestWorkflowSingleRecordAction />,
},
[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: <SeeActiveVersionWorkflowSingleRecordAction />,
},
[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: <SeeRunsWorkflowSingleRecordAction />,
},
[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: <SeeVersionsWorkflowSingleRecordAction />,
},
[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: <TidyUpWorkflowSingleRecordAction />,
},
[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: <DuplicateWorkflowSingleRecordAction />,
},
[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,
},
},
});
@@ -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: <SeeVersionWorkflowRunSingleRecordAction />,
},
[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: <SeeWorkflowWorkflowRunSingleRecordAction />,
},
[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: <StopWorkflowRunSingleRecordAction />,
},
[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: <SeeWorkflowWorkflowRunSingleRecordAction />,
},
[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: <SeeVersionWorkflowRunSingleRecordAction />,
},
},
actionKeys: [
SingleRecordActionKeys.ADD_TO_FAVORITES,
@@ -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: <UseAsDraftWorkflowVersionSingleRecordAction />,
component: <SeeRunsWorkflowVersionSingleRecordAction />,
},
[WorkflowVersionSingleRecordActionKeys.SEE_WORKFLOW]: {
key: WorkflowVersionSingleRecordActionKeys.SEE_WORKFLOW,
@@ -60,22 +60,22 @@ export const WORKFLOW_VERSIONS_ACTIONS_CONFIG = inheritActionsFromDefaultConfig(
],
component: <SeeWorkflowWorkflowVersionSingleRecordAction />,
},
[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: <SeeRunsWorkflowVersionSingleRecordAction />,
component: <UseAsDraftWorkflowVersionSingleRecordAction />,
},
[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,
},
},
},
);
@@ -17,6 +17,7 @@ export type ActionConfig = {
position: number;
Icon: IconComponent;
isPinned?: boolean;
isPrimaryCTA?: boolean;
accent?: MenuItemAccent;
availableOn?: ActionViewType[];
shouldBeRegistered: (params: ShouldBeRegisteredFunctionParams) => boolean;
@@ -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',
}
@@ -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) => ({
@@ -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) => {
@@ -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 };
@@ -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,
);
},
[],
);
@@ -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();
@@ -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<boolean>({
key: 'contextStoreIsPageInEditModeComponentState',
defaultValue: false,
componentInstanceContext: ContextStoreComponentInstanceContext,
});
@@ -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 };