页面结构修改

This commit is contained in:
fengxiangdebaozi committed 2026-05-13 18:18:05 +08:00
1 parent efc4d89fdf
commit 2e4bdf122e
21 files changed
+1266 -133

No files matched your search

+2 -107
View File
@@ -3,27 +3,14 @@ import { Navigate, Route, Routes } from "react-router-dom";
import { ThemeProvider as NextThemesProvider } from "next-themes";
import { QueryClientProvider } from "@/components/query-client-provider";
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 { I18nProvider } from "@/core/i18n/context";
import { detectLocale } from "@/core/i18n/locale";
import { SubtasksProvider } from "@/core/tasks/context";
import { ArtifactsProvider } from "@/components/workspace/artifacts";
import { HashRouter, useLocation } from "react-router-dom";
import LandingPage from "./pages/LandingPage";
import ChatsPage from "./pages/ChatsPage";
import ChatPage from "./pages/ChatPage";
import AgentsPage from "./pages/AgentsPage";
import AgentChatPage from "./pages/AgentChatPage";
import NewAgentPage from "./pages/NewAgentPage";
import LoginPage from "./pages/LoginPage";
import ScheduledTaskRunDetailPage from "./pages/ScheduledTaskRunDetailPage";
import ScheduledTasksPage from "./pages/ScheduledTasksPage";
import PageRoutes from "./pages/PageRoutes";
import { NotFoundPage } from "./pages/NotFoundPage";
function AppProviders({ children }: { children: React.ReactNode }) {
@@ -45,27 +32,6 @@ function AppProviders({ children }: { children: React.ReactNode }) {
);
}
function WorkspaceLayout({ children }: { children: React.ReactNode }) {
return (
<SidebarProvider className="h-screen" defaultOpen>
<WorkspaceSidebar />
<SidebarInset className="min-w-0">{children}</SidebarInset>
<CommandPalette />
<Toaster position="top-center" />
</SidebarProvider>
);
}
function ChatRuntime({ children }: { children: React.ReactNode }) {
return (
<SubtasksProvider>
<ArtifactsProvider>
<PromptInputProvider>{children}</PromptInputProvider>
</ArtifactsProvider>
</SubtasksProvider>
);
}
export function App() {
return (
<HashRouter>
@@ -75,78 +41,7 @@ export function App() {
<Route path="/login" element={<LoginPage />} />
<Route path="/login/:username" element={<LoginPage />} />
<Route path="/landing" element={<LandingPage />} />
<Route
path="/workspace"
element={<Navigate to="/workspace/chats/new" replace />}
/>
<Route
path="/workspace/chats"
element={
<WorkspaceLayout>
<ChatsPage />
</WorkspaceLayout>
}
/>
<Route
path="/workspace/chats/:thread_id"
element={
<WorkspaceLayout>
<ChatRuntime>
<ChatPage />
</ChatRuntime>
</WorkspaceLayout>
}
/>
<Route
path="/workspace/agents"
element={
<WorkspaceLayout>
<AgentsPage />
</WorkspaceLayout>
}
/>
<Route
path="/workspace/scheduled"
element={<Navigate to="/workspace/scheduled/tasks" replace />}
/>
<Route
path="/workspace/scheduled/tasks"
element={
<WorkspaceLayout>
<ScheduledTasksPage />
</WorkspaceLayout>
}
/>
<Route
path="/workspace/scheduled/runs/:run_id"
element={
<WorkspaceLayout>
<ScheduledTaskRunDetailPage />
</WorkspaceLayout>
}
/>
<Route
path="/workspace/agents/new"
element={
<WorkspaceLayout>
<NewAgentPage />
</WorkspaceLayout>
}
/>
<Route
path="/workspace/agents/:agent_id/chats"
element={<Navigate to="/workspace/agents" replace />}
/>
<Route
path="/workspace/agents/:agent_id/chats/:thread_id"
element={
<WorkspaceLayout>
<ChatRuntime>
<AgentChatPage />
</ChatRuntime>
</WorkspaceLayout>
}
/>
<Route path="/page/*" element={<PageRoutes />} />
<Route path="*" element={<NotFoundPage />} />
</Routes>
</AppProviders>
@@ -84,7 +84,7 @@ export function AgentCard({ agent }: AgentCardProps) {
]);
function handleChat() {
router.push(`/workspace/agents/${agent.id}/chats/new`);
router.push(`/page/workspace/agents/${agent.id}/chats/new`);
}
async function handleDelete() {
@@ -15,7 +15,7 @@ export function AgentGallery() {
const router = useRouter();
const handleNewAgent = () => {
router.push("/workspace/agents/new");
router.push("/page/workspace/agents/new");
};
return (
@@ -38,7 +38,7 @@ export function CommandPalette() {
const [isMac, setIsMac] = useState(false);
const handleNewChat = useCallback(() => {
router.push("/workspace/chats/new");
router.push("/page/workspace/chats/new");
setOpen(false);
}, [router]);
@@ -83,7 +83,7 @@ export function WorkspaceHeader({ className }: { className?: string }) {
<div className="flex items-center gap-2.5 px-2.5 py-3">
<BrandMark />
{env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY === "true" ? (
<Link href="/workspace/chats/new" className="min-w-0 flex-1 outline-none">
<Link href="/page/workspace/chats/new" className="min-w-0 flex-1 outline-none">
{titleBlock}
</Link>
) : (
@@ -20,18 +20,18 @@ export function WorkspaceNavChatList() {
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton
isActive={pathname === "/workspace/chats/new"}
isActive={pathname === "/page/workspace/chats/new"}
asChild
>
<Link className="text-sidebar-foreground" href="/workspace/chats/new">
<Link className="text-sidebar-foreground" href="/page/workspace/chats/new">
<MessageSquarePlus />
<span>{t.sidebar.newChat}</span>
</Link>
</SidebarMenuButton>
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton isActive={pathname === "/workspace/chats"} asChild>
<Link className="text-sidebar-foreground" href="/workspace/chats">
<SidebarMenuButton isActive={pathname === "/page/workspace/chats"} asChild>
<Link className="text-sidebar-foreground" href="/page/workspace/chats">
<MessagesSquare />
<span>{t.sidebar.chats}</span>
</Link>
@@ -39,10 +39,10 @@ export function WorkspaceNavChatList() {
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton
isActive={pathname.startsWith("/workspace/agents")}
isActive={pathname.startsWith("/page/workspace/agents")}
asChild
>
<Link className="text-sidebar-foreground" href="/workspace/agents">
<Link className="text-sidebar-foreground" href="/page/workspace/agents">
<BotIcon />
<span>{t.sidebar.agents}</span>
</Link>
@@ -50,10 +50,10 @@ export function WorkspaceNavChatList() {
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton
isActive={pathname === "/workspace/scheduled/tasks"}
isActive={pathname === "/page/workspace/scheduled/tasks"}
asChild
>
<Link className="text-sidebar-foreground" href="/workspace/scheduled/tasks">
<Link className="text-sidebar-foreground" href="/page/workspace/scheduled/tasks">
<ListChecks />
<span>任务管理</span>
</Link>
+2 -2
View File
@@ -36,8 +36,8 @@ export function pathOfThread(
: pickAgentRef(thread.context, thread.metadata);
return agentRef
? `/workspace/agents/${encodeURIComponent(agentRef)}/chats/${threadId}`
: `/workspace/chats/${threadId}`;
? `/page/workspace/agents/${encodeURIComponent(agentRef)}/chats/${threadId}`
: `/page/workspace/chats/${threadId}`;
}
export function textOfMessage(message: Message) {
+2 -2
View File
@@ -66,7 +66,7 @@ export default function AgentChatPage() {
history.replaceState(
null,
"",
`${window.location.pathname}${window.location.search}#/workspace/agents/${agent_id}/chats/${createdThreadId}`,
`${window.location.pathname}${window.location.search}#/page/workspace/agents/${agent_id}/chats/${createdThreadId}`,
);
},
onFinish: (state) => {
@@ -137,7 +137,7 @@ export default function AgentChatPage() {
size="sm"
variant="secondary"
onClick={() => {
router.push(`/workspace/agents/${agent_id}/chats/new`);
router.push(`/page/workspace/agents/${agent_id}/chats/new`);
}}
>
<PlusSquare /> {t.agents.newChat}
+1 -1
View File
@@ -64,7 +64,7 @@ export default function ChatPage() {
history.replaceState(
null,
"",
`${window.location.pathname}${window.location.search}#/workspace/chats/${createdThreadId}`,
`${window.location.pathname}${window.location.search}#/page/workspace/chats/${createdThreadId}`,
);
},
onFinish: (state) => {
+1 -1
View File
@@ -33,7 +33,7 @@ export default function LoginPage() {
}
setStoredAuth(auth);
setStatus("success");
router.replace("/workspace/chats/new");
router.replace("/page/workspace/chats/new");
} catch (error) {
if (cancelled) {
return;
+3 -3
View File
@@ -317,7 +317,7 @@ export default function NewAgentPage() {
<Button
variant="ghost"
size="icon-sm"
onClick={() => router.push("/workspace/agents")}
onClick={() => router.push("/page/workspace/agents")}
>
<ArrowLeftIcon className="h-4 w-4" />
</Button>
@@ -478,7 +478,7 @@ export default function NewAgentPage() {
<Button
onClick={() =>
router.push(
`/workspace/agents/${agentId}/chats/new`,
`/page/workspace/agents/${agentId}/chats/new`,
)
}
>
@@ -486,7 +486,7 @@ export default function NewAgentPage() {
</Button>
<Button
variant="outline"
onClick={() => router.push("/workspace/agents")}
onClick={() => router.push("/page/workspace/agents")}
>
{t.agents.backToGallery}
</Button>
+1 -1
View File
@@ -10,7 +10,7 @@ export function NotFoundPage() {
dedicated migration pass.
</p>
<Link
to="/workspace/chats/new"
to="/page/workspace/chats/new"
className="bg-primary text-primary-foreground rounded-md px-4 py-2 text-sm font-medium"
>
Open workspace
+20
View File
@@ -0,0 +1,20 @@
import { Navigate, Route, Routes } from "react-router-dom";
import WorkspaceRoutes from "./WorkspaceRoutes";
// 根路由容器,统一承接 /page/* 下的所有子系统路由
export default function PageRoutes() {
return (
<Routes>
<Route index element={<Navigate to="workspace" replace />} />
{/* 现有系统:DeerFlow Workspace */}
<Route path="workspace/*" element={<WorkspaceRoutes />} />
{/* TODO: 引入外部系统路由
import AnotherSystemRoutes from "外部系统路径";
<Route path="other/*" element={<AnotherSystemRoutes />} />
*/}
</Routes>
);
}
+1 -1
View File
@@ -12,7 +12,7 @@ export default function ScheduledChatPage() {
const { data, isLoading, error } = useSchedulerThread();
if (data?.thread_id) {
return <Navigate to={`/workspace/chats/${data.thread_id}`} replace />;
return <Navigate to={`/page/workspace/chats/${data.thread_id}`} replace />;
}
return (
@@ -174,7 +174,7 @@ export default function ScheduledTaskRunDetailPage() {
try {
await actions.removeRun.mutateAsync(run.id);
toast.success("执行记录已删除");
navigate("/workspace/scheduled/tasks");
navigate("/page/workspace/scheduled/tasks");
} catch (error) {
toast.error(error instanceof Error ? error.message : "删除失败");
}
@@ -198,7 +198,7 @@ export default function ScheduledTaskRunDetailPage() {
<ChevronDown className={cn("size-3 transition-transform", showMeta && "rotate-180")} />
执行信息
</Button>
<Button variant="ghost" size="sm" className="h-7 px-2 text-xs" onClick={() => navigate("/workspace/scheduled/tasks")}>
<Button variant="ghost" size="sm" className="h-7 px-2 text-xs" onClick={() => navigate("/page/workspace/scheduled/tasks")}>
<ListChecks className="size-3" />
返回记录
</Button>
@@ -686,7 +686,7 @@ export default function ScheduledTasksPage() {
<Button
size="sm"
variant="outline"
onClick={() => navigate(`/workspace/scheduled/runs/${run.id}`)}
onClick={() => navigate(`/page/workspace/scheduled/runs/${run.id}`)}
>
<Eye className="size-4" />
查看结果
@@ -0,0 +1,94 @@
import { Navigate, Route, Routes } from "react-router-dom";
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 ChatsPage from "./ChatsPage";
import ChatPage from "./ChatPage";
import AgentsPage from "./AgentsPage";
import AgentChatPage from "./AgentChatPage";
import NewAgentPage from "./NewAgentPage";
import ScheduledTaskRunDetailPage from "./ScheduledTaskRunDetailPage";
import ScheduledTasksPage from "./ScheduledTasksPage";
function WorkspaceLayout({ children }: { children: React.ReactNode }) {
return (
<SidebarProvider className="h-screen" defaultOpen>
<WorkspaceSidebar />
<SidebarInset className="min-w-0">{children}</SidebarInset>
<CommandPalette />
<Toaster position="top-center" />
</SidebarProvider>
);
}
function ChatRuntime({ children }: { children: React.ReactNode }) {
return (
<SubtasksProvider>
<ArtifactsProvider>
<PromptInputProvider>{children}</PromptInputProvider>
</ArtifactsProvider>
</SubtasksProvider>
);
}
export default function WorkspaceRoutes() {
return (
<Routes>
<Route index element={<Navigate to="chats/new" replace />} />
<Route
path="chats"
element={<WorkspaceLayout><ChatsPage /></WorkspaceLayout>}
/>
<Route
path="chats/:thread_id"
element={
<WorkspaceLayout>
<ChatRuntime>
<ChatPage />
</ChatRuntime>
</WorkspaceLayout>
}
/>
<Route
path="agents"
element={<WorkspaceLayout><AgentsPage /></WorkspaceLayout>}
/>
<Route
path="agents/new"
element={<WorkspaceLayout><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>
<ChatRuntime>
<AgentChatPage />
</ChatRuntime>
</WorkspaceLayout>
}
/>
<Route
path="scheduled"
element={<Navigate to="/page/workspace/scheduled/tasks" replace />}
/>
<Route
path="scheduled/tasks"
element={<WorkspaceLayout><ScheduledTasksPage /></WorkspaceLayout>}
/>
<Route
path="scheduled/runs/:run_id"
element={<WorkspaceLayout><ScheduledTaskRunDetailPage /></WorkspaceLayout>}
/>
</Routes>
);
}