inboxqueue

package
v0.2.0-rc.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 11, 2026 License: MIT Imports: 12 Imported by: 0

README

inboxqueue

Builds the app's Inbox from the daemon's own state: every open pull request with what it waits for, which saved inboxes hold it, how many pull requests wait on the person, and how many each inbox lists. The app reads it instead of matching every inbox's query against every pull request itself, and the desktop app's dock badge, tray text and tray icon read the total.

It follows the app's queue (upNext and kindOf in app/src/up-next.tsx) over the daemon's state, read on each request:

  • the cached review index, one pull request per repository and number across clones (the clone with a saved review, then a readable store, then a clone, speaks for it), so a pull request held by several clones counts once;
  • the job queue, since a queued or running fix leaves the author nothing to do;
  • the review groups, since a stacked pull request with an open member under it is not ready to merge;
  • the ui-state inbox record, whose snoozes (until a time, or while the head stays the one it was held on) hide a pull request, and whose archives (archived) hide one for good;
  • the saved inboxes (internal/inboxes).

Kinds

Each open pull request is one item with a kind, which is also what an inbox's waiting= filter reads:

  • review, or clone when it needs a clone: the user's review is requested, or it is assigned to them and they did not write it;
  • for their own: fix (changes requested, a conflict, failing checks or unresolved threads), merge (ready, not a draft, checks not running, and not stacked on an open member of its stack) or update (behind a base they can push to);
  • fix with fixing set: their own that an agent is fixing now, which is not in the queue;
  • other: someone else's that waits on nothing from them;
  • "": their own that waits on others.

Counts

The total (count, and {"waiting":N} on GET /api/index?view=waiting) is the number of distinct items in the queue, neither snoozed nor archived: review, clone, and fix, merge and update without fixing. It is the same number as the total on the app's sidebar Inbox heading, and this package is where that definition is kept. Saved inboxes play no part: the total includes pull requests that match no inbox, counts one in several inboxes once, and ignores each inbox's badge switch. With nothing waiting it is zero.

An inbox's own count is what its sidebar row shows: the items it holds, neither snoozed nor archived, that are in the queue or someone else's (other).

Matching

An inbox holds the items its query matches with internal/prfilter, after its older parts (what, owners, risk, repositories, bots) are folded into it as the app folds them. A query that does not read narrows nothing; an empty one holds every open pull request. Items whose kind is "" match waiting= with no kind, so waiting= never holds them.

API

GET /api/inbox answers:

{
  "count": 2,
  "items": [{ "key": "acme/app#12", "kind": "review", "inboxes": ["<id>"] },
            { "key": "acme/app#13", "kind": "fix", "fixing": true, "snoozed": true, "inboxes": [] }],
  "inboxes": [{ "id": "<id>", "query": "<folded query>", "count": 1 }]
}

items are in the index's order, and each item's inboxes in the saved order. inboxes is null when the saved inboxes cannot be read; no item is in any inbox then.

GET /api/inbox?query=Q answers what a query not saved yet would hold, for a filter being typed or an inbox being edited: {"query": Q, "problem": "", "matches": ["<key>", …]}. problem says why a query does not read (it then matches every item), or that it is longer than an inbox may save. A query over 8 KiB is refused with 413.

The host applies its launch authentication first. A change to the app's queue rules, or to which pull requests an inbox holds, belongs here too.

Documentation

Overview

Package inboxqueue builds the app's Inbox from the daemon's own state: the open pull requests with what each waits for, which saved inboxes hold each, and how many wait on the person.

The total (Count) is the shared definition of the number on the sidebar's Inbox heading and the desktop app's dock badge and tray: the distinct unsnoozed actionable pull requests in the queue, each once however many clones hold it. It ignores saved inboxes, their badge switches and any filter. Which inboxes hold a pull request is decided here too, with the inbox filter language of internal/prfilter, so the app does not match every inbox query against every pull request itself.

Index

Constants

View Source
const (
	Review  = "review"
	Clone   = "clone"
	Fix     = "fix"
	Merge   = "merge"
	Update  = "update"
	Other   = "other"
	Waiting = ""
)

Kinds of Item: what the person does next about a pull request in the queue, as the app's UpNextKind, then Other for someone else's that waits on nothing from them and Waiting for their own that waits on others.

Variables

This section is empty.

Functions

func Count

func Count(entries []reviewindex.Entry, queue []jobs.Job, groups []reviewgroups.Group, snoozes Snoozes, now time.Time) int

Count is the number of pull requests in the Inbox: each open one asking for the user's review or assigned to them, and each of their own with something for them to do (fix, merge or update), less those snoozed at now or archived. Saved inboxes play no part.

func Folded

func Folded(inbox inboxes.Inbox) string

Folded is the inbox's query with its older parts (what, owners, risk, repositories, bots) folded in, as the app matches it. An unknown what or risk reads as "any", as the app reads it.

func Key

func Key(pr reviewindex.Entry) string

Key names a pull request across the clones that hold it, as the app's upNextKey does.

func Matching

func Matching(items []Item, query string) []string

