Skip to content

simp/pull-request-dashboard

Repository files navigation

SIMP Pull Request Dashboard

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).

What each row shows

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 (the one thing that writes)

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.

GitHub token

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 write scoped to the notes repo.
  • Classic PAT: repo covers everything (read PRs/CI + write notes.json).

The token is held in session storage only and is cleared when the tab closes.

Commands

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

Deployment

.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.

Efficiency

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 as 304 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.

Architecture

  • 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-free 304s).
  • services/notes.service.ts — reads/writes the shared notes.json via 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.

About

Dashboard of all open pull requests across the SIMP org: CI status, reviewer status, closing-issue links, and shared notes.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors