A standalone, web-hosted board that shows every open pull request across the
simp organization in one place — so that with ~200 repos it
stays easy to see, per PR: is CI passing, has anyone reviewed it, does it close an issue,
and why is it still open (via shared notes).
It is a client-side Angular app (no backend). It authenticates with a GitHub Personal Access
Token entered in the browser and reads all PR state in one GraphQL query per 100 PRs (CI
rollup, review state, closing-issue links, author — all inline), so a full org scan costs a
handful of requests rather than hundreds. The only writes it ever makes are notes — and only
to a single notes.json in the dedicated notes repository (see below).
Modeled on the sibling
simp/modernization-dashboard(same Angular 21 + Tailwind 4 + GitHub Pages stack).
| Signal | Source |
|---|---|
| CI — passing / failing / running / none | check-runs on the PR's head commit |
| Reviewer — approved / changes requested / commented / requested / none | the PR's reviews + requested reviewers |
| Closes issue | GitHub's own closing references (catches keyword and UI-linked issues) |
| Notes | a shared quick note (dropdown), stored in notes.json — editable and deletable |
| Pin | pin important PRs to the top; the pin shows who pinned it. Shared via notes.json |
| Author / bot | bot PRs (Dependabot, Renovate, …) are collapsed behind a toggle by default |
Filter by CI state, reviewer state, notes, or free text; sort by recently-updated, newest, or repository. A summary bar shows open human-PR count, how many are failing CI, and how many have no reviewer.
Notes are stored as a single notes.json in a dedicated notes repository (default:
simp/pull-request-dashboard — this repo itself). Each PR has at most one quick note, keyed by
owner/repo#N; it's shown in a dropdown, is editable, and can be deleted. Saving/deleting commits
the file via the GitHub Contents API — no per-PR issues, git history is the audit trail, no backend.
Pins live in the same notes.json (a pins section keyed the same way). Pinning records who
pinned it and floats the PR to the top of the list for everyone; pinning/unpinning needs the same
Contents:write access as notes.
- Reading notes only needs a token that can read the notes repo.
- Saving/deleting a note needs a token with Contents: write on the notes repo. A read-only token can still view notes; the save/delete action explains if it lacks write access.
- Concurrent edits are last-write-wins; on a stale-file conflict the app reloads and retries once.
- If the notes repo doesn't exist yet, the dashboard still works — notes are simply disabled with a banner until the repo is created.
No Actions/workflow scope is needed — CI comes from the check/status rollup, not Actions data.
- Fine-grained PAT (recommended):
Metadata: Read,Pull requests: Read,Checks: Read, and — to add notes —Contents: Read and writescoped to the notes repo. - Classic PAT:
repocovers everything (read PRs/CI + writenotes.json).
The token is held in session storage only and is cleared when the tab closes.
npm install # install dependencies
npm start # dev server at http://localhost:4200
npm run build # production build
npm run build:pages # build for GitHub Pages (base-href /pull-request-dashboard/)
npm test # run unit tests (Vitest)
npm run lint # lint TS + HTML.github/workflows/pages-deploy.yml builds and publishes to GitHub Pages on push to main.
The site is fully static; no secrets are stored — each viewer supplies their own token.
PR data is read over the REST API (the GraphQL endpoint has no CORS support, so it can't be called from a browser-only app). To keep the request count down:
- Conditional requests (ETags): every GET is revalidated with
If-None-Match; unchanged data comes back as304 Not Modified, which does not count against the REST rate limit. ETags are persisted in localStorage, so the savings survive reloads. - Snapshot on load: the last scan's rows are cached in localStorage and shown instantly on reload (with a "saved snapshot" banner) until you Scan to refresh.
services/pr-list.service.ts— read-only GitHub REST client: discovers repos with open PRs, lists each repo's PRs, and enriches them with review state + CI.services/http-cache.service.ts— ETag conditional-GET cache (rate-limit-free304s).services/notes.service.ts— reads/writes the sharednotes.jsonvia the Contents API.services/pr-derive.ts— pure helpers (bot detection, review-status roll-up, CI-rollup mapping, note key), unit-tested.components/pr-list/— toolbar (filters/sort/summary) + the PR rows.components/note-panel/— the per-PR quick-note dropdown (view / edit / delete).app.ts— loads notes, streams the PR scan into the table, and applies note updates.