diff --git a/apps/studio/components/grid/components/footer/operations/SaveQueueActionBar.tsx b/apps/studio/components/grid/components/footer/operations/SaveQueueActionBar.tsx index 4d35fa9ce2e..ee5d6cf1f66 100644 --- a/apps/studio/components/grid/components/footer/operations/SaveQueueActionBar.tsx +++ b/apps/studio/components/grid/components/footer/operations/SaveQueueActionBar.tsx @@ -2,6 +2,7 @@ import { useOperationQueueActions } from 'components/grid/hooks/useOperationQueu import { useOperationQueueShortcuts } from 'components/grid/hooks/useOperationQueueShortcuts' import { useIsQueueOperationsEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext' import { AnimatePresence, motion } from 'framer-motion' +import { useEffect, useState } from 'react' import { createPortal } from 'react-dom' import { useTableEditorStateSnapshot } from 'state/table-editor' import { Button } from 'ui' diff --git a/apps/studio/components/grid/hooks/useOperationQueueShortcuts.ts b/apps/studio/components/grid/hooks/useOperationQueueShortcuts.ts index d1503ea6750..1c1f3852df8 100644 --- a/apps/studio/components/grid/hooks/useOperationQueueShortcuts.ts +++ b/apps/studio/components/grid/hooks/useOperationQueueShortcuts.ts @@ -1,5 +1,9 @@ +import { useQueryClient } from '@tanstack/react-query' + import { useOperationQueueActions } from './useOperationQueueActions' import { useIsQueueOperationsEnabled } from '@/components/interfaces/App/FeaturePreview/FeaturePreviewContext' +import { tableRowKeys } from '@/data/table-rows/keys' +import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' import { useHotKey } from '@/hooks/ui/useHotKey' import { useTableEditorStateSnapshot } from '@/state/table-editor' @@ -14,6 +18,8 @@ import { useTableEditorStateSnapshot } from '@/state/table-editor' * before the data grid handles the keyboard event. */ export function useOperationQueueShortcuts() { + const queryClient = useQueryClient() + const { data: project } = useSelectedProjectQuery() const isQueueOperationsEnabled = useIsQueueOperationsEnabled() const snap = useTableEditorStateSnapshot() const { handleSave } = useOperationQueueActions() @@ -43,4 +49,23 @@ export function useOperationQueueShortcuts() { '.', { enabled: isEnabled } ) + + useHotKey( + (event) => { + event.preventDefault() + event.stopPropagation() + + const tableIdLatestOperation = snap.operationQueue.operations.at(-1)?.tableId + snap.undoLatestOperation() + + // Invalidate the query to revert the optimistic update + if (project && tableIdLatestOperation) { + queryClient.invalidateQueries({ + queryKey: tableRowKeys.tableRowsAndCount(project.ref, tableIdLatestOperation), + }) + } + }, + 'z', + { enabled: isEnabled } + ) } diff --git a/apps/studio/state/table-editor.tsx b/apps/studio/state/table-editor.tsx index f8b2df8a3be..1a0453b0eca 100644 --- a/apps/studio/state/table-editor.tsx +++ b/apps/studio/state/table-editor.tsx @@ -1,5 +1,5 @@ -import type { PostgresColumn } from '@supabase/postgres-meta' import * as Sentry from '@sentry/nextjs' +import type { PostgresColumn } from '@supabase/postgres-meta' import { useConstant } from 'common' import type { SupaRow } from 'components/grid/types' import { @@ -308,6 +308,16 @@ export const createTableEditorState = () => { } }, + /** + * Undo the latest operation from the queue + */ + undoLatestOperation: () => { + state.operationQueue.operations = state.operationQueue.operations.slice(0, -1) + if (state.operationQueue.operations.length === 0) { + state.operationQueue.status = 'idle' + } + }, + /** * Update the queue status */