From 8ecc32da6dfaa4577a6734967323bacac84be2a9 Mon Sep 17 00:00:00 2001
From: fengxiangdebaozi <10845145+fengxiangdebaozi@user.noreply.gitee.com>
Date: Thu, 14 May 2026 18:13:58 +0800
Subject: [PATCH] =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E7=BB=93=E6=9E=84=E4=BF=AE?=
=?UTF-8?q?=E6=94=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
frontend-web/src/components/ui/sidebar.tsx | 7 +++++-
.../workspace/artifacts/context.tsx | 8 +++----
frontend-web/src/core/route-base.tsx | 24 +++++++++++++++++++
frontend-web/src/core/threads/utils.ts | 13 ++++++++--
frontend-web/src/pages/AgentChatPage.tsx | 4 +++-
frontend-web/src/pages/ChatPage.tsx | 4 +++-
frontend-web/src/pages/ChatsPage.tsx | 3 ++-
frontend-web/src/pages/PageRoutes.tsx | 5 ++--
.../src/pages/ScheduledTaskRunDetailPage.tsx | 3 ++-
frontend-web/src/pages/ScheduledTasksPage.tsx | 2 +-
frontend-web/src/pages/StrategyRoutes.tsx | 5 ++++
frontend-web/src/pages/WorkspaceRoutes.tsx | 11 ++++++++-
frontend-web/src/shims/next-navigation.ts | 13 ++++++----
.../src/strategy-components/Header.tsx | 14 ++++-------
14 files changed, 87 insertions(+), 29 deletions(-)
create mode 100644 frontend-web/src/core/route-base.tsx
diff --git a/frontend-web/src/components/ui/sidebar.tsx b/frontend-web/src/components/ui/sidebar.tsx
index 2e6d3ca1..80e8e357 100644
--- a/frontend-web/src/components/ui/sidebar.tsx
+++ b/frontend-web/src/components/ui/sidebar.tsx
@@ -53,6 +53,10 @@ function useSidebar() {
return context;
}
+function useSidebarSafe() {
+ return React.useContext(SidebarContext);
+}
+
function SidebarProvider({
defaultOpen = true,
open: openProp,
@@ -229,7 +233,7 @@ function Sidebar({
{
setSelectedArtifact(artifact);
if (env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY !== "true") {
- setSidebarOpen(false);
+ sidebar?.setOpen(false);
}
if (!autoSelect) {
setAutoSelect(false);
}
},
- [setSidebarOpen, setSelectedArtifact, setAutoSelect],
+ [sidebar, setSelectedArtifact, setAutoSelect],
);
const deselect = useCallback(() => {
diff --git a/frontend-web/src/core/route-base.tsx b/frontend-web/src/core/route-base.tsx
new file mode 100644
index 00000000..8790a83e
--- /dev/null
+++ b/frontend-web/src/core/route-base.tsx
@@ -0,0 +1,24 @@
+import { createContext, useCallback, useContext } from "react";
+import { useNavigate, type NavigateOptions } from "react-router-dom";
+
+export const RouteBaseContext = createContext("/page/workspace");
+export const RouteBaseProvider = RouteBaseContext.Provider;
+
+export function useRouteBase() {
+ return useContext(RouteBaseContext);
+}
+
+export function useRouteNavigate() {
+ const navigate = useNavigate();
+ const base = useRouteBase();
+ return useCallback(
+ (path: string | number, opts?: NavigateOptions) => {
+ if (typeof path === "string") {
+ navigate(path.replace("/page/workspace", base), opts);
+ } else {
+ navigate(path);
+ }
+ },
+ [navigate, base],
+ );
+}
diff --git a/frontend-web/src/core/threads/utils.ts b/frontend-web/src/core/threads/utils.ts
index 1c2b7ab5..8877eda3 100644
--- a/frontend-web/src/core/threads/utils.ts
+++ b/frontend-web/src/core/threads/utils.ts
@@ -1,5 +1,7 @@
+import { useContext } from "react";
import type { Message } from "@langchain/langgraph-sdk";
+import { RouteBaseContext } from "@/core/route-base";
import type { AgentThread, AgentThreadContext } from "./types";
type ThreadAgentRef = Pick
;
@@ -28,6 +30,7 @@ function pickAgentRef(
export function pathOfThread(
thread: ThreadRouteTarget,
context?: ThreadAgentRef | null,
+ base = "/page/workspace",
) {
const threadId = typeof thread === "string" ? thread : thread.thread_id;
const agentRef =
@@ -36,8 +39,14 @@ export function pathOfThread(
: pickAgentRef(thread.context, thread.metadata);
return agentRef
- ? `/page/workspace/agents/${encodeURIComponent(agentRef)}/chats/${threadId}`
- : `/page/workspace/chats/${threadId}`;
+ ? `${base}/agents/${encodeURIComponent(agentRef)}/chats/${threadId}`
+ : `${base}/chats/${threadId}`;
+}
+
+export function usePathOfThread() {
+ const base = useContext(RouteBaseContext);
+ return (thread: ThreadRouteTarget, context?: ThreadAgentRef | null) =>
+ pathOfThread(thread, context, base);
}
export function textOfMessage(message: Message) {
diff --git a/frontend-web/src/pages/AgentChatPage.tsx b/frontend-web/src/pages/AgentChatPage.tsx
index 871998b9..9f4679de 100644
--- a/frontend-web/src/pages/AgentChatPage.tsx
+++ b/frontend-web/src/pages/AgentChatPage.tsx
@@ -2,6 +2,7 @@
import { BotIcon, PlusSquare } from "lucide-react";
import { useParams, useRouter } from "next/navigation";
+import { useRouteBase } from "@/core/route-base";
import { useCallback, useEffect, useState } from "react";
import type { PromptInputMessage } from "@/components/ai-elements/prompt-input";
@@ -32,6 +33,7 @@ import { env } from "@/env";
import { cn } from "@/lib/utils";
export default function AgentChatPage() {
+ const routeBase = useRouteBase();
const { t } = useI18n();
const [showFollowups, setShowFollowups] = useState(false);
const [hasStartedConversation, setHasStartedConversation] = useState(false);
@@ -66,7 +68,7 @@ export default function AgentChatPage() {
history.replaceState(
null,
"",
- `${window.location.pathname}${window.location.search}#/page/workspace/agents/${agent_id}/chats/${createdThreadId}`,
+ `${window.location.pathname}${window.location.search}#${routeBase}/agents/${agent_id}/chats/${createdThreadId}`,
);
},
onFinish: (state) => {
diff --git a/frontend-web/src/pages/ChatPage.tsx b/frontend-web/src/pages/ChatPage.tsx
index 3ada83f5..66c75403 100644
--- a/frontend-web/src/pages/ChatPage.tsx
+++ b/frontend-web/src/pages/ChatPage.tsx
@@ -26,11 +26,13 @@ import { useModels } from "@/core/models/hooks";
import { useNotification } from "@/core/notification/hooks";
import { useThreadSettings } from "@/core/settings";
import { useThreadStream } from "@/core/threads/hooks";
+import { useRouteBase } from "@/core/route-base";
import { textOfMessage } from "@/core/threads/utils";
import { env } from "@/env";
import { cn } from "@/lib/utils";
export default function ChatPage() {
+ const routeBase = useRouteBase();
const { t } = useI18n();
const [showFollowups, setShowFollowups] = useState(false);
const [hasStartedConversation, setHasStartedConversation] = useState(false);
@@ -64,7 +66,7 @@ export default function ChatPage() {
history.replaceState(
null,
"",
- `${window.location.pathname}${window.location.search}#/page/workspace/chats/${createdThreadId}`,
+ `${window.location.pathname}${window.location.search}#${routeBase}/chats/${createdThreadId}`,
);
},
onFinish: (state) => {
diff --git a/frontend-web/src/pages/ChatsPage.tsx b/frontend-web/src/pages/ChatsPage.tsx
index ceb8228d..e2990a5f 100644
--- a/frontend-web/src/pages/ChatsPage.tsx
+++ b/frontend-web/src/pages/ChatsPage.tsx
@@ -12,10 +12,11 @@ import {
} from "@/components/workspace/workspace-container";
import { useI18n } from "@/core/i18n/hooks";
import { useThreads } from "@/core/threads/hooks";
-import { pathOfThread, titleOfThread } from "@/core/threads/utils";
+import { usePathOfThread, titleOfThread } from "@/core/threads/utils";
import { formatTimeAgo } from "@/core/utils/datetime";
export default function ChatsPage() {
+ const pathOfThread = usePathOfThread();
const { t } = useI18n();
const { data: threads } = useThreads();
const [search, setSearch] = useState("");
diff --git a/frontend-web/src/pages/PageRoutes.tsx b/frontend-web/src/pages/PageRoutes.tsx
index 6e174624..1d252412 100644
--- a/frontend-web/src/pages/PageRoutes.tsx
+++ b/frontend-web/src/pages/PageRoutes.tsx
@@ -8,7 +8,7 @@ import StrategyRoutes from "./StrategyRoutes";
import Header from "@/strategy-components/Header";
// 设为 true 时隐藏侧边栏(开发中,暂未完成)
-const SIDEBAR_ENABLED = true;
+const SIDEBAR_ENABLED = false;
function PageLayout() {
const [collapsed, setCollapsed] = useState(false);
@@ -26,7 +26,7 @@ function PageLayout() {
!SIDEBAR_ENABLED ? "" : collapsed ? "pl-16" : "pl-64"
}`}
>
-
+ {SIDEBAR_ENABLED && }
} />
@@ -36,6 +36,7 @@ function PageLayout() {
}
/>
diff --git a/frontend-web/src/pages/ScheduledTaskRunDetailPage.tsx b/frontend-web/src/pages/ScheduledTaskRunDetailPage.tsx
index 4071b1e8..febf21fb 100644
--- a/frontend-web/src/pages/ScheduledTaskRunDetailPage.tsx
+++ b/frontend-web/src/pages/ScheduledTaskRunDetailPage.tsx
@@ -2,7 +2,8 @@
import { useEffect, useMemo, useState } from "react";
import { ChevronDown, Download, FileText, ListChecks, Trash2 } from "lucide-react";
-import { useNavigate, useParams } from "react-router-dom";
+import { useParams } from "react-router-dom";
+import { useRouteNavigate as useNavigate } from "@/core/route-base";
import { toast } from "sonner";
import { Badge } from "@/components/ui/badge";
diff --git a/frontend-web/src/pages/ScheduledTasksPage.tsx b/frontend-web/src/pages/ScheduledTasksPage.tsx
index b0481fbb..d863247e 100644
--- a/frontend-web/src/pages/ScheduledTasksPage.tsx
+++ b/frontend-web/src/pages/ScheduledTasksPage.tsx
@@ -17,7 +17,7 @@ import {
RefreshCw,
Trash2,
} from "lucide-react";
-import { useNavigate } from "react-router-dom";
+import { useRouteNavigate as useNavigate } from "@/core/route-base";
import { toast } from "sonner";
import { Badge } from "@/components/ui/badge";
diff --git a/frontend-web/src/pages/StrategyRoutes.tsx b/frontend-web/src/pages/StrategyRoutes.tsx
index 879730b9..54941cdd 100644
--- a/frontend-web/src/pages/StrategyRoutes.tsx
+++ b/frontend-web/src/pages/StrategyRoutes.tsx
@@ -1,7 +1,9 @@
import { Navigate, Route, Routes } from "react-router-dom";
import type { ReactNode } from "react";
+import { Toaster } from "sonner";
import { getStoredAuth } from "@/core/auth";
+import { RouteBaseProvider } from "@/core/route-base";
import { SubtasksProvider } from "@/core/tasks/context";
import { ArtifactsProvider } from "@/components/workspace/artifacts";
import { PromptInputProvider } from "@/components/ai-elements/prompt-input";
@@ -28,6 +30,7 @@ function ChatRuntime({ children }: { children: ReactNode }) {
export default function StrategyRoutes() {
return (
+
} />
@@ -86,5 +89,7 @@ export default function StrategyRoutes() {
/>
+
+
);
}
diff --git a/frontend-web/src/pages/WorkspaceRoutes.tsx b/frontend-web/src/pages/WorkspaceRoutes.tsx
index b03318e5..4357ae5c 100644
--- a/frontend-web/src/pages/WorkspaceRoutes.tsx
+++ b/frontend-web/src/pages/WorkspaceRoutes.tsx
@@ -11,6 +11,8 @@ 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";
@@ -24,10 +26,12 @@ export function WorkspaceLayout({
children,
pageSidebarCollapsed,
pageSidebarHidden = false,
+ headerHidden = false,
}: {
children: ReactNode;
pageSidebarCollapsed: boolean;
pageSidebarHidden?: boolean;
+ headerHidden?: boolean;
}) {
const pageSidebarWidth = pageSidebarHidden
? "0rem"
@@ -41,6 +45,7 @@ export function WorkspaceLayout({
style={
{
"--page-sidebar-width": pageSidebarWidth,
+ "--header-height": headerHidden ? "0rem" : "4rem",
} as CSSProperties
}
// Keep the fixed workspace sidebar aligned to the outer page sidebar width.
@@ -69,13 +74,16 @@ function ChatRuntime({ children }: { children: ReactNode }) {
export default function WorkspaceRoutes({
pageSidebarCollapsed = false,
pageSidebarHidden = false,
+ headerHidden = false,
}: {
pageSidebarCollapsed?: boolean;
pageSidebarHidden?: boolean;
+ headerHidden?: boolean;
}) {
- const layoutProps = { pageSidebarCollapsed, pageSidebarHidden };
+ const layoutProps = { pageSidebarCollapsed, pageSidebarHidden, headerHidden };
return (
+
} />
+
);
}
diff --git a/frontend-web/src/shims/next-navigation.ts b/frontend-web/src/shims/next-navigation.ts
index db9aed3c..b3bf4941 100644
--- a/frontend-web/src/shims/next-navigation.ts
+++ b/frontend-web/src/shims/next-navigation.ts
@@ -1,4 +1,4 @@
-import { useMemo } from "react";
+import { useContext, useMemo } from "react";
import {
useLocation,
useNavigate,
@@ -6,19 +6,24 @@ import {
useSearchParams as useRouterSearchParams,
} from "react-router-dom";
+import { RouteBaseContext } from "@/core/route-base";
+
export function useRouter() {
const navigate = useNavigate();
+ const base = useContext(RouteBaseContext);
return useMemo(
() => ({
- push: (href: string) => navigate(href),
- replace: (href: string) => navigate(href, { replace: true }),
+ push: (href: string) =>
+ navigate(href.replace("/page/workspace", base)),
+ replace: (href: string) =>
+ navigate(href.replace("/page/workspace", base), { replace: true }),
back: () => navigate(-1),
forward: () => navigate(1),
refresh: () => window.location.reload(),
prefetch: async () => {},
}),
- [navigate],
+ [navigate, base],
);
}
diff --git a/frontend-web/src/strategy-components/Header.tsx b/frontend-web/src/strategy-components/Header.tsx
index 78c5d1d8..f5b1c716 100644
--- a/frontend-web/src/strategy-components/Header.tsx
+++ b/frontend-web/src/strategy-components/Header.tsx
@@ -1,5 +1,5 @@
import React from 'react';
-import { Bell, Search, User, ChevronDown, Moon, Sun, Palette } from 'lucide-react';
+import { Bell, Search, User, ChevronDown, Moon, Palette } from 'lucide-react';
import { useTheme } from '../contexts/ThemeContext';
const Header: React.FC = () => {
@@ -40,11 +40,7 @@ const Header: React.FC = () => {
}`}
title={isDark ? '切换到红白主题' : '切换到深色主题'}
>
- {isDark ? (
-
- ) : (
-
- )}
+ {isDark ? : }
{/* 通知 */}
@@ -63,14 +59,12 @@ const Header: React.FC = () => {
isDark ? 'hover:bg-slate-800/50' : 'hover:bg-red-500'
}`}>