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:
Pine
2026-09-13 17:31:54 +08:00
parent 05eedbca9d
commit 58df004d02
6 changed files with 50 additions and 13 deletions
@@ -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 -3
View File
@@ -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" }}
/>
);
+6 -2
View File
@@ -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>
);
}