diff --git a/plugins/kanban/dashboard/dist/index.js b/plugins/kanban/dashboard/dist/index.js index 1f0b4c6d3b5..71adc77a666 100644 --- a/plugins/kanban/dashboard/dist/index.js +++ b/plugins/kanban/dashboard/dist/index.js @@ -2398,8 +2398,11 @@ ? h("div", { className: "hermes-kanban-run-error" }, r.error) : null, r.metadata - ? h("code", { className: "hermes-kanban-run-meta" }, - JSON.stringify(r.metadata)) + ? h("div", { className: "hermes-kanban-run-meta-block" }, + h("div", { className: "hermes-kanban-run-meta-label" }, "Metadata"), + h("code", { className: "hermes-kanban-run-meta" }, + JSON.stringify(r.metadata, null, 2)), + ) : null, ); }), diff --git a/plugins/kanban/dashboard/dist/style.css b/plugins/kanban/dashboard/dist/style.css index cb88bdfa5dd..3233facb53c 100644 --- a/plugins/kanban/dashboard/dist/style.css +++ b/plugins/kanban/dashboard/dist/style.css @@ -863,15 +863,37 @@ padding: 0.15rem 0 0; font-family: var(--font-mono, ui-monospace, monospace); } +/* Run metadata is a secondary detail panel. Render it as a clearly-labeled + * sub-block with a thin left rule, capped height, and muted treatment so + * a verbose JSON blob (e.g. changed_files + URLs from a writer task) does + * not visually swamp the parent run row or get mistaken for a crash dump. + * See issue #19548. */ +.hermes-kanban-run-meta-block { + margin-top: 0.4rem; + padding: 0.25rem 0.5rem; + border-left: 2px solid var(--color-border); + background: transparent; +} +.hermes-kanban-run-meta-label { + font-size: 0.65rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.06em; + color: var(--color-muted-foreground); + padding-bottom: 0.15rem; +} .hermes-kanban-run-meta { display: block; + max-height: 8.5rem; + overflow: auto; font-size: 0.72rem; line-height: 1.5; - padding: 0.15rem 0 0; + padding: 0; color: var(--color-muted-foreground); white-space: pre-wrap; word-break: break-word; font-family: var(--font-mono, ui-monospace, monospace); + background: transparent; } /* ------------------------------------------------------------------------- diff --git a/tests/plugins/test_kanban_dashboard_plugin.py b/tests/plugins/test_kanban_dashboard_plugin.py index 0fc6c493c14..9eb4ac45a97 100644 --- a/tests/plugins/test_kanban_dashboard_plugin.py +++ b/tests/plugins/test_kanban_dashboard_plugin.py @@ -1785,3 +1785,51 @@ def test_dashboard_lane_head_preserves_assignee_casing(): "Lane head must not visually uppercase profile names — see #21320 " "and the explanatory comment in the CSS rule." ) + + +# --------------------------------------------------------------------------- +# Built-asset regressions for the dashboard's run-history rendering +# (issue #19548 — completed-run metadata used to render as a large pale box +# that read like a crash dump). The plugin ships built-only, so we lock in +# the rendered shape with static assertions on dist/index.js + dist/style.css. +# --------------------------------------------------------------------------- + + +def _dashboard_dist_path(name: str) -> Path: + repo_root = Path(__file__).resolve().parents[2] + p = repo_root / "plugins" / "kanban" / "dashboard" / "dist" / name + assert p.exists(), f"dashboard asset missing: {p}" + return p + + +def test_run_metadata_pretty_printed_with_label(): + """Run-history metadata is pretty-printed JSON inside a labeled sub-block.""" + js = _dashboard_dist_path("index.js").read_text(encoding="utf-8") + # Pretty-printed JSON (indent=2) so a writer task's changed_files + + # URLs blob doesn't render as one wall-of-text monoline. + assert "JSON.stringify(r.metadata, null, 2)" in js + # Explicit label so the panel reads as auxiliary detail, not a crash dump. + assert '"hermes-kanban-run-meta-label"' in js + assert '"Metadata"' in js + # Wrapped in the labelled meta block container. + assert '"hermes-kanban-run-meta-block"' in js + + +def test_run_metadata_secondary_styling(): + """Metadata block is capped, transparent, and visually secondary.""" + css = _dashboard_dist_path("style.css").read_text(encoding="utf-8") + # The label class exists with muted-foreground treatment. + assert ".hermes-kanban-run-meta-label" in css + # Container styling: thin left rule, no opaque highlighted fill that + # could be mistaken for an error/warning panel. + assert ".hermes-kanban-run-meta-block" in css + block_start = css.index(".hermes-kanban-run-meta-block {") + block_decl = css[block_start : block_start + 400] + assert "background: transparent" in block_decl + assert "border-left" in block_decl + # Cap meta height so verbose JSON doesn't sprawl across the run row. + meta_start = css.index(".hermes-kanban-run-meta {") + meta_decl = css[meta_start : meta_start + 400] + assert "max-height" in meta_decl + assert "overflow: auto" in meta_decl + assert "color: var(--color-muted-foreground)" in meta_decl