From 0a57bbc464f20687611cd6ca2b19e63b83f3a358 Mon Sep 17 00:00:00 2001 From: canvas-bot Date: Mon, 15 Jun 2026 04:18:04 +0400 Subject: [PATCH] =?UTF-8?q?feat(wizard):=20per-phase=20preview=20=E2=80=94?= =?UTF-8?q?=20graph=20in=20Analyze,=20form=20in=20Generate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Wizard already has the progress stepper with checkmarks, the preview pane, and the review summary card before Publish. The remaining gap from the UX overhaul was that the preview pane showed the same flat list regardless of phase. Specialise it: - Analyze + onward: graph-style vertical chain with dispatch-kind bubbles (manual / assistant / system) and connector edges, so the operator sees the flow as a graph not a list. - Generate + onward: form preview that renders disabled input/select controls for each named field, so the operator sees what end users will fill in. - Validate + onward: rules list (unchanged). - Draft saved: all three render together so the review card has the full picture beside it. EA2 write contract is unchanged — createDraft / applyBatch / publishFlow still fire at every phase transition. 31/31 vitest pass. --- src/index.css | 68 +++++++++++++++++++++++++++ src/scenes/Wizard.tsx | 104 ++++++++++++++++++++++++------------------ 2 files changed, 128 insertions(+), 44 deletions(-) diff --git a/src/index.css b/src/index.css index c8ac383..3e8b98d 100644 --- a/src/index.css +++ b/src/index.css @@ -2260,3 +2260,71 @@ select.studio-input { background: var(--bp-paper); } } .global-banner-warn { background: #fff6e0; color: #5a3a00; border-color: #b08a4a; } [data-theme="dark"] .global-banner-warn { background: #3a2a0a; color: #ffd690; border-color: #6b4a14; } + +/* Wizard per-phase preview: graph + form */ +.wizard-preview-graph { + display: flex; + flex-direction: column; + gap: 0; +} +.wizard-graph-node { + display: flex; + flex-direction: column; + align-items: stretch; + position: relative; + padding-bottom: 4px; +} +.wizard-graph-bubble { + display: grid; + grid-template-columns: 22px 1fr; + align-items: center; + gap: 8px; + padding: 8px 10px; + border: 1px solid color-mix(in srgb, var(--bp-navy) 25%, transparent); + background: var(--bp-paper); + font-size: 12px; +} +.wizard-graph-bubble.kind-agent { background: color-mix(in srgb, var(--bp-amber) 18%, var(--bp-paper)); border-color: color-mix(in srgb, var(--bp-amber) 60%, var(--bp-navy)); } +.wizard-graph-bubble.kind-system { background: color-mix(in srgb, var(--bp-navy) 10%, var(--bp-paper)); } +.wizard-graph-idx { font-family: var(--bp-mono); font-size: 10px; color: var(--bp-muted); text-align: right; } +.wizard-graph-name { color: var(--bp-navy); font-weight: 600; line-height: 1.3; } +.wizard-graph-meta { + font-family: var(--bp-mono); + font-size: 9.5px; + text-transform: uppercase; + letter-spacing: 0.08em; + color: var(--bp-muted); + padding: 2px 0 0 30px; +} +.wizard-graph-edge { + width: 1px; + height: 12px; + background: color-mix(in srgb, var(--bp-navy) 35%, transparent); + margin: 4px 0 4px 10px; +} + +.wizard-form-preview { + display: flex; + flex-direction: column; + gap: 8px; + padding: 10px; + border: 1px dashed color-mix(in srgb, var(--bp-navy) 25%, transparent); + background: color-mix(in srgb, var(--bp-paper) 70%, var(--bp-canvas)); +} +.wizard-form-field { display: flex; flex-direction: column; gap: 3px; } +.wizard-form-label { + font-family: var(--bp-mono); + font-size: 10px; + letter-spacing: 0.06em; + text-transform: uppercase; + color: var(--bp-muted); +} +.wizard-form-input { + padding: 6px 8px; + font-size: 12px; + border: 1px solid color-mix(in srgb, var(--bp-navy) 25%, transparent); + background: var(--bp-paper); + color: var(--bp-navy); + font-family: inherit; +} +.wizard-form-input:disabled { opacity: 0.7; } diff --git a/src/scenes/Wizard.tsx b/src/scenes/Wizard.tsx index daa524a..3dda0eb 100644 --- a/src/scenes/Wizard.tsx +++ b/src/scenes/Wizard.tsx @@ -263,59 +263,75 @@ export default function Wizard() { ); + const renderGraphPreview = () => ( +
+
Flow · {draft.nodes.length} step{draft.nodes.length === 1 ? "" : "s"}
+
+ {draft.nodes.map((n, i) => ( +
+
+ {i + 1} + {n.display_name || "Untitled"} +
+
+ {({ human: "Manual", agent: "Assistant", system: "System" } as Record)[n.dispatch_kind || "human"]} +
+ {i < draft.nodes.length - 1 &&
} +
+ ))} +
+
+ ); + + const renderFormPreview = () => ( +
+
Form preview · what users will fill in
+
+ {draft.fields.filter((f) => f.name).length === 0 ? ( +
Add fields on the left to see the form here.
+ ) : ( + draft.fields.filter((f) => f.name).map((f, i) => ( +
+ + {f.type === "boolean" ? ( + + ) : f.type === "number" ? ( + + ) : ( + + )} +
+ )) + )} +
+
+ ); + + const renderRulesPreview = () => ( +
+
Rules · {draft.rules.filter((r) => r.trim()).length}
+
    + {draft.rules.filter((r) => r.trim()).map((r, i) =>
  • {r}
  • )} + {draft.rules.filter((r) => r.trim()).length === 0 && ( +
  • No rules typed yet
  • + )} +
+
+ ); + const renderPreviewPane = () => { if (draft.nodes.length === 0 && draft.fields.length === 0 && draft.rules.length === 0) return null; return ( ); }; -- 2.54.0