detached 063865b

fix(events): deliver repo.updated and repo.deleted to owner watchers and refresh the inbox

commit
063865bc65d6c8da4a64891a292cb92e187005be
author
brice · · 2026-10-19 06:49 UTC
parent
bc6524c
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
2 files · +16 -5
M internal/adapters/web/inbox.go +3 -2
@@ -155,12 +155,13 @@ func (s *Server) inboxCount(ctx context.Context) (n int, show bool) {
155155 return ov.Counts.MergeRequests + ov.Counts.Issues, true
156156 }
157157
158-// inbox renders the fragments an event of a merge request or an issue changes
158+// inbox renders the fragments an event of a merge request, an issue or a repository changes
159159 // on the inbox page: the counters, the filter and the two lists.
160160 func (l *liveStream) inbox(ctx context.Context, we ports.WatchEvent) ([]fragment, error) {
161161 switch we.Event.(type) {
162162 case domain.MergeRequestOpened, domain.MergeRequestMerged, domain.MergeRequestClosed, domain.MergeRequestReady, domain.CommentAdded,
163- domain.IssueOpened, domain.IssueClosed, domain.IssueReopened, domain.IssueCommented:
163+ domain.IssueOpened, domain.IssueClosed, domain.IssueReopened, domain.IssueCommented,
164+ domain.RepoUpdated, domain.RepoDeleted:
164165 default:
165166 return nil, nil
166167 }
@@ -155,12 +155,13 @@ func (s *Server) inboxCount(ctx context.Context) (n int, show bool) {
155 return ov.Counts.MergeRequests + ov.Counts.Issues, true155 return ov.Counts.MergeRequests + ov.Counts.Issues, true
156 }156 }
157 157
158-// inbox renders the fragments an event of a merge request or an issue changes158+// inbox renders the fragments an event of a merge request, an issue or a repository changes
159 // on the inbox page: the counters, the filter and the two lists.159 // on the inbox page: the counters, the filter and the two lists.
160 func (l *liveStream) inbox(ctx context.Context, we ports.WatchEvent) ([]fragment, error) {160 func (l *liveStream) inbox(ctx context.Context, we ports.WatchEvent) ([]fragment, error) {
161 switch we.Event.(type) {161 switch we.Event.(type) {
162 case domain.MergeRequestOpened, domain.MergeRequestMerged, domain.MergeRequestClosed, domain.MergeRequestReady, domain.CommentAdded,162 case domain.MergeRequestOpened, domain.MergeRequestMerged, domain.MergeRequestClosed, domain.MergeRequestReady, domain.CommentAdded,
163- domain.IssueOpened, domain.IssueClosed, domain.IssueReopened, domain.IssueCommented:163+ domain.IssueOpened, domain.IssueClosed, domain.IssueReopened, domain.IssueCommented,
164+ domain.RepoUpdated, domain.RepoDeleted:
164 default:165 default:
165 return nil, nil166 return nil, nil
166 }167 }
M internal/usecase/events.go +13 -3
@@ -270,7 +270,7 @@ func (e *Events) parseID(id string) (uint64, bool) {
270270 type watch struct {
271271 p domain.Principal
272272 home bool
273- owner bool // the owner topic: merge request and issue events of every repository
273+ owner bool // the owner topic: merge request, issue, repo update and deletion events of every repository
274274 repos map[domain.RepoName]bool
275275
276276 checked time.Time // when the token store last confirmed the principal
@@ -281,7 +281,7 @@ func (w *watch) wants(name domain.RepoName) bool { return w.home || w.repos[name
281281 // wantsEvent is wants for an event: the owner topic also follows the events
282282 // about merge requests and issues of every repository.
283283 func (w *watch) wantsEvent(name domain.RepoName, ev domain.Event) bool {
284- return w.wants(name) || (w.owner && isItemEvent(ev))
284+ return w.wants(name) || (w.owner && (isItemEvent(ev) || isRepoLifecycleEvent(ev)))
285285 }
286286
287287 // parseTopics validates the topics of a watch. A repository topic needs a
@@ -495,7 +495,7 @@ func (e *Events) deliver(ctx context.Context, w *watch, be bufferedEvent, send f
495495 return send(ports.WatchEvent{Gap: true})
496496 case domain.RepoDeleted:
497497 // The repository is gone: use the visibility it had.
498- if !w.wants(ev.Repo) || !canReadAs(w.p, ev.Repo, ev.Visibility) {
498+ if !w.wantsEvent(ev.Repo, ev) || !canReadAs(w.p, ev.Repo, ev.Visibility) {
499499 return nil
500500 }
501501 return send(out)
@@ -594,6 +594,16 @@ func isIssueEvent(ev domain.Event) bool {
594594 return false
595595 }
596596
597+// isRepoLifecycleEvent reports whether ev is a repository update or deletion:
598+// the owner topic follows them, for they change what the inbox lists.
599+func isRepoLifecycleEvent(ev domain.Event) bool {
600+ switch ev.(type) {
601+ case domain.RepoUpdated, domain.RepoDeleted:
602+ return true
603+ }
604+ return false
605+}
606+
597607 // isItemEvent reports whether ev is about a merge request or an issue.
598608 func isItemEvent(ev domain.Event) bool {
599609 switch ev.(type) {
@@ -270,7 +270,7 @@ func (e *Events) parseID(id string) (uint64, bool) {
270 type watch struct {270 type watch struct {
271 p domain.Principal271 p domain.Principal
272 home bool272 home bool
273- owner bool // the owner topic: merge request and issue events of every repository273+ owner bool // the owner topic: merge request, issue, repo update and deletion events of every repository
274 repos map[domain.RepoName]bool274 repos map[domain.RepoName]bool
275 275
276 checked time.Time // when the token store last confirmed the principal276 checked time.Time // when the token store last confirmed the principal
@@ -281,7 +281,7 @@ func (w *watch) wants(name domain.RepoName) bool { return w.home || w.repos[name
281 // wantsEvent is wants for an event: the owner topic also follows the events281 // wantsEvent is wants for an event: the owner topic also follows the events
282 // about merge requests and issues of every repository.282 // about merge requests and issues of every repository.
283 func (w *watch) wantsEvent(name domain.RepoName, ev domain.Event) bool {283 func (w *watch) wantsEvent(name domain.RepoName, ev domain.Event) bool {
284- return w.wants(name) || (w.owner && isItemEvent(ev))284+ return w.wants(name) || (w.owner && (isItemEvent(ev) || isRepoLifecycleEvent(ev)))
285 }285 }
286 286
287 // parseTopics validates the topics of a watch. A repository topic needs a287 // parseTopics validates the topics of a watch. A repository topic needs a
@@ -495,7 +495,7 @@ func (e *Events) deliver(ctx context.Context, w *watch, be bufferedEvent, send f
495 return send(ports.WatchEvent{Gap: true})495 return send(ports.WatchEvent{Gap: true})
496 case domain.RepoDeleted:496 case domain.RepoDeleted:
497 // The repository is gone: use the visibility it had.497 // The repository is gone: use the visibility it had.
498- if !w.wants(ev.Repo) || !canReadAs(w.p, ev.Repo, ev.Visibility) {498+ if !w.wantsEvent(ev.Repo, ev) || !canReadAs(w.p, ev.Repo, ev.Visibility) {
499 return nil499 return nil
500 }500 }
501 return send(out)501 return send(out)
@@ -594,6 +594,16 @@ func isIssueEvent(ev domain.Event) bool {
594 return false594 return false
595 }595 }
596 596
597+// isRepoLifecycleEvent reports whether ev is a repository update or deletion:
598+// the owner topic follows them, for they change what the inbox lists.
599+func isRepoLifecycleEvent(ev domain.Event) bool {
600+ switch ev.(type) {
601+ case domain.RepoUpdated, domain.RepoDeleted:
602+ return true
603+ }
604+ return false
605+}
606+
597 // isItemEvent reports whether ev is about a merge request or an issue.607 // isItemEvent reports whether ev is about a merge request or an issue.
598 func isItemEvent(ev domain.Event) bool {608 func isItemEvent(ev domain.Event) bool {
599 switch ev.(type) {609 switch ev.(type) {

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 2

Tags 43

↑↓ moveenter openesc close