mirror of
https://github.com/supabase/supabase.git
synced 2026-09-22 13:37:53 +08:00
a4be167491
## What kind of change does this PR introduce? Bug fix and UI polish. ## What is the current behavior? The Warehouse Connect option repeats its own name, and a configured Warehouse has no direct route back to its management page. Warehouse table states also use badges instead of the status-dot pattern used by Replication, and a backfilling table can misleadingly appear as “Caught up”. ## What is the new behavior? - Describes Warehouse as an analytical endpoint and adds a low-emphasis “Manage Warehouse” link from the Connect sheet. - Shares Replication’s status-dot presentation with Warehouse while keeping feature-specific state mapping separate. - Shows replication lag only for live tables, so backfilling and “Caught up” are never presented together. | Before | After | | --- | --- | | <img width="1244" height="1156" alt="CleanShot 2026-09-18 at 14 03 49@2x" src="https://github.com/user-attachments/assets/60aa3496-6930-491a-af9e-9ffcfb035a0f" /> | <img width="1216" height="1214" alt="CleanShot 2026-09-18 at 14 04 33@2x" src="https://github.com/user-attachments/assets/84a8c80e-d8d1-4ee5-9cce-352d1f6477c2" /> | | <img width="1314" height="1414" alt="CleanShot 2026-09-18 at 14 02 50@2x" src="https://github.com/user-attachments/assets/8871a4a5-0543-4290-91a7-9da949ec4c49" /> | <img width="1308" height="1498" alt="CleanShot 2026-09-18 at 14 02 43@2x" src="https://github.com/user-attachments/assets/ac3fc6d1-5b4d-4a3a-8ab7-bb54025e2145" /> | ## To test 1. Open `/project/<ref>?showConnect=true&connectTab=warehouse` for a project with Warehouse configured. Confirm the mode subtitle says “Analytical endpoint”. Confirm the new “Manage Warehouse” button opens `/project/<ref>/integrations/warehouse/overview`. 2. Open `/project/<ref>/integrations/warehouse/overview` while a table is backfilling. Confirm it has a pulsing amber status dot and does not show “Caught up”. 3. Once the table is live, confirm it has a green “Live” status dot and its lag appears normally. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added clearer Warehouse setup progress messaging with a “View progress” action while setup is running. - Connection details are shown once the Warehouse is provisioned or has live tables. - Added a Cancel action when editing changed Warehouse table selections. - Updated table statuses with live, syncing, and warning indicators, including animated syncing states. - Lag details are displayed for live tables when available. - Renamed the Warehouse connection option to “Analytical endpoint.” - **Style** - Improved Warehouse management controls and table name readability. - Removed the table Size column from the Warehouse overview. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
153 lines
5.5 KiB
TypeScript
153 lines
5.5 KiB
TypeScript
import { useParams } from 'common'
|
|
import { TableEditor } from 'icons'
|
|
import { MoreVertical, RotateCcw } from 'lucide-react'
|
|
import Link from 'next/link'
|
|
import {
|
|
Button,
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuTrigger,
|
|
TableCell,
|
|
TableRow,
|
|
} from 'ui'
|
|
|
|
import { ErroredTableDetails } from '../ErroredTableDetails'
|
|
import { SlotLagMetrics as SlotLagMetricsType, TableState } from './ReplicationPipelineStatus.types'
|
|
import { getStatusConfig, getTableSyncLagLabel } from './ReplicationPipelineStatus.utils'
|
|
import { DropdownMenuItemTooltip } from '@/components/ui/DropdownMenuItemTooltip'
|
|
import { StateDot } from '@/components/ui/StateDot'
|
|
import { ReplicationPipelineTableStatus } from '@/data/replication/pipeline-replication-status-query'
|
|
|
|
interface TableReplicationRowProps {
|
|
table: ReplicationPipelineTableStatus
|
|
isRestarting: boolean
|
|
showDisabledState: boolean
|
|
disabledStateMessage: string
|
|
isAnyRestartInProgress: boolean
|
|
isPipelineStopped: boolean
|
|
onSelectRestart: () => void
|
|
onSelectShowError: () => void
|
|
}
|
|
|
|
export const TableReplicationRow = ({
|
|
table,
|
|
isRestarting,
|
|
showDisabledState,
|
|
disabledStateMessage,
|
|
isAnyRestartInProgress,
|
|
isPipelineStopped,
|
|
onSelectRestart,
|
|
onSelectShowError,
|
|
}: TableReplicationRowProps) => {
|
|
const { ref } = useParams()
|
|
const statusConfig = getStatusConfig(table.state as TableState['state'])
|
|
const tableName = `${table.schema}.${table.name}`
|
|
const canRestart = !showDisabledState && !isRestarting && !isAnyRestartInProgress
|
|
const pipelineAction = isPipelineStopped ? 'start' : 'restart'
|
|
|
|
const isErrorState = table.state.name === 'error'
|
|
const canShowError =
|
|
isErrorState && 'reason' in table.state && !showDisabledState && !isRestarting
|
|
// A table copying during the initial sync reports its own slot metrics. Shown as one line rather
|
|
// than a grid, so the detail survives without a table cell turning into a dashboard.
|
|
const syncLag = table.table_sync_lag as SlotLagMetricsType | null | undefined
|
|
const syncLagParts = syncLag == null ? undefined : getTableSyncLagLabel(syncLag)
|
|
const syncLagLabel =
|
|
syncLagParts !== undefined && syncLagParts.length > 0 ? syncLagParts.join(' · ') : undefined
|
|
// Status column already names the state (Copying, Queued, …). Prefer the sync line when we have
|
|
// one; keep the description only when it adds something the status label doesn't say.
|
|
const detailsLine =
|
|
syncLagLabel !== undefined ? syncLagLabel : isErrorState ? undefined : statusConfig.description
|
|
|
|
return (
|
|
<TableRow>
|
|
<TableCell>
|
|
<span className="text-foreground-lighter">{table.schema}.</span>
|
|
<span className="text-foreground">{table.name}</span>
|
|
</TableCell>
|
|
|
|
<TableCell>
|
|
{isRestarting ? (
|
|
<StateDot variant="warning" isPulsing>
|
|
Resetting
|
|
</StateDot>
|
|
) : showDisabledState ? (
|
|
<StateDot variant="default">Not available</StateDot>
|
|
) : (
|
|
<StateDot
|
|
variant={statusConfig.variant}
|
|
isPulsing={statusConfig.isPulsing}
|
|
pulseDelayMs={statusConfig.isPulsing ? (table.id % 8) * 55 : undefined}
|
|
>
|
|
{statusConfig.label}
|
|
</StateDot>
|
|
)}
|
|
</TableCell>
|
|
|
|
<TableCell>
|
|
{isRestarting ? (
|
|
<p className="text-sm text-foreground-lighter">
|
|
Resetting. The pipeline will {pipelineAction} automatically…
|
|
</p>
|
|
) : showDisabledState ? (
|
|
<p className="text-sm text-foreground-lighter">{disabledStateMessage}</p>
|
|
) : isErrorState ? (
|
|
<div className="flex flex-col gap-y-3 text-sm text-foreground-lighter">
|
|
<p>{statusConfig.description}.</p>
|
|
<ErroredTableDetails table={table} />
|
|
</div>
|
|
) : (
|
|
<p className="text-sm text-foreground-lighter">{detailsLine}</p>
|
|
)}
|
|
</TableCell>
|
|
|
|
<TableCell>
|
|
<div className="flex items-center justify-end gap-x-2">
|
|
{canShowError && (
|
|
<Button variant="default" onClick={onSelectShowError}>
|
|
View error
|
|
</Button>
|
|
)}
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger asChild>
|
|
<Button
|
|
variant="default"
|
|
className="px-1.25 hit-area-2"
|
|
aria-label={`Options for ${tableName}`}
|
|
icon={<MoreVertical />}
|
|
/>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent side="bottom" align="end" className="w-44">
|
|
<DropdownMenuItemTooltip
|
|
className="gap-x-2"
|
|
disabled={!canRestart}
|
|
onClick={onSelectRestart}
|
|
tooltip={{
|
|
content: {
|
|
side: 'left',
|
|
text: canRestart ? undefined : disabledStateMessage,
|
|
},
|
|
}}
|
|
>
|
|
<RotateCcw size={14} />
|
|
<span>Reset table</span>
|
|
</DropdownMenuItemTooltip>
|
|
<DropdownMenuItem className="gap-x-2" asChild>
|
|
<Link
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
href={`/project/${ref}/editor/${table.id}`}
|
|
>
|
|
<TableEditor size={14} />
|
|
<span>View in Table Editor</span>
|
|
</Link>
|
|
</DropdownMenuItem>
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
</div>
|
|
</TableCell>
|
|
</TableRow>
|
|
)
|
|
}
|