From 4b4f71a2ccf38f48fda009231a6c4daa13605689 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 18 May 2026 10:03:41 +0100 Subject: [PATCH] fix(ui): polish reasoning labels and settings margins --- CHANGELOG.md | 1 + .../OpenClaw/SystemRunSettingsView.swift | 1 - ui/src/ui/thinking-labels.ts | 31 +++++++++++++++++-- ui/src/ui/views/chat.test.ts | 22 ++++++------- ui/src/ui/views/sessions.test.ts | 12 +++---- 5 files changed, 46 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cc656bddf72..d07567673e50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -52,6 +52,7 @@ Docs: https://docs.openclaw.ai - Agents/Codex: fail closed when an explicitly requested Codex harness is not registered instead of silently trying configured model fallbacks. Fixes #83349. Thanks @r2-vibes. - QA-Lab: make runtime tool coverage fail on missing required tool exercise instead of treating pass/pass parity envelope drift as missing coverage. - Core/plugins: harden clawpatch-reported edge cases across gateway auth cleanup, Claude session id paths, plugin activation policy, apply-patch hunk handling, diagnostic redaction, and plugin metadata validation. +- UI: show reasoning choices as plain labels instead of leaking internal override wording in session and chat pickers. - Mac app: prefer explicit private/Tailscale/LAN Gateway endpoints over SSH tunnels, preserve legacy loopback tunnel configs, persist transport choices, and show captured SSH stderr when tunneling really fails. - Gateway/sessions: keep ACP/acpx and runtime child sessions visible in configured-only session lists when their owner or parent session belongs to a configured agent. - Mac app: keep app-level menu commands and Dashboard failure states reachable when the remote Gateway is disconnected, and keep the Settings sidebar toggle in the leading titlebar area. diff --git a/apps/macos/Sources/OpenClaw/SystemRunSettingsView.swift b/apps/macos/Sources/OpenClaw/SystemRunSettingsView.swift index 908d10298fc4..bc069b45c8f8 100644 --- a/apps/macos/Sources/OpenClaw/SystemRunSettingsView.swift +++ b/apps/macos/Sources/OpenClaw/SystemRunSettingsView.swift @@ -14,7 +14,6 @@ struct ExecApprovalsSettings: View { } .frame(maxWidth: .infinity, alignment: .leading) .padding(.vertical, 4) - .padding(.trailing, SettingsLayout.scrollbarGutter) } } } diff --git a/ui/src/ui/thinking-labels.ts b/ui/src/ui/thinking-labels.ts index ac141f9497bf..c4e9d58a796f 100644 --- a/ui/src/ui/thinking-labels.ts +++ b/ui/src/ui/thinking-labels.ts @@ -10,7 +10,7 @@ export function formatInheritedThinkingLabel(effectiveLevel: string | null | und if (!normalized || normalized === "off") { return "Off"; } - return `Inherited: ${normalized}`; + return `Inherited: ${formatThinkingLevelDisplayLabel(normalized)}`; } export function formatThinkingOverrideLabel(value: string, label?: string | null): string { @@ -18,6 +18,31 @@ export function formatThinkingOverrideLabel(value: string, label?: string | null if (!normalized || normalized === "off") { return "Off"; } - const displayLabel = label?.trim() || normalized; - return `Override: ${displayLabel}`; + return formatThinkingLevelDisplayLabel(label?.trim() || normalized); +} + +function formatThinkingLevelDisplayLabel(value: string): string { + const raw = normalizeLowercaseStringOrEmpty(value); + if (["on", "enable", "enabled"].includes(raw)) { + return "On"; + } + const normalized = normalizeThinkingOptionValue(value); + switch (normalized) { + case "adaptive": + return "Adaptive"; + case "minimal": + return "Minimal"; + case "low": + return "Low"; + case "medium": + return "Medium"; + case "high": + return "High"; + case "xhigh": + return "Extra high"; + case "max": + return "Maximum"; + default: + return value.charAt(0).toUpperCase() + value.slice(1); + } } diff --git a/ui/src/ui/views/chat.test.ts b/ui/src/ui/views/chat.test.ts index 63eae1e35ff6..5b78b9f1dd48 100644 --- a/ui/src/ui/views/chat.test.ts +++ b/ui/src/ui/views/chat.test.ts @@ -1339,7 +1339,7 @@ describe("chat session controls", () => { ]); expect( [...(thinkingSelect?.options ?? [])].map((option) => option.textContent?.trim()), - ).toEqual(["Off", "Off", "Override: adaptive", "Override: xhigh", "Override: maximum"]); + ).toEqual(["Off", "Off", "Adaptive", "Extra high", "Maximum"]); }); it("labels chat thinking default from the active session row", () => { @@ -1356,8 +1356,8 @@ describe("chat session controls", () => { ); expect(thinkingSelect?.value).toBe(""); - expect(thinkingSelect?.options[0]?.textContent?.trim()).toBe("Inherited: adaptive"); - expect(thinkingSelect?.title).toBe("Inherited: adaptive"); + expect(thinkingSelect?.options[0]?.textContent?.trim()).toBe("Inherited: Adaptive"); + expect(thinkingSelect?.title).toBe("Inherited: Adaptive"); }); it("always renders full thinking labels", () => { @@ -1387,14 +1387,14 @@ describe("chat session controls", () => { expect(container.querySelector('select[data-chat-thinking-select-compact="true"]')).toBeNull(); expect(thinkingSelect?.value).toBe(""); - expect(thinkingSelect?.title).toBe("Inherited: high"); + expect(thinkingSelect?.title).toBe("Inherited: High"); expect([...thinkingSelect!.options].map((option) => option.textContent?.trim())).toEqual([ - "Inherited: high", + "Inherited: High", "Off", - "Override: low", - "Override: medium", - "Override: high", - "Override: xhigh", + "Low", + "Medium", + "High", + "Extra high", ]); }); @@ -1411,7 +1411,7 @@ describe("chat session controls", () => { ); expect(thinkingSelect?.value).toBe(""); - expect(thinkingSelect?.options[0]?.textContent?.trim()).toBe("Inherited: adaptive"); - expect(thinkingSelect?.title).toBe("Inherited: adaptive"); + expect(thinkingSelect?.options[0]?.textContent?.trim()).toBe("Inherited: Adaptive"); + expect(thinkingSelect?.title).toBe("Inherited: Adaptive"); }); }); diff --git a/ui/src/ui/views/sessions.test.ts b/ui/src/ui/views/sessions.test.ts index b4bf2d4d27d0..a91645a1f135 100644 --- a/ui/src/ui/views/sessions.test.ts +++ b/ui/src/ui/views/sessions.test.ts @@ -272,7 +272,7 @@ describe("sessions view", () => { Array.from(thinking?.options ?? []) .find((option) => option.value === "max") ?.textContent?.trim(), - ).toBe("Override: maximum"); + ).toBe("Maximum"); thinking!.value = "max"; thinking!.dispatchEvent(new Event("change", { bubbles: true })); @@ -303,12 +303,12 @@ describe("sessions view", () => { const thinking = container.querySelector("tbody select") as HTMLSelectElement | null; expect(thinking?.value).toBe(""); - expect(thinking?.options[0]?.textContent?.trim()).toBe("Inherited: adaptive"); + expect(thinking?.options[0]?.textContent?.trim()).toBe("Inherited: Adaptive"); expect( Array.from(thinking?.options ?? []) .find((option) => option.value === "adaptive") ?.textContent?.trim(), - ).toBe("Override: adaptive"); + ).toBe("Adaptive"); }); it("labels inherited thinking from list defaults when lightweight rows omit row defaults", async () => { @@ -340,9 +340,9 @@ describe("sessions view", () => { const thinking = container.querySelector("tbody select") as HTMLSelectElement | null; expect(thinking?.value).toBe(""); - expect(thinking?.options[0]?.textContent?.trim()).toBe("Inherited: high"); + expect(thinking?.options[0]?.textContent?.trim()).toBe("Inherited: High"); expect(Array.from(thinking?.options ?? []).map((option) => option.textContent?.trim())).toEqual( - ["Inherited: high", "Off", "Override: high"], + ["Inherited: High", "Off", "High"], ); }); @@ -372,7 +372,7 @@ describe("sessions view", () => { Array.from(thinking?.options ?? []) .find((option) => option.value === "low") ?.textContent?.trim(), - ).toBe("Override: on"); + ).toBe("On"); thinking!.value = "low"; thinking!.dispatchEvent(new Event("change", { bubbles: true }));