Skip to content

console: dataflow visualizer rebuild (drill-down navigator)#37487

Draft
antiguru wants to merge 45 commits into
MaterializeInc:mainfrom
antiguru:moritz/dataflow-visualizer-rebuild
Draft

console: dataflow visualizer rebuild (drill-down navigator)#37487
antiguru wants to merge 45 commits into
MaterializeInc:mainfrom
antiguru:moritz/dataflow-visualizer-rebuild

Conversation

@antiguru

@antiguru antiguru commented Jul 7, 2026

Copy link
Copy Markdown
Member

Motivation

The graphviz-based dataflow visualizer doesn't scale to real dataflow sizes: it renders everything at once with no way to focus on a subgraph, and edges into collapsed regions disappear.

Description

Replaces it with a React Flow + elkjs drill-down navigator: one scope's direct children render at a time, double-clicking a region navigates into it, and boundary-crossing ports carry peer info so cross-region connections stay visible and jumpable (single-click select, double-click jumps straight to the peer's matching port when unambiguous). Adds a node detail panel, LIR operator tree with member highlighting, filters/toolbar including elapsed/size/CPU-skew/memory-skew heatmaps (skew matches EXPLAIN ANALYZE ... WITH SKEW), a cluster dataflows list page, and a dataflow switcher on the detail page.

@antiguru antiguru force-pushed the moritz/dataflow-visualizer-rebuild branch from 29631f3 to 03e6ae3 Compare July 8, 2026 20:31
antiguru and others added 29 commits July 8, 2026 22:42
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…yout worker/hook

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ports

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…tors

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…mary

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…isualize links, stale pins

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…roke, edge highlight

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…onent

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…, fix viewport bug

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…h-based coloring

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… nesting

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
antiguru and others added 16 commits July 8, 2026 22:42
…default LIR groups on

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…tory navigation

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…to the detail panel

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Grouping boxes shipped as part of the dataflow visualizer rebuild; these
predate that work and no longer reflect the implementation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ments

Add mustGet(map, key) and use it in place of .get(x)! throughout
dataflowGraph.ts and elkGraph.ts, so a missing key throws with the key
in the message instead of a bare non-null-assertion crash. Convert the
file's // doc-comment blocks to JSDoc and fix em-dash/semicolon
comment style along the way.

Also move formatElapsedNs to utils/format.ts: it's a generic
duration formatter, not dataflow-specific, and utils/format.ts is
where the rest of the codebase's formatters already live.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Destructure cluster near the top of each *Table component so the
nested render() closures use the narrowed const instead of
props.cluster!, which loses TypeScript's narrowing across the closure
boundary.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
DataflowGraphView, nodes.tsx, ChannelEdge, and LirPanel now pull colors
from useTheme() (or the raw colors module for palette/highlight
constants that intentionally read the same in both modes) instead of
hardcoded hex values and Chakra's light-only gray.* tokens. React
Flow's Background/Controls/MiniMap are themed via their documented
--xy-* CSS custom properties, since they render outside Chakra's
component tree. lirGroupColor/operatorColor/nodeFillColor now take
their palette/accent colors as parameters instead of module-level
constants, so callers can pass the theme-resolved palette.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
DataflowBreadcrumbs' clickable crumbs now use TextLink instead of a
manually-styled Text-as-button, and gain a title on the truncated
final crumb (matching ObjectJourneyBreadcrumb's convention). Its
structure.nodes.get(id)! lookup becomes an explicit throw with the
missing id in the message.

UsagePrivilegeAlert now renders through the shared Alert component
instead of raw Chakra Alert/AlertIcon.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Swap the manually-styled LIR link for TextLink, and the «/»/→ glyphs
for ChevronLeftIcon/ChevronRightIcon/ArrowRightIcon. Extract every
inline prop object type to a named (and, for the panel's own props,
exported) interface, matching the rest of the codebase's convention.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
useDataflowGraphData and useDataflowList each hand-rolled the same
retain-last-good-result-while-a-new-key-loads logic (with two
different implementations), guarding against briefly showing stale
data mislabeled under a new key during a loading transition. Extract
one hook and use it in both places.

useDataflowGraphData also stops throwing on a malformed dataflow id:
dataflowIdLiteral now returns undefined instead of throwing, and the
hook surfaces an `error` field instead of crashing to the error
boundary on a bad URL.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Skew is a worst-worker-over-average ratio: with one worker there's
nothing to compare against, so every node's ratio is trivially 1 (or
the no-data 0 sentinel), and the heatmap silently rendered no color at
all, indistinguishable from being off. Disable the three skew options
instead, with a tooltip explaining why.

Also reuses this as the pass to swap the toolbar's raw Input/Select
for the shared SearchInput/SimpleSelect components.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… check

DatabaseError.ts's isPermissonError expects a nested result.error.code
shape; the dataflow pages get an ExecuteSqlError directly, a different
shape, so add a predicate for it rather than force-fitting the
existing one. useDataflowIdForExport now also surfaces databaseError,
so DataflowsPage can check both its own and the export-id query's
error.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…rkerCount

Replace the remaining .get(scope)! lookups with mustGet, drop the
locally-duplicated hashString in favor of nodeStyle's, simplify
permissionError to isInsufficientPrivilegeError, and pass
workerCount through to DataflowToolbar for the skew-heatmap disable.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…nguage

Canvas nodes: 8px card radius, subtle resting shadow, and text-ui-med/
text-small type tokens for name and stat lines, matching the workflow
dependency graph's GraphNode. Selection color, edge animation, and elk's
compact layout spacing are unchanged (elk auto-sizes to content, unlike
the workflow graph's fixed-size dagre cards, so no spacing changes apply).

Detail panel: row labels use text-ui-med/foreground.tertiary (matching
SidebarItemLabel), row values keep monospace for numeric column alignment,
and stat/LIR/edge/peer groups get a border-top divider and text-small
section label, matching SidebarSection without its collapse behavior.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
CardShell and LirGroupNode never set an explicit text color, so they
inherited the default (dark) body text regardless of the hashed
palette color behind them. colors.lineGraph mixes dark and light
swatches in both themes (it's indexed by hash, not by color mode), so
a dark background with the default dark text was unreadable.

Add textColorFor(background), picking black or white by comparing WCAG
contrast ratios against the fill's actual luminance, and use it in
both places.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@antiguru antiguru force-pushed the moritz/dataflow-visualizer-rebuild branch from 03e6ae3 to b26299d Compare July 8, 2026 20:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant