feat: multi-style pure SVG org chart renderer (no Playwright needed)

Rewrote org-chart-svg.ts to support all 5 styles (monochrome, nebula,
circuit, warmth, schematic) as pure SVG — no browser or Satori needed.
Routes now accept ?style= query param. Added standalone comparison script.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
dotta 2026-03-20 06:33:29 -05:00
parent 6a568662b8
commit f2c42aad12
3 changed files with 516 additions and 89 deletions

View file

@ -47,7 +47,7 @@ import { assertBoard, assertCompanyAccess, getActorInfo } from "./authz.js";
import { findServerAdapter, listAdapterModels } from "../adapters/index.js";
import { redactEventPayload } from "../redaction.js";
import { redactCurrentUserValue } from "../log-redaction.js";
import { renderOrgChartSvg, renderOrgChartPng, type OrgNode } from "./org-chart-svg.js";
import { renderOrgChartSvg, renderOrgChartPng, type OrgNode, type OrgChartStyle, ORG_CHART_STYLES } from "./org-chart-svg.js";
import { runClaudeLogin } from "@paperclipai/adapter-claude-local/server";
import {
DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX,
@ -899,9 +899,10 @@ export function agentRoutes(db: Db) {
router.get("/companies/:companyId/org.svg", async (req, res) => {
const companyId = req.params.companyId as string;
assertCompanyAccess(req, companyId);
const style = (ORG_CHART_STYLES.includes(req.query.style as OrgChartStyle) ? req.query.style : "warmth") as OrgChartStyle;
const tree = await svc.orgForCompany(companyId);
const leanTree = tree.map((node) => toLeanOrgNode(node as Record<string, unknown>));
const svg = renderOrgChartSvg(leanTree as unknown as OrgNode[]);
const svg = renderOrgChartSvg(leanTree as unknown as OrgNode[], style);
res.setHeader("Content-Type", "image/svg+xml");
res.setHeader("Cache-Control", "no-cache");
res.send(svg);
@ -910,9 +911,10 @@ export function agentRoutes(db: Db) {
router.get("/companies/:companyId/org.png", async (req, res) => {
const companyId = req.params.companyId as string;
assertCompanyAccess(req, companyId);
const style = (ORG_CHART_STYLES.includes(req.query.style as OrgChartStyle) ? req.query.style : "warmth") as OrgChartStyle;
const tree = await svc.orgForCompany(companyId);
const leanTree = tree.map((node) => toLeanOrgNode(node as Record<string, unknown>));
const png = await renderOrgChartPng(leanTree as unknown as OrgNode[]);
const png = await renderOrgChartPng(leanTree as unknown as OrgNode[], style);
res.setHeader("Content-Type", "image/png");
res.setHeader("Cache-Control", "no-cache");
res.send(png);