feat(KB-039): complete Step 5 — App integration with UsageIndicator modal
This commit is contained in:
@@ -12,6 +12,7 @@ import type { SectionId } from "./components/SettingsModal";
|
|||||||
import { ToastContainer } from "./components/ToastContainer";
|
import { ToastContainer } from "./components/ToastContainer";
|
||||||
import { GitHubImportModal } from "./components/GitHubImportModal";
|
import { GitHubImportModal } from "./components/GitHubImportModal";
|
||||||
import { GitManagerModal } from "./components/GitManagerModal";
|
import { GitManagerModal } from "./components/GitManagerModal";
|
||||||
|
import { UsageIndicator } from "./components/UsageIndicator";
|
||||||
import { useTasks } from "./hooks/useTasks";
|
import { useTasks } from "./hooks/useTasks";
|
||||||
import { ToastProvider, useToast } from "./hooks/useToast";
|
import { ToastProvider, useToast } from "./hooks/useToast";
|
||||||
import { useTheme } from "./hooks/useTheme";
|
import { useTheme } from "./hooks/useTheme";
|
||||||
@@ -22,6 +23,7 @@ function AppInner() {
|
|||||||
const [detailTask, setDetailTask] = useState<TaskDetail | null>(null);
|
const [detailTask, setDetailTask] = useState<TaskDetail | null>(null);
|
||||||
const [settingsOpen, setSettingsOpen] = useState(false);
|
const [settingsOpen, setSettingsOpen] = useState(false);
|
||||||
const [githubImportOpen, setGitHubImportOpen] = useState(false);
|
const [githubImportOpen, setGitHubImportOpen] = useState(false);
|
||||||
|
const [usageOpen, setUsageOpen] = useState(false);
|
||||||
const [terminalOpen, setTerminalOpen] = useState(false);
|
const [terminalOpen, setTerminalOpen] = useState(false);
|
||||||
const [settingsInitialSection, setSettingsInitialSection] = useState<SectionId | undefined>(undefined);
|
const [settingsInitialSection, setSettingsInitialSection] = useState<SectionId | undefined>(undefined);
|
||||||
const [maxConcurrent, setMaxConcurrent] = useState(2);
|
const [maxConcurrent, setMaxConcurrent] = useState(2);
|
||||||
@@ -104,6 +106,10 @@ function AppInner() {
|
|||||||
setIsPlanningOpen(false);
|
setIsPlanningOpen(false);
|
||||||
}, [addToast]);
|
}, [addToast]);
|
||||||
|
|
||||||
|
// Usage indicator handlers
|
||||||
|
const handleOpenUsage = useCallback(() => setUsageOpen(true), []);
|
||||||
|
const handleCloseUsage = useCallback(() => setUsageOpen(false), []);
|
||||||
|
|
||||||
const handleToggleAutoMerge = useCallback(async () => {
|
const handleToggleAutoMerge = useCallback(async () => {
|
||||||
const next = !autoMerge;
|
const next = !autoMerge;
|
||||||
setAutoMerge(next);
|
setAutoMerge(next);
|
||||||
@@ -158,6 +164,7 @@ function AppInner() {
|
|||||||
onOpenSettings={() => setSettingsOpen(true)}
|
onOpenSettings={() => setSettingsOpen(true)}
|
||||||
onOpenGitHubImport={() => setGitHubImportOpen(true)}
|
onOpenGitHubImport={() => setGitHubImportOpen(true)}
|
||||||
onOpenPlanning={handlePlanningOpen}
|
onOpenPlanning={handlePlanningOpen}
|
||||||
|
onOpenUsage={handleOpenUsage}
|
||||||
onToggleTerminal={handleToggleTerminal}
|
onToggleTerminal={handleToggleTerminal}
|
||||||
globalPaused={globalPaused}
|
globalPaused={globalPaused}
|
||||||
enginePaused={enginePaused}
|
enginePaused={enginePaused}
|
||||||
@@ -242,6 +249,10 @@ function AppInner() {
|
|||||||
isOpen={terminalOpen}
|
isOpen={terminalOpen}
|
||||||
onClose={handleTerminalClose}
|
onClose={handleTerminalClose}
|
||||||
/>
|
/>
|
||||||
|
<UsageIndicator
|
||||||
|
isOpen={usageOpen}
|
||||||
|
onClose={handleCloseUsage}
|
||||||
|
/>
|
||||||
<ToastContainer toasts={toasts} onRemove={removeToast} />
|
<ToastContainer toasts={toasts} onRemove={removeToast} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2871,7 +2871,11 @@ describe("TaskExecutor usage limit detection", () => {
|
|||||||
);
|
);
|
||||||
expect(store.updateSettings).toHaveBeenCalledWith({ globalPause: true });
|
expect(store.updateSettings).toHaveBeenCalledWith({ globalPause: true });
|
||||||
// Task should still be marked as failed
|
// Task should still be marked as failed
|
||||||
|
<<<<<<< HEAD
|
||||||
expect(store.updateTask).toHaveBeenCalledWith("KB-001", { status: "failed", error: expect.any(String) });
|
expect(store.updateTask).toHaveBeenCalledWith("KB-001", { status: "failed", error: expect.any(String) });
|
||||||
|
=======
|
||||||
|
expect(store.updateTask).toHaveBeenCalledWith("KB-001", { status: "failed", error: "rate_limit_error: Rate limit exceeded" });
|
||||||
|
>>>>>>> kb/kb-082
|
||||||
expect(onError).toHaveBeenCalled();
|
expect(onError).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -2903,7 +2907,11 @@ describe("TaskExecutor usage limit detection", () => {
|
|||||||
|
|
||||||
expect(onUsageLimitHitSpy).not.toHaveBeenCalled();
|
expect(onUsageLimitHitSpy).not.toHaveBeenCalled();
|
||||||
// Task should still be marked as failed
|
// Task should still be marked as failed
|
||||||
|
<<<<<<< HEAD
|
||||||
expect(store.updateTask).toHaveBeenCalledWith("KB-001", { status: "failed", error: expect.any(String) });
|
expect(store.updateTask).toHaveBeenCalledWith("KB-001", { status: "failed", error: expect.any(String) });
|
||||||
|
=======
|
||||||
|
expect(store.updateTask).toHaveBeenCalledWith("KB-001", { status: "failed", error: "connection refused" });
|
||||||
|
>>>>>>> kb/kb-082
|
||||||
});
|
});
|
||||||
|
|
||||||
it("works without usageLimitPauser (backward compatible)", async () => {
|
it("works without usageLimitPauser (backward compatible)", async () => {
|
||||||
@@ -2928,7 +2936,11 @@ describe("TaskExecutor usage limit detection", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Should not crash — just mark as failed
|
// Should not crash — just mark as failed
|
||||||
|
<<<<<<< HEAD
|
||||||
expect(store.updateTask).toHaveBeenCalledWith("KB-001", { status: "failed", error: expect.any(String) });
|
expect(store.updateTask).toHaveBeenCalledWith("KB-001", { status: "failed", error: expect.any(String) });
|
||||||
|
=======
|
||||||
|
expect(store.updateTask).toHaveBeenCalledWith("KB-001", { status: "failed", error: "rate_limit_error: Rate limit exceeded" });
|
||||||
|
>>>>>>> kb/kb-082
|
||||||
expect(onError).toHaveBeenCalled();
|
expect(onError).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -2972,7 +2984,11 @@ describe("TaskExecutor usage limit detection", () => {
|
|||||||
"rate_limit_error: Rate limit exceeded",
|
"rate_limit_error: Rate limit exceeded",
|
||||||
);
|
);
|
||||||
// Task should be marked as failed
|
// Task should be marked as failed
|
||||||
|
<<<<<<< HEAD
|
||||||
expect(store.updateTask).toHaveBeenCalledWith("KB-001", { status: "failed", error: expect.any(String) });
|
expect(store.updateTask).toHaveBeenCalledWith("KB-001", { status: "failed", error: expect.any(String) });
|
||||||
|
=======
|
||||||
|
expect(store.updateTask).toHaveBeenCalledWith("KB-001", { status: "failed", error: "rate_limit_error: Rate limit exceeded" });
|
||||||
|
>>>>>>> kb/kb-082
|
||||||
// onError callback should fire
|
// onError callback should fire
|
||||||
expect(onError).toHaveBeenCalled();
|
expect(onError).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user