from html import escape from pathlib import Path from typing import Dict, List ACCESS_COLOR = { "PRIVATE": "#6b7280", "SHARED_USERS": "#d97706", "DOMAIN": "#ea580c", "PUBLIC": "#dc2626", } def _safe(value: str) -> str: return escape(str(value or "")) def render_diagram(summary_rows: List[dict], output_html: Path, max_rows: int = 120) -> None: rows = summary_rows[:max_rows] by_root: Dict[str, List[dict]] = {} for row in rows: root = row["root_path"] by_root.setdefault(root, []).append(row) roots = sorted(by_root.keys()) for root in roots: by_root[root].sort(key=lambda x: -int(x["item_count"])) total_items = sum(int(r["item_count"]) for r in rows) root_cols = [] for root in roots: items = by_root[root][:16] root_total = sum(int(x["item_count"]) for x in items) cards = [] for item in items: access = item["access_scope"] color = ACCESS_COLOR.get(access, "#6b7280") owner = item["owner_email"] if len(owner) > 32: owner = owner[:31] + "..." cards.append( f"""