From 0d7180b170d56eb1641f665b89ba3f74cf599e1f Mon Sep 17 00:00:00 2001 From: chorewer <1175794600@qq.com> Date: Thu, 21 May 2026 17:14:55 +0800 Subject: [PATCH 1/2] feat(dashboard): multi-project switcher with runtime switching Add a project switcher to the dashboard header that lets users switch between KIP and KIP-infra (and any future sibling projects) without restarting the server. Co-Authored-By: Claude Sonnet 4.6 --- docker-compose.yml | 4 ++- tools/kip-state/index.py | 4 ++- ui/client/src/App.tsx | 35 +++++++++++++++++++++--- ui/client/src/hooks/useApi.ts | 27 +++++++++++++++++++ ui/client/src/styles/global.css | 13 +++++++++ ui/client/src/views/Nodes.tsx | 20 +++++++++++--- ui/server/src/index.ts | 48 +++++++++++++++++++++++++++++---- ui/server/src/routes/agents.ts | 8 +++--- ui/server/src/routes/logs.ts | 9 ++++--- ui/server/src/routes/nodes.ts | 13 ++++++--- ui/server/src/routes/project.ts | 24 +++++++++++++---- ui/server/src/routes/summary.ts | 7 +++-- 12 files changed, 177 insertions(+), 35 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 1336f05..4aac5ad 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -18,5 +18,7 @@ services: ports: - "18080:8081" volumes: - - .:/project + - .:/projects/KIP + - /root/ai4math/KIP-infra:/projects/KIP-infra + command: ["node", "server/dist/index.js", "--project", "/projects/KIP", "--port", "8081"] restart: unless-stopped diff --git a/tools/kip-state/index.py b/tools/kip-state/index.py index 31bad2f..3e11ce3 100644 --- a/tools/kip-state/index.py +++ b/tools/kip-state/index.py @@ -301,6 +301,8 @@ def main(argv: list[str] | None = None) -> int: help="KIP project root (default: cwd)") ap.add_argument("--db", type=Path, default=None, help="Output SQLite path (default: /.dashboard/state.db)") + ap.add_argument("--lean-root", type=Path, default=None, + help="Lean source root (default: /KIP)") ap.add_argument("--quiet", action="store_true") args = ap.parse_args(argv) @@ -315,7 +317,7 @@ def main(argv: list[str] | None = None) -> int: status_path = project / "blueprint" / "status.yaml" chapters_dir = project / "blueprint" / "src" / "chapters" - lean_root = project / "KIP" + lean_root = args.lean_root.resolve() if args.lean_root else project / "KIP" agents_dir = project / "agents" log(f"[kip-state] project={project}") diff --git a/ui/client/src/App.tsx b/ui/client/src/App.tsx index 5c24e17..11ecf7b 100644 --- a/ui/client/src/App.tsx +++ b/ui/client/src/App.tsx @@ -1,5 +1,5 @@ import { Routes, Route, NavLink, Navigate } from 'react-router-dom'; -import { useProject } from './hooks/useApi'; +import { useProject, useProjects, useProjectSwitch } from './hooks/useApi'; import Overview from './views/Overview'; import LogViewer from './views/LogViewer'; import Nodes from './views/Nodes'; @@ -17,15 +17,42 @@ function ConnectionBanner({ isError }: { isError: boolean }) { ); } +function ProjectSwitcher() { + const { data: project } = useProject(); + const { data: projects } = useProjects(); + const switcher = useProjectSwitch(); + + if (!projects || projects.length <= 1) { + return ( + + {project?.name ?? '…'} + + ); + } + + return ( + + ); +} + export default function App() { - const { data: project, isError } = useProject(); + const { isError } = useProject(); return (
-

KIP

- {project && {project.name}} +