Skip to content

Conversation

@sideshowbarker
Copy link
Contributor

@sideshowbarker sideshowbarker commented Jan 8, 2026

Summary

This change adds a new Notifications view to dash that displays GH notifications — allowing you to triage you GH "inbox" within dash. Fixes #141

  • View unread notifications with type icons (PR, Issue, Discussion, Release)
  • Mark notifications as done (d) or read (m)
  • Mark all notifications as done (D) or read (M)
  • Unsubscribe from notification threads (u)
  • Bookmark notifications to keep them visible after marking read (b)
  • Open notifications in browser (o) or view in sidebar (Enter)
  • Sort by repository (S)
  • Filter by repo:owner/name and is:unread/read/all/done
  • New-comment count indicator for PR/Issue notifications
  • Auto-scroll to latest comment when viewing
  • Active view indicator styled with bold text and gold color for notifications

Bookmark system:

  • Local storage in ~/.config/gh-dash/bookmarks.json
  • Bookmarked items appear in default view even when read
  • Explicit "is:unread" search excludes bookmarked+read items

The implementation follows existing patterns from PR and Issue views, but in this case with requiring you to explicitly/intentionally initiate the "view" action — to prevent accidental "read" marking.

How did you test this change?

Added new tests:

  • tui/components/notificationrow/data_test.go
  • notificationssection/filters_test.go

Images/Videos

image image image

@sideshowbarker sideshowbarker changed the title add Notifications dashboard Notifications dashboard Jan 8, 2026
@mchisolm0
Copy link
Contributor

Looks awesome! Wanted to mention that it seems the ? help menu seems to needs a s to switch to notifications and move the s to switch to prs to the notifications context.

Video
CleanShot.2026-01-08.at.20.08.14.mp4

@sideshowbarker
Copy link
Contributor Author

Looks awesome! Wanted to mention that it seems the ? help menu seems to needs a s to switch to notifications and move the s to switch to prs to the notifications context.

Thanks for catching that~ I’ve fixed it now, and pushed an update to this branch

@sideshowbarker sideshowbarker force-pushed the notifications branch 2 times, most recently from bc4e144 to c74dc61 Compare January 10, 2026 00:47
@dlvhdr
Copy link
Owner

dlvhdr commented Jan 10, 2026

Hey man, I did a quick mockup of how I would like this to look.
If you don't have time to take it there, no worries, we can always do it later.
But it's not too different.

Things to note:

  • Every row should have an icon. Rows that don't look out of place. Let's try and find one that fits each notification type.
  • Rows are 3 lines high to fit all the info clearly (I might make PRs / issues 3 line high as well).
  • The activity column I am not sure about, since right now it shows just the number of new comments but maybe we can show there additional info like the content of a comment. Or we can do what github does on its mobile app which is to show the comment content where I just wrote "@Someone commented".
image

@dlvhdr
Copy link
Owner

dlvhdr commented Jan 10, 2026

Here's how I would show the preview pane:
image

@sideshowbarker
Copy link
Contributor Author

Rows are 3 lines high to fit all the info clearly (I might make PRs / issues 3 line high as well).

What if the title is too long to fit in one line? e.g., if the user is showing the Preview?

  • If we wrap the title, the we end up with 4 lines rather than 3
  • if we want to keep it at exactly 3 lines, we have to truncate/elide the title

@dlvhdr
Copy link
Owner

dlvhdr commented Jan 10, 2026

Rows are 3 lines high to fit all the info clearly (I might make PRs / issues 3 line high as well).

What if the title is too long to fit in one line? e.g., if the user is showing the Preview?

  • If we wrap the title, the we end up with 4 lines rather than 3

  • if we want to keep it at exactly 3 lines, we have to truncate/elide the title

I think it's fine to put ellipsis there

Copy link
Owner

@dlvhdr dlvhdr left a comment

Choose a reason for hiding this comment

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

haven't finished going over all files, but there's enough to start.
thanks for putting all the work in! it looks amazing :)

@sideshowbarker

This comment was marked as outdated.

