console-ui-next/PROGRESS.md
将 Nacos 控制台前端从 React 16 + Webpack 升级到 React 18 + Vite + Shadcn/ui,保留全部原有功能并改善用户体验。
| 分类 | 技术选型 |
|---|---|
| 框架 | React 18 + TypeScript |
| 构建工具 | Vite 7 |
| 样式 | Tailwind CSS 4(oklch 色彩系统,蓝白主题) |
| UI 组件库 | Shadcn/ui(基于 Radix UI) |
| 状态管理 | Zustand v5(stores: auth, server, namespace, app, config, history, service) |
| 路由 | React Router v7(HashRouter, 懒加载, AuthGuard/AdminGuard/GuestGuard) |
| 国际化 | react-i18next(zh-CN / en-US) |
| HTTP 客户端 | Axios(请求/响应拦截器, Token 处理) |
| 代码编辑器 | @monaco-editor/react |
/nacos/v3/auth/*),有 /nacos 上下文路径/nacos 上下文路径前缀
/v3/console/core/namespace/*/v3/console/cs/config/*/v3/console/cs/history/*/v3/console/server/*src/types/config.ts)src/api/config.ts)- 涵盖所有端点src/stores/config-store.ts)src/pages/configurationManagement/)src/pages/newconfig/)src/pages/configdetail/)src/pages/configeditor/)src/pages/historyRollback/)- 搜索、分页、差异对比弹窗src/pages/historyDetail/)- 元数据展示、灰度规则解析src/pages/configRollback/)- 按 opType 区分回滚逻辑与警告提示ConflictPolicy 冲突策略类型、ConfigCloneItem 克隆条目接口)exportUrl 导出 URL 构建、importFile ZIP 上传、clone JSON 克隆)selectedIds: Set<string>、toggleSelect、selectAll、clearSelection)window.open 触发浏览器下载)ConfigListenerInfo 监听查询响应、ConfigBetaInfo 灰度配置信息)getBeta 获取灰度配置、publishBeta 灰度发布、stopBeta 停止灰度)src/pages/listeningToQuery/)
src/pages/configeditor/)
getBeta API 加载现有灰度配置stopBeta API + 清除灰度状态src/types/service.ts)- ServiceView, ServiceDetailInfo, Instance, ClusterInfo, Selector, HealthChecker, SubscriberInfo 等src/api/service.ts)- 10 个方法:listServices, getService, createService, updateService, deleteService, getSelectorTypes, updateCluster, listInstances, updateInstance, listSubscriberssrc/stores/service-store.ts)- 服务列表/搜索/分页/详情/选择器类型状态管理src/pages/serviceManagement/)
src/pages/serviceDetail/)
v3/console/ns/instance/list),不依赖服务详情响应的 cluster.hosts 字段src/pages/subscriberList/)
src/types/mcp.ts)- McpServerBasicInfo, McpServerDetailInfo, McpToolSpecification, McpVersionDetail, McpSecurityScheme 等src/api/mcp.ts)- listMcpServers, getMcpServer, createMcpServer, updateMcpServer, deleteMcpServer, importMcpTools, verifyMcpImport 等src/stores/mcp-store.ts)- 列表/搜索/分页/详情/版本选择状态管理src/pages/mcpServerManagement/)- 搜索、分页、启用/禁用、删除src/pages/mcpServerDetail/)
overflow-hidden py-0 gap-0 + 自定义 header(px-5 py-3.5 border-b bg-muted/30)+ 语义图标InfoCell 网格布局McpToolList):树形参数层级展示(递归 SchemaTreeNode)+ 请求/响应模版 + 标注信息is_latest 字段映射修复)src/pages/newMcpServer/)
py-0 gap-0 + 自定义 header + 语义图标(Server/Terminal/Globe/Shield/Wrench)space-y-5 + space-y-2.5(Label-Input)tool-manager/):Wrench 图标(amber)+ 计数 Badge + 左侧列表 bg-muted/20 + 选中态 bg-primary/10 ring-1latest=false, overrideExisting=falselatest=true, overrideExisting=truelatest=isCurrentLatest, overrideExisting=trueuseEffect 自动切换:当前策略不可用时切换到第一个可用策略importMode prop):HTTP 转换仅支持 OpenAPI 导入,SSE/Streamable 支持 MCP 实例导入,Stdio 不支持导入backdrop-blur-sm 毛玻璃效果currentMcp 缓存数据填充表单,避免重复 API 请求和 skeleton 闪烁protocol === 'http' || 'https' 时显示琥珀色 "HTTP 转换" 徽章 + RefreshCw 图标mcp-store.ts):fetchMcpServers 和 fetchMcpDetail 仅在无缓存数据时设置 loading=true,有数据时保持 UI 可见mcpServerDetail):组件卸载时不再调用 clearCurrentMcp(),保留缓存数据供编辑页复用routes.tsx):PageLoading 从全屏 min-h-screen 缩小为 py-32,减少视觉跳动currentMcp.name === editMcpName 时跳过 API 请求,initLoading 初始为 falsesrc/types/agent.ts)- AgentBasicInfo(对齐后端 AgentCardVersionInfo), AgentDetailInfo(对齐后端 AgentCardDetailInfo), AgentSkill, AgentCapabilities, AgentProvider, AgentVersionDetail 等src/api/agent.ts)- listAgents, getAgent, createAgent, updateAgent, deleteAgent, getVersionListsrc/stores/agent-store.ts)- 列表/搜索/分页/详情/版本/选择状态管理src/pages/agentManagement/)- 卡片网格布局、搜索、分页、批量删除src/components/ai/agent/AgentCard.tsx)
src/pages/agentDetail/)- Hero Header + 基本信息 + 能力 + Skills + Provider + I/O 模式 + 附加接口src/pages/newAgent/)
setAsLatest=falsesetAsLatest=truestrategyAvailability useMemo 动态计算可用性,不可用选项灰化 + 原因提示AgentBasicInfo 移除列表接口不返回的字段(url, preferredTransport, defaultInputModes, defaultOutputModes, provider),新增 versionDetails, registrationTypeAgentDetailInfo 承接详情接口专属字段,新增 latestVersionImportMcpToolsDialog.tsx 中 response.data.data 改为 response.data(axios 拦截器已解包一层)ToolList.tsx 用原生 div overflow-y-auto overflow-x-hidden 替换 Radix ScrollArea(其 min-width:100% 导致内容宽度不受约束)现象:登录始终返回错误,同时弹出两个错误提示。
根因:
/nacos/* 转发到 8080 端口,但登录接口(/nacos/v3/auth/user/login)实际在 8848 端口。return response.data(解包 HTTP body),但 auth-store 又做了一次 response.data(双重解包)。修复:
/nacos/v1/auth 和 /nacos/v3/auth 添加单独的代理规则,指向 8848 端口。response as unknown as TokenData 代替 response.data。现象:配置管理页面加载成功但表格显示"暂无数据"。
根因(3 个 bug):
contextPath 为空(nacos.console.contextPath=),API 路径是 /v3/console/* 而非 /nacos/v3/console/*。代理原样转发导致 8080 将请求当作静态资源处理,返回 "No static resource" 错误。response.data?.data(多了一层 .data),导致 namespaces = [],命名空间始终为空。"true", "30")而非布尔/数字类型,store 直接使用导致类型判断失败。修复:
rewrite: (path) => path.replace(/^\/nacos/, ''),去掉 /nacos 前缀。const body = response as unknown as { code: number; data: Namespace[] }; const namespaces = body.data || []。String(val) === 'true' 做布尔转换,Number(val) 做数值转换。现象:npx shadcn@latest add 因 TLS 证书错误失败。
修复:手动创建组件文件(textarea.tsx, radio-group.tsx, skeleton.tsx),按照 Shadcn/ui 规范使用 @radix-ui 原语实现。
现象(4 项):
根因:
py-6 + CardContent pt-6 = 双重 top padding(48px);同时 AppLayout <main p-6> 和页面自身 p-6 也是双重 padding。p-0 移除了所有内边距,表头和数据行紧贴卡片边缘。configs.length > 0 时显示。修复:
py-0 + CardContent py-4;移除所有页面级 p-6(由 AppLayout 统一提供)。pl-6,尾列增加 pr-6(表头和数据行均添加)。setPage(1, newSize) 重置到第 1 页;分页器显示条件改为 total > 0。现象:配置列表页和历史版本列表页切换每页条数时,整个表格区域闪烁(先显示 Skeleton 再显示数据)。
根因:加载状态触发了条件渲染,将整个表格替换为 Skeleton 组件,导致布局位移。
修复:
loading && list.length === 0(首次加载无数据)时显示 Skeleton。opacity-50 pointer-events-none 表示加载中状态。total > 0(不再受 loading 状态影响)。configurationManagement 和 historyRollback 两个列表页。现象:服务列表页显示 IP 数 = 1,但点进详情页后集群卡片中无实例数据。
根因:初始实现直接使用服务详情 API 响应的 cluster.hosts 字段渲染实例,但该字段可能为空或不完整。旧版代码中每个集群的实例是通过独立的 InstanceTable 组件单独调用 v3/console/ns/instance/list API 获取的。
修复:
instancesByCluster 状态,独立存储每个集群的实例数据。fetchClusterInstances() 回调,按集群名调用 serviceApi.listInstances() 获取实例列表(带分页参数)。useEffect 监听 currentService 变化,服务详情加载后自动为每个集群发起实例获取请求。ClusterCard 组件改为接收 instances、instanceTotal、instanceLoading props,不再使用 cluster.hosts。fetchClusterInstances(),避免 setTimeout hack。现象:详情页版本下拉和 Hero Header 中的 Latest 徽章始终不显示。
根因:后端 Java 类 ServerVersionDetail 的字段名为 is_latest(snake_case),Jackson 序列化后 JSON 也是 is_latest。但前端 TypeScript McpVersionDetail 接口定义为 isLatest(camelCase),导致字段永远为 undefined。
修复:将 McpVersionDetail 接口的字段名从 isLatest 改为 is_latest,同步更新详情页和编辑页所有引用(4 处)。
后端 ConsoleInstanceController(/v3/console/ns/instance)目前仅提供 list 和 update 两个端点,没有 DELETE 方法。Admin API(/v3/admin/ns/instance)有 deregister 端点,但属于内部/SDK 接口,Console 前端不应直接调用。
待办:后端在 ConsoleInstanceController 中添加 DELETE 端点后,前端再实现非持久化实例删除功能(删除按钮 + 确认对话框)。
响应拦截器模式:Axios 拦截器执行 return response.data,所有 API 调用结果已经是 HTTP body。Store 层必须正确类型转换:对于标准包装响应({ code, data })使用 response as unknown as { code: number; data: T },对于扁平响应(如服务器状态)使用 response as unknown as T。
命名空间 ID 约定:Nacos v3 使用 "public" 作为公共命名空间 ID(不是空字符串)。namespace store 初始化时默认为 "",从 API 获取后更新为 "public"。
双端口代理策略:认证端点 → 8848(保留 /nacos 前缀),控制台端点 → 8080(通过 rewrite 去掉 /nacos 前缀)。
旧代码调研原则:实现每个模块前,充分调研旧版 console-ui/ React 16 代码库,了解 API 结构、数据流和 UI 交互模式。
console-ui-next/
├── src/
│ ├── api/ # API 层(client.ts, auth.ts, config.ts, namespace.ts, server.ts, service.ts)
│ ├── components/
│ │ ├── config/ # 配置相关组件(MonacoEditor.tsx, DiffEditor.tsx)
│ │ ├── layout/ # 布局组件(sidebar.tsx, header.tsx)
│ │ └── ui/ # Shadcn/ui 组件(21+ 个)
│ ├── layouts/ # 应用布局(AppLayout.tsx)
│ ├── locales/ # 国际化 JSON 文件(zh-CN.json, en-US.json)
│ ├── pages/ # 页面组件
│ │ ├── configurationManagement/ # 配置列表
│ │ ├── newconfig/ # 新建配置
│ │ ├── configdetail/ # 配置详情
│ │ ├── configeditor/ # 编辑配置
│ │ ├── historyRollback/ # 历史版本列表 + 差异对比
│ │ ├── historyDetail/ # 历史版本详情
│ │ ├── configRollback/ # 回滚确认
│ │ ├── listeningToQuery/ # 监听查询(按配置/按 IP)
│ │ ├── serviceManagement/ # 服务列表
│ │ ├── serviceDetail/ # 服务详情(集群卡片 + 实例表格)
│ │ ├── subscriberList/ # 订阅者列表
│ │ ├── login/ # 登录页
│ │ ├── register/ # 注册页
│ │ └── welcome/ # 欢迎/首页
│ ├── router/ # 路由与守卫
│ ├── stores/ # Zustand stores(auth, server, namespace, app, config, history, service)
│ └── types/ # TypeScript 类型定义
├── vite.config.ts # Vite 配置(含双端口代理)
├── tailwind.config.ts
└── package.json
export default 导出页面主组件useState,副作用用 useEffect,回调优化用 useCallbackglobals.css
oklch(0.55 0.18 240)oklch(0.95 0.01 230)oklch(0.6 0.22 20)--sidebar-background, --sidebar-primary 等--radius: 0.75rem(12px),衍生 -sm, -md, -lg, -xl<main p-6> 统一提供页面内边距,页面组件不再重复添加 paddingpy-0 紧凑样式,表格区域首尾列加 pl-6/pr-6grid grid-cols-1 md:grid-cols-2 等<div className="space-y-2"><Label /><Input /></div><span className="text-destructive ml-1">*</span>default(主操作)、outline(次要)、ghost(文字)、destructive(删除)flex flex-wrap items-end gap-4State 和 Actions 接口定义,合并为 Store = State & Actionsset() 更新状态,get() 读取当前状态loading/error 统一管理response as unknown as { code: number; data: T } 正确类型转换src/api/ 下,对象字面量风格:export const xxxApi = { list, get, create, ... }application/x-www-form-urlencoded(通过 qs 库)const { t } = useTranslation(),键名格式 domain.key(如 config.dataId)t() 翻译Plus, Search, MoreHorizontal, ChevronLeft 等)toast.error(), toast.success())Dialog 用于确认操作DropdownMenu 用于表格行操作菜单config-store.ts),组件文件用 PascalCase(MonacoEditor.tsx)@/ 指向 src/(如 @/components, @/stores, @/api)阶段 6(AI 注册中心)MCP 服务器管理与 Agent 管理进行中。
MCP 服务器列表、详情、编辑/创建页面已完成核心功能与视觉重设计。详情页包含 Hero Header、基本信息、端点、安全方案、工具列表(树形参数+模版)、HTTP 转换标识等完整展示。编辑页包含协议选择器(卡片式三色方案)、发布策略弹窗(点击发布按钮触发 Dialog 选择策略)、工具管理(按协议类型限制导入方式)、安全方案编辑等完整编辑功能。
Agent 管理已完成列表、详情、编辑/创建页面核心功能。列表卡片展示名称、版本、描述、能力标签、Skill 数量,支持 iconUrl 图片渲染(白色背景 + 加载失败回退)。编辑页发布逻辑已统一为与 MCP Server 一致的底部工具栏 + 三选项策略 Dialog 模式。TypeScript 类型已对齐后端 Java 模型(AgentBasicInfo 对应 AgentCardVersionInfo,AgentDetailInfo 对应 AgentCardDetailInfo)。
版本管理统一支持发布新版本、设为最新版本、更新当前版本三种语义清晰的操作。页面切换和命名空间切换已优化为无闪烁体验(store 缓存 + 按需 loading)。侧边栏收起态交互已重设计,用 Popover flyout 替代 Tooltip 实现可交互的子菜单面板。
bg-background/80 backdrop-blur-md 半透明模糊背景,导航链接居中排列,左侧命名空间选择器,右侧语言/主题/用户操作nacos-logo-dark.svg 完整 Logo,收缩状态显示蓝色无穷符号图标(nacos-icon.png)Popover 替换 Tooltip,hover 触发 flyout 面板(120ms 延迟关闭),面板包含分组标题 + Separator + 带图标的子菜单项列表,当前活跃项高亮,点击子项导航并自动关闭bg-primary 改为卡片风格(bg-popover + border + shadow),与 flyout 面板视觉统一console-ui 原始资源复制),与 Nacos 官网保持一致--input 颜色从 oklch(0.91 0.008 230) 调深至 oklch(0.82 0.012 230),保持 bg-transparent 背景shadow-sm 改为极轻阴影 shadow-[0_1px_2px_0_rgba(0,0,0,0.03)],border 改为 border-border/60;McpCard 悬停效果从 hover:shadow-md 降为 hover:shadow-sm,边框从 hover:border-primary/30 降为 hover:border-primary/20-mb-6,解决滚动到底时工具栏上移问题(main 元素的 p-6 底部 padding 将 sticky 元素推离视口底部)