make graph view on run #47

Open
opened 2026-03-09 08:39:30 +00:00 by despiegk · 4 comments
Owner

image

runs are jobs which depend on each other

check that the result of scheduling a service is X nr of jobs being scheduled this should be visible in a run

so we can see all the dependencies, and what is running, what is waiting, ...

then if we click on a job we see the detail in a modal

![image](/attachments/dc9015f2-75d2-436c-a115-b05449bcc06f) runs are jobs which depend on each other check that the result of scheduling a service is X nr of jobs being scheduled this should be visible in a run so we can see all the dependencies, and what is running, what is waiting, ... then if we click on a job we see the detail in a modal
444 KiB
Author
Owner

Implementation Spec for Issue #47 - Run Graph View

Objective

Replace the flat list of job IDs in the Run detail panel with an interactive directed acyclic graph (DAG) visualization. Each job is rendered as a node showing its status; edges represent dependency relationships between jobs. Clicking a job node opens the existing job modal with full details.

Requirements

  • Render a canvas/SVG-based graph in the Run detail panel showing jobs as nodes and dependency edges as directed arrows
  • Each node displays job ID, action name, and color-coded status indicator
  • Running job nodes pulse; waiting nodes show waiting indicator; terminal nodes are static
  • Clicking a node calls existing showJobModal(id) to display job details
  • Auto-layout nodes left-to-right in topological order (independent jobs on left, dependent ones on right)
  • No external library additions — use inline SVG + positioned HTML divs
  • Run metadata (status, timestamps, duration) still displays above the graph

Files to Modify

  • crates/zinit_ui/static/css/dashboard.css — Graph node, edge, and container styles
  • crates/zinit_ui/static/js/dashboard.js — Rewrite viewRun(), add graph layout and rendering functions
  • crates/zinit_ui/static/js/demo.js — Enhance demo data with job dependencies for testing

Implementation Plan

Step 1: Add graph CSS styles

Files: dashboard.css

  • Add .run-graph-container, .run-graph-node, status modifiers, .run-graph-svg, .run-graph-edge styles
  • Dependencies: none

Step 2: Rewrite viewRun() function

Files: dashboard.js

  • Fetch full job details via run.get_jobs + job.get for each
  • Build run metadata header, then call renderRunGraph() instead of flat chips
  • Dependencies: Step 1

Step 3: Add buildRunGraphLayout(jobs) function

Files: dashboard.js

  • Topological sort using Kahn's algorithm to assign layers
  • Compute (x, y) positions for each node
  • Dependencies: none (called by Step 4)

Step 4: Add renderRunGraph(jobs, containerEl) function

Files: dashboard.js

  • Render positioned HTML divs for nodes + SVG overlay for edges with arrowheads
  • Wire up onclick to showJobModal()
  • Dependencies: Steps 1, 3

Step 5: Handle edge cases

Files: dashboard.js

  • Empty runs, single-job runs, external dependency references, fetch failures
  • Dependencies: Steps 2-4

Step 6: Update demo data

Files: demo.js

  • Create actions with depends_on relationships and runs containing those jobs
  • Dependencies: Steps 2-4

Acceptance Criteria

  • Run detail panel shows visual graph of jobs instead of flat ID chips
  • Job nodes are color-coded by status (green=succeeded, red=failed, blue=running, yellow=waiting, gray=pending)
  • Running nodes have pulsing animation
  • Directed edges (arrows) connect dependent jobs
  • Clicking a node opens job detail modal
  • Graph auto-layouts in topological order
  • Empty/single-job runs handled gracefully
  • Scrollable container for large runs
  • Works in both light and dark theme

Notes

  • No external graph library needed — runs are typically small (5-20 jobs)
  • Existing showJobModal() function reused as-is
  • All CSS variables already defined for theming
  • N+2 RPC calls per run view (acceptable for typical run sizes)
