Files
supabase/apps/studio/components/interfaces/Database/Replication/BatchRestartDialog.test.tsx
Danny White 0b002892d7 refactor(studio): simplify pipeline reset dialogs (#50443)
## What kind of change does this PR introduce?

Studio UI refactor.

## What is the current behavior?

Pipeline table reset dialogs repeat explanatory content and use more
layout than the reset decision needs.

## What is the new behavior?

Simplifies the single-table and batch reset confirmations while
preserving their cost estimate, destructive consequences, and existing
reset mutations.

| Before | After |
| --- | --- |
| <img width="854" height="1090" alt="CleanShot 2026-09-16 at 12 54
36@2x"
src="https://github.com/user-attachments/assets/f9eef09b-89d1-4747-bc4c-e81fb64c584b"
/> | <img width="840" height="742" alt="CleanShot 2026-09-16 at 17 01
11@2x"
src="https://github.com/user-attachments/assets/fa45728c-ec66-45c8-9fef-9d2eb8310d4d"
/> |

This is an independent slice extracted from #49630. The related review
series is this one, #50444, #50445, #50446, then #49630.

## To test

1. Open `/project/<ref>/database/replication` and select a pipeline.
2. Reset one replicated table and confirm the dialog explains that
destination data will be deleted and resynchronised.
3. Choose **Reset all tables** and confirm the batch dialog shows the
same concise treatment.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## UI Updates

* **UI Updates**
* Renamed replication “restart” actions to “reset” across dialogs,
buttons, notifications, and cost estimates.
* Updated messaging to clarify whether the pipeline will start or
restart automatically after resetting.
* Added clearer initial-sync guidance for all, some, or none of the
affected tables.
* Improved reset cost estimate messaging, including when no additional
initial-sync charge applies.
* Updated reset dialogs with clearer titles, descriptions, loading
states, and error messages.
  * Disabled reset actions when pipeline status is unavailable.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-17 12:13:51 +10:00

102 lines
3.1 KiB
TypeScript

import { act, fireEvent, render, screen } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'
import { BatchRestartDialog } from './BatchRestartDialog'
import { PipelineStatusName } from './Replication.constants'
import type { ReplicationPipelineTableStatus } from '@/data/replication/pipeline-replication-status-query'
const mocks = vi.hoisted(() => ({
rollbackTables: vi.fn().mockResolvedValue({ pipeline_id: 9, tables: [] }),
}))
vi.mock('common', () => ({
useParams: () => ({ ref: 'project-ref', pipelineId: '9' }),
}))
vi.mock('@/data/replication/rollback-tables-mutation', () => ({
useRollbackTablesMutation: () => ({
mutateAsync: mocks.rollbackTables,
isPending: false,
}),
}))
vi.mock('./RestartCostEstimate', () => ({
RestartCostEstimate: ({ tables }: { tables: { schema: string; name: string }[] }) => (
<div data-testid="copy-targets">
{tables.map(({ schema, name }) => `${schema}.${name}`).join(',')}
</div>
),
}))
const table = (
id: number,
state: ReplicationPipelineTableStatus['state']
): ReplicationPipelineTableStatus => ({
id,
schema: 'public',
name: `table_${id}`,
table_id: id,
table_name: `public.table_${id}`,
state,
})
describe('BatchRestartDialog', () => {
it('describes every table reset by the all-errored backend target', async () => {
const onRestartStart = vi.fn()
const tables = [
table(1, { name: 'error', reason: 'manual', retry_policy: { policy: 'manual_retry' } }),
table(2, { name: 'error', reason: 'terminal', retry_policy: { policy: 'no_retry' } }),
table(3, {
name: 'error',
reason: 'timed',
retry_policy: { policy: 'timed_retry', next_retry: '2026-07-21T12:00:00Z' },
}),
table(4, { name: 'following_wal' }),
]
render(
<BatchRestartDialog
open
onOpenChange={vi.fn()}
mode="errored"
tables={tables}
tableSyncCopy={{ type: 'include_tables', table_ids: [1, 2] }}
pipelineStatusName={PipelineStatusName.STARTED}
onRestartStart={onRestartStart}
/>
)
expect(screen.getByText(/This resets 3 failed tables/)).toBeInTheDocument()
expect(
screen.getByText(
/2 of 3 tables will sync existing rows again. The remaining 1 table will skip initial sync/
)
).toBeInTheDocument()
expect(screen.getByTestId('copy-targets')).toHaveTextContent('public.table_1,public.table_2')
await act(async () => {
fireEvent.click(screen.getByRole('button', { name: 'Reset failed tables' }))
})
expect(onRestartStart).toHaveBeenCalledWith([1, 2, 3])
expect(mocks.rollbackTables).toHaveBeenCalledWith(
expect.objectContaining({
pipelineId: 9,
target: { type: 'all_errored_tables' },
rollbackType: 'full',
})
)
})
it('prevents a reset when the pipeline status is unavailable', () => {
render(
<BatchRestartDialog
open
onOpenChange={vi.fn()}
mode="all"
tables={[table(1, { name: 'following_wal' })]}
/>
)
expect(screen.getByRole('button', { name: 'Reset all tables' })).toBeDisabled()
})
})