useOperationQueueActions.ts83 lines · main
1// @ts-nocheck
2import { useQueryClient } from '@tanstack/react-query'
3import { useCallback } from 'react'
4import { toast } from 'sonner'
5
6import { tableRowKeys } from '@/data/table-rows/keys'
7import { useOperationQueueSaveMutation } from '@/data/table-rows/operation-queue-save-mutation'
8import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
9import { useGetImpersonatedRoleState } from '@/state/role-impersonation-state'
10import { useTableEditorStateSnapshot } from '@/state/table-editor'
11import { QueuedOperation } from '@/state/table-editor-operation-queue.types'
12
13interface UseOperationQueueActionsOptions {
14 onSaveSuccess?: () => void
15 onCancelSuccess?: () => void
16}
17
18/**
19 * Hook that provides save and cancel actions for the operation queue.
20 * Consolidates the logic used by both the useSaveQueueToast hook and OperationQueueSidePanel.
21 */
22export function useOperationQueueActions(options: UseOperationQueueActionsOptions = {}) {
23 const { onSaveSuccess, onCancelSuccess } = options
24
25 const queryClient = useQueryClient()
26 const { data: project } = useSelectedProjectQuery()
27 const snap = useTableEditorStateSnapshot()
28 const getImpersonatedRoleState = useGetImpersonatedRoleState()
29
30 const { mutate: saveOperationQueue, isPending: isMutationPending } =
31 useOperationQueueSaveMutation({
32 onSuccess: () => {
33 snap.clearQueue()
34 snap.closeSidePanel()
35 toast.success('Changes saved successfully')
36 onSaveSuccess?.()
37 },
38 onError: (error) => {
39 snap.setQueueStatus('idle')
40 toast.error(`Failed to save changes: ${error.message}`)
41 },
42 })
43
44 const isSaving = snap.operationQueue.status === 'saving' || isMutationPending
45 const operations = snap.operationQueue.operations as readonly QueuedOperation[]
46
47 const handleSave = useCallback(() => {
48 if (!project || operations.length === 0) return
49
50 snap.setQueueStatus('saving')
51
52 saveOperationQueue({
53 projectRef: project.ref,
54 connectionString: project.connectionString,
55 operations,
56 roleImpersonationState: getImpersonatedRoleState(),
57 })
58 }, [snap, project, operations, saveOperationQueue, getImpersonatedRoleState])
59
60 const handleCancel = useCallback(() => {
61 // Get unique table IDs from the queue before clearing
62 const operations = snap.operationQueue.operations as readonly QueuedOperation[]
63 const tableIds = [...new Set(operations.map((op) => op.tableId))]
64
65 // Clear the queue and invalidate queries to revert optimistic updates
66 snap.clearQueue()
67 if (project) {
68 // Invalidate queries for each table that had pending operations
69 tableIds.forEach((tableId) => {
70 queryClient.invalidateQueries({
71 queryKey: tableRowKeys.tableRowsAndCount(project.ref, tableId),
72 })
73 })
74 }
75 onCancelSuccess?.()
76 }, [snap, project, queryClient, onCancelSuccess])
77
78 return {
79 handleSave,
80 handleCancel,
81 isSaving,
82 }
83}