Command menu refactoring (#9257)
Refactored the `CommandMenu` component to make it more readable and easier to refactor. The file was way too big so I introduced a few hooks and eliminated code duplication. Introduced: - `useMatchCommands` hook to match commands with the search - `useCommandMenuCommands` which returns all command menu commands - `useMatchingCommandMenuCommands` to return the commands matched with the search - `CommandMenuContainer` to simplify the `DefaultLayout` - Unmounted the `CommandMenu` when it wasn't opened to improve performances I also introduced a new behavior: Automatically select the first item when opening the command menu: https://github.com/user-attachments/assets/4b683d49-570e-47c9-8939-99f42ed8691c
This commit is contained in:
@ -1,8 +1,8 @@
|
||||
import { MultipleRecordsActionMenuEntrySetterEffect } from '@/action-menu/actions/record-actions/multiple-records/components/MultipleRecordsActionMenuEntrySetterEffect';
|
||||
import { NoSelectionActionMenuEntrySetterEffect } from '@/action-menu/actions/record-actions/no-selection/components/NoSelectionActionMenuEntrySetterEffect';
|
||||
import { ShowPageSingleRecordActionMenuEntrySetterEffect } from '@/action-menu/actions/record-actions/single-record/components/ShowPageSingleRecordActionMenuEntrySetterEffect';
|
||||
import { SingleRecordActionMenuEntrySetterEffect } from '@/action-menu/actions/record-actions/single-record/components/SingleRecordActionMenuEntrySetterEffect';
|
||||
import { WorkflowRunRecordActionMenuEntrySetterEffect } from '@/action-menu/actions/record-actions/workflow-run-record-actions/components/WorkflowRunRecordActionMenuEntrySetter';
|
||||
import { ActionViewType } from '@/action-menu/actions/types/ActionViewType';
|
||||
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
||||
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
@ -67,14 +67,16 @@ const ActionEffects = ({
|
||||
contextStoreTargetedRecordsRule.selectedRecordIds.length === 1 && (
|
||||
<>
|
||||
{contextStoreCurrentViewType === ContextStoreViewType.ShowPage && (
|
||||
<ShowPageSingleRecordActionMenuEntrySetterEffect
|
||||
<SingleRecordActionMenuEntrySetterEffect
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
viewType={ActionViewType.SHOW_PAGE}
|
||||
/>
|
||||
)}
|
||||
{(contextStoreCurrentViewType === ContextStoreViewType.Table ||
|
||||
contextStoreCurrentViewType === ContextStoreViewType.Kanban) && (
|
||||
<SingleRecordActionMenuEntrySetterEffect
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
viewType={ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION}
|
||||
/>
|
||||
)}
|
||||
{isWorkflowEnabled && (
|
||||
|
||||
@ -1,78 +1,23 @@
|
||||
import { getActionConfig } from '@/action-menu/actions/record-actions/single-record/utils/getActionConfig';
|
||||
import { ActionAvailableOn } from '@/action-menu/actions/types/ActionAvailableOn';
|
||||
import { wrapActionInCallbacks } from '@/action-menu/actions/utils/wrapActionInCallbacks';
|
||||
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||
import { ActionViewType } from '@/action-menu/actions/types/ActionViewType';
|
||||
import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries';
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { useActionMenuEntriesWithCallbacks } from '@/action-menu/hooks/useActionMenuEntriesWithCallbacks';
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { useContext, useEffect } from 'react';
|
||||
import { isDefined } from 'twenty-ui';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
export const SingleRecordActionMenuEntrySetterEffect = ({
|
||||
objectMetadataItem,
|
||||
viewType,
|
||||
}: {
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
viewType: ActionViewType;
|
||||
}) => {
|
||||
const isPageHeaderV2Enabled = useIsFeatureEnabled(
|
||||
'IS_PAGE_HEADER_V2_ENABLED',
|
||||
);
|
||||
|
||||
const actionConfig = getActionConfig(
|
||||
objectMetadataItem,
|
||||
isPageHeaderV2Enabled,
|
||||
);
|
||||
|
||||
const { addActionMenuEntry, removeActionMenuEntry } = useActionMenuEntries();
|
||||
|
||||
const contextStoreTargetedRecordsRule = useRecoilComponentValueV2(
|
||||
contextStoreTargetedRecordsRuleComponentState,
|
||||
const { actionMenuEntries } = useActionMenuEntriesWithCallbacks(
|
||||
objectMetadataItem,
|
||||
viewType,
|
||||
);
|
||||
|
||||
const selectedRecordId =
|
||||
contextStoreTargetedRecordsRule.mode === 'selection'
|
||||
? contextStoreTargetedRecordsRule.selectedRecordIds[0]
|
||||
: undefined;
|
||||
|
||||
if (!isDefined(selectedRecordId)) {
|
||||
throw new Error('Selected record ID is required');
|
||||
}
|
||||
|
||||
const { onActionStartedCallback, onActionExecutedCallback } =
|
||||
useContext(ActionMenuContext);
|
||||
|
||||
const actionMenuEntries = Object.values(actionConfig ?? {})
|
||||
.filter((action) =>
|
||||
action.availableOn?.includes(
|
||||
ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
),
|
||||
)
|
||||
.map((action) => {
|
||||
const { shouldBeRegistered, onClick, ConfirmationModal } =
|
||||
action.actionHook({
|
||||
recordId: selectedRecordId,
|
||||
objectMetadataItem,
|
||||
});
|
||||
|
||||
if (!shouldBeRegistered) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const wrappedAction = wrapActionInCallbacks({
|
||||
action: {
|
||||
...action,
|
||||
onClick,
|
||||
ConfirmationModal,
|
||||
},
|
||||
onActionStartedCallback,
|
||||
onActionExecutedCallback,
|
||||
});
|
||||
|
||||
return wrappedAction;
|
||||
})
|
||||
.filter(isDefined);
|
||||
|
||||
useEffect(() => {
|
||||
for (const action of actionMenuEntries) {
|
||||
addActionMenuEntry(action);
|
||||
|
||||
@ -2,7 +2,7 @@ import { useAddToFavoritesSingleRecordAction } from '@/action-menu/actions/recor
|
||||
import { useDeleteSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useDeleteSingleRecordAction';
|
||||
import { useRemoveFromFavoritesSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useRemoveFromFavoritesSingleRecordAction';
|
||||
import { SingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/types/SingleRecordActionsKey';
|
||||
import { ActionAvailableOn } from '@/action-menu/actions/types/ActionAvailableOn';
|
||||
import { ActionViewType } from '@/action-menu/actions/types/ActionViewType';
|
||||
import { SingleRecordActionHook } from '@/action-menu/actions/types/SingleRecordActionHook';
|
||||
import {
|
||||
ActionMenuEntry,
|
||||
@ -25,8 +25,8 @@ export const DEFAULT_SINGLE_RECORD_ACTIONS_CONFIG_V1: Record<
|
||||
position: 0,
|
||||
Icon: IconHeart,
|
||||
availableOn: [
|
||||
ActionAvailableOn.SHOW_PAGE,
|
||||
ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionViewType.SHOW_PAGE,
|
||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
],
|
||||
actionHook: useAddToFavoritesSingleRecordAction,
|
||||
},
|
||||
@ -38,8 +38,8 @@ export const DEFAULT_SINGLE_RECORD_ACTIONS_CONFIG_V1: Record<
|
||||
position: 1,
|
||||
Icon: IconHeartOff,
|
||||
availableOn: [
|
||||
ActionAvailableOn.SHOW_PAGE,
|
||||
ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionViewType.SHOW_PAGE,
|
||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
],
|
||||
actionHook: useRemoveFromFavoritesSingleRecordAction,
|
||||
},
|
||||
@ -53,8 +53,8 @@ export const DEFAULT_SINGLE_RECORD_ACTIONS_CONFIG_V1: Record<
|
||||
accent: 'danger',
|
||||
isPinned: true,
|
||||
availableOn: [
|
||||
ActionAvailableOn.SHOW_PAGE,
|
||||
ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionViewType.SHOW_PAGE,
|
||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
],
|
||||
actionHook: useDeleteSingleRecordAction,
|
||||
},
|
||||
|
||||
@ -6,7 +6,7 @@ import { useNavigateToNextRecordSingleRecordAction } from '@/action-menu/actions
|
||||
import { useNavigateToPreviousRecordSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useNavigateToPreviousRecordSingleRecordAction';
|
||||
import { useRemoveFromFavoritesSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useRemoveFromFavoritesSingleRecordAction';
|
||||
import { SingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/types/SingleRecordActionsKey';
|
||||
import { ActionAvailableOn } from '@/action-menu/actions/types/ActionAvailableOn';
|
||||
import { ActionViewType } from '@/action-menu/actions/types/ActionViewType';
|
||||
import { SingleRecordActionHook } from '@/action-menu/actions/types/SingleRecordActionHook';
|
||||
import {
|
||||
ActionMenuEntry,
|
||||
@ -38,7 +38,7 @@ export const DEFAULT_SINGLE_RECORD_ACTIONS_CONFIG_V2: Record<
|
||||
position: 0,
|
||||
isPinned: false,
|
||||
Icon: IconFileExport,
|
||||
availableOn: [ActionAvailableOn.SHOW_PAGE],
|
||||
availableOn: [ActionViewType.SHOW_PAGE],
|
||||
actionHook: useExportNoteAction,
|
||||
},
|
||||
addToFavoritesSingleRecord: {
|
||||
@ -51,8 +51,8 @@ export const DEFAULT_SINGLE_RECORD_ACTIONS_CONFIG_V2: Record<
|
||||
isPinned: true,
|
||||
Icon: IconHeart,
|
||||
availableOn: [
|
||||
ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionAvailableOn.SHOW_PAGE,
|
||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionViewType.SHOW_PAGE,
|
||||
],
|
||||
actionHook: useAddToFavoritesSingleRecordAction,
|
||||
},
|
||||
@ -66,8 +66,8 @@ export const DEFAULT_SINGLE_RECORD_ACTIONS_CONFIG_V2: Record<
|
||||
position: 2,
|
||||
Icon: IconHeartOff,
|
||||
availableOn: [
|
||||
ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionAvailableOn.SHOW_PAGE,
|
||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionViewType.SHOW_PAGE,
|
||||
],
|
||||
actionHook: useRemoveFromFavoritesSingleRecordAction,
|
||||
},
|
||||
@ -82,8 +82,8 @@ export const DEFAULT_SINGLE_RECORD_ACTIONS_CONFIG_V2: Record<
|
||||
accent: 'danger',
|
||||
isPinned: true,
|
||||
availableOn: [
|
||||
ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionAvailableOn.SHOW_PAGE,
|
||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionViewType.SHOW_PAGE,
|
||||
],
|
||||
actionHook: useDeleteSingleRecordAction,
|
||||
},
|
||||
@ -98,8 +98,8 @@ export const DEFAULT_SINGLE_RECORD_ACTIONS_CONFIG_V2: Record<
|
||||
accent: 'danger',
|
||||
isPinned: true,
|
||||
availableOn: [
|
||||
ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionAvailableOn.SHOW_PAGE,
|
||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionViewType.SHOW_PAGE,
|
||||
],
|
||||
actionHook: useDestroySingleRecordAction,
|
||||
},
|
||||
@ -112,7 +112,7 @@ export const DEFAULT_SINGLE_RECORD_ACTIONS_CONFIG_V2: Record<
|
||||
position: 5,
|
||||
isPinned: true,
|
||||
Icon: IconChevronUp,
|
||||
availableOn: [ActionAvailableOn.SHOW_PAGE],
|
||||
availableOn: [ActionViewType.SHOW_PAGE],
|
||||
actionHook: useNavigateToPreviousRecordSingleRecordAction,
|
||||
},
|
||||
navigateToNextRecord: {
|
||||
@ -124,7 +124,7 @@ export const DEFAULT_SINGLE_RECORD_ACTIONS_CONFIG_V2: Record<
|
||||
position: 6,
|
||||
isPinned: true,
|
||||
Icon: IconChevronDown,
|
||||
availableOn: [ActionAvailableOn.SHOW_PAGE],
|
||||
availableOn: [ActionViewType.SHOW_PAGE],
|
||||
actionHook: useNavigateToNextRecordSingleRecordAction,
|
||||
},
|
||||
};
|
||||
|
||||
@ -14,7 +14,7 @@ import { useSeeRunsWorkflowSingleRecordAction } from '@/action-menu/actions/reco
|
||||
import { useSeeVersionsWorkflowSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-actions/hooks/useSeeVersionsWorkflowSingleRecordAction';
|
||||
import { useTestWorkflowSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-actions/hooks/useTestWorkflowSingleRecordAction';
|
||||
import { WorkflowSingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/workflow-actions/types/WorkflowSingleRecordActionsKeys';
|
||||
import { ActionAvailableOn } from '@/action-menu/actions/types/ActionAvailableOn';
|
||||
import { ActionViewType } from '@/action-menu/actions/types/ActionViewType';
|
||||
import { SingleRecordActionHook } from '@/action-menu/actions/types/SingleRecordActionHook';
|
||||
import {
|
||||
ActionMenuEntry,
|
||||
@ -51,8 +51,8 @@ export const WORKFLOW_SINGLE_RECORD_ACTIONS_CONFIG: Record<
|
||||
type: ActionMenuEntryType.Standard,
|
||||
scope: ActionMenuEntryScope.RecordSelection,
|
||||
availableOn: [
|
||||
ActionAvailableOn.SHOW_PAGE,
|
||||
ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionViewType.SHOW_PAGE,
|
||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
],
|
||||
actionHook: useActivateDraftWorkflowSingleRecordAction,
|
||||
},
|
||||
@ -66,8 +66,8 @@ export const WORKFLOW_SINGLE_RECORD_ACTIONS_CONFIG: Record<
|
||||
type: ActionMenuEntryType.Standard,
|
||||
scope: ActionMenuEntryScope.RecordSelection,
|
||||
availableOn: [
|
||||
ActionAvailableOn.SHOW_PAGE,
|
||||
ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionViewType.SHOW_PAGE,
|
||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
],
|
||||
actionHook: useActivateLastPublishedVersionWorkflowSingleRecordAction,
|
||||
},
|
||||
@ -81,8 +81,8 @@ export const WORKFLOW_SINGLE_RECORD_ACTIONS_CONFIG: Record<
|
||||
type: ActionMenuEntryType.Standard,
|
||||
scope: ActionMenuEntryScope.RecordSelection,
|
||||
availableOn: [
|
||||
ActionAvailableOn.SHOW_PAGE,
|
||||
ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionViewType.SHOW_PAGE,
|
||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
],
|
||||
actionHook: useDeactivateWorkflowSingleRecordAction,
|
||||
},
|
||||
@ -96,8 +96,8 @@ export const WORKFLOW_SINGLE_RECORD_ACTIONS_CONFIG: Record<
|
||||
type: ActionMenuEntryType.Standard,
|
||||
scope: ActionMenuEntryScope.RecordSelection,
|
||||
availableOn: [
|
||||
ActionAvailableOn.SHOW_PAGE,
|
||||
ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionViewType.SHOW_PAGE,
|
||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
],
|
||||
actionHook: useDiscardDraftWorkflowSingleRecordAction,
|
||||
},
|
||||
@ -111,8 +111,8 @@ export const WORKFLOW_SINGLE_RECORD_ACTIONS_CONFIG: Record<
|
||||
type: ActionMenuEntryType.Standard,
|
||||
scope: ActionMenuEntryScope.RecordSelection,
|
||||
availableOn: [
|
||||
ActionAvailableOn.SHOW_PAGE,
|
||||
ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionViewType.SHOW_PAGE,
|
||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
],
|
||||
actionHook: useSeeActiveVersionWorkflowSingleRecordAction,
|
||||
},
|
||||
@ -126,8 +126,8 @@ export const WORKFLOW_SINGLE_RECORD_ACTIONS_CONFIG: Record<
|
||||
type: ActionMenuEntryType.Standard,
|
||||
scope: ActionMenuEntryScope.RecordSelection,
|
||||
availableOn: [
|
||||
ActionAvailableOn.SHOW_PAGE,
|
||||
ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionViewType.SHOW_PAGE,
|
||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
],
|
||||
actionHook: useSeeRunsWorkflowSingleRecordAction,
|
||||
},
|
||||
@ -141,8 +141,8 @@ export const WORKFLOW_SINGLE_RECORD_ACTIONS_CONFIG: Record<
|
||||
type: ActionMenuEntryType.Standard,
|
||||
scope: ActionMenuEntryScope.RecordSelection,
|
||||
availableOn: [
|
||||
ActionAvailableOn.SHOW_PAGE,
|
||||
ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionViewType.SHOW_PAGE,
|
||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
],
|
||||
actionHook: useSeeVersionsWorkflowSingleRecordAction,
|
||||
},
|
||||
@ -156,8 +156,8 @@ export const WORKFLOW_SINGLE_RECORD_ACTIONS_CONFIG: Record<
|
||||
type: ActionMenuEntryType.Standard,
|
||||
scope: ActionMenuEntryScope.RecordSelection,
|
||||
availableOn: [
|
||||
ActionAvailableOn.SHOW_PAGE,
|
||||
ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionViewType.SHOW_PAGE,
|
||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
],
|
||||
actionHook: useTestWorkflowSingleRecordAction,
|
||||
},
|
||||
@ -169,7 +169,7 @@ export const WORKFLOW_SINGLE_RECORD_ACTIONS_CONFIG: Record<
|
||||
shortLabel: '',
|
||||
position: 9,
|
||||
Icon: IconChevronUp,
|
||||
availableOn: [ActionAvailableOn.SHOW_PAGE],
|
||||
availableOn: [ActionViewType.SHOW_PAGE],
|
||||
actionHook: useNavigateToPreviousRecordSingleRecordAction,
|
||||
},
|
||||
navigateToNextRecord: {
|
||||
@ -180,7 +180,7 @@ export const WORKFLOW_SINGLE_RECORD_ACTIONS_CONFIG: Record<
|
||||
shortLabel: '',
|
||||
position: 10,
|
||||
Icon: IconChevronDown,
|
||||
availableOn: [ActionAvailableOn.SHOW_PAGE],
|
||||
availableOn: [ActionViewType.SHOW_PAGE],
|
||||
actionHook: useNavigateToNextRecordSingleRecordAction,
|
||||
},
|
||||
addToFavoritesSingleRecord: {
|
||||
@ -193,8 +193,8 @@ export const WORKFLOW_SINGLE_RECORD_ACTIONS_CONFIG: Record<
|
||||
isPinned: false,
|
||||
Icon: IconHeart,
|
||||
availableOn: [
|
||||
ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionAvailableOn.SHOW_PAGE,
|
||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionViewType.SHOW_PAGE,
|
||||
],
|
||||
actionHook: useAddToFavoritesSingleRecordAction,
|
||||
},
|
||||
@ -208,8 +208,8 @@ export const WORKFLOW_SINGLE_RECORD_ACTIONS_CONFIG: Record<
|
||||
position: 12,
|
||||
Icon: IconHeartOff,
|
||||
availableOn: [
|
||||
ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionAvailableOn.SHOW_PAGE,
|
||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionViewType.SHOW_PAGE,
|
||||
],
|
||||
actionHook: useRemoveFromFavoritesSingleRecordAction,
|
||||
},
|
||||
@ -224,8 +224,8 @@ export const WORKFLOW_SINGLE_RECORD_ACTIONS_CONFIG: Record<
|
||||
accent: 'danger',
|
||||
isPinned: false,
|
||||
availableOn: [
|
||||
ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionAvailableOn.SHOW_PAGE,
|
||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionViewType.SHOW_PAGE,
|
||||
],
|
||||
actionHook: useDeleteSingleRecordAction,
|
||||
},
|
||||
@ -240,8 +240,8 @@ export const WORKFLOW_SINGLE_RECORD_ACTIONS_CONFIG: Record<
|
||||
accent: 'danger',
|
||||
isPinned: false,
|
||||
availableOn: [
|
||||
ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionAvailableOn.SHOW_PAGE,
|
||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionViewType.SHOW_PAGE,
|
||||
],
|
||||
actionHook: useDestroySingleRecordAction,
|
||||
},
|
||||
|
||||
@ -3,7 +3,7 @@ import { useNavigateToNextRecordSingleRecordAction } from '@/action-menu/actions
|
||||
import { useNavigateToPreviousRecordSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useNavigateToPreviousRecordSingleRecordAction';
|
||||
import { useRemoveFromFavoritesSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useRemoveFromFavoritesSingleRecordAction';
|
||||
import { SingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/types/SingleRecordActionsKey';
|
||||
import { ActionAvailableOn } from '@/action-menu/actions/types/ActionAvailableOn';
|
||||
import { ActionViewType } from '@/action-menu/actions/types/ActionViewType';
|
||||
import { SingleRecordActionHook } from '@/action-menu/actions/types/SingleRecordActionHook';
|
||||
import {
|
||||
ActionMenuEntry,
|
||||
@ -33,8 +33,8 @@ export const WORKFLOW_RUNS_SINGLE_RECORD_ACTIONS_CONFIG: Record<
|
||||
isPinned: true,
|
||||
Icon: IconHeart,
|
||||
availableOn: [
|
||||
ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionAvailableOn.SHOW_PAGE,
|
||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionViewType.SHOW_PAGE,
|
||||
],
|
||||
actionHook: useAddToFavoritesSingleRecordAction,
|
||||
},
|
||||
@ -48,8 +48,8 @@ export const WORKFLOW_RUNS_SINGLE_RECORD_ACTIONS_CONFIG: Record<
|
||||
position: 1,
|
||||
Icon: IconHeartOff,
|
||||
availableOn: [
|
||||
ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionAvailableOn.SHOW_PAGE,
|
||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionViewType.SHOW_PAGE,
|
||||
],
|
||||
actionHook: useRemoveFromFavoritesSingleRecordAction,
|
||||
},
|
||||
@ -62,7 +62,7 @@ export const WORKFLOW_RUNS_SINGLE_RECORD_ACTIONS_CONFIG: Record<
|
||||
position: 2,
|
||||
isPinned: true,
|
||||
Icon: IconChevronUp,
|
||||
availableOn: [ActionAvailableOn.SHOW_PAGE],
|
||||
availableOn: [ActionViewType.SHOW_PAGE],
|
||||
actionHook: useNavigateToPreviousRecordSingleRecordAction,
|
||||
},
|
||||
navigateToNextRecord: {
|
||||
@ -74,7 +74,7 @@ export const WORKFLOW_RUNS_SINGLE_RECORD_ACTIONS_CONFIG: Record<
|
||||
position: 3,
|
||||
isPinned: true,
|
||||
Icon: IconChevronDown,
|
||||
availableOn: [ActionAvailableOn.SHOW_PAGE],
|
||||
availableOn: [ActionViewType.SHOW_PAGE],
|
||||
actionHook: useNavigateToNextRecordSingleRecordAction,
|
||||
},
|
||||
};
|
||||
|
||||
@ -7,7 +7,7 @@ import { useSeeRunsWorkflowVersionSingleRecordAction } from '@/action-menu/actio
|
||||
import { useSeeVersionsWorkflowVersionSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-version-actions/hooks/useSeeVersionsWorkflowVersionSingleRecordAction';
|
||||
import { useUseAsDraftWorkflowVersionSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-version-actions/hooks/useUseAsDraftWorkflowVersionSingleRecordAction';
|
||||
import { WorkflowVersionSingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/workflow-version-actions/types/WorkflowVersionSingleRecordActionsKeys';
|
||||
import { ActionAvailableOn } from '@/action-menu/actions/types/ActionAvailableOn';
|
||||
import { ActionViewType } from '@/action-menu/actions/types/ActionViewType';
|
||||
import { SingleRecordActionHook } from '@/action-menu/actions/types/SingleRecordActionHook';
|
||||
import {
|
||||
ActionMenuEntry,
|
||||
@ -40,8 +40,8 @@ export const WORKFLOW_VERSIONS_SINGLE_RECORD_ACTIONS_CONFIG: Record<
|
||||
scope: ActionMenuEntryScope.RecordSelection,
|
||||
Icon: IconPencil,
|
||||
availableOn: [
|
||||
ActionAvailableOn.SHOW_PAGE,
|
||||
ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionViewType.SHOW_PAGE,
|
||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
],
|
||||
actionHook: useUseAsDraftWorkflowVersionSingleRecordAction,
|
||||
},
|
||||
@ -54,8 +54,8 @@ export const WORKFLOW_VERSIONS_SINGLE_RECORD_ACTIONS_CONFIG: Record<
|
||||
scope: ActionMenuEntryScope.RecordSelection,
|
||||
Icon: IconHistoryToggle,
|
||||
availableOn: [
|
||||
ActionAvailableOn.SHOW_PAGE,
|
||||
ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionViewType.SHOW_PAGE,
|
||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
],
|
||||
actionHook: useSeeRunsWorkflowVersionSingleRecordAction,
|
||||
},
|
||||
@ -68,8 +68,8 @@ export const WORKFLOW_VERSIONS_SINGLE_RECORD_ACTIONS_CONFIG: Record<
|
||||
scope: ActionMenuEntryScope.RecordSelection,
|
||||
Icon: IconHistory,
|
||||
availableOn: [
|
||||
ActionAvailableOn.SHOW_PAGE,
|
||||
ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionViewType.SHOW_PAGE,
|
||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
],
|
||||
actionHook: useSeeVersionsWorkflowVersionSingleRecordAction,
|
||||
},
|
||||
@ -81,7 +81,7 @@ export const WORKFLOW_VERSIONS_SINGLE_RECORD_ACTIONS_CONFIG: Record<
|
||||
shortLabel: '',
|
||||
position: 4,
|
||||
Icon: IconChevronUp,
|
||||
availableOn: [ActionAvailableOn.SHOW_PAGE],
|
||||
availableOn: [ActionViewType.SHOW_PAGE],
|
||||
actionHook: useNavigateToPreviousRecordSingleRecordAction,
|
||||
},
|
||||
navigateToNextRecord: {
|
||||
@ -92,7 +92,7 @@ export const WORKFLOW_VERSIONS_SINGLE_RECORD_ACTIONS_CONFIG: Record<
|
||||
shortLabel: '',
|
||||
position: 5,
|
||||
Icon: IconChevronDown,
|
||||
availableOn: [ActionAvailableOn.SHOW_PAGE],
|
||||
availableOn: [ActionViewType.SHOW_PAGE],
|
||||
actionHook: useNavigateToNextRecordSingleRecordAction,
|
||||
},
|
||||
addToFavoritesSingleRecord: {
|
||||
@ -105,8 +105,8 @@ export const WORKFLOW_VERSIONS_SINGLE_RECORD_ACTIONS_CONFIG: Record<
|
||||
isPinned: false,
|
||||
Icon: IconHeart,
|
||||
availableOn: [
|
||||
ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionAvailableOn.SHOW_PAGE,
|
||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionViewType.SHOW_PAGE,
|
||||
],
|
||||
actionHook: useAddToFavoritesSingleRecordAction,
|
||||
},
|
||||
@ -120,8 +120,8 @@ export const WORKFLOW_VERSIONS_SINGLE_RECORD_ACTIONS_CONFIG: Record<
|
||||
position: 7,
|
||||
Icon: IconHeartOff,
|
||||
availableOn: [
|
||||
ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionAvailableOn.SHOW_PAGE,
|
||||
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||
ActionViewType.SHOW_PAGE,
|
||||
],
|
||||
actionHook: useRemoveFromFavoritesSingleRecordAction,
|
||||
},
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
export enum ActionAvailableOn {
|
||||
export enum ActionViewType {
|
||||
INDEX_PAGE_BULK_SELECTION = 'INDEX_PAGE_BULK_SELECTION',
|
||||
INDEX_PAGE_SINGLE_RECORD_SELECTION = 'INDEX_PAGE_SINGLE_RECORD_SELECTION',
|
||||
INDEX_PAGE_NO_SELECTION = 'INDEX_PAGE_NO_SELECTION',
|
||||
@ -1,20 +1,18 @@
|
||||
import { getActionConfig } from '@/action-menu/actions/record-actions/single-record/utils/getActionConfig';
|
||||
import { ActionAvailableOn } from '@/action-menu/actions/types/ActionAvailableOn';
|
||||
import { ActionViewType } from '@/action-menu/actions/types/ActionViewType';
|
||||
import { wrapActionInCallbacks } from '@/action-menu/actions/utils/wrapActionInCallbacks';
|
||||
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||
import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries';
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { useContext, useEffect } from 'react';
|
||||
import { useContext } from 'react';
|
||||
import { isDefined } from 'twenty-ui';
|
||||
|
||||
export const ShowPageSingleRecordActionMenuEntrySetterEffect = ({
|
||||
objectMetadataItem,
|
||||
}: {
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
}) => {
|
||||
export const useActionMenuEntriesWithCallbacks = (
|
||||
objectMetadataItem: ObjectMetadataItem,
|
||||
viewType: ActionViewType,
|
||||
) => {
|
||||
const isPageHeaderV2Enabled = useIsFeatureEnabled(
|
||||
'IS_PAGE_HEADER_V2_ENABLED',
|
||||
);
|
||||
@ -24,8 +22,6 @@ export const ShowPageSingleRecordActionMenuEntrySetterEffect = ({
|
||||
isPageHeaderV2Enabled,
|
||||
);
|
||||
|
||||
const { addActionMenuEntry, removeActionMenuEntry } = useActionMenuEntries();
|
||||
|
||||
const contextStoreTargetedRecordsRule = useRecoilComponentValueV2(
|
||||
contextStoreTargetedRecordsRuleComponentState,
|
||||
);
|
||||
@ -38,13 +34,12 @@ export const ShowPageSingleRecordActionMenuEntrySetterEffect = ({
|
||||
if (!isDefined(selectedRecordId)) {
|
||||
throw new Error('Selected record ID is required');
|
||||
}
|
||||
|
||||
const { onActionStartedCallback, onActionExecutedCallback } =
|
||||
useContext(ActionMenuContext);
|
||||
|
||||
const actionMenuEntries = Object.values(actionConfig ?? {})
|
||||
.filter((action) =>
|
||||
action.availableOn?.includes(ActionAvailableOn.SHOW_PAGE),
|
||||
)
|
||||
.filter((action) => action.availableOn?.includes(viewType))
|
||||
.map((action) => {
|
||||
const { shouldBeRegistered, onClick, ConfirmationModal } =
|
||||
action.actionHook({
|
||||
@ -70,17 +65,5 @@ export const ShowPageSingleRecordActionMenuEntrySetterEffect = ({
|
||||
})
|
||||
.filter(isDefined);
|
||||
|
||||
useEffect(() => {
|
||||
for (const action of actionMenuEntries) {
|
||||
addActionMenuEntry(action);
|
||||
}
|
||||
|
||||
return () => {
|
||||
for (const action of actionMenuEntries) {
|
||||
removeActionMenuEntry(action.key);
|
||||
}
|
||||
};
|
||||
}, [actionMenuEntries, addActionMenuEntry, removeActionMenuEntry]);
|
||||
|
||||
return null;
|
||||
return { actionMenuEntries };
|
||||
};
|
||||
@ -1,4 +1,4 @@
|
||||
import { ActionAvailableOn } from '@/action-menu/actions/types/ActionAvailableOn';
|
||||
import { ActionViewType } from '@/action-menu/actions/types/ActionViewType';
|
||||
import { ConfirmationModalProps } from '@/ui/layout/modal/components/ConfirmationModal';
|
||||
import { MouseEvent, ReactElement } from 'react';
|
||||
import { IconComponent, MenuItemAccent } from 'twenty-ui';
|
||||
@ -23,7 +23,7 @@ export type ActionMenuEntry = {
|
||||
Icon: IconComponent;
|
||||
isPinned?: boolean;
|
||||
accent?: MenuItemAccent;
|
||||
availableOn?: ActionAvailableOn[];
|
||||
availableOn?: ActionViewType[];
|
||||
onClick?: (event?: MouseEvent<HTMLElement>) => void;
|
||||
ConfirmationModal?: ReactElement<ConfirmationModalProps>;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user