@sideshowbarker sideshowbarker force-pushed the notifications branch 4 times, most recently from 7457b67 to f3a1fd3 Compare January 11, 2026 19:38
Repository owner deleted a comment from cezary13k Jan 13, 2026
Repository owner deleted a comment from cezary13k Jan 17, 2026
Repository owner deleted a comment from cezary13k Jan 17, 2026
This change adds a new Notifications view to dash that displays GH
notifications — allowing you to triage your GH "inbox" within dash.

- View unread notifications with type icons (PR, Issue, Discussion, Release)
- Mark notifications as done (d) or read (m)
- Mark all notifications as done (D) or read (M)
- Unsubscribe from notification threads (u)
- Bookmark notifications to keep them visible after marking read (b)
- Open notifications in browser (o) or view in sidebar (Enter)
- Sort by repository (S)
- Filter by repo:owner/name and is:unread/read/all/done
- Toggle smart filtering to current repo (t)
- New-comment count indicator for PR/Issue notifications
- Actor display: shows @username of who triggered the notification
- Auto-scroll to latest comment when viewing

Bookmark system:
- Local storage in ~/.config/gh-dash/bookmarks.json
- Bookmarked items appear in default view even when read
- Explicit "is:unread" search excludes bookmarked+read items

Actor display:
- Fetches author from latest_comment_url, falls back to PR/Issue author
- Appends @username to notification title (helps identify spam)
- Color configurable via theme.colors.text.actor

The implementation follows existing patterns from PR and Issue views,
but in this case with requiring you to explicitly/intentionally initiate
the "view" action — to prevent accidental "read" marking.
Implements maintainer feedback from PR review:

Row layout now shows three lines per notification:
- Line 1: repo/name #number + bookmark icon if bookmarked (SecondaryText for unread, FaintText for read)
- Line 2: Title (PrimaryText, bold for unread notifications)
- Line 3: Activity description (FaintText color)

Activity descriptions are generated based on notification reason and actor:
- comment: "@username commented on this pull request/issue"
- review_requested: "@username requested your review"
- mention: "@username mentioned you"
- author: "Activity on your thread"
- assign: "You were assigned"
- state_change: "Pull request/Issue state changed"
- ci_activity: "CI activity"
- subscribed: "@username commented on this pull request/issue"

Preview pane prompt improvements:
- Added "S sort by repo" to the actions list
- "(Note: this will mark it as read)" now appears for all notification types
- Non-PR/Issue types show "Press Enter to open in browser" (simplified)

Technical changes:
- Bookmark icon moved to end of line 1 (removed separate bookmark column)
- Row content uses raw ANSI codes without resets to preserve background colors
- Title truncation handled dynamically by table based on actual column width
- Table adds ellipsis when truncating multi-line content
- getStylePrefix() helper extracts ANSI codes from lipgloss styles without reset
- Columns reduced from 5 to 4 (type, title block, activity count, timestamp)
- Use blue dot below icon to indicate unread notifications instead of
  faint text styling — the dot is the sole visual indicator of read status

- Keep notifications marked as read visible in the inbox until the user
  manually refreshes or restarts (sessionMarkedRead tracking)

- Respect smartFilteringAtLaunch setting — scope to current repo by
  default when running from a clone directory, show repo:owner/name
  in search input to indicate active filtering

- Footer view switcher improvements:
  - Gold/yellow color for notification bell when active
  - Solid bell icon for active, outline bell for inactive

- Add column-alignment documentation (align: left/right/center)
…ow runs

The GH API just returns subject.url=null for CheckSuite notifications —
making it impossible to deterministically identify the specific workflow
it came from, and directly link to it. So, this change:

- Adds async URL resolution that fetches recent workflow runs, and finds
  the best match based on timestamp proximity to the notification
- Initially shows /actions page as a placeholder; updates to specific
  run URL once resolved
- Adds ResolvedUrl field to notification data for async-resolved URLs
- Exposes a FindBestWorkflowRunMatch() function for testability
- Adds a bunch of tests for workflow-run matching logic
- Add pagination support for notifications (fetches more as user scrolls)
- Add `defaults.notificationsLimit` config option (default: 20)
- Update docs and DESIGN.md with new configuration
…highlighting

All notification row columns now render 3 lines to match the Title column.
This ensures the selected row background color extends properly across all
columns. Uses raw ANSI codes without resets to preserve parent background.
…ation content

When viewing a PR or Issue notification in the preview pane, the keybindings
from the PR and Issue tabs are now available:

PR notifications:
- [/] sidebar tabs, v approve, a assign, A unassign, c comment
- d diff, C checkout, x close, W ready, X reopen, m merge, u update
- e summary view more

Issue notifications:
- L label, a assign, A unassign, c comment, x close, X reopen

Note: PR/Issue keybindings take precedence over notification keybindings
when viewing content (e.g., 'd' triggers diff instead of markAsDone).
…hboard

This change adds multiple configurable sections in the Notifications
dashboard — to parallel the behavior we have for PRs and Issues. Users
can define their own custom sections — just as for PRs and Issues.

Default sections:

- All, Created, Participating, Mentioned, Review Requested, Assigned,
  Subscribed, Team Mentioned

New features:

- reason: filter support (author, comment, mention, review-requested,
  assign, subscribed, team-mention, state-change, ci-activity)
- reason:participating meta-filter expands to multiple reasons
- Search section (magnifying glass) for one-off queries
- Search section respects smartFilteringAtLaunch setting
- Client-side reason filtering after API fetch
This changes fetching of notifications such that now, bookmarked and
session-marked-read notifications are fetched separately by thread ID on
the first page — allowing the main fetch to use the user's intended
filter (“show unread” by default). That keeps unread notifications
consolidated, and keeps pagination working correctly.

Otherwise, without this change, when bookmarks or session-marked-read
notifications exist, the fetch logic switched to “all=true” to include
read notifications. But that causes unread notifications to be scattered
across many pages (mixed with “read” ones) — breaking pagination: users
would only see ~20 notifications instead of all their unread items.
This change adds local tracking of “Done” notification IDs in a
persistent local store (“~/.local/state/gh-dash/done.json”) — similar to
how we handle Bookmarked notifications. And so now we never show the
user any notifications they have locally marked as “Done” in dash.

Otherwise, without this change, we have a fundamental problem: GitHub’s
“mark as done” API doesn’t actually delete notifications; instead, they
still appear in “all=true” API responses. And that causes users to see
those “Done” notifications when they filter to “is:read” or “is:all”.

This change also refactors our BookmarkStore around a shared
NotificationIDStore implementation that we use for our DoneStore, too.
… locally

This change ensures that users see a full page of results even when many
notifications have been marked as done locally — by making these changes:

- Switch to calculating HasNextPage _before_ read-state filtering, based
  on raw API response count
- Add a loop that fetches additional pages until the requested limit is
  reached, or all pages are exhausted

Otherwise, without this change: When filtering to “is:read”, most
notifications might be filtered out by the local “Done” store, leaving
very few visible. So, pagination would end prematurely, because HasNextPage
was calculated _after_ read-state filtering. So, if 20 notifications were
fetched but only 5 were read, HasNextPage would be false (5 < 20).
…avior

- Add notification-section to docs sidebar (astro.config.mjs)
- Change getStateFilePath to return (string, error) for proper error handling
- Update outline bell icon to nf-fa-bell_o (U+F0A2)
- Apply gold color to both icon and label in active notifications view
- Extract viewSeparator const in footer
- Use distinct icons for open/closed issues (U+F41B/U+F41D)
- Update discussion icon to nf-oct-comment_discussion (U+F442) with white color
- Update release icon to nf-oct-tag (U+F412) with blue color
- Extract GetStylePrefix to utils package for reuse
- Add clarifying comment for markAllAsDone scope
- Advance cursor to next notification after marking as read
Move the notification subject cache (subjectPR, subjectIssue, subjectId)
from the top-level Model in ui.go to notificationview.Model where it
logically belongs. This improves encapsulation by keeping the cached
subject data in the component responsible for displaying it.
… descriptors

Have prview.Update() and issueview.Update() recognize all PR/Issue keys
and return action descriptors, allowing the UI to forward key messages
and handle the returned actions. This reduces duplication in notification
view key handling and means adding a new keybinding only requires changes
in the respective view's Update().

