fix(FN-678): preserve settings section state across reopen

- Add a shared settings section scope helper so the modal consistently resolves the active section
- Prevent the authentication auto-open flow from leaking into later general settings sessions
- Add regression coverage for reopening the settings modal after authentication and general entry points
This commit is contained in:
gsxdsm
2026-04-01 13:37:33 -07:00
parent b8db80b5d6
commit 79a711a8a2
3 changed files with 29 additions and 2 deletions

View File

@@ -49,6 +49,11 @@ const SETTINGS_SECTIONS = [
] as const;
export type SectionId = (typeof SETTINGS_SECTIONS)[number]["id"];
type SectionScope = (typeof SETTINGS_SECTIONS)[number]["scope"];
function getSectionScope(sectionId: SectionId): SectionScope {
return SETTINGS_SECTIONS.find((section) => section.id === sectionId)?.scope;
}
interface SettingsModalProps {
onClose: () => void;
@@ -80,7 +85,7 @@ export function SettingsModal({
const [prefixError, setPrefixError] = useState<string | null>(null);
/** Get the scope of the currently active section */
const activeSectionScope = SETTINGS_SECTIONS.find((s) => s.id === activeSection)?.scope;
const activeSectionScope = getSectionScope(activeSection);
// Auth state (independent of the settings save flow)
const [authProviders, setAuthProviders] = useState<AuthProvider[]>([]);

View File

@@ -248,6 +248,9 @@ describe("App auto-open Settings on unauthenticated", () => {
expect(screen.getByText("Anthropic")).toBeTruthy();
});
// Authentication auto-open should not render General fields yet
expect(screen.queryByLabelText("Task Prefix")).toBeNull();
// Close the auto-opened settings modal via Cancel button
fireEvent.click(screen.getByText("Cancel"));

View File

@@ -778,7 +778,26 @@ describe("SettingsModal", () => {
// General content should be visible
expect(screen.getByLabelText("Task Prefix")).toBeTruthy();
// Authentication content should NOT be visible
expect(screen.queryByText("✗ Not authenticated")).toBeNull();
expect(screen.queryByText("Anthropic")).toBeNull();
});
it("preserves section-scope behavior across authentication auto-open and general reopen states", async () => {
const { unmount } = render(
<SettingsModal onClose={onClose} addToast={addToast} initialSection="authentication" />,
);
await waitFor(() => expect(fetchSettings).toHaveBeenCalled());
await waitFor(() => expect(fetchAuthStatus).toHaveBeenCalled());
expect(screen.getByText("Anthropic")).toBeTruthy();
expect(screen.queryByLabelText("Task Prefix")).toBeNull();
unmount();
render(<SettingsModal onClose={onClose} addToast={addToast} />);
await waitFor(() => expect(fetchSettings).toHaveBeenCalledTimes(2));
expect(screen.getByLabelText("Task Prefix")).toBeTruthy();
expect(screen.queryByText("Anthropic")).toBeNull();
});
it("shows sign-in hint when no providers are authenticated", async () => {