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:
@@ -90,6 +90,7 @@ async function captureDashboards(page, dir) {
|
||||
await page.getByTestId("create-dashboard").click()
|
||||
await page.waitForURL(/\/dashboards\/.+/, { timeout: 15000 })
|
||||
// A widget, so the grid has something in it worth photographing.
|
||||
await page.getByTestId("add-widget").click()
|
||||
await page.getByTestId("add-widget-stat").click()
|
||||
await page.waitForSelector("[data-testid=widget-settings]")
|
||||
await page.getByTestId("toggle-edit").click()
|
||||
@@ -109,11 +110,13 @@ async function captureDashboards(page, dir) {
|
||||
async function captureFlows(page, dir) {
|
||||
await page.goto(`${APP_URL}/flows`, { waitUntil: "networkidle" })
|
||||
|
||||
const seed = page.getByTestId("create-first-flow")
|
||||
if (await seed.count()) {
|
||||
await seed.click()
|
||||
await page.waitForURL(/\/flows\/.+/, { timeout: 15000 })
|
||||
if (await page.getByTestId("flow-card").count()) {
|
||||
await page.getByTestId("flow-card").first().click()
|
||||
} else {
|
||||
await page.getByTestId("new-flow-name").fill("first_flow")
|
||||
await page.getByTestId("create-flow").click()
|
||||
}
|
||||
await page.waitForURL(/\/flows\/.+/, { timeout: 15000 })
|
||||
|
||||
if (!(await page.locator(".react-flow__node").count())) {
|
||||
await page.getByTestId("add-node").click()
|
||||
@@ -126,7 +129,7 @@ async function captureFlows(page, dir) {
|
||||
|
||||
// Adding a node opens its panel; the canvas shot wants it out of the way.
|
||||
await page.keyboard.press("Escape")
|
||||
// The dock and tabs slide in; let them land before the shutter.
|
||||
// The dock and the title bar slide in; let them land before the shutter.
|
||||
await page.waitForTimeout(1200)
|
||||
await page.screenshot({ path: `${dir}/app-flows.png` })
|
||||
|
||||
|
||||
Reference in New Issue
Block a user