Raphaël Bosi
2025-03-04 17:27:14 +01:00
committed by GitHub
parent d6171c66df
commit 9da973592d
28 changed files with 360 additions and 32 deletions

View File

@ -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,

View File

@ -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,
},
}; };

View File

@ -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,
// },
}; };

View File

@ -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'}
/> />
); );

View File

@ -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'}
/> />
); );

View File

@ -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,
};
};

View File

@ -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',
} }

View File

@ -93,7 +93,7 @@ export const useDeleteSingleRecordAction: ActionHookWithObjectMetadataItem = ({
closeRightDrawer({ emitCloseEvent: false }); closeRightDrawer({ emitCloseEvent: false });
} }
}} }}
deleteButtonText={'Delete Record'} confirmButtonText={'Delete Record'}
/> />
), ),
}; };

View File

@ -86,7 +86,7 @@ export const useDestroySingleRecordAction: ActionHookWithObjectMetadataItem = ({
closeRightDrawer(); closeRightDrawer();
} }
}} }}
deleteButtonText={'Permanently Destroy Record'} confirmButtonText={'Permanently Destroy Record'}
/> />
), ),
}; };

View File

@ -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'}
/>
),
};
};

View File

@ -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',
} }

View File

@ -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,
)} )}

View File

@ -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,
); );

View File

@ -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,

View File

@ -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'}
/> />
</> </>
); );

View File

@ -300,7 +300,7 @@ export const RecordDetailRelationRecordsListItem = ({
</> </>
} }
onConfirmClick={handleConfirmDelete} onConfirmClick={handleConfirmDelete}
deleteButtonText={`Delete ${relationObjectTypeName}`} confirmButtonText={`Delete ${relationObjectTypeName}`}
/>, />,
document.body, document.body,
)} )}

View File

@ -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`}
/> />
</> </>
); );

View File

@ -50,7 +50,7 @@ export const DeleteAccount = () => {
</> </>
} }
onConfirmClick={deleteAccount} onConfirmClick={deleteAccount}
deleteButtonText={t`Delete account`} confirmButtonText={t`Delete account`}
/> />
</> </>
); );

View File

@ -51,7 +51,7 @@ export const DeleteWorkspace = () => {
</Trans> </Trans>
} }
onConfirmClick={deleteWorkspace} onConfirmClick={deleteWorkspace}
deleteButtonText={t`Delete workspace`} confirmButtonText={t`Delete workspace`}
/> />
</> </>
); );

View File

@ -34,7 +34,7 @@ export const RoleAssignmentConfirmationModal = ({
/> />
} }
onConfirmClick={onConfirm} onConfirmClick={onConfirm}
deleteButtonText={t`Confirm`} confirmButtonText={t`Confirm`}
confirmButtonAccent="blue" confirmButtonAccent="blue"
/> />
); );

View File

@ -85,7 +85,7 @@ export const SettingsServerlessFunctionSettingsTab = ({
</> </>
} }
onConfirmClick={deleteFunction} onConfirmClick={deleteFunction}
deleteButtonText="Delete function" confirmButtonText="Delete function"
/> />
</> </>
); );

View File

@ -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"

View File

@ -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],
}; };

View File

@ -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, {

View File

@ -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>

View File

@ -329,7 +329,7 @@ export const SettingsWorkspaceMembers = () => {
workspaceMemberToDelete && workspaceMemberToDelete &&
handleRemoveWorkspaceMember(workspaceMemberToDelete) handleRemoveWorkspaceMember(workspaceMemberToDelete)
} }
deleteButtonText={t`Delete account`} confirmButtonText={t`Delete account`}
/> />
</SubMenuTopBarContainer> </SubMenuTopBarContainer>
); );

View File

@ -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}
/> />
</> </>

View File

@ -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>