690 extract shouldberegistered from the useaction hooks (#11355)

Closes https://github.com/twentyhq/core-team-issues/issues/690

This PR is the first part of a refactoring on the actions system
https://github.com/twentyhq/core-team-issues/issues/683. It:
- Removes `shouldBeRegistered` from the useAction hook
- Instead `shouldBeRegistered` becomes a function to which we can pass
parameters which describe the context of the app (the object, the
selected record, information about favorites ...). It returns a boolean.
- `useShouldActionBeRegisteredParams` returns the parameters to pass to
the `shouldBeRegistered`
- Introduces a way to inherit actions from the default config and to
overwrite its properties, closing
https://github.com/twentyhq/core-team-issues/issues/72

Some tests testing if an action was registered correctly have been
removed, we should add them back at the end of the global refactoring.
This commit is contained in:
Raphaël Bosi
2025-04-02 17:58:14 +02:00
committed by GitHub
parent bc57e98949
commit 5e905180c8
65 changed files with 931 additions and 1943 deletions

View File

@ -10,8 +10,8 @@ import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadat
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { useRecoilValue } from 'recoil'; import { useRecoilValue } from 'recoil';
import { FeatureFlagKey } from '~/generated/graphql';
import { isDefined } from 'twenty-shared/utils'; import { isDefined } from 'twenty-shared/utils';
import { FeatureFlagKey } from '~/generated/graphql';
export const RecordActionMenuEntriesSetter = () => { export const RecordActionMenuEntriesSetter = () => {
const localContextStoreCurrentObjectMetadataItemId = const localContextStoreCurrentObjectMetadataItemId =

View File

@ -1,15 +1,13 @@
import { ActionHook } from '@/action-menu/actions/types/ActionHook'; import { RecordConfigAction } from '@/action-menu/actions/types/RecordConfigAction';
import { wrapActionInCallbacks } from '@/action-menu/actions/utils/wrapActionInCallbacks'; import { wrapActionInCallbacks } from '@/action-menu/actions/utils/wrapActionInCallbacks';
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext'; import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries'; import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries';
import { ActionMenuEntry } from '@/action-menu/types/ActionMenuEntry'; import { useShouldActionBeRegisteredParams } from '@/action-menu/hooks/useShouldActionBeRegisteredParams';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem'; import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { useContext, useEffect } from 'react'; import { useContext, useEffect } from 'react';
type RegisterRecordActionEffectProps = { type RegisterRecordActionEffectProps = {
action: ActionMenuEntry & { action: RecordConfigAction;
useAction: ActionHook;
};
objectMetadataItem: ObjectMetadataItem; objectMetadataItem: ObjectMetadataItem;
}; };
@ -17,7 +15,7 @@ export const RegisterRecordActionEffect = ({
action, action,
objectMetadataItem, objectMetadataItem,
}: RegisterRecordActionEffectProps) => { }: RegisterRecordActionEffectProps) => {
const { shouldBeRegistered, onClick, ConfirmationModal } = action.useAction({ const { onClick, ConfirmationModal } = action.useAction({
objectMetadataItem, objectMetadataItem,
}); });
@ -36,6 +34,12 @@ export const RegisterRecordActionEffect = ({
onActionExecutedCallback, onActionExecutedCallback,
}); });
const params = useShouldActionBeRegisteredParams({
objectMetadataItem,
});
const shouldBeRegistered = action.shouldBeRegistered(params);
useEffect(() => { useEffect(() => {
if (shouldBeRegistered) { if (shouldBeRegistered) {
addActionMenuEntry(wrappedAction); addActionMenuEntry(wrappedAction);

View File

@ -13,7 +13,7 @@ import { useHideDeletedRecordsNoSelectionRecordAction } from '@/action-menu/acti
import { useImportRecordsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useImportRecordsNoSelectionRecordAction'; import { useImportRecordsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useImportRecordsNoSelectionRecordAction';
import { useSeeDeletedRecordsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useSeeDeletedRecordsNoSelectionRecordAction'; import { useSeeDeletedRecordsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useSeeDeletedRecordsNoSelectionRecordAction';
import { useSeeWorkflowsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useSeeWorkflowsNoSelectionRecordAction'; import { useSeeWorkflowsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useSeeWorkflowsNoSelectionRecordAction';
import { NoSelectionRecordActionKeys } from '@/action-menu/actions/record-actions/no-selection/types/NoSelectionRecordActionsKey'; import { NoSelectionRecordActionKeys } from '@/action-menu/actions/record-actions/no-selection/types/NoSelectionRecordActionsKeys';
import { useAddToFavoritesSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useAddToFavoritesSingleRecordAction'; 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 { useDeleteSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useDeleteSingleRecordAction';
import { useDestroySingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useDestroySingleRecordAction'; import { useDestroySingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useDestroySingleRecordAction';
@ -23,14 +23,16 @@ import { useNavigateToPreviousRecordSingleRecordAction } from '@/action-menu/act
import { useRemoveFromFavoritesSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useRemoveFromFavoritesSingleRecordAction'; import { useRemoveFromFavoritesSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useRemoveFromFavoritesSingleRecordAction';
import { useRestoreSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useRestoreSingleRecordAction'; import { useRestoreSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useRestoreSingleRecordAction';
import { SingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/types/SingleRecordActionsKey'; import { SingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/types/SingleRecordActionsKey';
import { ActionHook } from '@/action-menu/actions/types/ActionHook';
import { ActionViewType } from '@/action-menu/actions/types/ActionViewType'; import { ActionViewType } from '@/action-menu/actions/types/ActionViewType';
import { RecordConfigAction } from '@/action-menu/actions/types/RecordConfigAction';
import { import {
ActionMenuEntry,
ActionMenuEntryScope, ActionMenuEntryScope,
ActionMenuEntryType, ActionMenuEntryType,
} from '@/action-menu/types/ActionMenuEntry'; } from '@/action-menu/types/ActionMenuEntry';
import { BACKEND_BATCH_REQUEST_MAX_COUNT } from '@/object-record/constants/BackendBatchRequestMaxCount';
import { msg } from '@lingui/core/macro'; import { msg } from '@lingui/core/macro';
import { isNonEmptyString } from '@sniptt/guards';
import { isDefined } from 'twenty-shared/utils';
import { import {
IconBuildingSkyscraper, IconBuildingSkyscraper,
IconCheckbox, IconCheckbox,
@ -52,13 +54,13 @@ import {
IconUser, IconUser,
} from 'twenty-ui'; } from 'twenty-ui';
export const DEFAULT_ACTIONS_CONFIG: Record< export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
string, | NoSelectionRecordActionKeys
ActionMenuEntry & { | SingleRecordActionKeys
useAction: ActionHook; | MultipleRecordsActionKeys,
} RecordConfigAction
> = { > = {
createNewRecord: { [NoSelectionRecordActionKeys.CREATE_NEW_RECORD]: {
type: ActionMenuEntryType.Standard, type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.Object, scope: ActionMenuEntryScope.Object,
key: NoSelectionRecordActionKeys.CREATE_NEW_RECORD, key: NoSelectionRecordActionKeys.CREATE_NEW_RECORD,
@ -67,10 +69,12 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
position: 0, position: 0,
isPinned: true, isPinned: true,
Icon: IconPlus, Icon: IconPlus,
shouldBeRegistered: ({ hasObjectReadOnlyPermission }) =>
!hasObjectReadOnlyPermission,
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
useAction: useCreateNewTableRecordNoSelectionRecordAction, useAction: useCreateNewTableRecordNoSelectionRecordAction,
}, },
exportNoteToPdf: { [SingleRecordActionKeys.EXPORT_NOTE_TO_PDF]: {
type: ActionMenuEntryType.Standard, type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection, scope: ActionMenuEntryScope.RecordSelection,
key: SingleRecordActionKeys.EXPORT_NOTE_TO_PDF, key: SingleRecordActionKeys.EXPORT_NOTE_TO_PDF,
@ -79,10 +83,14 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
position: 1, position: 1,
isPinned: false, isPinned: false,
Icon: IconFileExport, Icon: IconFileExport,
shouldBeRegistered: ({ selectedRecord, isNoteOrTask }) =>
isDefined(isNoteOrTask) &&
isNoteOrTask &&
isNonEmptyString(selectedRecord?.bodyV2?.blocknote),
availableOn: [ActionViewType.SHOW_PAGE], availableOn: [ActionViewType.SHOW_PAGE],
useAction: useExportNoteAction, useAction: useExportNoteAction,
}, },
addToFavoritesSingleRecord: { [SingleRecordActionKeys.ADD_TO_FAVORITES]: {
type: ActionMenuEntryType.Standard, type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection, scope: ActionMenuEntryScope.RecordSelection,
key: SingleRecordActionKeys.ADD_TO_FAVORITES, key: SingleRecordActionKeys.ADD_TO_FAVORITES,
@ -91,13 +99,15 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
position: 2, position: 2,
isPinned: true, isPinned: true,
Icon: IconHeart, Icon: IconHeart,
shouldBeRegistered: ({ selectedRecord, isFavorite }) =>
!selectedRecord?.isRemote && !isFavorite,
availableOn: [ availableOn: [
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
ActionViewType.SHOW_PAGE, ActionViewType.SHOW_PAGE,
], ],
useAction: useAddToFavoritesSingleRecordAction, useAction: useAddToFavoritesSingleRecordAction,
}, },
removeFromFavoritesSingleRecord: { [SingleRecordActionKeys.REMOVE_FROM_FAVORITES]: {
type: ActionMenuEntryType.Standard, type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection, scope: ActionMenuEntryScope.RecordSelection,
key: SingleRecordActionKeys.REMOVE_FROM_FAVORITES, key: SingleRecordActionKeys.REMOVE_FROM_FAVORITES,
@ -106,13 +116,18 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
isPinned: true, isPinned: true,
position: 3, position: 3,
Icon: IconHeartOff, Icon: IconHeartOff,
shouldBeRegistered: ({ selectedRecord, isFavorite }) =>
isDefined(selectedRecord) &&
!selectedRecord?.isRemote &&
isDefined(isFavorite) &&
isFavorite,
availableOn: [ availableOn: [
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
ActionViewType.SHOW_PAGE, ActionViewType.SHOW_PAGE,
], ],
useAction: useRemoveFromFavoritesSingleRecordAction, useAction: useRemoveFromFavoritesSingleRecordAction,
}, },
exportSingleRecord: { [SingleRecordActionKeys.EXPORT]: {
type: ActionMenuEntryType.Standard, type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection, scope: ActionMenuEntryScope.RecordSelection,
key: SingleRecordActionKeys.EXPORT, key: SingleRecordActionKeys.EXPORT,
@ -122,13 +137,15 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
Icon: IconFileExport, Icon: IconFileExport,
accent: 'default', accent: 'default',
isPinned: false, isPinned: false,
shouldBeRegistered: ({ selectedRecord }) =>
isDefined(selectedRecord) && !selectedRecord.isRemote,
availableOn: [ availableOn: [
ActionViewType.SHOW_PAGE, ActionViewType.SHOW_PAGE,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
], ],
useAction: useExportMultipleRecordsAction, useAction: useExportMultipleRecordsAction,
}, },
exportMultipleRecords: { [MultipleRecordsActionKeys.EXPORT]: {
type: ActionMenuEntryType.Standard, type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection, scope: ActionMenuEntryScope.RecordSelection,
key: MultipleRecordsActionKeys.EXPORT, key: MultipleRecordsActionKeys.EXPORT,
@ -138,10 +155,11 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
Icon: IconFileExport, Icon: IconFileExport,
accent: 'default', accent: 'default',
isPinned: false, isPinned: false,
shouldBeRegistered: () => true,
availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION], availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION],
useAction: useExportMultipleRecordsAction, useAction: useExportMultipleRecordsAction,
}, },
exportView: { [NoSelectionRecordActionKeys.EXPORT_VIEW]: {
type: ActionMenuEntryType.Standard, type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.Object, scope: ActionMenuEntryScope.Object,
key: NoSelectionRecordActionKeys.EXPORT_VIEW, key: NoSelectionRecordActionKeys.EXPORT_VIEW,
@ -151,10 +169,11 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
Icon: IconFileExport, Icon: IconFileExport,
accent: 'default', accent: 'default',
isPinned: false, isPinned: false,
shouldBeRegistered: () => true,
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
useAction: useExportMultipleRecordsAction, useAction: useExportMultipleRecordsAction,
}, },
deleteSingleRecord: { [SingleRecordActionKeys.DELETE]: {
type: ActionMenuEntryType.Standard, type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection, scope: ActionMenuEntryScope.RecordSelection,
key: SingleRecordActionKeys.DELETE, key: SingleRecordActionKeys.DELETE,
@ -164,13 +183,15 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
Icon: IconTrash, Icon: IconTrash,
accent: 'default', accent: 'default',
isPinned: true, isPinned: true,
shouldBeRegistered: ({ selectedRecord }) =>
isDefined(selectedRecord) && !selectedRecord.isRemote,
availableOn: [ availableOn: [
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
ActionViewType.SHOW_PAGE, ActionViewType.SHOW_PAGE,
], ],
useAction: useDeleteSingleRecordAction, useAction: useDeleteSingleRecordAction,
}, },
deleteMultipleRecords: { [MultipleRecordsActionKeys.DELETE]: {
type: ActionMenuEntryType.Standard, type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection, scope: ActionMenuEntryScope.RecordSelection,
key: MultipleRecordsActionKeys.DELETE, key: MultipleRecordsActionKeys.DELETE,
@ -180,10 +201,21 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
Icon: IconTrash, Icon: IconTrash,
accent: 'default', accent: 'default',
isPinned: true, isPinned: true,
shouldBeRegistered: ({
hasObjectReadOnlyPermission,
isRemote,
isSoftDeleteFilterActive,
numberOfSelectedRecords,
}) =>
!hasObjectReadOnlyPermission &&
!isRemote &&
!isSoftDeleteFilterActive &&
isDefined(numberOfSelectedRecords) &&
numberOfSelectedRecords < BACKEND_BATCH_REQUEST_MAX_COUNT,
availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION], availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION],
useAction: useDeleteMultipleRecordsAction, useAction: useDeleteMultipleRecordsAction,
}, },
seeDeletedRecords: { [NoSelectionRecordActionKeys.SEE_DELETED_RECORDS]: {
type: ActionMenuEntryType.Standard, type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.Object, scope: ActionMenuEntryScope.Object,
key: NoSelectionRecordActionKeys.SEE_DELETED_RECORDS, key: NoSelectionRecordActionKeys.SEE_DELETED_RECORDS,
@ -193,10 +225,12 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
Icon: IconRotate2, Icon: IconRotate2,
accent: 'default', accent: 'default',
isPinned: false, isPinned: false,
shouldBeRegistered: ({ isSoftDeleteFilterActive }) =>
!isSoftDeleteFilterActive,
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
useAction: useSeeDeletedRecordsNoSelectionRecordAction, useAction: useSeeDeletedRecordsNoSelectionRecordAction,
}, },
hideDeletedRecords: { [NoSelectionRecordActionKeys.HIDE_DELETED_RECORDS]: {
type: ActionMenuEntryType.Standard, type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.Object, scope: ActionMenuEntryScope.Object,
key: NoSelectionRecordActionKeys.HIDE_DELETED_RECORDS, key: NoSelectionRecordActionKeys.HIDE_DELETED_RECORDS,
@ -206,10 +240,12 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
Icon: IconEyeOff, Icon: IconEyeOff,
accent: 'default', accent: 'default',
isPinned: false, isPinned: false,
shouldBeRegistered: ({ isSoftDeleteFilterActive }) =>
isDefined(isSoftDeleteFilterActive) && isSoftDeleteFilterActive,
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
useAction: useHideDeletedRecordsNoSelectionRecordAction, useAction: useHideDeletedRecordsNoSelectionRecordAction,
}, },
importRecords: { [NoSelectionRecordActionKeys.IMPORT_RECORDS]: {
type: ActionMenuEntryType.Standard, type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.Object, scope: ActionMenuEntryScope.Object,
key: NoSelectionRecordActionKeys.IMPORT_RECORDS, key: NoSelectionRecordActionKeys.IMPORT_RECORDS,
@ -219,10 +255,11 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
Icon: IconFileImport, Icon: IconFileImport,
accent: 'default', accent: 'default',
isPinned: false, isPinned: false,
shouldBeRegistered: () => true,
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
useAction: useImportRecordsNoSelectionRecordAction, useAction: useImportRecordsNoSelectionRecordAction,
}, },
destroySingleRecord: { [SingleRecordActionKeys.DESTROY]: {
type: ActionMenuEntryType.Standard, type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection, scope: ActionMenuEntryScope.RecordSelection,
key: SingleRecordActionKeys.DESTROY, key: SingleRecordActionKeys.DESTROY,
@ -232,13 +269,21 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
Icon: IconTrashX, Icon: IconTrashX,
accent: 'danger', accent: 'danger',
isPinned: true, isPinned: true,
shouldBeRegistered: ({
selectedRecord,
hasObjectReadOnlyPermission,
isRemote,
}) =>
!hasObjectReadOnlyPermission &&
!isRemote &&
isDefined(selectedRecord?.deletedAt),
availableOn: [ availableOn: [
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
ActionViewType.SHOW_PAGE, ActionViewType.SHOW_PAGE,
], ],
useAction: useDestroySingleRecordAction, useAction: useDestroySingleRecordAction,
}, },
navigateToPreviousRecord: { [SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD]: {
type: ActionMenuEntryType.Standard, type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection, scope: ActionMenuEntryScope.RecordSelection,
key: SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD, key: SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD,
@ -246,10 +291,11 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
position: 13, position: 13,
isPinned: true, isPinned: true,
Icon: IconChevronUp, Icon: IconChevronUp,
shouldBeRegistered: ({ isInRightDrawer }) => !isInRightDrawer,
availableOn: [ActionViewType.SHOW_PAGE], availableOn: [ActionViewType.SHOW_PAGE],
useAction: useNavigateToPreviousRecordSingleRecordAction, useAction: useNavigateToPreviousRecordSingleRecordAction,
}, },
navigateToNextRecord: { [SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD]: {
type: ActionMenuEntryType.Standard, type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection, scope: ActionMenuEntryScope.RecordSelection,
key: SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD, key: SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD,
@ -257,10 +303,11 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
position: 14, position: 14,
isPinned: true, isPinned: true,
Icon: IconChevronDown, Icon: IconChevronDown,
shouldBeRegistered: ({ isInRightDrawer }) => !isInRightDrawer,
availableOn: [ActionViewType.SHOW_PAGE], availableOn: [ActionViewType.SHOW_PAGE],
useAction: useNavigateToNextRecordSingleRecordAction, useAction: useNavigateToNextRecordSingleRecordAction,
}, },
destroyMultipleRecords: { [MultipleRecordsActionKeys.DESTROY]: {
type: ActionMenuEntryType.Standard, type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection, scope: ActionMenuEntryScope.RecordSelection,
key: MultipleRecordsActionKeys.DESTROY, key: MultipleRecordsActionKeys.DESTROY,
@ -270,10 +317,22 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
Icon: IconTrashX, Icon: IconTrashX,
accent: 'danger', accent: 'danger',
isPinned: true, isPinned: true,
shouldBeRegistered: ({
hasObjectReadOnlyPermission,
isRemote,
isSoftDeleteFilterActive,
numberOfSelectedRecords,
}) =>
!hasObjectReadOnlyPermission &&
!isRemote &&
isDefined(isSoftDeleteFilterActive) &&
isSoftDeleteFilterActive &&
isDefined(numberOfSelectedRecords) &&
numberOfSelectedRecords < BACKEND_BATCH_REQUEST_MAX_COUNT,
availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION], availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION],
useAction: useDestroyMultipleRecordsAction, useAction: useDestroyMultipleRecordsAction,
}, },
restoreSingleRecord: { [SingleRecordActionKeys.RESTORE]: {
type: ActionMenuEntryType.Standard, type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection, scope: ActionMenuEntryScope.RecordSelection,
key: SingleRecordActionKeys.RESTORE, key: SingleRecordActionKeys.RESTORE,
@ -283,13 +342,25 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
Icon: IconRefresh, Icon: IconRefresh,
accent: 'default', accent: 'default',
isPinned: true, isPinned: true,
shouldBeRegistered: ({
selectedRecord,
hasObjectReadOnlyPermission,
isRemote,
isShowPage,
isSoftDeleteFilterActive,
}) =>
!isRemote &&
isDefined(selectedRecord?.deletedAt) &&
!hasObjectReadOnlyPermission &&
((isDefined(isShowPage) && isShowPage) ||
(isDefined(isSoftDeleteFilterActive) && isSoftDeleteFilterActive)),
availableOn: [ availableOn: [
ActionViewType.SHOW_PAGE, ActionViewType.SHOW_PAGE,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
], ],
useAction: useRestoreSingleRecordAction, useAction: useRestoreSingleRecordAction,
}, },
restoreMultipleRecords: { [MultipleRecordsActionKeys.RESTORE]: {
type: ActionMenuEntryType.Standard, type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection, scope: ActionMenuEntryScope.RecordSelection,
key: MultipleRecordsActionKeys.RESTORE, key: MultipleRecordsActionKeys.RESTORE,
@ -299,10 +370,22 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
Icon: IconRefresh, Icon: IconRefresh,
accent: 'default', accent: 'default',
isPinned: true, isPinned: true,
shouldBeRegistered: ({
hasObjectReadOnlyPermission,
isRemote,
isSoftDeleteFilterActive,
numberOfSelectedRecords,
}) =>
!hasObjectReadOnlyPermission &&
!isRemote &&
isDefined(isSoftDeleteFilterActive) &&
isSoftDeleteFilterActive &&
isDefined(numberOfSelectedRecords) &&
numberOfSelectedRecords < BACKEND_BATCH_REQUEST_MAX_COUNT,
availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION], availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION],
useAction: useRestoreMultipleRecordsAction, useAction: useRestoreMultipleRecordsAction,
}, },
seeAllWorkflows: { [NoSelectionRecordActionKeys.GO_TO_WORKFLOWS]: {
type: ActionMenuEntryType.Navigation, type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global, scope: ActionMenuEntryScope.Global,
key: NoSelectionRecordActionKeys.GO_TO_WORKFLOWS, key: NoSelectionRecordActionKeys.GO_TO_WORKFLOWS,
@ -312,11 +395,12 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
Icon: IconSettingsAutomation, Icon: IconSettingsAutomation,
accent: 'default', accent: 'default',
isPinned: false, isPinned: false,
shouldBeRegistered: () => true,
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
useAction: useSeeWorkflowsNoSelectionRecordAction, useAction: useSeeWorkflowsNoSelectionRecordAction,
hotKeys: ['G', 'W'], hotKeys: ['G', 'W'],
}, },
goToPeople: { [NoSelectionRecordActionKeys.GO_TO_PEOPLE]: {
type: ActionMenuEntryType.Navigation, type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global, scope: ActionMenuEntryScope.Global,
key: NoSelectionRecordActionKeys.GO_TO_PEOPLE, key: NoSelectionRecordActionKeys.GO_TO_PEOPLE,
@ -331,10 +415,11 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
ActionViewType.INDEX_PAGE_BULK_SELECTION, ActionViewType.INDEX_PAGE_BULK_SELECTION,
ActionViewType.SHOW_PAGE, ActionViewType.SHOW_PAGE,
], ],
shouldBeRegistered: () => true,
useAction: useGoToPeopleNoSelectionRecordAction, useAction: useGoToPeopleNoSelectionRecordAction,
hotKeys: ['G', 'P'], hotKeys: ['G', 'P'],
}, },
goToCompanies: { [NoSelectionRecordActionKeys.GO_TO_COMPANIES]: {
type: ActionMenuEntryType.Navigation, type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global, scope: ActionMenuEntryScope.Global,
key: NoSelectionRecordActionKeys.GO_TO_COMPANIES, key: NoSelectionRecordActionKeys.GO_TO_COMPANIES,
@ -349,10 +434,11 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
ActionViewType.INDEX_PAGE_BULK_SELECTION, ActionViewType.INDEX_PAGE_BULK_SELECTION,
ActionViewType.SHOW_PAGE, ActionViewType.SHOW_PAGE,
], ],
shouldBeRegistered: () => true,
useAction: useGoToCompaniesNoSelectionRecordAction, useAction: useGoToCompaniesNoSelectionRecordAction,
hotKeys: ['G', 'C'], hotKeys: ['G', 'C'],
}, },
goToOpportunities: { [NoSelectionRecordActionKeys.GO_TO_OPPORTUNITIES]: {
type: ActionMenuEntryType.Navigation, type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global, scope: ActionMenuEntryScope.Global,
key: NoSelectionRecordActionKeys.GO_TO_OPPORTUNITIES, key: NoSelectionRecordActionKeys.GO_TO_OPPORTUNITIES,
@ -367,10 +453,11 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
ActionViewType.INDEX_PAGE_BULK_SELECTION, ActionViewType.INDEX_PAGE_BULK_SELECTION,
ActionViewType.SHOW_PAGE, ActionViewType.SHOW_PAGE,
], ],
shouldBeRegistered: () => true,
useAction: useGoToOpportunitiesNoSelectionRecordAction, useAction: useGoToOpportunitiesNoSelectionRecordAction,
hotKeys: ['G', 'O'], hotKeys: ['G', 'O'],
}, },
goToSettings: { [NoSelectionRecordActionKeys.GO_TO_SETTINGS]: {
type: ActionMenuEntryType.Navigation, type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global, scope: ActionMenuEntryScope.Global,
key: NoSelectionRecordActionKeys.GO_TO_SETTINGS, key: NoSelectionRecordActionKeys.GO_TO_SETTINGS,
@ -385,10 +472,11 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
ActionViewType.INDEX_PAGE_BULK_SELECTION, ActionViewType.INDEX_PAGE_BULK_SELECTION,
ActionViewType.SHOW_PAGE, ActionViewType.SHOW_PAGE,
], ],
shouldBeRegistered: () => true,
useAction: useGoToSettingsNoSelectionRecordAction, useAction: useGoToSettingsNoSelectionRecordAction,
hotKeys: ['G', 'S'], hotKeys: ['G', 'S'],
}, },
goToTasks: { [NoSelectionRecordActionKeys.GO_TO_TASKS]: {
type: ActionMenuEntryType.Navigation, type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global, scope: ActionMenuEntryScope.Global,
key: NoSelectionRecordActionKeys.GO_TO_TASKS, key: NoSelectionRecordActionKeys.GO_TO_TASKS,
@ -403,6 +491,7 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
ActionViewType.INDEX_PAGE_BULK_SELECTION, ActionViewType.INDEX_PAGE_BULK_SELECTION,
ActionViewType.SHOW_PAGE, ActionViewType.SHOW_PAGE,
], ],
shouldBeRegistered: () => true,
useAction: useGoToTasksNoSelectionRecordAction, useAction: useGoToTasksNoSelectionRecordAction,
hotKeys: ['G', 'T'], hotKeys: ['G', 'T'],
}, },

