feat: enable export of deleted records (#12776)

resolve #12662
This PR enables exporting deleted records by detecting when deleted view
mode is active and adding deletedAt: { is: 'NOT_NULL' } to
graphqlFilter.

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Naifer
2025-07-04 21:58:24 +01:00
committed by GitHub
parent 1729970836
commit 324dadca63
15 changed files with 186 additions and 48 deletions

View File

@ -13,6 +13,7 @@ import { AddToFavoritesSingleRecordAction } from '@/action-menu/actions/record-a
import { DeleteSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/components/DeleteSingleRecordAction';
import { DestroySingleRecordAction } from '@/action-menu/actions/record-actions/single-record/components/DestroySingleRecordAction';
import { ExportNoteActionSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/components/ExportNoteActionSingleRecordAction';
import { ExportSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/components/ExportSingleRecordAction';
import { NavigateToNextRecordSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/components/NavigateToNextRecordSingleRecordAction';
import { NavigateToPreviousRecordSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/components/NavigateToPreviousRecordSingleRecordAction';
import { RemoveFromFavoritesSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/components/RemoveFromFavoritesSingleRecordAction';
@ -137,10 +138,10 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
],
component: <RemoveFromFavoritesSingleRecordAction />,
},
[SingleRecordActionKeys.EXPORT]: {
[SingleRecordActionKeys.EXPORT_FROM_RECORD_INDEX]: {
type: ActionType.Standard,
scope: ActionScope.RecordSelection,
key: SingleRecordActionKeys.EXPORT,
key: SingleRecordActionKeys.EXPORT_FROM_RECORD_INDEX,
label: msg`Export`,
shortLabel: msg`Export`,
position: 4,
@ -149,12 +150,24 @@ export const DEFAULT_RECORD_ACTIONS_CONFIG: Record<
isPinned: false,
shouldBeRegistered: ({ selectedRecord }) =>
isDefined(selectedRecord) && !selectedRecord.isRemote,
availableOn: [
ActionViewType.SHOW_PAGE,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
],
availableOn: [ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION],
component: <ExportMultipleRecordsAction />,
},
[SingleRecordActionKeys.EXPORT_FROM_RECORD_SHOW]: {
type: ActionType.Standard,
scope: ActionScope.RecordSelection,
key: SingleRecordActionKeys.EXPORT_FROM_RECORD_SHOW,
label: msg`Export`,
shortLabel: msg`Export`,
position: 4,
Icon: IconFileExport,
accent: 'default',
isPinned: false,
shouldBeRegistered: ({ selectedRecord }) =>
isDefined(selectedRecord) && !selectedRecord.isRemote,
availableOn: [ActionViewType.SHOW_PAGE],
component: <ExportSingleRecordAction />,
},
[MultipleRecordsActionKeys.EXPORT]: {
type: ActionType.Standard,
scope: ActionScope.RecordSelection,

View File

@ -222,7 +222,8 @@ export const WORKFLOW_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({
SingleRecordActionKeys.DELETE,
SingleRecordActionKeys.DESTROY,
SingleRecordActionKeys.RESTORE,
SingleRecordActionKeys.EXPORT,
SingleRecordActionKeys.EXPORT_FROM_RECORD_INDEX,
SingleRecordActionKeys.EXPORT_FROM_RECORD_SHOW,
MultipleRecordsActionKeys.DELETE,
MultipleRecordsActionKeys.DESTROY,
MultipleRecordsActionKeys.RESTORE,
@ -259,14 +260,18 @@ export const WORKFLOW_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({
position: 12,
label: msg`Permanently destroy workflow`,
},
[SingleRecordActionKeys.EXPORT]: {
[SingleRecordActionKeys.EXPORT_FROM_RECORD_INDEX]: {
position: 13,
label: msg`Export workflow`,
shouldBeRegistered: ({ selectedRecord }) =>
!isDefined(selectedRecord?.deletedAt),
},
[MultipleRecordsActionKeys.EXPORT]: {
[SingleRecordActionKeys.EXPORT_FROM_RECORD_SHOW]: {
position: 14,
label: msg`Export workflow`,
},
[MultipleRecordsActionKeys.EXPORT]: {
position: 15,
label: msg`Export workflows`,
},
[NoSelectionRecordActionKeys.EXPORT_VIEW]: {

View File

@ -51,7 +51,8 @@ export const WORKFLOW_RUNS_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({
SingleRecordActionKeys.REMOVE_FROM_FAVORITES,
SingleRecordActionKeys.NAVIGATE_TO_PREVIOUS_RECORD,
SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD,
SingleRecordActionKeys.EXPORT,
SingleRecordActionKeys.EXPORT_FROM_RECORD_INDEX,
SingleRecordActionKeys.EXPORT_FROM_RECORD_SHOW,
MultipleRecordsActionKeys.EXPORT,
NoSelectionRecordActionKeys.EXPORT_VIEW,
NoSelectionRecordActionKeys.SEE_DELETED_RECORDS,
@ -73,7 +74,11 @@ export const WORKFLOW_RUNS_ACTIONS_CONFIG = inheritActionsFromDefaultConfig({
isPinned: false,
position: 3,
},
[SingleRecordActionKeys.EXPORT]: {
[SingleRecordActionKeys.EXPORT_FROM_RECORD_INDEX]: {
position: 4,
label: msg`Export run`,
},
[SingleRecordActionKeys.EXPORT_FROM_RECORD_SHOW]: {
position: 4,
label: msg`Export run`,
},

View File

@ -118,7 +118,8 @@ export const WORKFLOW_VERSIONS_ACTIONS_CONFIG = inheritActionsFromDefaultConfig(
SingleRecordActionKeys.NAVIGATE_TO_NEXT_RECORD,
SingleRecordActionKeys.ADD_TO_FAVORITES,
SingleRecordActionKeys.REMOVE_FROM_FAVORITES,
SingleRecordActionKeys.EXPORT,
SingleRecordActionKeys.EXPORT_FROM_RECORD_INDEX,
SingleRecordActionKeys.EXPORT_FROM_RECORD_SHOW,
MultipleRecordsActionKeys.EXPORT,
NoSelectionRecordActionKeys.EXPORT_VIEW,
NoSelectionRecordActionKeys.SEE_DELETED_RECORDS,
@ -140,7 +141,11 @@ export const WORKFLOW_VERSIONS_ACTIONS_CONFIG = inheritActionsFromDefaultConfig(
position: 6,
isPinned: false,
},
[SingleRecordActionKeys.EXPORT]: {
[SingleRecordActionKeys.EXPORT_FROM_RECORD_INDEX]: {
position: 7,
label: msg`Export version`,
},
[SingleRecordActionKeys.EXPORT_FROM_RECORD_SHOW]: {
position: 7,
label: msg`Export version`,
},

View File

@ -1,7 +1,7 @@
import { Action } from '@/action-menu/actions/components/Action';
import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow';
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
import { useExportRecords } from '@/object-record/record-index/export/hooks/useExportRecords';
import { useRecordIndexExportRecords } from '@/object-record/record-index/export/hooks/useRecordIndexExportRecords';
import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
@ -16,7 +16,7 @@ export const ExportMultipleRecordsAction = () => {
throw new Error('Current view ID is not defined');
}
const { download } = useExportRecords({
const { download } = useRecordIndexExportRecords({
delayMs: 100,
objectMetadataItem,
recordIndexId: getRecordIndexIdFromObjectNamePluralAndViewId(

View File

@ -0,0 +1,30 @@
import { useSelectedRecordIdOrThrow } from '@/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIdOrThrow';
import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow';
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
import { useExportSingleRecord } from '@/object-record/record-show/hooks/useExportSingleRecord';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { Action } from '@/action-menu/actions/components/Action';
export const ExportSingleRecordAction = () => {
const { objectMetadataItem } = useContextStoreObjectMetadataItemOrThrow();
const contextStoreCurrentViewId = useRecoilComponentValueV2(
contextStoreCurrentViewIdComponentState,
);
if (!contextStoreCurrentViewId) {
throw new Error('Current view ID is not defined');
}
const recordId = useSelectedRecordIdOrThrow();
const filename = `${objectMetadataItem.nameSingular}.csv`;
const { download } = useExportSingleRecord({
filename,
objectMetadataItem,
recordId,
});
return <Action onClick={download} />;
};

View File

@ -6,6 +6,7 @@ export enum SingleRecordActionKeys {
NAVIGATE_TO_NEXT_RECORD = 'navigate-to-next-record-single-record',
NAVIGATE_TO_PREVIOUS_RECORD = 'navigate-to-previous-record-single-record',
EXPORT_NOTE_TO_PDF = 'export-note-to-pdf-single-record',
EXPORT = 'export-single-record',
EXPORT_FROM_RECORD_INDEX = 'export-from-record-index-single-record',
EXPORT_FROM_RECORD_SHOW = 'export-from-record-show-single-record',
RESTORE = 'restore-single-record',
}

View File

@ -45,7 +45,7 @@ export const createMockActionMenuActions = ({
{
type: ActionType.Standard,
scope: ActionScope.RecordSelection,
key: SingleRecordActionKeys.EXPORT,
key: SingleRecordActionKeys.EXPORT_FROM_RECORD_INDEX,
label: msg`Export`,
shortLabel: msg`Export`,
position: 4,
@ -53,10 +53,7 @@ export const createMockActionMenuActions = ({
accent: 'default',
isPinned: false,
shouldBeRegistered: () => true,
availableOn: [
ActionViewType.SHOW_PAGE,
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
],
availableOn: [ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION],
component: <Action onClick={exportMock} />,
},
{