387 lines
11 KiB
TypeScript
387 lines
11 KiB
TypeScript
import type { CSSProperties, ReactNode } from "react";
|
||
import { Navigate, Route, Routes } from "react-router-dom";
|
||
|
||
import { getStoredAuth } from "@/core/auth";
|
||
|
||
import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar";
|
||
import { PromptInputProvider } from "@/components/ai-elements/prompt-input";
|
||
import { WorkspaceSidebar } from "@/components/workspace/workspace-sidebar";
|
||
import { CommandPalette } from "@/components/workspace/command-palette";
|
||
import { Toaster } from "sonner";
|
||
import { SubtasksProvider } from "@/core/tasks/context";
|
||
import { ArtifactsProvider } from "@/components/workspace/artifacts";
|
||
|
||
import { RouteBaseProvider } from "@/core/route-base";
|
||
|
||
import ChatsPage from "./ChatsPage";
|
||
import ChatPage from "./ChatPage";
|
||
import AgentsPage from "./AgentsPage";
|
||
import AgentChatPage from "./AgentChatPage";
|
||
import NewAgentPage from "./NewAgentPage";
|
||
import AdminAgentsPage from "./AdminAgentsPage";
|
||
import AdminScheduledTasksPage from "./AdminScheduledTasksPage";
|
||
import AdminSkillsPage from "./AdminSkillsPage";
|
||
import ScheduledTaskRunDetailPage from "./ScheduledTaskRunDetailPage";
|
||
import ScheduledTasksPage from "./ScheduledTasksPage";
|
||
import LlmMetricsPage from "./LlmMetricsPage";
|
||
import MemoryPage from "./MemoryPage";
|
||
import PromptPrefixSettingsPage from "./PromptPrefixSettingsPage";
|
||
import PrivateSquareSettingsPage from "./PrivateSquareSettingsPage";
|
||
import SkillEvolutionPage from "./SkillEvolutionPage";
|
||
import SkillsPage from "./SkillsPage";
|
||
import UsersPage from "./UsersPage";
|
||
import AdminUserActivityPage from "./AdminUserActivityPage";
|
||
import AdminMemoryPage from "./AdminMemoryPage";
|
||
import AdminUserHubPage from "./AdminUserHubPage";
|
||
import TagsPage from "./TagsPage";
|
||
import RecommendedQuestionsPage from "./RecommendedQuestionsPage";
|
||
import AIWritingPage from "@/open-canvas/pages/AIWritingPage";
|
||
import StudioNotebooksPage from "./StudioNotebooksPage";
|
||
import StudioNotebookDetailPage from "./StudioNotebookDetailPage";
|
||
import RoundtablePlanningPage from "@/roundtable-planning/pages/RoundtablePlanningPage";
|
||
import "@/roundtable-planning/styles/roundtable-planning.css";
|
||
|
||
export function WorkspaceLayout({
|
||
children,
|
||
pageSidebarCollapsed,
|
||
pageSidebarHidden = false,
|
||
headerHidden = false,
|
||
compactWorkspaceSidebar = false,
|
||
pageSidebarDark = false,
|
||
}: {
|
||
children: ReactNode;
|
||
pageSidebarCollapsed: boolean;
|
||
pageSidebarHidden?: boolean;
|
||
headerHidden?: boolean;
|
||
compactWorkspaceSidebar?: boolean;
|
||
pageSidebarDark?: boolean;
|
||
}) {
|
||
const pageSidebarWidth = pageSidebarHidden
|
||
? "0rem"
|
||
: pageSidebarDark
|
||
// dark page sidebar:
|
||
// 展开: 视觉右边界 108px(外框 98 + 内层 translateX 10)+ 10px gap = 118px
|
||
// 收起: sidebar 主体完全消失(连同其占据的宽度),workspace 内容铺到屏幕左边;
|
||
// 左下角浮动按钮是 fixed,叠在主内容上不影响 layout
|
||
// 与 PageRoutes.tsx 的 main pl-[118px] / pl-0 保持一致
|
||
? (pageSidebarCollapsed ? "0rem" : "118px")
|
||
: pageSidebarCollapsed
|
||
? "4rem"
|
||
: "16rem";
|
||
|
||
return (
|
||
<SidebarProvider
|
||
className="h-full w-full overflow-x-hidden [&_[data-slot=sidebar-container]]:left-[var(--page-sidebar-width)]"
|
||
style={
|
||
{
|
||
"--page-sidebar-width": pageSidebarWidth,
|
||
"--header-height": headerHidden ? "0rem" : "4rem",
|
||
} as CSSProperties
|
||
}
|
||
// Keep the fixed workspace sidebar aligned to the outer page sidebar width.
|
||
// This lets it slide together when the outer sidebar collapses or expands.
|
||
data-page-sidebar-collapsed={pageSidebarCollapsed}
|
||
defaultOpen
|
||
>
|
||
<WorkspaceSidebar compactChrome={compactWorkspaceSidebar} />
|
||
<SidebarInset className="min-w-0">{children}</SidebarInset>
|
||
<CommandPalette />
|
||
<Toaster position="top-center" />
|
||
</SidebarProvider>
|
||
);
|
||
}
|
||
|
||
export function ChatRuntime({ children }: { children: ReactNode }) {
|
||
return (
|
||
<SubtasksProvider>
|
||
<ArtifactsProvider>
|
||
<PromptInputProvider>{children}</PromptInputProvider>
|
||
</ArtifactsProvider>
|
||
</SubtasksProvider>
|
||
);
|
||
}
|
||
|
||
export default function WorkspaceRoutes({
|
||
pageSidebarCollapsed = false,
|
||
pageSidebarHidden = false,
|
||
headerHidden = false,
|
||
compactWorkspaceSidebar = false,
|
||
pageSidebarDark = false,
|
||
}: {
|
||
pageSidebarCollapsed?: boolean;
|
||
pageSidebarHidden?: boolean;
|
||
headerHidden?: boolean;
|
||
compactWorkspaceSidebar?: boolean;
|
||
pageSidebarDark?: boolean;
|
||
}) {
|
||
const layoutProps = {
|
||
pageSidebarCollapsed,
|
||
pageSidebarHidden,
|
||
headerHidden,
|
||
compactWorkspaceSidebar,
|
||
pageSidebarDark,
|
||
};
|
||
|
||
return (
|
||
<RouteBaseProvider value="/page/workspace">
|
||
<Routes>
|
||
<Route index element={<Navigate to="chats/new" replace />} />
|
||
<Route
|
||
path="chats"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<ChatsPage />
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="chats/:thread_id"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<ChatRuntime>
|
||
<ChatPage />
|
||
</ChatRuntime>
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="agents"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<AgentsPage />
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="agents/new"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<NewAgentPage />
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="agents/:agent_id/chats"
|
||
element={<Navigate to="/page/workspace/agents" replace />}
|
||
/>
|
||
<Route
|
||
path="agents/:agent_id/chats/:thread_id"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<ChatRuntime>
|
||
<AgentChatPage />
|
||
</ChatRuntime>
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="skills"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<SkillsPage />
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="skills/evolution"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<SkillEvolutionPage />
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="memory"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<MemoryPage />
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="ai-writing"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<AIWritingPage hideAdvancedFields />
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="studio/notebooks"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<StudioNotebooksPage />
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="studio/notebooks/:notebookId"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<ChatRuntime>
|
||
<StudioNotebookDetailPage />
|
||
</ChatRuntime>
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="roundtable"
|
||
element={<Navigate to="/page/workspace/roundtable/planning" replace />}
|
||
/>
|
||
<Route
|
||
path="roundtable/planning"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<ChatRuntime>
|
||
<RoundtablePlanningPage />
|
||
</ChatRuntime>
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="scheduled"
|
||
element={<Navigate to="/page/workspace/scheduled/tasks" replace />}
|
||
/>
|
||
<Route
|
||
path="scheduled/tasks"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<ScheduledTasksPage />
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="scheduled/runs/:run_id"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<ScheduledTaskRunDetailPage />
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
{/* Unified admin user hub */}
|
||
<Route
|
||
path="admin"
|
||
element={
|
||
getStoredAuth()?.system_role === "admin" ? (
|
||
<WorkspaceLayout {...layoutProps} pageSidebarHidden>
|
||
<AdminUserHubPage />
|
||
</WorkspaceLayout>
|
||
) : (
|
||
<Navigate to="/page/workspace/chats/new" replace />
|
||
)
|
||
}
|
||
/>
|
||
{/* Legacy redirects */}
|
||
<Route
|
||
path="admin/users"
|
||
element={<Navigate to="/page/workspace/admin" replace />}
|
||
/>
|
||
<Route
|
||
path="admin/user-activity"
|
||
element={<Navigate to="/page/workspace/admin" replace />}
|
||
/>
|
||
<Route
|
||
path="admin/memory"
|
||
element={<Navigate to="/page/workspace/admin" replace />}
|
||
/>
|
||
<Route
|
||
path="admin/scheduled-tasks"
|
||
element={
|
||
getStoredAuth()?.system_role === "admin" ? (
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<AdminScheduledTasksPage />
|
||
</WorkspaceLayout>
|
||
) : (
|
||
<Navigate to="/page/workspace/chats/new" replace />
|
||
)
|
||
}
|
||
/>
|
||
<Route
|
||
path="admin/agents"
|
||
element={
|
||
getStoredAuth()?.system_role === "admin" ? (
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<AdminAgentsPage />
|
||
</WorkspaceLayout>
|
||
) : (
|
||
<Navigate to="/page/workspace/chats/new" replace />
|
||
)
|
||
}
|
||
/>
|
||
<Route
|
||
path="admin/skills"
|
||
element={
|
||
getStoredAuth()?.system_role === "admin" ? (
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<AdminSkillsPage />
|
||
</WorkspaceLayout>
|
||
) : (
|
||
<Navigate to="/page/workspace/chats/new" replace />
|
||
)
|
||
}
|
||
/>
|
||
<Route
|
||
path="admin/tags"
|
||
element={
|
||
getStoredAuth()?.system_role === "admin" ? (
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<TagsPage />
|
||
</WorkspaceLayout>
|
||
) : (
|
||
<Navigate to="/page/workspace/chats/new" replace />
|
||
)
|
||
}
|
||
/>
|
||
<Route
|
||
path="settings/recommended-questions"
|
||
element={
|
||
getStoredAuth()?.system_role === "admin" ? (
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<RecommendedQuestionsPage />
|
||
</WorkspaceLayout>
|
||
) : (
|
||
<Navigate to="/page/workspace/chats/new" replace />
|
||
)
|
||
}
|
||
/>
|
||
<Route
|
||
path="settings/prompt-prefix"
|
||
element={
|
||
getStoredAuth()?.system_role === "admin" ? (
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<PromptPrefixSettingsPage />
|
||
</WorkspaceLayout>
|
||
) : (
|
||
<Navigate to="/page/workspace/chats/new" replace />
|
||
)
|
||
}
|
||
/>
|
||
<Route
|
||
path="settings/private-square"
|
||
element={
|
||
getStoredAuth()?.system_role === "admin" ? (
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<PrivateSquareSettingsPage />
|
||
</WorkspaceLayout>
|
||
) : (
|
||
<Navigate to="/page/workspace/chats/new" replace />
|
||
)
|
||
}
|
||
/>
|
||
<Route
|
||
path="settings/llm-metrics"
|
||
element={
|
||
getStoredAuth()?.system_role === "admin" ? (
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<LlmMetricsPage />
|
||
</WorkspaceLayout>
|
||
) : (
|
||
<Navigate to="/page/workspace/chats/new" replace />
|
||
)
|
||
}
|
||
/>
|
||
</Routes>
|
||
</RouteBaseProvider>
|
||
);
|
||
}
|