Create 'Hide deleted records' action (#11198)

This PR:
- Makes 'See deleted records' action unavailable when the deleted filter
is active
- Creates 'Hide deleted records'



https://github.com/user-attachments/assets/b45f8ead-d973-418d-afba-a5983ac85172
This commit is contained in:
Raphaël Bosi
2025-03-26 17:59:59 +01:00
committed by GitHub
parent 760a21d8fa
commit 1860768b52
7 changed files with 146 additions and 14 deletions

View File

@ -4,6 +4,7 @@ import { useExportMultipleRecordsAction } from '@/action-menu/actions/record-act
import { useRestoreMultipleRecordsAction } from '@/action-menu/actions/record-actions/multiple-records/hooks/useRestoreMultipleRecordsAction';
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 { 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 { useSeeWorkflowsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useSeeWorkflowsNoSelectionRecordAction';
@ -29,6 +30,7 @@ import {
IconChevronDown,
IconChevronUp,
IconDatabaseExport,
IconEyeOff,
IconFileExport,
IconFileImport,
IconHeart,
@ -185,13 +187,26 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
useAction: useSeeDeletedRecordsNoSelectionRecordAction,
},
hideDeletedRecords: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.Object,
key: NoSelectionRecordActionKeys.HIDE_DELETED_RECORDS,
label: msg`Hide deleted records`,
shortLabel: msg`Hide deleted`,
position: 10,
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 records`,
shortLabel: msg`Import`,
position: 10,
position: 11,
Icon: IconFileImport,
accent: 'default',
isPinned: false,
@ -204,7 +219,7 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
key: SingleRecordActionKeys.DESTROY,
label: msg`Permanently destroy record`,
shortLabel: msg`Destroy`,
position: 11,
position: 12,
Icon: IconTrashX,
accent: 'danger',
isPinned: true,
@ -219,7 +234,7 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
scope: ActionMenuEntryScope.RecordSelection,
key: SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD,
label: msg`Navigate to previous record`,
position: 12,
position: 13,
isPinned: true,
Icon: IconChevronUp,
availableOn: [ActionViewType.SHOW_PAGE],
@ -230,7 +245,7 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
scope: ActionMenuEntryScope.RecordSelection,
key: SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD,
label: msg`Navigate to next record`,
position: 13,
position: 14,
isPinned: true,
Icon: IconChevronDown,
availableOn: [ActionViewType.SHOW_PAGE],
@ -242,7 +257,7 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
key: MultipleRecordsActionKeys.DESTROY,
label: msg`Permanently destroy records`,
shortLabel: msg`Destroy`,
position: 14,
position: 15,
Icon: IconTrashX,
accent: 'danger',
isPinned: true,
@ -255,7 +270,7 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
key: SingleRecordActionKeys.RESTORE,
label: msg`Restore record`,
shortLabel: msg`Restore`,
position: 15,
position: 16,
Icon: IconRefresh,
accent: 'default',
isPinned: true,
@ -271,7 +286,7 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
key: MultipleRecordsActionKeys.RESTORE,
label: msg`Restore records`,
shortLabel: msg`Restore`,
position: 16,
position: 17,
Icon: IconRefresh,
accent: 'default',
isPinned: true,
@ -284,7 +299,7 @@ export const DEFAULT_ACTIONS_CONFIG: Record<
key: NoSelectionRecordActionKeys.SEE_WORKFLOWS,
label: msg`Go to workflows`,
shortLabel: msg`See workflows`,
position: 17,
position: 18,
Icon: IconSettingsAutomation,
accent: 'default',
isPinned: false,

View File

@ -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 { 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';
@ -34,6 +35,7 @@ import {
IconChevronDown,
IconChevronUp,
IconDatabaseExport,
IconEyeOff,
IconFileImport,
IconHeart,
IconHeartOff,
@ -335,13 +337,26 @@ export const WORKFLOW_ACTIONS_CONFIG: Record<
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: 20,
position: 21,
Icon: IconFileImport,
accent: 'default',
isPinned: false,
@ -354,7 +369,7 @@ export const WORKFLOW_ACTIONS_CONFIG: Record<
key: NoSelectionRecordActionKeys.SEE_RUNS,
label: msg`Go to runs`,
shortLabel: msg`See runs`,
position: 21,
position: 22,
Icon: IconHistoryToggle,
accent: 'default',
isPinned: true,

View File

@ -1,5 +1,6 @@
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 { 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 { NoSelectionRecordActionKeys } from '@/action-menu/actions/record-actions/no-selection/types/NoSelectionRecordActionsKey';
@ -23,6 +24,7 @@ import {
IconChevronDown,
IconChevronUp,
IconDatabaseExport,
IconEyeOff,
IconHeart,
IconHeartOff,
IconHistory,
@ -173,13 +175,26 @@ export const WORKFLOW_RUNS_ACTIONS_CONFIG: Record<
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.SEE_WORKFLOWS,
label: msg`Go to workflows`,
shortLabel: msg`See workflows`,
position: 10,
position: 11,
Icon: IconSettingsAutomation,
accent: 'default',
isPinned: true,

View File

@ -1,5 +1,6 @@
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 { 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 { useSeeWorkflowsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useSeeWorkflowsNoSelectionRecordAction';
@ -26,6 +27,7 @@ import {
IconChevronDown,
IconChevronUp,
IconDatabaseExport,
IconEyeOff,
IconHeart,
IconHeartOff,
IconHistory,
@ -205,13 +207,26 @@ export const WORKFLOW_VERSIONS_ACTIONS_CONFIG: Record<
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.SEE_WORKFLOWS,
label: msg`Go to workflows`,
shortLabel: msg`See workflows`,
position: 13,
position: 14,
Icon: IconSettingsAutomation,
accent: 'default',
isPinned: true,
@ -225,7 +240,7 @@ export const WORKFLOW_VERSIONS_ACTIONS_CONFIG: Record<
key: NoSelectionRecordActionKeys.SEE_RUNS,
label: msg`Go to runs`,
shortLabel: msg`See runs`,
position: 14,
position: 15,
Icon: IconHistoryToggle,
accent: 'default',
isPinned: true,

View File

@ -0,0 +1,58 @@
import { useCallback } from 'react';
import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/ActionHook';
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
import { useCheckIsSoftDeleteFilter } from '@/object-record/record-filter/hooks/useCheckIsSoftDeleteFilter';
import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter';
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
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';
import { isDefined } from 'twenty-shared/utils';
export const useHideDeletedRecordsNoSelectionRecordAction: ActionHookWithObjectMetadataItem =
({ objectMetadataItem }) => {
const currentViewId = useRecoilComponentValueV2(
contextStoreCurrentViewIdComponentState,
);
if (!currentViewId) {
throw new Error('Current view ID is not defined');
}
const recordIndexId = getRecordIndexIdFromObjectNamePluralAndViewId(
objectMetadataItem.namePlural,
currentViewId,
);
const { toggleSoftDeleteFilterState } = useHandleToggleTrashColumnFilter({
objectNameSingular: objectMetadataItem.nameSingular,
viewBarId: recordIndexId,
});
const { checkIsSoftDeleteFilter } = useCheckIsSoftDeleteFilter();
const currentRecordFilters = useRecoilComponentValueV2(
currentRecordFiltersComponentState,
recordIndexId,
);
const deletedFilter = currentRecordFilters.find(checkIsSoftDeleteFilter);
const { removeRecordFilter } = useRemoveRecordFilter();
const onClick = useCallback(() => {
if (!isDefined(deletedFilter)) {
return;
}
removeRecordFilter({ recordFilterId: deletedFilter.id });
toggleSoftDeleteFilterState(false);
}, [deletedFilter, removeRecordFilter, toggleSoftDeleteFilterState]);
return {
shouldBeRegistered: isDefined(deletedFilter),
onClick,
};
};

View File

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

View File

@ -2,6 +2,7 @@ export enum NoSelectionRecordActionKeys {
EXPORT_VIEW = 'export-view',
CREATE_NEW_RECORD = 'create-new-record',
SEE_DELETED_RECORDS = 'see-deleted-records',
HIDE_DELETED_RECORDS = 'hide-deleted-records',
IMPORT_RECORDS = 'import-records',
SEE_RUNS = 'see-runs',
SEE_WORKFLOWS = 'see-workflows',