submitClassify()'s success path closes the modal and reloads the list but
never resets the submit button (only the error paths did), and
openClassifyModal() reset the form fields but not the button. So after a
successful classify, the next modal opened with the button stuck disabled on
"Classifying…" — only a full page refresh cleared it.
Reset the submit button to "Classify"/enabled in openClassifyModal so every
open starts clean regardless of how the previous one ended.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The classify modal's _loadProjects() fetched /api/projects/list and called
.json() on it, but that endpoint returns HTML project cards (used by the
projects overview via htmx). Parsing HTML as JSON threw, the catch swallowed
it, and the Project dropdown came up empty — so deployments couldn't be
assigned to a project.
- Add GET /api/projects/list-json returning assignable projects (id, name,
status) as JSON, excluding deleted/archived/completed to match the default
/list view.
- Point the modal's _loadProjects() at the JSON endpoint.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
UI for the pending-deployment workflow (commits 2 + 3 from the plan,
landed together since commit 1 already shipped the full backend).
New surfaces
- /deploy — mobile-first 3-step wizard. Pick unit → take photo (uses
<input capture="environment"> so it opens the phone camera) → add
optional note + submit. EXIF GPS auto-extracted on the server.
Success page shows the captured coords + links to either "Deploy
another" or "View pending hopper." Whole flow is meant to take
under 90 seconds on site.
- /tools/pending-deployments — the hopper. Filter pills: Awaiting /
Assigned / Cancelled. Each card shows photo thumbnail, unit serial
link, captured-at timestamp, coordinates, operator note, and
status-appropriate actions.
- Classify modal on the hopper: two modes — "Assign to existing
location" (project + location pickers, scoped to vibration_monitoring)
or "Create new location" (with new-or-existing project, plus a
"use captured coords" checkbox that writes the pending row's coords
onto the new location). Calls /pending/{id}/promote on submit.
- Cancel button uses prompt() for the optional reason → POSTs to
/pending/{id}/cancel.
Backend additions
- GET /api/deployments/seismograph-picker — JSON list of non-retired
seismograph units for the /deploy unit picker. Annotates each unit
with has_pending so the picker can flag units that already have a
pending capture waiting.
Discovery
- New "Field Deploy" + "Pending Deployments" cards on /tools.
- Dashboard banner: auto-shows when there are awaiting captures,
polled every 30s. Hides when count drops to 0. Click → /tools/
pending-deployments.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>