// SVG Pipeline Stage Visualization import { STAGES, STAGE_SHORT, STAGE_HEX } from "../../design/tokens"; import { escapeHtml } from "../../core/helpers"; import type { PipelineInfo } from "../../types/api"; export function renderPipelineSVG(pipeline: PipelineInfo): string { const stagesDone = pipeline.stagesDone || []; const currentStage = pipeline.stage || ""; const failed = pipeline.status === "failed"; const nodeSpacing = 80; const nodeR = 14; const svgWidth = STAGES.length * nodeSpacing + 40; const svgHeight = 72; const yCenter = 28; const yLabel = 60; let svg = ``; // Connecting lines for (let i = 0; i < STAGES.length - 1; i++) { const x1 = 20 + i * nodeSpacing + nodeR; const x2 = 20 + (i + 1) * nodeSpacing - nodeR; const isDone = stagesDone.indexOf(STAGES[i]) !== -1; const lineColor = isDone ? "#4ade80" : "#1a3a6a"; const dashAttr = isDone ? "" : ' stroke-dasharray="4,3"'; svg += ``; } // Stage nodes for (let i = 0; i < STAGES.length; i++) { const s = STAGES[i]; const cx = 20 + i * nodeSpacing; const isDone = stagesDone.indexOf(s) !== -1; const isActive = s === currentStage; const isFailed = failed && isActive; let fillColor = "#0d1f3c"; let strokeColor = "#1a3a6a"; let textColor = "#5a6d8a"; let extra = ""; if (isDone) { fillColor = "#4ade80"; strokeColor = "#4ade80"; textColor = "#060a14"; } else if (isFailed) { fillColor = "#f43f5e"; strokeColor = "#f43f5e"; textColor = "#fff"; } else if (isActive) { fillColor = "#00d4ff"; strokeColor = "#00d4ff"; textColor = "#060a14"; extra = ' class="stage-node-active"'; } if (isActive && !isFailed) { svg += `` + `` + ``; } svg += ``; svg += `${STAGE_SHORT[s]}`; svg += `${escapeHtml(s === "compound_quality" ? "quality" : s)}`; } svg += ""; return svg; } export function renderDoraGrades( dora: | Record | null | undefined, ): string { if (!dora) return ""; const metrics = [ { key: "deploy_freq", label: "Deploy Frequency" }, { key: "lead_time", label: "Lead Time" }, { key: "cfr", label: "Change Failure Rate" }, { key: "mttr", label: "Mean Time to Recovery" }, ]; let html = '
'; for (const m of metrics) { const d = (dora as Record)[m.key]; if (!d) continue; const grade = (d.grade || "N/A").toLowerCase(); const gradeClass = "dora-" + grade; html += `
` + `${escapeHtml(m.label)}` + `${escapeHtml(d.grade || "N/A")}` + `${d.value != null ? d.value.toFixed(1) : "\u2014"} ${escapeHtml(d.unit || "")}` + `
`; } html += "
"; return html; }