diff --git a/webui/src/features/datasources/DatasourcesPage.tsx b/webui/src/features/datasources/DatasourcesPage.tsx
index 44dcfe0..0e54ec1 100644
--- a/webui/src/features/datasources/DatasourcesPage.tsx
+++ b/webui/src/features/datasources/DatasourcesPage.tsx
@@ -23,14 +23,24 @@ import { FormGrid, DialogSection, ToolbarGroup, ActionToolbar,
ActionBlockerHint,
Button,
ConfirmDialog,
+ ContentSection,
Dialog,
DocumentationHelpLink,
DismissibleAlert,
+ FilterBar,
FormField,
IconButton,
LoadingFrame,
+ MetricCard,
+ MetricGrid,
SegmentedControl,
+ SelectionList,
+ SelectionListItem,
+ SelectionListItemContent,
+ StatePanel,
StatusBadge,
+ WorkspaceFrame,
+ WorkspaceLayout,
hasScope,
isApiError,
useUnsavedChanges,
@@ -284,10 +294,18 @@ export default function DatasourcesPage({
};
return (
-
-
-
+
-
+
-
+
{view === "catalogue" ? visibleDatasources.map((item) => (
- setSelectedDatasourceRef(item.ref)}
>
-
- {item.name}
- {item.source_name} · {item.kind}
-
+
-
+
)) : null}
{view === "staging" ? visibleStages.map((item) => (
- setSelectedStageRef(item.ref)}
>
-
- {item.name}
- {item.source_name} · {formatCount(item.row_count, "row")}
-
+
-
+
)) : null}
{view === "origins" ? visibleOrigins.map((item) => (
- setSelectedOriginRef(item.ref)}
>
-
- {item.name}
- {item.provider} · {item.kind}
-
+
-
+
)) : null}
{view === "catalogue" && !visibleDatasources.length ? (
- No datasources
+
) : null}
{view === "staging" && !visibleStages.length ? (
- No staged data
+
) : null}
{view === "origins" && !visibleOrigins.length ? (
-
- {originsAvailable ? "No connector origins" : "Connectors unavailable"}
-
+
) : null}
-
+
-
-
-
-
+ >}
+ >
+
{view === "catalogue" ?
: view === "staging" ?
@@ -522,8 +525,7 @@ export default function DatasourcesPage({
) : null}
{working ? Working...
: null}
-
-
+
setRetireOpen(false)}
onConfirm={() => void retireSelected()}
/>
-
+
);
}
@@ -624,24 +626,24 @@ function DatasourceDetail({
}) {
return (
<>
-
-
-
-
-
-
-
+
+
+
+
+
+
+
{datasource.description ? (
{datasource.description}
) : null}
-
-
+
Authority {readableToken(datasource.governance.authority_mode)}
Classification {datasource.governance.classification}
@@ -653,25 +655,25 @@ function DatasourceDetail({
{datasource.governance.semantic_definition ? (
{datasource.governance.semantic_definition}
) : null}
-
-
-
+
+
+
Preview
{preview ? `${formatNumber(preview.total_rows)} total rows` : ""}
-
+
{loading ? (
Loading preview...
) : preview ? (
) : (
- No preview available
+
)}
-
-
-
+
+
+
Materializations
Immutable revisions
-
+
@@ -708,14 +710,14 @@ function DatasourceDetail({
-
-
-
+
+
+
Schema
Version {datasource.schema_version}
-
+
-
+
>
);
}
@@ -727,21 +729,21 @@ function StageDetail({ stage }: { stage: DatasourceStage }) {
const schemaClassification = stage.validation.schema_change?.classification ?? "new";
return (
<>
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
Validation
-
+
Fingerprint {shortFingerprint(stage.fingerprint)}
Target {stage.target_datasource_ref || "New datasource"}
@@ -770,27 +772,27 @@ function StageDetail({ stage }: { stage: DatasourceStage }) {
All configured quality rules passed and no blocking schema change was detected.
)}
-
+
{schemaChanges.length ? (
-
-
+
{schemaChanges.map((change, index) => (
))}
-
+
) : null}
-
-
+
+
Detected schema
{stage.shape}
-
+
-
+
>
);
}
@@ -834,22 +836,22 @@ function SchemaChangeItem({ change }: { change: DatasourceSchemaChange }) {
function OriginDetail({ origin }: { origin: DatasourceOrigin }) {
return (
<>
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
{origin.description ? (
{origin.description}
) : null}
-
-
+
+
Registration options
{origin.supported_modes.join(", ")}
-
+
Origin reference {origin.ref}
Kind {readableToken(origin.kind)}
@@ -858,14 +860,14 @@ function OriginDetail({ origin }: { origin: DatasourceOrigin }) {
Health {origin.health.summary}
Pushdown {pushdownSummary(origin)}
-
-
-
+
+
+
Discovered schema
Version {origin.schema_version}
-
+
-
+
>
);
}
@@ -1479,17 +1481,8 @@ function SchemaTable({ fields }: { fields: Datasource["schema"] }) {
);
}
-function Metric({ label, value }: { label: string; value: string }) {
- return (
-
- {label}
- {value}
-
- );
-}
-
function EmptyWorkspace({ icon, label }: { icon: React.ReactNode; label: string }) {
- return
{icon}{label}
;
+ return
;
}
function filterItems
(
diff --git a/webui/src/styles/datasources.css b/webui/src/styles/datasources.css
index 60d7ef7..ef5b15e 100644
--- a/webui/src/styles/datasources.css
+++ b/webui/src/styles/datasources.css
@@ -1,65 +1,9 @@
-.datasources-page {
- position: relative;
- height: calc(100vh - 115px);
- min-width: 0;
- min-height: 0;
- padding: 0;
- overflow: hidden;
- color: var(--text);
- background: var(--bg);
-}
-
-.datasources-page *,
-.datasources-page *::before,
-.datasources-page *::after {
- box-sizing: border-box;
-}
-
-.datasources-shell {
- display: grid;
- grid-template-columns: minmax(250px, 300px) minmax(0, 1fr);
- width: 100%;
- height: 100%;
- min-width: 0;
- min-height: 0;
- overflow: hidden;
- border: var(--border-line);
- background: var(--panel);
-}
-
-.datasources-sidebar,
-.datasources-workspace,
.datasources-content,
.datasources-list-frame {
min-width: 0;
min-height: 0;
}
-.datasources-sidebar {
- display: flex;
- flex-direction: column;
- overflow: hidden;
- border-right: var(--border-line);
- background: var(--panel-soft);
-}
-
-.datasources-sidebar-toolbar,
-.datasources-workspace-toolbar,
-.datasources-section-heading {
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 10px;
- flex: 0 0 auto;
- border-bottom: var(--border-line);
- background: var(--panel-header);
-}
-
-.datasources-sidebar-toolbar {
- min-height: 52px;
- padding: 8px 10px 8px 14px;
-}
-
.datasources-toolbar-actions,
.datasources-current-title,
.datasources-current-title > span,
@@ -75,80 +19,11 @@
background: var(--panel);
}
-.datasources-search {
- padding: 9px;
- border-bottom: var(--border-line);
-}
-
-.datasources-search input {
- width: 100%;
- min-height: 34px;
- padding: 7px 9px;
-}
-
.datasources-list-frame {
flex: 1 1 auto;
overflow: hidden;
}
-.datasources-list {
- height: 100%;
- overflow: auto;
- padding: 6px;
-}
-
-.datasources-list > button {
- display: grid;
- grid-template-columns: minmax(0, 1fr) auto;
- align-items: center;
- gap: 8px;
- width: 100%;
- min-height: 56px;
- padding: 8px 9px;
- border: 0;
- border-radius: var(--radius-sm);
- background: transparent;
- color: var(--text);
- cursor: pointer;
- text-align: left;
-}
-
-.datasources-list > button:hover,
-.datasources-list > button:focus-visible {
- background: var(--primary-soft);
- outline: none;
-}
-
-.datasources-list > button.is-selected {
- background: var(--primary-soft-strong);
- box-shadow: inset 3px 0 0 var(--accent);
-}
-
-.datasources-list > button > span:first-child {
- min-width: 0;
-}
-
-.datasources-list strong,
-.datasources-list small {
- display: block;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.datasources-list strong {
- color: var(--text-strong);
- font-size: 13px;
-}
-
-.datasources-list small {
- margin-top: 4px;
- color: var(--muted);
- font-size: 11px;
-}
-
-.datasources-list-empty,
-.datasources-inline-empty,
.datasources-inline-loading {
display: grid;
place-items: center;
@@ -158,17 +33,8 @@
text-align: center;
}
-.datasources-workspace {
- position: relative;
- display: flex;
- flex-direction: column;
- overflow: hidden;
- background: var(--bg);
-}
-
.datasources-workspace-toolbar {
- min-height: 58px;
- padding: 8px 10px 8px 14px;
+ min-width: 0;
}
.datasources-current-title {
@@ -218,43 +84,6 @@
padding: 14px;
}
-.datasources-metrics {
- display: grid;
- grid-template-columns: repeat(5, minmax(100px, 1fr));
- gap: 8px;
- margin-bottom: 14px;
-}
-
-.datasources-metrics > span {
- min-width: 0;
- min-height: 61px;
- padding: 9px 10px;
- border: var(--border-line);
- border-radius: var(--radius-sm);
- background: var(--panel);
-}
-
-.datasources-metrics small,
-.datasources-metrics strong {
- display: block;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.datasources-metrics small {
- color: var(--muted);
- font-size: 10px;
- text-transform: uppercase;
-}
-
-.datasources-metrics strong {
- margin-top: 6px;
- color: var(--text-strong);
- font-size: 14px;
- text-transform: capitalize;
-}
-
.datasources-description {
margin-bottom: 14px;
padding: 10px 12px;
@@ -265,18 +94,6 @@
line-height: 1.45;
}
-.datasources-detail-section {
- min-width: 0;
- margin-bottom: 14px;
- border: var(--border-line);
- background: var(--panel);
-}
-
-.datasources-section-heading {
- min-height: 42px;
- padding: 7px 10px;
-}
-
.datasources-section-heading > span {
color: var(--text-strong);
font-size: 13px;
@@ -501,26 +318,10 @@
overflow: auto;
}
- .datasources-shell {
- grid-template-columns: 1fr;
- height: auto;
- overflow: visible;
- }
-
- .datasources-sidebar {
- max-height: 42vh;
- border-right: 0;
- border-bottom: var(--border-line);
- }
-
.datasources-workspace {
min-height: 58vh;
}
- .datasources-metrics {
- grid-template-columns: repeat(2, minmax(0, 1fr));
- }
-
.datasources-workspace-toolbar {
align-items: flex-start;
flex-wrap: wrap;
@@ -532,7 +333,6 @@
}
@media (max-width: 560px) {
- .datasources-metrics,
.datasources-key-values {
grid-template-columns: 1fr;
}