View File

@ -1,24 +1,7 @@
import { useDeleteMultipleRecordsAction } from '@/action-menu/actions/record-actions/multiple-records/hooks/useDeleteMultipleRecordsAction';
import { useDestroyMultipleRecordsAction } from '@/action-menu/actions/record-actions/multiple-records/hooks/useDestroyMultipleRecordsAction';
import { useExportMultipleRecordsAction } from '@/action-menu/actions/record-actions/multiple-records/hooks/useExportMultipleRecordsAction';
import { MultipleRecordsActionKeys } from '@/action-menu/actions/record-actions/multiple-records/types/MultipleRecordsActionKeys'; import { MultipleRecordsActionKeys } from '@/action-menu/actions/record-actions/multiple-records/types/MultipleRecordsActionKeys';
import { useCreateNewTableRecordNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useCreateNewTableRecordNoSelectionRecordAction';
import { useGoToCompaniesNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useGoToCompaniesNoSelectionRecordAction';
import { useGoToOpportunitiesNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useGoToOpportunitiesNoSelectionRecordAction';
import { useGoToPeopleNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useGoToPeopleNoSelectionRecordAction';
import { useGoToSettingsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useGoToSettingsNoSelectionRecordAction';
import { useGoToTasksNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useGoToTasksNoSelectionRecordAction';
import { useHideDeletedRecordsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useHideDeletedRecordsNoSelectionRecordAction';
import { useImportRecordsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useImportRecordsNoSelectionRecordAction';
import { useSeeDeletedRecordsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useSeeDeletedRecordsNoSelectionRecordAction';
import { useSeeRunsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useSeeRunsNoSelectionRecordAction'; import { useSeeRunsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useSeeRunsNoSelectionRecordAction';
import { NoSelectionRecordActionKeys } from '@/action-menu/actions/record-actions/no-selection/types/NoSelectionRecordActionsKey'; import { NoSelectionRecordActionKeys } from '@/action-menu/actions/record-actions/no-selection/types/NoSelectionRecordActionsKeys';
import { useAddToFavoritesSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useAddToFavoritesSingleRecordAction'; import { NoSelectionWorkflowRecordActionKeys } from '@/action-menu/actions/record-actions/no-selection/workflow-actions/types/NoSelectionWorkflowRecordActionsKeys';
import { useDeleteSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useDeleteSingleRecordAction';
import { useDestroySingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useDestroySingleRecordAction';
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 { SingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/types/SingleRecordActionsKey'; import { SingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/types/SingleRecordActionsKey';
import { useActivateWorkflowSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-actions/hooks/useActivateWorkflowSingleRecordAction'; import { useActivateWorkflowSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-actions/hooks/useActivateWorkflowSingleRecordAction';
import { useDeactivateWorkflowSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-actions/hooks/useDeactivateWorkflowSingleRecordAction'; import { useDeactivateWorkflowSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-actions/hooks/useDeactivateWorkflowSingleRecordAction';
@ -28,452 +11,268 @@ import { useSeeRunsWorkflowSingleRecordAction } from '@/action-menu/actions/reco
import { useSeeVersionsWorkflowSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-actions/hooks/useSeeVersionsWorkflowSingleRecordAction'; 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 { 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 { WorkflowSingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/workflow-actions/types/WorkflowSingleRecordActionsKeys';
import { ActionHook } from '@/action-menu/actions/types/ActionHook'; import { inheritActionsFromDefaultConfig } from '@/action-menu/actions/record-actions/utils/inheritActionsFromDefaultConfig';
import { ActionViewType } from '@/action-menu/actions/types/ActionViewType'; import { ActionViewType } from '@/action-menu/actions/types/ActionViewType';
import { import {
ActionMenuEntry,
ActionMenuEntryScope, ActionMenuEntryScope,
ActionMenuEntryType, ActionMenuEntryType,
} from '@/action-menu/types/ActionMenuEntry'; } from '@/action-menu/types/ActionMenuEntry';
import { msg } from '@lingui/core/macro'; import { msg } from '@lingui/core/macro';
import { isDefined } from 'twenty-shared/utils';
import { import {
IconBuildingSkyscraper,
IconCheckbox,
IconChevronDown,
IconChevronUp,
IconDatabaseExport,
IconEyeOff,
IconFileImport,
IconHeart,
IconHeartOff,
IconHistoryToggle, IconHistoryToggle,
IconNoteOff, IconNoteOff,
IconPlayerPause, IconPlayerPause,
IconPlayerPlay, IconPlayerPlay,
IconPlus,
IconPower, IconPower,
IconRotate2,
IconSettings,
IconTargetArrow,
IconTrash,
IconTrashX,
IconUser,
IconVersions, IconVersions,
} from 'twenty-ui'; } from 'twenty-ui';
export const WORKFLOW_ACTIONS_CONFIG: Record< export const WORKFLOW_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({
string, config: {
ActionMenuEntry & { [WorkflowSingleRecordActionKeys.ACTIVATE]: {
useAction: ActionHook; key: WorkflowSingleRecordActionKeys.ACTIVATE,
} label: msg`Activate Workflow`,
> = { shortLabel: msg`Activate`,
createNewRecord: { isPinned: true,
type: ActionMenuEntryType.Standard, position: 1,
scope: ActionMenuEntryScope.Object, Icon: IconPower,
key: NoSelectionRecordActionKeys.CREATE_NEW_RECORD, type: ActionMenuEntryType.Standard,
label: msg`Create new record`, scope: ActionMenuEntryScope.RecordSelection,
shortLabel: msg`New record`, shouldBeRegistered: ({ workflowWithCurrentVersion }) =>
position: 0, isDefined(workflowWithCurrentVersion?.currentVersion?.trigger) &&
isPinned: true, isDefined(workflowWithCurrentVersion.currentVersion?.steps) &&
Icon: IconPlus, workflowWithCurrentVersion.currentVersion.steps.length > 0 &&
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], (workflowWithCurrentVersion.currentVersion.status === 'DRAFT' ||
useAction: useCreateNewTableRecordNoSelectionRecordAction, !workflowWithCurrentVersion.versions?.some(
(version) => version.status === 'ACTIVE',
)),
availableOn: [
ActionViewType.SHOW_PAGE,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
],
useAction: useActivateWorkflowSingleRecordAction,
},
[WorkflowSingleRecordActionKeys.DEACTIVATE]: {
key: WorkflowSingleRecordActionKeys.DEACTIVATE,
label: msg`Deactivate Workflow`,
shortLabel: msg`Deactivate`,
isPinned: true,
position: 2,
Icon: IconPlayerPause,
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
shouldBeRegistered: ({ workflowWithCurrentVersion }) =>
isDefined(workflowWithCurrentVersion) &&
workflowWithCurrentVersion.currentVersion.status === 'ACTIVE',
availableOn: [
ActionViewType.SHOW_PAGE,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
],
useAction: useDeactivateWorkflowSingleRecordAction,
},
[WorkflowSingleRecordActionKeys.DISCARD_DRAFT]: {
key: WorkflowSingleRecordActionKeys.DISCARD_DRAFT,
label: msg`Discard Draft`,
shortLabel: msg`Discard Draft`,
isPinned: true,
position: 3,
Icon: IconNoteOff,
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
shouldBeRegistered: ({ workflowWithCurrentVersion }) =>
isDefined(workflowWithCurrentVersion) &&
workflowWithCurrentVersion.versions.length > 1 &&
workflowWithCurrentVersion.currentVersion.status === 'DRAFT',
availableOn: [
ActionViewType.SHOW_PAGE,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
],
useAction: useDiscardDraftWorkflowSingleRecordAction,
},
[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: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
shouldBeRegistered: ({ workflowWithCurrentVersion }) =>
(workflowWithCurrentVersion?.statuses?.includes('ACTIVE') || false) &&
(workflowWithCurrentVersion?.statuses?.includes('DRAFT') || false),
availableOn: [
ActionViewType.SHOW_PAGE,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
],
useAction: useSeeActiveVersionWorkflowSingleRecordAction,
},
[WorkflowSingleRecordActionKeys.SEE_RUNS]: {
key: WorkflowSingleRecordActionKeys.SEE_RUNS,
label: msg`See runs`,
shortLabel: msg`See runs`,
isPinned: true,
position: 5,
Icon: IconHistoryToggle,
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
shouldBeRegistered: ({ workflowWithCurrentVersion }) =>
isDefined(workflowWithCurrentVersion),
availableOn: [
ActionViewType.SHOW_PAGE,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
],
useAction: useSeeRunsWorkflowSingleRecordAction,
},
[WorkflowSingleRecordActionKeys.SEE_VERSIONS]: {
key: WorkflowSingleRecordActionKeys.SEE_VERSIONS,
label: msg`See versions history`,
shortLabel: msg`See versions`,
isPinned: false,
position: 6,
Icon: IconVersions,
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
shouldBeRegistered: ({ workflowWithCurrentVersion }) =>
isDefined(workflowWithCurrentVersion),
availableOn: [
ActionViewType.SHOW_PAGE,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
],
useAction: useSeeVersionsWorkflowSingleRecordAction,
},
[WorkflowSingleRecordActionKeys.TEST]: {
key: WorkflowSingleRecordActionKeys.TEST,
label: msg`Test Workflow`,
shortLabel: msg`Test`,
isPinned: true,
position: 7,
Icon: IconPlayerPlay,
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
shouldBeRegistered: ({ workflowWithCurrentVersion }) =>
isDefined(workflowWithCurrentVersion?.currentVersion?.trigger) &&
((workflowWithCurrentVersion.currentVersion.trigger.type === 'MANUAL' &&
!isDefined(
workflowWithCurrentVersion.currentVersion.trigger.settings
.objectType,
)) ||
workflowWithCurrentVersion.currentVersion.trigger.type === 'WEBHOOK'),
availableOn: [
ActionViewType.SHOW_PAGE,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
],
useAction: useTestWorkflowSingleRecordAction,
},
[NoSelectionWorkflowRecordActionKeys.GO_TO_RUNS]: {
type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global,
key: NoSelectionWorkflowRecordActionKeys.GO_TO_RUNS,
label: msg`Go to runs`,
shortLabel: msg`See runs`,
position: 22,
Icon: IconHistoryToggle,
accent: 'default',
isPinned: true,
shouldBeRegistered: () => true,
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
useAction: useSeeRunsNoSelectionRecordAction,
},
}, },
activateWorkflowSingleRecord: { actionKeys: [
key: WorkflowSingleRecordActionKeys.ACTIVATE, NoSelectionRecordActionKeys.CREATE_NEW_RECORD,
label: msg`Activate Workflow`, SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD,
shortLabel: msg`Activate`, SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD,
isPinned: true, SingleRecordActionKeys.ADD_TO_FAVORITES,
position: 1, SingleRecordActionKeys.REMOVE_FROM_FAVORITES,
Icon: IconPower, SingleRecordActionKeys.DELETE,
type: ActionMenuEntryType.Standard, SingleRecordActionKeys.DESTROY,
scope: ActionMenuEntryScope.RecordSelection, SingleRecordActionKeys.EXPORT,
availableOn: [ MultipleRecordsActionKeys.DELETE,
ActionViewType.SHOW_PAGE, MultipleRecordsActionKeys.DESTROY,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, MultipleRecordsActionKeys.EXPORT,
], NoSelectionRecordActionKeys.SEE_DELETED_RECORDS,
useAction: useActivateWorkflowSingleRecordAction, NoSelectionRecordActionKeys.HIDE_DELETED_RECORDS,
NoSelectionRecordActionKeys.GO_TO_PEOPLE,
NoSelectionRecordActionKeys.GO_TO_COMPANIES,
NoSelectionRecordActionKeys.GO_TO_OPPORTUNITIES,
NoSelectionRecordActionKeys.GO_TO_SETTINGS,
NoSelectionRecordActionKeys.GO_TO_TASKS,
],
propertiesToOverwrite: {
[NoSelectionRecordActionKeys.CREATE_NEW_RECORD]: {
position: 0,
label: msg`Create new workflow`,
},
[SingleRecordActionKeys.ADD_TO_FAVORITES]: {
position: 8,
},
[SingleRecordActionKeys.REMOVE_FROM_FAVORITES]: {
position: 9,
},
[SingleRecordActionKeys.DELETE]: {
position: 10,
label: msg`Delete workflow`,
},
[MultipleRecordsActionKeys.DELETE]: {
position: 11,
label: msg`Delete workflows`,
},
[SingleRecordActionKeys.DESTROY]: {
position: 12,
label: msg`Permanently destroy workflow`,
},
[SingleRecordActionKeys.EXPORT]: {
position: 13,
label: msg`Export workflow`,
},
[MultipleRecordsActionKeys.EXPORT]: {
position: 14,
label: msg`Export workflows`,
},
[NoSelectionRecordActionKeys.EXPORT_VIEW]: {
position: 15,
label: msg`Export view`,
},
[MultipleRecordsActionKeys.DESTROY]: {
position: 16,
label: msg`Permanently destroy workflows`,
},
[SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD]: {
position: 17,
label: msg`Navigate to previous workflow`,
},
[SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD]: {
position: 18,
label: msg`Navigate to next workflow`,
},
[NoSelectionRecordActionKeys.SEE_DELETED_RECORDS]: {
position: 19,
label: msg`See deleted workflows`,
},
[NoSelectionRecordActionKeys.HIDE_DELETED_RECORDS]: {
position: 20,
label: msg`Hide deleted workflows`,
},
[NoSelectionRecordActionKeys.IMPORT_RECORDS]: {
position: 21,
label: msg`Import workflows`,
},
[NoSelectionRecordActionKeys.GO_TO_PEOPLE]: {
position: 23,
},
[NoSelectionRecordActionKeys.GO_TO_COMPANIES]: {
position: 24,
},
[NoSelectionRecordActionKeys.GO_TO_OPPORTUNITIES]: {
position: 25,
},
[NoSelectionRecordActionKeys.GO_TO_SETTINGS]: {
position: 26,
},
[NoSelectionRecordActionKeys.GO_TO_TASKS]: {
position: 27,
},
}, },
deactivateWorkflowSingleRecord: { });
key: WorkflowSingleRecordActionKeys.DEACTIVATE,
label: msg`Deactivate Workflow`,
shortLabel: msg`Deactivate`,
isPinned: true,
position: 2,
Icon: IconPlayerPause,
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
availableOn: [
ActionViewType.SHOW_PAGE,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
],
useAction: useDeactivateWorkflowSingleRecordAction,
},
discardWorkflowDraftSingleRecord: {
key: WorkflowSingleRecordActionKeys.DISCARD_DRAFT,
label: msg`Discard Draft`,
shortLabel: msg`Discard Draft`,
isPinned: true,
position: 3,
Icon: IconNoteOff,
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
availableOn: [
ActionViewType.SHOW_PAGE,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
],
useAction: useDiscardDraftWorkflowSingleRecordAction,
},
seeWorkflowActiveVersionSingleRecord: {
key: WorkflowSingleRecordActionKeys.SEE_ACTIVE_VERSION,
label: msg`See active version`,
shortLabel: msg`See active version`,
isPinned: false,
position: 4,
Icon: IconVersions,
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
availableOn: [
ActionViewType.SHOW_PAGE,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
],
useAction: useSeeActiveVersionWorkflowSingleRecordAction,
},
seeWorkflowRunsSingleRecord: {
key: WorkflowSingleRecordActionKeys.SEE_RUNS,
label: msg`See runs`,
shortLabel: msg`See runs`,
isPinned: true,
position: 5,
Icon: IconHistoryToggle,
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
availableOn: [
ActionViewType.SHOW_PAGE,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
],
useAction: useSeeRunsWorkflowSingleRecordAction,
},
seeWorkflowVersionsHistorySingleRecord: {
key: WorkflowSingleRecordActionKeys.SEE_VERSIONS,
label: msg`See versions history`,
shortLabel: msg`See versions`,
isPinned: false,
position: 6,
Icon: IconVersions,
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
availableOn: [
ActionViewType.SHOW_PAGE,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
],
useAction: useSeeVersionsWorkflowSingleRecordAction,
},
testWorkflowSingleRecord: {
key: WorkflowSingleRecordActionKeys.TEST,
label: msg`Test Workflow`,
shortLabel: msg`Test`,
isPinned: true,
position: 7,
Icon: IconPlayerPlay,
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
availableOn: [
ActionViewType.SHOW_PAGE,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
],
useAction: useTestWorkflowSingleRecordAction,
},
navigateToPreviousRecord: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
key: SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD,
label: msg`Navigate to previous workflow`,
position: 8,
Icon: IconChevronUp,
availableOn: [ActionViewType.SHOW_PAGE],
useAction: useNavigateToPreviousRecordSingleRecordAction,
},
navigateToNextRecord: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
key: SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD,
label: msg`Navigate to next workflow`,
position: 9,
Icon: IconChevronDown,
availableOn: [ActionViewType.SHOW_PAGE],
useAction: useNavigateToNextRecordSingleRecordAction,
},
addToFavoritesSingleRecord: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
key: SingleRecordActionKeys.ADD_TO_FAVORITES,
label: msg`Add to favorites`,
shortLabel: msg`Add to favorites`,
position: 10,
isPinned: false,
Icon: IconHeart,
availableOn: [
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
ActionViewType.SHOW_PAGE,
],
useAction: useAddToFavoritesSingleRecordAction,
},
removeFromFavoritesSingleRecord: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
key: SingleRecordActionKeys.REMOVE_FROM_FAVORITES,
label: msg`Remove from favorites`,
shortLabel: msg`Remove from favorites`,
isPinned: false,
position: 11,
Icon: IconHeartOff,
availableOn: [
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
ActionViewType.SHOW_PAGE,
],
useAction: useRemoveFromFavoritesSingleRecordAction,
},
deleteSingleRecord: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
key: SingleRecordActionKeys.DELETE,
label: msg`Delete workflow`,
shortLabel: msg`Delete`,
position: 12,
Icon: IconTrash,
accent: 'danger',
isPinned: true,
availableOn: [
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
ActionViewType.SHOW_PAGE,
],
useAction: useDeleteSingleRecordAction,
},
deleteMultipleRecords: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
key: MultipleRecordsActionKeys.DELETE,
label: msg`Delete workflows`,
shortLabel: msg`Delete`,
position: 13,
Icon: IconTrash,
accent: 'danger',
isPinned: true,
availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION],
useAction: useDeleteMultipleRecordsAction,
},
destroySingleRecord: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
key: SingleRecordActionKeys.DESTROY,
label: msg`Permanently destroy record`,
shortLabel: msg`Destroy`,
position: 14,
Icon: IconTrashX,
accent: 'danger',
isPinned: true,
availableOn: [
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
ActionViewType.SHOW_PAGE,
],
useAction: useDestroySingleRecordAction,
},
exportSingleRecord: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
key: SingleRecordActionKeys.EXPORT,
label: msg`Export workflow`,
shortLabel: msg`Export`,
position: 15,
Icon: IconDatabaseExport,
accent: 'default',
isPinned: false,
availableOn: [
ActionViewType.SHOW_PAGE,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
],
useAction: useExportMultipleRecordsAction,
},
exportMultipleRecords: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
key: MultipleRecordsActionKeys.EXPORT,
label: msg`Export workflows`,
shortLabel: msg`Export`,
position: 16,
Icon: IconDatabaseExport,
accent: 'default',
isPinned: false,
availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION],
useAction: useExportMultipleRecordsAction,
},
exportView: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.Object,
key: NoSelectionRecordActionKeys.EXPORT_VIEW,
label: msg`Export view`,
shortLabel: msg`Export`,
position: 17,
Icon: IconDatabaseExport,
accent: 'default',
isPinned: false,
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
useAction: useExportMultipleRecordsAction,
},
destroyMultipleRecords: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
key: MultipleRecordsActionKeys.DESTROY,
label: msg`Permanently destroy workflows`,
shortLabel: msg`Destroy`,
position: 18,
Icon: IconTrashX,
accent: 'danger',
isPinned: true,
availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION],
useAction: useDestroyMultipleRecordsAction,
},
seeDeletedRecords: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.Object,
key: NoSelectionRecordActionKeys.SEE_DELETED_RECORDS,
label: msg`See deleted workflows`,
shortLabel: msg`Deleted workflows`,
position: 19,
Icon: IconRotate2,
accent: 'default',
isPinned: false,
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
useAction: useSeeDeletedRecordsNoSelectionRecordAction,
},
hideDeletedRecords: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.Object,
key: NoSelectionRecordActionKeys.HIDE_DELETED_RECORDS,
label: msg`Hide deleted workflows`,
shortLabel: msg`Hide deleted`,
position: 20,
Icon: IconEyeOff,
accent: 'default',
isPinned: false,
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
useAction: useHideDeletedRecordsNoSelectionRecordAction,
},
importRecords: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.Object,
key: NoSelectionRecordActionKeys.IMPORT_RECORDS,
label: msg`Import workflows`,
shortLabel: msg`Import`,
position: 21,
Icon: IconFileImport,
accent: 'default',
isPinned: false,
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
useAction: useImportRecordsNoSelectionRecordAction,
},
seeAllRuns: {
type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global,
key: NoSelectionRecordActionKeys.GO_TO_RUNS,
label: msg`Go to runs`,
shortLabel: msg`See runs`,
position: 22,
Icon: IconHistoryToggle,
accent: 'default',
isPinned: true,
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
useAction: useSeeRunsNoSelectionRecordAction,
},
goToPeople: {
type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global,
key: NoSelectionRecordActionKeys.GO_TO_PEOPLE,
label: msg`Go to People`,
shortLabel: msg`People`,
position: 23,
Icon: IconUser,
isPinned: false,
availableOn: [
ActionViewType.INDEX_PAGE_NO_SELECTION,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
ActionViewType.INDEX_PAGE_BULK_SELECTION,
ActionViewType.SHOW_PAGE,
],
useAction: useGoToPeopleNoSelectionRecordAction,
hotKeys: ['G', 'P'],
},
goToCompanies: {
type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global,
key: NoSelectionRecordActionKeys.GO_TO_COMPANIES,
label: msg`Go to Companies`,
shortLabel: msg`Companies`,
position: 24,
Icon: IconBuildingSkyscraper,
isPinned: false,
availableOn: [
ActionViewType.INDEX_PAGE_NO_SELECTION,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
ActionViewType.INDEX_PAGE_BULK_SELECTION,
ActionViewType.SHOW_PAGE,
],
useAction: useGoToCompaniesNoSelectionRecordAction,
hotKeys: ['G', 'C'],
},
goToOpportunities: {
type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global,
key: NoSelectionRecordActionKeys.GO_TO_OPPORTUNITIES,
label: msg`Go to Opportunities`,
shortLabel: msg`Opportunities`,
position: 25,
Icon: IconTargetArrow,
isPinned: false,
availableOn: [
ActionViewType.INDEX_PAGE_NO_SELECTION,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
ActionViewType.INDEX_PAGE_BULK_SELECTION,
ActionViewType.SHOW_PAGE,
],
useAction: useGoToOpportunitiesNoSelectionRecordAction,
hotKeys: ['G', 'O'],
},
goToSettings: {
type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global,
key: NoSelectionRecordActionKeys.GO_TO_SETTINGS,
label: msg`Go to Settings`,
shortLabel: msg`Settings`,
position: 26,
Icon: IconSettings,
isPinned: false,
availableOn: [
ActionViewType.INDEX_PAGE_NO_SELECTION,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
ActionViewType.INDEX_PAGE_BULK_SELECTION,
ActionViewType.SHOW_PAGE,
],
useAction: useGoToSettingsNoSelectionRecordAction,
hotKeys: ['G', 'S'],
},
goToTasks: {
type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global,
key: NoSelectionRecordActionKeys.GO_TO_TASKS,
label: msg`Go to Tasks`,
shortLabel: msg`Tasks`,
position: 27,
Icon: IconCheckbox,
isPinned: false,
availableOn: [
ActionViewType.INDEX_PAGE_NO_SELECTION,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
ActionViewType.INDEX_PAGE_BULK_SELECTION,
ActionViewType.SHOW_PAGE,
],
useAction: useGoToTasksNoSelectionRecordAction,
hotKeys: ['G', 'T'],
},
};

