460 create restore one and restore many records action (#10647)
Closes https://github.com/twentyhq/core-team-issues/issues/460 https://github.com/user-attachments/assets/5271e56d-bf67-49cc-a8da-e25c12171e2e
This commit is contained in:
@ -1,5 +1,6 @@
|
|||||||
import { useDeleteMultipleRecordsAction } from '@/action-menu/actions/record-actions/multiple-records/hooks/useDeleteMultipleRecordsAction';
|
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 { useExportMultipleRecordsAction } from '@/action-menu/actions/record-actions/multiple-records/hooks/useExportMultipleRecordsAction';
|
||||||
|
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 { MultipleRecordsActionKeys } from '@/action-menu/actions/record-actions/multiple-records/types/MultipleRecordsActionKeys';
|
||||||
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';
|
||||||
@ -7,6 +8,7 @@ import { NoSelectionRecordActionKeys } from '@/action-menu/actions/record-action
|
|||||||
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 { 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 { 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 { ActionHook } from '@/action-menu/actions/types/ActionHook';
|
||||||
import { ActionViewType } from '@/action-menu/actions/types/ActionViewType';
|
import { ActionViewType } from '@/action-menu/actions/types/ActionViewType';
|
||||||
@ -21,6 +23,7 @@ import {
|
|||||||
IconFileImport,
|
IconFileImport,
|
||||||
IconHeart,
|
IconHeart,
|
||||||
IconHeartOff,
|
IconHeartOff,
|
||||||
|
IconRefresh,
|
||||||
IconRotate2,
|
IconRotate2,
|
||||||
IconTrash,
|
IconTrash,
|
||||||
} from 'twenty-ui';
|
} from 'twenty-ui';
|
||||||
@ -127,13 +130,42 @@ export const DEFAULT_ACTIONS_CONFIG_V1: Record<
|
|||||||
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
|
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
|
||||||
useAction: useExportMultipleRecordsAction,
|
useAction: useExportMultipleRecordsAction,
|
||||||
},
|
},
|
||||||
|
restoreSingleRecord: {
|
||||||
|
type: ActionMenuEntryType.Standard,
|
||||||
|
scope: ActionMenuEntryScope.RecordSelection,
|
||||||
|
key: SingleRecordActionKeys.RESTORE,
|
||||||
|
label: msg`Restore record`,
|
||||||
|
shortLabel: msg`Restore`,
|
||||||
|
position: 7,
|
||||||
|
Icon: IconRefresh,
|
||||||
|
accent: 'default',
|
||||||
|
isPinned: true,
|
||||||
|
availableOn: [
|
||||||
|
ActionViewType.SHOW_PAGE,
|
||||||
|
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||||
|
],
|
||||||
|
useAction: useRestoreSingleRecordAction,
|
||||||
|
},
|
||||||
|
restoreMultipleRecords: {
|
||||||
|
type: ActionMenuEntryType.Standard,
|
||||||
|
scope: ActionMenuEntryScope.RecordSelection,
|
||||||
|
key: MultipleRecordsActionKeys.RESTORE,
|
||||||
|
label: msg`Restore records`,
|
||||||
|
shortLabel: msg`Restore`,
|
||||||
|
position: 8,
|
||||||
|
Icon: IconRefresh,
|
||||||
|
accent: 'default',
|
||||||
|
isPinned: true,
|
||||||
|
availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION],
|
||||||
|
useAction: useRestoreMultipleRecordsAction,
|
||||||
|
},
|
||||||
seeDeletedRecords: {
|
seeDeletedRecords: {
|
||||||
type: ActionMenuEntryType.Standard,
|
type: ActionMenuEntryType.Standard,
|
||||||
scope: ActionMenuEntryScope.Object,
|
scope: ActionMenuEntryScope.Object,
|
||||||
key: NoSelectionRecordActionKeys.SEE_DELETED_RECORDS,
|
key: NoSelectionRecordActionKeys.SEE_DELETED_RECORDS,
|
||||||
label: msg`See deleted records`,
|
label: msg`See deleted records`,
|
||||||
shortLabel: msg`Deleted records`,
|
shortLabel: msg`Deleted records`,
|
||||||
position: 7,
|
position: 9,
|
||||||
Icon: IconRotate2,
|
Icon: IconRotate2,
|
||||||
accent: 'default',
|
accent: 'default',
|
||||||
isPinned: false,
|
isPinned: false,
|
||||||
@ -146,7 +178,7 @@ export const DEFAULT_ACTIONS_CONFIG_V1: Record<
|
|||||||
key: NoSelectionRecordActionKeys.IMPORT_RECORDS,
|
key: NoSelectionRecordActionKeys.IMPORT_RECORDS,
|
||||||
label: msg`Import records`,
|
label: msg`Import records`,
|
||||||
shortLabel: msg`Import`,
|
shortLabel: msg`Import`,
|
||||||
position: 8,
|
position: 10,
|
||||||
Icon: IconFileImport,
|
Icon: IconFileImport,
|
||||||
accent: 'default',
|
accent: 'default',
|
||||||
isPinned: false,
|
isPinned: false,
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { useDeleteMultipleRecordsAction } from '@/action-menu/actions/record-actions/multiple-records/hooks/useDeleteMultipleRecordsAction';
|
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 { useDestroyMultipleRecordsAction } from '@/action-menu/actions/record-actions/multiple-records/hooks/useDestroyMultipleRecordsAction';
|
||||||
import { useExportMultipleRecordsAction } from '@/action-menu/actions/record-actions/multiple-records/hooks/useExportMultipleRecordsAction';
|
import { useExportMultipleRecordsAction } from '@/action-menu/actions/record-actions/multiple-records/hooks/useExportMultipleRecordsAction';
|
||||||
|
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 { MultipleRecordsActionKeys } from '@/action-menu/actions/record-actions/multiple-records/types/MultipleRecordsActionKeys';
|
||||||
import { useCreateNewTableRecordNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useCreateNewTableRecordNoSelectionRecordAction';
|
import { useCreateNewTableRecordNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useCreateNewTableRecordNoSelectionRecordAction';
|
||||||
import { useImportRecordsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useImportRecordsNoSelectionRecordAction';
|
import { useImportRecordsNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useImportRecordsNoSelectionRecordAction';
|
||||||
@ -13,6 +14,7 @@ import { useExportNoteAction } from '@/action-menu/actions/record-actions/single
|
|||||||
import { useNavigateToNextRecordSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useNavigateToNextRecordSingleRecordAction';
|
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 { useNavigateToPreviousRecordSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useNavigateToPreviousRecordSingleRecordAction';
|
||||||
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 { 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 { ActionHook } from '@/action-menu/actions/types/ActionHook';
|
||||||
import { ActionViewType } from '@/action-menu/actions/types/ActionViewType';
|
import { ActionViewType } from '@/action-menu/actions/types/ActionViewType';
|
||||||
@ -31,6 +33,7 @@ import {
|
|||||||
IconHeart,
|
IconHeart,
|
||||||
IconHeartOff,
|
IconHeartOff,
|
||||||
IconPlus,
|
IconPlus,
|
||||||
|
IconRefresh,
|
||||||
IconRotate2,
|
IconRotate2,
|
||||||
IconTrash,
|
IconTrash,
|
||||||
IconTrashX,
|
IconTrashX,
|
||||||
@ -244,4 +247,33 @@ export const DEFAULT_ACTIONS_CONFIG_V2: Record<
|
|||||||
availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION],
|
availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION],
|
||||||
useAction: useDestroyMultipleRecordsAction,
|
useAction: useDestroyMultipleRecordsAction,
|
||||||
},
|
},
|
||||||
|
restoreSingleRecord: {
|
||||||
|
type: ActionMenuEntryType.Standard,
|
||||||
|
scope: ActionMenuEntryScope.RecordSelection,
|
||||||
|
key: SingleRecordActionKeys.RESTORE,
|
||||||
|
label: msg`Restore record`,
|
||||||
|
shortLabel: msg`Restore`,
|
||||||
|
position: 15,
|
||||||
|
Icon: IconRefresh,
|
||||||
|
accent: 'default',
|
||||||
|
isPinned: true,
|
||||||
|
availableOn: [
|
||||||
|
ActionViewType.SHOW_PAGE,
|
||||||
|
ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||||
|
],
|
||||||
|
useAction: useRestoreSingleRecordAction,
|
||||||
|
},
|
||||||
|
restoreMultipleRecords: {
|
||||||
|
type: ActionMenuEntryType.Standard,
|
||||||
|
scope: ActionMenuEntryScope.RecordSelection,
|
||||||
|
key: MultipleRecordsActionKeys.RESTORE,
|
||||||
|
label: msg`Restore records`,
|
||||||
|
shortLabel: msg`Restore`,
|
||||||
|
position: 16,
|
||||||
|
Icon: IconRefresh,
|
||||||
|
accent: 'default',
|
||||||
|
isPinned: true,
|
||||||
|
availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION],
|
||||||
|
useAction: useRestoreMultipleRecordsAction,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -347,4 +347,34 @@ export const WORKFLOW_ACTIONS_CONFIG: Record<
|
|||||||
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
|
availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION],
|
||||||
useAction: useImportRecordsNoSelectionRecordAction,
|
useAction: useImportRecordsNoSelectionRecordAction,
|
||||||
},
|
},
|
||||||
|
// TODO: uncomment when restore is implemented for workflows
|
||||||
|
// restoreSingleRecord: {
|
||||||
|
// type: ActionMenuEntryType.Standard,
|
||||||
|
// scope: ActionMenuEntryScope.RecordSelection,
|
||||||
|
// key: SingleRecordActionKeys.RESTORE,
|
||||||
|
// label: msg`Restore workflow`,
|
||||||
|
// shortLabel: msg`Restore`,
|
||||||
|
// position: 15,
|
||||||
|
// Icon: IconRefresh,
|
||||||
|
// accent: 'default',
|
||||||
|
// isPinned: true,
|
||||||
|
// availableOn: [
|
||||||
|
// ActionViewType.INDEX_PAGE_SINGLE_RECORD_SELECTION,
|
||||||
|
// ActionViewType.SHOW_PAGE,
|
||||||
|
// ],
|
||||||
|
// useAction: useRestoreSingleRecordAction,
|
||||||
|
// },
|
||||||
|
// restoreMultipleRecords: {
|
||||||
|
// type: ActionMenuEntryType.Standard,
|
||||||
|
// scope: ActionMenuEntryScope.RecordSelection,
|
||||||
|
// key: MultipleRecordsActionKeys.RESTORE,
|
||||||
|
// label: msg`Restore workflows`,
|
||||||
|
// shortLabel: msg`Restore`,
|
||||||
|
// position: 16,
|
||||||
|
// Icon: IconRefresh,
|
||||||
|
// accent: 'default',
|
||||||
|
// isPinned: true,
|
||||||
|
// availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION],
|
||||||
|
// useAction: useRestoreMultipleRecordsAction,
|
||||||
|
// },
|
||||||
};
|
};
|
||||||
|
|||||||
@ -115,7 +115,7 @@ export const useDeleteMultipleRecordsAction: ActionHookWithObjectMetadataItem =
|
|||||||
title={'Delete Records'}
|
title={'Delete Records'}
|
||||||
subtitle={`Are you sure you want to delete these records? They can be recovered from the Options menu.`}
|
subtitle={`Are you sure you want to delete these records? They can be recovered from the Options menu.`}
|
||||||
onConfirmClick={handleDeleteClick}
|
onConfirmClick={handleDeleteClick}
|
||||||
deleteButtonText={'Delete Records'}
|
confirmButtonText={'Delete Records'}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -126,7 +126,7 @@ export const useDestroyMultipleRecordsAction: ActionHookWithObjectMetadataItem =
|
|||||||
"Are you sure you want to destroy these records? They won't be recoverable anymore."
|
"Are you sure you want to destroy these records? They won't be recoverable anymore."
|
||||||
}
|
}
|
||||||
onConfirmClick={handleDestroyClick}
|
onConfirmClick={handleDestroyClick}
|
||||||
deleteButtonText={'Destroy Records'}
|
confirmButtonText={'Destroy Records'}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,135 @@
|
|||||||
|
import { useCallback, useState } from 'react';
|
||||||
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
|
import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/ActionHook';
|
||||||
|
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||||
|
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
|
||||||
|
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
|
||||||
|
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||||
|
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 { RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||||
|
import { useLazyFetchAllRecords } from '@/object-record/hooks/useLazyFetchAllRecords';
|
||||||
|
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 { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
|
||||||
|
import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId';
|
||||||
|
import { useHasObjectReadOnlyPermission } from '@/settings/roles/hooks/useHasObjectReadOnlyPermission';
|
||||||
|
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
|
||||||
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
|
||||||
|
export const useRestoreMultipleRecordsAction: ActionHookWithObjectMetadataItem =
|
||||||
|
({ objectMetadataItem }) => {
|
||||||
|
const [isRestoreRecordsModalOpen, setIsRestoreRecordsModalOpen] =
|
||||||
|
useState(false);
|
||||||
|
|
||||||
|
const contextStoreCurrentViewId = useRecoilComponentValueV2(
|
||||||
|
contextStoreCurrentViewIdComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!contextStoreCurrentViewId) {
|
||||||
|
throw new Error('Current view ID is not defined');
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasObjectReadOnlyPermission = useHasObjectReadOnlyPermission();
|
||||||
|
|
||||||
|
const { resetTableRowSelection } = useRecordTable({
|
||||||
|
recordTableId: getRecordIndexIdFromObjectNamePluralAndViewId(
|
||||||
|
objectMetadataItem.namePlural,
|
||||||
|
contextStoreCurrentViewId,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
const { restoreManyRecords } = useRestoreManyRecords({
|
||||||
|
objectNameSingular: objectMetadataItem.nameSingular,
|
||||||
|
});
|
||||||
|
|
||||||
|
const contextStoreNumberOfSelectedRecords = useRecoilComponentValueV2(
|
||||||
|
contextStoreNumberOfSelectedRecordsComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const contextStoreTargetedRecordsRule = useRecoilComponentValueV2(
|
||||||
|
contextStoreTargetedRecordsRuleComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const contextStoreFilters = useRecoilComponentValueV2(
|
||||||
|
contextStoreFiltersComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { filterValueDependencies } = useFilterValueDependencies();
|
||||||
|
|
||||||
|
const deletedAtFilter: RecordGqlOperationFilter = {
|
||||||
|
deletedAt: { is: 'NOT_NULL' },
|
||||||
|
};
|
||||||
|
|
||||||
|
const graphqlFilter = {
|
||||||
|
...computeContextStoreFilters(
|
||||||
|
contextStoreTargetedRecordsRule,
|
||||||
|
contextStoreFilters,
|
||||||
|
objectMetadataItem,
|
||||||
|
filterValueDependencies,
|
||||||
|
),
|
||||||
|
...deletedAtFilter,
|
||||||
|
};
|
||||||
|
|
||||||
|
const { checkIsSoftDeleteFilter } = useCheckIsSoftDeleteFilter();
|
||||||
|
|
||||||
|
const isDeletedFilterActive = contextStoreFilters.some(
|
||||||
|
checkIsSoftDeleteFilter,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { fetchAllRecords: fetchAllRecordIds } = useLazyFetchAllRecords({
|
||||||
|
objectNameSingular: objectMetadataItem.nameSingular,
|
||||||
|
filter: graphqlFilter,
|
||||||
|
limit: DEFAULT_QUERY_PAGE_SIZE,
|
||||||
|
recordGqlFields: { id: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleRestoreClick = useCallback(async () => {
|
||||||
|
const recordsToRestore = await fetchAllRecordIds();
|
||||||
|
const recordIdsToRestore = recordsToRestore.map((record) => record.id);
|
||||||
|
|
||||||
|
resetTableRowSelection();
|
||||||
|
|
||||||
|
await restoreManyRecords({
|
||||||
|
idsToRestore: recordIdsToRestore,
|
||||||
|
});
|
||||||
|
}, [restoreManyRecords, fetchAllRecordIds, resetTableRowSelection]);
|
||||||
|
|
||||||
|
const isRemoteObject = objectMetadataItem.isRemote;
|
||||||
|
|
||||||
|
const shouldBeRegistered =
|
||||||
|
!hasObjectReadOnlyPermission &&
|
||||||
|
!isRemoteObject &&
|
||||||
|
isDeletedFilterActive &&
|
||||||
|
isDefined(contextStoreNumberOfSelectedRecords) &&
|
||||||
|
contextStoreNumberOfSelectedRecords < BACKEND_BATCH_REQUEST_MAX_COUNT &&
|
||||||
|
contextStoreNumberOfSelectedRecords > 0;
|
||||||
|
|
||||||
|
const onClick = () => {
|
||||||
|
if (!shouldBeRegistered) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsRestoreRecordsModalOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const confirmationModal = (
|
||||||
|
<ConfirmationModal
|
||||||
|
isOpen={isRestoreRecordsModalOpen}
|
||||||
|
setIsOpen={setIsRestoreRecordsModalOpen}
|
||||||
|
title={'Restore Records'}
|
||||||
|
subtitle={`Are you sure you want to restore these records?`}
|
||||||
|
onConfirmClick={handleRestoreClick}
|
||||||
|
confirmButtonText={'Restore Records'}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
shouldBeRegistered,
|
||||||
|
onClick,
|
||||||
|
ConfirmationModal: confirmationModal,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -2,4 +2,5 @@ export enum MultipleRecordsActionKeys {
|
|||||||
DELETE = 'delete-multiple-records',
|
DELETE = 'delete-multiple-records',
|
||||||
EXPORT = 'export-multiple-records',
|
EXPORT = 'export-multiple-records',
|
||||||
DESTROY = 'destroy-multiple-records',
|
DESTROY = 'destroy-multiple-records',
|
||||||
|
RESTORE = 'restore-multiple-records',
|
||||||
}
|
}
|
||||||
|
|||||||
@ -93,7 +93,7 @@ export const useDeleteSingleRecordAction: ActionHookWithObjectMetadataItem = ({
|
|||||||
closeRightDrawer({ emitCloseEvent: false });
|
closeRightDrawer({ emitCloseEvent: false });
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
deleteButtonText={'Delete Record'}
|
confirmButtonText={'Delete Record'}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|||||||
@ -86,7 +86,7 @@ export const useDestroySingleRecordAction: ActionHookWithObjectMetadataItem = ({
|
|||||||
closeRightDrawer();
|
closeRightDrawer();
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
deleteButtonText={'Permanently Destroy Record'}
|
confirmButtonText={'Permanently Destroy Record'}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,95 @@
|
|||||||
|
import { useSelectedRecordIdOrThrow } from '@/action-menu/actions/record-actions/single-record/hooks/useSelectedRecordIdOrThrow';
|
||||||
|
import { ActionHookWithObjectMetadataItem } from '@/action-menu/actions/types/ActionHook';
|
||||||
|
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
|
||||||
|
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
||||||
|
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
|
||||||
|
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 { isSoftDeleteFilterActiveComponentState } from '@/object-record/record-table/states/isSoftDeleteFilterActiveComponentState';
|
||||||
|
import { useHasObjectReadOnlyPermission } from '@/settings/roles/hooks/useHasObjectReadOnlyPermission';
|
||||||
|
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
|
||||||
|
import { useRightDrawer } from '@/ui/layout/right-drawer/hooks/useRightDrawer';
|
||||||
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
import { useCallback, useContext, useState } from 'react';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
|
export const useRestoreSingleRecordAction: ActionHookWithObjectMetadataItem = ({
|
||||||
|
objectMetadataItem,
|
||||||
|
}) => {
|
||||||
|
const recordId = useSelectedRecordIdOrThrow();
|
||||||
|
|
||||||
|
const [isRestoreRecordModalOpen, setIsRestoreRecordModalOpen] =
|
||||||
|
useState(false);
|
||||||
|
|
||||||
|
const hasObjectReadOnlyPermission = useHasObjectReadOnlyPermission();
|
||||||
|
|
||||||
|
const { resetTableRowSelection } = useRecordTable({
|
||||||
|
recordTableId: objectMetadataItem.namePlural,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { restoreManyRecords } = useRestoreManyRecords({
|
||||||
|
objectNameSingular: objectMetadataItem.nameSingular,
|
||||||
|
});
|
||||||
|
|
||||||
|
const selectedRecord = useRecoilValue(recordStoreFamilyState(recordId));
|
||||||
|
|
||||||
|
const { closeRightDrawer } = useRightDrawer();
|
||||||
|
|
||||||
|
const handleRestoreClick = useCallback(async () => {
|
||||||
|
resetTableRowSelection();
|
||||||
|
|
||||||
|
await restoreManyRecords({
|
||||||
|
idsToRestore: [recordId],
|
||||||
|
});
|
||||||
|
}, [restoreManyRecords, resetTableRowSelection, recordId]);
|
||||||
|
|
||||||
|
const isRemoteObject = objectMetadataItem.isRemote;
|
||||||
|
|
||||||
|
const isSoftDeleteFilterActive = useRecoilComponentValueV2(
|
||||||
|
isSoftDeleteFilterActiveComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const isShowPage =
|
||||||
|
useRecoilComponentValueV2(contextStoreCurrentViewTypeComponentState) ===
|
||||||
|
ContextStoreViewType.ShowPage;
|
||||||
|
|
||||||
|
const { isInRightDrawer } = useContext(ActionMenuContext);
|
||||||
|
|
||||||
|
const shouldBeRegistered =
|
||||||
|
!isRemoteObject &&
|
||||||
|
isDefined(selectedRecord?.deletedAt) &&
|
||||||
|
!hasObjectReadOnlyPermission &&
|
||||||
|
(isShowPage || isSoftDeleteFilterActive);
|
||||||
|
|
||||||
|
const onClick = () => {
|
||||||
|
if (!shouldBeRegistered) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsRestoreRecordModalOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleConfirmClick = () => {
|
||||||
|
handleRestoreClick();
|
||||||
|
if (isInRightDrawer) {
|
||||||
|
closeRightDrawer({ emitCloseEvent: false });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
shouldBeRegistered,
|
||||||
|
onClick,
|
||||||
|
ConfirmationModal: (
|
||||||
|
<ConfirmationModal
|
||||||
|
isOpen={isRestoreRecordModalOpen}
|
||||||
|
setIsOpen={setIsRestoreRecordModalOpen}
|
||||||
|
title={'Restore Record'}
|
||||||
|
subtitle={'Are you sure you want to restore this record?'}
|
||||||
|
onConfirmClick={handleConfirmClick}
|
||||||
|
confirmButtonText={'Restore Record'}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -7,4 +7,5 @@ export enum SingleRecordActionKeys {
|
|||||||
NAVIGATE_TO_PREVIOUS_RECORD = 'navigate-to-previous-record-single-record',
|
NAVIGATE_TO_PREVIOUS_RECORD = 'navigate-to-previous-record-single-record',
|
||||||
EXPORT_NOTE_TO_PDF = 'export-note-to-pdf-single-record',
|
EXPORT_NOTE_TO_PDF = 'export-note-to-pdf-single-record',
|
||||||
EXPORT = 'export-single-record',
|
EXPORT = 'export-single-record',
|
||||||
|
RESTORE = 'restore-single-record',
|
||||||
}
|
}
|
||||||
|
|||||||
@ -218,7 +218,7 @@ export const CurrentWorkspaceMemberFavorites = ({
|
|||||||
title={`Remove ${folder.favorites.length} ${folder.favorites.length > 1 ? 'favorites' : 'favorite'}?`}
|
title={`Remove ${folder.favorites.length} ${folder.favorites.length > 1 ? 'favorites' : 'favorite'}?`}
|
||||||
subtitle={`This action will delete this favorite folder ${folder.favorites.length > 1 ? `and all ${folder.favorites.length} favorites` : 'and the favorite'} inside. Do you want to continue?`}
|
subtitle={`This action will delete this favorite folder ${folder.favorites.length > 1 ? `and all ${folder.favorites.length} favorites` : 'and the favorite'} inside. Do you want to continue?`}
|
||||||
onConfirmClick={handleConfirmDelete}
|
onConfirmClick={handleConfirmDelete}
|
||||||
deleteButtonText="Delete Folder"
|
confirmButtonText="Delete Folder"
|
||||||
/>,
|
/>,
|
||||||
document.body,
|
document.body,
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -30,9 +30,9 @@ export const RecordGroupReorderConfirmationModal = ({
|
|||||||
isOpen={isRecordGroupReorderConfirmationModalVisible}
|
isOpen={isRecordGroupReorderConfirmationModalVisible}
|
||||||
setIsOpen={setIsRecordGroupReorderConfirmationModalVisible}
|
setIsOpen={setIsRecordGroupReorderConfirmationModalVisible}
|
||||||
title="Group sorting"
|
title="Group sorting"
|
||||||
subtitle={`Would you like to remove ${recordGroupSort} group sorting ?`}
|
subtitle={`Would you like to remove ${recordGroupSort} group sorting?`}
|
||||||
onConfirmClick={onConfirmClick}
|
onConfirmClick={onConfirmClick}
|
||||||
deleteButtonText="Remove"
|
confirmButtonText="Remove"
|
||||||
/>,
|
/>,
|
||||||
document.body,
|
document.body,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -2,19 +2,21 @@ import { useEffect } from 'react';
|
|||||||
|
|
||||||
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
|
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
|
||||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||||
|
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState';
|
|
||||||
import { hasUserSelectedAllRowsComponentState } from '@/object-record/record-table/record-table-row/states/hasUserSelectedAllRowsFamilyState';
|
import { hasUserSelectedAllRowsComponentState } from '@/object-record/record-table/record-table-row/states/hasUserSelectedAllRowsFamilyState';
|
||||||
import { selectedRowIdsComponentSelector } from '@/object-record/record-table/states/selectors/selectedRowIdsComponentSelector';
|
import { selectedRowIdsComponentSelector } from '@/object-record/record-table/states/selectors/selectedRowIdsComponentSelector';
|
||||||
import { unselectedRowIdsComponentSelector } from '@/object-record/record-table/states/selectors/unselectedRowIdsComponentSelector';
|
import { unselectedRowIdsComponentSelector } from '@/object-record/record-table/states/selectors/unselectedRowIdsComponentSelector';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
import { useRecoilValue } from 'recoil';
|
|
||||||
|
|
||||||
export const RecordIndexFiltersToContextStoreEffect = () => {
|
export const RecordIndexFiltersToContextStoreEffect = () => {
|
||||||
const { recordIndexId } = useRecordIndexContextOrThrow();
|
const { recordIndexId } = useRecordIndexContextOrThrow();
|
||||||
|
|
||||||
const recordIndexFilters = useRecoilValue(recordIndexFiltersState);
|
const recordIndexFilters = useRecoilComponentValueV2(
|
||||||
|
currentRecordFiltersComponentState,
|
||||||
|
recordIndexId,
|
||||||
|
);
|
||||||
|
|
||||||
const setContextStoreTargetedRecords = useSetRecoilComponentStateV2(
|
const setContextStoreTargetedRecords = useSetRecoilComponentStateV2(
|
||||||
contextStoreTargetedRecordsRuleComponentState,
|
contextStoreTargetedRecordsRuleComponentState,
|
||||||
|
|||||||
@ -31,9 +31,9 @@ export const RecordIndexRemoveSortingModal = () => {
|
|||||||
isOpen={isRemoveSortingModalOpen}
|
isOpen={isRemoveSortingModalOpen}
|
||||||
setIsOpen={setIsRemoveSortingModalOpen}
|
setIsOpen={setIsRemoveSortingModalOpen}
|
||||||
title={'Remove sorting?'}
|
title={'Remove sorting?'}
|
||||||
subtitle={<>This is required to enable manual row reordering.</>}
|
subtitle={'This is required to enable manual row reordering.'}
|
||||||
onConfirmClick={() => handleRemoveClick()}
|
onConfirmClick={handleRemoveClick}
|
||||||
deleteButtonText={'Remove Sorting'}
|
confirmButtonText={'Remove Sorting'}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -300,7 +300,7 @@ export const RecordDetailRelationRecordsListItem = ({
|
|||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
onConfirmClick={handleConfirmDelete}
|
onConfirmClick={handleConfirmDelete}
|
||||||
deleteButtonText={`Delete ${relationObjectTypeName}`}
|
confirmButtonText={`Delete ${relationObjectTypeName}`}
|
||||||
/>,
|
/>,
|
||||||
document.body,
|
document.body,
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -18,8 +18,8 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
|||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
|
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
|
||||||
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
|
|
||||||
import { Trans, useLingui } from '@lingui/react/macro';
|
import { Trans, useLingui } from '@lingui/react/macro';
|
||||||
|
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
|
||||||
|
|
||||||
type SettingsAccountsRowDropdownMenuProps = {
|
type SettingsAccountsRowDropdownMenuProps = {
|
||||||
account: ConnectedAccount;
|
account: ConnectedAccount;
|
||||||
@ -106,7 +106,7 @@ export const SettingsAccountsRowDropdownMenu = ({
|
|||||||
</Trans>
|
</Trans>
|
||||||
}
|
}
|
||||||
onConfirmClick={deleteAccount}
|
onConfirmClick={deleteAccount}
|
||||||
deleteButtonText={t`Delete account`}
|
confirmButtonText={t`Delete account`}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -50,7 +50,7 @@ export const DeleteAccount = () => {
|
|||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
onConfirmClick={deleteAccount}
|
onConfirmClick={deleteAccount}
|
||||||
deleteButtonText={t`Delete account`}
|
confirmButtonText={t`Delete account`}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -51,7 +51,7 @@ export const DeleteWorkspace = () => {
|
|||||||
</Trans>
|
</Trans>
|
||||||
}
|
}
|
||||||
onConfirmClick={deleteWorkspace}
|
onConfirmClick={deleteWorkspace}
|
||||||
deleteButtonText={t`Delete workspace`}
|
confirmButtonText={t`Delete workspace`}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -34,7 +34,7 @@ export const RoleAssignmentConfirmationModal = ({
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
onConfirmClick={onConfirm}
|
onConfirmClick={onConfirm}
|
||||||
deleteButtonText={t`Confirm`}
|
confirmButtonText={t`Confirm`}
|
||||||
confirmButtonAccent="blue"
|
confirmButtonAccent="blue"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -85,7 +85,7 @@ export const SettingsServerlessFunctionSettingsTab = ({
|
|||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
onConfirmClick={deleteFunction}
|
onConfirmClick={deleteFunction}
|
||||||
deleteButtonText="Delete function"
|
confirmButtonText="Delete function"
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -24,7 +24,7 @@ export type ConfirmationModalProps = {
|
|||||||
subtitle: ReactNode;
|
subtitle: ReactNode;
|
||||||
setIsOpen: (val: boolean) => void;
|
setIsOpen: (val: boolean) => void;
|
||||||
onConfirmClick: () => void;
|
onConfirmClick: () => void;
|
||||||
deleteButtonText?: string;
|
confirmButtonText?: string;
|
||||||
confirmationPlaceholder?: string;
|
confirmationPlaceholder?: string;
|
||||||
confirmationValue?: string;
|
confirmationValue?: string;
|
||||||
confirmButtonAccent?: ButtonAccent;
|
confirmButtonAccent?: ButtonAccent;
|
||||||
@ -70,7 +70,7 @@ export const ConfirmationModal = ({
|
|||||||
subtitle,
|
subtitle,
|
||||||
setIsOpen,
|
setIsOpen,
|
||||||
onConfirmClick,
|
onConfirmClick,
|
||||||
deleteButtonText = `Delete`,
|
confirmButtonText = 'Confirm',
|
||||||
confirmationValue,
|
confirmationValue,
|
||||||
confirmationPlaceholder,
|
confirmationPlaceholder,
|
||||||
confirmButtonAccent = 'danger',
|
confirmButtonAccent = 'danger',
|
||||||
@ -159,7 +159,7 @@ export const ConfirmationModal = ({
|
|||||||
onClick={handleConfirmClick}
|
onClick={handleConfirmClick}
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
accent={confirmButtonAccent}
|
accent={confirmButtonAccent}
|
||||||
title={deleteButtonText}
|
title={confirmButtonText}
|
||||||
disabled={!isValidValue || loading}
|
disabled={!isValidValue || loading}
|
||||||
fullWidth
|
fullWidth
|
||||||
dataTestId="confirmation-modal-confirm-button"
|
dataTestId="confirmation-modal-confirm-button"
|
||||||
|
|||||||
@ -18,7 +18,7 @@ export const Default: Story = {
|
|||||||
isOpen: true,
|
isOpen: true,
|
||||||
title: 'Pariatur labore.',
|
title: 'Pariatur labore.',
|
||||||
subtitle: 'Velit dolore aliquip laborum occaecat fugiat.',
|
subtitle: 'Velit dolore aliquip laborum occaecat fugiat.',
|
||||||
deleteButtonText: 'Delete',
|
confirmButtonText: 'Delete',
|
||||||
},
|
},
|
||||||
decorators: [ComponentDecorator],
|
decorators: [ComponentDecorator],
|
||||||
};
|
};
|
||||||
|
|||||||
@ -47,7 +47,7 @@ export const OverrideWorkflowDraftConfirmationModal = ({
|
|||||||
title="A draft already exists"
|
title="A draft already exists"
|
||||||
subtitle="A draft already exists for this workflow. Are you sure you want to erase it?"
|
subtitle="A draft already exists for this workflow. Are you sure you want to erase it?"
|
||||||
onConfirmClick={handleOverrideDraft}
|
onConfirmClick={handleOverrideDraft}
|
||||||
deleteButtonText={'Override Draft'}
|
confirmButtonText={'Override Draft'}
|
||||||
AdditionalButtons={
|
AdditionalButtons={
|
||||||
<StyledCenteredButton
|
<StyledCenteredButton
|
||||||
to={getAppPath(AppPath.RecordShowPage, {
|
to={getAppPath(AppPath.RecordShowPage, {
|
||||||
|
|||||||
@ -190,7 +190,7 @@ export const SettingsBilling = () => {
|
|||||||
` ${impact}`
|
` ${impact}`
|
||||||
}
|
}
|
||||||
onConfirmClick={switchInterval}
|
onConfirmClick={switchInterval}
|
||||||
deleteButtonText={t`Change ${to}`}
|
confirmButtonText={t`Change ${to}`}
|
||||||
confirmButtonAccent={'blue'}
|
confirmButtonAccent={'blue'}
|
||||||
/>
|
/>
|
||||||
</SubMenuTopBarContainer>
|
</SubMenuTopBarContainer>
|
||||||
|
|||||||
@ -329,7 +329,7 @@ export const SettingsWorkspaceMembers = () => {
|
|||||||
workspaceMemberToDelete &&
|
workspaceMemberToDelete &&
|
||||||
handleRemoveWorkspaceMember(workspaceMemberToDelete)
|
handleRemoveWorkspaceMember(workspaceMemberToDelete)
|
||||||
}
|
}
|
||||||
deleteButtonText={t`Delete account`}
|
confirmButtonText={t`Delete account`}
|
||||||
/>
|
/>
|
||||||
</SubMenuTopBarContainer>
|
</SubMenuTopBarContainer>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -260,7 +260,7 @@ export const SettingsDevelopersApiKeyDetail = () => {
|
|||||||
</Trans>
|
</Trans>
|
||||||
}
|
}
|
||||||
onConfirmClick={deleteIntegration}
|
onConfirmClick={deleteIntegration}
|
||||||
deleteButtonText={t`Delete`}
|
confirmButtonText={t`Delete`}
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
/>
|
/>
|
||||||
<ConfirmationModal
|
<ConfirmationModal
|
||||||
@ -277,7 +277,7 @@ export const SettingsDevelopersApiKeyDetail = () => {
|
|||||||
</Trans>
|
</Trans>
|
||||||
}
|
}
|
||||||
onConfirmClick={regenerateApiKey}
|
onConfirmClick={regenerateApiKey}
|
||||||
deleteButtonText={t`Regenerate key`}
|
confirmButtonText={t`Regenerate key`}
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -266,7 +266,7 @@ export const SettingsDevelopersWebhooksDetail = () => {
|
|||||||
</Trans>
|
</Trans>
|
||||||
}
|
}
|
||||||
onConfirmClick={deleteWebhook}
|
onConfirmClick={deleteWebhook}
|
||||||
deleteButtonText={t`Delete webhook`}
|
confirmButtonText={t`Delete webhook`}
|
||||||
/>
|
/>
|
||||||
</Section>
|
</Section>
|
||||||
</SettingsPageContainer>
|
</SettingsPageContainer>
|
||||||
|
|||||||
Reference in New Issue
Block a user