mirror of
https://github.com/supabase/supabase.git
synced 2026-10-06 01:45:10 +03:00
## What kind of change does this PR introduce? Studio UI improvement. ## What is the current behavior? The pipeline Overview uses bespoke loading, metrics, table-state and empty-state layouts that shift while data resolves and repeat status information from the detail header. ## What is the new behavior? Rebuilds the Overview around stable **Pipeline health** and **Replicated tables** sections. It adds layout-matched loading geometry, prioritised pipeline notices, initial-sync progress, clearer empty states, and accessible loading announcements. Complete pipeline configuration remains deferred to #49631. | Before | After | | --- | --- | | <img width="1024" height="759" alt="54861" src="https://github.com/user-attachments/assets/56e5cc5a-5d49-44c8-94d7-e1f1e0c827d5" /> | <img width="1024" height="759" alt="Replication Database Agua Basket Supabase" src="https://github.com/user-attachments/assets/43b6d0f6-6fd5-47f9-b3e5-788a33511304" /> | This is the final independent slice in the review series: #50443, #50444, #50445, #50446, then this PR. Each PR targets `master` and can merge on its own. Rebase this PR as earlier slices merge. ## To test 1. Open `/project/<ref>/database/replication` and select a pipeline. 2. Throttle the initial requests and confirm **Pipeline health** and **Replicated tables** keep their final geometry while loading. 3. Check running, initial-sync, stopped, failed, disconnected and unavailable states. 4. Confirm the Overview contains Pipeline health and Replicated tables only, without a Configuration section. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Reorganized replication pipeline status into Pipeline health and Replicated tables sections. - Added loading skeletons with accessible status announcements. - Added clearer notices for pipeline health, failed or disconnected pipelines, paused updates, lag, and synchronization progress. - Improved empty states when table data is unavailable or the pipeline is inactive. - Added options to view logs and reset failed tables. - **Tests** - Added coverage for loading behavior, pipeline notices, table counts, synchronization progress, and empty states. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
95 lines
3.0 KiB
TypeScript
95 lines
3.0 KiB
TypeScript
import { describe, expect, test } from 'vitest'
|
|
|
|
import {
|
|
getInitialSyncSummary,
|
|
getPipelineStateNotice,
|
|
getTableStatusEmptyState,
|
|
} from './PipelineOverview.utils'
|
|
import { PipelineStatusRequestStatus } from '@/state/replication-pipeline-request-status'
|
|
|
|
const disabledStateConfig = { title: 'Starting pipeline', message: 'This can take a moment.' }
|
|
const liveTables = (count: number) =>
|
|
Array.from({ length: count }, () => ({ state: { name: 'following_wal' as const } }))
|
|
|
|
describe('getTableStatusEmptyState', () => {
|
|
test.each([
|
|
[true, 'stopped' as const, 'Starting pipeline'],
|
|
[false, 'stopped' as const, 'Pipeline stopped'],
|
|
[false, 'failed' as const, 'Pipeline failed'],
|
|
[false, 'started' as const, 'No table data yet'],
|
|
])('returns the appropriate empty state', (isDisabled, statusName, title) => {
|
|
expect(getTableStatusEmptyState({ isDisabled, disabledStateConfig, statusName }).title).toBe(
|
|
title
|
|
)
|
|
})
|
|
})
|
|
|
|
describe('getPipelineStateNotice', () => {
|
|
test('omits a notice for a healthy running pipeline', () => {
|
|
expect(
|
|
getPipelineStateNotice({
|
|
requestStatus: PipelineStatusRequestStatus.None,
|
|
statusName: 'started',
|
|
tableStatuses: liveTables(3),
|
|
})
|
|
).toBeUndefined()
|
|
})
|
|
|
|
test.each([
|
|
['failed' as const, 'destructive', true],
|
|
['stopped' as const, 'note', false],
|
|
])('explains a %s pipeline', (statusName, type, showLogsLink) => {
|
|
expect(
|
|
getPipelineStateNotice({
|
|
requestStatus: PipelineStatusRequestStatus.None,
|
|
statusName,
|
|
tableStatuses: liveTables(3),
|
|
})
|
|
).toMatchObject({ type, showLogsLink })
|
|
})
|
|
|
|
test('reports a requested transition ahead of the API status', () => {
|
|
expect(
|
|
getPipelineStateNotice({
|
|
requestStatus: PipelineStatusRequestStatus.StartRequested,
|
|
statusName: 'stopped',
|
|
tableStatuses: liveTables(3),
|
|
})?.title
|
|
).toBe('Starting pipeline')
|
|
})
|
|
|
|
test('distinguishes copying tables from queued tables', () => {
|
|
expect(
|
|
getPipelineStateNotice({
|
|
requestStatus: PipelineStatusRequestStatus.None,
|
|
statusName: 'started',
|
|
tableStatuses: [
|
|
...liveTables(2),
|
|
{ state: { name: 'copying_table' as const } },
|
|
{ state: { name: 'queued' as const } },
|
|
],
|
|
})?.description
|
|
).toContain('1 of 4 tables is copying and 1 is waiting.')
|
|
})
|
|
})
|
|
|
|
describe('getInitialSyncSummary', () => {
|
|
test.each([
|
|
[4, 3, 8, '4 of 8 tables are copying and 3 are waiting.'],
|
|
[1, 1, 4, '1 of 4 tables is copying and 1 is waiting.'],
|
|
[2, 0, 8, '2 of 8 tables are copying.'],
|
|
[0, 3, 3, '3 tables are waiting to copy.'],
|
|
[1, 0, 1, '1 of 1 table is copying.'],
|
|
[0, 0, 2, 'The last tables are finishing their copy.'],
|
|
])('summarises initial sync progress', (copyingCount, queuedCount, totalCount, expected) => {
|
|
expect(
|
|
getInitialSyncSummary({
|
|
syncingCount: copyingCount + queuedCount,
|
|
copyingCount,
|
|
queuedCount,
|
|
totalCount,
|
|
})
|
|
).toBe(expected)
|
|
})
|
|
})
|