Changes:
- Add PRAction type and PRActionType enum in new action.go file
- Add IssueAction type and IssueActionType enum
- Change prview.Update() signature to return (Model, tea.Cmd, *PRAction)
- Change issueview.Update() signature to return (Model, tea.Cmd, *IssueAction)
- Add key matching for all PR/Issue keys in respective Update() functions
- Update all call sites in ui.go
- Consolidate notification view key handling to use returned actions
- Add comprehensive tests for action types and key handling
…rity

- Extract markNotificationAsRead helper to consolidate duplicate
  notification read state update logic
- Extract updateNotificationSections helper for section updates
- Rename notification view functions for better clarity
Use tea.Batch to run the mark-as-read API call in parallel with fetching
PR/Issue data, so the content displays without waiting for the mark-as-read
to complete. This matches the pattern already used in the default case.
…ection module

Move openInBrowser, DiffPR, and CheckoutPR commands from ui.go to
notificationssection/commands.go, following the pattern established by
prssection (checkout.go, diff.go).

- Add openInBrowser() method to handle the Open key in the section
- Add DiffPR() and CheckoutPR() standalone functions that accept PR data
- Update ui.go to pass Open key to section and call standalone functions
- Add tests for DiffPR and CheckoutPR
- Document the command architecture in DESIGN.md
Move the DiffPR function from notificationssection to the common package
so it can be shared between prssection and notificationssection without
duplication.
…tifications

Parse workflow-run notification titles for “failed”/“succeeded” keywords
and indicate the status in dash by setting the icon accordingly, in the
appropriate green or not-green color — similar to what gitify does.
@sideshowbarker sideshowbarker force-pushed the notifications branch 2 times, most recently from 7218e69 to 245daed Compare January 17, 2026 23:32
- Add notificationrow_test.go with tests for reason descriptions,
  CheckSuite status parsing, activity rendering, and state handling
- Add filter parsing edge case tests for whitespace, duplicate filters,
  and combined filter scenarios
- Add bookmark store edge case tests for file I/O errors, special
  characters, and idempotent operations
- Add GetStylePrefix tests for various lipgloss style types
- Parallelize API calls for missing bookmarked/session-marked-read
  notifications using goroutines instead of sequential fetches
- Convert filter slices to maps for O(1) lookups (reason filters,
  repo filters, bookmark IDs)
- Make bookmark/done store file I/O async to avoid blocking UI
- Add Flush() method for test synchronization with async saves
Change prview.Update from returning (Model, tea.Cmd, *PRAction) to the
standard Bubble Tea signature (Model, tea.Cmd). Key-to-action mapping
is now handled by a separate MsgToAction function that callers invoke
after checking IsTextInputBoxFocused().

This makes the API more idiomatic and explicit about when action
detection should occur.
Extract repeated patterns into reusable helper methods:
- openSidebarForPRInput: opens sidebar with GoToFirstTab for PR actions
- openSidebarForInput: opens sidebar and syncs content
- promptConfirmation: shows confirmation prompt on section

Reduces 16 instances of duplicated 5–6 line blocks across PRsView,
IssuesView, and NotificationsView handlers to single-line calls.
The NotificationIDStore.Add() method spawns async goroutines calling
save(). Multiple concurrent saves could race on os.WriteFile, which
truncates before writing — causing readers to see empty files.

Fix by using unique temp files (os.CreateTemp) with atomic rename.
Expose the PR author's username as {{.Author}} in custom keybinding
command templates for both PR and branch views.
sideshowbarker and others added 2 commits January 20, 2026 07:37
…to prView)

This change makes us unconditionally sync the sidebar and return after
updating prView — ensuring tab changes get reflected in the UI.

Otherwise, without this change, tab navigation in the PR sidebar wasn't
working when viewing a PR notification. The code only returned after
prView.Update() when prCmd was non-nil – but tab navigation
(carousel.MoveLeft/MoveRight) updates state without returning a command.
@dlvhdr dlvhdr merged commit 8bb74d7 into dlvhdr:main Jan 20, 2026
3 of 4 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.

[Feature Request] Support notifications section

3 participants