Skip to content

Add Jump to Latest to the notifications popover - #1167

Merged
lawrencecchen merged 7 commits into
mainfrom
task-notifications-jump-to-latest
Mar 11, 2026
Merged

lawrencecchen merged 7 commits into
mainfrom
task-notifications-jump-to-latest

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Mar 11, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • add a Jump to Latest button to the notifications popover header, positioned before Clear All
  • show the current jump shortcut badge on that button and route it through the existing jump action
  • add UI coverage for the popover button and its shortcut badge

Testing

  • ./scripts/setup.sh
  • ./scripts/reload.sh --tag task-notifications-jump-to-latest

Issues

  • Task: add a "Jump to Latest" button in notifications, left of Clear All, with cmd shift u clearly denoted

Summary by cubic

Adds a Jump to Latest button in the notifications popover that focuses the most recent unread notification and closes the popover. It sits before Clear All and shows the jump shortcut inline (⌘⇧U by default), fulfilling the Linear task.

  • New Features
    • Adds the button before Clear All; disabled when no unread. Clear All is disabled when empty.
    • Shows the configured shortcut inline next to the label, matches existing styling, and exposes it via the button’s accessibility value; adds identifiers on the button and Clear All.
    • Reuses the existing jump-to-unread action and closes the popover on click; keeps both actions visible when empty.
    • Adds localization for “Jump to Latest” (en, ja) and stabilizes UI tests by reading the shortcut from the button value (checks for ⌘, ⇧, and U).

Written for commit 4910fb7. Summary will update on new commits.

Summary by CodeRabbit

  • New Features

    • Added a "Jump to Latest" button in the notifications popover with keyboard shortcut support; retains Clear All and is disabled when no unread notifications remain.
  • Accessibility

    • Improved accessibility labels and visible shortcut annotations for notification controls.
  • Localization

    • Added "Jump to Latest" localization entries (English and Japanese).
  • Tests

    • Added UI tests verifying the Jump to Latest button, its shortcut display, and disabled state.

@vercel

vercel Bot commented Mar 11, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Mar 11, 2026 2:23am

@coderabbitai

coderabbitai Bot commented Mar 11, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds a localized "Jump to Latest" notification label, exposes and augments ShortcutAnnotation for accessibility, wires a persisted jump-to-latest shortcut into the notifications popover with a Jump to Latest action, and adds UI tests asserting the new button and shortcut badge.

Changes

Cohort / File(s) Summary
Localization
Resources/Localizable.xcstrings
Added notifications.jumpToLatest translations (en, ja).
Notification UI component
Sources/NotificationsPage.swift
Made ShortcutAnnotation public and added optional accessibilityIdentifier; extracted badge view and applied accessibility conditionally.
Notifications popover / shortcut wiring
Sources/Update/UpdateTitlebarAccessory.swift
Added AppStorage-backed jumpToUnreadShortcutData, decoding helper and jumpToUnreadShortcut accessor, hasUnreadNotifications, jumpToLatestUnread() action; replaced Clear All-only UI with a Jump to Latest button displaying the stored shortcut and wired accessibility/safeHelp/disabled states while retaining Clear All.
UI tests
cmuxUITests/MultiWindowNotificationsUITests.swift
Added testNotificationsPopoverJumpToLatestButtonShowsShortcut() (duplicated in diff) and updated testEmptyNotificationsPopoverBlocksTerminalTyping to assert presence and disabled state of Jump to Latest and Clear All when no notifications exist.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant User
participant NotificationsPopover
participant AppStorage
participant AppDelegate
participant WindowManager
User->>NotificationsPopover: Open popover or press shortcut
NotificationsPopover->>AppStorage: Read jumpToUnreadShortcutData
AppStorage-->>NotificationsPopover: Return shortcut data
NotificationsPopover-->>User: Render "Jump to Latest" button with shortcut badge
User->>NotificationsPopover: Click "Jump to Latest"
NotificationsPopover->>AppDelegate: call jumpToLatestUnread()
AppDelegate->>WindowManager: focus latest window/tab with unread
WindowManager-->>User: UI focus moved to latest unread

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

  • manaflow-ai/cmux-dev-artifacts#332: Touches shortcut accessibility and ShortcutAnnotation exposure — relevant to accessibilityIdentifier additions.
  • manaflow-ai/cmux-dev-artifacts#333: Relates to shortcut badge rendering/order — relevant because new badge is introduced for Jump to Latest.
  • manaflow-ai/cmux-dev-artifacts#334: Failing UITests for Jump to Latest — relevant since this PR adds the Jump to Latest button and corresponding UITests.

