From 2f8f0bc9ebe787ee20efd1d1b900d6fa9d3f753a Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Wed, 23 Sep 2026 11:01:54 -0400 Subject: [PATCH] feat: worker lanes move to the System tab, in the roster's own idiom (4295) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Operator, 2026-09-23: *"where is the setting surface to set the number of each kind of worker? we have a system view under settings but no options to be set here"* — then *"move it to system tab and improve the view to be more inline with other UI elements."* They went looking under System and found a read-only roster. The card's own first cut argued that a control had no place on a tab about things being broken; that was wrong twice over. Half these lanes are optional and off by DESIGN, so "not running" is the normal state someone comes here to change — and a tab that only reports is a tab you leave in order to act somewhere else. So it is the roster's second half now, and built out of the same parts: the pane above says what is running, this one says how hard. Dot, name, detail, numbers on the right; the controls take the place the roster gives to latency. It was a bordered card wrapping a v-table, which is what made it read as bolted on. - The row styles move from SystemHealthTab's scoped block into app.css, so the second pane IS the first one's idiom rather than imitating it. A copy would have drifted the first time either was touched. - Lane state uses the roster's four dots. A lane that is off reads grey, never red: colouring an intended state as a fault is how an indicator stops being read. - The card owns its own polling. On Activity it rode that tab's 3s queue timer; System has none, so moving without this would have shown an empty pane to anyone who opened System first. 15s and `document.hidden`-guarded — it is a dial, not a live meter, and v-window keeps a hidden tab mounted. - The table header carried the column names, so each control now labels itself: `slots · cap N`, `auto`, `on`. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01LVjrnpQjRgHdvq95rASoiR --- .../components/settings/SystemActivityTab.vue | 7 - .../components/settings/SystemHealthTab.vue | 47 +- .../components/settings/WorkerLanesCard.vue | 430 ++++++++++-------- frontend/src/styles/app.css | 47 ++ 4 files changed, 296 insertions(+), 235 deletions(-) diff --git a/frontend/src/components/settings/SystemActivityTab.vue b/frontend/src/components/settings/SystemActivityTab.vue index 7c8d8a0..5e7f091 100644 --- a/frontend/src/components/settings/SystemActivityTab.vue +++ b/frontend/src/components/settings/SystemActivityTab.vue @@ -17,11 +17,6 @@ - - - @@ -177,7 +172,6 @@ import { useSystemActivityStore } from '../../stores/systemActivity.js' import { formatRelative as fmtRelative } from '../../utils/date.js' import ErrorDetailModal from '../common/ErrorDetailModal.vue' import QueuesTable from './QueuesTable.vue' -import WorkerLanesCard from './WorkerLanesCard.vue' import CardHeading from '../common/CardHeading.vue' import GpuActivityPanel from './GpuActivityPanel.vue' import DownloadsActivityPanel from './DownloadsActivityPanel.vue' @@ -242,7 +236,6 @@ function pollQueues() { store.loadQueues() store.loadWorkers() store.loadRecentRuns() - store.loadLanes() } function pollFailures() { if (document.hidden) return diff --git a/frontend/src/components/settings/SystemHealthTab.vue b/frontend/src/components/settings/SystemHealthTab.vue index c1853aa..753d2d2 100644 --- a/frontend/src/components/settings/SystemHealthTab.vue +++ b/frontend/src/components/settings/SystemHealthTab.vue @@ -65,6 +65,17 @@ then neither, and an indicator that reddened on every update would stop being read.

+ + + @@ -73,6 +84,7 @@ import { onMounted } from 'vue' import { useSystemHealthStore } from '../../stores/systemHealth.js' import { formatRelative } from '../../utils/date.js' +import WorkerLanesCard from './WorkerLanesCard.vue' const store = useSystemHealthStore() @@ -91,38 +103,3 @@ function kindLabel(kind) { // One refresh on open, so arriving at the tab doesn't wait out the nav's tick. onMounted(() => { store.refresh() }) - - diff --git a/frontend/src/components/settings/WorkerLanesCard.vue b/frontend/src/components/settings/WorkerLanesCard.vue index dce4fd8..247e9db 100644 --- a/frontend/src/components/settings/WorkerLanesCard.vue +++ b/frontend/src/components/settings/WorkerLanesCard.vue @@ -1,210 +1,194 @@