Skip to content

fix(notifications): clean up control flow and fix PR/Issue action confirmations#744

Merged
dlvhdr merged 19 commits intodlvhdr:mainfrom
sideshowbarker:dlvhdr/notifications-fixes
Feb 7, 2026
Merged

fix(notifications): clean up control flow and fix PR/Issue action confirmations#744
dlvhdr merged 19 commits intodlvhdr:mainfrom
sideshowbarker:dlvhdr/notifications-fixes

Conversation

@sideshowbarker
Copy link
Contributor

@sideshowbarker sideshowbarker commented Jan 21, 2026

Summary

This PR fixes several bugs in the Notifications view and refactors task handling for better code organization.

Bug Fixes

Notifications view:

  • Fix stale closure in NewModel() that broke all notification actions (close, reopen, merge, ready, update) — closures captured a pointer to a local value that was copied on return
  • Fix double browser open when pressing o on a notification PR
  • Fix PR/Issue action confirmations not working
  • Fix sidebar scrolling in notification PR/Issue views
  • Fix sidebar scrolling when marking notification as done

PR view:

  • Fix r/R refresh not updating reviewer status — the GraphQL cache wasn't being cleared

Refactoring

  • Move pendingNotificationAction state from ui.Model to notificationview.Model
  • Handle confirmation keys directly in notificationview.Update() instead of special-casing in ui.go
  • Consolidate issue close/reopen into tasks package
  • Consolidate remaining view tasks (assign, unassign, comment, label, approve) into tasks package
  • Simplify section ID lookup and hoist subject lookups in executeNotificationAction

@sideshowbarker sideshowbarker changed the title dlvhdr/notifications fixes fix(notifications): clean up control flow and fix PR/Issue action confirmations Jan 21, 2026
@sideshowbarker sideshowbarker force-pushed the dlvhdr/notifications-fixes branch from 9ff588b to d8ccb5c Compare January 21, 2026 08:46
@sideshowbarker sideshowbarker force-pushed the dlvhdr/notifications-fixes branch 2 times, most recently from 0d0bc72 to ae0e6c1 Compare January 28, 2026 06:07
@sideshowbarker sideshowbarker requested a review from dlvhdr January 28, 2026 06:08
@sideshowbarker sideshowbarker force-pushed the dlvhdr/notifications-fixes branch from 239ed0b to afc7134 Compare February 4, 2026 09:46
dlvhdr
dlvhdr previously approved these changes Feb 6, 2026
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.

<3

@dlvhdr
Copy link
Owner

dlvhdr commented Feb 6, 2026

@sideshowbarker just need to resolve the merge conflicts

@sideshowbarker

This comment was marked as outdated.

dlvhdr and others added 18 commits February 7, 2026 17:12
…firmations

- Refactor NotificationsView key handling for clearer control flow:

  - Check for PR/Issue actions first, then handle navigation
  - Always return after updating prView/issueSidebar (fixes tab navigation)
  - Remove redundant MarkAsRead handler (section handles it)

- Fix PR/Issue action confirmations in Notifications view:

  - Add promptConfirmationForNotificationPR/Issue methods
  - Use footer-based confirmation instead of section confirmation
  - Add executeNotificationAction to run tasks after confirmation
  - Add closeIssue/reopenIssue helper methods
This change fixes a bug that caused us to not be showing up-to-date status/
state in Reviewers. The fix causes the cached GraphQL client to be cleared
when a refresh is requested — ensuring the next enrichment invalidates the
cache, and then a request for fresh data is made over the network to GitHub.

Otherwise, without this change, when pressing “r” or “R” to refresh, the
enriched PR data (including reviewers) was being served from a
5-minute-TTL GraphQL cache. That meant that if someone approved the PR,
and then we refreshed in dash, the reviewer status wouldn't update.
…onview

Move the pendingNotificationAction state from ui.Model to
notificationview.Model, consolidating notification-related state in one
place.

