From b162fea003da0612954b1517f3d1f55549871c6e Mon Sep 17 00:00:00 2001 From: Thomas Karpiniec Date: Wed, 11 Feb 2026 04:05:34 +0000 Subject: [PATCH] appview: re-index issues and pulls when labels are modified Signed-off-by: Thomas Karpiniec --- appview/indexer/notifier.go | 18 ++++++++++++++++++ appview/labels/labels.go | 18 ++++++++++++++++++ appview/notify/logging_notifier.go | 10 ++++++++++ appview/notify/merged_notifier.go | 8 ++++++++ appview/notify/notifier.go | 6 ++++++ appview/state/router.go | 1 + appview/notify/db/db.go | 3 +++ 7 file(s) changed, 64 insertion(s)(+), 0 deletion(s)(-) diff --git a/appview/indexer/notifier.go b/appview/indexer/notifier.go --- a/appview/indexer/notifier.go +++ b/appview/indexer/notifier.go @@ -38,6 +38,24 @@ } } +func (ix *Indexer) NewIssueLabelOp(ctx context.Context, issue *models.Issue) { + l := log.FromContext(ctx).With("notifier", "indexer", "issue", issue) + l.Debug("reindexing issue after label change") + err := ix.Issues.Index(ctx, *issue) + if err != nil { + l.Error("failed to index an issue", "err", err) + } +} + +func (ix *Indexer) NewPullLabelOp(ctx context.Context, pull *models.Pull) { + l := log.FromContext(ctx).With("notifier", "indexer", "pull", pull) + l.Debug("reindexing pull after label change") + err := ix.Pulls.Index(ctx, pull) + if err != nil { + l.Error("failed to index a pr", "err", err) + } +} + func (ix *Indexer) NewPull(ctx context.Context, pull *models.Pull) { l := log.FromContext(ctx).With("notifier", "indexer", "pull", pull) l.Debug("indexing new pr") diff --git a/appview/labels/labels.go b/appview/labels/labels.go --- a/appview/labels/labels.go +++ b/appview/labels/labels.go @@ -13,6 +13,7 @@ "tangled.org/core/appview/db" "tangled.org/core/appview/middleware" "tangled.org/core/appview/models" + "tangled.org/core/appview/notify" "tangled.org/core/appview/oauth" "tangled.org/core/appview/pages" "tangled.org/core/appview/validator" @@ -34,6 +35,7 @@ logger *slog.Logger validator *validator.Validator enforcer *rbac.Enforcer + notifier notify.Notifier } func New( @@ -42,6 +44,7 @@ db *db.DB, validator *validator.Validator, enforcer *rbac.Enforcer, + notifier notify.Notifier, logger *slog.Logger, ) *Labels { return &Labels{ @@ -51,6 +54,7 @@ logger: logger, validator: validator, enforcer: enforcer, + notifier: notifier, } } @@ -244,6 +248,20 @@ // clear aturi when everything is successful atUri = "" + + subject := syntax.ATURI(subjectUri) + if subject.Collection() == tangled.RepoIssueNSID { + issues, err := db.GetIssues(l.db, orm.FilterEq("at_uri", subjectUri)) + if err == nil && len(issues) == 1 { + l.notifier.NewIssueLabelOp(r.Context(), &issues[0]) + } + } + if subject.Collection() == tangled.RepoPullNSID { + pulls, err := db.GetPulls(l.db, orm.FilterEq("at_uri", subjectUri)) + if err == nil && len(pulls) == 1 { + l.notifier.NewPullLabelOp(r.Context(), pulls[0]) + } + } l.pages.HxRefresh(w) } diff --git a/appview/notify/logging_notifier.go b/appview/notify/logging_notifier.go --- a/appview/notify/logging_notifier.go +++ b/appview/notify/logging_notifier.go @@ -59,6 +59,16 @@ l.inner.DeleteIssue(ctx, issue) } +func (l *loggingNotifier) NewIssueLabelOp(ctx context.Context, issue *models.Issue) { + ctx = tlog.IntoContext(ctx, tlog.SubLogger(l.logger, "NewIssueLabelOp")) + l.inner.NewIssueLabelOp(ctx, issue) +} + +func (l *loggingNotifier) NewPullLabelOp(ctx context.Context, pull *models.Pull) { + ctx = tlog.IntoContext(ctx, tlog.SubLogger(l.logger, "NewPullLabelOp")) + l.inner.NewPullLabelOp(ctx, pull) +} + func (l *loggingNotifier) NewFollow(ctx context.Context, follow *models.Follow) { ctx = tlog.IntoContext(ctx, tlog.SubLogger(l.logger, "NewFollow")) l.inner.NewFollow(ctx, follow) diff --git a/appview/notify/merged_notifier.go b/appview/notify/merged_notifier.go --- a/appview/notify/merged_notifier.go +++ b/appview/notify/merged_notifier.go @@ -58,6 +58,14 @@ m.fanout(func(n Notifier) { n.DeleteIssue(ctx, issue) }) } +func (m *mergedNotifier) NewIssueLabelOp(ctx context.Context, issue *models.Issue) { + m.fanout(func(n Notifier) { n.NewIssueLabelOp(ctx, issue) }) +} + +func (m *mergedNotifier) NewPullLabelOp(ctx context.Context, pull *models.Pull) { + m.fanout(func(n Notifier) { n.NewPullLabelOp(ctx, pull) }) +} + func (m *mergedNotifier) NewFollow(ctx context.Context, follow *models.Follow) { m.fanout(func(n Notifier) { n.NewFollow(ctx, follow) }) } diff --git a/appview/notify/notifier.go b/appview/notify/notifier.go --- a/appview/notify/notifier.go +++ b/appview/notify/notifier.go @@ -25,6 +25,9 @@ NewPullComment(ctx context.Context, comment *models.PullComment, mentions []syntax.DID) NewPullState(ctx context.Context, actor syntax.DID, pull *models.Pull) + NewIssueLabelOp(ctx context.Context, issue *models.Issue) + NewPullLabelOp(ctx context.Context, pull *models.Pull) + UpdateProfile(ctx context.Context, profile *models.Profile) NewString(ctx context.Context, s *models.String) @@ -49,6 +52,9 @@ } func (m *BaseNotifier) NewIssueState(ctx context.Context, actor syntax.DID, issue *models.Issue) {} func (m *BaseNotifier) DeleteIssue(ctx context.Context, issue *models.Issue) {} + +func (m *BaseNotifier) NewIssueLabelOp(ctx context.Context, issue *models.Issue) {} +func (m *BaseNotifier) NewPullLabelOp(ctx context.Context, pull *models.Pull) {} func (m *BaseNotifier) NewFollow(ctx context.Context, follow *models.Follow) {} func (m *BaseNotifier) DeleteFollow(ctx context.Context, follow *models.Follow) {} diff --git a/appview/state/router.go b/appview/state/router.go --- a/appview/state/router.go +++ b/appview/state/router.go @@ -340,6 +340,7 @@ s.db, s.validator, s.enforcer, + s.notifier, log.SubLogger(s.logger, "labels"), ) return ls.Router() diff --git a/appview/notify/db/db.go b/appview/notify/db/db.go --- a/appview/notify/db/db.go +++ b/appview/notify/db/db.go @@ -206,6 +206,9 @@ // no-op for now } +func (n *databaseNotifier) NewIssueLabelOp(ctx context.Context, issue *models.Issue) {} +func (n *databaseNotifier) NewPullLabelOp(ctx context.Context, pull *models.Pull) {} + func (n *databaseNotifier) NewFollow(ctx context.Context, follow *models.Follow) { actorDid := syntax.DID(follow.UserDid) recipients := sets.Singleton(syntax.DID(follow.SubjectDid)) -- tangled.sh