Skip to content

Fix sidebar status URL clicks - #8528

Merged
austinywang merged 2 commits into
mainfrom
issue-8520-status-pill-url-click
Jul 21, 2026
Merged

austinywang merged 2 commits into
mainfrom
issue-8520-status-pill-url-click

Conversation

@austinywang

@austinywang austinywang commented Jul 20, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • restore URL-bearing sidebar status entries as standard AppKit link buttons
  • route status clicks through the immutable row action bundle after selecting the workspace
  • reset pooled metadata rows between actionable and inert entries so stale click behavior cannot leak across reuse

Root cause

b7bd90103c (#8270) introduced the AppKit sidebar renderer. The shared snapshot continued carrying the complete SidebarStatusEntry, including url, but SidebarRowIconTextLine.configureMetadataEntry consumed only icon, text, and color, and SidebarAppKitRowActions had no status-URL route. The legacy SwiftUI renderer still created a button and opened the URL.

e35b74407a (#8433) made the AppKit renderer the default before v0.64.20, exposing that latent omission and explaining why v0.64.19 worked while v0.64.20 regressed.

The fix makes metadata rendering consume presentation and action metadata together: URL entries become accessible NSButton controls bound through a required onOpenStatusURL action, while entries without URLs remain inert labels.

Verification

  • commit 57307391b3 adds the failing behavior test before the fix
  • the test renders the real AppKit workspace cell, locates the control bound to the exact stored URL, performs the button click, and observes the dispatched URL through an injected opener
  • ./scripts/lint-pbxproj-test-wiring.sh
  • ./scripts/check-pbxproj.sh
  • python3 scripts/check-package-resolved-policy.py
  • local Xcode build/tests intentionally not run per issue instructions; GitHub CI is the Swift compile/test gate
  • current main removed scripts/swift_file_length_budget.py and .github/swift-file-length-budget.tsv in Remove Swift file length budget #8125, so that requested checker is unavailable; neither budget TSV was touched

Localization

No user-facing strings were added or changed. The pill continues to display the status value and uses the stored URL as its tooltip, matching the legacy renderer.

Closes #8520


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.


Summary by cubic

Restore clickable sidebar status pills: URL-bearing entries now render as link buttons and open in the default browser after selecting the workspace, fixing #8520.

  • Bug Fixes
    • Render URL metadata as NSButton links bound via onOpenStatusURL; wired to NSWorkspace.shared.open.
    • Route clicks through row actions after updating selection; non-URL entries remain inert labels.
    • Reset reused metadata views between actionable and inert states; updated layout/measurement to support buttons.

Written for commit 92b0e93. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Status metadata entries with URLs now appear as clickable, underlined links.
    • Selecting a link opens its destination in the system’s default application.
  • Bug Fixes

    • Non-link metadata and workspace row content continue displaying correctly alongside interactive status links.
  • Tests

    • Added coverage verifying status links are rendered interactively and open the expected URL.

@coderabbitai

coderabbitai Bot commented Jul 20, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4e23892b-b756-4592-87b3-0e096e089bf6

📥 Commits

Reviewing files that changed from the base of the PR and between ce90c0b and 92b0e93.

📒 Files selected for processing (5)
  • Sources/ContentView.swift
  • Sources/Sidebar/AppKitList/Cells/SidebarWorkspaceRowCellView.swift
  • Sources/Sidebar/AppKitList/Cells/SidebarWorkspaceRowModel.swift
  • Sources/Sidebar/AppKitList/Cells/SidebarWorkspaceRowSupportViews.swift
  • cmuxTests/SidebarAppKitRowCellTests.swift

📝 Walkthrough

Walkthrough

Sidebar status metadata entries with URLs now render as clickable underlined buttons. Their activation updates selection and opens the destination through a new row action callback, with coverage added for rendering and URL propagation.

Changes

Sidebar status URL interaction

Layer / File(s) Summary
Status URL callback wiring
Sources/Sidebar/AppKitList/Cells/SidebarWorkspaceRowModel.swift, Sources/Sidebar/AppKitList/Cells/SidebarWorkspaceRowCellView.swift, Sources/ContentView.swift
SidebarAppKitRowActions now carries an URL-opening callback, metadata activation updates selection, and the application opens the URL with NSWorkspace.
Clickable metadata rendering
Sources/Sidebar/AppKitList/Cells/SidebarWorkspaceRowSupportViews.swift
URL-backed metadata uses an underlined button with a tooltip and click handler; non-URL rows continue using the text view with updated sizing and layout behavior.
Status URL interaction tests
cmuxTests/SidebarAppKitRowCellTests.swift
Test helpers now accept metadata entries and URL callbacks, and a test verifies that clicking a rendered status button passes its destination URL.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested reviewers: azooz2003-bit

🚥 Pre-merge checks | ✅ 25
✅ Passed checks (25 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and matches the main change: restoring sidebar status URL clicks.
Description check ✅ Passed The description is mostly complete with summary, root cause, verification, and localization; only template extras like demo video/checklist are missing.
Linked Issues check ✅ Passed The code restores clickable URL status pills, preserves inert non-URL rows, and adds a test, matching issue #8520.
Out of Scope Changes check ✅ Passed The changes stay focused on the sidebar URL-click regression; the added tests and row/view wiring are directly related.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Cmux Swift Actor Isolation ✅ Passed New status-URL handling stays inside @MainActor AppKit UI/action types and MainActor tests; no new Sendable/value-model or background-bound isolation debt.
Cmux Swift Blocking Runtime ✅ Passed PASS: the diff only adds URL-routing/link-button behavior and tests; no semaphores, sleeps, sync waits, polling, or manual locks were introduced.
Cmux Browser Automation Off-Main ✅ Passed The commit only changes sidebar status-link UI and tests; no browser.* socket commands, router, or policy files were touched, so the off-main rule isn’t implicated.
Cmux Expensive Synchronous Load ✅ Passed Diff only adds URL-button wiring and tests; no agent-history load, JSON parse, or broad scan was introduced on the main/interactive path.
Cmux Cache Substitution Correctness ✅ Passed The diff only wires a transient UI link button to an opener; no fresh authoritative read was replaced in a persistence/history/undo/snapshot path, and pooled rows are reset on reconfigure.
Cmux No Hacky Sleeps ✅ Passed Patch only touches Swift app/test code and adds no sleeps, timers, polling, or delayed dispatch in changed files.
Cmux Algorithmic Complexity ✅ Passed PASS: The diff only threads an O(1) URL callback and keeps metadata rendering to a single bounded pass; no nested scans, rescans, or hot-path sorting/filtering were introduced.
Cmux Swift Concurrency ✅ Passed The diff only adds AppKit/XCTest callback wiring for URL clicks; it doesn’t introduce new background queues, Tasks, or internal async completion-handler APIs.
Cmux Swift @Concurrent ✅ Passed The diff only adds main-actor UI callbacks and a sync NSWorkspace open path; no @concurrent, nonisolated async, or heavy async work was introduced.
Cmux Swift Package Boundaries ✅ Passed Only AppKit/UI glue was added: row view/button wiring, action-bundle callback, and app-level NSWorkspace opening; no reusable domain logic or package-worthy core moved into Sources/.
Cmux Swiftpm Lockfiles ✅ Passed Diff touches only Swift source/tests; no Package.swift, Package.resolved, .gitignore, workflow, or Xcode project lockfile changes appear.
Cmux Swift Logging ✅ Passed Touched production Swift files add URL-link behavior only; no new print/debugPrint/dump/NSLog or Logger declarations appear in the diff.
Cmux User-Facing Error Privacy ✅ Passed Changed files only wire status URL clicks and tooltip text; no user-facing errors, alerts, command output, or recovery copy were added.
Cmux Full Internationalization ✅ Passed No new production copy was added; the PR only wires existing status data into a link button and opens the stored URL, with no xcstrings/InfoPlist locale changes.
Cmux Swiftui State Layout ✅ Passed Diff only adds a status-URL closure and AppKit row/button wiring; no new ObservableObject/@published, GeometryReader, or render-time state writes appear.
Cmux Architecture Rethink ✅ Passed PASS: adds one immutable onOpenStatusURL bridge from AppKit metadata rows to NSWorkspace, with no new timing/observer workaround or duplicate ownership.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed The PR only changes sidebar status-link rendering/tests; it adds no new NSWindow/NSPanel/WindowGroup code, identifiers, or close-shortcut routing.
Cmux Source Artifacts ✅ Passed All changed paths are hand-written source/test files allowed by the rule; no logs, screenshots, build output, caches, or temp/artifact dirs were added.
Cmux No Test Or Debug Seam In Production Source ✅ Passed PR adds production URL-opening behavior and a test-target callback path; no new #if DEBUG/test-only seam was introduced in Sources.
Cmux No Ambient Global State ✅ Passed The diff adds only instance-owned closures/properties and an inline AppKit handler; no new file-scope funcs, globals, static-only namespaces, or singletons were introduced.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-8520-status-pill-url-click

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR restores clickable status-URL entries in the AppKit sidebar renderer, which had regressed in v0.64.20 when the AppKit renderer became the default. The fix wires a new onOpenStatusURL action through SidebarAppKitRowActions, renders URL-bearing metadata entries as SidebarRowLinkButton controls instead of inert labels, and resets pooled row state on every configure pass to prevent stale click closures from leaking across cell reuse.

  • SidebarWorkspaceRowModel.swift — adds onOpenStatusURL: (URL) -> Void to SidebarAppKitRowActions, making URL handling a first-class required field alongside the existing PR/port actions.
  • SidebarWorkspaceRowSupportViews.swift — SidebarRowIconTextLine.configureMetadataEntry now branches on entry.url: URL entries show a SidebarRowLinkButton (underlined, with the URL as tooltip and click closure); non-URL entries keep the existing inert text label. All other configure methods (configureLog, configureBranchLine) explicitly reset metadataButton.isHidden = true and textView.isHidden = false.
  • SidebarWorkspaceRowCellView.swift — the call site passes an onOpenURL closure that calls commands.updateSelection() then onOpenStatusURL(url), selecting the workspace before opening the link.
  • ContentView.swift — provides the onOpenStatusURL implementation via NSWorkspace.shared.open(url).
  • SidebarAppKitRowCellTests.swift — adds a new metadataStatusURLRendersAnActionBoundToItsDestination test that injects a URL-bearing entry, finds the rendered button by its tooltip, performs the click, and verifies the URL is dispatched to the injected opener.

Confidence Score: 5/5

Safe to merge — the change is narrowly scoped to metadata row rendering, all pooled state resets are explicit, and the new button path mirrors the established SidebarRowLinkButton pattern already used for PR titles and ports.

The fix correctly identifies the missing URL-action route and wires it end-to-end: the button is properly hidden or reset on every non-URL configure pass, the weak-self capture prevents retain cycles in the pooled-cell context, and the layout delegates to intrinsicContentSize.height in a way consistent with SidebarRowPullRequestLine. The new test injects a URL-bearing entry, locates the rendered button by its tooltip, and performs a real click — covering the exact regression path. No production debug seams, no blocking concurrency, no ambient global state introduced.

No files require special attention.

Important Files Changed

Filename Overview
Sources/Sidebar/AppKitList/Cells/SidebarWorkspaceRowSupportViews.swift Core of the fix: adds metadataButton (SidebarRowLinkButton) to SidebarRowIconTextLine, branches configureMetadataEntry on entry.url, and resets button/text visibility in all other configure methods to prevent stale cell-reuse state.
Sources/Sidebar/AppKitList/Cells/SidebarWorkspaceRowCellView.swift Call site updated to pass onOpenURL closure that selects the workspace before dispatching the status URL; uses weak self correctly to avoid retain cycles in the pooled cell.
Sources/Sidebar/AppKitList/Cells/SidebarWorkspaceRowModel.swift Adds onOpenStatusURL: (URL) -> Void to SidebarAppKitRowActions as a required stored property; straightforward struct extension.
Sources/ContentView.swift Wires onOpenStatusURL to NSWorkspace.shared.open(url), consistent with how other external URL opens are handled in the app.
cmuxTests/SidebarAppKitRowCellTests.swift New metadataStatusURLRendersAnActionBoundToItsDestination test verifies end-to-end click dispatch through the real cell; existing test correctly updated with required onOpenURL parameter.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant CV as ContentView
    participant RA as SidebarAppKitRowActions
    participant Cell as SidebarWorkspaceRowTableCellView
    participant Row as SidebarRowIconTextLine
    participant Btn as SidebarRowLinkButton
    participant WS as NSWorkspace

    CV->>RA: "init(onOpenStatusURL: { NSWorkspace.shared.open(url) })"
    Cell->>Row: configureMetadataEntry(entry, model, color, onOpenURL)
    alt "entry.url != nil"
        Row->>Btn: configure(title, font, color, toolTip: url.absoluteString, onClick)
        Row->>Btn: "isHidden = false"
        Row->>Row: "textView.isHidden = true"
    else "entry.url == nil"
        Row->>Btn: "isHidden = true"
        Row->>Row: "textView.isHidden = false"
    end
    Note over Btn: User clicks button
    Btn->>Cell: onClick() → onOpenURL(url)
    Cell->>RA: commands.updateSelection()
    Cell->>RA: onOpenStatusURL(url)
    RA->>WS: NSWorkspace.shared.open(url)
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant CV as ContentView
    participant RA as SidebarAppKitRowActions
    participant Cell as SidebarWorkspaceRowTableCellView
    participant Row as SidebarRowIconTextLine
    participant Btn as SidebarRowLinkButton
    participant WS as NSWorkspace

    CV->>RA: "init(onOpenStatusURL: { NSWorkspace.shared.open(url) })"
    Cell->>Row: configureMetadataEntry(entry, model, color, onOpenURL)
    alt "entry.url != nil"
        Row->>Btn: configure(title, font, color, toolTip: url.absoluteString, onClick)
        Row->>Btn: "isHidden = false"
        Row->>Row: "textView.isHidden = true"
    else "entry.url == nil"
        Row->>Btn: "isHidden = true"
        Row->>Row: "textView.isHidden = false"
    end
    Note over Btn: User clicks button
    Btn->>Cell: onClick() → onOpenURL(url)
    Cell->>RA: commands.updateSelection()
    Cell->>RA: onOpenStatusURL(url)
    RA->>WS: NSWorkspace.shared.open(url)
Loading

Reviews (1): Last reviewed commit: "fix: restore sidebar status URL actions" | Re-trigger Greptile

@austinywang
austinywang merged commit 12798dc into main Jul 21, 2026
18 of 24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sidebar status pill no longer opens its --url on click (regression in v0.64.20, worked in v0.64.19)

1 participant