feat(FN-2380): add fast mode toggle to quick entry

- Add QuickEntryBox state for a Fast toggle and include executionMode="fast" in create payloads when enabled
- Reset fast mode during form reset flows so follow-up creates default back to standard mode
- Add regression tests for fast toggle pressed state and payload behavior across Enter and Save submission paths
- Add tests ensuring fast mode is omitted when inactive and cleared after successful create, Plan, and Subtask flows
This commit is contained in:
Fusion
2026-04-24 13:51:55 -07:00
committed by gsxdsm
parent c4c77740cb
commit d2da242d21
2 changed files with 133 additions and 0 deletions

View File

@@ -137,6 +137,7 @@ export function QuickEntryBox({ onCreate, addToast, tasks = [], availableModels,
const [favoriteModels, setFavoriteModels] = useState<string[]>([]);
const [settings, setSettings] = useState<Settings | null>(null);
const [selectedPresetId, setSelectedPresetId] = useState<string | undefined>(undefined);
const [isFastMode, setIsFastMode] = useState(false);
// AI Refinement state
const [isRefineMenuOpen, setIsRefineMenuOpen] = useState(false);
@@ -377,6 +378,7 @@ export function QuickEntryBox({ onCreate, addToast, tasks = [], availableModels,
setPlanningProvider(undefined);
setPlanningModelId(undefined);
setSelectedPresetId(undefined);
setIsFastMode(false);
setShowDeps(false);
setIsModelMenuOpen(false);
setModelMenuPosition(null);
@@ -444,6 +446,7 @@ export function QuickEntryBox({ onCreate, addToast, tasks = [], availableModels,
validatorModelId: hasValidatorOverride ? validatorModelId : undefined,
planningModelProvider: hasPlanningOverride ? planningProvider : undefined,
planningModelId: hasPlanningOverride ? planningModelId : undefined,
...(isFastMode ? { executionMode: "fast" } : {}),
});
if (createdTask && pendingImages.length > 0) {
const failures: string[] = [];
@@ -487,6 +490,7 @@ export function QuickEntryBox({ onCreate, addToast, tasks = [], availableModels,
projectId,
addToast,
resetForm,
isFastMode,
]);
const handleKeyDown = useCallback(
@@ -1417,6 +1421,18 @@ export function QuickEntryBox({ onCreate, addToast, tasks = [], availableModels,
portalRoot,
)}
<button
type="button"
className={`btn btn-sm ${isFastMode ? "btn-primary" : ""}`}
onClick={() => setIsFastMode((prev) => !prev)}
onMouseDown={(e) => e.preventDefault()}
aria-pressed={isFastMode}
data-testid="quick-entry-fast-toggle"
title="Toggle fast execution mode"
>
Fast
</button>
<button
type="button"
className="btn btn-task-create btn-sm"

View File

@@ -650,6 +650,123 @@ describe("QuickEntryBox", () => {
expect(screen.getByTestId("subtask-button")).toBeTruthy();
});
it("shows Fast toggle when expanded", () => {
renderQuickEntryBox({});
expandQuickEntry();
const fastToggle = screen.getByTestId("quick-entry-fast-toggle");
expect(fastToggle).toBeTruthy();
expect(fastToggle.getAttribute("aria-pressed")).toBe("false");
});
it("toggles Fast pressed state", () => {
renderQuickEntryBox({});
expandQuickEntry();
const fastToggle = screen.getByTestId("quick-entry-fast-toggle");
fireEvent.click(fastToggle);
expect(fastToggle.getAttribute("aria-pressed")).toBe("true");
fireEvent.click(fastToggle);
expect(fastToggle.getAttribute("aria-pressed")).toBe("false");
});
it.each(["Enter", "Save"] as const)("submits executionMode=fast when Fast is active via %s", async (submitPath) => {
const { props } = renderQuickEntryBox({});
expandQuickEntry();
const textarea = screen.getByTestId("quick-entry-input");
fireEvent.click(screen.getByTestId("quick-entry-fast-toggle"));
fireEvent.change(textarea, { target: { value: `Fast submission via ${submitPath}` } });
if (submitPath === "Enter") {
fireEvent.keyDown(textarea, { key: "Enter" });
} else {
clickSave();
}
await waitFor(() => {
expect(props.onCreate).toHaveBeenCalledWith(
expect.objectContaining({
description: `Fast submission via ${submitPath}`,
executionMode: "fast",
}),
);
});
});
it("omits executionMode when Fast is not active", async () => {
const { props } = renderQuickEntryBox({});
expandQuickEntry();
const textarea = screen.getByTestId("quick-entry-input");
fireEvent.change(textarea, { target: { value: "Standard submission" } });
fireEvent.keyDown(textarea, { key: "Enter" });
await waitFor(() => {
expect(props.onCreate).toHaveBeenCalled();
});
const firstPayload = props.onCreate.mock.calls[0]?.[0];
expect(firstPayload.executionMode).toBeUndefined();
});
it("resets Fast toggle to standard after successful task creation", async () => {
const { props } = renderQuickEntryBox({});
expandQuickEntry();
const textarea = screen.getByTestId("quick-entry-input");
fireEvent.click(screen.getByTestId("quick-entry-fast-toggle"));
fireEvent.change(textarea, { target: { value: "First fast task" } });
fireEvent.keyDown(textarea, { key: "Enter" });
await waitFor(() => {
expect(props.onCreate).toHaveBeenCalledTimes(1);
expect(props.onCreate).toHaveBeenCalledWith(
expect.objectContaining({
description: "First fast task",
executionMode: "fast",
}),
);
});
expandQuickEntry();
const fastToggle = screen.getByTestId("quick-entry-fast-toggle");
expect(fastToggle.getAttribute("aria-pressed")).toBe("false");
fireEvent.change(textarea, { target: { value: "Second standard task" } });
fireEvent.keyDown(textarea, { key: "Enter" });
await waitFor(() => {
expect(props.onCreate).toHaveBeenCalledTimes(2);
});
const secondPayload = props.onCreate.mock.calls[1]?.[0];
expect(secondPayload.executionMode).toBeUndefined();
});
it.each([
{ label: "Plan", buttonId: "plan-button", callbackProp: "onPlanningMode" as const },
{ label: "Subtask", buttonId: "subtask-button", callbackProp: "onSubtaskBreakdown" as const },
])("clears Fast state after %s flow reset", async ({ buttonId, callbackProp }) => {
const onPlanningMode = vi.fn();
const onSubtaskBreakdown = vi.fn();
renderQuickEntryBox({ onPlanningMode, onSubtaskBreakdown });
expandQuickEntry();
const textarea = screen.getByTestId("quick-entry-input");
fireEvent.click(screen.getByTestId("quick-entry-fast-toggle"));
fireEvent.change(textarea, { target: { value: `${callbackProp} input` } });
fireEvent.click(screen.getByTestId(buttonId));
await waitFor(() => {
expect(callbackProp === "onPlanningMode" ? onPlanningMode : onSubtaskBreakdown).toHaveBeenCalled();
});
expandQuickEntry();
expect(screen.getByTestId("quick-entry-fast-toggle").getAttribute("aria-pressed")).toBe("false");
});
it("opens dependency dropdown when clicking deps button", () => {
renderQuickEntryBox({});
expandQuickEntry();