Matching is the keys of the items query holds, in their order: what an inbox with that query would hold, for a filter not saved yet.

Types

type Draft

type Draft struct {
	Query   string   `json:"query"`
	Problem string   `json:"problem"`
	Matches []string `json:"matches"`
}

Draft is what a query not saved yet would hold: the keys of the items it matches, or why it cannot be read (Problem), in which case it holds them all as a filter that does not read narrows nothing.

type Inbox

type Inbox struct {
	ID    string `json:"id"`
	Query string `json:"query"`
	Count int    `json:"count"`
}

Inbox is a saved inbox as matched: the query its parts fold into, and how many listed items it holds.

type Item

type Item struct {
	Key string `json:"key"`
	// Kind is what it waits for, as an inbox's waiting= filter reads it: a
	// queue kind, Other, or Waiting (""). One an agent is fixing now is Fix,
	// with Fixing set, though it is not in the queue.
	Kind   string `json:"kind"`
	Fixing bool   `json:"fixing,omitempty"`
	// Snoozed is set while the person's snooze hides it.
	Snoozed bool `json:"snoozed,omitempty"`
	// Archived is set once the person archived it: it never shows in an
	// inbox again.
	Archived bool `json:"archived,omitempty"`
	// Inboxes are the ids of the saved inboxes that hold it, in their order.
	Inboxes []string `json:"inboxes"`
	// contains filtered or unexported fields
}

Item is an open pull request as the inboxes match it: one per Key, the clone that speaks for it chosen as the app chooses.

func Items

func Items(entries []reviewindex.Entry, queue []jobs.Job, groups []reviewgroups.Group, snoozes Snoozes, now time.Time) []Item

Items classifies the open pull requests of entries (the index's, in its order), one per Key, with queue the job queue's and groups the review groups, and marks those snoozed at now and those archived. Their Inboxes are empty.

func (Item) Hidden

func (i Item) Hidden() bool

Hidden reports whether the person's snooze or archive keeps the item out of every inbox.

func (Item) Listed

func (i Item) Listed() bool

Listed reports whether an inbox's own count includes the item: what the queue holds and others' pull requests, neither snoozed nor archived.

func (Item) Queued

func (i Item) Queued() bool

Queued reports whether the item waits on the person: in the queue, not being fixed, waiting on others or someone else's.

type Queue

type Queue struct {
	Count   int     `json:"count"`
	Items   []Item  `json:"items"`
	Inboxes []Inbox `json:"inboxes"`
}

Queue is the Inbox: every open pull request with what it waits for and the inboxes that hold it, the total waiting on the person (Count) and each inbox's own count. Inboxes is nil when the saved inboxes could not be read.

func Build

func Build(entries []reviewindex.Entry, queue []jobs.Job, groups []reviewgroups.Group, snoozes Snoozes, saved []inboxes.Inbox, now time.Time) Queue

Build is the Queue: Items, each matched against the saved inboxes in their order.

type Service

type Service struct {
	Index func(context.Context) (reviewindex.Snapshot, error)
	// Jobs reads the jobs the Queue looks at, which are only the queued or
	// running fixes (jobs.Queue.ActiveFixes), not the history.
	Jobs    func() []jobs.Job
	Groups  func(context.Context) ([]reviewgroups.Group, error)
	Snoozes func() (json.RawMessage, error)
	// Inboxes reads the saved inboxes. When it is nil or fails, no inbox
	// holds anything and the Queue's Inboxes is nil.
	Inboxes func() ([]inboxes.Inbox, error)
	Now     func() time.Time
}

Service builds the Queue from the daemon's own index, job queue, groups, saved ui-state and saved inboxes, read on each request.

func (*Service) Count

func (s *Service) Count(ctx context.Context) (int, error)

Count is the Inbox total now.

func (*Service) CountHandler

func (s *Service) CountHandler(index http.Handler) http.Handler

CountHandler answers GET /api/index?view=waiting with {"waiting":N}, the Inbox count, which the desktop app polls for its badge and tray; every other request goes to index. The host applies its launch authentication first.

func (*Service) Handler

func (s *Service) Handler() http.Handler

Handler serves GET /api/inbox, the Queue, and GET /api/inbox?query=Q, the Draft of Q. The host applies its launch authentication first.

func (*Service) Queue

func (s *Service) Queue(ctx context.Context) (Queue, error)

Queue is the Inbox now, matched against the saved inboxes when they read.

type Snoozes

type Snoozes struct {
	Snoozed  map[string]int64  `json:"snoozed"`
	Held     map[string]string `json:"held"`
	Archived map[string]int64  `json:"archived"`
}

Snoozes is what the app saved as ui-state "inbox" that hides a pull request from the queue: until a time (Unix milliseconds) or while its head stays the one it was held on, or for good once archived (when, in Unix milliseconds). All are keyed by Key.

func ParseSnoozes

func ParseSnoozes(raw json.RawMessage) (Snoozes, error)

ParseSnoozes reads the ui-state "inbox" value; null, as before the app saved one, hides nothing.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL