mirror of
https://github.com/supabase/supabase.git
synced 2026-10-06 18:05:11 +03:00
## 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 -->
102 lines
3.1 KiB
TypeScript
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()
|
|
})
|
|
})
|