View File

@ -1,305 +1,134 @@
import { useExportMultipleRecordsAction } from '@/action-menu/actions/record-actions/multiple-records/hooks/useExportMultipleRecordsAction';
import { MultipleRecordsActionKeys } from '@/action-menu/actions/record-actions/multiple-records/types/MultipleRecordsActionKeys'; import { MultipleRecordsActionKeys } from '@/action-menu/actions/record-actions/multiple-records/types/MultipleRecordsActionKeys';
import { useGoToCompaniesNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useGoToCompaniesNoSelectionRecordAction';
import { useGoToOpportunitiesNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useGoToOpportunitiesNoSelectionRecordAction';
import { useGoToPeopleNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useGoToPeopleNoSelectionRecordAction';
import { useGoToSettingsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useGoToSettingsNoSelectionRecordAction';
import { useGoToTasksNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useGoToTasksNoSelectionRecordAction';
import { useHideDeletedRecordsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useHideDeletedRecordsNoSelectionRecordAction';
import { useSeeDeletedRecordsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useSeeDeletedRecordsNoSelectionRecordAction';
import { useSeeWorkflowsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useSeeWorkflowsNoSelectionRecordAction'; import { useSeeWorkflowsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useSeeWorkflowsNoSelectionRecordAction';
import { NoSelectionRecordActionKeys } from '@/action-menu/actions/record-actions/no-selection/types/NoSelectionRecordActionsKey'; import { NoSelectionRecordActionKeys } from '@/action-menu/actions/record-actions/no-selection/types/NoSelectionRecordActionsKeys';
import { useAddToFavoritesSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useAddToFavoritesSingleRecordAction';
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 { SingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/types/SingleRecordActionsKey'; import { SingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/types/SingleRecordActionsKey';
import { useSeeVersionWorkflowRunSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-run-actions/hooks/useSeeVersionWorkflowRunSingleRecordAction'; import { useSeeVersionWorkflowRunSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-run-actions/hooks/useSeeVersionWorkflowRunSingleRecordAction';
import { useSeeWorkflowWorkflowRunSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-run-actions/hooks/useSeeWorkflowWorkflowRunSingleRecordAction'; import { useSeeWorkflowWorkflowRunSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-run-actions/hooks/useSeeWorkflowWorkflowRunSingleRecordAction';
import { WorkflowRunSingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/workflow-run-actions/types/WorkflowRunSingleRecordActionsKeys'; import { WorkflowRunSingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/workflow-run-actions/types/WorkflowRunSingleRecordActionsKeys';
import { ActionHook } from '@/action-menu/actions/types/ActionHook'; import { inheritActionsFromDefaultConfig } from '@/action-menu/actions/record-actions/utils/inheritActionsFromDefaultConfig';
import { ActionViewType } from '@/action-menu/actions/types/ActionViewType'; import { ActionViewType } from '@/action-menu/actions/types/ActionViewType';
import { import {
ActionMenuEntry,
ActionMenuEntryScope, ActionMenuEntryScope,
ActionMenuEntryType, ActionMenuEntryType,
} from '@/action-menu/types/ActionMenuEntry'; } from '@/action-menu/types/ActionMenuEntry';
import { msg } from '@lingui/core/macro'; import { msg } from '@lingui/core/macro';
import { import { IconSettingsAutomation, IconVersions } from 'twenty-ui';
IconBuildingSkyscraper,
IconCheckbox,
IconChevronDown,
IconChevronUp,
IconDatabaseExport,
IconEyeOff,
IconHeart,
IconHeartOff,
IconRotate2,
IconSettings,
IconSettingsAutomation,
IconTargetArrow,
IconUser,
IconVersions,
} from 'twenty-ui';
export const WORKFLOW_RUNS_ACTIONS_CONFIG: Record< export const WORKFLOW_RUNS_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({
string, config: {
ActionMenuEntry & { [WorkflowRunSingleRecordActionKeys.SEE_WORKFLOW]: {
useAction: ActionHook; key: WorkflowRunSingleRecordActionKeys.SEE_WORKFLOW,
} label: msg`See workflow`,
> = { shortLabel: msg`See workflow`,
seeWorkflowSingleRecord: { position: 0,
key: WorkflowRunSingleRecordActionKeys.SEE_WORKFLOW, isPinned: true,
label: msg`See workflow`, type: ActionMenuEntryType.Standard,
shortLabel: msg`See workflow`, scope: ActionMenuEntryScope.RecordSelection,
position: 0, Icon: IconSettingsAutomation,
isPinned: true, shouldBeRegistered: () => true,
type: ActionMenuEntryType.Standard, availableOn: [
scope: ActionMenuEntryScope.RecordSelection, ActionViewType.SHOW_PAGE,
Icon: IconSettingsAutomation, ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
availableOn: [ ],
ActionViewType.SHOW_PAGE, useAction: useSeeWorkflowWorkflowRunSingleRecordAction,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, },
], [WorkflowRunSingleRecordActionKeys.SEE_VERSION]: {
useAction: useSeeWorkflowWorkflowRunSingleRecordAction, key: WorkflowRunSingleRecordActionKeys.SEE_VERSION,
label: msg`See version`,
shortLabel: msg`See version`,
position: 1,
isPinned: true,
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
Icon: IconVersions,
shouldBeRegistered: () => true,
availableOn: [
ActionViewType.SHOW_PAGE,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
],
useAction: useSeeVersionWorkflowRunSingleRecordAction,
},
[NoSelectionRecordActionKeys.GO_TO_WORKFLOWS]: {
type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global,
key: NoSelectionRecordActionKeys.GO_TO_WORKFLOWS,
label: msg`Go to workflows`,
shortLabel: msg`See workflows`,
position: 11,
Icon: IconSettingsAutomation,
accent: 'default',
isPinned: true,
shouldBeRegistered: () => true,
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
useAction: useSeeWorkflowsNoSelectionRecordAction,
hotKeys: ['G', 'W'],
},
}, },
seeVersionSingleRecord: { actionKeys: [
key: WorkflowRunSingleRecordActionKeys.SEE_VERSION, SingleRecordActionKeys.ADD_TO_FAVORITES,
label: msg`See version`, SingleRecordActionKeys.REMOVE_FROM_FAVORITES,
shortLabel: msg`See version`, SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD,
position: 1, SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD,
isPinned: true, SingleRecordActionKeys.EXPORT,
type: ActionMenuEntryType.Standard, MultipleRecordsActionKeys.EXPORT,
scope: ActionMenuEntryScope.RecordSelection, NoSelectionRecordActionKeys.EXPORT_VIEW,
Icon: IconVersions, NoSelectionRecordActionKeys.SEE_DELETED_RECORDS,
availableOn: [ NoSelectionRecordActionKeys.HIDE_DELETED_RECORDS,
ActionViewType.SHOW_PAGE, NoSelectionRecordActionKeys.GO_TO_PEOPLE,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, NoSelectionRecordActionKeys.GO_TO_COMPANIES,
], NoSelectionRecordActionKeys.GO_TO_OPPORTUNITIES,
useAction: useSeeVersionWorkflowRunSingleRecordAction, NoSelectionRecordActionKeys.GO_TO_SETTINGS,
NoSelectionRecordActionKeys.GO_TO_TASKS,
],
propertiesToOverwrite: {
[SingleRecordActionKeys.ADD_TO_FAVORITES]: {
isPinned: false,
position: 2,
},
[SingleRecordActionKeys.REMOVE_FROM_FAVORITES]: {
isPinned: false,
position: 3,
},
[SingleRecordActionKeys.EXPORT]: {
position: 4,
label: msg`Export run`,
},
[MultipleRecordsActionKeys.EXPORT]: {
position: 5,
label: msg`Export runs`,
},
[NoSelectionRecordActionKeys.EXPORT_VIEW]: {
position: 6,
label: msg`Export view`,
},
[NoSelectionRecordActionKeys.SEE_DELETED_RECORDS]: {
position: 7,
label: msg`See deleted runs`,
},
[NoSelectionRecordActionKeys.HIDE_DELETED_RECORDS]: {
position: 8,
label: msg`Hide deleted runs`,
},
[SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD]: {
position: 9,
},
[SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD]: {
position: 10,
},
[NoSelectionRecordActionKeys.GO_TO_PEOPLE]: {
position: 12,
},
[NoSelectionRecordActionKeys.GO_TO_COMPANIES]: {
position: 13,
},
[NoSelectionRecordActionKeys.GO_TO_OPPORTUNITIES]: {
position: 14,
},
[NoSelectionRecordActionKeys.GO_TO_SETTINGS]: {
position: 15,
},
[NoSelectionRecordActionKeys.GO_TO_TASKS]: {
position: 16,
},
}, },
addToFavoritesSingleRecord: { });
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
key: SingleRecordActionKeys.ADD_TO_FAVORITES,
label: msg`Add to favorites`,
shortLabel: msg`Add to favorites`,
position: 2,
isPinned: false,
Icon: IconHeart,
availableOn: [
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
ActionViewType.SHOW_PAGE,
],
useAction: useAddToFavoritesSingleRecordAction,
},
removeFromFavoritesSingleRecord: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
key: SingleRecordActionKeys.REMOVE_FROM_FAVORITES,
label: msg`Remove from favorites`,
shortLabel: msg`Remove from favorites`,
isPinned: false,
position: 3,
Icon: IconHeartOff,
availableOn: [
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
ActionViewType.SHOW_PAGE,
],
useAction: useRemoveFromFavoritesSingleRecordAction,
},
navigateToPreviousRecord: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
key: SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD,
label: msg`Navigate to previous run`,
position: 4,
isPinned: true,
Icon: IconChevronUp,
availableOn: [ActionViewType.SHOW_PAGE],
useAction: useNavigateToPreviousRecordSingleRecordAction,
},
navigateToNextRecord: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
key: SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD,
label: msg`Navigate to next run`,
position: 5,
isPinned: true,
Icon: IconChevronDown,
availableOn: [ActionViewType.SHOW_PAGE],
useAction: useNavigateToNextRecordSingleRecordAction,
},
exportSingleRecord: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
key: SingleRecordActionKeys.EXPORT,
label: msg`Export run`,
shortLabel: msg`Export`,
position: 6,
Icon: IconDatabaseExport,
accent: 'default',
isPinned: false,
availableOn: [
ActionViewType.SHOW_PAGE,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
],
useAction: useExportMultipleRecordsAction,
},
exportMultipleRecords: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
key: MultipleRecordsActionKeys.EXPORT,
label: msg`Export runs`,
shortLabel: msg`Export`,
position: 7,
Icon: IconDatabaseExport,
accent: 'default',
isPinned: false,
availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION],
useAction: useExportMultipleRecordsAction,
},
exportView: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.Object,
key: NoSelectionRecordActionKeys.EXPORT_VIEW,
label: msg`Export view`,
shortLabel: msg`Export`,
position: 8,
Icon: IconDatabaseExport,
accent: 'default',
isPinned: false,
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
useAction: useExportMultipleRecordsAction,
},
seeDeletedRecords: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.Object,
key: NoSelectionRecordActionKeys.SEE_DELETED_RECORDS,
label: msg`See deleted runs`,
shortLabel: msg`Deleted runs`,
position: 9,
Icon: IconRotate2,
accent: 'default',
isPinned: false,
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
useAction: useSeeDeletedRecordsNoSelectionRecordAction,
},
hideDeletedRecords: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.Object,
key: NoSelectionRecordActionKeys.HIDE_DELETED_RECORDS,
label: msg`Hide deleted runs`,
shortLabel: msg`Hide deleted`,
position: 10,
Icon: IconEyeOff,
accent: 'default',
isPinned: false,
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
useAction: useHideDeletedRecordsNoSelectionRecordAction,
},
seeAllWorkflows: {
type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global,
key: NoSelectionRecordActionKeys.GO_TO_WORKFLOWS,
label: msg`Go to workflows`,
shortLabel: msg`See workflows`,
position: 11,
Icon: IconSettingsAutomation,
accent: 'default',
isPinned: true,
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
useAction: useSeeWorkflowsNoSelectionRecordAction,
hotKeys: ['G', 'W'],
},
goToPeople: {
type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global,
key: NoSelectionRecordActionKeys.GO_TO_PEOPLE,
label: msg`Go to People`,
shortLabel: msg`People`,
position: 12,
Icon: IconUser,
isPinned: false,
availableOn: [
ActionViewType.INDEX_PAGE_NO_SELECTION,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
ActionViewType.INDEX_PAGE_BULK_SELECTION,
ActionViewType.SHOW_PAGE,
],
useAction: useGoToPeopleNoSelectionRecordAction,
hotKeys: ['G', 'P'],
},
goToCompanies: {
type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global,
key: NoSelectionRecordActionKeys.GO_TO_COMPANIES,
label: msg`Go to Companies`,
shortLabel: msg`Companies`,
position: 13,
Icon: IconBuildingSkyscraper,
isPinned: false,
availableOn: [
ActionViewType.INDEX_PAGE_NO_SELECTION,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
ActionViewType.INDEX_PAGE_BULK_SELECTION,
ActionViewType.SHOW_PAGE,
],
useAction: useGoToCompaniesNoSelectionRecordAction,
hotKeys: ['G', 'C'],
},
goToOpportunities: {
type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global,
key: NoSelectionRecordActionKeys.GO_TO_OPPORTUNITIES,
label: msg`Go to Opportunities`,
shortLabel: msg`Opportunities`,
position: 14,
Icon: IconTargetArrow,
isPinned: false,
availableOn: [
ActionViewType.INDEX_PAGE_NO_SELECTION,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
ActionViewType.INDEX_PAGE_BULK_SELECTION,
ActionViewType.SHOW_PAGE,
],
useAction: useGoToOpportunitiesNoSelectionRecordAction,
hotKeys: ['G', 'O'],
},
goToSettings: {
type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global,
key: NoSelectionRecordActionKeys.GO_TO_SETTINGS,
label: msg`Go to Settings`,
shortLabel: msg`Settings`,
position: 15,
Icon: IconSettings,
isPinned: false,
availableOn: [
ActionViewType.INDEX_PAGE_NO_SELECTION,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
ActionViewType.INDEX_PAGE_BULK_SELECTION,
ActionViewType.SHOW_PAGE,
],
useAction: useGoToSettingsNoSelectionRecordAction,
hotKeys: ['G', 'S'],
},
goToTasks: {
type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global,
key: NoSelectionRecordActionKeys.GO_TO_TASKS,
label: msg`Go to Tasks`,
shortLabel: msg`Tasks`,
position: 16,
Icon: IconCheckbox,
isPinned: false,
availableOn: [
ActionViewType.INDEX_PAGE_NO_SELECTION,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
ActionViewType.INDEX_PAGE_BULK_SELECTION,
ActionViewType.SHOW_PAGE,
],
useAction: useGoToTasksNoSelectionRecordAction,
hotKeys: ['G', 'T'],
},
};

View File

@ -1,350 +1,194 @@
import { useExportMultipleRecordsAction } from '@/action-menu/actions/record-actions/multiple-records/hooks/useExportMultipleRecordsAction';
import { MultipleRecordsActionKeys } from '@/action-menu/actions/record-actions/multiple-records/types/MultipleRecordsActionKeys'; import { MultipleRecordsActionKeys } from '@/action-menu/actions/record-actions/multiple-records/types/MultipleRecordsActionKeys';
import { useGoToCompaniesNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useGoToCompaniesNoSelectionRecordAction';
import { useGoToOpportunitiesNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useGoToOpportunitiesNoSelectionRecordAction';
import { useGoToPeopleNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useGoToPeopleNoSelectionRecordAction';
import { useGoToSettingsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useGoToSettingsNoSelectionRecordAction';
import { useGoToTasksNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useGoToTasksNoSelectionRecordAction';
import { useHideDeletedRecordsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useHideDeletedRecordsNoSelectionRecordAction';
import { useSeeDeletedRecordsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useSeeDeletedRecordsNoSelectionRecordAction';
import { useSeeRunsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useSeeRunsNoSelectionRecordAction'; import { useSeeRunsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useSeeRunsNoSelectionRecordAction';
import { useSeeWorkflowsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useSeeWorkflowsNoSelectionRecordAction'; import { useSeeWorkflowsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useSeeWorkflowsNoSelectionRecordAction';
import { NoSelectionRecordActionKeys } from '@/action-menu/actions/record-actions/no-selection/types/NoSelectionRecordActionsKey'; import { NoSelectionRecordActionKeys } from '@/action-menu/actions/record-actions/no-selection/types/NoSelectionRecordActionsKeys';
import { useAddToFavoritesSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useAddToFavoritesSingleRecordAction'; import { NoSelectionWorkflowRecordActionKeys } from '@/action-menu/actions/record-actions/no-selection/workflow-actions/types/NoSelectionWorkflowRecordActionsKeys';
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 { SingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/types/SingleRecordActionsKey'; import { SingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/types/SingleRecordActionsKey';
import { useSeeRunsWorkflowVersionSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-version-actions/hooks/useSeeRunsWorkflowVersionSingleRecordAction'; import { useSeeRunsWorkflowVersionSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-version-actions/hooks/useSeeRunsWorkflowVersionSingleRecordAction';
import { useSeeVersionsWorkflowVersionSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-version-actions/hooks/useSeeVersionsWorkflowVersionSingleRecordAction'; import { useSeeVersionsWorkflowVersionSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-version-actions/hooks/useSeeVersionsWorkflowVersionSingleRecordAction';
import { useSeeWorkflowWorkflowVersionSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-version-actions/hooks/useSeeWorkflowWorkflowVersionSingleRecordAction'; import { useSeeWorkflowWorkflowVersionSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-version-actions/hooks/useSeeWorkflowWorkflowVersionSingleRecordAction';
import { useUseAsDraftWorkflowVersionSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/workflow-version-actions/hooks/useUseAsDraftWorkflowVersionSingleRecordAction'; 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 { WorkflowVersionSingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/workflow-version-actions/types/WorkflowVersionSingleRecordActionsKeys';
import { ActionHook } from '@/action-menu/actions/types/ActionHook'; import { inheritActionsFromDefaultConfig } from '@/action-menu/actions/record-actions/utils/inheritActionsFromDefaultConfig';
import { ActionViewType } from '@/action-menu/actions/types/ActionViewType'; import { ActionViewType } from '@/action-menu/actions/types/ActionViewType';
import { import {
ActionMenuEntry,
ActionMenuEntryScope, ActionMenuEntryScope,
ActionMenuEntryType, ActionMenuEntryType,
} from '@/action-menu/types/ActionMenuEntry'; } from '@/action-menu/types/ActionMenuEntry';
import { msg } from '@lingui/core/macro'; import { msg } from '@lingui/core/macro';
import { isDefined } from 'twenty-shared/utils';
import { import {
IconBuildingSkyscraper,
IconCheckbox,
IconChevronDown,
IconChevronUp,
IconDatabaseExport,
IconEyeOff,
IconHeart,
IconHeartOff,
IconHistoryToggle, IconHistoryToggle,
IconPencil, IconPencil,
IconRotate2,
IconSettings,
IconSettingsAutomation, IconSettingsAutomation,
IconTargetArrow,
IconUser,
IconVersions, IconVersions,
} from 'twenty-ui'; } from 'twenty-ui';
export const WORKFLOW_VERSIONS_ACTIONS_CONFIG: Record< export const WORKFLOW_VERSIONS_ACTIONS_CONFIG = inheritActionsFromDefaultConfig(
string, {
ActionMenuEntry & { config: {
useAction: ActionHook; [WorkflowVersionSingleRecordActionKeys.USE_AS_DRAFT]: {
} key: WorkflowVersionSingleRecordActionKeys.USE_AS_DRAFT,
> = { label: msg`Use as draft`,
useAsDraftWorkflowVersionSingleRecord: { shortLabel: msg`Use as draft`,
key: WorkflowVersionSingleRecordActionKeys.USE_AS_DRAFT, position: 1,
label: msg`Use as draft`, isPinned: true,
shortLabel: msg`Use as draft`, type: ActionMenuEntryType.Standard,
position: 1, scope: ActionMenuEntryScope.RecordSelection,
isPinned: true, Icon: IconPencil,
type: ActionMenuEntryType.Standard, shouldBeRegistered: ({ selectedRecord }) =>
scope: ActionMenuEntryScope.RecordSelection, isDefined(selectedRecord) && selectedRecord.status !== 'DRAFT',
Icon: IconPencil, availableOn: [
availableOn: [ ActionViewType.SHOW_PAGE,
ActionViewType.SHOW_PAGE, ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION, ],
useAction: useUseAsDraftWorkflowVersionSingleRecordAction,
},
[WorkflowVersionSingleRecordActionKeys.SEE_WORKFLOW]: {
key: WorkflowVersionSingleRecordActionKeys.SEE_WORKFLOW,
label: msg`See workflow`,
shortLabel: msg`See workflow`,
position: 2,
isPinned: true,
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
Icon: IconSettingsAutomation,
shouldBeRegistered: ({ selectedRecord }) =>
isDefined(selectedRecord?.workflow?.id),
availableOn: [
ActionViewType.SHOW_PAGE,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
],
useAction: useSeeWorkflowWorkflowVersionSingleRecordAction,
},
[WorkflowVersionSingleRecordActionKeys.SEE_RUNS]: {
key: WorkflowVersionSingleRecordActionKeys.SEE_RUNS,
label: msg`See runs`,
shortLabel: msg`See runs`,
position: 3,
isPinned: true,
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
Icon: IconHistoryToggle,
shouldBeRegistered: ({ workflowWithCurrentVersion }) =>
isDefined(workflowWithCurrentVersion),
availableOn: [
ActionViewType.SHOW_PAGE,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
],
useAction: useSeeRunsWorkflowVersionSingleRecordAction,
},
[WorkflowVersionSingleRecordActionKeys.SEE_VERSIONS]: {
key: WorkflowVersionSingleRecordActionKeys.SEE_VERSIONS,
label: msg`See versions history`,
shortLabel: msg`See versions`,
position: 4,
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
Icon: IconVersions,
shouldBeRegistered: ({ workflowWithCurrentVersion }) =>
isDefined(workflowWithCurrentVersion),
availableOn: [
ActionViewType.SHOW_PAGE,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
],
useAction: useSeeVersionsWorkflowVersionSingleRecordAction,
},
[NoSelectionRecordActionKeys.GO_TO_WORKFLOWS]: {
type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global,
key: NoSelectionRecordActionKeys.GO_TO_WORKFLOWS,
label: msg`Go to workflows`,
shortLabel: msg`See workflows`,
position: 14,
Icon: IconSettingsAutomation,
accent: 'default',
isPinned: true,
shouldBeRegistered: () => true,
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
useAction: useSeeWorkflowsNoSelectionRecordAction,
hotKeys: ['G', 'W'],
},
[NoSelectionWorkflowRecordActionKeys.GO_TO_RUNS]: {
type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global,
key: NoSelectionWorkflowRecordActionKeys.GO_TO_RUNS,
label: msg`Go to runs`,
shortLabel: msg`See runs`,
position: 15,
Icon: IconHistoryToggle,
accent: 'default',
isPinned: true,
shouldBeRegistered: () => true,
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
useAction: useSeeRunsNoSelectionRecordAction,
},
},
actionKeys: [
SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD,
SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD,
SingleRecordActionKeys.ADD_TO_FAVORITES,
SingleRecordActionKeys.REMOVE_FROM_FAVORITES,
SingleRecordActionKeys.EXPORT,
MultipleRecordsActionKeys.EXPORT,
NoSelectionRecordActionKeys.EXPORT_VIEW,
NoSelectionRecordActionKeys.SEE_DELETED_RECORDS,
NoSelectionRecordActionKeys.HIDE_DELETED_RECORDS,
NoSelectionRecordActionKeys.GO_TO_PEOPLE,
NoSelectionRecordActionKeys.GO_TO_COMPANIES,
NoSelectionRecordActionKeys.GO_TO_OPPORTUNITIES,
NoSelectionRecordActionKeys.GO_TO_SETTINGS,
NoSelectionRecordActionKeys.GO_TO_TASKS,
], ],
useAction: useUseAsDraftWorkflowVersionSingleRecordAction, propertiesToOverwrite: {
[SingleRecordActionKeys.ADD_TO_FAVORITES]: {
position: 5,
isPinned: false,
},
[SingleRecordActionKeys.REMOVE_FROM_FAVORITES]: {
position: 6,
isPinned: false,
},
[SingleRecordActionKeys.EXPORT]: {
position: 7,
label: msg`Export version`,
},
[MultipleRecordsActionKeys.EXPORT]: {
position: 8,
label: msg`Export versions`,
},
[NoSelectionRecordActionKeys.EXPORT_VIEW]: {
position: 9,
},
[NoSelectionRecordActionKeys.SEE_DELETED_RECORDS]: {
position: 10,
},
[NoSelectionRecordActionKeys.HIDE_DELETED_RECORDS]: {
position: 11,
},
[SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD]: {
position: 12,
label: msg`Navigate to previous version`,
},
[SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD]: {
position: 13,
label: msg`Navigate to next version`,
},
[NoSelectionRecordActionKeys.GO_TO_PEOPLE]: {
position: 16,
},
[NoSelectionRecordActionKeys.GO_TO_COMPANIES]: {
position: 17,
},
[NoSelectionRecordActionKeys.GO_TO_OPPORTUNITIES]: {
position: 18,
},
[NoSelectionRecordActionKeys.GO_TO_SETTINGS]: {
position: 19,
},
[NoSelectionRecordActionKeys.GO_TO_TASKS]: {
position: 20,
},
},
}, },
seeWorkflowSingleRecord: { );
key: WorkflowVersionSingleRecordActionKeys.SEE_WORKFLOW,
label: msg`See workflow`,
shortLabel: msg`See workflow`,
position: 2,
isPinned: true,
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
Icon: IconSettingsAutomation,
availableOn: [
ActionViewType.SHOW_PAGE,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
],
useAction: useSeeWorkflowWorkflowVersionSingleRecordAction,
},
seeWorkflowRunsSingleRecord: {
key: WorkflowVersionSingleRecordActionKeys.SEE_RUNS,
label: msg`See runs`,
shortLabel: msg`See runs`,
position: 3,
isPinned: true,
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
Icon: IconHistoryToggle,
availableOn: [
ActionViewType.SHOW_PAGE,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
],
useAction: useSeeRunsWorkflowVersionSingleRecordAction,
},
seeWorkflowVersionsHistorySingleRecord: {
key: WorkflowVersionSingleRecordActionKeys.SEE_VERSIONS,
label: msg`See versions history`,
shortLabel: msg`See versions`,
position: 4,
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
Icon: IconVersions,
availableOn: [
ActionViewType.SHOW_PAGE,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
],
useAction: useSeeVersionsWorkflowVersionSingleRecordAction,
},
navigateToPreviousRecord: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
key: SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD,
label: msg`Navigate to previous version`,
position: 5,
Icon: IconChevronUp,
availableOn: [ActionViewType.SHOW_PAGE],
useAction: useNavigateToPreviousRecordSingleRecordAction,
},
navigateToNextRecord: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
key: SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD,
label: msg`Navigate to next version`,
position: 6,
Icon: IconChevronDown,
availableOn: [ActionViewType.SHOW_PAGE],
useAction: useNavigateToNextRecordSingleRecordAction,
},
addToFavoritesSingleRecord: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
key: SingleRecordActionKeys.ADD_TO_FAVORITES,
label: msg`Add to favorites`,
shortLabel: msg`Add to favorites`,
position: 7,
isPinned: false,
Icon: IconHeart,
availableOn: [
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
ActionViewType.SHOW_PAGE,
],
useAction: useAddToFavoritesSingleRecordAction,
},
removeFromFavoritesSingleRecord: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
key: SingleRecordActionKeys.REMOVE_FROM_FAVORITES,
label: msg`Remove from favorites`,
shortLabel: msg`Remove from favorites`,
isPinned: false,
position: 8,
Icon: IconHeartOff,
availableOn: [
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
ActionViewType.SHOW_PAGE,
],
useAction: useRemoveFromFavoritesSingleRecordAction,
},
exportSingleRecord: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
key: SingleRecordActionKeys.EXPORT,
label: msg`Export version`,
shortLabel: msg`Export`,
position: 9,
Icon: IconDatabaseExport,
accent: 'default',
isPinned: false,
availableOn: [
ActionViewType.SHOW_PAGE,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
],
useAction: useExportMultipleRecordsAction,
},
exportMultipleRecords: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
key: MultipleRecordsActionKeys.EXPORT,
label: msg`Export versions`,
shortLabel: msg`Export`,
position: 10,
Icon: IconDatabaseExport,
accent: 'default',
isPinned: false,
availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION],
useAction: useExportMultipleRecordsAction,
},
exportView: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.Object,
key: NoSelectionRecordActionKeys.EXPORT_VIEW,
label: msg`Export view`,
shortLabel: msg`Export`,
position: 11,
Icon: IconDatabaseExport,
accent: 'default',
isPinned: false,
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
useAction: useExportMultipleRecordsAction,
},
seeDeletedRecords: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.Object,
key: NoSelectionRecordActionKeys.SEE_DELETED_RECORDS,
label: msg`See deleted versions`,
shortLabel: msg`Deleted versions`,
position: 12,
Icon: IconRotate2,
accent: 'default',
isPinned: false,
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
useAction: useSeeDeletedRecordsNoSelectionRecordAction,
},
hideDeletedRecords: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.Object,
key: NoSelectionRecordActionKeys.HIDE_DELETED_RECORDS,
label: msg`Hide deleted versions`,
shortLabel: msg`Hide deleted`,
position: 13,
Icon: IconEyeOff,
accent: 'default',
isPinned: false,
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
useAction: useHideDeletedRecordsNoSelectionRecordAction,
},
seeAllWorkflows: {
type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global,
key: NoSelectionRecordActionKeys.GO_TO_WORKFLOWS,
label: msg`Go to workflows`,
shortLabel: msg`See workflows`,
position: 14,
Icon: IconSettingsAutomation,
accent: 'default',
isPinned: true,
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
useAction: useSeeWorkflowsNoSelectionRecordAction,
hotKeys: ['G', 'W'],
},
seeAllRuns: {
type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global,
key: NoSelectionRecordActionKeys.GO_TO_RUNS,
label: msg`Go to runs`,
shortLabel: msg`See runs`,
position: 15,
Icon: IconHistoryToggle,
accent: 'default',
isPinned: true,
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
useAction: useSeeRunsNoSelectionRecordAction,
},
goToPeople: {
type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global,
key: NoSelectionRecordActionKeys.GO_TO_PEOPLE,
label: msg`Go to People`,
shortLabel: msg`People`,
position: 16,
Icon: IconUser,
isPinned: false,
availableOn: [
ActionViewType.INDEX_PAGE_NO_SELECTION,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
ActionViewType.INDEX_PAGE_BULK_SELECTION,
ActionViewType.SHOW_PAGE,
],
useAction: useGoToPeopleNoSelectionRecordAction,
hotKeys: ['G', 'P'],
},
goToCompanies: {
type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global,
key: NoSelectionRecordActionKeys.GO_TO_COMPANIES,
label: msg`Go to Companies`,
shortLabel: msg`Companies`,
position: 17,
Icon: IconBuildingSkyscraper,
isPinned: false,
availableOn: [
ActionViewType.INDEX_PAGE_NO_SELECTION,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
ActionViewType.INDEX_PAGE_BULK_SELECTION,
ActionViewType.SHOW_PAGE,
],
useAction: useGoToCompaniesNoSelectionRecordAction,
hotKeys: ['G', 'C'],
},
goToOpportunities: {
type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global,
key: NoSelectionRecordActionKeys.GO_TO_OPPORTUNITIES,
label: msg`Go to Opportunities`,
shortLabel: msg`Opportunities`,
position: 18,
Icon: IconTargetArrow,
isPinned: false,
availableOn: [
ActionViewType.INDEX_PAGE_NO_SELECTION,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
ActionViewType.INDEX_PAGE_BULK_SELECTION,
ActionViewType.SHOW_PAGE,
],
useAction: useGoToOpportunitiesNoSelectionRecordAction,
hotKeys: ['G', 'O'],
},
goToSettings: {
type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global,
key: NoSelectionRecordActionKeys.GO_TO_SETTINGS,
label: msg`Go to Settings`,
shortLabel: msg`Settings`,
position: 19,
Icon: IconSettings,
isPinned: false,
availableOn: [
ActionViewType.INDEX_PAGE_NO_SELECTION,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
ActionViewType.INDEX_PAGE_BULK_SELECTION,
ActionViewType.SHOW_PAGE,
],
useAction: useGoToSettingsNoSelectionRecordAction,
hotKeys: ['G', 'S'],
},
goToTasks: {
type: ActionMenuEntryType.Navigation,
scope: ActionMenuEntryScope.Global,
key: NoSelectionRecordActionKeys.GO_TO_TASKS,
label: msg`Go to Tasks`,
shortLabel: msg`Tasks`,
position: 20,
Icon: IconCheckbox,
isPinned: false,
availableOn: [
ActionViewType.INDEX_PAGE_NO_SELECTION,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
ActionViewType.INDEX_PAGE_BULK_SELECTION,
ActionViewType.SHOW_PAGE,
],
useAction: useGoToTasksNoSelectionRecordAction,
hotKeys: ['G', 'T'],
},
};

View File

@ -75,8 +75,6 @@ const getWrapper = (
...overrides, ...overrides,
}); });
const defaultWrapper = getWrapper();
describe('useDestroyMultipleRecordsAction', () => { describe('useDestroyMultipleRecordsAction', () => {
it('should call destroyManyRecords on click if records are filtered by deletedAt', async () => { it('should call destroyManyRecords on click if records are filtered by deletedAt', async () => {
const { result } = renderHook( const { result } = renderHook(
@ -121,24 +119,4 @@ describe('useDestroyMultipleRecordsAction', () => {
expect(destroyManyRecordsMock).toHaveBeenCalledWith(expectedParams); expect(destroyManyRecordsMock).toHaveBeenCalledWith(expectedParams);
}); });
}); });
it('should not call destroyManyRecords on click if records are not filtered by deletedAt', async () => {
const { result } = renderHook(
() =>
useDestroyMultipleRecordsAction({
objectMetadataItem: personMockObjectMetadataItem,
}),
{
wrapper: defaultWrapper,
},
);
expect(result.current.ConfirmationModal?.props?.isOpen).toBeFalsy();
act(() => {
result.current.onClick();
});
expect(result.current.ConfirmationModal?.props?.isOpen).toBeFalsy();
});
}); });

View File

@ -2,23 +2,18 @@ import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/Ac
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState'; import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters'; import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters';
import { BACKEND_BATCH_REQUEST_MAX_COUNT } from '@/object-record/constants/BackendBatchRequestMaxCount';
import { DEFAULT_QUERY_PAGE_SIZE } from '@/object-record/constants/DefaultQueryPageSize'; import { DEFAULT_QUERY_PAGE_SIZE } from '@/object-record/constants/DefaultQueryPageSize';
import { useDeleteManyRecords } from '@/object-record/hooks/useDeleteManyRecords'; import { useDeleteManyRecords } from '@/object-record/hooks/useDeleteManyRecords';
import { useLazyFetchAllRecords } from '@/object-record/hooks/useLazyFetchAllRecords'; import { useLazyFetchAllRecords } from '@/object-record/hooks/useLazyFetchAllRecords';
import { useCheckIsSoftDeleteFilter } from '@/object-record/record-filter/hooks/useCheckIsSoftDeleteFilter';
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies'; import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId'; import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId';
import { useHasObjectReadOnlyPermission } from '@/settings/roles/hooks/useHasObjectReadOnlyPermission';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal'; import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { t } from '@lingui/core/macro'; import { t } from '@lingui/core/macro';
import { useCallback, useState } from 'react'; import { useCallback, useState } from 'react';
import { isDefined } from 'twenty-shared/utils';
export const useDeleteMultipleRecordsAction: ActionHookWithObjectMetadataItem = export const useDeleteMultipleRecordsAction: ActionHookWithObjectMetadataItem =
({ objectMetadataItem }) => { ({ objectMetadataItem }) => {
@ -33,8 +28,6 @@ export const useDeleteMultipleRecordsAction: ActionHookWithObjectMetadataItem =
throw new Error('Current view ID is not defined'); throw new Error('Current view ID is not defined');
} }
const hasObjectReadOnlyPermission = useHasObjectReadOnlyPermission();
const { resetTableRowSelection } = useRecordTable({ const { resetTableRowSelection } = useRecordTable({
recordTableId: getRecordIndexIdFromObjectNamePluralAndViewId( recordTableId: getRecordIndexIdFromObjectNamePluralAndViewId(
objectMetadataItem.namePlural, objectMetadataItem.namePlural,
@ -46,10 +39,6 @@ export const useDeleteMultipleRecordsAction: ActionHookWithObjectMetadataItem =
objectNameSingular: objectMetadataItem.nameSingular, objectNameSingular: objectMetadataItem.nameSingular,
}); });
const contextStoreNumberOfSelectedRecords = useRecoilComponentValueV2(
contextStoreNumberOfSelectedRecordsComponentState,
);
const contextStoreTargetedRecordsRule = useRecoilComponentValueV2( const contextStoreTargetedRecordsRule = useRecoilComponentValueV2(
contextStoreTargetedRecordsRuleComponentState, contextStoreTargetedRecordsRuleComponentState,
); );
@ -67,12 +56,6 @@ export const useDeleteMultipleRecordsAction: ActionHookWithObjectMetadataItem =
filterValueDependencies, filterValueDependencies,
); );
const { checkIsSoftDeleteFilter } = useCheckIsSoftDeleteFilter();
const isDeletedFilterActive = contextStoreFilters.some(
checkIsSoftDeleteFilter,
);
const { fetchAllRecords: fetchAllRecordIds } = useLazyFetchAllRecords({ const { fetchAllRecords: fetchAllRecordIds } = useLazyFetchAllRecords({
objectNameSingular: objectMetadataItem.nameSingular, objectNameSingular: objectMetadataItem.nameSingular,
filter: graphqlFilter, filter: graphqlFilter,
@ -91,21 +74,7 @@ export const useDeleteMultipleRecordsAction: ActionHookWithObjectMetadataItem =
}); });
}, [deleteManyRecords, fetchAllRecordIds, resetTableRowSelection]); }, [deleteManyRecords, fetchAllRecordIds, resetTableRowSelection]);
const isRemoteObject = objectMetadataItem.isRemote;
const shouldBeRegistered =
!hasObjectReadOnlyPermission &&
!isRemoteObject &&
!isDeletedFilterActive &&
isDefined(contextStoreNumberOfSelectedRecords) &&
contextStoreNumberOfSelectedRecords < BACKEND_BATCH_REQUEST_MAX_COUNT &&
contextStoreNumberOfSelectedRecords > 0;
const onClick = () => { const onClick = () => {
if (!shouldBeRegistered) {
return;
}
setIsDeleteRecordsModalOpen(true); setIsDeleteRecordsModalOpen(true);
}; };
@ -121,7 +90,6 @@ export const useDeleteMultipleRecordsAction: ActionHookWithObjectMetadataItem =
); );
return { return {
shouldBeRegistered,
onClick, onClick,
ConfirmationModal: confirmationModal, ConfirmationModal: confirmationModal,
}; };

