hyperhive/frontend/packages/dashboard/src/system-sections.css
iris ffb2d78a56 fix(dashboard): draw jobq tree connectors with CSS lines instead of box-drawing chars
Replace the Unicode prefix string approach (└─ / ├─ / │  built up as text
in a single <span class="rqe-tree-indent">) with positioned DOM elements
that draw real lines:

- rqe-tree-guide: fixed-width ancestor column, optionally draws a full
  vertical border-left when the ancestor has siblings below it
  (.rqe-tree-guide-line).
- rqe-tree-connector: draws the L/T shape via ::before (vertical stem,
  top→center for last child, full height for mid child) and ::after
  (horizontal spur, center→right). .rqe-tree-connector-last vs
  .rqe-tree-connector-mid controls stem length.

renderTreeNode() now takes ancestorLines: boolean[] instead of a prefix
string. Each entry is true when the ancestor at that depth was not the
last child (so a vertical guide is still needed through that column).
childAncestorLines propagates depth === 0 correctly (root nodes have no
guide columns, so their children start with an empty array).

Lines are drawn with var(--border) so they follow the theme and work at
any font size without alignment drift. Addresses the review note on PR 2686.
2026-07-26 03:14:52 +02:00

395 lines
11 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* ─── SYST3M/BU1LDS section panels — shared by dashboard, /core.html,
and /builds.html ──────────────────────────────────────────────────
Rebuild queue, meta inputs, kept state, and container-load panels.
Imported by core.css, dashboard.css, and builds.css. */
/* ─── meta inputs panel ────────────────────────────────────────────── */
.meta-inputs {
list-style: none;
padding: 0;
margin: 0 0 0.8em;
display: grid;
gap: 0.2em;
}
.meta-inputs li {
padding: 0.25em 0.6em;
border: 1px solid var(--border);
background: color-mix(in srgb, var(--bg-elev) 60%, transparent);
}
.meta-inputs label {
display: flex;
align-items: baseline;
gap: 0.5em;
cursor: pointer;
font-size: 0.9em;
}
.meta-input-name { color: var(--amber); font-weight: bold; }
.meta-input-rev { color: var(--muted); }
.meta-input-ts { color: var(--muted); font-size: 0.85em; }
.meta-input-url {
color: var(--muted);
font-size: 0.85em;
margin-left: auto;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.meta-inputs-bulk {
margin: 0 0 0.5em;
font-size: 0.8em;
color: var(--muted);
}
.meta-bulk-btn {
font: inherit;
font-size: 1em;
background: transparent;
border: 1px solid var(--purple-dim);
color: var(--cyan);
padding: 0.1em 0.6em;
margin-right: 0.2em;
cursor: pointer;
}
.meta-bulk-btn:hover {
border-color: var(--cyan);
text-shadow: 0 0 6px currentColor;
}
.meta-input-twig {
color: var(--purple-dim);
margin-right: 0.1em;
}
.btn-meta-update {
background: color-mix(in srgb, var(--purple) 12%, transparent);
border: 1px solid var(--purple);
color: var(--purple);
text-shadow: 0 0 4px currentColor;
padding: 0.3em 1em;
font: inherit;
font-size: 0.85em;
letter-spacing: 0.08em;
cursor: pointer;
transition: box-shadow 0.15s ease, background 0.15s ease;
}
.btn-meta-update:hover:not([disabled]) {
background: color-mix(in srgb, var(--purple) 22%, transparent);
box-shadow: 0 0 10px -2px currentColor;
}
.btn-meta-update[disabled] {
opacity: 0.35;
cursor: not-allowed;
}
.meta-update-running {
margin: 0 0 0.7em;
padding: 0.4em 0.7em;
border: 1px solid var(--purple);
background: color-mix(in srgb, var(--purple) 12%, transparent);
color: var(--purple);
font-size: 0.85em;
animation: badge-pulse 1.6s ease-in-out infinite;
}
/* ─── rebuild queue panel ──────────────────────────────────────────────── */
.rebuild-queue {
list-style: none;
padding: 0;
margin: 0;
display: grid;
gap: 0.2em;
}
.rebuild-queue-entry {
padding: 0.3em 0.6em;
border: 1px solid var(--border);
background: color-mix(in srgb, var(--bg-elev) 60%, transparent);
font-size: 0.9em;
display: flex;
flex-wrap: wrap;
align-items: baseline;
gap: 0.4em;
}
.rebuild-queue-entry.rqe-running {
border-color: var(--purple);
background: color-mix(in srgb, var(--purple) 12%, transparent);
animation: badge-pulse 1.6s ease-in-out infinite;
}
.rebuild-queue-entry.rqe-failed { border-color: var(--red); color: var(--red); }
.rebuild-queue-entry.rqe-cancelled { opacity: 0.6; }
.rebuild-queue-entry.rqe-done { opacity: 0.7; color: var(--green); }
.rqe-state { font-weight: bold; min-width: 1.2em; text-align: center; }
.rqe-kind { color: var(--cyan); }
.rqe-agent { color: var(--amber); font-weight: bold; }
.rqe-source {
font-size: 0.75em;
padding: 0.05em 0.45em;
border-radius: 0.7em;
border: 1px solid var(--border);
color: var(--muted);
text-transform: uppercase;
letter-spacing: 0.05em;
}
.rqe-source-manual { color: var(--cyan); border-color: var(--cyan); }
.rqe-source-meta_update { color: var(--purple); border-color: var(--purple); }
.rqe-source-auto_update { color: var(--muted); }
.rqe-source-crash_recover { color: var(--amber); border-color: var(--amber); }
.rqe-source-approval { color: var(--green); border-color: var(--green); }
.rqe-when { color: var(--muted); font-size: 0.85em; }
.rqe-reason { color: var(--muted); font-size: 0.85em; flex: 1 1 auto; }
/* Per-node DAG chain: one chip per primitive node, dependency order. */
.rqe-nodes {
flex-basis: 100%;
margin: 0.15em 0 0 1.8em;
font-size: 0.85em;
display: flex;
flex-wrap: wrap;
align-items: baseline;
gap: 0.15em;
}
/* ─── jobq node tree (replaces .rqe-nodes for tree-structured payloads) ──── */
.rqe-nodes-tree {
flex-basis: 100%;
margin: 0.25em 0 0 1.8em;
font-size: 0.85em;
display: flex;
flex-direction: column;
gap: 3px;
}
.rqe-tree-row {
display: flex;
align-items: center;
gap: 0;
min-height: 1.6em;
}
/* Guide column: fixed-width spacer that optionally draws a vertical guide
line through rows where a sibling of an ancestor continues below. */
.rqe-tree-guide,
.rqe-tree-connector {
flex-shrink: 0;
width: 1.1em;
align-self: stretch;
position: relative;
}
.rqe-tree-guide-line::before {
content: '';
position: absolute;
left: 50%;
top: 0;
bottom: 0;
border-left: 1px solid var(--border);
}
/* Connector: vertical stem from top, horizontal spur to the right.
Last child (└): stem goes top→center. Mid child (├): stem is full height. */
.rqe-tree-connector::before {
content: '';
position: absolute;
left: 50%;
top: 0;
bottom: 50%;
border-left: 1px solid var(--border);
}
.rqe-tree-connector-mid::before {
bottom: 0;
}
.rqe-tree-connector::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
right: 0;
border-top: 1px solid var(--border);
}
.rqe-node {
padding: 0.05em 0.45em;
border: 1px solid var(--border);
border-radius: 0.7em;
color: var(--muted);
white-space: nowrap;
}
.rqe-node-running {
color: var(--purple);
border-color: var(--purple);
animation: badge-pulse 1.6s ease-in-out infinite;
}
.rqe-node-done { color: var(--green); border-color: color-mix(in srgb, var(--green) 45%, transparent); }
.rqe-node-failed { color: var(--red); border-color: var(--red); }
.rqe-node-cancelled { opacity: 0.55; text-decoration: line-through; }
.rqe-node-arrow { color: var(--muted); }
.rqe-node-log { margin-left: 0.1em; text-decoration: none; }
.rqe-step {
flex-basis: 100%;
margin: 0.1em 0 0 1.8em;
color: var(--cyan);
font-size: 0.85em;
}
.rqe-error {
flex-basis: 100%;
margin: 0.3em 0 0;
padding: 0.3em 0.5em;
background: color-mix(in srgb, var(--red) 10%, transparent);
border-left: 2px solid var(--red);
color: var(--red);
font-size: 0.8em;
white-space: pre-wrap;
}
.rqe-cancel {
margin-left: auto;
}
.rqe-cancel-btn {
background: transparent;
border: 1px solid var(--purple-dim);
color: var(--muted);
border-radius: 999px;
width: 1.6em;
height: 1.6em;
font-size: 0.85em;
line-height: 1;
padding: 0;
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
transition: color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
.rqe-cancel-btn:hover:not(:disabled),
.rqe-cancel-btn:focus-visible {
color: var(--red);
border-color: var(--red);
box-shadow: 0 0 8px -2px var(--red);
outline: none;
}
.rqe-cancel-btn:disabled {
opacity: 0.5;
cursor: default;
}
/* ─── running-rebuild live log (renderRebuildLiveLog in builds.js) ──────────
Streams the currently-running rebuild's build log inline under the queue.
Hidden (native `hidden` attr) when nothing is building. Used on
/builds.html; lives here (not in builds.css) so it can be shared if
the dashboard ever gains an inline live-log view. */
.rebuild-live-log {
margin-top: 0.8em;
border: 1px solid var(--purple-dim);
border-radius: 4px;
background: color-mix(in srgb, var(--crust) 70%, transparent);
}
.rebuild-live-log-header {
display: flex;
align-items: center;
gap: 0.4em;
padding: 0.4em 0.6em;
font-size: 0.85em;
border-bottom: 1px solid var(--border);
}
.rebuild-live-log-toggle {
background: transparent;
border: 0;
color: var(--muted);
cursor: pointer;
font-family: inherit;
font-size: 1em;
padding: 0 0.2em;
}
.rebuild-live-log-toggle:hover { color: var(--fg); }
.rebuild-live-log-title { color: var(--muted); }
.rebuild-live-log-raw {
margin-left: auto;
color: var(--purple);
text-decoration: none;
font-size: 0.9em;
}
.rebuild-live-log-raw:hover { text-decoration: underline; }
.rebuild-live-log-badge {
font-size: 0.75em;
font-weight: bold;
padding: 0.05em 0.5em;
border-radius: 999px;
letter-spacing: 0.05em;
}
.rebuild-live-log-badge.rll-running {
color: var(--amber);
background: color-mix(in srgb, var(--amber) 18%, transparent);
}
.rebuild-live-log-badge.rll-ok {
color: var(--green);
background: color-mix(in srgb, var(--green) 18%, transparent);
}
.rebuild-live-log-badge.rll-fail {
color: var(--red);
background: color-mix(in srgb, var(--red) 18%, transparent);
}
.rebuild-live-log-output {
margin: 0;
padding: 0.5em 0.7em;
max-height: 22em;
overflow-y: auto;
white-space: pre-wrap;
word-break: break-word;
font-family: "JetBrains Mono", "Fira Code", "Cascadia Code", "Source Code Pro", monospace;
font-size: 0.8em;
line-height: 1.4;
color: var(--fg);
}
/* ─── SYST3M C0NT41N3R L04D: live cgroup cpu/mem ─────────────────────────────
Reuses the shared `.hive-stats-table` styling (in common.css); only
the inline meter bar is new. */
.cload-meter {
display: inline-block;
width: 6em;
height: 10px;
vertical-align: middle;
margin-left: 6px;
background: var(--bg-elev);
border: 1px solid var(--border);
border-radius: 3px;
overflow: hidden;
}
.cload-meter .fill {
display: block;
height: 100%;
background: var(--green);
}
.cload-meter .fill.warn {
background: var(--amber);
}
.cload-meter .fill.hot {
background: var(--red);
}
/* ─── K3PT ST4T3 stale permission entries sub-section ────────────────────
Agents with explicit capability / tool-group entries in the JSON but no
live container (renamed or manually-deleted agents). Lazy-loaded on tab
activation, refreshed on capabilities_changed / tool_groups_changed. */
.tombstones-stale-heading {
margin: 1.2em 0 0.3em;
color: var(--muted);
font-size: 0.8em;
text-transform: uppercase;
letter-spacing: 0.08em;
border-top: 1px solid var(--border);
padding-top: 0.8em;
}
.tombstones-stale-list {
list-style: none;
padding: 0;
margin: 0;
display: grid;
gap: 0.3em;
}
.tombstones-stale-row {
display: flex;
align-items: center;
gap: 0.5em;
padding: 0.35em 0.6em;
border: 1px dashed var(--border);
background: color-mix(in srgb, var(--bg-elev) 35%, transparent);
}
.tombstones-stale-name {
color: var(--muted);
font-weight: bold;
font-size: 0.9em;
}
.tombstones-stale-err {
margin-top: 0.4em;
color: var(--red);
font-size: 0.85em;
}