From ee603dee1a4309c03c15769461203794fc86c156 Mon Sep 17 00:00:00 2001 From: Yuhan Lei Date: Sat, 2 May 2026 23:40:06 +0800 Subject: [PATCH 1/3] fix(app): simplify titlebar worktree badge --- .../layout/pawwork-worktree-badge.test.tsx | 56 ++++++++++++++--- .../pages/layout/pawwork-worktree-badge.tsx | 61 ++++++++++++++----- 2 files changed, 94 insertions(+), 23 deletions(-) diff --git a/packages/app/src/pages/layout/pawwork-worktree-badge.test.tsx b/packages/app/src/pages/layout/pawwork-worktree-badge.test.tsx index 93ccc9a62..14150a159 100644 --- a/packages/app/src/pages/layout/pawwork-worktree-badge.test.tsx +++ b/packages/app/src/pages/layout/pawwork-worktree-badge.test.tsx @@ -17,6 +17,14 @@ beforeAll(async () => { mock.module("@opencode-ai/ui/icon", () => ({ Icon: (props: any) => ({ type: "Icon", props: props ?? {}, children: [] }) as Node, })) + mock.module("@opencode-ai/ui/tooltip", () => ({ + Tooltip: (props: any) => + ({ + type: "Tooltip", + props: props ?? {}, + children: Array.isArray(props?.children) ? props.children : [props?.children].filter(Boolean), + }) as Node, + })) PawworkWorktreeBadge = (await import("./pawwork-worktree-badge")).PawworkWorktreeBadge }) @@ -55,7 +63,7 @@ function find(node: Node | string, predicate: (n: Node) => boolean): Node | unde } describe("PawworkWorktreeBadge", () => { - test("shows worktree name and branch in the visible titlebar label", () => { + test("shows only the worktree name in the visible titlebar label", () => { const onClick = () => undefined const tree = PawworkWorktreeBadge({ name: "feature-c", @@ -66,11 +74,45 @@ describe("PawworkWorktreeBadge", () => { disabled: true, }) as unknown as Node - const label = find(tree, (node) => node.type === "span") - expect(label?.children.join("")).toBe("feature-c (pawwork/feature-c)") - expect(tree.props.title).toBe("pawwork/feature-c · /repo/.worktrees/pawwork/feature-c") - expect(tree.props.onClick).toBe(onClick) - expect(tree.props["aria-label"]).toBe("Open worktrees") - expect(tree.props.disabled).toBe(true) + const button = find(tree, (node) => node.type === "button") + const label = find(tree, (node) => node.type === "span" && node.children.join("") === "feature-c") + expect(label?.children.join("")).toBe("feature-c") + expect(button?.props.title).toBeUndefined() + expect(button?.props.onClick).toBe(onClick) + expect(button?.props["aria-label"]).toBe("Open worktrees") + expect(button?.props.disabled).toBe(true) + }) + + test("keeps visible label compact and shows three ordered hover rows", () => { + const tree = PawworkWorktreeBadge({ + name: "very-long-worktree-name-used-for-titlebar-regression", + branch: "pawwork/very-long-worktree-name-used-for-titlebar-regression", + directory: "/repo/.worktrees/pawwork/very-long-worktree-name-used-for-titlebar-regression", + ariaLabel: "Open worktrees", + onClick: () => undefined, + }) as unknown as Node + + const tooltip = find(tree, (node) => node.type === "Tooltip") + const button = find(tree, (node) => node.type === "button") + const label = find(tree, (node) => node.type === "span" && node.children.join("").startsWith("very-long-worktree")) + + expect(button?.props.class).toContain("max-w-[280px]") + expect(label?.children.join("")).toBe("very-long-worktree-name-used-for-titlebar-regression") + expect(tooltip?.props.placement).toBe("bottom") + expect(tooltip?.props.value).toMatchObject({ + type: "div", + props: { "data-component": "pawwork-worktree-tooltip" }, + children: [ + expect.objectContaining({ + children: expect.arrayContaining([expect.objectContaining({ children: ["Worktree"] })]), + }), + expect.objectContaining({ + children: expect.arrayContaining([expect.objectContaining({ children: ["Branch"] })]), + }), + expect.objectContaining({ + children: expect.arrayContaining([expect.objectContaining({ children: ["Location"] })]), + }), + ], + }) }) }) diff --git a/packages/app/src/pages/layout/pawwork-worktree-badge.tsx b/packages/app/src/pages/layout/pawwork-worktree-badge.tsx index 1efa253fc..4e5ef8e3b 100644 --- a/packages/app/src/pages/layout/pawwork-worktree-badge.tsx +++ b/packages/app/src/pages/layout/pawwork-worktree-badge.tsx @@ -1,5 +1,23 @@ import { Button } from "@opencode-ai/ui/button" import { Icon } from "@opencode-ai/ui/icon" +import { Tooltip } from "@opencode-ai/ui/tooltip" + +function WorktreeTooltipRow(props: { label: string; value?: string; emphasis?: boolean }) { + return ( +
+ {props.label} + + {props.value || "Not available"} + +
+ ) +} export function PawworkWorktreeBadge(props: { name: string @@ -9,23 +27,34 @@ export function PawworkWorktreeBadge(props: { ariaLabel: string disabled?: boolean }) { - const title = () => [props.branch, props.directory].filter(Boolean).join(" · ") || props.name - const label = () => (props.branch ? `${props.name} (${props.branch})` : props.name) + const label = () => props.name || props.branch || props.directory || "Worktree" + const tooltip = () => ( +
+ + + +
+ ) return ( - + + + ) } From 883afc827a9d0251de69eb6819fb05860afcb2c8 Mon Sep 17 00:00:00 2001 From: Yuhan Lei Date: Sat, 2 May 2026 23:45:16 +0800 Subject: [PATCH 2/3] test(app): preserve tooltip exports in worktree badge test --- .../app/src/pages/layout/pawwork-worktree-badge.test.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/app/src/pages/layout/pawwork-worktree-badge.test.tsx b/packages/app/src/pages/layout/pawwork-worktree-badge.test.tsx index 14150a159..96c436d78 100644 --- a/packages/app/src/pages/layout/pawwork-worktree-badge.test.tsx +++ b/packages/app/src/pages/layout/pawwork-worktree-badge.test.tsx @@ -24,6 +24,12 @@ beforeAll(async () => { props: props ?? {}, children: Array.isArray(props?.children) ? props.children : [props?.children].filter(Boolean), }) as Node, + TooltipKeybind: (props: any) => + ({ + type: "TooltipKeybind", + props: props ?? {}, + children: Array.isArray(props?.children) ? props.children : [props?.children].filter(Boolean), + }) as Node, })) PawworkWorktreeBadge = (await import("./pawwork-worktree-badge")).PawworkWorktreeBadge }) From 1ecd35244e9c7813e822859f8baf8fca8035957a Mon Sep 17 00:00:00 2001 From: Yuhan Lei Date: Sat, 2 May 2026 23:48:42 +0800 Subject: [PATCH 3/3] fix(app): address worktree badge review --- .../layout/pawwork-worktree-badge.test.tsx | 23 +++++++++++++++++++ .../pages/layout/pawwork-worktree-badge.tsx | 4 ++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/packages/app/src/pages/layout/pawwork-worktree-badge.test.tsx b/packages/app/src/pages/layout/pawwork-worktree-badge.test.tsx index 96c436d78..1ff8701b2 100644 --- a/packages/app/src/pages/layout/pawwork-worktree-badge.test.tsx +++ b/packages/app/src/pages/layout/pawwork-worktree-badge.test.tsx @@ -105,6 +105,7 @@ describe("PawworkWorktreeBadge", () => { expect(button?.props.class).toContain("max-w-[280px]") expect(label?.children.join("")).toBe("very-long-worktree-name-used-for-titlebar-regression") expect(tooltip?.props.placement).toBe("bottom") + expect(tooltip?.props.class).toBe("shrink min-w-0") expect(tooltip?.props.value).toMatchObject({ type: "div", props: { "data-component": "pawwork-worktree-tooltip" }, @@ -121,4 +122,26 @@ describe("PawworkWorktreeBadge", () => { ], }) }) + + test("does not duplicate fallback text in the structured tooltip", () => { + const tree = PawworkWorktreeBadge({ + name: "", + branch: "pawwork/fallback-branch", + directory: "/repo/.worktrees/pawwork/fallback-branch", + ariaLabel: "Open worktrees", + onClick: () => undefined, + }) as unknown as Node + + const tooltip = find(tree, (node) => node.type === "Tooltip") + const rows = (tooltip?.props.value as Node).children as Node[] + const worktreeRow = rows[0] + const branchRow = rows[1] + + expect(worktreeRow.children).toEqual( + expect.arrayContaining([expect.objectContaining({ children: ["Not available"] })]), + ) + expect(branchRow.children).toEqual( + expect.arrayContaining([expect.objectContaining({ children: ["pawwork/fallback-branch"] })]), + ) + }) }) diff --git a/packages/app/src/pages/layout/pawwork-worktree-badge.tsx b/packages/app/src/pages/layout/pawwork-worktree-badge.tsx index 4e5ef8e3b..de5d0b31a 100644 --- a/packages/app/src/pages/layout/pawwork-worktree-badge.tsx +++ b/packages/app/src/pages/layout/pawwork-worktree-badge.tsx @@ -30,14 +30,14 @@ export function PawworkWorktreeBadge(props: { const label = () => props.name || props.branch || props.directory || "Worktree" const tooltip = () => (
- +
) return ( - +