View File

@ -2,23 +2,18 @@ import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/Ac
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState'; import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters'; import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters';
import { BACKEND_BATCH_REQUEST_MAX_COUNT } from '@/object-record/constants/BackendBatchRequestMaxCount';
import { DEFAULT_QUERY_PAGE_SIZE } from '@/object-record/constants/DefaultQueryPageSize'; import { DEFAULT_QUERY_PAGE_SIZE } from '@/object-record/constants/DefaultQueryPageSize';
import { RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; import { RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
import { useDestroyManyRecords } from '@/object-record/hooks/useDestroyManyRecords'; import { useDestroyManyRecords } from '@/object-record/hooks/useDestroyManyRecords';
import { useLazyFetchAllRecords } from '@/object-record/hooks/useLazyFetchAllRecords'; import { useLazyFetchAllRecords } from '@/object-record/hooks/useLazyFetchAllRecords';
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies'; import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId'; import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId';
import { useHasObjectReadOnlyPermission } from '@/settings/roles/hooks/useHasObjectReadOnlyPermission';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal'; import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useCallback, useState } from 'react'; import { useCallback, useState } from 'react';
import { isDefined } from 'twenty-shared/utils';
export const useDestroyMultipleRecordsAction: ActionHookWithObjectMetadataItem = export const useDestroyMultipleRecordsAction: ActionHookWithObjectMetadataItem =
({ objectMetadataItem }) => { ({ objectMetadataItem }) => {
@ -40,16 +35,10 @@ export const useDestroyMultipleRecordsAction: ActionHookWithObjectMetadataItem =
), ),
}); });
const hasObjectReadOnlyPermission = useHasObjectReadOnlyPermission();
const { destroyManyRecords } = useDestroyManyRecords({ const { destroyManyRecords } = useDestroyManyRecords({
objectNameSingular: objectMetadataItem.nameSingular, objectNameSingular: objectMetadataItem.nameSingular,
}); });
const contextStoreNumberOfSelectedRecords = useRecoilComponentValueV2(
contextStoreNumberOfSelectedRecordsComponentState,
);
const contextStoreTargetedRecordsRule = useRecoilComponentValueV2( const contextStoreTargetedRecordsRule = useRecoilComponentValueV2(
contextStoreTargetedRecordsRuleComponentState, contextStoreTargetedRecordsRuleComponentState,
); );
@ -73,16 +62,6 @@ export const useDestroyMultipleRecordsAction: ActionHookWithObjectMetadataItem =
...deletedAtFilter, ...deletedAtFilter,
}; };
const deletedAtFieldMetadata = objectMetadataItem.fields.find(
(field) => field.name === 'deletedAt',
);
const isDeletedFilterActive = contextStoreFilters.some(
(filter) =>
filter.fieldMetadataId === deletedAtFieldMetadata?.id &&
filter.operand === RecordFilterOperand.IsNotEmpty,
);
const { fetchAllRecords: fetchAllRecordIds } = useLazyFetchAllRecords({ const { fetchAllRecords: fetchAllRecordIds } = useLazyFetchAllRecords({
objectNameSingular: objectMetadataItem.nameSingular, objectNameSingular: objectMetadataItem.nameSingular,
filter: graphqlFilter, filter: graphqlFilter,
@ -99,21 +78,7 @@ export const useDestroyMultipleRecordsAction: ActionHookWithObjectMetadataItem =
await destroyManyRecords({ recordIdsToDestroy }); await destroyManyRecords({ recordIdsToDestroy });
}, [destroyManyRecords, fetchAllRecordIds, resetTableRowSelection]); }, [destroyManyRecords, fetchAllRecordIds, resetTableRowSelection]);
const isRemoteObject = objectMetadataItem.isRemote;
const shouldBeRegistered =
!hasObjectReadOnlyPermission &&
!isRemoteObject &&
isDeletedFilterActive &&
isDefined(contextStoreNumberOfSelectedRecords) &&
contextStoreNumberOfSelectedRecords < BACKEND_BATCH_REQUEST_MAX_COUNT &&
contextStoreNumberOfSelectedRecords > 0;
const onClick = () => { const onClick = () => {
if (!shouldBeRegistered) {
return;
}
setIsDestroyRecordsModalOpen(true); setIsDestroyRecordsModalOpen(true);
}; };
@ -131,7 +96,6 @@ export const useDestroyMultipleRecordsAction: ActionHookWithObjectMetadataItem =
); );
return { return {
shouldBeRegistered,
onClick, onClick,
ConfirmationModal: confirmationModal, ConfirmationModal: confirmationModal,
}; };

