diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV1.ts b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV1.ts index b052bdacc..2580fa5f1 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV1.ts +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV1.ts @@ -1,5 +1,6 @@ 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 { useRestoreMultipleRecordsAction } from '@/action-menu/actions/record-actions/multiple-records/hooks/useRestoreMultipleRecordsAction'; 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 { 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 { useDeleteSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useDeleteSingleRecordAction'; 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 { ActionHook } from '@/action-menu/actions/types/ActionHook'; import { ActionViewType } from '@/action-menu/actions/types/ActionViewType'; @@ -21,6 +23,7 @@ import { IconFileImport, IconHeart, IconHeartOff, + IconRefresh, IconRotate2, IconTrash, } from 'twenty-ui'; @@ -127,13 +130,42 @@ export const DEFAULT_ACTIONS_CONFIG_V1: Record< availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], 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: { type: ActionMenuEntryType.Standard, scope: ActionMenuEntryScope.Object, key: NoSelectionRecordActionKeys.SEE_DELETED_RECORDS, label: msg`See deleted records`, shortLabel: msg`Deleted records`, - position: 7, + position: 9, Icon: IconRotate2, accent: 'default', isPinned: false, @@ -146,7 +178,7 @@ export const DEFAULT_ACTIONS_CONFIG_V1: Record< key: NoSelectionRecordActionKeys.IMPORT_RECORDS, label: msg`Import records`, shortLabel: msg`Import`, - position: 8, + position: 10, Icon: IconFileImport, accent: 'default', isPinned: false, diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV2.ts b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV2.ts index dbf340d39..1ff94fd43 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV2.ts +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/DefaultActionsConfigV2.ts @@ -1,6 +1,7 @@ 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 { 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 { useCreateNewTableRecordNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useCreateNewTableRecordNoSelectionRecordAction'; 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 { useNavigateToPreviousRecordSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useNavigateToPreviousRecordSingleRecordAction'; 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 { ActionHook } from '@/action-menu/actions/types/ActionHook'; import { ActionViewType } from '@/action-menu/actions/types/ActionViewType'; @@ -31,6 +33,7 @@ import { IconHeart, IconHeartOff, IconPlus, + IconRefresh, IconRotate2, IconTrash, IconTrashX, @@ -244,4 +247,33 @@ export const DEFAULT_ACTIONS_CONFIG_V2: Record< availableOn: [ActionViewType.INDEX_PAGE_BULK_SELECTION], 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, + }, }; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.ts b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.ts index 216b883e7..b25010e62 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.ts +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/constants/WorkflowActionsConfig.ts @@ -347,4 +347,34 @@ export const WORKFLOW_ACTIONS_CONFIG: Record< availableOn: [ActionViewType.INDEX_PAGE_NO_SELECTION], 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, + // }, }; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/hooks/useDeleteMultipleRecordsAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/hooks/useDeleteMultipleRecordsAction.tsx index dcd60c2f3..9795021e5 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/hooks/useDeleteMultipleRecordsAction.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/hooks/useDeleteMultipleRecordsAction.tsx @@ -115,7 +115,7 @@ export const useDeleteMultipleRecordsAction: ActionHookWithObjectMetadataItem = title={'Delete Records'} subtitle={`Are you sure you want to delete these records? They can be recovered from the Options menu.`} onConfirmClick={handleDeleteClick} - deleteButtonText={'Delete Records'} + confirmButtonText={'Delete Records'} /> ); diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/hooks/useDestroyMultipleRecordsAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/hooks/useDestroyMultipleRecordsAction.tsx index 060c07845..5647fc06b 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/hooks/useDestroyMultipleRecordsAction.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/hooks/useDestroyMultipleRecordsAction.tsx @@ -126,7 +126,7 @@ export const useDestroyMultipleRecordsAction: ActionHookWithObjectMetadataItem = "Are you sure you want to destroy these records? They won't be recoverable anymore." } onConfirmClick={handleDestroyClick} - deleteButtonText={'Destroy Records'} + confirmButtonText={'Destroy Records'} /> ); diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/hooks/useRestoreMultipleRecordsAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/hooks/useRestoreMultipleRecordsAction.tsx new file mode 100644 index 000000000..5f387a0a8 --- /dev/null +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/hooks/useRestoreMultipleRecordsAction.tsx @@ -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 = ( + + ); + + return { + shouldBeRegistered, + onClick, + ConfirmationModal: confirmationModal, + }; + }; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/types/MultipleRecordsActionKeys.ts b/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/types/MultipleRecordsActionKeys.ts index 2c52d9eab..bc9c148d1 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/types/MultipleRecordsActionKeys.ts +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/multiple-records/types/MultipleRecordsActionKeys.ts @@ -2,4 +2,5 @@ export enum MultipleRecordsActionKeys { DELETE = 'delete-multiple-records', EXPORT = 'export-multiple-records', DESTROY = 'destroy-multiple-records', + RESTORE = 'restore-multiple-records', } diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useDeleteSingleRecordAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useDeleteSingleRecordAction.tsx index ced7c172d..e37be1e1e 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useDeleteSingleRecordAction.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useDeleteSingleRecordAction.tsx @@ -93,7 +93,7 @@ export const useDeleteSingleRecordAction: ActionHookWithObjectMetadataItem = ({ closeRightDrawer({ emitCloseEvent: false }); } }} - deleteButtonText={'Delete Record'} + confirmButtonText={'Delete Record'} /> ), }; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useDestroySingleRecordAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useDestroySingleRecordAction.tsx index 0cd03ef53..ca017aef1 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useDestroySingleRecordAction.tsx +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useDestroySingleRecordAction.tsx @@ -86,7 +86,7 @@ export const useDestroySingleRecordAction: ActionHookWithObjectMetadataItem = ({ closeRightDrawer(); } }} - deleteButtonText={'Permanently Destroy Record'} + confirmButtonText={'Permanently Destroy Record'} /> ), }; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useRestoreSingleRecordAction.tsx b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useRestoreSingleRecordAction.tsx new file mode 100644 index 000000000..1462ba37d --- /dev/null +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/hooks/useRestoreSingleRecordAction.tsx @@ -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: ( + + ), + }; +}; diff --git a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/types/SingleRecordActionsKey.ts b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/types/SingleRecordActionsKey.ts index bca5bb107..019962423 100644 --- a/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/types/SingleRecordActionsKey.ts +++ b/packages/twenty-front/src/modules/action-menu/actions/record-actions/single-record/types/SingleRecordActionsKey.ts @@ -7,4 +7,5 @@ export enum SingleRecordActionKeys { NAVIGATE_TO_PREVIOUS_RECORD = 'navigate-to-previous-record-single-record', EXPORT_NOTE_TO_PDF = 'export-note-to-pdf-single-record', EXPORT = 'export-single-record', + RESTORE = 'restore-single-record', } diff --git a/packages/twenty-front/src/modules/favorites/components/CurrentWorkspaceMemberFavorites.tsx b/packages/twenty-front/src/modules/favorites/components/CurrentWorkspaceMemberFavorites.tsx index 25daccb38..c432de023 100644 --- a/packages/twenty-front/src/modules/favorites/components/CurrentWorkspaceMemberFavorites.tsx +++ b/packages/twenty-front/src/modules/favorites/components/CurrentWorkspaceMemberFavorites.tsx @@ -218,7 +218,7 @@ export const CurrentWorkspaceMemberFavorites = ({ 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?`} onConfirmClick={handleConfirmDelete} - deleteButtonText="Delete Folder" + confirmButtonText="Delete Folder" />, document.body, )} diff --git a/packages/twenty-front/src/modules/object-record/record-group/components/RecordGroupReorderConfirmationModal.tsx b/packages/twenty-front/src/modules/object-record/record-group/components/RecordGroupReorderConfirmationModal.tsx index 0a906ec1a..ab3a26520 100644 --- a/packages/twenty-front/src/modules/object-record/record-group/components/RecordGroupReorderConfirmationModal.tsx +++ b/packages/twenty-front/src/modules/object-record/record-group/components/RecordGroupReorderConfirmationModal.tsx @@ -30,9 +30,9 @@ export const RecordGroupReorderConfirmationModal = ({ isOpen={isRecordGroupReorderConfirmationModalVisible} setIsOpen={setIsRecordGroupReorderConfirmationModalVisible} title="Group sorting" - subtitle={`Would you like to remove ${recordGroupSort} group sorting ?`} + subtitle={`Would you like to remove ${recordGroupSort} group sorting?`} onConfirmClick={onConfirmClick} - deleteButtonText="Remove" + confirmButtonText="Remove" />, document.body, ); diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexFiltersToContextStoreEffect.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexFiltersToContextStoreEffect.tsx index d009c9c61..325cf8935 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexFiltersToContextStoreEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexFiltersToContextStoreEffect.tsx @@ -2,19 +2,21 @@ import { useEffect } from 'react'; import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState'; 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 { recordIndexFiltersState } from '@/object-record/record-index/states/recordIndexFiltersState'; import { hasUserSelectedAllRowsComponentState } from '@/object-record/record-table/record-table-row/states/hasUserSelectedAllRowsFamilyState'; import { selectedRowIdsComponentSelector } from '@/object-record/record-table/states/selectors/selectedRowIdsComponentSelector'; import { unselectedRowIdsComponentSelector } from '@/object-record/record-table/states/selectors/unselectedRowIdsComponentSelector'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; -import { useRecoilValue } from 'recoil'; export const RecordIndexFiltersToContextStoreEffect = () => { const { recordIndexId } = useRecordIndexContextOrThrow(); - const recordIndexFilters = useRecoilValue(recordIndexFiltersState); + const recordIndexFilters = useRecoilComponentValueV2( + currentRecordFiltersComponentState, + recordIndexId, + ); const setContextStoreTargetedRecords = useSetRecoilComponentStateV2( contextStoreTargetedRecordsRuleComponentState, diff --git a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRemoveSortingModal.tsx b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRemoveSortingModal.tsx index bf56d4962..da92e0b14 100644 --- a/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRemoveSortingModal.tsx +++ b/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexRemoveSortingModal.tsx @@ -31,9 +31,9 @@ export const RecordIndexRemoveSortingModal = () => { isOpen={isRemoveSortingModalOpen} setIsOpen={setIsRemoveSortingModalOpen} title={'Remove sorting?'} - subtitle={<>This is required to enable manual row reordering.} - onConfirmClick={() => handleRemoveClick()} - deleteButtonText={'Remove Sorting'} + subtitle={'This is required to enable manual row reordering.'} + onConfirmClick={handleRemoveClick} + confirmButtonText={'Remove Sorting'} /> ); diff --git a/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsListItem.tsx b/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsListItem.tsx index 3c03d53ee..407e0e0d6 100644 --- a/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsListItem.tsx +++ b/packages/twenty-front/src/modules/object-record/record-show/record-detail-section/components/RecordDetailRelationRecordsListItem.tsx @@ -300,7 +300,7 @@ export const RecordDetailRelationRecordsListItem = ({ } onConfirmClick={handleConfirmDelete} - deleteButtonText={`Delete ${relationObjectTypeName}`} + confirmButtonText={`Delete ${relationObjectTypeName}`} />, document.body, )} diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsRowDropdownMenu.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsRowDropdownMenu.tsx index abb8b5f99..bef28aa02 100644 --- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsRowDropdownMenu.tsx +++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsRowDropdownMenu.tsx @@ -18,8 +18,8 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal'; -import { useNavigateSettings } from '~/hooks/useNavigateSettings'; import { Trans, useLingui } from '@lingui/react/macro'; +import { useNavigateSettings } from '~/hooks/useNavigateSettings'; type SettingsAccountsRowDropdownMenuProps = { account: ConnectedAccount; @@ -106,7 +106,7 @@ export const SettingsAccountsRowDropdownMenu = ({ } onConfirmClick={deleteAccount} - deleteButtonText={t`Delete account`} + confirmButtonText={t`Delete account`} /> ); diff --git a/packages/twenty-front/src/modules/settings/profile/components/DeleteAccount.tsx b/packages/twenty-front/src/modules/settings/profile/components/DeleteAccount.tsx index 8973c2a26..b5b14342c 100644 --- a/packages/twenty-front/src/modules/settings/profile/components/DeleteAccount.tsx +++ b/packages/twenty-front/src/modules/settings/profile/components/DeleteAccount.tsx @@ -50,7 +50,7 @@ export const DeleteAccount = () => { } onConfirmClick={deleteAccount} - deleteButtonText={t`Delete account`} + confirmButtonText={t`Delete account`} /> ); diff --git a/packages/twenty-front/src/modules/settings/profile/components/DeleteWorkspace.tsx b/packages/twenty-front/src/modules/settings/profile/components/DeleteWorkspace.tsx index 363600596..9e2833ae3 100644 --- a/packages/twenty-front/src/modules/settings/profile/components/DeleteWorkspace.tsx +++ b/packages/twenty-front/src/modules/settings/profile/components/DeleteWorkspace.tsx @@ -51,7 +51,7 @@ export const DeleteWorkspace = () => { } onConfirmClick={deleteWorkspace} - deleteButtonText={t`Delete workspace`} + confirmButtonText={t`Delete workspace`} /> ); diff --git a/packages/twenty-front/src/modules/settings/roles/role-assignment/components/RoleAssignmentConfirmationModal.tsx b/packages/twenty-front/src/modules/settings/roles/role-assignment/components/RoleAssignmentConfirmationModal.tsx index 4f53eac02..83c3a1435 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-assignment/components/RoleAssignmentConfirmationModal.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-assignment/components/RoleAssignmentConfirmationModal.tsx @@ -34,7 +34,7 @@ export const RoleAssignmentConfirmationModal = ({ /> } onConfirmClick={onConfirm} - deleteButtonText={t`Confirm`} + confirmButtonText={t`Confirm`} confirmButtonAccent="blue" /> ); diff --git a/packages/twenty-front/src/modules/settings/serverless-functions/components/tabs/SettingsServerlessFunctionSettingsTab.tsx b/packages/twenty-front/src/modules/settings/serverless-functions/components/tabs/SettingsServerlessFunctionSettingsTab.tsx index d9fd86500..2c633d600 100644 --- a/packages/twenty-front/src/modules/settings/serverless-functions/components/tabs/SettingsServerlessFunctionSettingsTab.tsx +++ b/packages/twenty-front/src/modules/settings/serverless-functions/components/tabs/SettingsServerlessFunctionSettingsTab.tsx @@ -85,7 +85,7 @@ export const SettingsServerlessFunctionSettingsTab = ({ } onConfirmClick={deleteFunction} - deleteButtonText="Delete function" + confirmButtonText="Delete function" /> ); diff --git a/packages/twenty-front/src/modules/ui/layout/modal/components/ConfirmationModal.tsx b/packages/twenty-front/src/modules/ui/layout/modal/components/ConfirmationModal.tsx index 0ef913ea4..7c639f4b7 100644 --- a/packages/twenty-front/src/modules/ui/layout/modal/components/ConfirmationModal.tsx +++ b/packages/twenty-front/src/modules/ui/layout/modal/components/ConfirmationModal.tsx @@ -24,7 +24,7 @@ export type ConfirmationModalProps = { subtitle: ReactNode; setIsOpen: (val: boolean) => void; onConfirmClick: () => void; - deleteButtonText?: string; + confirmButtonText?: string; confirmationPlaceholder?: string; confirmationValue?: string; confirmButtonAccent?: ButtonAccent; @@ -70,7 +70,7 @@ export const ConfirmationModal = ({ subtitle, setIsOpen, onConfirmClick, - deleteButtonText = `Delete`, + confirmButtonText = 'Confirm', confirmationValue, confirmationPlaceholder, confirmButtonAccent = 'danger', @@ -159,7 +159,7 @@ export const ConfirmationModal = ({ onClick={handleConfirmClick} variant="secondary" accent={confirmButtonAccent} - title={deleteButtonText} + title={confirmButtonText} disabled={!isValidValue || loading} fullWidth dataTestId="confirmation-modal-confirm-button" diff --git a/packages/twenty-front/src/modules/ui/layout/modal/components/__stories__/ConfirmationModal.stories.tsx b/packages/twenty-front/src/modules/ui/layout/modal/components/__stories__/ConfirmationModal.stories.tsx index 004a9f19c..8eb6ac425 100644 --- a/packages/twenty-front/src/modules/ui/layout/modal/components/__stories__/ConfirmationModal.stories.tsx +++ b/packages/twenty-front/src/modules/ui/layout/modal/components/__stories__/ConfirmationModal.stories.tsx @@ -18,7 +18,7 @@ export const Default: Story = { isOpen: true, title: 'Pariatur labore.', subtitle: 'Velit dolore aliquip laborum occaecat fugiat.', - deleteButtonText: 'Delete', + confirmButtonText: 'Delete', }, decorators: [ComponentDecorator], }; diff --git a/packages/twenty-front/src/modules/workflow/components/OverrideWorkflowDraftConfirmationModal.tsx b/packages/twenty-front/src/modules/workflow/components/OverrideWorkflowDraftConfirmationModal.tsx index ac9c828b5..c976ec217 100644 --- a/packages/twenty-front/src/modules/workflow/components/OverrideWorkflowDraftConfirmationModal.tsx +++ b/packages/twenty-front/src/modules/workflow/components/OverrideWorkflowDraftConfirmationModal.tsx @@ -47,7 +47,7 @@ export const OverrideWorkflowDraftConfirmationModal = ({ title="A draft already exists" subtitle="A draft already exists for this workflow. Are you sure you want to erase it?" onConfirmClick={handleOverrideDraft} - deleteButtonText={'Override Draft'} + confirmButtonText={'Override Draft'} AdditionalButtons={ { ` ${impact}` } onConfirmClick={switchInterval} - deleteButtonText={t`Change ${to}`} + confirmButtonText={t`Change ${to}`} confirmButtonAccent={'blue'} /> diff --git a/packages/twenty-front/src/pages/settings/SettingsWorkspaceMembers.tsx b/packages/twenty-front/src/pages/settings/SettingsWorkspaceMembers.tsx index 9c9c95ca4..9a6641b1b 100644 --- a/packages/twenty-front/src/pages/settings/SettingsWorkspaceMembers.tsx +++ b/packages/twenty-front/src/pages/settings/SettingsWorkspaceMembers.tsx @@ -329,7 +329,7 @@ export const SettingsWorkspaceMembers = () => { workspaceMemberToDelete && handleRemoveWorkspaceMember(workspaceMemberToDelete) } - deleteButtonText={t`Delete account`} + confirmButtonText={t`Delete account`} /> ); diff --git a/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx b/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx index 5c4d92284..5f77fb5fb 100644 --- a/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx +++ b/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail.tsx @@ -260,7 +260,7 @@ export const SettingsDevelopersApiKeyDetail = () => { } onConfirmClick={deleteIntegration} - deleteButtonText={t`Delete`} + confirmButtonText={t`Delete`} loading={isLoading} /> { } onConfirmClick={regenerateApiKey} - deleteButtonText={t`Regenerate key`} + confirmButtonText={t`Regenerate key`} loading={isLoading} /> diff --git a/packages/twenty-front/src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx b/packages/twenty-front/src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx index ab3950bd2..52b21e17f 100644 --- a/packages/twenty-front/src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx +++ b/packages/twenty-front/src/pages/settings/developers/webhooks/components/SettingsDevelopersWebhookDetail.tsx @@ -266,7 +266,7 @@ export const SettingsDevelopersWebhooksDetail = () => { } onConfirmClick={deleteWebhook} - deleteButtonText={t`Delete webhook`} + confirmButtonText={t`Delete webhook`} />