From 2cb3f4ee88f40834678b7abf2c5b2c065876024a Mon Sep 17 00:00:00 2001 From: Haitao Pan Date: Sun, 15 Mar 2026 12:01:22 +0800 Subject: [PATCH] Align xworkmate web shell with desktop UI --- .../xworkmate/XWorkmateWorkspacePage.tsx | 2404 +++++------------ 1 file changed, 618 insertions(+), 1786 deletions(-) diff --git a/src/components/xworkmate/XWorkmateWorkspacePage.tsx b/src/components/xworkmate/XWorkmateWorkspacePage.tsx index 91ee6c9..1c758a6 100644 --- a/src/components/xworkmate/XWorkmateWorkspacePage.tsx +++ b/src/components/xworkmate/XWorkmateWorkspacePage.tsx @@ -1,108 +1,76 @@ "use client"; -import { useMemo, useState, type ReactNode } from "react"; -import Link from "next/link"; +import { useEffect, useMemo, useState } from "react"; import type { LucideIcon } from "lucide-react"; import { - ArrowRight, - Blocks, Bot, Briefcase, - ChevronLeft, ChevronRight, - ChevronsLeftRight, + ChevronsRight, Cloud, + Cpu, + Grip, KeyRound, - LayoutDashboard, - MoonStar, - PanelLeftClose, - PanelLeftOpen, - ShieldCheck, + ListTodo, + Puzzle, + RefreshCw, + Settings2, + Shield, Sparkles, - SunMedium, UserCircle2, - Vault, - Waypoints, - Workflow, + X, } from "lucide-react"; -import LanguageToggle from "@/components/LanguageToggle"; -import { OpenClawAssistantPane } from "@/components/openclaw/OpenClawAssistantPane"; -import { useTheme } from "@/components/theme"; import { useLanguage } from "@/i18n/LanguageProvider"; import type { IntegrationDefaults } from "@/lib/openclaw/types"; -import { useUserStore } from "@/lib/userStore"; import { cn } from "@/lib/utils"; -import Card from "@/modules/extensions/builtin/user-center/components/Card"; import { IntegrationsConsole } from "@/modules/extensions/builtin/user-center/components/IntegrationsConsole"; import { useOpenClawConsoleStore } from "@/state/openclawConsoleStore"; type WorkspaceDestination = | "assistant" | "tasks" - | "modules" + | "skills" + | "nodes" + | "agents" + | "mcpServer" + | "clawHub" | "secrets" + | "aiGateway" | "settings" | "account"; -type SidebarState = "expanded" | "collapsed" | "hidden"; -interface SectionTab { +type SectionTab = { key: string; label: string; -} +}; -interface SectionDefinition { +type SectionCard = { + title: string; + description: string; + meta: string; +}; + +type SectionDefinition = { key: WorkspaceDestination; label: string; - shortLabel: string; description: string; icon: LucideIcon; tabs: SectionTab[]; -} + cards?: SectionCard[]; +}; -interface SidebarSectionButtonProps { - section: SectionDefinition; - active: boolean; - collapsed: boolean; - onClick: () => void; -} - -interface UtilityButtonProps { +type SidebarButtonProps = { + icon: LucideIcon; label: string; - icon: LucideIcon; - collapsed: boolean; - active?: boolean; + active: boolean; onClick: () => void; -} +}; -interface SurfaceCardProps { - icon: LucideIcon; +type DetailCardProps = { title: string; description: string; - body?: string; - action?: ReactNode; -} - -interface StatusRowProps { - label: string; - value: string; - ok?: boolean; -} - -interface OverviewMetric { - label: string; - value: string; - caption: string; - icon: LucideIcon; -} - -const INITIAL_TABS: Record = { - assistant: "workspace", - tasks: "queue", - modules: "gateway", - secrets: "vault", - settings: "integrations", - account: "profile", + meta: string; }; function pickCopy(isChinese: boolean, zh: string, en: string): string { @@ -127,24 +95,26 @@ function createSections(isChinese: boolean): SectionDefinition[] { return [ { key: "assistant", - label: pickCopy(isChinese, "助手", "Assistant"), - shortLabel: pickCopy(isChinese, "助手", "AI"), + label: pickCopy(isChinese, "主页", "Home"), description: pickCopy( isChinese, - "在线版 XWorkmate 主页,承接对话、截图与执行入口。", - "The online XWorkmate home for chat, screenshots, and execution.", + "在线版 XWorkmate 首页,保持与桌面端一致的主工作区壳层。", + "Online XWorkmate home with the same shell as the desktop workspace.", ), - icon: Sparkles, - tabs: [], + icon: ListTodo, + tabs: [ + { key: "queued", label: pickCopy(isChinese, "排队中", "Queued") }, + { key: "main", label: "Main" }, + { key: "assistant", label: "Assistant" }, + ], }, { key: "tasks", label: pickCopy(isChinese, "任务", "Tasks"), - shortLabel: pickCopy(isChinese, "任务", "Tasks"), description: pickCopy( isChinese, - "查看队列、运行态和历史会话,保持与桌面端一致的任务视角。", - "Queue, running work, and history in the same structure as desktop.", + "与桌面版同步的队列、运行态、历史和计划任务视图。", + "Queue, running, history, and scheduled views aligned with desktop.", ), icon: Briefcase, tabs: [ @@ -152,88 +122,260 @@ function createSections(isChinese: boolean): SectionDefinition[] { { key: "running", label: pickCopy(isChinese, "运行中", "Running") }, { key: "history", label: pickCopy(isChinese, "历史", "History") }, { key: "failed", label: pickCopy(isChinese, "失败", "Failed") }, - { key: "scheduled", label: pickCopy(isChinese, "定时", "Scheduled") }, + { key: "scheduled", label: pickCopy(isChinese, "计划中", "Scheduled") }, + ], + cards: [ + { + title: pickCopy(isChinese, "任务队列", "Task Queue"), + description: pickCopy( + isChinese, + "当前在线版优先承接桌面端的默认任务壳层,后续继续接运行态与历史列表。", + "The web version currently prioritizes the default task shell before live and history lists.", + ), + meta: pickCopy(isChinese, "对齐桌面端 tabs", "Desktop-aligned tabs"), + }, + { + title: pickCopy(isChinese, "计划任务", "Scheduled Jobs"), + description: pickCopy( + isChinese, + "预留 Gateway cron 只读展示区,与桌面端 Scheduled 页签一致。", + "Reserved for the Gateway cron read-only surface used in desktop Scheduled.", + ), + meta: "Gateway cron", + }, + { + title: pickCopy(isChinese, "默认任务联动", "Default Task Flow"), + description: pickCopy( + isChinese, + "当前会话可直接作为默认任务启动入口,保持最近桌面版的工作流习惯。", + "The current conversation remains the default task launch point, matching the latest desktop flow.", + ), + meta: pickCopy(isChinese, "当前会话即任务", "Session-first"), + }, ], }, { - key: "modules", - label: pickCopy(isChinese, "模块", "Modules"), - shortLabel: pickCopy(isChinese, "模块", "Mods"), + key: "skills", + label: pickCopy(isChinese, "技能", "Skills"), description: pickCopy( isChinese, - "围绕网关、节点、代理和连接器组织在线工作区能力。", - "Gateway, nodes, agents, skills, and connectors for the online workspace.", + "管理技能包、能力扩展和 ClawHub 安装入口。", + "Manage skill packages, extensions, and ClawHub installs.", ), - icon: Blocks, + icon: Sparkles, tabs: [ - { key: "gateway", label: pickCopy(isChinese, "Gateway", "Gateway") }, - { key: "nodes", label: pickCopy(isChinese, "节点", "Nodes") }, - { key: "agents", label: pickCopy(isChinese, "代理", "Agents") }, - { key: "skills", label: pickCopy(isChinese, "技能", "Skills") }, + { key: "installed", label: pickCopy(isChinese, "已安装", "Installed") }, + { key: "recommended", label: pickCopy(isChinese, "推荐", "Recommended") }, { key: "clawhub", label: "ClawHub" }, + ], + cards: [ { - key: "connectors", - label: pickCopy(isChinese, "连接器", "Connectors"), + title: "ClawHub", + description: pickCopy( + isChinese, + "在线版入口保留技能市场入口,结构与桌面端最近版本一致。", + "The online workspace keeps the skill market entry aligned with the latest desktop structure.", + ), + meta: pickCopy(isChinese, "技能市场", "Marketplace"), + }, + { + title: pickCopy(isChinese, "技能包", "Skill Packs"), + description: pickCopy( + isChinese, + "围绕安装、启用和会话内能力扩展组织,而不是散落到多个页面。", + "Organized around install, enablement, and session capability expansion instead of scattered pages.", + ), + meta: pickCopy(isChinese, "结构对齐", "Structure aligned"), + }, + ], + }, + { + key: "nodes", + label: pickCopy(isChinese, "节点", "Nodes"), + description: pickCopy( + isChinese, + "管理边缘节点、实例和运行状态。", + "Manage edge nodes, instances, and runtime status.", + ), + icon: Grip, + tabs: [ + { key: "instances", label: pickCopy(isChinese, "实例", "Instances") }, + { key: "capacity", label: pickCopy(isChinese, "容量", "Capacity") }, + ], + cards: [ + { + title: pickCopy(isChinese, "边缘节点", "Edge Nodes"), + description: pickCopy( + isChinese, + "桌面版最近更新把节点作为独立工作区保留,在线版首页先同步信息架构。", + "Recent desktop updates kept nodes as a dedicated workspace, and the web shell now mirrors that IA.", + ), + meta: pickCopy(isChinese, "工作区", "Workspace"), + }, + ], + }, + { + key: "agents", + label: pickCopy(isChinese, "代理", "Agents"), + description: pickCopy( + isChinese, + "管理代理实例、行为配置和活跃代理。", + "Manage agent instances, behavior configuration, and the active agent.", + ), + icon: Bot, + tabs: [ + { key: "overview", label: pickCopy(isChinese, "概览", "Overview") }, + { key: "routing", label: pickCopy(isChinese, "路由", "Routing") }, + ], + cards: [ + { + title: pickCopy(isChinese, "代理路由", "Agent Routing"), + description: pickCopy( + isChinese, + "保留 coding / research / browser 的任务导向切换心智,与桌面端最近工作流一致。", + "Preserves the coding / research / browser task routing model used by the latest desktop workflow.", + ), + meta: pickCopy(isChinese, "任务分流", "Task routing"), + }, + ], + }, + { + key: "mcpServer", + label: "MCP Hub", + description: pickCopy( + isChinese, + "管理 MCP 连接与工具配置。", + "Manage MCP connections and tool configuration.", + ), + icon: Cpu, + tabs: [ + { key: "servers", label: pickCopy(isChinese, "服务", "Servers") }, + { key: "tools", label: pickCopy(isChinese, "工具", "Tools") }, + ], + cards: [ + { + title: "MCP Hub", + description: pickCopy( + isChinese, + "最近桌面版已将 MCP Server 提升为一级工具分组,在线版同步这一层级。", + "Recent desktop builds promoted MCP Server into a first-class tools group, now mirrored online.", + ), + meta: pickCopy(isChinese, "一级工具", "Primary tool"), + }, + ], + }, + { + key: "clawHub", + label: "ClawHub", + description: pickCopy( + isChinese, + "浏览并安装技能包、代理模板和连接器。", + "Browse and install skills, agent templates, and connectors.", + ), + icon: Puzzle, + tabs: [ + { key: "skills", label: pickCopy(isChinese, "技能", "Skills") }, + { key: "templates", label: pickCopy(isChinese, "模板", "Templates") }, + { key: "connectors", label: pickCopy(isChinese, "连接器", "Connectors") }, + ], + cards: [ + { + title: pickCopy(isChinese, "模板与连接器", "Templates and Connectors"), + description: pickCopy( + isChinese, + "ClawHub 不再只是技能列表,而是统一承接扩展分发。", + "ClawHub is no longer only a skill list; it now acts as the extension distribution surface.", + ), + meta: pickCopy(isChinese, "扩展分发", "Extension distribution"), }, ], }, { key: "secrets", label: pickCopy(isChinese, "密钥", "Secrets"), - shortLabel: pickCopy(isChinese, "密钥", "Keys"), description: pickCopy( isChinese, - "统一管理 Vault、本地会话覆盖和模型接入凭证。", - "Manage Vault, session overrides, and provider credentials.", + "围绕 Vault、提供方和审计组织凭证管理。", + "Credential management around Vault, providers, and audit.", ), icon: KeyRound, tabs: [ { key: "vault", label: "Vault" }, - { - key: "local-store", - label: pickCopy(isChinese, "本地存储", "Local Store"), - }, { key: "providers", label: pickCopy(isChinese, "提供方", "Providers") }, { key: "audit", label: pickCopy(isChinese, "审计", "Audit") }, ], + cards: [ + { + title: "Vault", + description: pickCopy( + isChinese, + "保持桌面端最近的 Vault-first 设计,在线版继续只暴露引用而不展示明文。", + "Keeps the recent desktop Vault-first design and only exposes references, never raw values.", + ), + meta: pickCopy(isChinese, "安全引用", "Secure refs"), + }, + ], + }, + { + key: "aiGateway", + label: "AI Gateway", + description: pickCopy( + isChinese, + "管理代理、模型与网关配置。", + "Manage agents, models, and gateway configuration.", + ), + icon: Cloud, + tabs: [ + { key: "models", label: pickCopy(isChinese, "模型", "Models") }, + { key: "agents", label: pickCopy(isChinese, "代理", "Agents") }, + { key: "routes", label: pickCopy(isChinese, "路由", "Routes") }, + ], + cards: [ + { + title: pickCopy(isChinese, "模型与代理", "Models and Agents"), + description: pickCopy( + isChinese, + "桌面版最近把 AI Gateway 独立成完整页面,在线版首页同步该模块入口。", + "Recent desktop updates gave AI Gateway its own full page, and the online shell now mirrors that entry.", + ), + meta: pickCopy(isChinese, "独立模块", "Dedicated module"), + }, + ], }, { key: "settings", label: pickCopy(isChinese, "设置", "Settings"), - shortLabel: pickCopy(isChinese, "设置", "Prefs"), description: pickCopy( isChinese, - "把接口集成、外观和诊断入口收敛到一个在线设置中心。", - "Bring integrations, appearance, and diagnostics into one settings hub.", + "统一管理工作区、集成、外观和诊断。", + "Centralize workspace, integrations, appearance, and diagnostics.", ), - icon: LayoutDashboard, + icon: Settings2, tabs: [ { key: "general", label: pickCopy(isChinese, "通用", "General") }, { key: "workspace", label: pickCopy(isChinese, "工作区", "Workspace") }, + { key: "gateway", label: pickCopy(isChinese, "集成", "Integrations") }, + { key: "diagnostics", label: pickCopy(isChinese, "诊断", "Diagnostics") }, + ], + cards: [ { - key: "integrations", - label: pickCopy(isChinese, "集成", "Integrations"), + title: pickCopy(isChinese, "集成默认项", "Integration Defaults"), + description: pickCopy( + isChinese, + "继续复用当前在线版的集成配置 store 和探测逻辑,不改 API 合约。", + "Continues to reuse the existing web integration store and probe flow without changing the API contract.", + ), + meta: pickCopy(isChinese, "复用现有能力", "Reused capability"), }, - { key: "appearance", label: pickCopy(isChinese, "外观", "Appearance") }, - { - key: "diagnostics", - label: pickCopy(isChinese, "诊断", "Diagnostics"), - }, - { - key: "experimental", - label: pickCopy(isChinese, "实验性", "Experimental"), - }, - { key: "about", label: pickCopy(isChinese, "关于", "About") }, ], }, { key: "account", label: pickCopy(isChinese, "账号", "Account"), - shortLabel: pickCopy(isChinese, "账号", "Me"), description: pickCopy( isChinese, - "查看当前身份、工作区和会话信息。", - "Profile, workspace, and current session information.", + "身份、工作区和当前会话信息。", + "Identity, workspace, and current session information.", ), icon: UserCircle2, tabs: [ @@ -241,165 +383,268 @@ function createSections(isChinese: boolean): SectionDefinition[] { { key: "workspace", label: pickCopy(isChinese, "工作区", "Workspace") }, { key: "sessions", label: pickCopy(isChinese, "会话", "Sessions") }, ], + cards: [ + { + title: pickCopy(isChinese, "工作区身份", "Workspace Identity"), + description: pickCopy( + isChinese, + "对齐桌面端最近的身份与工作区拆分,避免把账号信息混到业务页面。", + "Aligns with the desktop split between identity and workspace instead of mixing account details into business pages.", + ), + meta: pickCopy(isChinese, "身份上下文", "Identity context"), + }, + ], }, ]; } -function SidebarSectionButton({ - section, +function SidebarButton({ + icon: Icon, + label, active, - collapsed, onClick, -}: SidebarSectionButtonProps) { - const Icon = section.icon; - +}: SidebarButtonProps) { return ( ); } -function UtilityButton({ +function DesktopChip({ label, - icon: Icon, - collapsed, active = false, - onClick, -}: UtilityButtonProps) { +}: { + label: string; + active?: boolean; +}) { + return ( +
+ {label} +
+ ); +} + +function ToolbarChip({ + label, + active = false, +}: { + label: string; + active?: boolean; +}) { return ( ); } -function SurfaceCard({ - icon: Icon, - title, - description, - body, - action, -}: SurfaceCardProps) { +function DetailCard({ title, description, meta }: DetailCardProps) { return ( - -
-
- -
-
-

- {title} -

-

- {description} -

-
+
+
+ {meta}
- {body ? ( -

{body}

- ) : null} - {action ?
{action}
: null} - - ); -} - -function StatusRow({ label, value, ok }: StatusRowProps) { - return ( -
-
-

{label}

-

{value}

-
- - - {ok ? "ready" : "pending"} - +

+ {title} +

+

+ {description} +

); } -function OverviewMetrics({ items }: { items: OverviewMetric[] }) { +function AssistantHome({ + isChinese, + tabs, + endpointLabel, + connected, + prompt, + onPromptChange, + onOpenConnections, +}: { + isChinese: boolean; + tabs: SectionTab[]; + endpointLabel: string; + connected: boolean; + prompt: string; + onPromptChange: (value: string) => void; + onOpenConnections: () => void; +}) { return ( -
- {items.map((item) => { - const Icon = item.icon; - - return ( - -
-
- -
-
-

- {item.label} -

-

- {item.value} -

-
+ <> +
+
+
+
+ + +
-

- {item.caption} +

+ {pickCopy(isChinese, "默认任务", "Default Task")} +

+

+ {pickCopy( + isChinese, + "连接 Gateway 后,当前对话会自动作为默认任务开始执行。", + "After connecting the gateway, the current conversation starts as the default task.", + )}

- - ); - })} -
+
+ {tabs.map((tab, index) => ( + + ))} +
+
+
+ {connected + ? `${pickCopy(isChinese, "在线", "Online")} · ${endpointLabel}` + : pickCopy(isChinese, "离线 · 未连接目标", "Offline · No target")} +
+
+
+ +
+
+
+

+ {pickCopy(isChinese, "先连接 Gateway", "Connect Gateway First")} +

+

+ {pickCopy( + isChinese, + "连接后可直接对话、创建任务,并在当前会话查看结果。", + "Connect first to start chatting, create tasks, and view results in the current conversation.", + )} +

+
+ + +
+
+
+
+ +
+