From b349d3f8c200ed1f2f9749a8c399b1079e2613b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Bosi?= <71827178+bosiraphael@users.noreply.github.com> Date: Wed, 26 Feb 2025 18:51:17 +0100 Subject: [PATCH] 62 create see deleted records action (#10525) Closes https://github.com/twentyhq/core-team-issues/issues/62 - Created action - Removed action from the option menu - Fixed the filters and sorts providers for the command menu https://github.com/user-attachments/assets/b42de3ea-536c-458c-a0e7-abd6f929d234 --- .../constants/DefaultActionsConfigV1.ts | 15 +++++++ .../constants/DefaultActionsConfigV2.ts | 23 +++++++++-- ...teNewTableRecordNoSelectionRecordAction.ts | 15 ++++++- ...eeDeletedRecordsNoSelectionRecordAction.ts | 39 +++++++++++++++++++ .../types/NoSelectionRecordActionsKey.ts | 1 + .../components/CommandMenuContainer.tsx | 24 ++++++++++-- .../ObjectOptionsDropdownMenuContent.tsx | 23 ----------- .../components/RecordIndexContainerGater.tsx | 6 ++- ...ordIndexIdFromObjectNamePluralAndViewId.ts | 6 +++ 9 files changed, 119 insertions(+), 33 deletions(-) create mode 100644 packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/hooks/useSeeDeletedRecordsNoSelectionRecordAction.ts create mode 100644 packages/twenty-front/src/modules/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId.ts diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV1.ts b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV1.ts index 2bfdbd080..2b462e003 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV1.ts +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV1.ts @@ -1,6 +1,7 @@ import { useDeleteMultipleRecordsAction } from '@/action-menu/actions/record-actions/multiple-records/hooks/useDeleteMultipleRecordsAction'; 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 { useSeeDeletedRecordsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useSeeDeletedRecordsNoSelectionRecordAction'; import { NoSelectionRecordActionKeys } from '@/action-menu/actions/record-actions/no-selection/types/NoSelectionRecordActionsKey'; import { useAddToFavoritesSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useAddToFavoritesSingleRecordAction'; import { useDeleteSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useDeleteSingleRecordAction'; @@ -18,6 +19,7 @@ import { IconDatabaseExport, IconHeart, IconHeartOff, + IconRotate2, IconTrash, } from 'twenty-ui'; @@ -107,4 +109,17 @@ export const DEFAULT_ACTIONS_CONFIG_V1: Record< availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], useAction: useExportMultipleRecordsAction, }, + seeDeletedRecords: { + type: ActionMenuEntryType.Standard, + scope: ActionMenuEntryScope.Object, + key: NoSelectionRecordActionKeys.SEE_DELETED_RECORDS, + label: msg`See deleted records`, + shortLabel: msg`Deleted records`, + position: 6, + Icon: IconRotate2, + accent: 'default', + isPinned: false, + availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], + useAction: useSeeDeletedRecordsNoSelectionRecordAction, + }, }; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV2.ts b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV2.ts index 9da6c8c27..5cc68a08f 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV2.ts +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV2.ts @@ -3,6 +3,7 @@ import { useDestroyMultipleRecordsAction } from '@/action-menu/actions/record-ac 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 { useCreateNewTableRecordNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useCreateNewTableRecordNoSelectionRecordAction'; +import { useSeeDeletedRecordsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useSeeDeletedRecordsNoSelectionRecordAction'; import { NoSelectionRecordActionKeys } from '@/action-menu/actions/record-actions/no-selection/types/NoSelectionRecordActionsKey'; import { useAddToFavoritesSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useAddToFavoritesSingleRecordAction'; import { useDeleteSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useDeleteSingleRecordAction'; @@ -28,6 +29,7 @@ import { IconHeart, IconHeartOff, IconPlus, + IconRotate2, IconTrash, IconTrashX, } from 'twenty-ui'; @@ -147,13 +149,26 @@ export const DEFAULT_ACTIONS_CONFIG_V2: Record< availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], useAction: useExportMultipleRecordsAction, }, + seeDeletedRecords: { + type: ActionMenuEntryType.Standard, + scope: ActionMenuEntryScope.Object, + key: NoSelectionRecordActionKeys.SEE_DELETED_RECORDS, + label: msg`See deleted records`, + shortLabel: msg`Deleted records`, + position: 8, + Icon: IconRotate2, + accent: 'default', + isPinned: false, + availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], + useAction: useSeeDeletedRecordsNoSelectionRecordAction, + }, destroySingleRecord: { type: ActionMenuEntryType.Standard, scope: ActionMenuEntryScope.RecordSelection, key: SingleRecordActionKeys.DESTROY, label: msg`Permanently destroy record`, shortLabel: msg`Destroy`, - position: 8, + position: 9, Icon: IconTrashX, accent: 'danger', isPinned: true, @@ -168,7 +183,7 @@ export const DEFAULT_ACTIONS_CONFIG_V2: Record< scope: ActionMenuEntryScope.RecordSelection, key: SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD, label: msg`Navigate to previous record`, - position: 9, + position: 10, isPinned: true, Icon: IconChevronUp, availableOn: [ActionViewType.SHOW_PAGE], @@ -179,7 +194,7 @@ export const DEFAULT_ACTIONS_CONFIG_V2: Record< scope: ActionMenuEntryScope.RecordSelection, key: SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD, label: msg`Navigate to next record`, - position: 10, + position: 11, isPinned: true, Icon: IconChevronDown, availableOn: [ActionViewType.SHOW_PAGE], @@ -191,7 +206,7 @@ export const DEFAULT_ACTIONS_CONFIG_V2: Record< key: MultipleRecordsActionKeys.DESTROY, label: msg`Permanently destroy records`, shortLabel: msg`Destroy`, - position: 11, + position: 12, Icon: IconTrashX, accent: 'danger', isPinned: true, diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/hooks/useCreateNewTableRecordNoSelectionRecordAction.ts b/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/hooks/useCreateNewTableRecordNoSelectionRecordAction.ts index a1a2ca7f1..e73a6ab6b 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/hooks/useCreateNewTableRecordNoSelectionRecordAction.ts +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/hooks/useCreateNewTableRecordNoSelectionRecordAction.ts @@ -1,12 +1,23 @@ import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/ActionHook'; +import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { useCreateNewTableRecord } from '@/object-record/record-table/hooks/useCreateNewTableRecords'; -import { getRecordIndexIdFromObjectNamePlural } from '@/object-record/utils/getRecordIndexIdFromObjectNamePlural'; +import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId'; import { useHasObjectReadOnlyPermission } from '@/settings/roles/hooks/useHasObjectReadOnlyPermission'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; export const useCreateNewTableRecordNoSelectionRecordAction: ActionHookWithObjectMetadataItem = ({ objectMetadataItem }) => { - const recordTableId = getRecordIndexIdFromObjectNamePlural( + const currentViewId = useRecoilComponentValueV2( + contextStoreCurrentViewIdComponentState, + ); + + if (!currentViewId) { + throw new Error('Current view ID is not defined'); + } + + const recordTableId = getRecordIndexIdFromObjectNamePluralAndViewId( objectMetadataItem.namePlural, + currentViewId, ); const hasObjectReadOnlyPermission = useHasObjectReadOnlyPermission(); diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/hooks/useSeeDeletedRecordsNoSelectionRecordAction.ts b/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/hooks/useSeeDeletedRecordsNoSelectionRecordAction.ts new file mode 100644 index 000000000..c62caacf6 --- /dev/null +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/hooks/useSeeDeletedRecordsNoSelectionRecordAction.ts @@ -0,0 +1,39 @@ +import { useCallback } from 'react'; + +import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/ActionHook'; +import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; +import { useHandleToggleTrashColumnFilter } from '@/object-record/record-index/hooks/useHandleToggleTrashColumnFilter'; +import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; + +export const useSeeDeletedRecordsNoSelectionRecordAction: ActionHookWithObjectMetadataItem = + ({ objectMetadataItem }) => { + const currentViewId = useRecoilComponentValueV2( + contextStoreCurrentViewIdComponentState, + ); + + if (!currentViewId) { + throw new Error('Current view ID is not defined'); + } + + const recordIndexId = getRecordIndexIdFromObjectNamePluralAndViewId( + objectMetadataItem.namePlural, + currentViewId, + ); + + const { handleToggleTrashColumnFilter, toggleSoftDeleteFilterState } = + useHandleToggleTrashColumnFilter({ + objectNameSingular: objectMetadataItem.nameSingular, + viewBarId: recordIndexId, + }); + + const onClick = useCallback(() => { + handleToggleTrashColumnFilter(); + toggleSoftDeleteFilterState(true); + }, [handleToggleTrashColumnFilter, toggleSoftDeleteFilterState]); + + return { + shouldBeRegistered: true, + onClick, + }; + }; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/types/NoSelectionRecordActionsKey.ts b/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/types/NoSelectionRecordActionsKey.ts index 606b49928..2db8b6587 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/types/NoSelectionRecordActionsKey.ts +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/no-selection/types/NoSelectionRecordActionsKey.ts @@ -1,4 +1,5 @@ export enum NoSelectionRecordActionKeys { EXPORT_VIEW = 'export-view-no-selection', CREATE_NEW_RECORD = 'create-new-record-no-selection', + SEE_DELETED_RECORDS = 'see-deleted-records-no-selection', } diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuContainer.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuContainer.tsx index 142b8f4e0..509cb682b 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuContainer.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuContainer.tsx @@ -13,12 +13,16 @@ import { useCommandMenuHotKeys } from '@/command-menu/hooks/useCommandMenuHotKey import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState'; import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState'; import { CommandMenuAnimationVariant } from '@/command-menu/types/CommandMenuAnimationVariant'; +import { contextStoreCurrentObjectMetadataItemComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemComponentState'; +import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; import { RecordFilterGroupsComponentInstanceContext } from '@/object-record/record-filter-group/states/context/RecordFilterGroupsComponentInstanceContext'; import { RecordFiltersComponentInstanceContext } from '@/object-record/record-filter/states/context/RecordFiltersComponentInstanceContext'; import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext'; +import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId'; import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope'; import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { workflowReactFlowRefState } from '@/workflow/workflow-diagram/states/workflowReactFlowRefState'; import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { useTheme } from '@emotion/react'; @@ -89,15 +93,29 @@ export const CommandMenuContainer = ({ const setCommandMenuSearch = useSetRecoilState(commandMenuSearchState); + const contextStoreCurrentObjectMetadataItem = useRecoilComponentValueV2( + contextStoreCurrentObjectMetadataItemComponentState, + COMMAND_MENU_COMPONENT_INSTANCE_ID, + ); + + const currentViewId = useRecoilComponentValueV2( + contextStoreCurrentViewIdComponentState, + COMMAND_MENU_COMPONENT_INSTANCE_ID, + ); + + const recordIndexId = getRecordIndexIdFromObjectNamePluralAndViewId( + contextStoreCurrentObjectMetadataItem?.namePlural ?? '', + currentViewId ?? '', + ); return ( { const CurrentViewIcon = currentView?.icon ? getIcon(currentView.icon) : null; - const { objectNamePlural } = useObjectNamePluralFromSingular({ - objectNameSingular: objectMetadataItem.nameSingular, - }); - const recordGroupFieldMetadata = useRecoilComponentValueV2( recordGroupFieldMetadataComponentState, ); @@ -68,12 +60,6 @@ export const ObjectOptionsDropdownMenuContent = () => { TableOptionsHotkeyScope.Dropdown, ); - const { handleToggleTrashColumnFilter, toggleSoftDeleteFilterState } = - useHandleToggleTrashColumnFilter({ - objectNameSingular: objectMetadataItem.nameSingular, - viewBarId: recordIndexId, - }); - const { visibleBoardFields } = useObjectOptionsForBoard({ objectNameSingular: objectMetadataItem.nameSingular, recordBoardId: recordIndexId, @@ -163,15 +149,6 @@ export const ObjectOptionsDropdownMenuContent = () => { text={t`Import`} /> )} - { - handleToggleTrashColumnFilter(); - toggleSoftDeleteFilterState(true); - closeDropdown(); - }} - LeftIcon={IconRotate2} - text={t`Deleted ${objectNamePlural}`} - /> ); diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerGater.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerGater.tsx index 942a6af5e..19a803b6e 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerGater.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexContainerGater.tsx @@ -14,6 +14,7 @@ import { RecordIndexLoadBaseOnContextStoreEffect } from '@/object-record/record- import { RecordIndexPageHeader } from '@/object-record/record-index/components/RecordIndexPageHeader'; import { useHandleIndexIdentifierClick } from '@/object-record/record-index/hooks/useHandleIndexIdentifierClick'; import { RecordSortsComponentInstanceContext } from '@/object-record/record-sort/states/context/RecordSortsComponentInstanceContext'; +import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId'; import { PageBody } from '@/ui/layout/page/components/PageBody'; import { PageTitle } from '@/ui/utilities/page-title/components/PageTitle'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; @@ -36,7 +37,10 @@ export const RecordIndexContainerGater = () => { const { objectMetadataItem } = useContextStoreObjectMetadataItemOrThrow(); - const recordIndexId = `${objectMetadataItem.namePlural}-${contextStoreCurrentViewId}`; + const recordIndexId = getRecordIndexIdFromObjectNamePluralAndViewId( + objectMetadataItem.namePlural, + contextStoreCurrentViewId || '', + ); const handleIndexRecordsLoaded = useRecoilCallback( ({ set }) => diff --git a/packages/twenty-front/src/modules/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId.ts b/packages/twenty-front/src/modules/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId.ts new file mode 100644 index 000000000..925aa27d1 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId.ts @@ -0,0 +1,6 @@ +export const getRecordIndexIdFromObjectNamePluralAndViewId = ( + objectNamePlural: string, + viewId: string, +): string => { + return `${objectNamePlural}-${viewId}`; +};