## Implementation Spec for Issue #47 - Run Graph View ### Objective Replace the flat list of job IDs in the Run detail panel with an interactive directed acyclic graph (DAG) visualization. Each job is rendered as a node showing its status; edges represent dependency relationships between jobs. Clicking a job node opens the existing job modal with full details. ### Requirements - Render a canvas/SVG-based graph in the Run detail panel showing jobs as nodes and dependency edges as directed arrows - Each node displays job ID, action name, and color-coded status indicator - Running job nodes pulse; waiting nodes show waiting indicator; terminal nodes are static - Clicking a node calls existing `showJobModal(id)` to display job details - Auto-layout nodes left-to-right in topological order (independent jobs on left, dependent ones on right) - No external library additions — use inline SVG + positioned HTML divs - Run metadata (status, timestamps, duration) still displays above the graph ### Files to Modify - `crates/zinit_ui/static/css/dashboard.css` — Graph node, edge, and container styles - `crates/zinit_ui/static/js/dashboard.js` — Rewrite `viewRun()`, add graph layout and rendering functions - `crates/zinit_ui/static/js/demo.js` — Enhance demo data with job dependencies for testing ### Implementation Plan #### Step 1: Add graph CSS styles Files: `dashboard.css` - Add `.run-graph-container`, `.run-graph-node`, status modifiers, `.run-graph-svg`, `.run-graph-edge` styles - Dependencies: none #### Step 2: Rewrite `viewRun()` function Files: `dashboard.js` - Fetch full job details via `run.get_jobs` + `job.get` for each - Build run metadata header, then call `renderRunGraph()` instead of flat chips - Dependencies: Step 1 #### Step 3: Add `buildRunGraphLayout(jobs)` function Files: `dashboard.js` - Topological sort using Kahn's algorithm to assign layers - Compute (x, y) positions for each node - Dependencies: none (called by Step 4) #### Step 4: Add `renderRunGraph(jobs, containerEl)` function Files: `dashboard.js` - Render positioned HTML divs for nodes + SVG overlay for edges with arrowheads - Wire up onclick to `showJobModal()` - Dependencies: Steps 1, 3 #### Step 5: Handle edge cases Files: `dashboard.js` - Empty runs, single-job runs, external dependency references, fetch failures - Dependencies: Steps 2-4 #### Step 6: Update demo data Files: `demo.js` - Create actions with `depends_on` relationships and runs containing those jobs - Dependencies: Steps 2-4 ### Acceptance Criteria - [ ] Run detail panel shows visual graph of jobs instead of flat ID chips - [ ] Job nodes are color-coded by status (green=succeeded, red=failed, blue=running, yellow=waiting, gray=pending) - [ ] Running nodes have pulsing animation - [ ] Directed edges (arrows) connect dependent jobs - [ ] Clicking a node opens job detail modal - [ ] Graph auto-layouts in topological order - [ ] Empty/single-job runs handled gracefully - [ ] Scrollable container for large runs - [ ] Works in both light and dark theme ### Notes - No external graph library needed — runs are typically small (5-20 jobs) - Existing `showJobModal()` function reused as-is - All CSS variables already defined for theming - N+2 RPC calls per run view (acceptable for typical run sizes)
Author
Owner
use a graph library https://observablehq.com/@d3/force-directed-graph/2
Author
Owner

Updated Spec: Use D3 Force-Directed Graph

Per feedback, switching from manual topological layout to D3 force-directed graph based on https://observablehq.com/@d3/force-directed-graph/2

Key Changes from Original Spec

  1. Add D3 library via CDN (d3.min.js v7) — loaded in the HTML template
  2. Use d3.forceSimulation() for physics-based node layout instead of manual Kahn's algorithm
  3. Interactive dragging — users can drag job nodes to rearrange the graph
  4. SVG-only rendering — nodes rendered as SVG circles/groups (not HTML divs), edges as SVG lines

D3 Graph Approach

// Build nodes from jobs, links from depends_on
const simulation = d3.forceSimulation(nodes)
  .force("link", d3.forceLink(links).id(d => d.id))
  .force("charge", d3.forceManyBody())
  .force("center", d3.forceCenter(width / 2, height / 2));
  • Nodes: SVG circles colored by job status (green=succeeded, red=failed, blue=running, yellow=waiting, gray=pending)
  • Links: SVG lines connecting dependent jobs with arrowheads
  • Drag: d3.drag() for interactive repositioning
  • Labels: Job name text next to each node
  • Click: Click node → showJobModal(jobId)

