feat(ui): Data Flow tab — live lineage graph + PII overlay + movement triggers

New DataFlowView (topology-style): nodes positioned from /api/dataflow with
measured-anchor SVG edges and animated particles (active CDC + running
movements). PII overlay shows shield badges + per-column detail inspector.
Bottom strip triggers ETL movements and toggles the ETL agent. Wired into
SideNav (Data Flow) and App routing; added types + api helpers.
This commit is contained in:
mo
2026-06-27 02:09:38 +02:00
parent ee9357aa31
commit 6f20e24b8b
5 changed files with 539 additions and 1 deletions
+34
View File
@@ -4,8 +4,11 @@ import type {
Approval,
CdcChange,
CdcStats,
DataflowGraph,
FeedEntry,
GpuStatus,
Movement,
PiiDataset,
StatusData,
TerminalLine,
WorkloadData,
@@ -129,6 +132,37 @@ export function runAgentOpOnce(source?: string, op?: string) {
})
}
export async function fetchDataflow(refresh = false): Promise<DataflowGraph | null> {
return fetchJson<DataflowGraph>(`/api/dataflow${refresh ? '?refresh=true' : ''}`, 25000)
}
export function runDataflowMovement(movementId: string, conf?: Record<string, unknown>) {
return fetch(`/api/dataflow/${movementId}/run`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(conf ? { conf } : {}),
})
}
export async function fetchMovements(): Promise<Movement[]> {
const j = await fetchJson<{ movements?: Movement[] }>('/api/movements', 8000)
return j?.movements || []
}
export async function fetchPii(refresh = false): Promise<{ datasets: PiiDataset[]; summary: Record<string, number> } | null> {
return fetchJson<{ datasets: PiiDataset[]; summary: Record<string, number> }>(
`/api/pii${refresh ? '?refresh=true' : ''}`, 15000,
)
}
export function toggleEtlAgent(enabled?: boolean) {
return fetch('/api/agent-ops/etl/toggle', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(enabled === undefined ? {} : { enabled }),
})
}
export async function decideApproval(id: string, approved: boolean, decidedBy: string, note: string) {
return fetch(`/api/approvals/${id}/decide`, {
method: 'POST',