Skip to content

feat(admin-ui): Next.js admin UI for task monitoring#19

Merged
anish749 merged 19 commits into
mainfrom
feat/admin-ui
May 16, 2026
Merged

feat(admin-ui): Next.js admin UI for task monitoring#19
anish749 merged 19 commits into
mainfrom
feat/admin-ui

Conversation

@anish749

Copy link
Copy Markdown
Owner

Problem

The oncetask library is a Go module — no HTTP API, no UI. Every consumer that wants to inspect or operate on the onceTasks collection (View Logs, Reset a failed task, Cancel a runaway recurrence) has to build their own admin tooling against Firestore directly. Donna's Den is the existing example of this duplication.

Solution

A standalone Next.js app in admin-ui/ that points at a Firestore project, lists tasks, and exposes the library's mutation surface. Deploy alongside your workers, share with whoever needs ops access.

Architecture

Browser ─HTTP→ Next.js API routes ─@google-cloud/firestore→ Firestore
                       ↑
                 ADC / service account

No Firebase SDK on the client. The Next.js server holds the credential and proxies every read/write through local API routes. The browser only talks to the local app.

Generic by default

  • Task types populated by skip-scan distinct-value discovery on the collection (SELECT type LIMIT 1 then NOT IN [...] until empty). No consumer code, no hardcoded enums.
  • Environments discovered the same way. UI dropdown, not a server env var.
  • Outbound links (View Logs, Gmail thread, conversation deep-link) declared in YAML at ONCETASK_LINKS_CONFIG. Mustache-style {path.to.field} placeholders with auto URL-encoding, plus a requires: field for conditional rendering. See links.example.yaml.

Mutations

resetTask, cancelTask, deleteTask in src/lib/oncetask/mutations.ts mirror the field updates in pkg/oncetask/reset.go and pkg/oncetask/cancellation.go. React Query handles invalidation so list + detail refresh after every action.

Auth

Nothing built in. README points operators at oauth2-proxy / Caddy forward_auth / Cloudflare Access / Tailscale. The server validates that mutations target tasks belonging to the task's stamped env — accidentally pointing at the wrong project still requires the task ID to exist there.

Stack

Next.js 16 (App Router) · React 19 · TypeScript · Tailwind v4 · shadcn (base-ui) · @google-cloud/firestore · @tanstack/react-query · js-yaml · lodash.get.

Quick start

cd admin-ui
cp .env.example .env.local   # set GOOGLE_CLOUD_PROJECT, ONCETASK_LINKS_CONFIG
gcloud auth application-default login
npm install
npm run dev

anish749 added 19 commits May 12, 2026 13:11
Standalone Next.js app that points at a Firestore database, lists tasks
from the onceTasks collection, and exposes Reset / Cancel / Delete that
mirror the library's Manager semantics.

- Server-side @google-cloud/firestore reads + writes; browser only talks
  to local API routes (no Firebase SDK).
- Task type and environment dropdowns populated by skip-scan distinct-value
  discovery on the collection - no consumer code or env vars required.
- Outbound links (View Logs, Gmail thread, conversation deep-link, etc.)
  configured via YAML at ONCETASK_LINKS_CONFIG; mustache-style placeholders
  with auto URL-encoding and a 'requires' field for conditional rendering.
- React Query handles polling and mutation invalidation across list and
  detail panes.
- No built-in auth - deploy behind oauth2-proxy / Caddy forward_auth /
  Cloudflare Access / similar.
- Label each filter dropdown with its name (Status, Task type, Environment)
  above the Select trigger; "all" option is just "All" now that the
  label provides context.
- Replace package-lock.json with pnpm-lock.yaml; update README.
Client owns the orderBy policy per status; server accepts orderBy+orderDir params and applies them. Drops the per-status default orderBys and the JS re-sort so the displayed order matches what the server actually returned. Also aligns the doneAt zero-value with the Go production code ("" not "0001-01-01T00:00:00Z").
New top-level tab structure: Browse (existing UI, unchanged) and Index-aware (Active / Done / Resource sub-tabs). Index-aware mode only issues queries that the production Go code's Firestore indexes already serve — no new composite indexes are prompted. Sub-state filtering for Active (Ready/Leased/Waiting) is done client-side over the env+type result set.
Client-side filters (status derivation, resourceKey substring, indexed view sub-state) apply over what the server returns. Bumping the per-query cap to 2000 widens the window the user can filter through. The new FetchInfo banner makes the cap explicit — shown/fetched counts, and an amber warning when the cap was the constraint so operators know more data may exist.

Adds DoneTasksView client-side status filter (Completed/Failed/Cancelled) as a four-button toggle over the fetched rows.
@anish749 anish749 merged commit 4833076 into main May 16, 2026
4 checks passed
@anish749 anish749 deleted the feat/admin-ui branch May 16, 2026 13:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant