Massive overhaul that turns the demo from presenter-mode into a
fully-functional FlowMaster operator surface.
NEW: real backend mutations
- api.executeAction(txId, actionId, actor, values) → POST /api/runtime/transactions/{tx}/actions/{actionId}
- api.startTransaction(defKey, business_subject) → POST /api/runtime/transactions
- api.createProcess(payload) → POST /api/ea2/flow
- store.executeAction / startInstance with toast feedback + auto-refresh
- Inspector Overview action buttons fire real backend calls (Submit/Save Draft/etc)
- LeftRail Confirm/Reject buttons fire real backend calls
- LeftRail 'Start new instance' button starts a real tx for live procurement
- CommandBar 'Real actions' group with 'Start new instance' + 'Execute action on headline tx'
NEW: Process Studio (src/scenes/Studio.tsx)
- in-UI process designer: name + display + hub + description + node list + edge list
- live JSON preview of the EA2 payload
- Publish button calls api.createProcess against demo.flow-master.ai
- Validates locally before publishing
- Auto-refreshes scenarios after publish so the new process shows up
NEW: Settings (src/scenes/Settings.tsx)
- Identity: sign in as any email (loginAs), see actor + display name
- Quick-user buttons for common demo identities
- Backend URL + clear-token diagnostic
- Polling cadence (2-120s)
- Dark/light theme toggle (CSS data-theme attribute)
- Show-console default toggle
- All persisted to localStorage (LS_KEY = fm.mc.prefs.v1)
NEW: Live API console (src/components/Console.tsx)
- Right-side drawer triggered from topbar
- Every fetch (GET/POST/etc) streams in real time with status + duration
- Click any entry to expand request + response JSON
- Filter: all / writes / errors
- Replaces the old guided-tour overlay entirely
NEW: live polling
- store.startPolling()/stopPolling() with setInterval guarded for SSR
- Auto-refresh while in LIVE mode at configurable cadence
REMOVED: Tour.tsx, all startTour() store actions and tour references
- Landing CTA now reads 'Enter Mission Control' / 'Design a process' / 'Open live console'
ALSO:
- api.ts: instrumentedFetch with observer pattern → store.apiLog
- Topbar: user identity chip linking to Settings, Console toggle with badge
- Light theme: minimal CSS data-theme override (text + surfaces only)
- localStorage persistence for mode, scenarioId, email, theme, pollEverySec, consoleOpen, recents
- 24/24 vitest, smoke quick run shows 0 console errors + 7 API calls captured
Confidence: high
Scope-risk: broad (~14 files)
Not-tested: actual end-to-end backend mutation roundtrip (requires LIVE + sign-in; structure proven via probe scripts)
44 lines
1.7 KiB
JavaScript
44 lines
1.7 KiB
JavaScript
import { chromium } from "playwright";
|
|
const b = await chromium.launch({ headless: true });
|
|
const p = await b.newPage({ viewport: { width: 1440, height: 900 } });
|
|
const errors = [];
|
|
p.on("pageerror", e => errors.push(`pageerror ${e.message}`));
|
|
p.on("console", m => { if (m.type() === "error") errors.push(`console.error ${m.text().slice(0, 200)}`); });
|
|
|
|
await p.goto("http://127.0.0.1:5173", { waitUntil: "networkidle" });
|
|
await p.locator(".sc-card").first().click();
|
|
await p.waitForSelector(".mc"); await p.waitForTimeout(400);
|
|
|
|
// Open console first
|
|
await p.locator(".link-btn", { hasText: "Console" }).first().click();
|
|
await p.waitForSelector(".console");
|
|
|
|
// Toggle live
|
|
await p.locator(".mode-toggle").first().click();
|
|
await p.waitForTimeout(6000); // let all calls land
|
|
|
|
const callCount = await p.locator(".call").count();
|
|
console.log("api calls logged:", callCount);
|
|
const firstCall = await p.locator(".call-head").first();
|
|
if (await firstCall.count()) {
|
|
console.log("first call:", await firstCall.innerText());
|
|
}
|
|
|
|
// Click a call to expand
|
|
if (callCount > 0) {
|
|
await p.locator(".call-head").first().click();
|
|
await p.waitForTimeout(300);
|
|
console.log("expanded has body:", await p.locator(".call-body").first().isVisible());
|
|
}
|
|
|
|
// Sign in via settings
|
|
await p.locator(".tab", { hasText: "Settings" }).click();
|
|
await p.waitForSelector(".settings"); await p.waitForTimeout(300);
|
|
const userBtn = p.locator(".quick-users .link-btn", { hasText: "dev@flow-master.ai" }).first();
|
|
console.log("settings quick-user:", await userBtn.isVisible());
|
|
|
|
console.log("\nconsole errors:", errors.length);
|
|
errors.slice(0, 5).forEach(e => console.log(" -", e));
|
|
await p.screenshot({ path: "qa/screenshots/v3-console-open.png", fullPage: false });
|
|
await b.close();
|