From 905ce02b0b50c15861132297737d20be990a1d84 Mon Sep 17 00:00:00 2001 From: DigHuang <114602213+DigHuang@users.noreply.github.com> Date: Tue, 10 Mar 2026 11:39:56 +0800 Subject: [PATCH] feat(ui): refactor style ui & add Models page with provider settings (#379) --- .npmrc | 1 + electron/utils/openclaw-auth.ts | 40 + package.json | 4 +- src/App.tsx | 2 + src/assets/channels/dingtalk.svg | 4 + src/assets/channels/discord.svg | 3 + src/assets/channels/feishu.svg | 6 + src/assets/channels/telegram.svg | 3 + src/assets/channels/whatsapp.svg | 3 + src/components/layout/Sidebar.tsx | 233 ++-- src/components/settings/ProvidersSettings.tsx | 964 ++++++------- src/components/ui/sheet.tsx | 136 ++ src/pages/Channels/index.tsx | 477 +++---- src/pages/Chat/ChatInput.tsx | 39 +- src/pages/Chat/index.tsx | 47 +- src/pages/Cron/index.tsx | 481 +++---- src/pages/Dashboard/index.tsx | 372 ----- src/pages/Models/index.tsx | 441 ++++++ src/pages/Settings/index.tsx | 20 +- src/pages/Skills/index.tsx | 1193 +++++++---------- src/styles/globals.css | 12 +- 21 files changed, 2277 insertions(+), 2204 deletions(-) create mode 100644 .npmrc create mode 100644 src/assets/channels/dingtalk.svg create mode 100644 src/assets/channels/discord.svg create mode 100644 src/assets/channels/feishu.svg create mode 100644 src/assets/channels/telegram.svg create mode 100644 src/assets/channels/whatsapp.svg create mode 100644 src/components/ui/sheet.tsx create mode 100644 src/pages/Models/index.tsx diff --git a/.npmrc b/.npmrc new file mode 100644 index 000000000..a079e262c --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +package-import-method=copy diff --git a/electron/utils/openclaw-auth.ts b/electron/utils/openclaw-auth.ts index a296e44c3..a28ce6e02 100644 --- a/electron/utils/openclaw-auth.ts +++ b/electron/utils/openclaw-auth.ts @@ -882,6 +882,46 @@ export async function sanitizeOpenClawConfig(): Promise { } } + // ── plugins section ────────────────────────────────────────────── + // Remove absolute paths in plugins that no longer exist or are bundled (preventing hardlink validation errors) + const plugins = config.plugins; + if (plugins) { + if (Array.isArray(plugins)) { + const validPlugins: unknown[] = []; + for (const p of plugins) { + if (typeof p === 'string' && p.startsWith('/')) { + if (p.includes('node_modules/openclaw/extensions') || !(await fileExists(p))) { + console.log(`[sanitize] Removing stale/bundled plugin path "${p}" from openclaw.json`); + modified = true; + } else { + validPlugins.push(p); + } + } else { + validPlugins.push(p); + } + } + if (modified) config.plugins = validPlugins; + } else if (typeof plugins === 'object') { + const pluginsObj = plugins as Record; + if (Array.isArray(pluginsObj.load)) { + const validLoad: unknown[] = []; + for (const p of pluginsObj.load) { + if (typeof p === 'string' && p.startsWith('/')) { + if (p.includes('node_modules/openclaw/extensions') || !(await fileExists(p))) { + console.log(`[sanitize] Removing stale/bundled plugin path "${p}" from openclaw.json`); + modified = true; + } else { + validLoad.push(p); + } + } else { + validLoad.push(p); + } + } + if (modified) pluginsObj.load = validLoad; + } + } + } + // ── commands section ─────────────────────────────────────────── // Required for SIGUSR1 in-process reload authorization. const commands = ( diff --git a/package.json b/package.json index b2fd0d9e3..87dc1d64c 100644 --- a/package.json +++ b/package.json @@ -106,5 +106,5 @@ "zustand": "^5.0.11", "zx": "^8.8.5" }, - "packageManager": "pnpm@10.29.2+sha512.bef43fa759d91fd2da4b319a5a0d13ef7a45bb985a3d7342058470f9d2051a3ba8674e629672654686ef9443ad13a82da2beb9eeb3e0221c87b8154fff9d74b8" -} \ No newline at end of file + "packageManager": "pnpm@10.31.0+sha512.e3927388bfaa8078ceb79b748ffc1e8274e84d75163e67bc22e06c0d3aed43dd153151cbf11d7f8301ff4acb98c68bdc5cadf6989532801ffafe3b3e4a63c268" +} diff --git a/src/App.tsx b/src/App.tsx index 63ac0783b..39b37219a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -10,6 +10,7 @@ import i18n from './i18n'; import { MainLayout } from './components/layout/MainLayout'; import { TooltipProvider } from '@/components/ui/tooltip'; import { Dashboard } from './pages/Dashboard'; +import { Models } from './pages/Models'; import { Chat } from './pages/Chat'; import { Channels } from './pages/Channels'; import { Skills } from './pages/Skills'; @@ -164,6 +165,7 @@ function App() { {/* Main application routes */} }> } /> + } /> } /> } /> } /> diff --git a/src/assets/channels/dingtalk.svg b/src/assets/channels/dingtalk.svg new file mode 100644 index 000000000..08728b244 --- /dev/null +++ b/src/assets/channels/dingtalk.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/assets/channels/discord.svg b/src/assets/channels/discord.svg new file mode 100644 index 000000000..1e407ef8f --- /dev/null +++ b/src/assets/channels/discord.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/assets/channels/feishu.svg b/src/assets/channels/feishu.svg new file mode 100644 index 000000000..f12ece1ca --- /dev/null +++ b/src/assets/channels/feishu.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/assets/channels/telegram.svg b/src/assets/channels/telegram.svg new file mode 100644 index 000000000..6d9a85e70 --- /dev/null +++ b/src/assets/channels/telegram.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/assets/channels/whatsapp.svg b/src/assets/channels/whatsapp.svg new file mode 100644 index 000000000..5e26cb30d --- /dev/null +++ b/src/assets/channels/whatsapp.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/components/layout/Sidebar.tsx b/src/components/layout/Sidebar.tsx index 87940f72f..a8f29b2c0 100644 --- a/src/components/layout/Sidebar.tsx +++ b/src/components/layout/Sidebar.tsx @@ -6,17 +6,18 @@ import { useEffect, useState } from 'react'; import { NavLink, useLocation, useNavigate } from 'react-router-dom'; import { - Home, - MessageSquare, - Radio, + Network, Puzzle, Clock, - Settings, - ChevronLeft, - ChevronRight, + Settings as SettingsIcon, + PanelLeftClose, + PanelLeft, + Plus, Terminal, ExternalLink, Trash2, + Cpu, + LayoutDashboard, } from 'lucide-react'; import { cn } from '@/lib/utils'; import { useSettingsStore } from '@/stores/settings'; @@ -26,6 +27,7 @@ import { Badge } from '@/components/ui/badge'; import { ConfirmDialog } from '@/components/ui/confirm-dialog'; import { hostApiFetch } from '@/lib/host-api'; import { useTranslation } from 'react-i18next'; +import logoSvg from '@/assets/logo.svg'; type SessionBucketKey = | 'today' @@ -51,23 +53,29 @@ function NavItem({ to, icon, label, badge, collapsed, onClick }: NavItemProps) { onClick={onClick} className={({ isActive }) => cn( - 'flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium transition-colors', - 'hover:bg-accent hover:text-accent-foreground', + 'flex items-center gap-2.5 rounded-lg px-2.5 py-2 text-[14px] font-medium transition-colors', + 'hover:bg-black/5 dark:hover:bg-white/5 text-foreground/80', isActive - ? 'bg-accent text-accent-foreground' - : 'text-muted-foreground', - collapsed && 'justify-center px-2' + ? 'bg-black/5 dark:bg-white/10 text-foreground' + : '', + collapsed && 'justify-center px-0' ) } > - {icon} - {!collapsed && ( + {({ isActive }) => ( <> - {label} - {badge && ( - - {badge} - +
+ {icon} +
+ {!collapsed && ( + <> + {label} + {badge && ( + + {badge} + + )} + )} )} @@ -161,23 +169,46 @@ export function Sidebar() { } const navItems = [ - { to: '/cron', icon: , label: t('sidebar.cronTasks') }, - { to: '/skills', icon: , label: t('sidebar.skills') }, - { to: '/channels', icon: , label: t('sidebar.channels') }, - { to: '/dashboard', icon: , label: t('sidebar.dashboard') }, - { to: '/settings', icon: , label: t('sidebar.settings') }, + { to: '/models', icon: , label: t('sidebar.models', 'Models') }, + { to: '/channels', icon: , label: t('sidebar.channels') }, + { to: '/skills', icon: , label: t('sidebar.skills') }, + { to: '/cron', icon: , label: t('sidebar.cronTasks') }, + { to: '/dashboard', icon: , label: t('sidebar.dashboard') }, ]; return (