Add comprehensive tests for the pending action methods:
- SetPendingPRAction/SetPendingIssueAction with all action types
- Prompt text verification including "ready" → "mark as ready" case
- HasPendingAction, GetPendingAction, ClearPendingAction
- Nil subject handling for both PR and Issue
- Confirmation acceptance (y, Y, Enter) and cancellation
The TestRefresh_ClearsEnrichmentCache and TestRefreshAll_ClearsEnrichmentCache
tests were missing sidebar initialization, causing a nil pointer dereference
when syncSidebar() was called during the refresh key handling.
GetSidebarContentWidth was checking m.ctx.Config == nil but m.ctx itself
could be nil (since NewModel() sets ctx: nil), causing a panic in tests.
The tests were calling m.Update() which triggers refresh logic that
calls ctx.StartTask(). Without initializing StartTask to a no-op
function, this caused a nil pointer dereference.
The tests were triggering syncProgramContext which calls UpdateProgramContext
on all model components (tabs, footer, prView, issueSidebar, branchSidebar,
notificationView). Without initializing these components, nil pointer
dereferences occurred.
…te method

Move the confirmation key handling from ui.go into notificationview's
new Update() method, matching the pattern used by prview. The component
now owns its confirmation behavior via a callback set by ui.go.

Changes:
- Add Update() method to notificationview that handles y/Y/Enter to
  confirm and any other key to cancel
- Add onConfirmAction callback field and SetOnConfirmAction() setter
- Modify executeNotificationAction() to accept action as parameter
- Set callback in initComponents() during initialization

This removes special-case handling from ui.go and makes the component
self-contained.
Remove early returns when handling PR/Issue keybindings in notification
view so that key messages reach the sidebar's Update method. This fixes
Ctrl+D and other scroll keys not working in the sidebar.
Same fix as 6619183 — remove early return so key messages reach the
sidebar's Update method.
Use m.currSectionId directly instead of calling getCurrSection()
and GetId().
Fetch PR and Issue subjects once at the start of the function instead
of redundantly in each switch case.
Move CloseIssue and ReopenIssue functions to tasks/issue.go, following
the same pattern as PR operations in tasks/pr.go. This eliminates
duplicate implementations that existed in ui.go and issuessection.

Also moves UpdateIssueMsg to the tasks package for consistency with
UpdatePRMsg.
When issueview.Model is not properly initialized (e.g., in tests that create
partial models), the ac pointer is nil. This caused a panic when
syncProgramContext called UpdateProgramContext on all components.
- Document the `s` key for switching to PRs view
- Update confirmation prompt section to reflect current architecture where
  pendingAction is managed by notificationView.Model with callback pattern
Move the issueview task methods (assign, unassign, comment, label) and
prview task methods (assign, unassign, comment, approve) into the
centralized tasks package, using the same fireTask/GitHubTask pattern
established for close/reopen in c0c2605.
The OpenGithub case in the NotificationsView switch appended
openBrowser() to cmds but didn't return, so the message also
propagated to updateCurrentSection — which forwarded the same
`o` key to the notification section's Open handler, opening the
browser a second time.
@sideshowbarker sideshowbarker force-pushed the dlvhdr/notifications-fixes branch from 1429149 to 49ec092 Compare February 7, 2026 08:19
NewModel() creates a local Model value and sets up closures/callbacks
that capture &m. Since the function returns m by value, the caller gets
a copy while the closures permanently reference the original (now-stale)
model. Any state set on the live model during the UI lifecycle (e.g.
subjectPR via SetSubjectPR) is invisible to the stale copy.

This caused executeNotificationAction to always read nil from
GetSubjectPR()/GetSubjectIssue(), silently dropping every notification
action (close, reopen, merge, ready, update for both PRs and issues).

Fix: remove the callback pattern from notificationView entirely. Update()
now returns the confirmed action string, and the outer ui.go Update
calls executeNotificationAction directly on the live model.

Also remove wasted renderRunningTask()/footer.SetRightSection() calls
from the StartTask closure, which wrote to the stale model's footer.
The spinner.TickMsg handler already refreshes the footer correctly on
the live model.
@sideshowbarker sideshowbarker force-pushed the dlvhdr/notifications-fixes branch from 49ec092 to 7c5a3bc Compare February 7, 2026 08:22
@sideshowbarker
Copy link
Contributor Author

@sideshowbarker just need to resolve the merge conflicts

Merge conflicts all resolved, and now all green 🍀

@sideshowbarker sideshowbarker requested a review from dlvhdr February 7, 2026 08:26
@dlvhdr dlvhdr merged commit 76ae15d into dlvhdr:main Feb 7, 2026
3 checks passed
@sideshowbarker sideshowbarker deleted the dlvhdr/notifications-fixes branch February 7, 2026 10:43
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.

2 participants