Repository: supabase/supabase
File: apps/studio/components/grid/hooks/useOperationQueueActions.ts (TypeScript)

Code before:
 * Hook that provides save and cancel actions for the operation queue.
 * Consolidates the logic used by both the useSaveQueueToast hook and OperationQueueSidePanel.
 */
export function useOperationQueueActions(options: UseOperationQueueActionsOptions = {}) {
  const { onSaveSuccess, onCancelSuccess } = options

  const queryClient = useQueryClient()
  const { data: project } = useSelectedProjectQuery()
  const snap = useTableEditorStateSnapshot()
  const getImpersonatedRoleState = useGetImpersonatedRoleState()

  const { mutate: saveOperationQueue, isPending: isMutationPending } =
    useOperationQueueSaveMutation({
      onSuccess: () => {
        snap.clearQueue()
        toast.success('Changes saved successfully')
        onSaveSuccess?.()
      },
      onError: (error) => {
        snap.setQueueStatus('idle')
        toast.error(`Failed to save changes: ${error.message}`)
      },
    })

  const isSaving = snap.operationQueue.status === 'saving' || isMutationPending

  const handleSave = useCallback(() => {
    if (!project) return

    const operations = snap.operationQueue.operations as readonly QueuedOperation[]
    if (operations.length === 0) return

    snap.setQueueStatus('saving')

    saveOperationQueue({
      projectRef: project.ref,
      connectionString: project.connectionString,
      operations,
      roleImpersonationState: getImpersonatedRoleState(),
    })
  }, [snap, project, saveOperationQueue, getImpersonatedRoleState])

  const handleCancel = useCallback(() => {
    // Get unique table IDs from the queue before clearing
    const operations = snap.operationQueue.operations as readonly QueuedOperation[]
    const tableIds = [...new Set(operations.map((op) => op.tableId))]

    // Clear the queue and invalidate queries to revert optimistic updates
    snap.clearQueue()
    if (project) {
      // Invalidate queries for each table that had pending operations

Review comment (suggestion):
@awaseem this is the main fix if you're interested. The previous code wasn't causing `snap.operationQueue.operations` to be tracked correctly with valtio

Code after:
 * Consolidates the logic used by both the useSaveQueueToast hook and OperationQueueSidePanel.
 */
export function useOperationQueueActions(options: UseOperationQueueActionsOptions = {}) {
  const { onSaveSuccess, onCancelSuccess } = options

  const queryClient = useQueryClient()
  const { data: project } = useSelectedProjectQuery()
  const snap = useTableEditorStateSnapshot()
  const getImpersonatedRoleState = useGetImpersonatedRoleState()

  const { mutate: saveOperationQueue, isPending: isMutationPending } =
    useOperationQueueSaveMutation({
      onSuccess: () => {
        snap.clearQueue()
        snap.closeSidePanel()
        toast.success('Changes saved successfully')
        onSaveSuccess?.()
      },
      onError: (error) => {
        snap.setQueueStatus('idle')
        toast.error(`Failed to save changes: ${error.message}`)
      },
    })

  const isSaving = snap.operationQueue.status === 'saving' || isMutationPending
  const operations = snap.operationQueue.operations as readonly QueuedOperation[]

  const handleSave = useCallback(() => {
    if (!project || operations.length === 0) return

    snap.setQueueStatus('saving')

    saveOperationQueue({
      projectRef: project.ref,
      connectionString: project.connectionString,
      operations,
      roleImpersonationState: getImpersonatedRoleState(),
    })
  }, [snap, project, operations, saveOperationQueue, getImpersonatedRoleState])

  const handleCancel = useCallback(() => {
    // Get unique table IDs from the queue before clearing
    const operations = snap.operationQueue.operations as readonly QueuedOperation[]
    const tableIds = [...new Set(operations.map((op) => op.tableId))]

    // Clear the queue and invalidate queries to revert optimistic updates
    snap.clearQueue()
    if (project) {
      // Invalidate queries for each table that had pending operations
      tableIds.forEach((tableId) => {
        queryClient.invalidateQueries({