Rework the dashboards onto the flow canvas
One shell for both editors. Flows and dashboards each get a searchable
overview under the padded shell, their editors move to the full-bleed
canvas, and the floating chrome is shared: a title bar that only says
what you are looking at, and a bottom dock carrying everything else —
the flow bar's status, settings and Publish moved down there, the
add-flow button moved to the overview.
Dashboards gain the rest of M4's visualization work:
- widgets are picked by clicking them, with the header as the drag
handle so a slider still slides and a switch still flips while
editing; settings moved into the flows' SidePanel
- react-grid-layout for drag and edge-resize, so the stored x/y finally
mean something; a dashboard nobody arranged is shelf-packed once
- a per-dashboard grid size, so a panel can be matched to its screen
- the chart widget, drawn with uPlot: several messages on one axis, fed
from the stored history plus the live socket tail, coloured from the
new --chart-1..5 ramp
- /view/{name}: the URL a wall panel is pointed at — no sidebar, no
footer, no editing, and no editor code, since routes are split
- a widget wired to a payload type it cannot carry, or wired to nothing
at all, carries the same red dot a failing node does; the picker
records the type it bound and WidgetDef refuses a mismatch on save
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H7LwYgJfpkbLCTeiAf8U4A
This commit is contained in:
@@ -19,9 +19,8 @@ test.afterAll(async ({ browser }) => {
|
||||
|
||||
test("a draft stays off the engine until it is published", async ({ page }) => {
|
||||
await page.goto("/flows")
|
||||
await page.getByRole("button", { name: "New flow" }).click()
|
||||
await page.getByTestId("flow-name-input").fill(flowName)
|
||||
await page.getByRole("button", { name: "Create flow" }).click()
|
||||
await page.getByTestId("new-flow-name").fill(flowName)
|
||||
await page.getByTestId("create-flow").click()
|
||||
await page.waitForURL(`/flows/${flowName}`)
|
||||
|
||||
await page.getByTestId("add-node").click()
|
||||
|
||||
@@ -73,9 +73,8 @@ test("a flow can be created, wired up, and comes back after a reload", async ({
|
||||
await page.goto("/flows")
|
||||
|
||||
// Create a flow of our own so the test does not lean on existing data.
|
||||
await page.getByRole("button", { name: "New flow" }).click()
|
||||
await page.getByTestId("flow-name-input").fill(flowName)
|
||||
await page.getByRole("button", { name: "Create flow" }).click()
|
||||
await page.getByTestId("new-flow-name").fill(flowName)
|
||||
await page.getByTestId("create-flow").click()
|
||||
await page.waitForURL(`/flows/${flowName}`)
|
||||
|
||||
await addFunctionNode(page, 1)
|
||||
|
||||
Reference in New Issue
Block a user