CI / test (push) Successful in 1m32s
The metrics were exported and the only way to look at them was to stand up Prometheus beside the binary. For a project whose whole shape is one static binary with no dependencies, that is the wrong default: the common case is somebody wanting to know how full their cluster is, and that should not cost a monitoring stack. /admin now shows capacity per GPU class with a usage bar, free whole nodes per fabric — the number that decides whether a replica spanning nodes can land, since free cards on the wrong fabric are not capacity for a model that needs this one — and which replicas are holding hardware nobody is asking for. Nodes gain their memory and how many model files they can see. Taken from the same Summary that ctl status uses rather than derived in the page, because two implementations of the same arithmetic drift apart and the one on the screen is the one people would believe. A faulty card counts as neither used nor free, matching the scheduler. Counting it free is how a cluster looks like it has room it does not, and a page that disagreed with placement about that would be worse than no page. Prometheus stays supported and is now the answer to a narrower question: history, alerting, several clusters at once. The dashboard shows what is true now and keeps nothing, which is the honest division between them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
123 lines
6.5 KiB
CSS
123 lines
6.5 KiB
CSS
/* Deliberately one small stylesheet with no build step. The single-binary goal
|
|
rules out a JS toolchain, and nothing here needs one. */
|
|
:root {
|
|
color-scheme: light dark;
|
|
--bg: #fbfbfa;
|
|
--fg: #1c1c1a;
|
|
--muted: #6b6b66;
|
|
--line: #e3e3df;
|
|
--card: #ffffff;
|
|
--accent: #2f5d50;
|
|
--ok: #2f7a4f;
|
|
--warn: #9a6b1f;
|
|
--bad: #a33a32;
|
|
}
|
|
@media (prefers-color-scheme: dark) {
|
|
:root {
|
|
--bg: #17181a; --fg: #e8e8e4; --muted: #9a9a93; --line: #2c2e31;
|
|
--card: #1e2022; --accent: #7fb3a2; --ok: #6fbd8c; --warn: #d6a44e; --bad: #e07b72;
|
|
}
|
|
}
|
|
* { box-sizing: border-box; }
|
|
body {
|
|
margin: 0; background: var(--bg); color: var(--fg);
|
|
font: 15px/1.55 ui-sans-serif, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
}
|
|
.wrap { max-width: 1100px; margin: 0 auto; padding: 2.5rem 1.25rem 4rem; }
|
|
header { border-bottom: 1px solid var(--line); margin-bottom: 2rem; padding-bottom: 1.25rem; }
|
|
h1 { font-size: 1.5rem; margin: 0 0 .25rem; letter-spacing: -.01em; }
|
|
h2 { font-size: 1.05rem; margin: 2.25rem 0 .75rem; letter-spacing: -.005em; }
|
|
.sub { color: var(--muted); margin: 0; }
|
|
nav { margin-top: .75rem; display: flex; gap: 1rem; flex-wrap: wrap; }
|
|
nav a { color: var(--accent); text-decoration: none; font-size: .9rem; }
|
|
nav a:hover { text-decoration: underline; }
|
|
table { width: 100%; border-collapse: collapse; font-size: .875rem; background: var(--card);
|
|
border: 1px solid var(--line); border-radius: 6px; overflow: hidden; }
|
|
th, td { text-align: left; padding: .5rem .7rem; border-bottom: 1px solid var(--line); }
|
|
th { font-weight: 600; color: var(--muted); font-size: .78rem; text-transform: uppercase;
|
|
letter-spacing: .04em; }
|
|
tr:last-child td { border-bottom: none; }
|
|
td.num { text-align: right; font-variant-numeric: tabular-nums; }
|
|
code, pre { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .85em; }
|
|
pre { background: var(--card); border: 1px solid var(--line); border-radius: 6px;
|
|
padding: .9rem 1rem; overflow-x: auto; }
|
|
.state { font-weight: 600; font-size: .8rem; }
|
|
.state-ready, .state-active { color: var(--ok); }
|
|
.state-pending, .state-starting, .state-draining, .state-cordoned { color: var(--warn); }
|
|
.state-failed, .state-lost, .state-unreachable, .state-revoked { color: var(--bad); }
|
|
.empty { color: var(--muted); font-style: italic; padding: .9rem 0; }
|
|
.note { color: var(--muted); font-size: .85rem; margin: .4rem 0 0; }
|
|
footer { margin-top: 3rem; padding-top: 1rem; border-top: 1px solid var(--line);
|
|
color: var(--muted); font-size: .8rem; display: flex; justify-content: space-between; gap: 1rem; }
|
|
button {
|
|
font: inherit; font-weight: 600; cursor: pointer;
|
|
background: var(--accent); color: var(--bg); border: none;
|
|
border-radius: 6px; padding: .55rem 1.1rem;
|
|
}
|
|
button:hover { filter: brightness(1.1); }
|
|
ul { padding-left: 1.2rem; }
|
|
li { margin: .25rem 0; }
|
|
a { color: var(--accent); }
|
|
.wrap.narrow { max-width: 30rem; }
|
|
label { display: block; margin: .9rem 0; font-size: .9rem; font-weight: 600; }
|
|
input[type=text], input[type=email], input[type=password] {
|
|
display: block; width: 100%; margin-top: .3rem; font: inherit; font-weight: 400;
|
|
padding: .5rem .6rem; border: 1px solid var(--line); border-radius: 6px;
|
|
background: var(--card); color: var(--fg);
|
|
}
|
|
input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
|
|
.error { color: var(--bad); border: 1px solid var(--bad); border-radius: 6px;
|
|
padding: .6rem .8rem; background: var(--card); }
|
|
form.inline { display: inline; }
|
|
button.link { background: none; color: var(--accent); padding: 0;
|
|
text-decoration: underline; font-weight: 400; font-size: .9rem; }
|
|
button.link.danger { color: var(--bad); }
|
|
.ok { color: var(--ok); border: 1px solid var(--ok); border-radius: 6px;
|
|
padding: .6rem .8rem; background: var(--card); }
|
|
select { font: inherit; padding: .35rem .4rem; border: 1px solid var(--line);
|
|
border-radius: 6px; background: var(--card); color: var(--fg); }
|
|
.chart-wrap { position: relative; margin: .5rem 0 1.5rem; }
|
|
.chart { width: 100%; height: 120px; display: block;
|
|
background: var(--card); border: 1px solid var(--line); border-radius: 6px; }
|
|
.chart rect { transition: opacity .1s; }
|
|
.chart rect:hover { opacity: .65; }
|
|
.chart .axis { stroke: var(--line); stroke-width: 1; }
|
|
.chart-peak { position: absolute; top: .4rem; right: .6rem;
|
|
font-size: .72rem; color: var(--muted); }
|
|
.chart-row { display: grid; gap: 1rem; grid-template-columns: 1fr 1fr; }
|
|
@media (max-width: 720px) { .chart-row { grid-template-columns: 1fr; } }
|
|
.chat-bar { display: flex; align-items: center; gap: 1rem; margin-bottom: .75rem; }
|
|
.inline-label { font-size: .85rem; font-weight: 600; margin: 0; }
|
|
.inline-label select { margin-left: .4rem; font-weight: 400; }
|
|
.chat-log { min-height: 16rem; max-height: 55vh; overflow-y: auto; padding: .5rem;
|
|
background: var(--card); border: 1px solid var(--line); border-radius: 6px; }
|
|
.bubble { white-space: pre-wrap; word-wrap: break-word; padding: .55rem .75rem;
|
|
margin: .4rem 0; border-radius: 8px; max-width: 46rem; }
|
|
.bubble.you { background: var(--accent); color: var(--bg); margin-left: auto; }
|
|
.bubble.assistant { background: var(--bg); border: 1px solid var(--line); }
|
|
.bubble.failed { color: var(--bad); border-color: var(--bad); }
|
|
.chat-composer { display: flex; gap: .6rem; margin-top: .75rem; align-items: flex-end; }
|
|
.chat-composer textarea { flex: 1; font: inherit; padding: .5rem .6rem; resize: vertical;
|
|
border: 1px solid var(--line); border-radius: 6px; background: var(--card); color: var(--fg); }
|
|
|
|
/* KaTeX sits inside a bubble that sets white-space: pre-wrap for plain text;
|
|
display maths needs to escape that or every fraction gets the newlines in
|
|
its own source. */
|
|
.bubble .katex-display { white-space: normal; margin: .6rem 0; overflow-x: auto; }
|
|
.bubble .katex { white-space: normal; }
|
|
.bubble.you .katex { color: inherit; }
|
|
/* A reply that stopped because it ran out of room, not because it was done. */
|
|
.note.truncated { color: var(--warn, #a15c00); margin: .2rem 0 .8rem; }
|
|
/* Offered under a reply that contains files worth keeping. */
|
|
.link.download { display: inline-block; margin: .3rem 0 .8rem; }
|
|
|
|
/* A usage bar inside a table cell. Drawn with two elements rather than a
|
|
gradient so the number stays selectable and readable by a screen reader. */
|
|
.meter { position: relative; min-width: 9rem; }
|
|
.meter > span {
|
|
display: block; height: .75rem; border-radius: 2px;
|
|
background: var(--accent); opacity: .55;
|
|
}
|
|
.meter > em { font-style: normal; font-size: .8rem; color: var(--muted); }
|
|
.bad { color: var(--bad); }
|