928 lines
29 KiB
TypeScript
928 lines
29 KiB
TypeScript
import type { CSSProperties, ReactNode } from 'react';
|
||
import { Navigate, Route, Routes, useLocation, useParams } from 'react-router-dom';
|
||
|
||
import { getStoredAuth } from '@/core/auth';
|
||
import { isSentimentAgentVisible } from '@/core/sentiment-agent/config';
|
||
import {
|
||
resolveChatsIframeEntryRedirect,
|
||
resolveStandardChatFallback,
|
||
} from '@/core/page-layout/chats-iframe-route';
|
||
import { isEmbeddedHost } from '@/core/embed/frame-context';
|
||
|
||
import { SidebarInset, SidebarProvider } from '@/components/ui/sidebar';
|
||
import { PromptInputProvider } from '@/components/ai-elements/prompt-input';
|
||
import {
|
||
CompactShortcutButtons,
|
||
LayoutModeSwitcher,
|
||
ThemeSwitcher,
|
||
} from '@/components/workspace/appearance-controls';
|
||
import { WorkspaceSidebar } from '@/components/workspace/workspace-sidebar';
|
||
import { UserIdentityBadge } from '@/components/workspace/user-identity-badge';
|
||
import { CommandPalette } from '@/components/workspace/command-palette';
|
||
import { Toaster } from 'sonner';
|
||
import { SubtasksProvider } from '@/core/tasks/context';
|
||
import { ArtifactsProvider } from '@/components/workspace/artifacts';
|
||
import { DocumentRewritePresentationProvider } from '@/core/document-rewrite/context';
|
||
|
||
import { RouteBaseProvider } from '@/core/route-base';
|
||
|
||
import ChatsPage from './ChatsPage';
|
||
import ChatPage from './ChatPage';
|
||
import IframeChatPage from './IframeChatPage';
|
||
import AgentsPage from './AgentsPage';
|
||
import AgentChatPage from './AgentChatPage';
|
||
import SentimentAgentChatPage from './SentimentAgentChatPage';
|
||
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 LlmWikiKnowledgePage from './LlmWikiKnowledgePage';
|
||
import WeKnoraWikiManagementPage from '@/strategy-components/components/resource-management/llmwiki/WeKnoraWikiManagementPage';
|
||
import MarkdownDocxEditorPage from './MarkdownDocxEditorPage';
|
||
import LlmMetricsPage from './LlmMetricsPage';
|
||
import CheckpointMigrationPage from './CheckpointMigrationPage';
|
||
import MemoryPage from './MemoryPage';
|
||
import PromptPrefixSettingsPage from './PromptPrefixSettingsPage';
|
||
import PrivateSquareSettingsPage from './PrivateSquareSettingsPage';
|
||
import ModelConcurrencySettingsPage from './ModelConcurrencySettingsPage';
|
||
import ModelManagementPage from './ModelManagementPage';
|
||
import PublishSquaresSettingsPage from './PublishSquaresSettingsPage';
|
||
import SkillCompressionSettingsPage from './SkillCompressionSettingsPage';
|
||
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 PositionsPage from './PositionsPage';
|
||
import PositionRolesPage from './PositionRolesPage';
|
||
import PluginManagementPage from './PluginManagementPage';
|
||
import RecommendedQuestionsPage from './RecommendedQuestionsPage';
|
||
import AIWritingPage from '@/open-canvas/pages/AIWritingPage';
|
||
import DeepResearchPage from './DeepResearchPage';
|
||
import StudioNotebooksPage from './StudioNotebooksPage';
|
||
import StudioNotebookDetailPage from './StudioNotebookDetailPage';
|
||
import RoundtablePlanningPage from '@/roundtable-planning/pages/RoundtablePlanningPage';
|
||
import PositionRoundtablePage from '@/position-roundtable/pages/PositionRoundtablePage';
|
||
import EightBfRoundtablePage from '@/eightbf-roundtable/pages/EightBfRoundtablePage';
|
||
import BusinessChainEditorPage from '@/roundtable-planning/pages/BusinessChainEditorPage';
|
||
import BusinessChainListPage from '@/roundtable-planning/pages/BusinessChainListPage';
|
||
import DispatchChainPreviewPage from '@/roundtable-planning/pages/DispatchChainPreviewPage';
|
||
import '@/roundtable-planning/styles/roundtable-planning.css';
|
||
import { cn } from '@/lib/utils';
|
||
|
||
function NotebookDetailPageWithKey() {
|
||
const { notebookId } = useParams<{ notebookId: string }>();
|
||
return <StudioNotebookDetailPage key={notebookId} />;
|
||
}
|
||
|
||
// 恢复某条 bootstrap 会话时按 thread_id 重挂,切换会话不串台。
|
||
function NewAgentPageWithKey() {
|
||
const { thread_id } = useParams<{ thread_id: string }>();
|
||
return <NewAgentPage key={thread_id} />;
|
||
}
|
||
|
||
function shouldShowCompactTopActions(pathname: string): boolean {
|
||
return (
|
||
pathname === '/page/workspace/agents' ||
|
||
pathname === '/page/workspace/skills' ||
|
||
pathname === '/page/workspace/memory' ||
|
||
pathname === '/page/workspace/knowledge' ||
|
||
pathname.startsWith('/page/workspace/knowledge/')
|
||
);
|
||
}
|
||
|
||
function CompactWorkspaceTopActions() {
|
||
return (
|
||
<div className="z-[60] flex h-12 shrink-0 items-center justify-end gap-2 border-b border-border/70 bg-card/90 px-4 shadow-sm backdrop-blur-md">
|
||
<CompactShortcutButtons tone="content" />
|
||
<ThemeSwitcher tone="content" />
|
||
<LayoutModeSwitcher tone="content" />
|
||
<div className="bg-border/70 mx-1 h-6 w-px shrink-0" aria-hidden />
|
||
<UserIdentityBadge />
|
||
</div>
|
||
);
|
||
}
|
||
|
||
function CompactAppearanceActions() {
|
||
return (
|
||
<>
|
||
<CompactShortcutButtons tone="content" />
|
||
<ThemeSwitcher tone="content" />
|
||
<LayoutModeSwitcher tone="content" />
|
||
</>
|
||
);
|
||
}
|
||
|
||
export function WorkspaceLayout({
|
||
children,
|
||
pageSidebarCollapsed,
|
||
pageSidebarHidden = false,
|
||
workspaceSidebarHidden = false,
|
||
headerHidden = false,
|
||
compactActionsHidden = false,
|
||
compactWorkspaceSidebar = false,
|
||
defaultHistorySidebarOpen,
|
||
wrapperOverflowHidden = false,
|
||
insetOverflowHidden = false,
|
||
pageSidebarDark = false,
|
||
forceWorkspaceSidebarCollapsed = false,
|
||
}: {
|
||
children: ReactNode;
|
||
pageSidebarCollapsed: boolean;
|
||
pageSidebarHidden?: boolean;
|
||
workspaceSidebarHidden?: boolean;
|
||
headerHidden?: boolean;
|
||
compactActionsHidden?: boolean;
|
||
compactWorkspaceSidebar?: boolean;
|
||
/** 全量模式下通用问答等页:聊天记录侧栏默认展开;未指定时紧凑模式仍默认收起。 */
|
||
defaultHistorySidebarOpen?: boolean;
|
||
wrapperOverflowHidden?: boolean;
|
||
insetOverflowHidden?: boolean;
|
||
pageSidebarDark?: boolean;
|
||
/** Deployment-level compact mode: keep only the icon menu rail. */
|
||
forceWorkspaceSidebarCollapsed?: boolean;
|
||
}) {
|
||
// 全量模式下通用问答(/page/workspace/chats*)的历史侧栏默认展开;其余紧凑页
|
||
// (如智能体对话,为聊天区更宽而默认收起)维持原默认。
|
||
const pathname = useLocation().pathname;
|
||
const isGeneralQa = pathname.startsWith('/page/workspace/chats');
|
||
const showCompactTopActions =
|
||
headerHidden && !compactActionsHidden && shouldShowCompactTopActions(pathname);
|
||
|
||
const pageSidebarWidth = pageSidebarHidden
|
||
? '0rem'
|
||
: pageSidebarDark
|
||
? pageSidebarCollapsed
|
||
? '0rem'
|
||
: '118px'
|
||
: pageSidebarCollapsed
|
||
? '4rem'
|
||
: '16rem';
|
||
|
||
return (
|
||
<SidebarProvider
|
||
className={[
|
||
'relative h-full w-full overflow-x-hidden',
|
||
'[&_[data-slot=sidebar-container]]:absolute',
|
||
'[&_[data-slot=sidebar-container]]:left-0',
|
||
'[&_[data-slot=sidebar-container]]:top-0',
|
||
].join(' ')}
|
||
style={
|
||
{
|
||
'--page-sidebar-width': pageSidebarWidth,
|
||
'--header-height': headerHidden ? '0rem' : '4rem',
|
||
} as CSSProperties
|
||
}
|
||
key={String(compactWorkspaceSidebar)}
|
||
data-page-sidebar-collapsed={pageSidebarCollapsed}
|
||
defaultOpen={
|
||
forceWorkspaceSidebarCollapsed
|
||
? false
|
||
: (defaultHistorySidebarOpen ?? (isGeneralQa || !compactWorkspaceSidebar))
|
||
}
|
||
open={forceWorkspaceSidebarCollapsed ? false : undefined}
|
||
onOpenChange={forceWorkspaceSidebarCollapsed ? () => undefined : undefined}
|
||
disableToggle={forceWorkspaceSidebarCollapsed}
|
||
>
|
||
{!workspaceSidebarHidden && (
|
||
<WorkspaceSidebar
|
||
compactChrome={compactWorkspaceSidebar}
|
||
forceCollapsed={forceWorkspaceSidebarCollapsed}
|
||
/>
|
||
)}
|
||
<SidebarInset
|
||
className={cn('min-w-0', insetOverflowHidden && 'overflow-hidden')}
|
||
>
|
||
{showCompactTopActions ? (
|
||
<>
|
||
<CompactWorkspaceTopActions />
|
||
<div className="min-h-0 flex-1">{children}</div>
|
||
</>
|
||
) : (
|
||
children
|
||
)}
|
||
</SidebarInset>
|
||
<CommandPalette />
|
||
<Toaster position="top-center" />
|
||
</SidebarProvider>
|
||
);
|
||
}
|
||
|
||
export function ChatRuntime({ children }: { children: ReactNode }) {
|
||
return (
|
||
<SubtasksProvider>
|
||
<DocumentRewritePresentationProvider>
|
||
<ArtifactsProvider>
|
||
<PromptInputProvider>{children}</PromptInputProvider>
|
||
</ArtifactsProvider>
|
||
</DocumentRewritePresentationProvider>
|
||
</SubtasksProvider>
|
||
);
|
||
}
|
||
|
||
/**
|
||
* 通用问答新对话内容区:默认渲染 ChatPage;当 URL 带 ``?agent=<id>``(点击左栏
|
||
* 「常用智能体」时由侧边栏写入)时,**在右侧问答区原地嵌入**该智能体的对话页
|
||
* (AgentChatPage),路由仍停留在 /chats/new,不跳转出去、不更换左侧栏。
|
||
* key 绑定 location.key —— 每次点击(即便同一 agent)都重开一个干净的会话。
|
||
*/
|
||
function NewChatContent() {
|
||
const location = useLocation();
|
||
const agentId = new URLSearchParams(location.search).get('agent');
|
||
if (agentId) {
|
||
return <AgentChatPage key={`${agentId}:${location.key}`} embeddedAgentId={agentId} />;
|
||
}
|
||
return <ChatPage />;
|
||
}
|
||
|
||
function NewChatEntryRoute({
|
||
layoutProps,
|
||
}: {
|
||
layoutProps: {
|
||
pageSidebarCollapsed: boolean;
|
||
pageSidebarHidden: boolean;
|
||
workspaceSidebarHidden: boolean;
|
||
headerHidden: boolean;
|
||
compactWorkspaceSidebar: boolean;
|
||
compactActionsHidden: boolean;
|
||
pageSidebarDark: boolean;
|
||
forceWorkspaceSidebarCollapsed: boolean;
|
||
};
|
||
}) {
|
||
const location = useLocation();
|
||
const iframeEntryTarget = resolveChatsIframeEntryRedirect(
|
||
location.pathname,
|
||
location.search,
|
||
isEmbeddedHost(),
|
||
);
|
||
|
||
if (iframeEntryTarget) {
|
||
return <Navigate to={iframeEntryTarget} replace />;
|
||
}
|
||
|
||
// A bare external iframe historically opens the dedicated AgentSelector
|
||
// page. `resolveChatsIframeEntryRedirect` records that inferred context as
|
||
// `from=iframe`; explicit full-chat/presentation parameters stay here.
|
||
return (
|
||
<WorkspaceLayout {...layoutProps} defaultHistorySidebarOpen>
|
||
<ChatRuntime>
|
||
<NewChatContent />
|
||
</ChatRuntime>
|
||
</WorkspaceLayout>
|
||
);
|
||
}
|
||
|
||
function ChatsIndexEntryRoute({
|
||
layoutProps,
|
||
compactChrome,
|
||
}: {
|
||
layoutProps: {
|
||
pageSidebarCollapsed: boolean;
|
||
pageSidebarHidden: boolean;
|
||
workspaceSidebarHidden: boolean;
|
||
headerHidden: boolean;
|
||
compactWorkspaceSidebar: boolean;
|
||
compactActionsHidden: boolean;
|
||
pageSidebarDark: boolean;
|
||
forceWorkspaceSidebarCollapsed: boolean;
|
||
};
|
||
compactChrome: boolean;
|
||
}) {
|
||
const location = useLocation();
|
||
const iframeEntryTarget = resolveChatsIframeEntryRedirect(
|
||
location.pathname,
|
||
location.search,
|
||
isEmbeddedHost(),
|
||
);
|
||
|
||
if (iframeEntryTarget) {
|
||
return <Navigate to={iframeEntryTarget} replace />;
|
||
}
|
||
|
||
return (
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<ChatsPage compactChrome={compactChrome} />
|
||
</WorkspaceLayout>
|
||
);
|
||
}
|
||
|
||
function ChatThreadEntryRoute({
|
||
layoutProps,
|
||
}: {
|
||
layoutProps: {
|
||
pageSidebarCollapsed: boolean;
|
||
pageSidebarHidden: boolean;
|
||
workspaceSidebarHidden: boolean;
|
||
headerHidden: boolean;
|
||
compactWorkspaceSidebar: boolean;
|
||
compactActionsHidden: boolean;
|
||
pageSidebarDark: boolean;
|
||
forceWorkspaceSidebarCollapsed: boolean;
|
||
};
|
||
}) {
|
||
const location = useLocation();
|
||
const iframeEntryTarget = resolveChatsIframeEntryRedirect(
|
||
location.pathname,
|
||
location.search,
|
||
isEmbeddedHost(),
|
||
);
|
||
|
||
if (iframeEntryTarget) {
|
||
return <Navigate to={iframeEntryTarget} replace />;
|
||
}
|
||
|
||
return (
|
||
<WorkspaceLayout {...layoutProps} defaultHistorySidebarOpen>
|
||
<ChatRuntime>
|
||
<ChatPage />
|
||
</ChatRuntime>
|
||
</WorkspaceLayout>
|
||
);
|
||
}
|
||
|
||
/**
|
||
* `chats_iframe` is reserved for the Brainy postMessage protocol. `from=iframe`
|
||
* and `chatMode=iframe` opt into this page; ordinary iframe/Wujie embedding
|
||
* remains on the normal full chat workspace.
|
||
*/
|
||
function IframeChatEntryRoute({
|
||
layoutProps,
|
||
hasThreadParam,
|
||
}: {
|
||
layoutProps: {
|
||
pageSidebarCollapsed: boolean;
|
||
pageSidebarHidden: boolean;
|
||
workspaceSidebarHidden: boolean;
|
||
headerHidden: boolean;
|
||
compactWorkspaceSidebar: boolean;
|
||
compactActionsHidden: boolean;
|
||
pageSidebarDark: boolean;
|
||
forceWorkspaceSidebarCollapsed: boolean;
|
||
};
|
||
hasThreadParam: boolean;
|
||
}) {
|
||
const location = useLocation();
|
||
const standardChatTarget = resolveStandardChatFallback(
|
||
location.pathname,
|
||
location.search,
|
||
);
|
||
|
||
if (standardChatTarget) {
|
||
return <Navigate to={standardChatTarget} replace />;
|
||
}
|
||
|
||
return (
|
||
<WorkspaceLayout
|
||
{...layoutProps}
|
||
pageSidebarHidden
|
||
workspaceSidebarHidden
|
||
wrapperOverflowHidden={hasThreadParam}
|
||
insetOverflowHidden={hasThreadParam}
|
||
>
|
||
<ChatRuntime>
|
||
<IframeChatPage />
|
||
</ChatRuntime>
|
||
</WorkspaceLayout>
|
||
);
|
||
}
|
||
|
||
export default function WorkspaceRoutes({
|
||
pageSidebarCollapsed = false,
|
||
pageSidebarHidden = false,
|
||
workspaceSidebarHidden = false,
|
||
headerHidden = false,
|
||
compactActionsHidden = false,
|
||
compactWorkspaceSidebar = false,
|
||
pageSidebarDark = false,
|
||
forceWorkspaceSidebarCollapsed = false,
|
||
}: {
|
||
pageSidebarCollapsed?: boolean;
|
||
pageSidebarHidden?: boolean;
|
||
workspaceSidebarHidden?: boolean;
|
||
headerHidden?: boolean;
|
||
compactActionsHidden?: boolean;
|
||
compactWorkspaceSidebar?: boolean;
|
||
pageSidebarDark?: boolean;
|
||
forceWorkspaceSidebarCollapsed?: boolean;
|
||
}) {
|
||
const layoutProps = {
|
||
pageSidebarCollapsed,
|
||
pageSidebarHidden,
|
||
workspaceSidebarHidden,
|
||
headerHidden,
|
||
compactActionsHidden,
|
||
compactWorkspaceSidebar,
|
||
pageSidebarDark,
|
||
forceWorkspaceSidebarCollapsed,
|
||
};
|
||
|
||
return (
|
||
<RouteBaseProvider value="/page/workspace">
|
||
<Routes>
|
||
<Route index element={<Navigate to="chats/new" replace />} />
|
||
<Route
|
||
path="chats"
|
||
element={
|
||
<ChatsIndexEntryRoute
|
||
layoutProps={layoutProps}
|
||
compactChrome={headerHidden && !compactActionsHidden}
|
||
/>
|
||
}
|
||
/>
|
||
<Route
|
||
path="chats/new"
|
||
element={<NewChatEntryRoute layoutProps={layoutProps} />}
|
||
/>
|
||
<Route
|
||
path="chats/:thread_id"
|
||
element={<ChatThreadEntryRoute layoutProps={layoutProps} />}
|
||
/>
|
||
<Route
|
||
path="chats_iframe/new"
|
||
element={<IframeChatEntryRoute layoutProps={layoutProps} hasThreadParam={false} />}
|
||
/>
|
||
<Route
|
||
path="chats_iframe/:thread_id"
|
||
element={<IframeChatEntryRoute layoutProps={layoutProps} hasThreadParam />}
|
||
/>
|
||
<Route
|
||
path="agents"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<AgentsPage />
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="agents/new"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<NewAgentPage />
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
{/* 从「常用对话」点击智能体创建(bootstrap)会话回到创建页并恢复该会话。
|
||
key 绑定 thread_id —— 切换不同 bootstrap 会话时重挂一个干净的页面。 */}
|
||
<Route
|
||
path="agents/new/:thread_id"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<NewAgentPageWithKey />
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
{/* 舆情分析虚拟智能体:静态段优先于 :agent_id 命中,走前端直连外部
|
||
AG-UI 网关的专用对话页(不在后端 /api/agents 落库)。 */}
|
||
<Route
|
||
path="agents/sentiment-analysis/chats"
|
||
element={
|
||
isSentimentAgentVisible() ? (
|
||
<Navigate to="/page/workspace/agents/sentiment-analysis/chats/new" replace />
|
||
) : (
|
||
<Navigate to="/page/workspace/agents" replace />
|
||
)
|
||
}
|
||
/>
|
||
<Route
|
||
path="agents/sentiment-analysis/chats/:thread_id"
|
||
element={
|
||
isSentimentAgentVisible() ? (
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<SentimentAgentChatPage />
|
||
</WorkspaceLayout>
|
||
) : (
|
||
<Navigate to="/page/workspace/agents" replace />
|
||
)
|
||
}
|
||
/>
|
||
<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
|
||
showAgentList
|
||
compactAppearanceActions={
|
||
headerHidden && !compactActionsHidden ? <CompactAppearanceActions /> : undefined
|
||
}
|
||
/>
|
||
</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
|
||
compactChrome={headerHidden && !compactActionsHidden}
|
||
/>
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="deep-research"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<ChatRuntime>
|
||
<DeepResearchPage />
|
||
</ChatRuntime>
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="studio/notebooks"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<StudioNotebooksPage />
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="studio/notebooks/:notebookId"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<ChatRuntime>
|
||
<NotebookDetailPageWithKey />
|
||
</ChatRuntime>
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="roundtable"
|
||
element={
|
||
<Navigate to="/page/workspace/roundtable/planning" replace />
|
||
}
|
||
/>
|
||
<Route
|
||
path="roundtable/planning"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<ChatRuntime>
|
||
<RoundtablePlanningPage compactChrome={headerHidden && !compactActionsHidden} />
|
||
</ChatRuntime>
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="roundtable/8bf"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<ChatRuntime>
|
||
<EightBfRoundtablePage compactChrome={headerHidden && !compactActionsHidden} />
|
||
</ChatRuntime>
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="roundtable/position"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<ChatRuntime>
|
||
<PositionRoundtablePage compactChrome={headerHidden && !compactActionsHidden} />
|
||
</ChatRuntime>
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="roundtable/chains"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<BusinessChainEditorPage />
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="business-chains"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<BusinessChainListPage />
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
{/* Phase 7 临时预览入口:派活链路流程图弹窗(假数据自测,接通后台后可删) */}
|
||
<Route
|
||
path="roundtable/chain-preview"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<DispatchChainPreviewPage />
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="knowledge"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<LlmWikiKnowledgePage />
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="knowledge/graph"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<LlmWikiKnowledgePage mode="graph" />
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="knowledge/:noteId/wiki"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<WeKnoraWikiManagementPage />
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="knowledge/markdown-editor"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<MarkdownDocxEditorPage />
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="knowledge/:noteId"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<LlmWikiKnowledgePage mode="detail" />
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="scheduled"
|
||
element={<Navigate to="/page/workspace/scheduled/tasks" replace />}
|
||
/>
|
||
<Route
|
||
path="scheduled/tasks"
|
||
element={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<ScheduledTasksPage compactChrome={headerHidden && !compactActionsHidden} />
|
||
</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={
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<TagsPage />
|
||
</WorkspaceLayout>
|
||
}
|
||
/>
|
||
<Route
|
||
path="admin/plugins"
|
||
element={
|
||
getStoredAuth()?.system_role === 'admin' ? (
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<PluginManagementPage />
|
||
</WorkspaceLayout>
|
||
) : (
|
||
<Navigate to="/page/workspace/chats/new" replace />
|
||
)
|
||
}
|
||
/>
|
||
<Route
|
||
path="admin/positions"
|
||
element={
|
||
getStoredAuth()?.system_role === 'admin' ? (
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<PositionsPage />
|
||
</WorkspaceLayout>
|
||
) : (
|
||
<Navigate to="/page/workspace/chats/new" replace />
|
||
)
|
||
}
|
||
/>
|
||
<Route
|
||
path="admin/position-roles"
|
||
element={
|
||
getStoredAuth()?.system_role === 'admin' ? (
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<PositionRolesPage />
|
||
</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="admin/models"
|
||
element={
|
||
getStoredAuth()?.system_role === 'admin' ? (
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<ModelManagementPage />
|
||
</WorkspaceLayout>
|
||
) : (
|
||
<Navigate to="/page/workspace/chats/new" replace />
|
||
)
|
||
}
|
||
/>
|
||
<Route
|
||
path="settings/model-concurrency"
|
||
element={
|
||
getStoredAuth()?.system_role === 'admin' ? (
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<ModelConcurrencySettingsPage />
|
||
</WorkspaceLayout>
|
||
) : (
|
||
<Navigate to="/page/workspace/chats/new" replace />
|
||
)
|
||
}
|
||
/>
|
||
<Route
|
||
path="settings/publish-squares"
|
||
element={
|
||
getStoredAuth()?.system_role === 'admin' ? (
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<PublishSquaresSettingsPage />
|
||
</WorkspaceLayout>
|
||
) : (
|
||
<Navigate to="/page/workspace/chats/new" replace />
|
||
)
|
||
}
|
||
/>
|
||
<Route
|
||
path="settings/skill-compression"
|
||
element={
|
||
getStoredAuth()?.system_role === 'admin' ? (
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<SkillCompressionSettingsPage />
|
||
</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 />
|
||
)
|
||
}
|
||
/>
|
||
<Route
|
||
path="settings/checkpoint-migration"
|
||
element={
|
||
getStoredAuth()?.system_role === 'admin' ? (
|
||
<WorkspaceLayout {...layoutProps}>
|
||
<CheckpointMigrationPage />
|
||
</WorkspaceLayout>
|
||
) : (
|
||
<Navigate to="/page/workspace/chats/new" replace />
|
||
)
|
||
}
|
||
/>
|
||
</Routes>
|
||
</RouteBaseProvider>
|
||
);
|
||
}
|
||
|
||
// Suppress unused import warnings for pages referenced only in some branches
|
||
void UsersPage;
|
||
void AdminUserActivityPage;
|
||
void AdminMemoryPage;
|