diff --git a/.claude/skills/studio-e2e-tests/SKILL.md b/.claude/skills/studio-e2e-tests/SKILL.md index 1006981e42d..ecd48bc8376 100644 --- a/.claude/skills/studio-e2e-tests/SKILL.md +++ b/.claude/skills/studio-e2e-tests/SKILL.md @@ -88,7 +88,7 @@ test.describe.configure({ mode: 'serial' }) 3. **`getByText` with exact match** - Good for unique text ```typescript - page.getByText('Data API Access', { exact: true }) + page.getByText('Data API access', { exact: true }) ``` 4. **`locator` with CSS** - Use sparingly, more fragile diff --git a/.github/instructions/studio-e2e-tests.instructions.md b/.github/instructions/studio-e2e-tests.instructions.md index 58488df8d18..590512b176b 100644 --- a/.github/instructions/studio-e2e-tests.instructions.md +++ b/.github/instructions/studio-e2e-tests.instructions.md @@ -23,7 +23,7 @@ All comments are **advisory**. 3. **`getByText` with exact match** — good for unique text ```typescript - page.getByText('Data API Access', { exact: true }) + page.getByText('Data API access', { exact: true }) ``` 4. **`locator` with CSS** — use sparingly, more fragile diff --git a/apps/studio/components/interfaces/Database/Warehouse/WarehouseEditorPanel.tsx b/apps/studio/components/interfaces/Database/Warehouse/WarehouseEditorPanel.tsx index 113e08a4568..922b8509f0d 100644 --- a/apps/studio/components/interfaces/Database/Warehouse/WarehouseEditorPanel.tsx +++ b/apps/studio/components/interfaces/Database/Warehouse/WarehouseEditorPanel.tsx @@ -1,4 +1,4 @@ -import { ArrowRight, ChevronDown } from 'lucide-react' +import { ChevronDown } from 'lucide-react' import { useState, type ReactNode } from 'react' import { Button, @@ -7,6 +7,7 @@ import { DropdownMenuItem, DropdownMenuTrigger, } from 'ui' +import { InfoTooltip } from 'ui-patterns/info-tooltip' import { formatWarehouseSize, @@ -25,25 +26,25 @@ interface WarehouseEditorPanelProps { postgresSize?: string } -interface StorageModeConfig { - title: string - description: string +const MODE_LABELS: Record = { + postgres: 'Postgres', + has_warehouse_copy: 'Postgres + Warehouse', + warehouse_backed: 'Warehouse', } -const STORAGE_MODE_CONFIG: Record = { - postgres: { - title: 'Postgres', - description: 'Reads and writes on Postgres.', - }, - has_warehouse_copy: { - title: 'Postgres + Warehouse', - description: - 'Writes on Postgres. Analytical queries on Warehouse. Copy stays in sync with Postgres.', - }, - warehouse_backed: { - title: 'Warehouse', - description: 'Reads and writes on Warehouse.', - }, +const WAREHOUSE_MODE_TOOLTIPS: Partial> = { + has_warehouse_copy: ( + <> + Keeps this table in the Postgres heap and maintains a synced columnar copy in Warehouse. + Changes in Postgres propagate to the copy; sync is one-way, not bidirectional. + + ), + warehouse_backed: ( + <> + This table's storage was moved to Warehouse. The Postgres heap for this table no longer + exists. + + ), } function formatTimestamp(iso: string): string { @@ -63,86 +64,52 @@ function StorageMetaRow({ label, children }: { label: string; children: ReactNod ) } -function StorageModeHeader({ - title, - description, - trailing, -}: { - title: string - description: string - trailing?: ReactNode -}) { +function StorageModeRow({ mode }: { mode: WarehouseMode }) { + const tooltip = WAREHOUSE_MODE_TOOLTIPS[mode] + return ( -
-
-

{title}

-

{description}

+ +
+ {MODE_LABELS[mode]} + {tooltip && ( + + {tooltip} + + )}
- {trailing} -
+ ) } -function StorageCopyFlow({ - sourceName, - sourceSize, - copyName, - copySize, -}: { - sourceName: string - sourceSize?: string - copyName: string - copySize: string -}) { +function StorageSyncRows({ state }: { state: WarehouseTableState }) { return ( -
-
-
-

Postgres

- {sourceName} -

{sourceSize ?? '—'}

-
-
-
- ) -} - -function StorageSyncMeta({ state }: { state: WarehouseTableState }) { - const hasSyncMeta = - state.syncState !== undefined || - state.lastSyncedAt !== undefined || - state.lagSeconds !== undefined - - if (!hasSyncMeta) return null - - return ( -
- {state.syncState && } - {state.syncState && (state.lastSyncedAt !== undefined || state.lagSeconds !== undefined) && ( - + <> + {state.syncState && ( + + + )} {state.lastSyncedAt !== undefined && ( - Last synced {formatTimestamp(state.lastSyncedAt)} + + {formatTimestamp(state.lastSyncedAt)} + )} - {state.lastSyncedAt !== undefined && state.lagSeconds !== undefined && ( - + {state.lagSeconds !== undefined && ( + + {state.lagSeconds}s + )} - {state.lagSeconds !== undefined && Lag {state.lagSeconds}s} -
+ ) } -function CreateWarehouseCopyButton({ onAttach, onMove }: { onAttach: () => void; onMove: () => void }) { +function CreateWarehouseCopyButton({ + onAttach, + onMove, +}: { + onAttach: () => void + onMove: () => void +}) { return (