diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter.tsx index 254a0f20e..7081c310c 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter.tsx @@ -1,9 +1,12 @@ 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 { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState'; +import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; +import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType'; import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById'; import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; @@ -46,6 +49,10 @@ const ActionEffects = ({ contextStoreTargetedRecordsRuleComponentState, ); + const contextStoreCurrentViewType = useRecoilComponentValueV2( + contextStoreCurrentViewTypeComponentState, + ); + const isWorkflowEnabled = useIsFeatureEnabled('IS_WORKFLOW_ENABLED'); return ( @@ -59,9 +66,17 @@ const ActionEffects = ({ {contextStoreTargetedRecordsRule.mode === 'selection' && contextStoreTargetedRecordsRule.selectedRecordIds.length === 1 && ( <> - + {contextStoreCurrentViewType === ContextStoreViewType.ShowPage && ( + + )} + {(contextStoreCurrentViewType === ContextStoreViewType.Table || + contextStoreCurrentViewType === ContextStoreViewType.Kanban) && ( + + )} {isWorkflowEnabled && ( { + const isPageHeaderV2Enabled = useIsFeatureEnabled( + 'IS_PAGE_HEADER_V2_ENABLED', + ); + + const actionConfig = getActionConfig( + objectMetadataItem, + isPageHeaderV2Enabled, + ); + + const { addActionMenuEntry, removeActionMenuEntry } = useActionMenuEntries(); + + const contextStoreTargetedRecordsRule = useRecoilComponentValueV2( + contextStoreTargetedRecordsRuleComponentState, + ); + + const selectedRecordId = + contextStoreTargetedRecordsRule.mode === 'selection' + ? contextStoreTargetedRecordsRule.selectedRecordIds[0] + : undefined; + + if (!isDefined(selectedRecordId)) { + throw new Error('Selected record ID is required'); + } + + const actionMenuEntries = Object.values(actionConfig ?? {}) + .filter((action) => + action.availableOn?.includes(ActionAvailableOn.SHOW_PAGE), + ) + .map((action) => { + const { shouldBeRegistered, onClick, ConfirmationModal } = + action.actionHook({ + recordId: selectedRecordId, + objectMetadataItem, + }); + + if (shouldBeRegistered) { + return { + ...action, + onClick, + ConfirmationModal, + }; + } + + return undefined; + }) + .filter(isDefined); + + useEffect(() => { + for (const action of actionMenuEntries) { + addActionMenuEntry(action); + } + + return () => { + for (const action of actionMenuEntries) { + removeActionMenuEntry(action.key); + } + }; + }, [actionMenuEntries, addActionMenuEntry, removeActionMenuEntry]); + + return null; +}; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/components/SingleRecordActionMenuEntrySetterEffect.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/components/SingleRecordActionMenuEntrySetterEffect.tsx index f2e803d30..9238772a6 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/components/SingleRecordActionMenuEntrySetterEffect.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/components/SingleRecordActionMenuEntrySetterEffect.tsx @@ -1,4 +1,5 @@ import { getActionConfig } from '@/action-menu/actions/record-actions/single-record/utils/getActionConfig'; +import { ActionAvailableOn } from '@/action-menu/actions/types/actionAvailableOn'; import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; @@ -37,6 +38,11 @@ export const SingleRecordActionMenuEntrySetterEffect = ({ } const actionMenuEntries = Object.values(actionConfig ?? {}) + .filter((action) => + action.availableOn?.includes( + ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION, + ), + ) .map((action) => { const { shouldBeRegistered, onClick, ConfirmationModal } = action.actionHook({ diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/constants/DefaultSingleRecordActionsConfigV1.ts b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/constants/DefaultSingleRecordActionsConfigV1.ts index 269b5f585..db6512154 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/constants/DefaultSingleRecordActionsConfigV1.ts +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/constants/DefaultSingleRecordActionsConfigV1.ts @@ -1,6 +1,7 @@ import { useAddToFavoritesSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useAddToFavoritesSingleRecordAction'; import { useDeleteSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useDeleteSingleRecordAction'; import { useRemoveFromFavoritesSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useRemoveFromFavoritesSingleRecordAction'; +import { ActionAvailableOn } from '@/action-menu/actions/types/actionAvailableOn'; import { SingleRecordActionHook } from '@/action-menu/actions/types/singleRecordActionHook'; import { ActionMenuEntry, @@ -22,6 +23,10 @@ export const DEFAULT_SINGLE_RECORD_ACTIONS_CONFIG_V1: Record< label: 'Add to favorites', position: 0, Icon: IconHeart, + availableOn: [ + ActionAvailableOn.SHOW_PAGE, + ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION, + ], actionHook: useAddToFavoritesSingleRecordAction, }, removeFromFavoritesSingleRecord: { @@ -31,6 +36,10 @@ export const DEFAULT_SINGLE_RECORD_ACTIONS_CONFIG_V1: Record< label: 'Remove from favorites', position: 1, Icon: IconHeartOff, + availableOn: [ + ActionAvailableOn.SHOW_PAGE, + ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION, + ], actionHook: useRemoveFromFavoritesSingleRecordAction, }, deleteSingleRecord: { @@ -42,6 +51,10 @@ export const DEFAULT_SINGLE_RECORD_ACTIONS_CONFIG_V1: Record< Icon: IconTrash, accent: 'danger', isPinned: true, + availableOn: [ + ActionAvailableOn.SHOW_PAGE, + ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION, + ], actionHook: useDeleteSingleRecordAction, }, }; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/constants/DefaultSingleRecordActionsConfigV2.ts b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/constants/DefaultSingleRecordActionsConfigV2.ts index dbfc40569..984771456 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/constants/DefaultSingleRecordActionsConfigV2.ts +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/constants/DefaultSingleRecordActionsConfigV2.ts @@ -1,13 +1,22 @@ import { useAddToFavoritesSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useAddToFavoritesSingleRecordAction'; import { useDeleteSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useDeleteSingleRecordAction'; +import { useNavigateToNextRecordSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useNavigateToNextRecordSingleRecordAction'; +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 { ActionAvailableOn } from '@/action-menu/actions/types/actionAvailableOn'; import { SingleRecordActionHook } from '@/action-menu/actions/types/singleRecordActionHook'; import { ActionMenuEntry, ActionMenuEntryScope, ActionMenuEntryType, } from '@/action-menu/types/ActionMenuEntry'; -import { IconHeart, IconHeartOff, IconTrash } from 'twenty-ui'; +import { + IconChevronDown, + IconChevronUp, + IconHeart, + IconHeartOff, + IconTrash, +} from 'twenty-ui'; export const DEFAULT_SINGLE_RECORD_ACTIONS_CONFIG_V2: Record< string, @@ -20,9 +29,14 @@ export const DEFAULT_SINGLE_RECORD_ACTIONS_CONFIG_V2: Record< scope: ActionMenuEntryScope.RecordSelection, key: 'add-to-favorites-single-record', label: 'Add to favorites', + shortLabel: 'Add to favorites', position: 0, isPinned: true, Icon: IconHeart, + availableOn: [ + ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION, + ActionAvailableOn.SHOW_PAGE, + ], actionHook: useAddToFavoritesSingleRecordAction, }, removeFromFavoritesSingleRecord: { @@ -30,20 +44,54 @@ export const DEFAULT_SINGLE_RECORD_ACTIONS_CONFIG_V2: Record< scope: ActionMenuEntryScope.RecordSelection, key: 'remove-from-favorites-single-record', label: 'Remove from favorites', + shortLabel: 'Remove from favorites', isPinned: true, position: 1, Icon: IconHeartOff, + availableOn: [ + ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION, + ActionAvailableOn.SHOW_PAGE, + ], actionHook: useRemoveFromFavoritesSingleRecordAction, }, deleteSingleRecord: { type: ActionMenuEntryType.Standard, scope: ActionMenuEntryScope.RecordSelection, key: 'delete-single-record', - label: 'Delete', + label: 'Delete record', + shortLabel: 'Delete', position: 2, Icon: IconTrash, accent: 'danger', isPinned: true, + availableOn: [ + ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION, + ActionAvailableOn.SHOW_PAGE, + ], actionHook: useDeleteSingleRecordAction, }, + navigateToPreviousRecord: { + type: ActionMenuEntryType.Standard, + scope: ActionMenuEntryScope.RecordSelection, + key: 'navigate-to-previous-record', + label: 'Navigate to previous record', + shortLabel: '', + position: 3, + isPinned: true, + Icon: IconChevronUp, + availableOn: [ActionAvailableOn.SHOW_PAGE], + actionHook: useNavigateToPreviousRecordSingleRecordAction, + }, + navigateToNextRecord: { + type: ActionMenuEntryType.Standard, + scope: ActionMenuEntryScope.RecordSelection, + key: 'navigate-to-next-record', + label: 'Navigate to next record', + shortLabel: '', + position: 4, + isPinned: true, + Icon: IconChevronDown, + availableOn: [ActionAvailableOn.SHOW_PAGE], + actionHook: useNavigateToNextRecordSingleRecordAction, + }, }; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useNavigateToNextRecordSingleRecordAction.ts b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useNavigateToNextRecordSingleRecordAction.ts new file mode 100644 index 000000000..a775d5275 --- /dev/null +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useNavigateToNextRecordSingleRecordAction.ts @@ -0,0 +1,15 @@ +import { SingleRecordActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/singleRecordActionHook'; +import { useRecordShowPagePagination } from '@/object-record/record-show/hooks/useRecordShowPagePagination'; + +export const useNavigateToNextRecordSingleRecordAction: SingleRecordActionHookWithObjectMetadataItem = + ({ recordId, objectMetadataItem }) => { + const { navigateToNextRecord } = useRecordShowPagePagination( + objectMetadataItem.nameSingular, + recordId, + ); + + return { + shouldBeRegistered: true, + onClick: navigateToNextRecord, + }; + }; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useNavigateToPreviousRecordSingleRecordAction.ts b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useNavigateToPreviousRecordSingleRecordAction.ts new file mode 100644 index 000000000..f1287a68f --- /dev/null +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useNavigateToPreviousRecordSingleRecordAction.ts @@ -0,0 +1,15 @@ +import { SingleRecordActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/singleRecordActionHook'; +import { useRecordShowPagePagination } from '@/object-record/record-show/hooks/useRecordShowPagePagination'; + +export const useNavigateToPreviousRecordSingleRecordAction: SingleRecordActionHookWithObjectMetadataItem = + ({ recordId, objectMetadataItem }) => { + const { navigateToPreviousRecord } = useRecordShowPagePagination( + objectMetadataItem.nameSingular, + recordId, + ); + + return { + shouldBeRegistered: true, + onClick: navigateToPreviousRecord, + }; + }; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-actions/constants/WorkflowSingleRecordActionsConfig.ts b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-actions/constants/WorkflowSingleRecordActionsConfig.ts index fcad03ea9..c168ffe54 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-actions/constants/WorkflowSingleRecordActionsConfig.ts +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-actions/constants/WorkflowSingleRecordActionsConfig.ts @@ -1,3 +1,5 @@ +import { useNavigateToNextRecordSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useNavigateToNextRecordSingleRecordAction'; +import { useNavigateToPreviousRecordSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useNavigateToPreviousRecordSingleRecordAction'; import { useActivateDraftWorkflowSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-actions/hooks/useActivateDraftWorkflowSingleRecordAction'; import { useActivateLastPublishedVersionWorkflowSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-actions/hooks/useActivateLastPublishedVersionWorkflowSingleRecordAction'; import { useDeactivateWorkflowSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-actions/hooks/useDeactivateWorkflowSingleRecordAction'; @@ -6,6 +8,7 @@ import { useSeeActiveVersionWorkflowSingleRecordAction } from '@/action-menu/act import { useSeeRunsWorkflowSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-actions/hooks/useSeeRunsWorkflowSingleRecordAction'; 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 { ActionAvailableOn } from '@/action-menu/actions/types/actionAvailableOn'; import { SingleRecordActionHook } from '@/action-menu/actions/types/singleRecordActionHook'; import { ActionMenuEntry, @@ -13,6 +16,8 @@ import { ActionMenuEntryType, } from '@/action-menu/types/ActionMenuEntry'; import { + IconChevronDown, + IconChevronUp, IconHistory, IconHistoryToggle, IconPlayerPause, @@ -30,81 +35,143 @@ export const WORKFLOW_SINGLE_RECORD_ACTIONS_CONFIG: Record< activateWorkflowDraftSingleRecord: { key: 'activate-workflow-draft-single-record', label: 'Activate Draft', + shortLabel: 'Activate Draft', isPinned: true, position: 1, Icon: IconPower, type: ActionMenuEntryType.Standard, scope: ActionMenuEntryScope.RecordSelection, + availableOn: [ + ActionAvailableOn.SHOW_PAGE, + ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION, + ], actionHook: useActivateDraftWorkflowSingleRecordAction, }, activateWorkflowLastPublishedVersionSingleRecord: { key: 'activate-workflow-last-published-version-single-record', label: 'Activate last published version', + shortLabel: 'Activate last version', isPinned: true, position: 2, Icon: IconPower, type: ActionMenuEntryType.Standard, scope: ActionMenuEntryScope.RecordSelection, + availableOn: [ + ActionAvailableOn.SHOW_PAGE, + ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION, + ], actionHook: useActivateLastPublishedVersionWorkflowSingleRecordAction, }, deactivateWorkflowSingleRecord: { key: 'deactivate-workflow-single-record', label: 'Deactivate Workflow', + shortLabel: 'Deactivate', isPinned: true, position: 3, Icon: IconPlayerPause, type: ActionMenuEntryType.Standard, scope: ActionMenuEntryScope.RecordSelection, + availableOn: [ + ActionAvailableOn.SHOW_PAGE, + ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION, + ], actionHook: useDeactivateWorkflowSingleRecordAction, }, discardWorkflowDraftSingleRecord: { key: 'discard-workflow-draft-single-record', label: 'Discard Draft', + shortLabel: 'Discard Draft', isPinned: true, position: 4, Icon: IconTrash, type: ActionMenuEntryType.Standard, scope: ActionMenuEntryScope.RecordSelection, + availableOn: [ + ActionAvailableOn.SHOW_PAGE, + ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION, + ], actionHook: useDiscardDraftWorkflowSingleRecordAction, }, seeWorkflowActiveVersionSingleRecord: { key: 'see-workflow-active-version-single-record', label: 'See active version', + shortLabel: 'See active version', isPinned: false, position: 5, Icon: IconHistory, type: ActionMenuEntryType.Standard, scope: ActionMenuEntryScope.RecordSelection, + availableOn: [ + ActionAvailableOn.SHOW_PAGE, + ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION, + ], actionHook: useSeeActiveVersionWorkflowSingleRecordAction, }, seeWorkflowRunsSingleRecord: { key: 'see-workflow-runs-single-record', label: 'See runs', + shortLabel: 'See runs', isPinned: false, position: 6, Icon: IconHistoryToggle, type: ActionMenuEntryType.Standard, scope: ActionMenuEntryScope.RecordSelection, + availableOn: [ + ActionAvailableOn.SHOW_PAGE, + ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION, + ], actionHook: useSeeRunsWorkflowSingleRecordAction, }, seeWorkflowVersionsHistorySingleRecord: { key: 'see-workflow-versions-history-single-record', label: 'See versions history', + shortLabel: 'See versions', isPinned: false, position: 7, Icon: IconHistory, type: ActionMenuEntryType.Standard, scope: ActionMenuEntryScope.RecordSelection, + availableOn: [ + ActionAvailableOn.SHOW_PAGE, + ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION, + ], actionHook: useSeeVersionsWorkflowSingleRecordAction, }, testWorkflowSingleRecord: { key: 'test-workflow-single-record', label: 'Test Workflow', + shortLabel: 'Test', isPinned: true, position: 8, Icon: IconPlayerPlay, type: ActionMenuEntryType.Standard, scope: ActionMenuEntryScope.RecordSelection, + availableOn: [ + ActionAvailableOn.SHOW_PAGE, + ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION, + ], actionHook: useTestWorkflowSingleRecordAction, }, + navigateToPreviousRecord: { + type: ActionMenuEntryType.Standard, + scope: ActionMenuEntryScope.RecordSelection, + key: 'navigate-to-previous-record', + label: 'Navigate to previous workflow', + shortLabel: '', + position: 9, + Icon: IconChevronUp, + availableOn: [ActionAvailableOn.SHOW_PAGE], + actionHook: useNavigateToPreviousRecordSingleRecordAction, + }, + navigateToNextRecord: { + type: ActionMenuEntryType.Standard, + scope: ActionMenuEntryScope.RecordSelection, + key: 'navigate-to-next-record', + label: 'Navigate to next workflow', + shortLabel: '', + position: 10, + Icon: IconChevronDown, + availableOn: [ActionAvailableOn.SHOW_PAGE], + actionHook: useNavigateToNextRecordSingleRecordAction, + }, }; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-version-actions/constants/WorkflowVersionsSingleRecordActionsConfig.ts b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-version-actions/constants/WorkflowVersionsSingleRecordActionsConfig.ts index 7e9480914..659d0e166 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-version-actions/constants/WorkflowVersionsSingleRecordActionsConfig.ts +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/workflow-version-actions/constants/WorkflowVersionsSingleRecordActionsConfig.ts @@ -1,13 +1,22 @@ +import { useNavigateToNextRecordSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useNavigateToNextRecordSingleRecordAction'; +import { useNavigateToPreviousRecordSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useNavigateToPreviousRecordSingleRecordAction'; import { useSeeExecutionsWorkflowVersionSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-version-actions/hooks/useSeeExecutionsWorkflowVersionSingleRecordAction'; 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 { ActionAvailableOn } from '@/action-menu/actions/types/actionAvailableOn'; import { SingleRecordActionHook } from '@/action-menu/actions/types/singleRecordActionHook'; import { ActionMenuEntry, ActionMenuEntryScope, ActionMenuEntryType, } from '@/action-menu/types/ActionMenuEntry'; -import { IconHistory, IconHistoryToggle, IconPencil } from 'twenty-ui'; +import { + IconChevronDown, + IconChevronUp, + IconHistory, + IconHistoryToggle, + IconPencil, +} from 'twenty-ui'; export const WORKFLOW_VERSIONS_SINGLE_RECORD_ACTIONS_CONFIG: Record< string, @@ -23,6 +32,10 @@ export const WORKFLOW_VERSIONS_SINGLE_RECORD_ACTIONS_CONFIG: Record< type: ActionMenuEntryType.Standard, scope: ActionMenuEntryScope.RecordSelection, Icon: IconPencil, + availableOn: [ + ActionAvailableOn.SHOW_PAGE, + ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION, + ], actionHook: useUseAsDraftWorkflowVersionSingleRecordAction, }, seeWorkflowExecutionsSingleRecord: { @@ -32,6 +45,10 @@ export const WORKFLOW_VERSIONS_SINGLE_RECORD_ACTIONS_CONFIG: Record< type: ActionMenuEntryType.Standard, scope: ActionMenuEntryScope.RecordSelection, Icon: IconHistoryToggle, + availableOn: [ + ActionAvailableOn.SHOW_PAGE, + ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION, + ], actionHook: useSeeExecutionsWorkflowVersionSingleRecordAction, }, seeWorkflowVersionsHistorySingleRecord: { @@ -41,6 +58,32 @@ export const WORKFLOW_VERSIONS_SINGLE_RECORD_ACTIONS_CONFIG: Record< type: ActionMenuEntryType.Standard, scope: ActionMenuEntryScope.RecordSelection, Icon: IconHistory, + availableOn: [ + ActionAvailableOn.SHOW_PAGE, + ActionAvailableOn.INDEX_PAGE_SINGLE_RECORD_SELECTION, + ], actionHook: useSeeVersionsWorkflowVersionSingleRecordAction, }, + navigateToPreviousRecord: { + type: ActionMenuEntryType.Standard, + scope: ActionMenuEntryScope.RecordSelection, + key: 'navigate-to-previous-record', + label: 'Navigate to previous version', + shortLabel: '', + position: 9, + Icon: IconChevronUp, + availableOn: [ActionAvailableOn.SHOW_PAGE], + actionHook: useNavigateToPreviousRecordSingleRecordAction, + }, + navigateToNextRecord: { + type: ActionMenuEntryType.Standard, + scope: ActionMenuEntryScope.RecordSelection, + key: 'navigate-to-next-record', + label: 'Navigate to next version', + shortLabel: '', + position: 10, + Icon: IconChevronDown, + availableOn: [ActionAvailableOn.SHOW_PAGE], + actionHook: useNavigateToNextRecordSingleRecordAction, + }, }; diff --git a/packages/twenty-front/src/modules/action-menu/actions/types/actionAvailableOn.ts b/packages/twenty-front/src/modules/action-menu/actions/types/actionAvailableOn.ts new file mode 100644 index 000000000..fafc2a1e3 --- /dev/null +++ b/packages/twenty-front/src/modules/action-menu/actions/types/actionAvailableOn.ts @@ -0,0 +1,6 @@ +export enum ActionAvailableOn { + 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', + SHOW_PAGE = 'SHOW_PAGE', +} diff --git a/packages/twenty-front/src/modules/action-menu/components/RecordShowActionMenuButtons.tsx b/packages/twenty-front/src/modules/action-menu/components/RecordShowActionMenuButtons.tsx index 3f827c609..5a95f2c1f 100644 --- a/packages/twenty-front/src/modules/action-menu/components/RecordShowActionMenuButtons.tsx +++ b/packages/twenty-front/src/modules/action-menu/components/RecordShowActionMenuButtons.tsx @@ -1,7 +1,7 @@ import { actionMenuEntriesComponentSelector } from '@/action-menu/states/actionMenuEntriesComponentSelector'; import { PageHeaderOpenCommandMenuButton } from '@/ui/layout/page-header/components/PageHeaderOpenCommandMenuButton'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; -import { Button, useIsMobile } from 'twenty-ui'; +import { Button, IconButton, useIsMobile } from 'twenty-ui'; export const RecordShowActionMenuButtons = () => { const actionMenuEntries = useRecoilComponentValueV2( @@ -15,18 +15,29 @@ export const RecordShowActionMenuButtons = () => { return ( <> {!isMobile && - pinnedEntries.map((entry, index) => ( -