feat(FN-4674): fix SettingsModal research defaults rendering and coverage

Completed Step 5 of FN-4674 by fixing research defaults rendering in SettingsModal and adding corresponding test coverage.

Fusion-Task-Id: FN-4674
This commit is contained in:
Fusion (runfusion.ai)
2026-05-15 15:36:08 -07:00
committed by gsxdsm
parent eb8c426717
commit 569eb2eb79
2 changed files with 152 additions and 18 deletions

View File

@@ -4970,23 +4970,129 @@ export function SettingsModal({
</details>
</div>
<div className="form-group">
<label htmlFor="research-global-max-sources">Default Max Sources Per Run</label>
<input
id="research-global-max-sources"
className="input"
type="number"
min={1}
value={form.researchGlobalDefaults?.maxSourcesPerRun ?? 20}
onChange={(event) =>
setForm((current) => ({
...current,
researchGlobalDefaults: {
...(current.researchGlobalDefaults ?? {}),
maxSourcesPerRun: Number(event.target.value) || 1,
},
}))
}
/>
<div className="settings-research-limits-grid">
<div className="settings-research-limit-field">
<label htmlFor="research-global-max-concurrent">Default Max Concurrent Runs</label>
<input
id="research-global-max-concurrent"
className="input"
type="number"
min={1}
value={form.researchGlobalMaxConcurrentRuns ?? 3}
onChange={(event) =>
setForm((current) => ({
...current,
researchGlobalMaxConcurrentRuns: event.target.value === "" ? undefined : Number(event.target.value),
}))
}
/>
</div>
<div className="settings-research-limit-field">
<label htmlFor="research-global-max-sources">Default Max Sources Per Run</label>
<input
id="research-global-max-sources"
className="input"
type="number"
min={1}
value={form.researchGlobalMaxSourcesPerRun ?? 20}
onChange={(event) =>
setForm((current) => ({
...current,
researchGlobalMaxSourcesPerRun: event.target.value === "" ? undefined : Number(event.target.value),
researchGlobalDefaults: {
...(current.researchGlobalDefaults ?? {}),
maxSourcesPerRun: event.target.value === "" ? undefined : Number(event.target.value),
},
}))
}
/>
</div>
<div className="settings-research-limit-field">
<label htmlFor="research-global-default-timeout">Default Max Duration (ms)</label>
<input
id="research-global-default-timeout"
className="input"
type="number"
min={1000}
value={form.researchGlobalDefaultTimeout ?? 300000}
onChange={(event) =>
setForm((current) => ({
...current,
researchGlobalDefaultTimeout: event.target.value === "" ? undefined : Number(event.target.value),
}))
}
/>
</div>
<div className="settings-research-limit-field">
<label htmlFor="research-global-fetch-timeout">Request Timeout (ms)</label>
<input
id="research-global-fetch-timeout"
className="input"
type="number"
min={1000}
value={form.researchGlobalFetchTimeoutMs ?? 30000}
onChange={(event) =>
setForm((current) => ({
...current,
researchGlobalFetchTimeoutMs: event.target.value === "" ? undefined : Number(event.target.value),
}))
}
/>
</div>
<div className="settings-research-limit-field">
<label htmlFor="research-global-max-synthesis-rounds">Max Synthesis Rounds</label>
<input
id="research-global-max-synthesis-rounds"
className="input"
type="number"
min={1}
value={form.researchGlobalMaxSynthesisRounds ?? 2}
onChange={(event) =>
setForm((current) => ({
...current,
researchGlobalMaxSynthesisRounds: event.target.value === "" ? undefined : Number(event.target.value),
}))
}
/>
</div>
</div>
</div>
<div className="form-group">
<label>Enabled Sources</label>
<label htmlFor="research-global-source-webSearch" className="checkbox-label settings-research-source-locked">
<input id="research-global-source-webSearch" type="checkbox" checked disabled readOnly />
Web Search <span className="settings-muted">Always on</span>
</label>
<div className="settings-research-source-grid">
<label htmlFor="research-global-source-github" className="checkbox-label">
<input
id="research-global-source-github"
type="checkbox"
checked={form.researchGlobalGitHubEnabled ?? false}
onChange={(event) =>
setForm((current) => ({
...current,
researchGlobalGitHubEnabled: event.target.checked,
}))
}
/>
GitHub
</label>
<label htmlFor="research-global-source-local-docs" className="checkbox-label">
<input
id="research-global-source-local-docs"
type="checkbox"
checked={form.researchGlobalLocalDocsEnabled ?? true}
onChange={(event) =>
setForm((current) => ({
...current,
researchGlobalLocalDocsEnabled: event.target.checked,
}))
}
/>
Local Docs
</label>
</div>
</div>
{hasMissingResearchCredential && (
<div className="settings-empty-state" role="alert">

View File

@@ -3929,6 +3929,20 @@ describe("SettingsModal", () => {
await userEvent.click(await screen.findByRole("button", { name: /^Research$/i }));
};
it("renders global research defaults fields with expected default values", async () => {
renderModal();
await waitForSettingsModalReady();
await openResearchGlobalSection();
expect(screen.getByLabelText("Default Max Concurrent Runs")).toHaveValue(3);
expect(screen.getByLabelText("Default Max Sources Per Run")).toHaveValue(20);
expect(screen.getByLabelText("Default Max Duration (ms)")).toHaveValue(300000);
expect(screen.getByLabelText("Request Timeout (ms)")).toHaveValue(30000);
expect(screen.getByLabelText("Max Synthesis Rounds")).toHaveValue(2);
expect(screen.getByRole("checkbox", { name: /^GitHub$/i })).not.toBeChecked();
expect(screen.getByRole("checkbox", { name: /^Local Docs$/i })).toBeChecked();
});
it("saves global research defaults through updateGlobalSettings only", async () => {
renderModal();
await waitForSettingsModalReady();
@@ -3937,12 +3951,26 @@ describe("SettingsModal", () => {
await userEvent.click(screen.getByText(/Advanced — external search providers/i));
const providerSelect = await screen.findByLabelText("Search Provider");
fireEvent.change(providerSelect, { target: { value: "tavily" } });
fireEvent.change(screen.getByLabelText("Default Max Concurrent Runs"), { target: { value: "4" } });
fireEvent.change(screen.getByLabelText("Default Max Sources Per Run"), { target: { value: "25" } });
fireEvent.change(screen.getByLabelText("Default Max Duration (ms)"), { target: { value: "240000" } });
fireEvent.change(screen.getByLabelText("Request Timeout (ms)"), { target: { value: "45000" } });
fireEvent.change(screen.getByLabelText("Max Synthesis Rounds"), { target: { value: "3" } });
await userEvent.click(screen.getByRole("checkbox", { name: /^GitHub$/i }));
await userEvent.click(screen.getByRole("checkbox", { name: /^Local Docs$/i }));
await userEvent.click(screen.getByText("Save"));
await waitFor(() => {
expect(mockUpdateGlobalSettings).toHaveBeenCalledWith(
expect.objectContaining({
researchGlobalDefaults: expect.objectContaining({ searchProvider: "tavily" }),
researchGlobalDefaults: expect.objectContaining({ searchProvider: "tavily", maxSourcesPerRun: 25 }),
researchGlobalMaxConcurrentRuns: 4,
researchGlobalMaxSourcesPerRun: 25,
researchGlobalDefaultTimeout: 240000,
researchGlobalFetchTimeoutMs: 45000,
researchGlobalMaxSynthesisRounds: 3,
researchGlobalGitHubEnabled: true,
researchGlobalLocalDocsEnabled: false,
}),
);
});