Files
Danny White a5dcf3b57c feat(studio): rebuild pipeline health summary (#50445)
## What kind of change does this PR introduce?

Studio UI improvement.

## What is the current behavior?

Pipeline health is presented as a dense custom metrics panel with
repeated connection information and per-table lag details mixed into the
pipeline summary.

## What is the new behavior?

Moves the pipeline-level slot status, lag, WAL retention, and last
check-in into a standard detail section. It removes repeated connection
content and keeps table-specific state with the replicated tables.

| Before | After |
| --- | --- |
| <img width="1816" height="274" alt="CleanShot 2026-09-16 at 13 34
43@2x"
src="https://github.com/user-attachments/assets/eceed5bb-8af2-4a3b-83a9-7849f1554fbe"
/> | <img width="1830" height="506" alt="CleanShot 2026-09-16 at 13 34
15@2x"
src="https://github.com/user-attachments/assets/498c4390-17e2-45e5-a923-cb4a7cfd5978"
/> |

_Note that the page spacing may feel a bit funny. This is handled in
https://github.com/supabase/supabase/pull/49630_

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

## To test

1. Open `/project/<ref>/database/replication` and select a running
pipeline.
2. Confirm **Pipeline health** shows slot status, lag, WAL retention
remaining, and last check-in.
3. Confirm unlimited WAL retention is labelled **Unlimited** and a
caught-up pipeline is labelled **Caught up**.

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

## UI Improvements

- Added a dedicated Pipeline Health section summarizing WAL status, slot
status, and replication lag.
- Replaced the inline metrics layout with responsive detail cards and
clearer supporting descriptions.
- Added tooltips for lag values and relative reply times, including
precise timestamps.
- Updated lag labels and status indicators for improved clarity.
- Added concise explanations for reserved, extended, unreserved, lost,
and unknown WAL states.
- Improved presentation of pipeline details with optional contextual
descriptions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-17 14:52:46 +10:00

61 lines
2.4 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import dayjs from 'dayjs'
import { type ReactNode } from 'react'
import { SlotLagMetricKey } from './ReplicationPipelineStatus.types'
import { getFormattedLagValue } from './ReplicationPipelineStatus.utils'
export interface SlotLagField {
key: SlotLagMetricKey
label: string
type: 'bytes' | 'duration'
description: ReactNode
// Friendly label to show in place of a literal "0 bytes" when there's nothing to report.
zeroLabel?: string
// Friendly label to show when the value is null/absent (e.g. unlimited WAL retention).
nullLabel?: string
// Optional hover text for the value, derived from the raw value (e.g. an absolute timestamp).
getValueTooltip?: (value: number) => string
}
export const SLOT_LAG_FIELDS: SlotLagField[] = [
{
key: 'confirmed_flush_lsn_bytes',
// Same label as the list column. Scoped to the main slot's ongoing change stream, so "Caught
// up" stays true while tables are still doing their initial copy.
label: 'Lag',
type: 'bytes',
description:
'Changes still on their way to the destination, measured on the pipeline’s main slot. Tables in their initial sync use their own slots and aren’t counted.',
zeroLabel: 'Caught up',
},
{
key: 'safe_wal_size_bytes',
label: 'WAL retention remaining',
type: 'bytes',
description: (
<>
How much more WAL can accumulate before the replication slot is at risk of being lost.
Controlled by the <code className="text-code-inline">max_slot_wal_keep_size</code> setting.
</>
),
nullLabel: 'Unlimited',
},
{
key: 'reply_time_lag',
label: 'Last check-in',
type: 'duration',
description: 'Time since the pipeline last reported back to your database',
zeroLabel: 'Just now',
// reply_time_lag is "milliseconds ago", so the absolute time is now minus that, in local time.
getValueTooltip: (ms) => dayjs().subtract(ms, 'millisecond').format('MMM D, YYYY, h:mm:ss A'),
},
]
// Resolves a field's value into a display string (+ optional precise detail), honoring the
// friendly zero/null labels before falling back to the formatted byte/duration value.
export const getFieldDisplay = (field: SlotLagField, value: number | null | undefined) => {
if (value == null) return { display: field.nullLabel ?? 'n/a', detail: undefined }
if (field.zeroLabel && value === 0) return { display: field.zeroLabel, detail: undefined }
return getFormattedLagValue(field.type, value)
}