View File

@ -33,7 +33,6 @@ export const useExportMultipleRecordsAction = ({
}; };
return { return {
shouldBeRegistered: true,
onClick, onClick,
}; };
}; };

View File

@ -3,22 +3,17 @@ import { useCallback, useState } from 'react';
import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/ActionHook'; import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/ActionHook';
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState'; import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState'; import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters'; import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters';
import { BACKEND_BATCH_REQUEST_MAX_COUNT } from '@/object-record/constants/BackendBatchRequestMaxCount';
import { DEFAULT_QUERY_PAGE_SIZE } from '@/object-record/constants/DefaultQueryPageSize'; import { DEFAULT_QUERY_PAGE_SIZE } from '@/object-record/constants/DefaultQueryPageSize';
import { RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter'; import { RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
import { useLazyFetchAllRecords } from '@/object-record/hooks/useLazyFetchAllRecords'; import { useLazyFetchAllRecords } from '@/object-record/hooks/useLazyFetchAllRecords';
import { useRestoreManyRecords } from '@/object-record/hooks/useRestoreManyRecords'; import { useRestoreManyRecords } from '@/object-record/hooks/useRestoreManyRecords';
import { useCheckIsSoftDeleteFilter } from '@/object-record/record-filter/hooks/useCheckIsSoftDeleteFilter';
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies'; import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId'; import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId';
import { useHasObjectReadOnlyPermission } from '@/settings/roles/hooks/useHasObjectReadOnlyPermission';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal'; import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { isDefined } from 'twenty-shared/utils';
export const useRestoreMultipleRecordsAction: ActionHookWithObjectMetadataItem = export const useRestoreMultipleRecordsAction: ActionHookWithObjectMetadataItem =
({ objectMetadataItem }) => { ({ objectMetadataItem }) => {
@ -33,8 +28,6 @@ export const useRestoreMultipleRecordsAction: ActionHookWithObjectMetadataItem =
throw new Error('Current view ID is not defined'); throw new Error('Current view ID is not defined');
} }
const hasObjectReadOnlyPermission = useHasObjectReadOnlyPermission();
const { resetTableRowSelection } = useRecordTable({ const { resetTableRowSelection } = useRecordTable({
recordTableId: getRecordIndexIdFromObjectNamePluralAndViewId( recordTableId: getRecordIndexIdFromObjectNamePluralAndViewId(
objectMetadataItem.namePlural, objectMetadataItem.namePlural,
@ -46,10 +39,6 @@ export const useRestoreMultipleRecordsAction: ActionHookWithObjectMetadataItem =
objectNameSingular: objectMetadataItem.nameSingular, objectNameSingular: objectMetadataItem.nameSingular,
}); });
const contextStoreNumberOfSelectedRecords = useRecoilComponentValueV2(
contextStoreNumberOfSelectedRecordsComponentState,
);
const contextStoreTargetedRecordsRule = useRecoilComponentValueV2( const contextStoreTargetedRecordsRule = useRecoilComponentValueV2(
contextStoreTargetedRecordsRuleComponentState, contextStoreTargetedRecordsRuleComponentState,
); );
@ -74,12 +63,6 @@ export const useRestoreMultipleRecordsAction: ActionHookWithObjectMetadataItem =
...deletedAtFilter, ...deletedAtFilter,
}; };
const { checkIsSoftDeleteFilter } = useCheckIsSoftDeleteFilter();
const isDeletedFilterActive = contextStoreFilters.some(
checkIsSoftDeleteFilter,
);
const { fetchAllRecords: fetchAllRecordIds } = useLazyFetchAllRecords({ const { fetchAllRecords: fetchAllRecordIds } = useLazyFetchAllRecords({
objectNameSingular: objectMetadataItem.nameSingular, objectNameSingular: objectMetadataItem.nameSingular,
filter: graphqlFilter, filter: graphqlFilter,
@ -98,21 +81,7 @@ export const useRestoreMultipleRecordsAction: ActionHookWithObjectMetadataItem =
}); });
}, [restoreManyRecords, fetchAllRecordIds, resetTableRowSelection]); }, [restoreManyRecords, fetchAllRecordIds, resetTableRowSelection]);
const isRemoteObject = objectMetadataItem.isRemote;
const shouldBeRegistered =
!hasObjectReadOnlyPermission &&
!isRemoteObject &&
isDeletedFilterActive &&
isDefined(contextStoreNumberOfSelectedRecords) &&
contextStoreNumberOfSelectedRecords < BACKEND_BATCH_REQUEST_MAX_COUNT &&
contextStoreNumberOfSelectedRecords > 0;
const onClick = () => { const onClick = () => {
if (!shouldBeRegistered) {
return;
}
setIsRestoreRecordsModalOpen(true); setIsRestoreRecordsModalOpen(true);
}; };
@ -128,7 +97,6 @@ export const useRestoreMultipleRecordsAction: ActionHookWithObjectMetadataItem =
); );
return { return {
shouldBeRegistered,
onClick, onClick,
ConfirmationModal: confirmationModal, ConfirmationModal: confirmationModal,
}; };

View File

@ -1,27 +1,13 @@
import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/ActionHook'; import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/ActionHook';
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
import { useCreateNewIndexRecord } from '@/object-record/record-table/hooks/useCreateNewIndexRecord'; import { useCreateNewIndexRecord } from '@/object-record/record-table/hooks/useCreateNewIndexRecord';
import { useHasObjectReadOnlyPermission } from '@/settings/roles/hooks/useHasObjectReadOnlyPermission';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
export const useCreateNewTableRecordNoSelectionRecordAction: ActionHookWithObjectMetadataItem = export const useCreateNewTableRecordNoSelectionRecordAction: ActionHookWithObjectMetadataItem =
({ objectMetadataItem }) => { ({ objectMetadataItem }) => {
const currentViewId = useRecoilComponentValueV2(
contextStoreCurrentViewIdComponentState,
);
if (!currentViewId) {
throw new Error('Current view ID is not defined');
}
const hasObjectReadOnlyPermission = useHasObjectReadOnlyPermission();
const { createNewIndexRecord } = useCreateNewIndexRecord({ const { createNewIndexRecord } = useCreateNewIndexRecord({
objectMetadataItem, objectMetadataItem,
}); });
return { return {
shouldBeRegistered: !hasObjectReadOnlyPermission,
onClick: createNewIndexRecord, onClick: createNewIndexRecord,
}; };
}; };

View File

@ -7,8 +7,6 @@ export const useGoToCompaniesNoSelectionRecordAction: ActionHookWithoutObjectMet
() => { () => {
const navigateApp = useNavigateApp(); const navigateApp = useNavigateApp();
const shouldBeRegistered = true;
const onClick = () => { const onClick = () => {
navigateApp(AppPath.RecordIndexPage, { navigateApp(AppPath.RecordIndexPage, {
objectNamePlural: CoreObjectNamePlural.Company, objectNamePlural: CoreObjectNamePlural.Company,
@ -16,7 +14,6 @@ export const useGoToCompaniesNoSelectionRecordAction: ActionHookWithoutObjectMet
}; };
return { return {
shouldBeRegistered,
onClick, onClick,
}; };
}; };

View File

@ -7,8 +7,6 @@ export const useGoToOpportunitiesNoSelectionRecordAction: ActionHookWithoutObjec
() => { () => {
const navigateApp = useNavigateApp(); const navigateApp = useNavigateApp();
const shouldBeRegistered = true;
const onClick = () => { const onClick = () => {
navigateApp(AppPath.RecordIndexPage, { navigateApp(AppPath.RecordIndexPage, {
objectNamePlural: CoreObjectNamePlural.Opportunity, objectNamePlural: CoreObjectNamePlural.Opportunity,
@ -16,7 +14,6 @@ export const useGoToOpportunitiesNoSelectionRecordAction: ActionHookWithoutObjec
}; };
return { return {
shouldBeRegistered,
onClick, onClick,
}; };
}; };

View File

@ -7,8 +7,6 @@ export const useGoToPeopleNoSelectionRecordAction: ActionHookWithoutObjectMetada
() => { () => {
const navigateApp = useNavigateApp(); const navigateApp = useNavigateApp();
const shouldBeRegistered = true;
const onClick = () => { const onClick = () => {
navigateApp(AppPath.RecordIndexPage, { navigateApp(AppPath.RecordIndexPage, {
objectNamePlural: CoreObjectNamePlural.Person, objectNamePlural: CoreObjectNamePlural.Person,
@ -16,7 +14,6 @@ export const useGoToPeopleNoSelectionRecordAction: ActionHookWithoutObjectMetada
}; };
return { return {
shouldBeRegistered,
onClick, onClick,
}; };
}; };

View File

@ -6,14 +6,11 @@ export const useGoToSettingsNoSelectionRecordAction: ActionHookWithoutObjectMeta
() => { () => {
const navigateSettings = useNavigateSettings(); const navigateSettings = useNavigateSettings();
const shouldBeRegistered = true;
const onClick = () => { const onClick = () => {
navigateSettings(SettingsPath.ProfilePage); navigateSettings(SettingsPath.ProfilePage);
}; };
return { return {
shouldBeRegistered,
onClick, onClick,
}; };
}; };

View File

@ -7,8 +7,6 @@ export const useGoToTasksNoSelectionRecordAction: ActionHookWithoutObjectMetadat
() => { () => {
const navigateApp = useNavigateApp(); const navigateApp = useNavigateApp();
const shouldBeRegistered = true;
const onClick = () => { const onClick = () => {
navigateApp(AppPath.RecordIndexPage, { navigateApp(AppPath.RecordIndexPage, {
objectNamePlural: CoreObjectNamePlural.Task, objectNamePlural: CoreObjectNamePlural.Task,
@ -16,7 +14,6 @@ export const useGoToTasksNoSelectionRecordAction: ActionHookWithoutObjectMetadat
}; };
return { return {
shouldBeRegistered,
onClick, onClick,
}; };
}; };

View File

@ -52,7 +52,6 @@ export const useHideDeletedRecordsNoSelectionRecordAction: ActionHookWithObjectM
}, [deletedFilter, removeRecordFilter, toggleSoftDeleteFilterState]); }, [deletedFilter, removeRecordFilter, toggleSoftDeleteFilterState]);
return { return {
shouldBeRegistered: isDefined(deletedFilter),
onClick, onClick,
}; };
}; };

View File

@ -9,9 +9,6 @@ export const useImportRecordsNoSelectionRecordAction: ActionHookWithObjectMetada
); );
return { return {
shouldBeRegistered: true, onClick: openObjectRecordsSpreadsheetImportDialog,
onClick: () => {
openObjectRecordsSpreadsheetImportDialog();
},
}; };
}; };

View File

@ -2,8 +2,6 @@ import { useCallback } from 'react';
import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/ActionHook'; import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/ActionHook';
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
import { useCheckIsSoftDeleteFilter } from '@/object-record/record-filter/hooks/useCheckIsSoftDeleteFilter';
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
import { useHandleToggleTrashColumnFilter } from '@/object-record/record-index/hooks/useHandleToggleTrashColumnFilter'; import { useHandleToggleTrashColumnFilter } from '@/object-record/record-index/hooks/useHandleToggleTrashColumnFilter';
import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId'; import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
@ -29,24 +27,12 @@ export const useSeeDeletedRecordsNoSelectionRecordAction: ActionHookWithObjectMe
viewBarId: recordIndexId, viewBarId: recordIndexId,
}); });
const { checkIsSoftDeleteFilter } = useCheckIsSoftDeleteFilter();
const currentRecordFilters = useRecoilComponentValueV2(
currentRecordFiltersComponentState,
recordIndexId,
);
const isDeletedFilterActive = currentRecordFilters.some(
checkIsSoftDeleteFilter,
);
const onClick = useCallback(() => { const onClick = useCallback(() => {
handleToggleTrashColumnFilter(); handleToggleTrashColumnFilter();
toggleSoftDeleteFilterState(true); toggleSoftDeleteFilterState(true);
}, [handleToggleTrashColumnFilter, toggleSoftDeleteFilterState]); }, [handleToggleTrashColumnFilter, toggleSoftDeleteFilterState]);
return { return {
shouldBeRegistered: !isDeletedFilterActive,
onClick, onClick,
}; };
}; };

View File

