fix(console): 清理桌面端控制台 React/antd 开发期警告
- mermaidComponents 增加安全 <a> 渲染器:解构掉 XMarkdown 注入的 domNode/streamStatus,避免透传到 DOM 触发 React warning,并改为 外链在系统浏览器/新标签打开(防止 Tauri WebView 内跳转丢失应用) - 6 处独立 Spin+tip 改为嵌套模式(antd 要求 nest/fullscreen 才显示 tip), 消除 'tip only work in nest or fullscreen' 警告:MainLayout Suspense fallback、DefaultRedirect、Network Chat、政策/服务详情页 说明:Chat 页正文的 domNode/streamStatus、Input key、flushSync、 findDOMNode 警告来自 @agentscope-ai/chat 三方库内部硬编码,开发期 显示、不影响功能,生产构建无。
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import type { ReactNode } from "react";
|
||||
import type { CSSProperties, ComponentType, ReactNode } from "react";
|
||||
import type { ComponentProps } from "@ant-design/x-markdown";
|
||||
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
||||
import { oneDark } from "react-syntax-highlighter/dist/esm/styles/prism";
|
||||
import { MermaidCodeBlock } from "./MermaidCodeBlock";
|
||||
import { openExternalLink } from "@/utils/openExternalLink";
|
||||
|
||||
/**
|
||||
* Extracts plain text from React children recursively.
|
||||
@@ -66,6 +67,37 @@ function CodeWithMermaid({
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Safe markdown <a> renderer for XMarkdown.
|
||||
*
|
||||
* XMarkdown injects `domNode` / `streamStatus` into every custom component;
|
||||
* if passed through to the DOM element they trigger React warnings. The two
|
||||
* props are destructured off, and clicks open the link in the system browser
|
||||
* / new tab instead of navigating the Tauri WebView window away from the app.
|
||||
*/
|
||||
function SafeMarkdownAnchor({
|
||||
domNode: _domNode,
|
||||
streamStatus: _streamStatus,
|
||||
href,
|
||||
children,
|
||||
...rest
|
||||
}: ComponentProps) {
|
||||
const linkHref = typeof href === "string" ? href : undefined;
|
||||
return (
|
||||
<a
|
||||
{...rest}
|
||||
href={linkHref}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
if (linkHref) openExternalLink(linkHref);
|
||||
}}
|
||||
style={{ cursor: "pointer", ...(rest as { style?: CSSProperties }).style }}
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* XMarkdown components mapping that enables Mermaid diagram rendering.
|
||||
*
|
||||
@@ -76,7 +108,8 @@ function CodeWithMermaid({
|
||||
*/
|
||||
export const mermaidComponents: Record<
|
||||
string,
|
||||
React.ComponentType<ComponentProps>
|
||||
ComponentType<ComponentProps>
|
||||
> = {
|
||||
code: CodeWithMermaid,
|
||||
};
|
||||
a: SafeMarkdownAnchor,
|
||||
};
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Suspense, useMemo } from "react";
|
||||
import { Layout, Spin } from "antd";
|
||||
import { Routes, Route, useLocation, matchPath } from "react-router-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import Sidebar from "../Sidebar";
|
||||
import Header from "../Header";
|
||||
import ConsolePollService from "../../components/ConsolePollService";
|
||||
@@ -40,7 +39,6 @@ function pickSelectedKey(
|
||||
}
|
||||
|
||||
export default function MainLayout() {
|
||||
const { t } = useTranslation();
|
||||
const location = useLocation();
|
||||
const currentPath = location.pathname;
|
||||
const routes = useRoutes();
|
||||
@@ -81,7 +79,7 @@ export default function MainLayout() {
|
||||
<Suspense
|
||||
fallback={
|
||||
<Spin
|
||||
tip={t("common.loading")}
|
||||
size="large"
|
||||
style={{ display: "block", margin: "20vh auto" }}
|
||||
/>
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
import { Suspense } from "react";
|
||||
import { Navigate } from "react-router-dom";
|
||||
import { Spin } from "antd";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { lazyImportWithRetry } from "../../utils/lazyWithRetry";
|
||||
import { useCodingMode } from "../../stores/codingModeStore";
|
||||
import { routeRegistry } from "../../plugins/registry/store";
|
||||
@@ -140,12 +139,11 @@ const AppCenterPage = lazyImportWithRetry("../../pages/AppCenter");
|
||||
* deciding between /coding and /chat — see MainLayout.tsx history for why.
|
||||
*/
|
||||
function DefaultRedirect() {
|
||||
const { t } = useTranslation();
|
||||
const { codingMode, initialized } = useCodingMode();
|
||||
if (!initialized) {
|
||||
return (
|
||||
<Spin
|
||||
tip={t("common.loading")}
|
||||
size="large"
|
||||
style={{ display: "block", margin: "20vh auto" }}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -79,7 +79,9 @@ export default function AgentNetworkChatPage() {
|
||||
if (loading) {
|
||||
return (
|
||||
<div className={styles.loading}>
|
||||
<Spin size="large" tip="正在连接远程智能体…" />
|
||||
<Spin size="large" tip="正在连接远程智能体…">
|
||||
<div style={{ minHeight: 160 }} />
|
||||
</Spin>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -123,7 +125,9 @@ export default function AgentNetworkChatPage() {
|
||||
{conversation ? (
|
||||
<ChatWindow conversation={conversation} />
|
||||
) : (
|
||||
<Spin tip="加载会话…" />
|
||||
<Spin tip="加载会话…">
|
||||
<div style={{ minHeight: 240 }} />
|
||||
</Spin>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -38,7 +38,9 @@ export default function OpcPolicyDetail() {
|
||||
return (
|
||||
<RequireRole roles={["opc_member"]}>
|
||||
<div className={`${styles.page} opc-page`} style={{ display: "flex", alignItems: "center", justifyContent: "center", minHeight: 400 }}>
|
||||
<Spin size="large" tip="加载政策详情中..." />
|
||||
<Spin size="large" tip="加载政策详情中...">
|
||||
<div style={{ minHeight: 160 }} />
|
||||
</Spin>
|
||||
</div>
|
||||
</RequireRole>
|
||||
);
|
||||
|
||||
@@ -114,7 +114,9 @@ export default function ServiceDetailPage() {
|
||||
if (loading) {
|
||||
return (
|
||||
<div className={styles.loading}>
|
||||
<Spin size="large" tip="加载中..." />
|
||||
<Spin size="large" tip="加载中...">
|
||||
<div style={{ minHeight: 160 }} />
|
||||
</Spin>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user