feat: code splitting, activity log page, gateway session browser in chat

- Lazy-load all route pages (React.lazy + Suspense) - main bundle 520KB → 266KB
- New Activity Log page (/activity) with timeline view, day grouping, status filter
- Chat: gateway session browser - browse existing Clawdbot sessions from sidebar
- Chat: clicking a gateway session adds it as a local thread for conversation
- Sidebar: added Activity nav item between Projects and Chat
This commit is contained in:
2026-01-29 09:03:36 +00:00
parent 819649c8c7
commit 8c284684c9
4 changed files with 325 additions and 14 deletions

View File

@@ -1,26 +1,43 @@
import { lazy, Suspense } from "react";
import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom";
import { DashboardLayout } from "./components/DashboardLayout";
import { DashboardPage } from "./pages/DashboardPage";
import { QueuePage } from "./pages/QueuePage";
import { ChatPage } from "./pages/ChatPage";
import { ProjectsPage } from "./pages/ProjectsPage";
import { TaskPage } from "./pages/TaskPage";
import { AdminPage } from "./components/AdminPage";
import { LoginPage } from "./components/LoginPage";
import { ToastProvider } from "./components/Toast";
import { useSession } from "./lib/auth-client";
// Lazy-loaded pages for code splitting
const DashboardPage = lazy(() => import("./pages/DashboardPage").then(m => ({ default: m.DashboardPage })));
const QueuePage = lazy(() => import("./pages/QueuePage").then(m => ({ default: m.QueuePage })));
const ChatPage = lazy(() => import("./pages/ChatPage").then(m => ({ default: m.ChatPage })));
const ProjectsPage = lazy(() => import("./pages/ProjectsPage").then(m => ({ default: m.ProjectsPage })));
const TaskPage = lazy(() => import("./pages/TaskPage").then(m => ({ default: m.TaskPage })));
const ActivityPage = lazy(() => import("./pages/ActivityPage").then(m => ({ default: m.ActivityPage })));
const AdminPage = lazy(() => import("./components/AdminPage").then(m => ({ default: m.AdminPage })));
function PageLoader() {
return (
<div className="min-h-[50vh] flex items-center justify-center text-gray-400">
<div className="flex items-center gap-2">
<span className="w-2 h-2 bg-amber-400 rounded-full animate-bounce" style={{ animationDelay: "0ms" }} />
<span className="w-2 h-2 bg-amber-400 rounded-full animate-bounce" style={{ animationDelay: "150ms" }} />
<span className="w-2 h-2 bg-amber-400 rounded-full animate-bounce" style={{ animationDelay: "300ms" }} />
</div>
</div>
);
}
function AuthenticatedApp() {
return (
<BrowserRouter>
<Routes>
<Route element={<DashboardLayout />}>
<Route path="/" element={<DashboardPage />} />
<Route path="/queue" element={<QueuePage />} />
<Route path="/task/:taskRef" element={<TaskPage />} />
<Route path="/projects" element={<ProjectsPage />} />
<Route path="/chat" element={<ChatPage />} />
<Route path="/admin" element={<AdminPage />} />
<Route path="/" element={<Suspense fallback={<PageLoader />}><DashboardPage /></Suspense>} />
<Route path="/queue" element={<Suspense fallback={<PageLoader />}><QueuePage /></Suspense>} />
<Route path="/task/:taskRef" element={<Suspense fallback={<PageLoader />}><TaskPage /></Suspense>} />
<Route path="/projects" element={<Suspense fallback={<PageLoader />}><ProjectsPage /></Suspense>} />
<Route path="/chat" element={<Suspense fallback={<PageLoader />}><ChatPage /></Suspense>} />
<Route path="/activity" element={<Suspense fallback={<PageLoader />}><ActivityPage /></Suspense>} />
<Route path="/admin" element={<Suspense fallback={<PageLoader />}><AdminPage /></Suspense>} />
<Route path="*" element={<Navigate to="/" replace />} />
</Route>
</Routes>