@ -7,8 +7,6 @@ export const useSeeRunsNoSelectionRecordAction: ActionHookWithoutObjectMetadataI
() => { () => {
const navigateApp = useNavigateApp(); const navigateApp = useNavigateApp();
const shouldBeRegistered = true;
const onClick = () => { const onClick = () => {
navigateApp(AppPath.RecordIndexPage, { navigateApp(AppPath.RecordIndexPage, {
objectNamePlural: CoreObjectNamePlural.WorkflowRun, objectNamePlural: CoreObjectNamePlural.WorkflowRun,
@ -16,7 +14,6 @@ export const useSeeRunsNoSelectionRecordAction: ActionHookWithoutObjectMetadataI
}; };
return { return {
shouldBeRegistered,
onClick, onClick,
}; };
}; };

View File

@ -1,20 +1,12 @@
import { ActionHookWithoutObjectMetadataItem } from '@/action-menu/actions/types/ActionHook'; import { ActionHookWithoutObjectMetadataItem } from '@/action-menu/actions/types/ActionHook';
import { CoreObjectNamePlural } from '@/object-metadata/types/CoreObjectNamePlural'; import { CoreObjectNamePlural } from '@/object-metadata/types/CoreObjectNamePlural';
import { AppPath } from '@/types/AppPath'; import { AppPath } from '@/types/AppPath';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { FeatureFlagKey } from '~/generated-metadata/graphql';
import { useNavigateApp } from '~/hooks/useNavigateApp'; import { useNavigateApp } from '~/hooks/useNavigateApp';
export const useSeeWorkflowsNoSelectionRecordAction: ActionHookWithoutObjectMetadataItem = export const useSeeWorkflowsNoSelectionRecordAction: ActionHookWithoutObjectMetadataItem =
() => { () => {
const navigateApp = useNavigateApp(); const navigateApp = useNavigateApp();
const isWorkflowsEnabled = useIsFeatureEnabled(
FeatureFlagKey.IsWorkflowEnabled,
);
const shouldBeRegistered = isWorkflowsEnabled;
const onClick = () => { const onClick = () => {
navigateApp(AppPath.RecordIndexPage, { navigateApp(AppPath.RecordIndexPage, {
objectNamePlural: CoreObjectNamePlural.Workflow, objectNamePlural: CoreObjectNamePlural.Workflow,
@ -22,7 +14,6 @@ export const useSeeWorkflowsNoSelectionRecordAction: ActionHookWithoutObjectMeta
}; };
return { return {
shouldBeRegistered,
onClick, onClick,
}; };
}; };

View File

@ -4,7 +4,6 @@ export enum NoSelectionRecordActionKeys {
SEE_DELETED_RECORDS = 'see-deleted-records', SEE_DELETED_RECORDS = 'see-deleted-records',
HIDE_DELETED_RECORDS = 'hide-deleted-records', HIDE_DELETED_RECORDS = 'hide-deleted-records',
IMPORT_RECORDS = 'import-records', IMPORT_RECORDS = 'import-records',
GO_TO_RUNS = 'go-to-runs',
GO_TO_WORKFLOWS = 'go-to-workflows', GO_TO_WORKFLOWS = 'go-to-workflows',
GO_TO_PEOPLE = 'go-to-people', GO_TO_PEOPLE = 'go-to-people',
GO_TO_COMPANIES = 'go-to-companies', GO_TO_COMPANIES = 'go-to-companies',

View File

@ -0,0 +1,3 @@
export enum NoSelectionWorkflowRecordActionKeys {
GO_TO_RUNS = 'go-to-runs',
}

View File

@ -70,45 +70,12 @@ const wrapperConfigWithSelectedRecordNotAsFavorite: GetJestMetadataAndApolloMock
}, },
}; };
const wrapperWithSelectedRecordAsFavorite =
getJestMetadataAndApolloMocksAndActionMenuWrapper(
wrapperConfigWithSelectedRecordAsFavorite,
);
const wrapperWithSelectedRecordNotAsFavorite = const wrapperWithSelectedRecordNotAsFavorite =
getJestMetadataAndApolloMocksAndActionMenuWrapper( getJestMetadataAndApolloMocksAndActionMenuWrapper(
wrapperConfigWithSelectedRecordNotAsFavorite, wrapperConfigWithSelectedRecordNotAsFavorite,
); );
describe('useAddToFavoritesSingleRecordAction', () => { describe('useAddToFavoritesSingleRecordAction', () => {
it('should be registered when the record is not a favorite', () => {
const { result } = renderHook(
() =>
useAddToFavoritesSingleRecordAction({
objectMetadataItem: personMockObjectMetadataItem,
}),
{
wrapper: wrapperWithSelectedRecordNotAsFavorite,
},
);
expect(result.current.shouldBeRegistered).toBe(true);
});
it('should not be registered when the record is a favorite', () => {
const { result } = renderHook(
() =>
useAddToFavoritesSingleRecordAction({
objectMetadataItem: personMockObjectMetadataItem,
}),
{
wrapper: wrapperWithSelectedRecordAsFavorite,
},
);
expect(result.current.shouldBeRegistered).toBe(false);
});
it('should call createFavorite on click', () => { it('should call createFavorite on click', () => {
const { result } = renderHook( const { result } = renderHook(
() => () =>

View File

@ -61,60 +61,15 @@ const wrapperConfigWithSelectedRecordAsFavorite: GetJestMetadataAndApolloMocksAn
}, },
}; };
const wrapperConfigWithSelectedRecordNotAsFavorite: GetJestMetadataAndApolloMocksAndActionMenuWrapperProps =
{
...wrapperConfigWithSelectedRecordAsFavorite,
contextStoreTargetedRecordsRule: {
mode: 'selection',
selectedRecordIds: [peopleMock[1].id],
},
};
const wrapperWithSelectedRecordAsFavorite = const wrapperWithSelectedRecordAsFavorite =
getJestMetadataAndApolloMocksAndActionMenuWrapper( getJestMetadataAndApolloMocksAndActionMenuWrapper(
wrapperConfigWithSelectedRecordAsFavorite, wrapperConfigWithSelectedRecordAsFavorite,
); );
const wrapperWithSelectedRecordNotAsFavorite =
getJestMetadataAndApolloMocksAndActionMenuWrapper(
wrapperConfigWithSelectedRecordNotAsFavorite,
);
describe('useRemoveFromFavoritesSingleRecordAction', () => { describe('useRemoveFromFavoritesSingleRecordAction', () => {
it('should be registered when the record is a favorite', () => {
const { result } = renderHook(
() =>
useRemoveFromFavoritesSingleRecordAction({
objectMetadataItem: personMockObjectMetadataItem,
}),
{
wrapper: wrapperWithSelectedRecordAsFavorite,
},
);
expect(result.current.shouldBeRegistered).toBe(true);
});
it('should not be registered when the record is not a favorite', () => {
const { result } = renderHook(
() =>
useRemoveFromFavoritesSingleRecordAction({
objectMetadataItem: personMockObjectMetadataItem,
}),
{
wrapper: wrapperWithSelectedRecordNotAsFavorite,
},
);
expect(result.current.shouldBeRegistered).toBe(false);
});
it('should call deleteFavorite on click', () => { it('should call deleteFavorite on click', () => {
const { result } = renderHook( const { result } = renderHook(
() => () => useRemoveFromFavoritesSingleRecordAction(),
useRemoveFromFavoritesSingleRecordAction({
objectMetadataItem: personMockObjectMetadataItem,
}),
{ {
wrapper: wrapperWithSelectedRecordAsFavorite, wrapper: wrapperWithSelectedRecordAsFavorite,
}, },

View File

@ -1,9 +1,7 @@
import { useSelectedRecordIdOrThrow } from '@/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIdOrThrow'; import { useSelectedRecordIdOrThrow } from '@/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIdOrThrow';
import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/ActionHook'; import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/ActionHook';
import { useCreateFavorite } from '@/favorites/hooks/useCreateFavorite'; import { useCreateFavorite } from '@/favorites/hooks/useCreateFavorite';
import { useFavorites } from '@/favorites/hooks/useFavorites';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { isNull } from '@sniptt/guards';
import { useRecoilValue } from 'recoil'; import { useRecoilValue } from 'recoil';
import { isDefined } from 'twenty-shared/utils'; import { isDefined } from 'twenty-shared/utils';
@ -11,27 +9,12 @@ export const useAddToFavoritesSingleRecordAction: ActionHookWithObjectMetadataIt
({ objectMetadataItem }) => { ({ objectMetadataItem }) => {
const recordId = useSelectedRecordIdOrThrow(); const recordId = useSelectedRecordIdOrThrow();
const { sortedFavorites: favorites } = useFavorites();
const { createFavorite } = useCreateFavorite(); const { createFavorite } = useCreateFavorite();
const selectedRecord = useRecoilValue(recordStoreFamilyState(recordId)); const selectedRecord = useRecoilValue(recordStoreFamilyState(recordId));
const foundFavorite = favorites?.find(
(favorite) => favorite.recordId === recordId,
);
const isFavorite = !!foundFavorite;
const shouldBeRegistered =
isDefined(objectMetadataItem) &&
isDefined(selectedRecord) &&
!objectMetadataItem.isRemote &&
!isFavorite &&
isNull(selectedRecord.deletedAt);
const onClick = () => { const onClick = () => {
if (!shouldBeRegistered) { if (!isDefined(selectedRecord)) {
return; return;
} }
@ -39,7 +22,6 @@ export const useAddToFavoritesSingleRecordAction: ActionHookWithObjectMetadataIt
}; };
return { return {
shouldBeRegistered,
onClick, onClick,
}; };
}; };

View File

@ -3,14 +3,10 @@ import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/Ac
import { useDeleteFavorite } from '@/favorites/hooks/useDeleteFavorite'; import { useDeleteFavorite } from '@/favorites/hooks/useDeleteFavorite';
import { useFavorites } from '@/favorites/hooks/useFavorites'; import { useFavorites } from '@/favorites/hooks/useFavorites';
import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord'; import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
import { useHasObjectReadOnlyPermission } from '@/settings/roles/hooks/useHasObjectReadOnlyPermission';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal'; import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { t } from '@lingui/core/macro'; import { t } from '@lingui/core/macro';
import { isNull } from '@sniptt/guards';
import { useCallback, useState } from 'react'; import { useCallback, useState } from 'react';
import { useRecoilValue } from 'recoil';
import { isDefined } from 'twenty-shared/utils'; import { isDefined } from 'twenty-shared/utils';
export const useDeleteSingleRecordAction: ActionHookWithObjectMetadataItem = ({ export const useDeleteSingleRecordAction: ActionHookWithObjectMetadataItem = ({
@ -21,8 +17,6 @@ export const useDeleteSingleRecordAction: ActionHookWithObjectMetadataItem = ({
const [isDeleteRecordsModalOpen, setIsDeleteRecordsModalOpen] = const [isDeleteRecordsModalOpen, setIsDeleteRecordsModalOpen] =
useState(false); useState(false);
const hasObjectReadOnlyPermission = useHasObjectReadOnlyPermission();
const { resetTableRowSelection } = useRecordTable({ const { resetTableRowSelection } = useRecordTable({
recordTableId: objectMetadataItem.namePlural, recordTableId: objectMetadataItem.namePlural,
}); });
@ -31,8 +25,6 @@ export const useDeleteSingleRecordAction: ActionHookWithObjectMetadataItem = ({
objectNameSingular: objectMetadataItem.nameSingular, objectNameSingular: objectMetadataItem.nameSingular,
}); });
const selectedRecord = useRecoilValue(recordStoreFamilyState(recordId));
const { sortedFavorites: favorites } = useFavorites(); const { sortedFavorites: favorites } = useFavorites();
const { deleteFavorite } = useDeleteFavorite(); const { deleteFavorite } = useDeleteFavorite();
@ -56,23 +48,11 @@ export const useDeleteSingleRecordAction: ActionHookWithObjectMetadataItem = ({
recordId, recordId,
]); ]);
const isRemoteObject = objectMetadataItem.isRemote;
const shouldBeRegistered =
!isRemoteObject &&
isNull(selectedRecord?.deletedAt) &&
!hasObjectReadOnlyPermission;
const onClick = () => { const onClick = () => {
if (!shouldBeRegistered) {
return;
}
setIsDeleteRecordsModalOpen(true); setIsDeleteRecordsModalOpen(true);
}; };
return { return {
shouldBeRegistered,
onClick, onClick,
ConfirmationModal: ( ConfirmationModal: (
<ConfirmationModal <ConfirmationModal

View File

@ -1,15 +1,11 @@
import { useSelectedRecordIdOrThrow } from '@/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIdOrThrow'; import { useSelectedRecordIdOrThrow } from '@/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIdOrThrow';
import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/ActionHook'; import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/ActionHook';
import { useDestroyOneRecord } from '@/object-record/hooks/useDestroyOneRecord'; import { useDestroyOneRecord } from '@/object-record/hooks/useDestroyOneRecord';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
import { useHasObjectReadOnlyPermission } from '@/settings/roles/hooks/useHasObjectReadOnlyPermission';
import { AppPath } from '@/types/AppPath'; import { AppPath } from '@/types/AppPath';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal'; import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { useCallback, useState } from 'react'; import { useCallback, useState } from 'react';
import { useRecoilValue } from 'recoil';
import { useNavigateApp } from '~/hooks/useNavigateApp'; import { useNavigateApp } from '~/hooks/useNavigateApp';
import { isDefined } from 'twenty-shared/utils';
export const useDestroySingleRecordAction: ActionHookWithObjectMetadataItem = ({ export const useDestroySingleRecordAction: ActionHookWithObjectMetadataItem = ({
objectMetadataItem, objectMetadataItem,
@ -19,8 +15,6 @@ export const useDestroySingleRecordAction: ActionHookWithObjectMetadataItem = ({
const [isDestroyRecordsModalOpen, setIsDestroyRecordsModalOpen] = const [isDestroyRecordsModalOpen, setIsDestroyRecordsModalOpen] =
useState(false); useState(false);
const hasObjectReadOnlyPermission = useHasObjectReadOnlyPermission();
const navigateApp = useNavigateApp(); const navigateApp = useNavigateApp();
const { resetTableRowSelection } = useRecordTable({ const { resetTableRowSelection } = useRecordTable({
@ -31,8 +25,6 @@ export const useDestroySingleRecordAction: ActionHookWithObjectMetadataItem = ({
objectNameSingular: objectMetadataItem.nameSingular, objectNameSingular: objectMetadataItem.nameSingular,
}); });
const selectedRecord = useRecoilValue(recordStoreFamilyState(recordId));
const handleDeleteClick = useCallback(async () => { const handleDeleteClick = useCallback(async () => {
resetTableRowSelection(); resetTableRowSelection();
@ -48,23 +40,11 @@ export const useDestroySingleRecordAction: ActionHookWithObjectMetadataItem = ({
objectMetadataItem.namePlural, objectMetadataItem.namePlural,
]); ]);
const isRemoteObject = objectMetadataItem.isRemote;
const shouldBeRegistered =
!hasObjectReadOnlyPermission &&
!isRemoteObject &&
isDefined(selectedRecord?.deletedAt);
const onClick = () => { const onClick = () => {
if (!shouldBeRegistered) {
return;
}
setIsDestroyRecordsModalOpen(true); setIsDestroyRecordsModalOpen(true);
}; };
return { return {
shouldBeRegistered,
onClick, onClick,
ConfirmationModal: ( ConfirmationModal: (
<ConfirmationModal <ConfirmationModal

View File

@ -1,33 +1,19 @@
import { useSelectedRecordIdOrThrow } from '@/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIdOrThrow'; import { useSelectedRecordIdOrThrow } from '@/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIdOrThrow';
import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/ActionHook'; import { ActionHookWithoutObjectMetadataItem } from '@/action-menu/actions/types/ActionHook';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState'; import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { BlockNoteEditor } from '@blocknote/core'; import { BlockNoteEditor } from '@blocknote/core';
import { isNonEmptyString } from '@sniptt/guards';
import { useRecoilValue } from 'recoil'; import { useRecoilValue } from 'recoil';
import { isDefined } from 'twenty-shared/utils'; import { isDefined } from 'twenty-shared/utils';
export const useExportNoteAction: ActionHookWithObjectMetadataItem = ({ export const useExportNoteAction: ActionHookWithoutObjectMetadataItem = () => {
objectMetadataItem,
}) => {
const recordId = useSelectedRecordIdOrThrow(); const recordId = useSelectedRecordIdOrThrow();
const selectedRecord = useRecoilValue(recordStoreFamilyState(recordId)); const selectedRecord = useRecoilValue(recordStoreFamilyState(recordId));
const filename = `${(selectedRecord?.title || 'Untitled Note').replace(/[<>:"/\\|?*]/g, '-')}`; const filename = `${(selectedRecord?.title || 'Untitled Note').replace(/[<>:"/\\|?*]/g, '-')}`;
const isNoteOrTask =
objectMetadataItem?.nameSingular === CoreObjectNameSingular.Note ||
objectMetadataItem?.nameSingular === CoreObjectNameSingular.Task;
const shouldBeRegistered =
isDefined(objectMetadataItem) &&
isDefined(selectedRecord) &&
isNoteOrTask &&
isNonEmptyString(selectedRecord.bodyV2?.blocknote);
const onClick = async () => { const onClick = async () => {
if (!shouldBeRegistered || !selectedRecord.bodyV2.blocknote) { if (!isDefined(selectedRecord)) {
return; return;
} }
@ -65,7 +51,6 @@ export const useExportNoteAction: ActionHookWithObjectMetadataItem = ({
}; };
return { return {
shouldBeRegistered,
onClick, onClick,
}; };
}; };

View File

@ -1,22 +1,17 @@
import { useSelectedRecordIdOrThrow } from '@/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIdOrThrow'; import { useSelectedRecordIdOrThrow } from '@/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIdOrThrow';
import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/ActionHook'; import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/ActionHook';
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
import { useRecordShowPagePagination } from '@/object-record/record-show/hooks/useRecordShowPagePagination'; import { useRecordShowPagePagination } from '@/object-record/record-show/hooks/useRecordShowPagePagination';
import { useContext } from 'react';
export const useNavigateToNextRecordSingleRecordAction: ActionHookWithObjectMetadataItem = export const useNavigateToNextRecordSingleRecordAction: ActionHookWithObjectMetadataItem =
({ objectMetadataItem }) => { ({ objectMetadataItem }) => {
const recordId = useSelectedRecordIdOrThrow(); const recordId = useSelectedRecordIdOrThrow();
const { isInRightDrawer } = useContext(ActionMenuContext);
const { navigateToNextRecord } = useRecordShowPagePagination( const { navigateToNextRecord } = useRecordShowPagePagination(
objectMetadataItem.nameSingular, objectMetadataItem.nameSingular,
recordId, recordId,
); );
return { return {
shouldBeRegistered: !isInRightDrawer,
onClick: navigateToNextRecord, onClick: navigateToNextRecord,
}; };
}; };

View File

@ -1,22 +1,17 @@
import { useSelectedRecordIdOrThrow } from '@/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIdOrThrow'; import { useSelectedRecordIdOrThrow } from '@/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIdOrThrow';
import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/ActionHook'; import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/ActionHook';
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
import { useRecordShowPagePagination } from '@/object-record/record-show/hooks/useRecordShowPagePagination'; import { useRecordShowPagePagination } from '@/object-record/record-show/hooks/useRecordShowPagePagination';
import { useContext } from 'react';
export const useNavigateToPreviousRecordSingleRecordAction: ActionHookWithObjectMetadataItem = export const useNavigateToPreviousRecordSingleRecordAction: ActionHookWithObjectMetadataItem =
({ objectMetadataItem }) => { ({ objectMetadataItem }) => {
const recordId = useSelectedRecordIdOrThrow(); const recordId = useSelectedRecordIdOrThrow();
const { isInRightDrawer } = useContext(ActionMenuContext);
const { navigateToPreviousRecord } = useRecordShowPagePagination( const { navigateToPreviousRecord } = useRecordShowPagePagination(
objectMetadataItem.nameSingular, objectMetadataItem.nameSingular,
recordId, recordId,
); );
return { return {
shouldBeRegistered: !isInRightDrawer,
onClick: navigateToPreviousRecord, onClick: navigateToPreviousRecord,
}; };
}; };

View File

@ -1,11 +1,11 @@
import { useSelectedRecordIdOrThrow } from '@/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIdOrThrow'; import { useSelectedRecordIdOrThrow } from '@/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIdOrThrow';
import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/ActionHook'; import { ActionHookWithoutObjectMetadataItem } from '@/action-menu/actions/types/ActionHook';
import { useDeleteFavorite } from '@/favorites/hooks/useDeleteFavorite'; import { useDeleteFavorite } from '@/favorites/hooks/useDeleteFavorite';
import { useFavorites } from '@/favorites/hooks/useFavorites'; import { useFavorites } from '@/favorites/hooks/useFavorites';
import { isDefined } from 'twenty-shared/utils'; import { isDefined } from 'twenty-shared/utils';
export const useRemoveFromFavoritesSingleRecordAction: ActionHookWithObjectMetadataItem = export const useRemoveFromFavoritesSingleRecordAction: ActionHookWithoutObjectMetadataItem =
({ objectMetadataItem }) => { () => {
const recordId = useSelectedRecordIdOrThrow(); const recordId = useSelectedRecordIdOrThrow();
const { sortedFavorites: favorites } = useFavorites(); const { sortedFavorites: favorites } = useFavorites();
@ -16,15 +16,8 @@ export const useRemoveFromFavoritesSingleRecordAction: ActionHookWithObjectMetad
(favorite) => favorite.recordId === recordId, (favorite) => favorite.recordId === recordId,
); );
const isFavorite = !!foundFavorite;
const shouldBeRegistered =
isDefined(objectMetadataItem) &&
!objectMetadataItem.isRemote &&
isFavorite;
const onClick = () => { const onClick = () => {
if (!shouldBeRegistered) { if (!isDefined(foundFavorite)) {
return; return;
} }
@ -32,7 +25,6 @@ export const useRemoveFromFavoritesSingleRecordAction: ActionHookWithObjectMetad
}; };
return { return {
shouldBeRegistered,
onClick, onClick,
}; };
}; };

View File

@ -1,17 +1,9 @@
import { useSelectedRecordIdOrThrow } from '@/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIdOrThrow'; import { useSelectedRecordIdOrThrow } from '@/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIdOrThrow';
import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/ActionHook'; import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/ActionHook';
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
import { useRestoreManyRecords } from '@/object-record/hooks/useRestoreManyRecords'; import { useRestoreManyRecords } from '@/object-record/hooks/useRestoreManyRecords';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable'; import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
import { isSoftDeleteFilterActiveComponentState } from '@/object-record/record-table/states/isSoftDeleteFilterActiveComponentState';
import { useHasObjectReadOnlyPermission } from '@/settings/roles/hooks/useHasObjectReadOnlyPermission';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal'; import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useCallback, useState } from 'react'; import { useCallback, useState } from 'react';
import { useRecoilValue } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
export const useRestoreSingleRecordAction: ActionHookWithObjectMetadataItem = ({ export const useRestoreSingleRecordAction: ActionHookWithObjectMetadataItem = ({
objectMetadataItem, objectMetadataItem,
@ -21,8 +13,6 @@ export const useRestoreSingleRecordAction: ActionHookWithObjectMetadataItem = ({
const [isRestoreRecordModalOpen, setIsRestoreRecordModalOpen] = const [isRestoreRecordModalOpen, setIsRestoreRecordModalOpen] =
useState(false); useState(false);
const hasObjectReadOnlyPermission = useHasObjectReadOnlyPermission();
const { resetTableRowSelection } = useRecordTable({ const { resetTableRowSelection } = useRecordTable({
recordTableId: objectMetadataItem.namePlural, recordTableId: objectMetadataItem.namePlural,
}); });
@ -31,8 +21,6 @@ export const useRestoreSingleRecordAction: ActionHookWithObjectMetadataItem = ({
objectNameSingular: objectMetadataItem.nameSingular, objectNameSingular: objectMetadataItem.nameSingular,
}); });
const selectedRecord = useRecoilValue(recordStoreFamilyState(recordId));
const handleRestoreClick = useCallback(async () => { const handleRestoreClick = useCallback(async () => {
resetTableRowSelection(); resetTableRowSelection();
@ -41,27 +29,7 @@ export const useRestoreSingleRecordAction: ActionHookWithObjectMetadataItem = ({
}); });
}, [restoreManyRecords, resetTableRowSelection, recordId]); }, [restoreManyRecords, resetTableRowSelection, recordId]);
const isRemoteObject = objectMetadataItem.isRemote;
const isSoftDeleteFilterActive = useRecoilComponentValueV2(
isSoftDeleteFilterActiveComponentState,
);
const isShowPage =
useRecoilComponentValueV2(contextStoreCurrentViewTypeComponentState) ===
ContextStoreViewType.ShowPage;
const shouldBeRegistered =
!isRemoteObject &&
isDefined(selectedRecord?.deletedAt) &&
!hasObjectReadOnlyPermission &&
(isShowPage || isSoftDeleteFilterActive);
const onClick = () => { const onClick = () => {
if (!shouldBeRegistered) {
return;
}
setIsRestoreRecordModalOpen(true); setIsRestoreRecordModalOpen(true);
}; };
@ -70,7 +38,6 @@ export const useRestoreSingleRecordAction: ActionHookWithObjectMetadataItem = ({
}; };
return { return {
shouldBeRegistered,
onClick, onClick,
ConfirmationModal: ( ConfirmationModal: (
<ConfirmationModal <ConfirmationModal

View File

@ -51,51 +51,6 @@ const draftWorkflowMock = {
], ],
}; };
const activeWorkflowMock = {
...baseWorkflowMock,
currentVersion: {
...baseWorkflowMock.currentVersion,
status: 'ACTIVE',
},
versions: [
{
__typename: 'WorkflowVersion',
id: 'currentVersionId',
status: 'ACTIVE',
},
],
};
const noStepsWorkflowMock = {
...baseWorkflowMock,
currentVersion: {
...baseWorkflowMock.currentVersion,
steps: [],
},
versions: [
{
__typename: 'WorkflowVersion',
id: 'currentVersionId',
status: 'ACTIVE',
},
],
};
const noTriggerWorkflowMock = {
...baseWorkflowMock,
currentVersion: {
...baseWorkflowMock.currentVersion,
trigger: undefined,
},
versions: [
{
__typename: 'WorkflowVersion',
id: 'currentVersionId',
status: 'ACTIVE',
},
],
};
jest.mock('@/workflow/hooks/useWorkflowWithCurrentVersion', () => ({ jest.mock('@/workflow/hooks/useWorkflowWithCurrentVersion', () => ({
useWorkflowWithCurrentVersion: jest.fn(), useWorkflowWithCurrentVersion: jest.fn(),
})); }));
@ -138,66 +93,6 @@ describe('useActivateWorkflowSingleRecordAction', () => {
jest.clearAllMocks(); jest.clearAllMocks();
}); });
it('should be registered when workflow has trigger and steps and is not active', () => {
(useWorkflowWithCurrentVersion as jest.Mock).mockReturnValue(
draftWorkflowMock,
);
const { result } = renderHook(
() => useActivateWorkflowSingleRecordAction(),
{
wrapper: createWrapper(draftWorkflowMock),
},
);
expect(result.current.shouldBeRegistered).toBe(true);
});
it('should not be registered when workflow is already active', () => {
(useWorkflowWithCurrentVersion as jest.Mock).mockReturnValue(
activeWorkflowMock,
);
const { result } = renderHook(
() => useActivateWorkflowSingleRecordAction(),
{
wrapper: createWrapper(activeWorkflowMock),
},
);
expect(result.current.shouldBeRegistered).toBe(false);
});
it('should not be registered when workflow has no steps', () => {
(useWorkflowWithCurrentVersion as jest.Mock).mockReturnValue(
noStepsWorkflowMock,
);
const { result } = renderHook(
() => useActivateWorkflowSingleRecordAction(),
{
wrapper: createWrapper(noStepsWorkflowMock),
},
);
expect(result.current.shouldBeRegistered).toBe(false);
});
it('should not be registered when workflow has no trigger', () => {
(useWorkflowWithCurrentVersion as jest.Mock).mockReturnValue(
noTriggerWorkflowMock,
);
const { result } = renderHook(
() => useActivateWorkflowSingleRecordAction(),
{
wrapper: createWrapper(noTriggerWorkflowMock),
},
);
expect(result.current.shouldBeRegistered).toBe(false);
});
it('should call activateWorkflowVersion on click', () => { it('should call activateWorkflowVersion on click', () => {
(useWorkflowWithCurrentVersion as jest.Mock).mockReturnValue( (useWorkflowWithCurrentVersion as jest.Mock).mockReturnValue(
draftWorkflowMock, draftWorkflowMock,
@ -219,23 +114,4 @@ describe('useActivateWorkflowSingleRecordAction', () => {
workflowVersionId: draftWorkflowMock.currentVersion.id, workflowVersionId: draftWorkflowMock.currentVersion.id,
}); });
}); });
it('should not call activateWorkflowVersion when not registered', () => {
(useWorkflowWithCurrentVersion as jest.Mock).mockReturnValue(
activeWorkflowMock,
);
const { result } = renderHook(
() => useActivateWorkflowSingleRecordAction(),
{
wrapper: createWrapper(activeWorkflowMock),
},
);
act(() => {
result.current.onClick();
});
expect(activateWorkflowVersionMock).not.toHaveBeenCalled();
});
}); });

View File

@ -37,24 +37,6 @@ const activeWorkflowMock = {
}, },
}; };
const deactivatedWorkflowMock = {
__typename: 'Workflow',
id: 'workflowId',
lastPublishedVersionId: 'lastPublishedVersionId',
currentVersion: {
__typename: 'WorkflowVersion',
id: 'currentVersionId',
trigger: 'trigger',
status: 'DEACTIVATED',
steps: [
{
__typename: 'WorkflowStep',
id: 'stepId1',
},
],
},
};
jest.mock('@/workflow/hooks/useWorkflowWithCurrentVersion', () => ({ jest.mock('@/workflow/hooks/useWorkflowWithCurrentVersion', () => ({
useWorkflowWithCurrentVersion: jest.fn(), useWorkflowWithCurrentVersion: jest.fn(),
})); }));
@ -90,61 +72,11 @@ const activeWorkflowWrapper = getJestMetadataAndApolloMocksAndActionMenuWrapper(
}, },
); );
const deactivatedWorkflowWrapper =
getJestMetadataAndApolloMocksAndActionMenuWrapper({
apolloMocks: [],
componentInstanceId: '1',
contextStoreCurrentObjectMetadataNameSingular:
workflowMockObjectMetadataItem.nameSingular,
contextStoreTargetedRecordsRule: {
mode: 'selection',
selectedRecordIds: [deactivatedWorkflowMock.id],
},
onInitializeRecoilSnapshot: (snapshot) => {
snapshot.set(
recordStoreFamilyState(deactivatedWorkflowMock.id),
deactivatedWorkflowMock,
);
snapshot.set(currentWorkspaceState, {
...mockCurrentWorkspace,
featureFlags: [mockedWorkflowEnabledFeatureFlag],
});
},
});
describe('useDeactivateWorkflowSingleRecordAction', () => { describe('useDeactivateWorkflowSingleRecordAction', () => {
beforeEach(() => { beforeEach(() => {
jest.clearAllMocks(); jest.clearAllMocks();
}); });
it('should not be registered when the workflow is deactivated', () => {
(useWorkflowWithCurrentVersion as jest.Mock).mockImplementation(
() => deactivatedWorkflowMock,
);
const { result } = renderHook(
() => useDeactivateWorkflowSingleRecordAction(),
{
wrapper: deactivatedWorkflowWrapper,
},
);
expect(result.current.shouldBeRegistered).toBe(false);
});
it('should be registered when the workflow is active', () => {
(useWorkflowWithCurrentVersion as jest.Mock).mockImplementation(
() => activeWorkflowMock,
);
const { result } = renderHook(
() => useDeactivateWorkflowSingleRecordAction(),
{
wrapper: activeWorkflowWrapper,
},
);
expect(result.current.shouldBeRegistered).toBe(true);
});
it('should call deactivateWorkflowVersion on click', () => { it('should call deactivateWorkflowVersion on click', () => {
(useWorkflowWithCurrentVersion as jest.Mock).mockImplementation( (useWorkflowWithCurrentVersion as jest.Mock).mockImplementation(
() => activeWorkflowMock, () => activeWorkflowMock,

View File

@ -20,50 +20,6 @@ const mockedWorkflowEnabledFeatureFlag = {
workspaceId: '1', workspaceId: '1',
}; };
const noDraftWorkflowMock = {
__typename: 'Workflow',
id: 'workflowId',
lastPublishedVersionId: 'lastPublishedVersionId',
currentVersion: {
__typename: 'WorkflowVersion',
id: 'currentVersionId',
trigger: 'trigger',
status: 'ACTIVE',
steps: [
{
__typename: 'WorkflowStep',
id: 'stepId1',
},
],
},
versions: [
{
__typename: 'WorkflowVersion',
id: 'currentVersionId',
trigger: 'trigger',
status: 'ACTIVE',
steps: [
{
__typename: 'WorkflowStep',
id: 'stepId1',
},
],
},
{
__typename: 'WorkflowVersion',
id: 'versionId2',
trigger: 'trigger',
status: 'ACTIVE',
steps: [
{
__typename: 'WorkflowStep',
id: 'stepId2',
},
],
},
],
};
const draftWorkflowMock = { const draftWorkflowMock = {
__typename: 'Workflow', __typename: 'Workflow',
id: 'workflowId', id: 'workflowId',
@ -108,11 +64,6 @@ const draftWorkflowMock = {
], ],
}; };
const draftWorkflowMockWithOneVersion = {
...draftWorkflowMock,
versions: [draftWorkflowMock.currentVersion],
};
jest.mock('@/workflow/hooks/useWorkflowWithCurrentVersion', () => ({ jest.mock('@/workflow/hooks/useWorkflowWithCurrentVersion', () => ({
useWorkflowWithCurrentVersion: jest.fn(), useWorkflowWithCurrentVersion: jest.fn(),
})); }));
@ -125,28 +76,6 @@ jest.mock('@/workflow/hooks/useDeleteOneWorkflowVersion', () => ({
}), }),
})); }));
const noDraftWorkflowWrapper =
getJestMetadataAndApolloMocksAndActionMenuWrapper({
apolloMocks: [],
componentInstanceId: '1',
contextStoreCurrentObjectMetadataNameSingular:
workflowMockObjectMetadataItem.nameSingular,
contextStoreTargetedRecordsRule: {
mode: 'selection',
selectedRecordIds: [noDraftWorkflowMock.id],
},
onInitializeRecoilSnapshot: (snapshot) => {
snapshot.set(
recordStoreFamilyState(noDraftWorkflowMock.id),
noDraftWorkflowMock,
);
snapshot.set(currentWorkspaceState, {
...mockCurrentWorkspace,
featureFlags: [mockedWorkflowEnabledFeatureFlag],
});
},
});
const draftWorkflowWrapper = getJestMetadataAndApolloMocksAndActionMenuWrapper({ const draftWorkflowWrapper = getJestMetadataAndApolloMocksAndActionMenuWrapper({
apolloMocks: [], apolloMocks: [],
componentInstanceId: '1', componentInstanceId: '1',
@ -168,76 +97,11 @@ const draftWorkflowWrapper = getJestMetadataAndApolloMocksAndActionMenuWrapper({
}, },
}); });
const draftWorkflowWithOneVersionWrapper =
getJestMetadataAndApolloMocksAndActionMenuWrapper({
apolloMocks: [],
componentInstanceId: '1',
contextStoreCurrentObjectMetadataNameSingular:
workflowMockObjectMetadataItem.nameSingular,
contextStoreTargetedRecordsRule: {
mode: 'selection',
selectedRecordIds: [draftWorkflowMockWithOneVersion.id],
},
onInitializeRecoilSnapshot: (snapshot) => {
snapshot.set(
recordStoreFamilyState(draftWorkflowMockWithOneVersion.id),
draftWorkflowMockWithOneVersion,
);
snapshot.set(currentWorkspaceState, {
...mockCurrentWorkspace,
featureFlags: [mockedWorkflowEnabledFeatureFlag],
});
},
});
describe('useDiscardDraftWorkflowSingleRecordAction', () => { describe('useDiscardDraftWorkflowSingleRecordAction', () => {
beforeEach(() => { beforeEach(() => {
jest.clearAllMocks(); jest.clearAllMocks();
}); });
it('should not be registered when there is no draft', () => {
(useWorkflowWithCurrentVersion as jest.Mock).mockImplementation(
() => noDraftWorkflowMock,
);
const { result } = renderHook(
() => useDiscardDraftWorkflowSingleRecordAction(),
{
wrapper: noDraftWorkflowWrapper,
},
);
expect(result.current.shouldBeRegistered).toBe(false);
});
it('should not be registered when there is only one version', () => {
(useWorkflowWithCurrentVersion as jest.Mock).mockImplementation(
() => draftWorkflowMockWithOneVersion,
);
const { result } = renderHook(
() => useDiscardDraftWorkflowSingleRecordAction(),
{
wrapper: draftWorkflowWithOneVersionWrapper,
},
);
expect(result.current.shouldBeRegistered).toBe(false);
});
it('should be registered when the workflow is draft', () => {
(useWorkflowWithCurrentVersion as jest.Mock).mockImplementation(
() => draftWorkflowMock,
);
const { result } = renderHook(
() => useDiscardDraftWorkflowSingleRecordAction(),
{
wrapper: draftWorkflowWrapper,
},
);
expect(result.current.shouldBeRegistered).toBe(true);
});
it('should call deleteOneWorkflowVersion on click', () => { it('should call deleteOneWorkflowVersion on click', () => {
(useWorkflowWithCurrentVersion as jest.Mock).mockImplementation( (useWorkflowWithCurrentVersion as jest.Mock).mockImplementation(
() => draftWorkflowMock, () => draftWorkflowMock,

View File

@ -12,17 +12,8 @@ export const useActivateWorkflowSingleRecordAction: ActionHookWithoutObjectMetad
const workflowWithCurrentVersion = useWorkflowWithCurrentVersion(recordId); const workflowWithCurrentVersion = useWorkflowWithCurrentVersion(recordId);
const shouldBeRegistered =
isDefined(workflowWithCurrentVersion?.currentVersion?.trigger) &&
isDefined(workflowWithCurrentVersion.currentVersion?.steps) &&
workflowWithCurrentVersion.currentVersion.steps.length > 0 &&
(workflowWithCurrentVersion.currentVersion.status === 'DRAFT' ||
!workflowWithCurrentVersion.versions?.some(
(version) => version.status === 'ACTIVE',
));
const onClick = () => { const onClick = () => {
if (!shouldBeRegistered) { if (!isDefined(workflowWithCurrentVersion)) {
return; return;
} }
@ -33,7 +24,6 @@ export const useActivateWorkflowSingleRecordAction: ActionHookWithoutObjectMetad
}; };
return { return {
shouldBeRegistered,
onClick, onClick,
}; };
}; };

View File

@ -12,12 +12,8 @@ export const useDeactivateWorkflowSingleRecordAction: ActionHookWithoutObjectMet
const workflowWithCurrentVersion = useWorkflowWithCurrentVersion(recordId); const workflowWithCurrentVersion = useWorkflowWithCurrentVersion(recordId);
const shouldBeRegistered =
isDefined(workflowWithCurrentVersion) &&
workflowWithCurrentVersion.currentVersion.status === 'ACTIVE';
const onClick = () => { const onClick = () => {
if (!shouldBeRegistered) { if (!isDefined(workflowWithCurrentVersion)) {
return; return;
} }
@ -27,7 +23,6 @@ export const useDeactivateWorkflowSingleRecordAction: ActionHookWithoutObjectMet
}; };
return { return {
shouldBeRegistered,
onClick, onClick,
}; };
}; };

View File

@ -12,13 +12,8 @@ export const useDiscardDraftWorkflowSingleRecordAction: ActionHookWithoutObjectM
const workflowWithCurrentVersion = useWorkflowWithCurrentVersion(recordId); const workflowWithCurrentVersion = useWorkflowWithCurrentVersion(recordId);
const shouldBeRegistered =
isDefined(workflowWithCurrentVersion) &&
workflowWithCurrentVersion.versions.length > 1 &&
workflowWithCurrentVersion.currentVersion.status === 'DRAFT';
const onClick = () => { const onClick = () => {
if (!shouldBeRegistered) { if (!isDefined(workflowWithCurrentVersion)) {
return; return;
} }
@ -28,7 +23,6 @@ export const useDiscardDraftWorkflowSingleRecordAction: ActionHookWithoutObjectM
}; };
return { return {
shouldBeRegistered,
onClick, onClick,
}; };
}; };

View File

@ -3,26 +3,19 @@ import { ActionHookWithoutObjectMetadataItem } from '@/action-menu/actions/types
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular'; import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { AppPath } from '@/types/AppPath'; import { AppPath } from '@/types/AppPath';
import { useActiveWorkflowVersion } from '@/workflow/hooks/useActiveWorkflowVersion'; import { useActiveWorkflowVersion } from '@/workflow/hooks/useActiveWorkflowVersion';
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
import { useNavigateApp } from '~/hooks/useNavigateApp';
import { isDefined } from 'twenty-shared/utils'; import { isDefined } from 'twenty-shared/utils';
import { useNavigateApp } from '~/hooks/useNavigateApp';
export const useSeeActiveVersionWorkflowSingleRecordAction: ActionHookWithoutObjectMetadataItem = export const useSeeActiveVersionWorkflowSingleRecordAction: ActionHookWithoutObjectMetadataItem =
() => { () => {
const recordId = useSelectedRecordIdOrThrow(); const recordId = useSelectedRecordIdOrThrow();
const workflow = useWorkflowWithCurrentVersion(recordId);
const isDraft = workflow?.statuses?.includes('DRAFT') || false;
const workflowActiveVersion = useActiveWorkflowVersion(recordId); const workflowActiveVersion = useActiveWorkflowVersion(recordId);
const navigateApp = useNavigateApp(); const navigateApp = useNavigateApp();
const shouldBeRegistered = isDefined(workflowActiveVersion) && isDraft;
const onClick = () => { const onClick = () => {
if (!shouldBeRegistered) { if (!isDefined(workflowActiveVersion)) {
return; return;
} }
@ -33,7 +26,6 @@ export const useSeeActiveVersionWorkflowSingleRecordAction: ActionHookWithoutObj
}; };
return { return {
shouldBeRegistered,
onClick, onClick,
}; };
}; };

View File

@ -4,8 +4,8 @@ import { CoreObjectNamePlural } from '@/object-metadata/types/CoreObjectNamePlur
import { AppPath } from '@/types/AppPath'; import { AppPath } from '@/types/AppPath';
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
import { useNavigateApp } from '~/hooks/useNavigateApp';
import { isDefined } from 'twenty-shared/utils'; import { isDefined } from 'twenty-shared/utils';
import { useNavigateApp } from '~/hooks/useNavigateApp';
export const useSeeRunsWorkflowSingleRecordAction: ActionHookWithoutObjectMetadataItem = export const useSeeRunsWorkflowSingleRecordAction: ActionHookWithoutObjectMetadataItem =
() => { () => {
@ -15,10 +15,8 @@ export const useSeeRunsWorkflowSingleRecordAction: ActionHookWithoutObjectMetada
const navigateApp = useNavigateApp(); const navigateApp = useNavigateApp();
const shouldBeRegistered = isDefined(workflowWithCurrentVersion);
const onClick = () => { const onClick = () => {
if (!shouldBeRegistered) { if (!isDefined(workflowWithCurrentVersion)) {
return; return;
} }
@ -40,7 +38,6 @@ export const useSeeRunsWorkflowSingleRecordAction: ActionHookWithoutObjectMetada
}; };
return { return {
shouldBeRegistered,
onClick, onClick,
}; };
}; };

View File

@ -4,8 +4,8 @@ import { CoreObjectNamePlural } from '@/object-metadata/types/CoreObjectNamePlur
import { AppPath } from '@/types/AppPath'; import { AppPath } from '@/types/AppPath';
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
import { useNavigateApp } from '~/hooks/useNavigateApp';
import { isDefined } from 'twenty-shared/utils'; import { isDefined } from 'twenty-shared/utils';
import { useNavigateApp } from '~/hooks/useNavigateApp';
export const useSeeVersionsWorkflowSingleRecordAction: ActionHookWithoutObjectMetadataItem = export const useSeeVersionsWorkflowSingleRecordAction: ActionHookWithoutObjectMetadataItem =
() => { () => {
@ -15,10 +15,10 @@ export const useSeeVersionsWorkflowSingleRecordAction: ActionHookWithoutObjectMe
const navigateApp = useNavigateApp(); const navigateApp = useNavigateApp();
const shouldBeRegistered = isDefined(workflowWithCurrentVersion);
const onClick = () => { const onClick = () => {
if (!shouldBeRegistered) return; if (!isDefined(workflowWithCurrentVersion)) {
return;
}
navigateApp( navigateApp(
AppPath.RecordIndexPage, AppPath.RecordIndexPage,
@ -38,7 +38,6 @@ export const useSeeVersionsWorkflowSingleRecordAction: ActionHookWithoutObjectMe
}; };
return { return {
shouldBeRegistered,
onClick, onClick,
}; };
}; };

View File

@ -12,16 +12,8 @@ export const useTestWorkflowSingleRecordAction: ActionHookWithoutObjectMetadataI
const { runWorkflowVersion } = useRunWorkflowVersion(); const { runWorkflowVersion } = useRunWorkflowVersion();
const shouldBeRegistered =
isDefined(workflowWithCurrentVersion?.currentVersion?.trigger) &&
((workflowWithCurrentVersion.currentVersion.trigger.type === 'MANUAL' &&
!isDefined(
workflowWithCurrentVersion.currentVersion.trigger.settings.objectType,
)) ||
workflowWithCurrentVersion.currentVersion.trigger.type === 'WEBHOOK');
const onClick = () => { const onClick = () => {
if (!shouldBeRegistered) { if (!isDefined(workflowWithCurrentVersion)) {
return; return;
} }
@ -31,7 +23,6 @@ export const useTestWorkflowSingleRecordAction: ActionHookWithoutObjectMetadataI
}; };
return { return {
shouldBeRegistered,
onClick, onClick,
}; };
}; };

View File

@ -15,10 +15,13 @@ export const useSeeVersionWorkflowRunSingleRecordAction: ActionHookWithoutObject
const navigateApp = useNavigateApp(); const navigateApp = useNavigateApp();
const shouldBeRegistered = isDefined(workflowRun?.workflowVersion?.id);
const onClick = () => { const onClick = () => {
if (!shouldBeRegistered || !workflowRun?.workflowVersion?.id) return; if (
!isDefined(workflowRun) ||
!isDefined(workflowRun?.workflowVersion?.id)
) {
return;
}
navigateApp(AppPath.RecordShowPage, { navigateApp(AppPath.RecordShowPage, {
objectNameSingular: CoreObjectNameSingular.WorkflowVersion, objectNameSingular: CoreObjectNameSingular.WorkflowVersion,
@ -27,7 +30,6 @@ export const useSeeVersionWorkflowRunSingleRecordAction: ActionHookWithoutObject
}; };
return { return {
shouldBeRegistered,
onClick, onClick,
}; };
}; };

View File

@ -15,10 +15,10 @@ export const useSeeWorkflowWorkflowRunSingleRecordAction: ActionHookWithoutObjec
const navigateApp = useNavigateApp(); const navigateApp = useNavigateApp();
const shouldBeRegistered = isDefined(workflowRun?.workflow?.id);
const onClick = () => { const onClick = () => {
if (!shouldBeRegistered || !workflowRun?.workflow?.id) return; if (!isDefined(workflowRun) || !isDefined(workflowRun?.workflow?.id)) {
return;
}
navigateApp(AppPath.RecordShowPage, { navigateApp(AppPath.RecordShowPage, {
objectNameSingular: CoreObjectNameSingular.Workflow, objectNameSingular: CoreObjectNameSingular.Workflow,
@ -27,7 +27,6 @@ export const useSeeWorkflowWorkflowRunSingleRecordAction: ActionHookWithoutObjec
}; };
return { return {
shouldBeRegistered,
onClick, onClick,
}; };
}; };

View File

@ -6,8 +6,8 @@ import { AppPath } from '@/types/AppPath';
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
import { useRecoilValue } from 'recoil'; import { useRecoilValue } from 'recoil';
import { useNavigateApp } from '~/hooks/useNavigateApp';
import { isDefined } from 'twenty-shared/utils'; import { isDefined } from 'twenty-shared/utils';
import { useNavigateApp } from '~/hooks/useNavigateApp';
export const useSeeRunsWorkflowVersionSingleRecordAction: ActionHookWithoutObjectMetadataItem = export const useSeeRunsWorkflowVersionSingleRecordAction: ActionHookWithoutObjectMetadataItem =
() => { () => {
@ -21,10 +21,10 @@ export const useSeeRunsWorkflowVersionSingleRecordAction: ActionHookWithoutObjec
const navigateApp = useNavigateApp(); const navigateApp = useNavigateApp();
const shouldBeRegistered = isDefined(workflowWithCurrentVersion);
const onClick = () => { const onClick = () => {
if (!shouldBeRegistered) return; if (!isDefined(workflowWithCurrentVersion)) {
return;
}
navigateApp( navigateApp(
AppPath.RecordIndexPage, AppPath.RecordIndexPage,
@ -49,7 +49,6 @@ export const useSeeRunsWorkflowVersionSingleRecordAction: ActionHookWithoutObjec
}; };
return { return {
shouldBeRegistered,
onClick, onClick,
}; };
}; };

View File

@ -6,8 +6,8 @@ import { AppPath } from '@/types/AppPath';
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand'; import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
import { useRecoilValue } from 'recoil'; import { useRecoilValue } from 'recoil';
import { useNavigateApp } from '~/hooks/useNavigateApp';
import { isDefined } from 'twenty-shared/utils'; import { isDefined } from 'twenty-shared/utils';
import { useNavigateApp } from '~/hooks/useNavigateApp';
export const useSeeVersionsWorkflowVersionSingleRecordAction: ActionHookWithoutObjectMetadataItem = export const useSeeVersionsWorkflowVersionSingleRecordAction: ActionHookWithoutObjectMetadataItem =
() => { () => {
@ -21,10 +21,10 @@ export const useSeeVersionsWorkflowVersionSingleRecordAction: ActionHookWithoutO
const navigateApp = useNavigateApp(); const navigateApp = useNavigateApp();
const shouldBeRegistered = isDefined(workflowWithCurrentVersion);
const onClick = () => { const onClick = () => {
if (!shouldBeRegistered) return; if (!isDefined(workflowWithCurrentVersion)) {
return;
}
navigateApp( navigateApp(
AppPath.RecordIndexPage, AppPath.RecordIndexPage,
@ -44,7 +44,6 @@ export const useSeeVersionsWorkflowVersionSingleRecordAction: ActionHookWithoutO
}; };
return { return {
shouldBeRegistered,
onClick, onClick,
}; };
}; };

View File

@ -15,10 +15,13 @@ export const useSeeWorkflowWorkflowVersionSingleRecordAction: ActionHookWithoutO
const navigateApp = useNavigateApp(); const navigateApp = useNavigateApp();
const shouldBeRegistered = isDefined(workflowVersion?.workflow?.id);
const onClick = () => { const onClick = () => {
if (!shouldBeRegistered || !workflowVersion?.workflow?.id) return; if (
!isDefined(workflowVersion) ||
!isDefined(workflowVersion?.workflow?.id)
) {
return;
}
navigateApp(AppPath.RecordShowPage, { navigateApp(AppPath.RecordShowPage, {
objectNameSingular: CoreObjectNameSingular.Workflow, objectNameSingular: CoreObjectNameSingular.Workflow,
@ -27,7 +30,6 @@ export const useSeeWorkflowWorkflowVersionSingleRecordAction: ActionHookWithoutO
}; };
return { return {
shouldBeRegistered,
onClick, onClick,
}; };
}; };

View File

@ -8,8 +8,8 @@ import { useWorkflowVersion } from '@/workflow/hooks/useWorkflowVersion';
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion'; import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
import { openOverrideWorkflowDraftConfirmationModalState } from '@/workflow/states/openOverrideWorkflowDraftConfirmationModalState'; import { openOverrideWorkflowDraftConfirmationModalState } from '@/workflow/states/openOverrideWorkflowDraftConfirmationModalState';
import { useSetRecoilState } from 'recoil'; import { useSetRecoilState } from 'recoil';
import { useNavigateApp } from '~/hooks/useNavigateApp';
import { isDefined } from 'twenty-shared/utils'; import { isDefined } from 'twenty-shared/utils';
import { useNavigateApp } from '~/hooks/useNavigateApp';
export const useUseAsDraftWorkflowVersionSingleRecordAction: ActionHookWithoutObjectMetadataItem = export const useUseAsDraftWorkflowVersionSingleRecordAction: ActionHookWithoutObjectMetadataItem =
() => { () => {
@ -33,13 +33,10 @@ export const useUseAsDraftWorkflowVersionSingleRecordAction: ActionHookWithoutOb
const hasAlreadyDraftVersion = const hasAlreadyDraftVersion =
workflow?.versions.some((version) => version.status === 'DRAFT') || false; workflow?.versions.some((version) => version.status === 'DRAFT') || false;
const shouldBeRegistered =
isDefined(workflowVersion) &&
isDefined(workflow) &&
workflowVersion.status !== 'DRAFT';
const onClick = async () => { const onClick = async () => {
if (!shouldBeRegistered) return; if (!isDefined(workflowVersion) || !isDefined(workflow)) {
return;
}
if (hasAlreadyDraftVersion) { if (hasAlreadyDraftVersion) {
setOpenOverrideWorkflowDraftConfirmationModal(true); setOpenOverrideWorkflowDraftConfirmationModal(true);
@ -55,7 +52,7 @@ export const useUseAsDraftWorkflowVersionSingleRecordAction: ActionHookWithoutOb
} }
}; };
const ConfirmationModal = shouldBeRegistered ? ( const ConfirmationModal = isDefined(workflowVersion) ? (
<OverrideWorkflowDraftConfirmationModal <OverrideWorkflowDraftConfirmationModal
workflowId={workflowVersion.workflow.id} workflowId={workflowVersion.workflow.id}
workflowVersionIdToCopy={workflowVersion.id} workflowVersionIdToCopy={workflowVersion.id}
@ -63,7 +60,6 @@ export const useUseAsDraftWorkflowVersionSingleRecordAction: ActionHookWithoutOb
) : undefined; ) : undefined;
return { return {
shouldBeRegistered,
onClick, onClick,
ConfirmationModal, ConfirmationModal,
}; };

View File

@ -0,0 +1,31 @@
import { DEFAULT_RECORD_ACTIONS_CONFIG } from '@/action-menu/actions/record-actions/constants/DefaultRecordActionsConfig';
import { DefaultRecordActionConfigKeys } from '@/action-menu/actions/types/DefaultRecordActionConfigKeys';
import { RecordConfigAction } from '@/action-menu/actions/types/RecordConfigAction';
export const inheritActionsFromDefaultConfig = ({
config,
actionKeys,
propertiesToOverwrite,
}: {
config: Record<string, RecordConfigAction>;
actionKeys: DefaultRecordActionConfigKeys[];
propertiesToOverwrite: Partial<
Record<DefaultRecordActionConfigKeys, Partial<RecordConfigAction>>
>;
}): Record<string, RecordConfigAction> => {
const actionsFromDefaultConfig = actionKeys.reduce(
(acc, key) => ({
...acc,
[key]: {
...DEFAULT_RECORD_ACTIONS_CONFIG[key],
...propertiesToOverwrite[key],
},
}),
{} as Record<string, RecordConfigAction>,
);
return {
...actionsFromDefaultConfig,
...config,
};
};

View File

@ -1,20 +1,19 @@
import { ActionHookWithoutObjectMetadataItem } from '@/action-menu/actions/types/ActionHook'; import { RecordAgnosticConfigAction } from '@/action-menu/actions/types/RecordAgnosticConfigAction';
import { wrapActionInCallbacks } from '@/action-menu/actions/utils/wrapActionInCallbacks'; import { wrapActionInCallbacks } from '@/action-menu/actions/utils/wrapActionInCallbacks';
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext'; import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries'; import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries';
import { ActionMenuEntry } from '@/action-menu/types/ActionMenuEntry';
import { useContext, useEffect } from 'react'; import { useContext, useEffect } from 'react';
type RegisterAgnosticRecordActionEffectProps = { type RegisterAgnosticRecordActionEffectProps = {
action: ActionMenuEntry & { action: RecordAgnosticConfigAction;
useAction: ActionHookWithoutObjectMetadataItem;
};
}; };
export const RegisterAgnosticRecordActionEffect = ({ export const RegisterAgnosticRecordActionEffect = ({
action, action,
}: RegisterAgnosticRecordActionEffectProps) => { }: RegisterAgnosticRecordActionEffectProps) => {
const { shouldBeRegistered, onClick, ConfirmationModal } = action.useAction(); const { onClick, ConfirmationModal } = action.useAction();
const shouldBeRegistered = action.shouldBeRegistered({});
const { onActionStartedCallback, onActionExecutedCallback } = const { onActionStartedCallback, onActionExecutedCallback } =
useContext(ActionMenuContext); useContext(ActionMenuContext);

View File

@ -1,9 +1,8 @@
import { useSearchRecordsRecordAgnosticAction } from '@/action-menu/actions/record-agnostic-actions/hooks/useSearchRecordsRecordAgnosticAction'; import { useSearchRecordsRecordAgnosticAction } from '@/action-menu/actions/record-agnostic-actions/hooks/useSearchRecordsRecordAgnosticAction';
import { RecordAgnosticActionsKey } from '@/action-menu/actions/record-agnostic-actions/types/RecordAgnosticActionsKey'; import { RecordAgnosticActionsKeys } from '@/action-menu/actions/record-agnostic-actions/types/RecordAgnosticActionsKeys';
import { ActionHookWithoutObjectMetadataItem } from '@/action-menu/actions/types/ActionHook';
import { ActionViewType } from '@/action-menu/actions/types/ActionViewType'; import { ActionViewType } from '@/action-menu/actions/types/ActionViewType';
import { RecordAgnosticConfigAction } from '@/action-menu/actions/types/RecordAgnosticConfigAction';
import { import {
ActionMenuEntry,
ActionMenuEntryScope, ActionMenuEntryScope,
ActionMenuEntryType, ActionMenuEntryType,
} from '@/action-menu/types/ActionMenuEntry'; } from '@/action-menu/types/ActionMenuEntry';
@ -12,14 +11,12 @@ import { IconSearch } from 'twenty-ui';
export const RECORD_AGNOSTIC_ACTIONS_CONFIG: Record< export const RECORD_AGNOSTIC_ACTIONS_CONFIG: Record<
string, string,
ActionMenuEntry & { RecordAgnosticConfigAction
useAction: ActionHookWithoutObjectMetadataItem;
}
> = { > = {
searchRecords: { [RecordAgnosticActionsKeys.SEARCH_RECORDS]: {
type: ActionMenuEntryType.Standard, type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.Global, scope: ActionMenuEntryScope.Global,
key: RecordAgnosticActionsKey.SEARCH_RECORDS, key: RecordAgnosticActionsKeys.SEARCH_RECORDS,
label: msg`Search records`, label: msg`Search records`,
shortLabel: msg`Search`, shortLabel: msg`Search`,
position: 0, position: 0,
@ -28,11 +25,12 @@ export const RECORD_AGNOSTIC_ACTIONS_CONFIG: Record<
availableOn: [ActionViewType.GLOBAL], availableOn: [ActionViewType.GLOBAL],
useAction: useSearchRecordsRecordAgnosticAction, useAction: useSearchRecordsRecordAgnosticAction,
hotKeys: ['/'], hotKeys: ['/'],
shouldBeRegistered: () => true,
}, },
searchRecordsFallback: { [RecordAgnosticActionsKeys.SEARCH_RECORDS_FALLBACK]: {
type: ActionMenuEntryType.Fallback, type: ActionMenuEntryType.Fallback,
scope: ActionMenuEntryScope.Global, scope: ActionMenuEntryScope.Global,
key: RecordAgnosticActionsKey.SEARCH_RECORDS_FALLBACK, key: RecordAgnosticActionsKeys.SEARCH_RECORDS_FALLBACK,
label: msg`Search records`, label: msg`Search records`,
shortLabel: msg`Search`, shortLabel: msg`Search`,
position: 1, position: 1,
@ -41,5 +39,6 @@ export const RECORD_AGNOSTIC_ACTIONS_CONFIG: Record<
availableOn: [ActionViewType.GLOBAL], availableOn: [ActionViewType.GLOBAL],
useAction: useSearchRecordsRecordAgnosticAction, useAction: useSearchRecordsRecordAgnosticAction,
hotKeys: ['/'], hotKeys: ['/'],
shouldBeRegistered: () => true,
}, },
}; };

View File

@ -15,6 +15,5 @@ export const useSearchRecordsRecordAgnosticAction = () => {
return { return {
onClick, onClick,
shouldBeRegistered: true,
}; };
}; };

View File

@ -6,9 +6,9 @@ import { useActiveWorkflowVersionsWithManualTrigger } from '@/workflow/hooks/use
import { useRunWorkflowVersion } from '@/workflow/hooks/useRunWorkflowVersion'; import { useRunWorkflowVersion } from '@/workflow/hooks/useRunWorkflowVersion';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { msg } from '@lingui/core/macro'; import { msg } from '@lingui/core/macro';
import { capitalize, isDefined } from 'twenty-shared/utils';
import { IconSettingsAutomation } from 'twenty-ui'; import { IconSettingsAutomation } from 'twenty-ui';
import { FeatureFlagKey } from '~/generated/graphql'; import { FeatureFlagKey } from '~/generated/graphql';
import { capitalize, isDefined } from 'twenty-shared/utils';
export const useRunWorkflowActions = () => { export const useRunWorkflowActions = () => {
const isWorkflowEnabled = useIsFeatureEnabled( const isWorkflowEnabled = useIsFeatureEnabled(
@ -39,9 +39,9 @@ export const useRunWorkflowActions = () => {
label: msg`${name}`, label: msg`${name}`,
position: index, position: index,
Icon: IconSettingsAutomation, Icon: IconSettingsAutomation,
shouldBeRegistered: () => true,
useAction: () => { useAction: () => {
return { return {
shouldBeRegistered: true,
onClick: async () => { onClick: async () => {
await runWorkflowVersion({ await runWorkflowVersion({
workflowVersionId: activeWorkflowVersion.id, workflowVersionId: activeWorkflowVersion.id,

View File

@ -1,4 +1,4 @@
export enum RecordAgnosticActionsKey { export enum RecordAgnosticActionsKeys {
SEARCH_RECORDS = 'search-records', SEARCH_RECORDS = 'search-records',
SEARCH_RECORDS_FALLBACK = 'search-records-fallback', SEARCH_RECORDS_FALLBACK = 'search-records-fallback',
} }

View File

@ -1,7 +1,6 @@
import { ConfirmationModalProps } from '@/ui/layout/modal/components/ConfirmationModal'; import { ConfirmationModalProps } from '@/ui/layout/modal/components/ConfirmationModal';
export type ActionHookResult = { export type ActionHookResult = {
shouldBeRegistered: boolean;
onClick: () => Promise<void> | void; onClick: () => Promise<void> | void;
ConfirmationModal?: React.ReactElement<ConfirmationModalProps>; ConfirmationModal?: React.ReactElement<ConfirmationModalProps>;
}; };

View File

@ -0,0 +1,8 @@
import { MultipleRecordsActionKeys } from '@/action-menu/actions/record-actions/multiple-records/types/MultipleRecordsActionKeys';
import { NoSelectionRecordActionKeys } from '@/action-menu/actions/record-actions/no-selection/types/NoSelectionRecordActionsKeys';
import { SingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/types/SingleRecordActionsKey';
export type DefaultRecordActionConfigKeys =
| NoSelectionRecordActionKeys
| SingleRecordActionKeys
| MultipleRecordsActionKeys;

View File

@ -0,0 +1,9 @@
import { ActionHookWithoutObjectMetadataItem } from '@/action-menu/actions/types/ActionHook';
import { RecordConfigAction } from '@/action-menu/actions/types/RecordConfigAction';
export type RecordAgnosticConfigAction = Omit<
RecordConfigAction,
'useAction'
> & {
useAction: ActionHookWithoutObjectMetadataItem;
};

View File

@ -0,0 +1,25 @@
import { ActionHook } from '@/action-menu/actions/types/ActionHook';
import { ActionViewType } from '@/action-menu/actions/types/ActionViewType';
import { ShouldBeRegisteredFunctionParams } from '@/action-menu/actions/types/ShouldBeRegisteredFunctionParams';
import {
ActionMenuEntryScope,
ActionMenuEntryType,
} from '@/action-menu/types/ActionMenuEntry';
import { MessageDescriptor } from '@lingui/core';
import { IconComponent, MenuItemAccent } from 'twenty-ui';
export type RecordConfigAction = {
type: ActionMenuEntryType;
scope: ActionMenuEntryScope;
key: string;
label: MessageDescriptor;
shortLabel?: MessageDescriptor;
position: number;
Icon: IconComponent;
isPinned?: boolean;
accent?: MenuItemAccent;
availableOn?: ActionViewType[];
shouldBeRegistered: (params: ShouldBeRegisteredFunctionParams) => boolean;
useAction: ActionHook;
hotKeys?: string[];
};

View File

@ -0,0 +1,20 @@
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { WorkflowWithCurrentVersion } from '@/workflow/types/Workflow';
export type ShouldBeRegisteredFunctionParams = {
objectMetadataItem?: ObjectMetadataItem;
hasObjectReadOnlyPermission?: boolean;
isWorkflowsEnabled?: boolean;
recordFilters?: RecordFilter[];
isShowPage?: boolean;
isSoftDeleteFilterActive?: boolean;
isInRightDrawer?: boolean;
isFavorite?: boolean;
isRemote?: boolean;
isNoteOrTask?: boolean;
selectedRecord?: ObjectRecord;
numberOfSelectedRecords?: number;
workflowWithCurrentVersion?: WorkflowWithCurrentVersion;
};

View File

@ -1,4 +1,4 @@
import { DEFAULT_ACTIONS_CONFIG } from '@/action-menu/actions/record-actions/constants/DefaultActionsConfig'; import { DEFAULT_RECORD_ACTIONS_CONFIG } from '@/action-menu/actions/record-actions/constants/DefaultRecordActionsConfig';
import { WORKFLOW_ACTIONS_CONFIG } from '@/action-menu/actions/record-actions/constants/WorkflowActionsConfig'; import { WORKFLOW_ACTIONS_CONFIG } from '@/action-menu/actions/record-actions/constants/WorkflowActionsConfig';
import { WORKFLOW_RUNS_ACTIONS_CONFIG } from '@/action-menu/actions/record-actions/constants/WorkflowRunsActionsConfig'; import { WORKFLOW_RUNS_ACTIONS_CONFIG } from '@/action-menu/actions/record-actions/constants/WorkflowRunsActionsConfig';
import { WORKFLOW_VERSIONS_ACTIONS_CONFIG } from '@/action-menu/actions/record-actions/constants/WorkflowVersionsActionsConfig'; import { WORKFLOW_VERSIONS_ACTIONS_CONFIG } from '@/action-menu/actions/record-actions/constants/WorkflowVersionsActionsConfig';
@ -14,6 +14,6 @@ export const getActionConfig = (objectMetadataItem: ObjectMetadataItem) => {
case CoreObjectNameSingular.WorkflowRun: case CoreObjectNameSingular.WorkflowRun:
return WORKFLOW_RUNS_ACTIONS_CONFIG; return WORKFLOW_RUNS_ACTIONS_CONFIG;
default: default:
return DEFAULT_ACTIONS_CONFIG; return DEFAULT_RECORD_ACTIONS_CONFIG;
} }
}; };

View File

@ -0,0 +1,88 @@
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
import { useFavorites } from '@/favorites/hooks/useFavorites';
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
import { isSoftDeleteFilterActiveComponentState } from '@/object-record/record-table/states/isSoftDeleteFilterActiveComponentState';
import { useHasObjectReadOnlyPermission } from '@/settings/roles/hooks/useHasObjectReadOnlyPermission';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useWorkflowWithCurrentVersion } from '@/workflow/hooks/useWorkflowWithCurrentVersion';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { useContext } from 'react';
import { useRecoilValue } from 'recoil';
import { FeatureFlagKey } from '~/generated-metadata/graphql';
export const useShouldActionBeRegisteredParams = ({
objectMetadataItem,
}: {
objectMetadataItem: ObjectMetadataItem;
}) => {
const { sortedFavorites: favorites } = useFavorites();
const contextStoreTargetedRecordsRule = useRecoilComponentValueV2(
contextStoreTargetedRecordsRuleComponentState,
);
const recordId =
contextStoreTargetedRecordsRule.mode === 'selection'
? contextStoreTargetedRecordsRule.selectedRecordIds[0]
: undefined;
const foundFavorite = favorites?.find(
(favorite) => favorite.recordId === recordId,
);
const isFavorite = !!foundFavorite;
const selectedRecord =
useRecoilValue(recordStoreFamilyState(recordId ?? '')) || undefined;
const isRemoteObject = objectMetadataItem.isRemote;
const hasObjectReadOnlyPermission = useHasObjectReadOnlyPermission();
const isNoteOrTask =
objectMetadataItem?.nameSingular === CoreObjectNameSingular.Note ||
objectMetadataItem?.nameSingular === CoreObjectNameSingular.Task;
const { isInRightDrawer } = useContext(ActionMenuContext);
const isSoftDeleteFilterActive = useRecoilComponentValueV2(
isSoftDeleteFilterActiveComponentState,
);
const isShowPage =
useRecoilComponentValueV2(contextStoreCurrentViewTypeComponentState) ===
ContextStoreViewType.ShowPage;
const isWorkflowsEnabled = useIsFeatureEnabled(
FeatureFlagKey.IsWorkflowEnabled,
);
const numberOfSelectedRecords = useRecoilComponentValueV2(
contextStoreNumberOfSelectedRecordsComponentState,
);
const workflowWithCurrentVersion = useWorkflowWithCurrentVersion(
recordId,
objectMetadataItem.nameSingular !== CoreObjectNameSingular.Workflow,
);
return {
isFavorite,
isRemoteObject,
hasObjectReadOnlyPermission,
isNoteOrTask,
isInRightDrawer,
isSoftDeleteFilterActive,
isShowPage,
selectedRecord,
isWorkflowsEnabled,
numberOfSelectedRecords,
workflowWithCurrentVersion,
};
};

View File

@ -1,8 +1,8 @@
import { RecordActionMenuEntriesSetter } from '@/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter'; import { RecordActionMenuEntriesSetter } from '@/action-menu/actions/record-actions/components/RecordActionMenuEntriesSetter';
import { NoSelectionRecordActionKeys } from '@/action-menu/actions/record-actions/no-selection/types/NoSelectionRecordActionsKey'; import { NoSelectionRecordActionKeys } from '@/action-menu/actions/record-actions/no-selection/types/NoSelectionRecordActionsKeys';
import { RecordAgnosticActionMenuEntriesSetter } from '@/action-menu/actions/record-agnostic-actions/components/RecordAgnosticActionMenuEntriesSetter'; import { RecordAgnosticActionMenuEntriesSetter } from '@/action-menu/actions/record-agnostic-actions/components/RecordAgnosticActionMenuEntriesSetter';
import { RunWorkflowRecordAgnosticActionMenuEntriesSetter } from '@/action-menu/actions/record-agnostic-actions/components/RunWorkflowRecordAgnosticActionMenuEntriesSetter'; import { RunWorkflowRecordAgnosticActionMenuEntriesSetter } from '@/action-menu/actions/record-agnostic-actions/components/RunWorkflowRecordAgnosticActionMenuEntriesSetter';
import { RecordAgnosticActionsKey } from '@/action-menu/actions/record-agnostic-actions/types/RecordAgnosticActionsKey'; import { RecordAgnosticActionsKeys } from '@/action-menu/actions/record-agnostic-actions/types/RecordAgnosticActionsKeys';
import { ActionMenuConfirmationModals } from '@/action-menu/components/ActionMenuConfirmationModals'; import { ActionMenuConfirmationModals } from '@/action-menu/components/ActionMenuConfirmationModals';
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext'; import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext'; import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
@ -144,16 +144,16 @@ export const CommandMenuContainer = ({
isInRightDrawer: true, isInRightDrawer: true,
onActionExecutedCallback: ({ key }) => { onActionExecutedCallback: ({ key }) => {
if ( if (
key !== RecordAgnosticActionsKey.SEARCH_RECORDS && key !== RecordAgnosticActionsKeys.SEARCH_RECORDS &&
key !== key !==
RecordAgnosticActionsKey.SEARCH_RECORDS_FALLBACK && RecordAgnosticActionsKeys.SEARCH_RECORDS_FALLBACK &&
key !== NoSelectionRecordActionKeys.CREATE_NEW_RECORD key !== NoSelectionRecordActionKeys.CREATE_NEW_RECORD
) { ) {
toggleCommandMenu(); toggleCommandMenu();
} }
if ( if (
key !== RecordAgnosticActionsKey.SEARCH_RECORDS_FALLBACK key !== RecordAgnosticActionsKeys.SEARCH_RECORDS_FALLBACK
) { ) {
setCommandMenuSearch(''); setCommandMenuSearch('');
} }

View File

@ -9,6 +9,7 @@ import { isDefined } from 'twenty-shared/utils';
export const useWorkflowWithCurrentVersion = ( export const useWorkflowWithCurrentVersion = (
workflowId: string | undefined, workflowId: string | undefined,
skip = false,
): WorkflowWithCurrentVersion | undefined => { ): WorkflowWithCurrentVersion | undefined => {
const { record: workflow } = useFindOneRecord<Workflow>({ const { record: workflow } = useFindOneRecord<Workflow>({
objectNameSingular: CoreObjectNameSingular.Workflow, objectNameSingular: CoreObjectNameSingular.Workflow,
@ -20,7 +21,7 @@ export const useWorkflowWithCurrentVersion = (
lastPublishedVersionId: true, lastPublishedVersionId: true,
versions: true, versions: true,
}, },
skip: !isDefined(workflowId), skip: !isDefined(workflowId) || skip,
}); });
return useMemo(() => { return useMemo(() => {