feat(KB-659): merge kb/kb-659 (auto-resolved)
- test(KB-659): add agents view integration tests to App.test.tsx and search visibility tests to Header.test.tsx - fix(KB-659): resolve merge conflict in types.ts and duplicate declaration in SettingsModal - feat(KB-659): add agents view toggle to view selector
This commit is contained in:
@@ -25,7 +25,6 @@ import { ActivityLogModal } from "./components/ActivityLogModal";
|
||||
import { WorkflowStepManager } from "./components/WorkflowStepManager";
|
||||
import { AgentListModal } from "./components/AgentListModal";
|
||||
import { AgentsView } from "./components/AgentsView";
|
||||
import { ScriptsModal } from "./components/ScriptsModal";
|
||||
import { useTasks } from "./hooks/useTasks";
|
||||
import { useProjects } from "./hooks/useProjects";
|
||||
import { useCurrentProject } from "./hooks/useCurrentProject";
|
||||
@@ -59,26 +58,10 @@ function AppInner() {
|
||||
const [autoMerge, setAutoMerge] = useState(true);
|
||||
const [globalPaused, setGlobalPaused] = useState(false);
|
||||
const [enginePaused, setEnginePaused] = useState(false);
|
||||
|
||||
// Multi-project state
|
||||
const { projects, loading: projectsLoading, update: updateProject, unregister: unregisterProject } = useProjects();
|
||||
const { currentProject, setCurrentProject, clearCurrentProject, loading: currentProjectLoading } = useCurrentProject(projects);
|
||||
|
||||
// View state: "overview" for all projects, "project" for single project task view
|
||||
const [viewMode, setViewMode] = useState<"overview" | "project">(() => {
|
||||
const [view, setView] = useState<"board" | "list" | "agents">(() => {
|
||||
// Initialize from localStorage if available
|
||||
if (typeof window !== "undefined") {
|
||||
const saved = localStorage.getItem("kb-dashboard-view-mode");
|
||||
if (saved === "overview" || saved === "project") {
|
||||
return saved;
|
||||
}
|
||||
}
|
||||
return "overview";
|
||||
});
|
||||
|
||||
// Task view state (only meaningful when viewMode="project")
|
||||
const [taskView, setTaskView] = useState<"board" | "list" | "agents">(() => {
|
||||
if (typeof window !== "undefined") {
|
||||
const saved = localStorage.getItem("kb-dashboard-task-view");
|
||||
const saved = localStorage.getItem("kb-dashboard-view");
|
||||
if (saved === "list" || saved === "board" || saved === "agents") {
|
||||
return saved;
|
||||
}
|
||||
@@ -190,19 +173,8 @@ function AppInner() {
|
||||
const taskId = params.get("task");
|
||||
if (!taskId) return;
|
||||
|
||||
// Clean URL immediately without reloading
|
||||
const url = new URL(window.location.href);
|
||||
url.searchParams.delete("task");
|
||||
window.history.replaceState({}, "", url.toString());
|
||||
|
||||
// Load and open the task directly
|
||||
fetchTaskDetail(taskId)
|
||||
.then((task) => {
|
||||
handleDetailOpen(task);
|
||||
})
|
||||
.catch(() => {
|
||||
addToast(`Task ${taskId} not found`, "error");
|
||||
});
|
||||
const handleChangeView = useCallback((newView: "board" | "list" | "agents") => {
|
||||
setView(newView);
|
||||
}, []);
|
||||
|
||||
// Project selection handlers
|
||||
@@ -386,54 +358,33 @@ function AppInner() {
|
||||
const handleOpenAgents = useCallback(() => setAgentsOpen(true), []);
|
||||
const handleCloseAgents = useCallback(() => setAgentsOpen(false), []);
|
||||
|
||||
// Scripts handlers
|
||||
const handleOpenScripts = useCallback(() => setScriptsOpen(true), []);
|
||||
const handleCloseScripts = useCallback(() => setScriptsOpen(false), []);
|
||||
|
||||
const handleRunScript = useCallback((name: string, command: string) => {
|
||||
setTerminalInitialCommand(command);
|
||||
setScriptsOpen(false);
|
||||
setTerminalOpen(true);
|
||||
addToast(`Running script: ${name}`, "success");
|
||||
}, [addToast]);
|
||||
|
||||
const handleTerminalClose = useCallback(() => {
|
||||
setTerminalOpen(false);
|
||||
setTerminalInitialCommand(undefined);
|
||||
}, []);
|
||||
|
||||
// Setup wizard complete handler
|
||||
const handleSetupComplete = useCallback((project: ProjectInfo) => {
|
||||
setSetupWizardOpen(false);
|
||||
setCurrentProject(project);
|
||||
setViewMode("project");
|
||||
addToast(`Project ${project.name} added successfully`, "success");
|
||||
}, [setCurrentProject, addToast]);
|
||||
|
||||
// Determine which view to render
|
||||
const renderMainContent = () => {
|
||||
if (viewMode === "overview") {
|
||||
return (
|
||||
<ProjectOverview
|
||||
projects={projects}
|
||||
loading={projectsLoading}
|
||||
onSelectProject={handleSelectProject}
|
||||
onAddProject={handleAddProject}
|
||||
onPauseProject={handlePauseProject}
|
||||
onResumeProject={handleResumeProject}
|
||||
onRemoveProject={handleRemoveProject}
|
||||
onViewAllProjects={handleViewAllProjects}
|
||||
<>
|
||||
<Header
|
||||
onOpenSettings={() => setSettingsOpen(true)}
|
||||
onOpenGitHubImport={() => setGitHubImportOpen(true)}
|
||||
onOpenPlanning={handlePlanningOpen}
|
||||
onOpenUsage={handleOpenUsage}
|
||||
onOpenActivityLog={handleOpenActivityLog}
|
||||
onOpenSchedules={handleOpenSchedules}
|
||||
onOpenGitManager={handleOpenGitManager}
|
||||
onOpenWorkflowSteps={() => setWorkflowStepsOpen(true)}
|
||||
onOpenAgents={handleOpenAgents}
|
||||
onToggleTerminal={handleToggleTerminal}
|
||||
onOpenFiles={handleOpenFiles}
|
||||
filesOpen={filesOpen}
|
||||
globalPaused={globalPaused}
|
||||
enginePaused={enginePaused}
|
||||
onToggleGlobalPause={handleToggleGlobalPause}
|
||||
onToggleEnginePause={handleToggleEnginePause}
|
||||
view={view}
|
||||
onChangeView={handleChangeView}
|
||||
searchQuery={searchQuery}
|
||||
onSearchChange={setSearchQuery}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// Project task view
|
||||
if (taskView === "agents") {
|
||||
return <AgentsView addToast={addToast} />;
|
||||
}
|
||||
|
||||
if (taskView === "board") {
|
||||
return (
|
||||
{view === "agents" ? (
|
||||
<AgentsView addToast={addToast} />
|
||||
) : view === "board" ? (
|
||||
<Board
|
||||
tasks={tasks}
|
||||
maxConcurrent={maxConcurrent}
|
||||
|
||||
@@ -172,9 +172,6 @@ export function SettingsModal({
|
||||
};
|
||||
}, [activeSection, loadAuthStatus]);
|
||||
|
||||
/** Get the scope of the currently active section */
|
||||
const activeSectionScope = SETTINGS_SECTIONS.find((s) => s.id === activeSection)?.scope;
|
||||
|
||||
const handleLogin = useCallback(async (providerId: string) => {
|
||||
setAuthActionInProgress(providerId);
|
||||
try {
|
||||
|
||||
@@ -36,19 +36,6 @@ vi.mock("../../api", async (importOriginal) => {
|
||||
fetchModels: vi.fn(() => Promise.resolve([])),
|
||||
fetchGitRemotes: vi.fn(() => Promise.resolve([])),
|
||||
fetchAgents: vi.fn(() => Promise.resolve([])),
|
||||
fetchTaskDetail: vi.fn((id: string) => Promise.resolve({
|
||||
id,
|
||||
title: `Task ${id}`,
|
||||
description: "Deep linked task",
|
||||
column: "todo",
|
||||
dependencies: [],
|
||||
steps: [],
|
||||
currentStep: 0,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
log: [],
|
||||
prompt: "",
|
||||
})),
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user