From 32fad6dfba065eaabfac2122d7392637743a499e Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Sun, 21 Jun 2026 12:38:27 -0700 Subject: [PATCH] FN-6863: raise footer concurrency slider limits Raise the footer engine control sliders to support higher concurrency without hiding persisted values. - Increase max tasks, max triage, and max worktree slider baselines to 50. - Preserve value-aware slider maxima for persisted settings above the new baseline. - Add coverage for in-range 50 limits, above-range persisted values, and saving a value of 50. Files changed: .../dashboard/app/components/EngineControlMenu.tsx | 9 ++-- .../__tests__/EngineControlMenu.test.tsx | 50 +++++++++++++++++++--- 2 files changed, 49 insertions(+), 10 deletions(-) Fusion-Task-Id: FN-6863 Fusion-Task-Lineage: f42373fc-322b-4d20-9b8b-2d0c63254e79 --- .../app/components/EngineControlMenu.tsx | 9 ++-- .../__tests__/EngineControlMenu.test.tsx | 50 ++++++++++++++++--- 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/packages/dashboard/app/components/EngineControlMenu.tsx b/packages/dashboard/app/components/EngineControlMenu.tsx index c3cec88255..250e343f8f 100644 --- a/packages/dashboard/app/components/EngineControlMenu.tsx +++ b/packages/dashboard/app/components/EngineControlMenu.tsx @@ -35,9 +35,9 @@ const DEFAULT_CONCURRENCY_VALUES: ConcurrencyValues = { }; const CONCURRENCY_SLIDER_LIMITS: Record = { - maxConcurrent: { min: 1, max: 10 }, - maxTriageConcurrent: { min: 1, max: 10 }, - maxWorktrees: { min: 1, max: 20 }, + maxConcurrent: { min: 1, max: 50 }, + maxTriageConcurrent: { min: 1, max: 50 }, + maxWorktrees: { min: 1, max: 50 }, }; function clamp(value: number, min: number, max: number) { @@ -58,6 +58,9 @@ Engine stop/start, triage pause/resume, and live scheduler concurrency/worktree FNXC:EngineControls 2026-06-21-00:00: FN-6862 requires the footer popover chrome to stay opaque across themes. Its CSS must use a defined solid surface token (`var(--card)`) because `--surface-elevated` is not in the dashboard token vocabulary and makes the menu transparent when unresolved. + +FNXC:EngineControls 2026-06-21-00:00: +FN-6863 raises the footer concurrency sliders' base drag ceiling to 50 for max tasks, triage, and worktrees. Keep getConcurrencySliderMax value-aware so already-persisted settings above 50 expand the slider instead of hiding or clamping the truthful readout. */ export const EngineControlMenu = forwardRef(function EngineControlMenu({ projectId }, ref) { const { t } = useTranslation("app"); diff --git a/packages/dashboard/app/components/__tests__/EngineControlMenu.test.tsx b/packages/dashboard/app/components/__tests__/EngineControlMenu.test.tsx index cdbf513f42..25718f6e6c 100644 --- a/packages/dashboard/app/components/__tests__/EngineControlMenu.test.tsx +++ b/packages/dashboard/app/components/__tests__/EngineControlMenu.test.tsx @@ -104,9 +104,9 @@ describe("EngineControlMenu", () => { it("persists debounced concurrency and worktree slider changes and refreshes settings", async () => { legacyMocks.fetchSettings.mockResolvedValue({ ...defaultSettings, - maxConcurrent: 12, - maxTriageConcurrent: 3, - maxWorktrees: 25, + maxConcurrent: 60, + maxTriageConcurrent: 70, + maxWorktrees: 80, }); await openMenu(); @@ -116,10 +116,12 @@ describe("EngineControlMenu", () => { vi.useFakeTimers(); - expect(maxConcurrent).toHaveAttribute("max", "12"); - expect(maxConcurrent).toHaveValue("12"); - expect(maxWorktrees).toHaveAttribute("max", "25"); - expect(maxWorktrees).toHaveValue("25"); + expect(maxConcurrent).toHaveAttribute("max", "60"); + expect(maxConcurrent).toHaveValue("60"); + expect(maxTriage).toHaveAttribute("max", "70"); + expect(maxTriage).toHaveValue("70"); + expect(maxWorktrees).toHaveAttribute("max", "80"); + expect(maxWorktrees).toHaveValue("80"); fireEvent.change(maxConcurrent, { target: { value: "9" } }); fireEvent.change(maxTriage, { target: { value: "4" } }); @@ -136,6 +138,40 @@ describe("EngineControlMenu", () => { expect(apiMocks.fetchSettings).toHaveBeenCalledTimes(2); }); + it("uses a 50 max for all in-range concurrency sliders", async () => { + legacyMocks.fetchSettings.mockResolvedValue({ + ...defaultSettings, + maxConcurrent: 12, + maxTriageConcurrent: 3, + maxWorktrees: 25, + }); + await openMenu(); + + expect(await screen.findByLabelText(/max concurrent tasks/i)).toHaveAttribute("max", "50"); + expect(screen.getByLabelText(/max triage concurrent/i)).toHaveAttribute("max", "50"); + expect(screen.getByLabelText(/max worktrees/i)).toHaveAttribute("max", "50"); + }); + + it("persists a slider value of 50 through the debounced settings save", async () => { + await openMenu(); + + const maxConcurrent = await screen.findByLabelText(/max concurrent tasks/i); + vi.useFakeTimers(); + + expect(maxConcurrent).toHaveAttribute("max", "50"); + + fireEvent.change(maxConcurrent, { target: { value: "50" } }); + + await act(async () => { + await vi.advanceTimersByTimeAsync(500); + }); + + expect(legacyMocks.updateSettings).toHaveBeenCalledWith( + { maxConcurrent: 50, maxTriageConcurrent: 1, maxWorktrees: 4 }, + "proj_123", + ); + }); + it("renders a load error state without crashing", async () => { legacyMocks.fetchSettings.mockRejectedValue(new Error("settings unavailable")); await openMenu();