Files
Danny WhiteandJoshen Lim 205527c716 feat(studio): tune up replication page layout and empty state (#48265)
## What kind of change does this PR introduce?

UI polish for Database → Replication: empty state, page layout, diagram
containment, filter actions, and destination sheet copy.

## What is the current behavior?

- Empty destinations use a custom dashed box with generic copy.
- The diagram is full-bleed with `border-y`.
- Page chrome still uses legacy Scaffold wrappers and a long header
description that duplicates the empty state.
- Filter-row “Add destination” is a default button ahead of secondary
actions; Usage always shows.
- Local ETL warning sits on the page list.
- Destination sheet title/helper/access copy is more verbose; Type
helper sits beside the label.

## What is the new behavior?

- Empty state uses `EmptyStatePresentational` with clearer CTA copy;
toolbar “Add destination” is primary at the end of the filter row;
empty-state CTA stays default.
- Usage only appears when there is at least one Pipelines destination.
- Page uses `PageHeader` / `PageContainer` / `PageSection`, with a short
header: “Read replicas and analytics pipelines”.
- Diagram sits in a rounded bordered frame inside the page container
(same treatment as project overview).
- Local ETL warning shows in the add-destination sheet for Pipelines
types only, without blocking the form; Type + warning scroll with the
sheet body.
- Type helper sits under the dropdown as one flowing paragraph (“Cannot
be changed after creation…” plus shortened stage notice).
- Sheet title is “Add destination”; close only fires on dismiss; Lucide
icons (e.g. Snowflake) use consistent stroke width.

| Before | After |
| --- | --- |
| <img width="1479" height="930" alt="Replication Database Chisel
Toolshed Supabase"
src="https://github.com/user-attachments/assets/a3caf0ba-ed1a-4659-bdef-f66b67e85be4"
/> | <img width="1479" height="930" alt="Replication Database Chisel
Toolshed Supabase"
src="https://github.com/user-attachments/assets/d5a82641-a316-4577-9480-959346994c40"
/> |
| <img width="1479" height="930" alt="Replication Database Chisel
Toolshed Supabase"
src="https://github.com/user-attachments/assets/4f956e26-b8d4-4653-a60e-ceca7ec1e070"
/> | <img width="1479" height="930" alt="Replication Database Chisel
Toolshed Supabase"
src="https://github.com/user-attachments/assets/a72461ab-dea9-48a6-ab88-852a12ac80a5"
/> |

### Test plan

- [x] Open **Database → Replication** with no replicas/destinations:
empty state, primary filter-row Add destination, default empty-state Add
destination, no Usage button.
- [x] Confirm header→diagram and diagram→filter spacing feel even;
filter→empty state/table stays tight (`space-y-4`).
- [x] Confirm diagram is contained (rounded border), not full-bleed.
- [x] Add a Pipelines destination (or use a project that has one): Usage
appears; table still works; search “no results” still works.
- [ ] Open **Add destination**: title “Add destination”; Type helper
under the dropdown; Read Replica has no local warning; Pipelines type
shows local warning without hiding fields (when ETL isn’t set up
locally).
- [ ] Without Pipelines access: request-access panel shows “alpha” copy
and “Request alpha access”.
- [ ] Spot-check dark/light themes.

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-07-31 06:20:38 +10:00

58 lines
1.6 KiB
TypeScript

import { Background, ColorMode, ReactFlow, ReactFlowProvider } from '@xyflow/react'
import { useTheme } from 'next-themes'
import { PrimaryDatabaseNode, ReadReplicaNode, ReplicationNode } from './Nodes'
import '@xyflow/react/dist/style.css'
import { SmoothstepEdge } from './Edges'
export const EmptyReplicationDiagram = () => {
return (
<ReactFlowProvider>
<ReplicationDiagramContent />
</ReactFlowProvider>
)
}
const nodeTypes = {
primary: PrimaryDatabaseNode,
replication: ReplicationNode,
readReplica: ReadReplicaNode,
}
const edgeTypes = { smoothstep: SmoothstepEdge }
const ReplicationDiagramContent = () => {
const { resolvedTheme } = useTheme()
const backgroundPatternColor =
resolvedTheme === 'dark' ? 'rgba(255, 255, 255, 0.3)' : 'rgba(0, 0, 0, 0.4)'
return (
<div className="nowheel relative h-[350px] w-full border border-muted rounded-md overflow-hidden">
<ReactFlow
// FIXME: https://github.com/xyflow/xyflow/issues/4876
colorMode={'' as unknown as ColorMode}
fitView
fitViewOptions={{ minZoom: 0.8, maxZoom: 0.9 }}
className="bg"
zoomOnPinch={false}
zoomOnScroll={false}
nodesDraggable={false}
nodesConnectable={false}
zoomOnDoubleClick={false}
edgesFocusable={false}
edgesReconnectable={false}
defaultNodes={[]}
defaultEdges={[]}
nodeTypes={nodeTypes}
edgeTypes={edgeTypes}
proOptions={{ hideAttribution: true }}
>
<Background color={backgroundPatternColor} />
</ReactFlow>
</div>
)
}