feat(FN-3268): add planning disclosure UX for Step 2-3 in modal

The merge completes UX updates for the planning disclosure flow (steps 2–3) in the PlanningModeModal, including CSS enhancements and test coverage for the new behavior.

Fusion-Task-Id: FN-3268
This commit is contained in:
Fusion
2026-05-03 08:17:27 -07:00
committed by gsxdsm
parent b531f2472b
commit 4694cebf43
3 changed files with 39 additions and 3 deletions

View File

@@ -411,6 +411,12 @@
margin: 0 auto;
}
.planning-advanced-disclosure .onboarding-disclosure-content {
padding-inline-start: 0;
display: flex;
justify-content: center;
}
.planning-advanced-content {
display: flex;
flex-direction: column;

View File

@@ -1568,7 +1568,7 @@ export function PlanningModeModal({ isOpen, onClose, onTaskCreated, onTasksCreat
</div>
</div>
<OnboardingDisclosure summary="Advanced planning settings" className="planning-advanced-disclosure" defaultOpen>
<OnboardingDisclosure summary="Advanced planning settings" className="planning-advanced-disclosure">
<div className="planning-advanced-content">
<div className="planning-advanced-section planning-model-select-group">
<label htmlFor="planning-modal-model" className="form-label">

View File

@@ -338,6 +338,11 @@ describe("PlanningModeModal", () => {
/>
);
expect(screen.getByRole("button", { name: "Advanced planning settings" })).toBeDefined();
expect(screen.queryByRole("button", { name: "Planning Model" })).toBeNull();
fireEvent.click(screen.getByRole("button", { name: "Advanced planning settings" }));
const modelTrigger = screen.getByRole("button", { name: "Planning Model" });
expect(modelTrigger).toBeDefined();
@@ -362,8 +367,8 @@ describe("PlanningModeModal", () => {
expect(mockFetchModels).toHaveBeenCalledTimes(1);
});
fireEvent.click(screen.getByRole("button", { name: "Advanced planning settings" }));
expect(screen.getByText("openai/gpt-4o")).toBeDefined();
fireEvent.click(screen.getByRole("button", { name: "Planning Model" }));
fireEvent.click(screen.getByRole("option", { name: /Claude Sonnet 4.5/ }));
@@ -385,6 +390,7 @@ describe("PlanningModeModal", () => {
expect(mockFetchModels).toHaveBeenCalledTimes(1);
});
fireEvent.click(screen.getByRole("button", { name: "Advanced planning settings" }));
fireEvent.click(screen.getByRole("button", { name: "Planning Model" }));
fireEvent.click(screen.getByRole("option", { name: /Claude Sonnet 4.5/ }));
@@ -403,7 +409,7 @@ describe("PlanningModeModal", () => {
});
});
it("renders advanced disclosure controls in the initial view", async () => {
it("keeps advanced disclosure collapsed by default and reveals controls when expanded", async () => {
render(
<PlanningModeModal
isOpen={true}
@@ -421,6 +427,13 @@ describe("PlanningModeModal", () => {
expect(disclosure).not.toBeNull();
const disclosureScope = within(disclosure as HTMLElement);
expect(disclosureButton.getAttribute("aria-expanded")).toBe("false");
expect(disclosureScope.queryByRole("button", { name: "Planning Model" })).toBeNull();
expect(disclosureScope.queryByText(/Selects which model runs the planning interview/)).toBeNull();
fireEvent.click(disclosureButton);
expect(disclosureButton.getAttribute("aria-expanded")).toBe("true");
expect(disclosureScope.getByRole("button", { name: "Planning Model" })).toBeDefined();
await waitFor(() => {
expect(disclosureScope.getByText("openai/gpt-4o")).toBeDefined();
@@ -444,6 +457,7 @@ describe("PlanningModeModal", () => {
/>
);
fireEvent.click(screen.getByRole("button", { name: "Advanced planning settings" }));
fireEvent.click(screen.getByRole("button", { name: "Large" }));
fireEvent.change(screen.getByLabelText("Questions"), { target: { value: "7" } });
fireEvent.change(screen.getByPlaceholderText(/e.g., Build a user authentication/), {
@@ -607,6 +621,18 @@ describe("PlanningModeModal", () => {
expect(maxHeightValue).toContain("100dvh");
expect(maxHeightValue).toContain("--overlay-padding-top");
});
it("uses planning-scoped disclosure overrides to remove inherited content indent", async () => {
const { loadAllAppCssBaseOnly } = await import("../../test/cssFixture");
const css = loadAllAppCssBaseOnly();
const blockMatch = css.match(
/\.planning-advanced-disclosure\s+\.onboarding-disclosure-content\s*\{[^}]*\}/,
);
expect(blockMatch).toBeTruthy();
expect(blockMatch![0]).toContain("padding-inline-start: 0;");
expect(blockMatch![0]).toContain("justify-content: center;");
});
});
describe("Planning flow", () => {
@@ -2547,6 +2573,7 @@ describe("PlanningModeModal", () => {
expect(mockFetchModels).toHaveBeenCalled();
});
fireEvent.click(screen.getByRole("button", { name: "Advanced planning settings" }));
fireEvent.click(screen.getByRole("button", { name: "Planning Model" }));
await waitFor(() => {
@@ -2587,6 +2614,7 @@ describe("PlanningModeModal", () => {
expect(mockFetchModels).toHaveBeenCalled();
});
fireEvent.click(screen.getByRole("button", { name: "Advanced planning settings" }));
fireEvent.click(screen.getByRole("button", { name: "Planning Model" }));
await waitFor(() => {
@@ -2628,6 +2656,7 @@ describe("PlanningModeModal", () => {
expect(mockFetchModels).toHaveBeenCalled();
});
fireEvent.click(screen.getByRole("button", { name: "Advanced planning settings" }));
fireEvent.click(screen.getByRole("button", { name: "Planning Model" }));
await waitFor(() => {
@@ -2666,6 +2695,7 @@ describe("PlanningModeModal", () => {
expect(mockFetchModels).toHaveBeenCalled();
});
fireEvent.click(screen.getByRole("button", { name: "Advanced planning settings" }));
fireEvent.click(screen.getByRole("button", { name: "Planning Model" }));
await waitFor(() => {