refactor(web): drop vestigial graphTheme aliases and dead code

Removes unused annotateRunningNodes from run-graph and inlines the
const gt = graphTheme / const theme = graphTheme shims left over from
the dark-mode-only refactor. Template strings reference graphTheme
directly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Bryan Helmkamp 2026-04-20 09:32:45 -04:00
parent c769b2a30c
commit 837406f27c
No known key found for this signature in database
4 changed files with 149 additions and 236 deletions

View file

@ -34,7 +34,6 @@ export async function loader({ request, params }: any) {
type Direction = "LR" | "TB";
function buildDot(direction: Direction) {
const gt = graphTheme;
return `digraph sync {
graph [label="Sync"]
rankdir=${direction}
@ -44,27 +43,27 @@ function buildDot(direction: Direction) {
node [
fontname="ui-monospace, monospace"
fontsize=11
fontcolor="${gt.nodeText}"
color="${gt.edgeColor}"
fillcolor="${gt.nodeFill}"
fontcolor="${graphTheme.nodeText}"
color="${graphTheme.edgeColor}"
fillcolor="${graphTheme.nodeFill}"
style=filled
penwidth=1.2
]
edge [
fontname="ui-monospace, monospace"
fontsize=9
fontcolor="${gt.fontcolor}"
color="${gt.edgeColor}"
fontcolor="${graphTheme.fontcolor}"
color="${graphTheme.edgeColor}"
arrowsize=0.7
penwidth=1.2
]
start [shape=Mdiamond, label="Start", fillcolor="${gt.startFill}", color="${gt.startBorder}", fontcolor="${gt.startText}"]
exit [shape=Msquare, label="Exit", fillcolor="${gt.startFill}", color="${gt.startBorder}", fontcolor="${gt.startText}"]
start [shape=Mdiamond, label="Start", fillcolor="${graphTheme.startFill}", color="${graphTheme.startBorder}", fontcolor="${graphTheme.startText}"]
exit [shape=Msquare, label="Exit", fillcolor="${graphTheme.startFill}", color="${graphTheme.startBorder}", fontcolor="${graphTheme.startText}"]
detect [label="Detect\\nDrift"]
propose [label="Propose\\nChanges"]
review [shape=hexagon, label="Review\\nChanges", fillcolor="${gt.gateFill}", color="${gt.gateBorder}", fontcolor="${gt.gateText}"]
review [shape=hexagon, label="Review\\nChanges", fillcolor="${graphTheme.gateFill}", color="${graphTheme.gateBorder}", fontcolor="${graphTheme.gateText}"]
apply [label="Apply\\nChanges"]
start -> detect
@ -89,91 +88,6 @@ function stripGraphTitle(svg: SVGSVGElement) {
title.remove();
}
function annotateRunningNodes(svg: SVGSVGElement, stageList: Stage[]) {
const gt = graphTheme;
const runningDotIds = new Set(
stageList.filter((s) => s.status === "running").map((s) => s.dotId),
);
const completedDotIds = new Set(
stageList.filter((s) => s.status === "completed").map((s) => s.dotId),
);
const nodeGroups = svg.querySelectorAll(".node");
for (const group of nodeGroups) {
const titleEl = group.querySelector("title");
if (!titleEl) continue;
const nodeId = titleEl.textContent?.trim();
if (!nodeId) continue;
if (runningDotIds.has(nodeId)) {
// Animate with native SVG <animate> elements (cross-browser reliable)
const ns = "http://www.w3.org/2000/svg";
const shapes = group.querySelectorAll("ellipse, polygon, path");
for (const shape of shapes) {
shape.setAttribute("fill", gt.runningFill);
shape.setAttribute("stroke", gt.runningBorder);
shape.setAttribute("stroke-width", "2");
const animFill = document.createElementNS(ns, "animate");
animFill.setAttribute("attributeName", "fill");
animFill.setAttribute("values", `${gt.runningFill};${gt.runningPulseFill};${gt.runningFill}`);
animFill.setAttribute("dur", "1.5s");
animFill.setAttribute("repeatCount", "indefinite");
shape.appendChild(animFill);
const animStroke = document.createElementNS(ns, "animate");
animStroke.setAttribute("attributeName", "stroke");
animStroke.setAttribute("values", `${gt.runningBorder};${gt.runningPulseStroke};${gt.runningBorder}`);
animStroke.setAttribute("dur", "1.5s");
animStroke.setAttribute("repeatCount", "indefinite");
shape.appendChild(animStroke);
const animWidth = document.createElementNS(ns, "animate");
animWidth.setAttribute("attributeName", "stroke-width");
animWidth.setAttribute("values", "2;3.5;2");
animWidth.setAttribute("dur", "1.5s");
animWidth.setAttribute("repeatCount", "indefinite");
shape.appendChild(animWidth);
}
const texts = group.querySelectorAll("text");
for (const text of texts) {
text.setAttribute("fill", gt.runningText);
}
} else if (completedDotIds.has(nodeId)) {
// Tint completed nodes green
const shapes = group.querySelectorAll("ellipse, polygon, path");
for (const shape of shapes) {
shape.setAttribute("fill", gt.completedFill);
shape.setAttribute("stroke", gt.completedBorder);
}
const texts = group.querySelectorAll("text");
for (const text of texts) {
text.setAttribute("fill", gt.completedText);
}
}
}
// Also color edges leading into completed nodes
const edgeGroups = svg.querySelectorAll(".edge");
for (const group of edgeGroups) {
const titleEl = group.querySelector("title");
if (!titleEl) continue;
const edgeLabel = titleEl.textContent?.trim() ?? "";
const [, target] = edgeLabel.split("->");
if (!target) continue;
const targetId = target.trim();
if (completedDotIds.has(targetId)) {
const paths = group.querySelectorAll("path, polygon");
for (const p of paths) {
p.setAttribute("stroke", gt.completedBorder);
if (p.tagName === "polygon") p.setAttribute("fill", gt.completedBorder);
}
}
}
}
export default function RunGraph({ loaderData }: any) {
const { id } = useParams();
const { stages, graphSvg } = loaderData;

View file

@ -5,7 +5,6 @@ import { graphTheme } from "../lib/graph-theme";
type Direction = "LR" | "TB";
function buildDot(direction: Direction) {
const theme = graphTheme;
return `digraph fix_build {
graph [
label="Fix Build"
@ -17,29 +16,29 @@ function buildDot(direction: Direction) {
node [
fontname="ui-monospace, monospace"
fontsize=11
fontcolor="${theme.nodeText}"
color="${theme.edgeColor}"
fillcolor="${theme.nodeFill}"
fontcolor="${graphTheme.nodeText}"
color="${graphTheme.edgeColor}"
fillcolor="${graphTheme.nodeFill}"
style=filled
penwidth=1.2
]
edge [
fontname="ui-monospace, monospace"
fontsize=9
fontcolor="${theme.fontcolor}"
color="${theme.edgeColor}"
fontcolor="${graphTheme.fontcolor}"
color="${graphTheme.edgeColor}"
arrowsize=0.7
penwidth=1.2
]
start [shape=Mdiamond, label="Start", fillcolor="${theme.startFill}", color="${theme.startBorder}", fontcolor="${theme.startText}"]
exit [shape=Msquare, label="Exit", fillcolor="${theme.startFill}", color="${theme.startBorder}", fontcolor="${theme.startText}"]
start [shape=Mdiamond, label="Start", fillcolor="${graphTheme.startFill}", color="${graphTheme.startBorder}", fontcolor="${graphTheme.startText}"]
exit [shape=Msquare, label="Exit", fillcolor="${graphTheme.startFill}", color="${graphTheme.startBorder}", fontcolor="${graphTheme.startText}"]
analyze [label="Analyze\\nBuild Errors"]
diagnose [label="Diagnose\\nRoot Cause"]
fix [label="Apply\\nFix"]
validate [label="Validate\\nBuild"]
approve [shape=hexagon, label="Review\\nChanges", fillcolor="${theme.gateFill}", color="${theme.gateBorder}", fontcolor="${theme.gateText}"]
approve [shape=hexagon, label="Review\\nChanges", fillcolor="${graphTheme.gateFill}", color="${graphTheme.gateBorder}", fontcolor="${graphTheme.gateText}"]
start -> analyze
analyze -> diagnose
@ -47,7 +46,7 @@ function buildDot(direction: Direction) {
fix -> validate
validate -> exit [label="Pass"]
validate -> diagnose [label="Fail", style=dashed, color="#f87171"]
validate -> approve [label="Needs review", color="${theme.gateBorder}"]
validate -> approve [label="Needs review", color="${graphTheme.gateBorder}"]
approve -> exit [label="Accept"]
approve -> fix [label="Revise", style=dashed]
}`;

View file

@ -58,7 +58,7 @@
<script type="module" src="/assets/chunk-sadshphz.js"></script>
<script type="module" src="/assets/chunk-pmthkscp.js"></script>
<script type="module" src="/assets/chunk-v61ks9f7.js"></script>
<script type="module" src="/assets/entry-c13135br.js"></script>
<script type="module" src="/assets/entry-znhdzrrr.js"></script>
<script type="module" src="/assets/chunk-n1k68xa8.js"></script>
<script type="module" src="/assets/chunk-rsph5pvm.js"></script>
<script type="module" src="/assets/chunk-9t57pdty.js"></script>