Updated Implementation Steps

Step 1: Add D3 CDN to HTML template

Files: crates/zinit_ui/templates/index.html

  • Add <script src="https://d3js.org/d3.v7.min.js"></script> before dashboard.js

Step 2: Add graph CSS styles

Files: crates/zinit_ui/static/css/dashboard.css

  • .run-graph-container — container with border, background, min-height
  • SVG node/link styling, status colors, hover effects, pulse animation for running nodes

Step 3: Rewrite viewRun() to fetch full job data

Files: crates/zinit_ui/static/js/dashboard.js

  • Fetch run details + all job details via RPC
  • Build nodes/links data structure from jobs and their depends_on fields
  • Call new renderRunGraph() function

Step 4: Add renderRunGraph(jobs, containerEl) with D3 force simulation

Files: crates/zinit_ui/static/js/dashboard.js

  • Create SVG with D3
  • Build force simulation with link, charge, and center forces
  • Render nodes as circles with status colors + labels
  • Render links as lines with arrowheads
  • Add drag behavior
  • Add click handler for showJobModal()
  • Add tick function to update positions

Step 5: Handle edge cases

Files: crates/zinit_ui/static/js/dashboard.js

  • Empty runs, single-job runs, fetch failures

Step 6: Update demo data with dependencies

Files: crates/zinit_ui/static/js/demo.js

  • Create actions with depends_on and runs containing those jobs

Everything Else Unchanged

  • Same acceptance criteria
  • Same file list (plus index.html for D3 CDN)
  • Same data flow (run.get → run.get_jobs → job.get for each)
  • showJobModal() reused as-is
## Updated Spec: Use D3 Force-Directed Graph Per feedback, switching from manual topological layout to **D3 force-directed graph** based on https://observablehq.com/@d3/force-directed-graph/2 ### Key Changes from Original Spec 1. **Add D3 library** via CDN (`d3.min.js` v7) — loaded in the HTML template 2. **Use `d3.forceSimulation()`** for physics-based node layout instead of manual Kahn's algorithm 3. **Interactive dragging** — users can drag job nodes to rearrange the graph 4. **SVG-only rendering** — nodes rendered as SVG circles/groups (not HTML divs), edges as SVG lines ### D3 Graph Approach ```javascript // Build nodes from jobs, links from depends_on const simulation = d3.forceSimulation(nodes) .force("link", d3.forceLink(links).id(d => d.id)) .force("charge", d3.forceManyBody()) .force("center", d3.forceCenter(width / 2, height / 2)); ``` - **Nodes**: SVG circles colored by job status (green=succeeded, red=failed, blue=running, yellow=waiting, gray=pending) - **Links**: SVG lines connecting dependent jobs with arrowheads - **Drag**: `d3.drag()` for interactive repositioning - **Labels**: Job name text next to each node - **Click**: Click node → `showJobModal(jobId)` ### Updated Implementation Steps #### Step 1: Add D3 CDN to HTML template Files: `crates/zinit_ui/templates/index.html` - Add `<script src="https://d3js.org/d3.v7.min.js"></script>` before dashboard.js #### Step 2: Add graph CSS styles Files: `crates/zinit_ui/static/css/dashboard.css` - `.run-graph-container` — container with border, background, min-height - SVG node/link styling, status colors, hover effects, pulse animation for running nodes #### Step 3: Rewrite `viewRun()` to fetch full job data Files: `crates/zinit_ui/static/js/dashboard.js` - Fetch run details + all job details via RPC - Build nodes/links data structure from jobs and their `depends_on` fields - Call new `renderRunGraph()` function #### Step 4: Add `renderRunGraph(jobs, containerEl)` with D3 force simulation Files: `crates/zinit_ui/static/js/dashboard.js` - Create SVG with D3 - Build force simulation with link, charge, and center forces - Render nodes as circles with status colors + labels - Render links as lines with arrowheads - Add drag behavior - Add click handler for `showJobModal()` - Add tick function to update positions #### Step 5: Handle edge cases Files: `crates/zinit_ui/static/js/dashboard.js` - Empty runs, single-job runs, fetch failures #### Step 6: Update demo data with dependencies Files: `crates/zinit_ui/static/js/demo.js` - Create actions with `depends_on` and runs containing those jobs ### Everything Else Unchanged - Same acceptance criteria - Same file list (plus index.html for D3 CDN) - Same data flow (run.get → run.get_jobs → job.get for each) - `showJobModal()` reused as-is
Author
Owner

