Skip to content

Add GitHub notification bell with background polling and popover - #45

Merged
Tranthanh98 merged 2 commits into
mainfrom
feat-implement-github-notification
Oct 7, 2026
Merged

Tranthanh98 merged 2 commits into
mainfrom
feat-implement-github-notification

Conversation

@Tranthanh98

@Tranthanh98 Tranthanh98 commented Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

Add GitHub notification bell with background polling

Summary

Adds a GitHub notification bell to the toolbar with background polling of the GitHub notifications inbox, a popover to view notifications per account, and a small-icon asset.

Changes

  • New controller — macgit/App/GitHubNotificationController.swift manages per-account notification caches, errors, busy state, and a selected-account filter persisted in UserDefaults. It subscribes to GitProviderAccountController accounts, reconciles persisted caches, and runs a polling loop (60s interval), refreshing all accounts as needed.
  • New models — GitHubNotification, GitHubNotificationCache, GitHubNotificationDisplayRow, GitHubNotificationError, GitHubNotificationFetch.
  • New service — macgit/Services/GitHubNotificationService.swift (behind the GitHubNotificationProviding protocol), fetched with a GitHub API token from the token vault.
  • New views — GitHubNotificationBell, GitHubNotificationPopover, GitHubNotificationRefreshButton, GitHubNotificationRow under macgit/Views/Common/.
  • App wiring — macgitApp.swift, MainWindowView.swift, ContentView.swift, and WelcomeDashboardContent.swift updated to surface the bell in the toolbar/window.
  • Asset — adds the small-icon imageset.
  • Tests — adds macgitTests/GitHubNotificationTests.swift.

Notable behavior

  • Background polling starts via start(provider:); it only runs while the task is not cancelled and skips when the provider is loading.
  • Manual refresh bypasses cache freshness but never server backoff; X-Poll-Interval is stored separately as nextFetchAt.
  • In-flight reads are preserved during a fetch via pendingReads; a later update to the same notification is treated as new unread.
  • Accounts removed from the loaded list purge their caches; an initial empty account list does not purge persistent caches.
  • Tokens must be valid and unexpired; otherwise a connect-token error with a 300s retry is surfaced (SSH credentials alone cannot fetch the inbox).

Review notes / uncertainty

  • The review patch was truncated at next.nextFetchAt = ...; the remainder of GitHubNotificationController.swift (roughly the last ~40 lines) and all other new/changed files are not visible here, so their contents and any behavior in them are uncertain.
  • No test execution results or CI status are included in the supplied data; do not assume tests pass.

Summary by CodeRabbit

  • New Features
    • GitHub notifications are available from the menu bar and repository and welcome screens, with an unread badge when notifications need attention.
    • Browse notifications by connected account, see unread counts and update times, and load more results.
    • Open notifications on GitHub or mark them as read from the notification list.
    • Refresh notifications manually, with refresh availability and account-specific errors shown in the popover.
    • When no accounts are connected, the popover offers a way to connect one.

Introduce controllers, models, and services for fetching and caching GitHub notifications, wire a MenuBarExtra and in-app bell into the main window, and add tests plus a status bar icon asset.
Refresh remote presentation earlier during repository load and resolve preferred remote without querying all remotes.
@coderabbitai

coderabbitai Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 9dd10b84-535d-4647-8cab-c7cedd2e9e19
📥 Commits

Reviewing files that changed from the base of the PR and between f2dae7b and afb02a0.

⛔ Files ignored due to path filters (1)
  • macgit/Resources/Assets.xcassets/small-icon.imageset/small-icon.png is excluded by !**/*.png
📒 Files selected for processing (17)
  • macgit/App/GitHubNotificationController.swift
  • macgit/App/macgitApp.swift
  • macgit/Models/GitHubNotification.swift
  • macgit/Models/GitHubNotificationCache.swift
  • macgit/Models/GitHubNotificationDisplayRow.swift
  • macgit/Models/GitHubNotificationError.swift
  • macgit/Models/GitHubNotificationFetch.swift
  • macgit/Resources/Assets.xcassets/small-icon.imageset/Contents.json
  • macgit/Services/GitHubNotificationService.swift
  • macgit/Views/Common/GitHubNotificationBell.swift
  • macgit/Views/Common/GitHubNotificationPopover.swift
  • macgit/Views/Common/GitHubNotificationRefreshButton.swift
  • macgit/Views/Common/GitHubNotificationRow.swift
  • macgit/Views/MainWindow/ContentView.swift
  • macgit/Views/MainWindow/MainWindowView.swift
  • macgit/Views/MainWindow/WelcomeDashboardContent.swift
  • macgitTests/GitHubNotificationTests.swift

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 1 remain after this review.


📝 Walkthrough

Walkthrough

The app now fetches and caches GitHub notifications, tracks notification read state, and displays notifications in a popover. It also adds notification access to the menu bar and app views, and adjusts remote presentation timing and selection.

Changes

GitHub Notifications

Layer / File(s) Summary
Notification data and API
macgit/Models/GitHubNotification.swift, macgit/Models/GitHubNotificationCache.swift, macgit/Models/GitHubNotificationDisplayRow.swift, macgit/Models/GitHubNotificationError.swift, macgit/Models/GitHubNotificationFetch.swift, macgit/Services/GitHubNotificationService.swift, macgitTests/GitHubNotificationTests.swift
Adds notification and cache models, URL construction for supported subject types, and a service for conditional fetches and thread updates. Tests cover request parameters, response handling, cache behavior, and persistence.
Account refresh and read-state handling
macgit/App/GitHubNotificationController.swift, macgitTests/GitHubNotificationTests.swift
Adds account-specific refresh, retry and freshness checks, cache reconciliation, and read-state updates. Opening an unread notification persists its local viewed state before requesting the API update. Tests cover controller refresh, account removal, and notification opening.
Notification interface and app wiring
macgit/App/macgitApp.swift, macgit/Resources/Assets.xcassets/small-icon.imageset/Contents.json, macgit/Views/Common/GitHubNotification*.swift, macgit/Views/MainWindow/ContentView.swift, macgit/Views/MainWindow/MainWindowView.swift, macgit/Views/MainWindow/WelcomeDashboardContent.swift
Starts and injects the notification controller, adds menu-bar and in-app notification interfaces, and provides account selection, refresh, notification actions, and inbox links.

Remote Presentation

Layer / File(s) Summary
Remote presentation timing and selection
macgit/Views/MainWindow/MainWindowView.swift
Moves the initial remote presentation refresh earlier in loading. A non-nil preferred remote is now used even when it is empty.

Priority: ⬇️ Low

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

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant NotificationPopover
  participant GitHubNotificationController
  participant Cache
  participant GitHubNotificationService
  User->>NotificationPopover: Open notification
  NotificationPopover->>GitHubNotificationController: Open notification
  GitHubNotificationController->>Cache: Persist local viewed state
  GitHubNotificationController->>GitHubNotificationService: Update thread as read
  GitHubNotificationService-->>GitHubNotificationController: Return update result
Loading

Merge Risk: ⚪ Minimal · up to afb02

The identified remote shortcut behavior is unchanged, and notification refresh respects the intended polling interval. No identified issue blocks merging after normal checks.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 43 functions across 16 files. (1 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: a GitHub notification bell, background polling, and a popover.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 2.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 43 functions across 16 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@Tranthanh98
Tranthanh98 merged commit 950e81a into main Oct 7, 2026
2 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.

Add cached GitHub notification inbox with reusable popover and menu bar access

1 participant