Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/pages/proposals/ProposalCreation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
6 changes: 6 additions & 0 deletions src/pages/proposals/proposalCreation/ProposalWizard.css
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
15 changes: 10 additions & 5 deletions src/pages/proposals/proposalCreation/ProposalWizardShell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ type WizardHeaderProps = {
onSaveAndExit: () => void;
onStartOver: () => void;
pathLabel: string;
proposalSummary: string;
proposalTitle: string;
saveStatus: WizardSaveStatus;
saving: boolean;
submitting: boolean;
Expand All @@ -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 (
<GlassyCard as="article" className="proposal-wizard__header">
<div className="min-w-0">
Expand All @@ -57,12 +63,11 @@ export function WizardHeader({
{saveStatusLabel[saveStatus]}
</GlassyStatusChip>
</div>
<h1 className="mt-3 text-2xl leading-tight font-semibold text-text sm:text-3xl">
Proposal Wizard
<h1 className="proposal-wizard__header-title mt-3 text-2xl leading-tight font-semibold text-text sm:text-3xl">
{displayTitle}
</h1>
<p className="mt-1 max-w-3xl text-sm leading-6 text-muted">
Build the proposal in order. Completed steps remain available while
the next requirement stays visible.
<p className="proposal-wizard__header-summary mt-1 max-w-3xl text-sm leading-6 text-muted">
{displaySummary}
</p>
</div>
<div className="proposal-wizard__header-actions">
Expand Down
30 changes: 25 additions & 5 deletions tests/e2e/proposal-wizard.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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/);
}
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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(
Expand All @@ -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();
});

Expand All @@ -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();
Expand Down Expand Up @@ -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();
});

Expand Down
5 changes: 5 additions & 0 deletions tests/unit/proposal-wizard-ui-contract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ test("Proposal Wizard 2.0 owns submission and uses the shared glass shell", () =
expect(creation).toContain("apiProposalSubmitToPool");
expect(creation).toContain("<WizardProgress");
expect(creation).toContain("<WizardWorkspace");
expect(creation).toContain("proposalSummary={draft.summary}");
expect(creation).toContain("proposalTitle={draft.title}");
expect(shell).toContain("<GlassyCard");
expect(shell).toContain('proposalTitle.trim() || "Not set"');
expect(shell).toContain('proposalSummary.trim() || "Not set"');
expect(shell).not.toContain("Build the proposal in order");
expect(shell).not.toContain('from "@/components/primitives/card"');
});

Expand Down
Loading