Implementation Complete

Changes Made

1. Added D3.js v7 library (crates/zinit_ui/static/js/d3.v7.min.js)

  • Vendored locally (same pattern as Bootstrap, Chart.js)
  • Added script tag in templates/base.html

2. Run Graph View (crates/zinit_ui/static/js/dashboard.js)

  • Rewrote viewRun() to fetch full job details via job.get for each job in the run
  • Added renderRunGraph() function using D3 force-directed simulation
  • Nodes are colored by job phase (green=running/succeeded, red=failed, yellow=waiting, gray=pending)
  • Edges drawn from spec.depends_on action names matched to jobs in the same run
  • Interactive: drag nodes to rearrange, click nodes to open job detail modal
  • SVG arrowheads show dependency direction
  • Legend shows phase colors below graph
  • Empty state for runs with no jobs

3. Graph CSS (crates/zinit_ui/static/css/dashboard.css)

  • .run-graph-container with border, background, overflow handling
  • Node status colors matching existing state-badge palette
  • Pulse animation for running/pending nodes
  • Hover effects on nodes
  • Legend styling

4. Demo Pipeline Data (crates/zinit_sdk/src/demo.rs)

  • Added 6 pipeline jobs with depends_on relationships:
    init → build → test + lint → deploy → notify
  • Pipeline run created automatically with demo data
  • Graph visible immediately after running demo

5. ActionBuilder enhancement (crates/zinit_sdk/src/builders.rs)

  • Added .depends_on(action_name) and .depends_on_with_type(name, type) builder methods

Test Results

  • All SDK tests pass (18/18)
  • All affected crate tests pass (zinit_sdk, zinit_lib, zinit_server, zinit_ui)
  • Build clean (no new warnings)
## Implementation Complete ### Changes Made **1. Added D3.js v7 library** (`crates/zinit_ui/static/js/d3.v7.min.js`) - Vendored locally (same pattern as Bootstrap, Chart.js) - Added script tag in `templates/base.html` **2. Run Graph View** (`crates/zinit_ui/static/js/dashboard.js`) - Rewrote `viewRun()` to fetch full job details via `job.get` for each job in the run - Added `renderRunGraph()` function using D3 force-directed simulation - Nodes are colored by job phase (green=running/succeeded, red=failed, yellow=waiting, gray=pending) - Edges drawn from `spec.depends_on` action names matched to jobs in the same run - Interactive: drag nodes to rearrange, click nodes to open job detail modal - SVG arrowheads show dependency direction - Legend shows phase colors below graph - Empty state for runs with no jobs **3. Graph CSS** (`crates/zinit_ui/static/css/dashboard.css`) - `.run-graph-container` with border, background, overflow handling - Node status colors matching existing state-badge palette - Pulse animation for running/pending nodes - Hover effects on nodes - Legend styling **4. Demo Pipeline Data** (`crates/zinit_sdk/src/demo.rs`) - Added 6 pipeline jobs with `depends_on` relationships: init → build → test + lint → deploy → notify - Pipeline run created automatically with demo data - Graph visible immediately after running demo **5. ActionBuilder enhancement** (`crates/zinit_sdk/src/builders.rs`) - Added `.depends_on(action_name)` and `.depends_on_with_type(name, type)` builder methods ### Test Results - All SDK tests pass (18/18) - All affected crate tests pass (zinit_sdk, zinit_lib, zinit_server, zinit_ui) - Build clean (no new warnings)
despiegk added this to the now milestone 2026-03-09 10:22:55 +00:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
geomind_code/zinit#47
No description provided.