Possibly related PRs

Poem

🐰 I hop into popovers with a tiny badge so bright,
A shortcut on my paw to bring the latest into light,
I tap, I point — windows wake and greet,
The newest unread is now beneath your feet,
Hooray for hops and shortcuts — swift and light!

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The pull request description includes Summary and Testing sections, but is missing Demo Video, Review Trigger, and Checklist sections required by the template. Add Demo Video URL/attachment, include Review Trigger block with bot review commands, and complete the Checklist with checkmarks for testing, tests, docs, bot reviews, and comment resolution.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding a 'Jump to Latest' button to the notifications popover.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch task-notifications-jump-to-latest

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

@greptile-apps

greptile-apps Bot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a "Jump to Latest" button to the notifications popover header (left of "Clear All"), surfacing the existing jumpToLatestUnread action with its keyboard shortcut badge directly in the popover UI. The change is straightforward and consistent with the equivalent button already present in NotificationsPage.

Key changes:

  • NotificationsPopoverView gains the new button, shortcut-badge display (via ShortcutAnnotation), and a hasUnreadNotifications guard that disables the button when all notifications are read.
  • ShortcutAnnotation is promoted from private to internal and gains an optional accessibilityIdentifier parameter so the badge can be targeted in UI tests.
  • A new notifications.jumpToLatest localisation key is added (English + Japanese).
  • A new UI test verifies button presence, shortcut label rendering, and that clicking the button correctly re-focuses the expected window/tab.
  • The decodeShortcut helper and hasUnreadNotifications computed property are duplicated from NotificationsPage into NotificationsPopoverView rather than being shared — worth consolidating to avoid future drift.

Confidence Score: 4/5

  • Safe to merge; changes are additive and well-tested with no logic bugs identified.
  • The implementation follows established patterns, the UI test gives reasonable functional coverage, and there are no correctness issues. Minor deductions for the duplicated helpers and the hardcoded shortcut string in the test.
  • Sources/Update/UpdateTitlebarAccessory.swift — duplicated decodeShortcut and hasUnreadNotifications helpers.

Important Files Changed

Filename Overview
Sources/Update/UpdateTitlebarAccessory.swift Adds "Jump to Latest" button with shortcut badge to NotificationsPopoverView; introduces duplicated decodeShortcut / hasUnreadNotifications helpers already present in NotificationsPage.swift.
Sources/NotificationsPage.swift Makes ShortcutAnnotation internal and adds an optional accessibilityIdentifier parameter via a clean @ViewBuilder conditional — no issues.
cmuxUITests/MultiWindowNotificationsUITests.swift New UI test covers button existence, shortcut badge rendering, and focus-routing after click; shortcut label assertion "⌘⇧U" is hardcoded and could break if user defaults are customized on the test machine.
Resources/Localizable.xcstrings Adds notifications.jumpToLatest key with English and Japanese translations — looks correct and complete.

Sequence Diagram

sequenceDiagram
    actor User
    participant Popover as NotificationsPopoverView
    participant AppDelegate
    participant FocusSystem as Window/Tab Focus

    User->>Popover: Click "Jump to Latest" button
    Popover->>Popover: jumpToLatestUnread()
    Popover->>AppDelegate: DispatchQueue.main.async { jumpToLatestUnread() }
    AppDelegate->>FocusSystem: Focus latest unread window + tab
    Popover->>Popover: onDismiss() — closes popover
