diff --git a/src/pages/proposals/ProposalCreation.tsx b/src/pages/proposals/ProposalCreation.tsx index 952fbb1..69fb686 100644 --- a/src/pages/proposals/ProposalCreation.tsx +++ b/src/pages/proposals/ProposalCreation.tsx @@ -643,6 +643,8 @@ const ProposalCreation: React.FC = () => { onSaveAndExit={() => void handleSaveAndExit()} onStartOver={handleStartOver} pathLabel={presetId ? currentPath.label : "Not chosen"} + proposalSummary={draft.summary} + proposalTitle={draft.title} saveStatus={wizardState.saveStatus} saving={wizardState.saveStatus === "syncing"} submitting={submitting} diff --git a/src/pages/proposals/proposalCreation/ProposalWizard.css b/src/pages/proposals/proposalCreation/ProposalWizard.css index aa280dc..7c54c76 100644 --- a/src/pages/proposals/proposalCreation/ProposalWizard.css +++ b/src/pages/proposals/proposalCreation/ProposalWizard.css @@ -23,6 +23,12 @@ opacity: 0.92; } +.proposal-wizard__header-title, +.proposal-wizard__header-summary { + min-width: 0; + overflow-wrap: anywhere; +} + .proposal-wizard__progress { display: grid; grid-auto-columns: minmax(9rem, 1fr); diff --git a/src/pages/proposals/proposalCreation/ProposalWizardShell.tsx b/src/pages/proposals/proposalCreation/ProposalWizardShell.tsx index 568b120..ed0ad54 100644 --- a/src/pages/proposals/proposalCreation/ProposalWizardShell.tsx +++ b/src/pages/proposals/proposalCreation/ProposalWizardShell.tsx @@ -17,6 +17,8 @@ type WizardHeaderProps = { onSaveAndExit: () => void; onStartOver: () => void; pathLabel: string; + proposalSummary: string; + proposalTitle: string; saveStatus: WizardSaveStatus; saving: boolean; submitting: boolean; @@ -35,11 +37,15 @@ export function WizardHeader({ onSaveAndExit, onStartOver, pathLabel, + proposalSummary, + proposalTitle, saveStatus, saving, submitting, }: WizardHeaderProps) { const busy = saving || submitting; + const displayTitle = proposalTitle.trim() || "Not set"; + const displaySummary = proposalSummary.trim() || "Not set"; return (
@@ -57,12 +63,11 @@ export function WizardHeader({ {saveStatusLabel[saveStatus]}
-

- Proposal Wizard +

+ {displayTitle}

-

- Build the proposal in order. Completed steps remain available while - the next requirement stays visible. +

+ {displaySummary}

diff --git a/tests/e2e/proposal-wizard.spec.ts b/tests/e2e/proposal-wizard.spec.ts index 0936f14..3103fb9 100644 --- a/tests/e2e/proposal-wizard.spec.ts +++ b/tests/e2e/proposal-wizard.spec.ts @@ -240,8 +240,11 @@ async function openFreshWizard( await installApiFixtures(page); await page.goto("/app/proposals/new"); await expect( - page.getByRole("heading", { name: "Proposal Wizard" }), + page.getByRole("heading", { name: "Not set", exact: true }), ).toBeVisible(); + await expect(page.locator(".proposal-wizard__header-summary")).toHaveText( + "Not set", + ); await expect(page.getByText("Not chosen", { exact: true })).toBeVisible(); await expect(page).toHaveURL(/step=intent/); } @@ -314,6 +317,15 @@ test("fresh entry ignores legacy Review state and completes policy submission", .locator("#proposal-initiative") .selectOption("initiative-governance-observatory"); await page.locator("#summary").fill("Publish regular governance reports."); + await expect( + page.getByRole("heading", { + name: "Transparent governance reporting", + exact: true, + }), + ).toBeVisible(); + await expect(page.locator(".proposal-wizard__header-summary")).toHaveText( + "Publish regular governance reports.", + ); await page.locator("#what").fill("Create a public reporting policy."); await page.locator("#why").fill("Make governance decisions auditable."); await page.getByRole("button", { name: "Continue" }).click(); @@ -965,7 +977,7 @@ test("late hydration cannot replace the currently selected server draft", async await installApiFixtures(page); await page.goto("/app/proposals/new?draftId=draft-stale"); await expect( - page.getByRole("heading", { name: "Proposal Wizard" }), + page.getByRole("heading", { name: "Not set", exact: true }), ).toBeVisible(); await page.evaluate(() => { window.history.pushState( @@ -978,7 +990,9 @@ test("late hydration cannot replace the currently selected server draft", async await expect(page).toHaveURL(/draftId=draft-existing/); await expect(page).toHaveURL(/step=plan/); await page.waitForTimeout(550); - await expect(page.getByText("Existing policy draft")).toBeVisible(); + await expect( + page.getByRole("heading", { name: "Existing policy draft", exact: true }), + ).toBeVisible(); await expect(page.getByText("Stale response")).not.toBeVisible(); }); @@ -997,7 +1011,10 @@ test("browser history restores the local wizard session named in the URL", async await expect(page).toHaveURL(/session=session-history-other/); await expect( - page.getByText("History session title", { exact: true }), + page.getByRole("heading", { + name: "History session title", + exact: true, + }), ).toBeVisible(); await page.goBack(); @@ -1147,7 +1164,10 @@ test("Save and exit cannot redirect a session opened while saving", async ({ await expect(page).toHaveURL(/session=session-after-save-and-exit/); await expect(page).toHaveURL(/step=intent/); await expect( - page.getByText("New session avoids old redirect", { exact: true }), + page.getByRole("heading", { + name: "New session avoids old redirect", + exact: true, + }), ).toBeVisible(); }); diff --git a/tests/unit/proposal-wizard-ui-contract.test.ts b/tests/unit/proposal-wizard-ui-contract.test.ts index faf95c6..b6fdeb0 100644 --- a/tests/unit/proposal-wizard-ui-contract.test.ts +++ b/tests/unit/proposal-wizard-ui-contract.test.ts @@ -17,7 +17,12 @@ test("Proposal Wizard 2.0 owns submission and uses the shared glass shell", () = expect(creation).toContain("apiProposalSubmitToPool"); expect(creation).toContain("