fix(ui): hide useless docker manager on desktop, auto-start hermes dashboard, polish layout

Four independent UI fixes the user spotted in one screenshot tour:

services.js — desktop docker manager
  ClawPanel is not a docker management tool. The "Docker 多实例管理"
  block on the OpenClaw services page only makes sense for users who
  deployed ClawPanel itself in Web mode (serve.js / dev-api) and want
  to orchestrate multiple OpenClaw containers from one panel.

  On desktop Tauri this block always degrades to either "未启用" with
  a connect ENOENT error (no docker daemon on the user box) or to a
  generic "unavailable" placeholder — pure visual noise. Skip the
  whole config-section in render() and bail out of loadDockerManager()
  when isTauriRuntime() is true. Web mode keeps the feature.

profiles.js — Hermes Profile manager could not load
  Profile API only exists on the Hermes Dashboard process at 9119,
  which the user has to start by hand. When it is offline, the page
  showed a raw "由于目标计算机积极拒绝, 无法连接 (10061)" error which
  is useless: users do not know they need to start a separate process.

  load() now does the same probe → auto-start dance that
  extensions.js / dashboard.js use for their 9119 links: probe first,
  call hermesDashboardStart() if not running, only then issue the
  /api/profiles request. If the start itself fails, we fall through to
  the original catch and humanize-error renders a real reason.

lazy-deps.js — "[object Object]" on load failure
  humanizeError() returns { message, hint, raw, action? }, not a
  string. The catch branch passed the object straight into
  escapeHtml(), so String(obj) coerced to "[object Object]". Switch
  to humanizeErrorText() which is exactly the (message + hint)
  one-liner string variant.

layout.css — header buttons crammed against the description
  Several pages (hermes profiles / lazy-deps / files / gateways /
  group-chat / kanban / oauth) put their header buttons inside
  <div class="config-actions"> nested in <div class="page-header">,
  but the existing flex layout rule only matched .page-actions. The
  buttons therefore stacked directly under .page-desc with zero
  visible gap. Add .config-actions to both the desktop flex selector
  and the @media (max-width:768px) column-stack selector so all
  these pages get the same title-left / actions-right layout.

## Verification
- npm run build (no warnings beyond the existing chunk size note)
- Playwright on /services in browser mode: docker section present;
  same page after mocking window.__TAURI_INTERNALS__: section gone
- Playwright on /lazy-deps: rendered content does not contain the
  string "[object Object]"
- Playwright dynamic-imports profiles / lazy-deps / files render():
  computed style on .page-header is display:flex, flex-direction:row,
  title and button share the same getBoundingClientRect().top, button
  pushed to the right edge (justify-content:space-between effective)
This commit is contained in:
晴天
2026-05-16 13:46:24 +08:00
parent 7d75486a53
commit 4b0d8e5042
4 changed files with 23 additions and 6 deletions

View File

@@ -2,7 +2,7 @@
* 服务管理页面
* 服务启停 + 更新检测 + 配置备份管理
*/
import { api } from '../lib/tauri-api.js'
import { api, isTauriRuntime } from '../lib/tauri-api.js'
import { toast } from '../components/toast.js'
import { humanizeError } from '../lib/humanize-error.js'
import { showConfirm, showModal, showUpgradeModal } from '../components/modal.js'
@@ -34,11 +34,12 @@ export async function render() {
</div>
<div id="version-bar"><div class="stat-card loading-placeholder" style="height:80px;margin-bottom:var(--space-lg)"></div></div>
<div id="services-list"><div class="stat-card loading-placeholder" style="height:64px"></div></div>
${isTauriRuntime() ? '' : `
<div class="config-section" id="docker-manager-section">
<div class="config-section-title">${t('services.dockerManager')}</div>
<div class="form-hint" style="margin-bottom:var(--space-sm)">${t('services.dockerManagerHint')}</div>
<div id="docker-manager-bar"><div class="stat-card loading-placeholder" style="height:96px"></div></div>
</div>
</div>`}
<div class="config-section" id="config-editor-section" style="display:none">
<div class="config-section-title">${t('services.configEditor')}</div>
<div class="form-hint" style="margin-bottom:var(--space-sm)">${t('services.configEditorHint')}</div>
@@ -194,6 +195,9 @@ async function hasDockerManagerBackend() {
}
async function loadDockerManager(page) {
// Docker 多实例管理仅在 Web 部署模式serve.js / dev-api下有意义。
// 桌面 Tauri 用户不需要管理多个 OpenClaw 容器,整段 UI 已在 render() 里跳过渲染。
if (isTauriRuntime()) return
const bar = page.querySelector('#docker-manager-bar')
if (!bar) return
const backendReady = await hasDockerManagerBackend()