Put resources where somebody would look for them

`resources` was reachable from the SDK and the API and nowhere else, and
`node_queued` was published to nothing at all — so a node waiting for a machine
looked exactly like a node that had hung, which is the failure the event was
added for.

The node panel gets a Resources section: a size by name, the numbers for a node
that wants its own, and how long it is expected to take. Picking a flavor drops
the numbers, because saying both is two answers and the engine refuses it.

A queued node draws a neutral dot rather than one of the three status colours —
it is not running, it did not go well, and it did not go wrong; it is idle with
a reason, which the tooltip gives.

And a Workers screen, which is the first UI for any of this: every machine the
engine can reach with what is free of each, what is attached, what a cluster
has been asked for, and the sizes, editable. `fluksio status` grew a line of
the same.

The demo's training node already preferred a GPU worker, which was exactly the
declaration that used to be dropped, so it now says how much of that machine it
takes as well.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A6HeySA27EkGANZN95QySW
This commit is contained in:
2026-08-27 09:32:08 +02:00
co-authored by Claude Opus 5
parent 40f8ad378d
commit 7d87dfffdd
12 changed files with 1156 additions and 7 deletions
+10 -1
View File
@@ -91,10 +91,11 @@ for (const theme of ["light", "dark"]) {
await captureDashboards(page, dir)
await captureMedia(page, dir)
await captureRuns(page, dir)
await captureWorkers(page, dir)
await context.close()
console.log(
` wrote ${dir}/{website-hero,app-login,app-dashboard,app-flows,app-flow-panel,app-panel,app-runs,app-run,app-run-context}.png`,
` wrote ${dir}/{website-hero,app-login,app-dashboard,app-flows,app-flow-panel,app-panel,app-runs,app-run,app-run-context,app-workers}.png`,
)
}
}
@@ -232,6 +233,14 @@ async function captureMedia(page, dir) {
* The flow editor, empty-handed if the instance has no flows yet: seeds one
* with a node so the canvas and the node panel are both worth looking at.
*/
/** Every machine a node can run on, and the sizes it can ask for. */
async function captureWorkers(page, dir) {
await page.goto(`${APP_URL}/workers`, { waitUntil: "networkidle" })
await page.getByText(/^Sizes$/).waitFor({ timeout: 15000 })
await page.waitForTimeout(500)
await page.screenshot({ path: `${dir}/app-workers.png`, fullPage: true })
}
async function captureFlows(page, dir) {
await page.goto(`${APP_URL}/flows`, { waitUntil: "networkidle" })