Files
openclaw/scripts/capture-workboard-ui-proof.mts
T
Peter Steinberger 2915e563d6 feat(workboard): show full boards on session dashboards (#125094)
* feat(workboard): full-board dashboard widget

Adds a third trusted plugin widget kind, workboard:board, rendering the
complete Kanban board (all columns, live plugin.workboard.changed
refresh) inside a session dashboard. Props {boardId} scope it to one
board; without it the widget shows every board, matching workboard:mini
semantics. Card rendering reuses the workboard page renderColumn with an
explicit surface option so page and widget cannot drift; the shared
board filter moved to ui/src/lib/workboard/board-filter.ts. Mutations
follow the connection's canMutate; read-only connections get a
view-only board.

Proof: pnpm test ui/src/lib/board ui/src/pages/workboard
ui/src/lib/workboard extensions/workboard (9,494 passed), i18n baseline
green, autoreview clean (codex/gpt-5.6-sol). tsgo core/ui/extensions
green locally; remote check:changed blocked by Daytona capacity and the
tsgo:core Daytona exit reproduced locally as a heavy-check lock race,
passing on retry.

* test(ui): seed workboard fixtures in the mocked dev server

* fix(ci): register workboard proof capture script
2026-08-16 23:19:30 -07:00

90 lines
3.2 KiB
TypeScript

#!/usr/bin/env node
import { mkdir } from "node:fs/promises";
import path from "node:path";
import { chromium } from "playwright";
import {
canRunPlaywrightChromium,
resolvePlaywrightChromiumExecutablePath,
} from "../ui/src/test-helpers/control-ui-e2e.ts";
const DEFAULT_BASE_URL = "http://127.0.0.1:5187";
const DEFAULT_OUTPUT_DIR = path.resolve(".artifacts/control-ui-e2e/workboard-proof");
const WORKBOARD_SESSION_KEY = "agent:main:workboard-proof";
function readOption(name: string): string | undefined {
const prefix = `--${name}=`;
const inline = process.argv.slice(2).find((arg) => arg.startsWith(prefix));
if (inline) {
return inline.slice(prefix.length);
}
const index = process.argv.indexOf(`--${name}`);
return index >= 0 ? process.argv[index + 1] : undefined;
}
const baseUrl = new URL(readOption("base-url") ?? DEFAULT_BASE_URL);
const outputDir = path.resolve(readOption("output-dir") ?? DEFAULT_OUTPUT_DIR);
const executablePath = resolvePlaywrightChromiumExecutablePath(chromium.executablePath());
if (!canRunPlaywrightChromium(executablePath)) {
throw new Error(`Playwright Chromium is unavailable at ${executablePath}`);
}
await mkdir(outputDir, { recursive: true });
const browser = await chromium.launch({ executablePath });
const context = await browser.newContext({
colorScheme: "light",
reducedMotion: "reduce",
viewport: { width: 1440, height: 900 },
});
const page = await context.newPage();
page.setDefaultTimeout(30_000);
const gatewayUrl = new URL(baseUrl);
gatewayUrl.protocol = gatewayUrl.protocol === "https:" ? "wss:" : "ws:";
const settingsKey = `openclaw.control.settings.v1:${gatewayUrl.origin}`;
await page.addInitScript(
({ key, sessionKey }) => {
localStorage.setItem(
key,
JSON.stringify({
boardSessionViews: { [sessionKey]: { activeTabId: "main" } },
theme: "light",
}),
);
},
{ key: settingsKey, sessionKey: WORKBOARD_SESSION_KEY },
);
try {
await page.goto(new URL("/workboard/peter-tasks", baseUrl).toString());
const automationChip = page.locator(".workboard-automation-chip");
await automationChip.waitFor();
if ((await automationChip.textContent())?.trim() !== "Automation") {
throw new Error("Workboard automation chip did not render its expected label");
}
await page.getByText("Prepare launch readiness checklist", { exact: true }).waitFor();
await page.screenshot({
animations: "disabled",
path: path.join(outputDir, "workboard-chip.png"),
});
await page.goto(new URL("/dashboard", baseUrl).toString());
const widget = page.locator('[data-test-id="workboard-board-widget"]');
await widget.waitFor();
await page.getByText("Validate onboarding flow", { exact: true }).waitFor();
await page.getByText("Review accessibility audit", { exact: true }).waitFor();
await page.locator(".board-session-surface--dock-hidden").waitFor();
const columnCount = await widget.locator(".workboard-column").count();
if (columnCount !== 6) {
throw new Error(`Expected 6 Workboard columns, received ${columnCount}`);
}
await page.screenshot({
animations: "disabled",
path: path.join(outputDir, "workboard-widget.png"),
});
} finally {
await context.close();
await browser.close();
}
console.log(`[workboard-ui-proof] ${outputDir}`);