Loading

Last reviewed commit: 96069e1

Comment on lines +990 to +996
private func decodeShortcut(from data: Data, fallback: StoredShortcut) -> StoredShortcut {
guard !data.isEmpty,
let shortcut = try? JSONDecoder().decode(StoredShortcut.self, from: data) else {
return fallback
}
return shortcut
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicated decodeShortcut helper

This private decodeShortcut function is identical to the one already defined in NotificationsPage.swift (line 145–151). Both structs also duplicate hasUnreadNotifications (comparing NotificationsPage.swift line 141–143 with this file line 986–988). Now that ShortcutAnnotation has been made internal, consider extracting this decode helper to a shared extension or a free function (e.g., in a KeyboardShortcutSettings+Helpers.swift file) so both call-sites stay in sync if the decoding logic ever needs to change.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +998 to +1003
private func jumpToLatestUnread() {
DispatchQueue.main.async {
AppDelegate.shared?.jumpToLatestUnread()
onDismiss()
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing comment explaining DispatchQueue.main.async usage

The sibling open(_:) function (line 1005) carries an explicit comment explaining why DispatchQueue.main.async is required ("SwiftUI action closures are not guaranteed to run on the main actor"). For consistency and future maintainability, the same comment should be added here.

Suggested change
private func jumpToLatestUnread() {
DispatchQueue.main.async {
AppDelegate.shared?.jumpToLatestUnread()
onDismiss()
}
}
private func jumpToLatestUnread() {
// SwiftUI action closures are not guaranteed to run on the main actor.
// Ensure window focus + tab selection happens on the main thread.
DispatchQueue.main.async {
AppDelegate.shared?.jumpToLatestUnread()
onDismiss()
}
}

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +199 to +200
return
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded shortcut label assumes default user settings

XCTAssertEqual(shortcutBadge.label, "⌘⇧U") will fail if the test runner's UserDefaults already contain a customized value for the jumpToUnread shortcut key. Unlike the keyboard-trigger test (line 76) which sends the raw keys, this assertion relies on the UI-rendered string. Consider clearing the relevant defaults key before launching, or reading the expected label from the fallback shortcut rather than hardcoding the string, to make the test robust regardless of machine state.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
Sources/Update/UpdateTitlebarAccessory.swift (1)

979-996: Consider extracting shared shortcut decoding logic.

The jumpToUnreadShortcut, hasUnreadNotifications, and decodeShortcut(from:fallback:) implementations are duplicated between NotificationsPopoverView and NotificationsPage (lines 134-151 in NotificationsPage.swift). Consider extracting these to a shared extension or helper to reduce duplication.

♻️ Suggested shared helper location

You could add these as extensions on TerminalNotificationStore or create a small helper struct:

// e.g., in a shared file or extension
extension TerminalNotificationStore {
    var hasUnreadNotifications: Bool {
        notifications.contains(where: { !$0.isRead })
    }
}

// For shortcut decoding, a static helper could work:
enum ShortcutDecoder {
    static func decode(from data: Data, fallback: StoredShortcut) -> StoredShortcut {
        guard !data.isEmpty,
              let shortcut = try? JSONDecoder().decode(StoredShortcut.self, from: data) else {
            return fallback
        }
        return shortcut
    }
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/Update/UpdateTitlebarAccessory.swift` around lines 979 - 996, Extract
the duplicated logic for shortcut decoding and unread checks into a shared
helper: move decodeShortcut(from:fallback:) and jumpToUnreadShortcut usage out
of NotificationsPopoverView and NotificationsPage into a reusable utility (e.g.,
a ShortcutDecoder type with static func decode(from:fallback:) or similar) and
move hasUnreadNotifications into an extension on TerminalNotificationStore as
var hasUnreadNotifications: Bool; then update NotificationsPopoverView and
NotificationsPage to call ShortcutDecoder.decode(...) and
TerminalNotificationStore.hasUnreadNotifications respectively so the duplicated
implementations (jumpToUnreadShortcut, hasUnreadNotifications,
decodeShortcut(from:fallback:)) are removed.
cmuxUITests/MultiWindowNotificationsUITests.swift (1)

186-188: Consider documenting the hardcoded shortcut assumption.

The assertion XCTAssertEqual(shortcutBadge.label, "⌘⇧U") assumes the default shortcut for jumpToUnread is Cmd+Shift+U. This is fine for validating default behavior, but consider adding a brief comment noting this tests the default shortcut in case the default changes in the future.

 let shortcutBadge = app.staticTexts["notificationsPopover.jumpToLatest.shortcut"]
 XCTAssertTrue(shortcutBadge.waitForExistence(timeout: 2.0), "Expected Jump to Latest shortcut badge")
+// Validates default jumpToUnread shortcut (Cmd+Shift+U)
 XCTAssertEqual(shortcutBadge.label, "⌘⇧U")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmuxUITests/MultiWindowNotificationsUITests.swift` around lines 186 - 188,
Add a short inline comment above the Shortcut assertion to document that this
test expects the app's default keyboard shortcut for jumpToUnread (accessed via
the UI element identifier "notificationsPopover.jumpToLatest.shortcut" and the
variable shortcutBadge) to be "⌘⇧U"; update the comment to mention that if the
app's default shortcut changes the test should be adjusted accordingly so future
reviewers know this is an intentional hardcoded expectation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@cmuxUITests/MultiWindowNotificationsUITests.swift`:
- Around line 186-188: Add a short inline comment above the Shortcut assertion
to document that this test expects the app's default keyboard shortcut for
jumpToUnread (accessed via the UI element identifier
"notificationsPopover.jumpToLatest.shortcut" and the variable shortcutBadge) to
be "⌘⇧U"; update the comment to mention that if the app's default shortcut
changes the test should be adjusted accordingly so future reviewers know this is
an intentional hardcoded expectation.

In `@Sources/Update/UpdateTitlebarAccessory.swift`:
- Around line 979-996: Extract the duplicated logic for shortcut decoding and
unread checks into a shared helper: move decodeShortcut(from:fallback:) and
jumpToUnreadShortcut usage out of NotificationsPopoverView and NotificationsPage
into a reusable utility (e.g., a ShortcutDecoder type with static func
decode(from:fallback:) or similar) and move hasUnreadNotifications into an
extension on TerminalNotificationStore as var hasUnreadNotifications: Bool; then
update NotificationsPopoverView and NotificationsPage to call
ShortcutDecoder.decode(...) and TerminalNotificationStore.hasUnreadNotifications
respectively so the duplicated implementations (jumpToUnreadShortcut,
hasUnreadNotifications, decodeShortcut(from:fallback:)) are removed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2e940692-d57a-455d-ab71-78725aea9199

📥 Commits

Reviewing files that changed from the base of the PR and between 22ae558 and 96069e1.

📒 Files selected for processing (4)
  • Resources/Localizable.xcstrings
  • Sources/NotificationsPage.swift
  • Sources/Update/UpdateTitlebarAccessory.swift
  • cmuxUITests/MultiWindowNotificationsUITests.swift

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 4 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="Sources/Update/UpdateTitlebarAccessory.swift">

<violation number="1" location="Sources/Update/UpdateTitlebarAccessory.swift:916">
P2: Inconsistent label: every other surface in the app calls this action "Jump to Latest Unread" (menus, keyboard shortcut settings, notifications page, status menu). Using "Jump to Latest" here is inconsistent and introduces a separate localization key (`notifications.jumpToLatest` vs `notifications.jumpToLatestUnread`) that translators must handle independently.</violation>

<violation number="2" location="Sources/Update/UpdateTitlebarAccessory.swift:927">
P2: Same inconsistency in the tooltip string — should use `"notifications.jumpToLatestUnread"` / `"Jump to Latest Unread"` to match the rest of the app.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

.accessibilityIdentifier("notificationsPopover.jumpToLatest")
.safeHelp(
KeyboardShortcutSettings.Action.jumpToUnread.tooltip(
String(localized: "notifications.jumpToLatest", defaultValue: "Jump to Latest")

@cubic-dev-ai cubic-dev-ai Bot Mar 11, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Same inconsistency in the tooltip string — should use "notifications.jumpToLatestUnread" / "Jump to Latest Unread" to match the rest of the app.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Sources/Update/UpdateTitlebarAccessory.swift, line 927:

<comment>Same inconsistency in the tooltip string — should use `"notifications.jumpToLatestUnread"` / `"Jump to Latest Unread"` to match the rest of the app.</comment>

<file context>
@@ -910,6 +911,24 @@ private struct NotificationsPopoverView: View {
+                    .accessibilityIdentifier("notificationsPopover.jumpToLatest")
+                    .safeHelp(
+                        KeyboardShortcutSettings.Action.jumpToUnread.tooltip(
+                            String(localized: "notifications.jumpToLatest", defaultValue: "Jump to Latest")
+                        )
+                    )
</file context>
Suggested change
String(localized: "notifications.jumpToLatest", defaultValue: "Jump to Latest")
String(localized: "notifications.jumpToLatestUnread", defaultValue: "Jump to Latest Unread")
Fix with Cubic

if !notificationStore.notifications.isEmpty {
Button(action: jumpToLatestUnread) {
HStack(spacing: 6) {
Text(String(localized: "notifications.jumpToLatest", defaultValue: "Jump to Latest"))

@cubic-dev-ai cubic-dev-ai Bot Mar 11, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Inconsistent label: every other surface in the app calls this action "Jump to Latest Unread" (menus, keyboard shortcut settings, notifications page, status menu). Using "Jump to Latest" here is inconsistent and introduces a separate localization key (notifications.jumpToLatest vs notifications.jumpToLatestUnread) that translators must handle independently.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Sources/Update/UpdateTitlebarAccessory.swift, line 916:

<comment>Inconsistent label: every other surface in the app calls this action "Jump to Latest Unread" (menus, keyboard shortcut settings, notifications page, status menu). Using "Jump to Latest" here is inconsistent and introduces a separate localization key (`notifications.jumpToLatest` vs `notifications.jumpToLatestUnread`) that translators must handle independently.</comment>

<file context>
@@ -910,6 +911,24 @@ private struct NotificationsPopoverView: View {
                 if !notificationStore.notifications.isEmpty {
+                    Button(action: jumpToLatestUnread) {
+                        HStack(spacing: 6) {
+                            Text(String(localized: "notifications.jumpToLatest", defaultValue: "Jump to Latest"))
+                            ShortcutAnnotation(
+                                text: jumpToUnreadShortcut.displayString,
</file context>
Suggested change
Text(String(localized: "notifications.jumpToLatest", defaultValue: "Jump to Latest"))
Text(String(localized: "notifications.jumpToLatestUnread", defaultValue: "Jump to Latest Unread"))
Fix with Cubic

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cmuxUITests/MultiWindowNotificationsUITests.swift`:
- Around line 183-186: The test currently asserts the Jump to Latest button
badge equals a hard-coded "⌘⇧U" but the button reads its value from persisted
AppStorage via KeyboardShortcutSettings.Action.jumpToUnread.defaultsKey; before
asserting, seed the shortcut for this test (e.g., write the desired shortcut
into the same AppStorage/defaults key used by
KeyboardShortcutSettings.Action.jumpToUnread) or read that stored value and
assert the button.value against the seeded/read value; update the test to set
the shortcut into UserDefaults/AppStorage for the test run, then call
XCTAssertEqual(jumpButton.value as? String, seededShortcut) (referencing
jumpButton and KeyboardShortcutSettings.Action.jumpToUnread.defaultsKey).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3b0f3e09-301f-4f4e-9be5-d8a76d1f1723

📥 Commits

Reviewing files that changed from the base of the PR and between 96069e1 and 6b5f868.

📒 Files selected for processing (2)
  • Sources/Update/UpdateTitlebarAccessory.swift
  • cmuxUITests/MultiWindowNotificationsUITests.swift

Comment on lines +183 to +186
let jumpButton = app.buttons["notificationsPopover.jumpToLatest"]
XCTAssertTrue(jumpButton.waitForExistence(timeout: 6.0), "Expected Jump to Latest button in notifications popover")
XCTAssertEqual(jumpButton.value as? String, "⌘⇧U", "Expected Jump to Latest shortcut badge")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Seed the shortcut before asserting its exact badge text.

This test hard-codes ⌘⇧U, but the button reads its value from persisted @AppStorage. If another run changes KeyboardShortcutSettings.Action.jumpToUnread.defaultsKey, the feature still works and this assertion fails. Please set the shortcut explicitly for this test run, or assert against the value you seeded.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmuxUITests/MultiWindowNotificationsUITests.swift` around lines 183 - 186,
The test currently asserts the Jump to Latest button badge equals a hard-coded
"⌘⇧U" but the button reads its value from persisted AppStorage via
KeyboardShortcutSettings.Action.jumpToUnread.defaultsKey; before asserting, seed
the shortcut for this test (e.g., write the desired shortcut into the same
AppStorage/defaults key used by KeyboardShortcutSettings.Action.jumpToUnread) or
read that stored value and assert the button.value against the seeded/read
value; update the test to set the shortcut into UserDefaults/AppStorage for the
test run, then call XCTAssertEqual(jumpButton.value as? String, seededShortcut)
(referencing jumpButton and
KeyboardShortcutSettings.Action.jumpToUnread.defaultsKey).

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
Sources/Update/UpdateTitlebarAccessory.swift (1)

991-997: Consider consolidating duplicate decodeShortcut helper.

This method is duplicated verbatim in at least four files (NotificationsPage.swift, WorkspaceContentView.swift, cmuxApp.swift, and here). Consider extracting it to a shared location (e.g., as a static method on StoredShortcut or KeyboardShortcutSettings) to reduce maintenance burden.

♻️ Suggested consolidation

Add to KeyboardShortcutSettings or StoredShortcut:

extension StoredShortcut {
    static func decode(from data: Data, fallback: StoredShortcut) -> StoredShortcut {
        guard !data.isEmpty,
              let shortcut = try? JSONDecoder().decode(StoredShortcut.self, from: data) else {
            return fallback
        }
        return shortcut
    }
}

Then replace all call sites with:

private var jumpToUnreadShortcut: StoredShortcut {
    StoredShortcut.decode(from: jumpToUnreadShortcutData, fallback: KeyboardShortcutSettings.Action.jumpToUnread.defaultShortcut)
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/Update/UpdateTitlebarAccessory.swift` around lines 991 - 997, Several
files duplicate the decodeShortcut implementation; extract it to a single shared
API such as an extension on StoredShortcut (e.g.,
StoredShortcut.decode(from:fallback:)) and replace the local private func
decodeShortcut(...) implementations with calls to that new static method. Update
callers like the computed property jumpToUnreadShortcut to use
StoredShortcut.decode(from: jumpToUnreadShortcutData, fallback:
KeyboardShortcutSettings.Action.jumpToUnread.defaultShortcut) and remove the
private decodeShortcut function from UpdateTitlebarAccessory.swift and the other
files (NotificationsPage.swift, WorkspaceContentView.swift, cmuxApp.swift).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@Sources/Update/UpdateTitlebarAccessory.swift`:
- Around line 991-997: Several files duplicate the decodeShortcut
implementation; extract it to a single shared API such as an extension on
StoredShortcut (e.g., StoredShortcut.decode(from:fallback:)) and replace the
local private func decodeShortcut(...) implementations with calls to that new
static method. Update callers like the computed property jumpToUnreadShortcut to
use StoredShortcut.decode(from: jumpToUnreadShortcutData, fallback:
KeyboardShortcutSettings.Action.jumpToUnread.defaultShortcut) and remove the
private decodeShortcut function from UpdateTitlebarAccessory.swift and the other
files (NotificationsPage.swift, WorkspaceContentView.swift, cmuxApp.swift).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b7f5e64f-16c4-4658-8e11-419f59c6db22

📥 Commits

Reviewing files that changed from the base of the PR and between 6b5f868 and c095ff4.

📒 Files selected for processing (2)
  • Sources/Update/UpdateTitlebarAccessory.swift
  • cmuxUITests/MultiWindowNotificationsUITests.swift
🚧 Files skipped from review as they are similar to previous changes (1)
  • cmuxUITests/MultiWindowNotificationsUITests.swift

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
Sources/Update/UpdateTitlebarAccessory.swift (1)

988-994: Consider centralizing shortcut decoding.

Lines 988-994 are now another copy of the same JSON decode/fallback helper already used in Sources/NotificationsPage.swift, Sources/WorkspaceContentView.swift, and Sources/cmuxApp.swift. Pulling this into a shared helper on KeyboardShortcutSettings or StoredShortcut would reduce drift the next time the stored format changes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/Update/UpdateTitlebarAccessory.swift` around lines 988 - 994, The
decodeShortcut(from:fallback:) helper in UpdateTitlebarAccessory (the private
function decodeShortcut) duplicates logic used elsewhere; move this JSON decode
+ fallback logic into a single shared method on either KeyboardShortcutSettings
or StoredShortcut (e.g., StoredShortcut.decode(from:fallback:) or
KeyboardShortcutSettings.decodeShortcut(from:fallback:)) and replace the local
decodeShortcut implementation with calls to that new static/instance helper from
UpdateTitlebarAccessory, NotificationsPage, WorkspaceContentView, and cmuxApp so
all code uses the centralized decoder and avoids drift when the stored format
changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@Sources/Update/UpdateTitlebarAccessory.swift`:
- Around line 988-994: The decodeShortcut(from:fallback:) helper in
UpdateTitlebarAccessory (the private function decodeShortcut) duplicates logic
used elsewhere; move this JSON decode + fallback logic into a single shared
method on either KeyboardShortcutSettings or StoredShortcut (e.g.,
StoredShortcut.decode(from:fallback:) or
KeyboardShortcutSettings.decodeShortcut(from:fallback:)) and replace the local
decodeShortcut implementation with calls to that new static/instance helper from
UpdateTitlebarAccessory, NotificationsPage, WorkspaceContentView, and cmuxApp so
all code uses the centralized decoder and avoids drift when the stored format
changes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 12a9b362-a659-4041-8019-e85c03e92a96

📥 Commits

Reviewing files that changed from the base of the PR and between c095ff4 and 6754d96.

📒 Files selected for processing (1)
  • Sources/Update/UpdateTitlebarAccessory.swift

@lawrencecchen
lawrencecchen merged commit 527dfa6 into main Mar 11, 2026
13 checks passed
@lawrencecchen
lawrencecchen deleted the task-notifications-jump-to-latest branch March 11, 2026 02:30
bn-l pushed a commit to bn-l/cmux that referenced this pull request Apr 3, 2026
* Add jump-to-latest button to notifications popover

* Fix jump-to-latest popover accessibility

* Relax shortcut badge UI test expectation

* Stabilize jump-to-latest UI coverage

* Keep popover notification actions visible when empty

* Inline jump-to-latest shortcut label

* Match jump-to-latest shortcut label styling

This branch was successfully deployed

1 active deployment
Preview — 6754d961 Deployed Mar 11, 2026 by vercel[bot]
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.

1 participant