mirror of
https://github.com/supabase/supabase.git
synced 2026-10-06 09:55:06 +03:00
## 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 -->
105 lines
3.9 KiB
TypeScript
105 lines
3.9 KiB
TypeScript
import { type ReactNode } from 'react'
|
|
import { Card, CardContent, Tooltip, TooltipContent, TooltipTrigger } from 'ui'
|
|
import {
|
|
PageSection,
|
|
PageSectionContent,
|
|
PageSectionMeta,
|
|
PageSectionSummary,
|
|
PageSectionTitle,
|
|
} from 'ui-patterns/PageSection'
|
|
|
|
import { PIPELINE_DETAIL_GRID_CLASS_NAME, PipelineDetailItem } from './PipelineDetailItem'
|
|
import { type SlotLagMetrics as SlotLagMetricsType } from './ReplicationPipelineStatus.types'
|
|
import { getWalStatusMeta } from './ReplicationPipelineStatus.utils'
|
|
import { getFieldDisplay, SLOT_LAG_FIELDS } from './SlotLagMetrics'
|
|
import { SLOT_STATUS_TOOLTIP, SlotWalStatusValue } from './SlotStatus'
|
|
import { InlineLink } from '@/components/ui/InlineLink'
|
|
import { DOCS_URL } from '@/lib/constants'
|
|
|
|
interface PipelineHealthSectionProps {
|
|
/** Absent while the pipeline is stopped or failed and reports no slot metrics. */
|
|
metrics?: SlotLagMetricsType
|
|
/**
|
|
* Every notice about the pipeline's state, in priority order. This section is the single place
|
|
* they render, so a reader always finds "what needs my attention" at the top of Pipeline health.
|
|
*/
|
|
children?: ReactNode
|
|
}
|
|
|
|
export const PipelineHealthSection = ({ metrics, children }: PipelineHealthSectionProps) => {
|
|
const walStatusMeta = getWalStatusMeta(metrics?.wal_status)
|
|
|
|
return (
|
|
<PageSection>
|
|
<PageSectionMeta>
|
|
<PageSectionSummary>
|
|
<PageSectionTitle>Pipeline health</PageSectionTitle>
|
|
</PageSectionSummary>
|
|
</PageSectionMeta>
|
|
|
|
<PageSectionContent className="flex flex-col gap-y-4">
|
|
{children}
|
|
|
|
{metrics !== undefined && (
|
|
<Card>
|
|
<CardContent className="pb-5">
|
|
<dl className={PIPELINE_DETAIL_GRID_CLASS_NAME}>
|
|
<PipelineDetailItem
|
|
label="Slot status"
|
|
tooltip={SLOT_STATUS_TOOLTIP}
|
|
description={
|
|
<>
|
|
{walStatusMeta.description}{' '}
|
|
<InlineLink
|
|
className="text-foreground-lighter hover:text-foreground"
|
|
href={`${DOCS_URL}/guides/database/replication/pipelines-monitoring#slot-statuses`}
|
|
>
|
|
Learn more
|
|
</InlineLink>
|
|
</>
|
|
}
|
|
>
|
|
<SlotWalStatusValue status={metrics.wal_status} />
|
|
</PipelineDetailItem>
|
|
|
|
{SLOT_LAG_FIELDS.map((field) => {
|
|
const rawValue = metrics[field.key]
|
|
const { display, detail } = getFieldDisplay(field, rawValue)
|
|
const valueTooltip =
|
|
field.getValueTooltip && typeof rawValue === 'number'
|
|
? field.getValueTooltip(rawValue)
|
|
: undefined
|
|
|
|
return (
|
|
<PipelineDetailItem
|
|
key={field.key}
|
|
label={field.label}
|
|
tooltip={field.description}
|
|
>
|
|
{valueTooltip !== undefined ? (
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<span className="w-fit cursor-default">{display}</span>
|
|
</TooltipTrigger>
|
|
<TooltipContent side="bottom" className="text-xs">
|
|
{valueTooltip}
|
|
</TooltipContent>
|
|
</Tooltip>
|
|
) : (
|
|
display
|
|
)}
|
|
{detail !== undefined && (
|
|
<span className="block text-xs text-foreground-lighter">{detail}</span>
|
|
)}
|
|
</PipelineDetailItem>
|
|
)
|
|
})}
|
|
</dl>
|
|
</CardContent>
|
|
</Card>
|
|
)}
|
|
</PageSectionContent>
|
|
</PageSection>
|
|
)
|
|
}
|