v0.12.1 — Unit Swap wizard, editable timeline, roster/tz fixes #54
@@ -5,6 +5,45 @@ All notable changes to Terra-View will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [0.12.1] - 2026-05-20
|
||||||
|
|
||||||
|
Field-operations polish — three small features and two correctness fixes that smooth out the deployment workflow added in v0.12.0. The new Unit Swap wizard and editable deployment timeline are the operator-facing items; the swap/unassign/promote roster-flag fix closes a long-standing data-consistency hole.
|
||||||
|
|
||||||
|
### Added — Unit Swap wizard (`/tools/unit-swap`)
|
||||||
|
|
||||||
|
- **Mobile-first 4-step wizard** for the common field operation: pick project → pick location → choose incoming unit (with optional modem swap) → review + confirm. Designed for tap-driven use on a phone in the field; works on desktop too.
|
||||||
|
- **Benched-candidate awareness**: `GET /api/projects/.../available-units?include_benched=true` and `available-modems?include_benched=true` now return units/modems with `deployed=False` alongside the active fleet — exactly the inventory a tech pulls off the shelf. Each row carries a `deployed` boolean for badge rendering. Default (`include_benched=false`) is unchanged, so the existing location-detail swap modal isn't affected.
|
||||||
|
- **`POST /locations/{loc}/swap` enhancements**:
|
||||||
|
- Flips the incoming unit (and modem) back to `deployed=True` if either was on the bench, keeping the legacy `RosterUnit.deployed` flag consistent with the active-assignment signal.
|
||||||
|
- Adds the symmetric half of the orphan-pairing fix: when a newly-paired modem still claims a different seismograph (whose `deployed_with_modem_id` was never cleared in a past swap), the stale back-reference is broken before re-pairing.
|
||||||
|
- **`locations-with-assignments`** response now includes `modem.deployed`, so the wizard can badge the current modem in the location card, "Keep current modem" choice, picker rows, and review screen.
|
||||||
|
- Tile on `/tools` for discovery; sidebar entry in the Tools nav cluster.
|
||||||
|
|
||||||
|
### Added — Editable deployment timeline on `/unit/{id}`
|
||||||
|
|
||||||
|
- **Per-row inline edit (pencil icon)** on each assignment in the unit's Deployment Timeline. Opens a modal with `assigned_at`, `assigned_until` (with an "open-ended" checkbox that clears the end date), and notes. Saves via the existing `PATCH /api/projects/{pid}/assignments/{aid}`; delete (for misclicks) via the existing `DELETE`.
|
||||||
|
- **"+ Add deployment record" button** at the top of the timeline for backfilling historical windows — useful when orphan events sit outside any assignment. Modal flow: project → location → assigned_at → assigned_until (optional open-ended) → notes.
|
||||||
|
- **Closed-window assignments** now accepted by `POST /api/projects/.../locations/{loc}/assign`: the blanket "location already has an active assignment" check became overlap detection against same-location windows. Closed historical assignments that don't overlap an existing one are accepted (the backfill case).
|
||||||
|
- After any save/delete the timeline reloads and the SFM-events list re-fetches, so previously-orphaned events flip to "attributed" when their timestamp now falls inside an assignment window.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **`RosterUnit.deployed` now flips correctly on swap / unassign / promote-pending** (`POST /locations/{loc}/swap`, `POST /assignments/{aid}/unassign`, `POST /deployments/pending/{id}/promote`). The legacy `deployed` flag drives heartbeat polling and benched-vs-deployed roster filters; before this fix, those three workflows ended an assignment without flipping the flag, so the outgoing unit kept being polled and showed up as "deployed" forever. All three now: close the previous active assignment, break the outgoing unit's modem pairing (both directions), and set `deployed = False` on the outgoing unit. Unassign and swap also clear the modem's back-reference. Promote-pending additionally handles the case where the target location already has an active assignment — previously this silently created two active assignments at the same location; now the old one is closed (`assigned_until = pending.capture_time`, `status = completed`), the old unit benched + unpaired, and an `assignment_swapped` `UnitHistory` row is written.
|
||||||
|
- **Deployment timeline now respects user timezone for display *and* edits.** Timestamps were stored correctly as UTC but rendered raw — a 1:30 PM EDT swap displayed as "5:30" because the frontend sliced the naive UTC ISO string straight to the screen. Two-sided fix:
|
||||||
|
- **Display**: `services/deployment_timeline.py` converts every emitted timestamp (`starts_at`, `ends_at`, `event_overlay.peak_pvs_at`, `last_event`) through `utc_to_local()` using the user's configured timezone from `UserPreferences` before serializing. Frontend slicing keeps working — it just slices a local-time string now.
|
||||||
|
- **Write**: `PATCH /api/projects/{pid}/assignments/{aid}` and `POST /locations/{loc}/assign` interpret a *naive* `assigned_at` / `assigned_until` ISO string as the user's local time and convert to UTC via `local_to_utc()`. Explicit tz-aware strings (`...Z` or `...+00:00`) skip the conversion, so programmatic callers that already speak UTC keep working.
|
||||||
|
|
||||||
|
### Migration Notes
|
||||||
|
|
||||||
|
No schema changes. Static code-only release — pull and restart:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/serversdown/terra-view
|
||||||
|
docker compose build terra-view && docker compose up -d terra-view
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## [0.12.0] - 2026-05-17
|
## [0.12.0] - 2026-05-17
|
||||||
|
|
||||||
Field-deployment workflow + fleet-wide deployment views + SFM event DB management. The headline is the mobile capture flow: a field tech can now arrive on site, take one photo of the installed seismograph, and walk away — classification (which project, which location) happens later at a desk through the new pending-deployment hopper. EXIF GPS is auto-extracted on capture, so the resulting `UnitAssignment` lands with coordinates without anyone typing them.
|
Field-deployment workflow + fleet-wide deployment views + SFM event DB management. The headline is the mobile capture flow: a field tech can now arrive on site, take one photo of the installed seismograph, and walk away — classification (which project, which location) happens later at a desk through the new pending-deployment hopper. EXIF GPS is auto-extracted on capture, so the resulting `UnitAssignment` lands with coordinates without anyone typing them.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Terra-View v0.12.0
|
# Terra-View v0.12.1
|
||||||
Backend API and HTMX-powered web interface for managing a mixed fleet of seismographs and field modems. Track deployments, monitor health in real time, merge roster intent with incoming telemetry, and control your fleet through a unified database and dashboard.
|
Backend API and HTMX-powered web interface for managing a mixed fleet of seismographs and field modems. Track deployments, monitor health in real time, merge roster intent with incoming telemetry, and control your fleet through a unified database and dashboard.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
@@ -9,15 +9,20 @@ Backend API and HTMX-powered web interface for managing a mixed fleet of seismog
|
|||||||
- **Touch Optimized**: 44x44px minimum touch targets, hamburger menu, bottom navigation bar
|
- **Touch Optimized**: 44x44px minimum touch targets, hamburger menu, bottom navigation bar
|
||||||
- **Mobile Card View**: Compact unit cards with status dots, tap-to-navigate locations, and detail modals
|
- **Mobile Card View**: Compact unit cards with status dots, tap-to-navigate locations, and detail modals
|
||||||
- **Background Sync**: Queue edits while offline and automatically sync when connection returns
|
- **Background Sync**: Queue edits while offline and automatically sync when connection returns
|
||||||
|
- **Field-Deployment Workflow**: One-photo mobile capture at `/deploy` → desk-side classification at `/tools/pending-deployments` → automatic UnitAssignment creation with EXIF GPS
|
||||||
|
- **Unit Swap Wizard** (`/tools/unit-swap`): mobile-first 4-step flow for swapping a vibration unit (and optionally its modem) at a monitoring location. Surfaces benched-fleet candidates as eligible incoming units; cleans up stale modem back-references on swap
|
||||||
|
- **Editable Deployment Timeline** on every unit detail page: inline edit / delete each assignment, plus an "Add deployment record" button for backfilling historical windows. Frees-up previously-orphaned events when their timestamp now falls inside an assignment
|
||||||
- **Web Dashboard**: Modern, responsive UI with dark/light mode, live HTMX updates, and integrated fleet map
|
- **Web Dashboard**: Modern, responsive UI with dark/light mode, live HTMX updates, and integrated fleet map
|
||||||
- **Fleet Monitoring**: Track deployed, benched, retired, and ignored units in separate buckets with unknown-emitter triage
|
- **Fleet Monitoring**: Track deployed, benched, retired, and ignored units in separate buckets with unknown-emitter triage
|
||||||
- **Roster Management**: Full CRUD + CSV import/export, device-type aware metadata, and inline actions from the roster tables
|
- **Roster Management**: Full CRUD + CSV import/export, device-type aware metadata, and inline actions from the roster tables
|
||||||
- **Settings & Safeguards**: `/settings` page exposes roster stats, exports, replace-all imports, and danger-zone reset tools
|
- **Settings & Safeguards**: `/settings` page exposes roster stats, exports, replace-all imports, and danger-zone reset tools
|
||||||
- **Device & Modem Metadata**: Capture calibration windows, modem pairings, phone/IP details, and addresses per unit
|
- **Device & Modem Metadata**: Capture calibration windows, modem pairings, phone/IP details, and addresses per unit
|
||||||
- **Status Management**: Automatically mark deployed units as OK, Pending (>12h), or Missing (>24h) based on recent telemetry
|
- **Status Management**: Automatically mark deployed units as OK, Pending (>12h), or Missing (>24h) based on recent telemetry
|
||||||
- **Data Ingestion**: Accept reports from emitter scripts via REST API
|
- **SFM Event DB Manager** (`/admin/events`): cross-unit event browser with bulk false-trigger flagging and admin-only hard-delete (cleans on-disk binaries + sidecars too) for purging bogus events from misbehaving units
|
||||||
|
- **Deployment-History Calendar + Gantt** (`/tools/deployment-history`): fleet-wide 12-month calendar with side-panel day drill-down, plus "Gantt by Project" / "Gantt by Unit" tabs
|
||||||
- **Photo Management**: Upload and view photos for each unit
|
- **Photo Management**: Upload and view photos for each unit
|
||||||
- **Interactive Maps**: Leaflet-based maps showing unit locations with tap-to-navigate for mobile
|
- **Interactive Maps**: Leaflet-based maps showing unit locations with tap-to-navigate for mobile (reusable location-map partial across project overview + Vibration tab)
|
||||||
|
- **Timezone-Aware Timeline**: deployment assignments display and edit in the user's configured local timezone; UTC stays canonical on disk
|
||||||
- **SQLite Storage**: Lightweight, file-based database for easy deployment
|
- **SQLite Storage**: Lightweight, file-based database for easy deployment
|
||||||
- **Database Management**: Comprehensive backup and restore system
|
- **Database Management**: Comprehensive backup and restore system
|
||||||
- **Manual Snapshots**: Create on-demand backups with descriptions
|
- **Manual Snapshots**: Create on-demand backups with descriptions
|
||||||
|
|||||||
+1
-1
@@ -30,7 +30,7 @@ Base.metadata.create_all(bind=engine)
|
|||||||
ENVIRONMENT = os.getenv("ENVIRONMENT", "production")
|
ENVIRONMENT = os.getenv("ENVIRONMENT", "production")
|
||||||
|
|
||||||
# Initialize FastAPI app
|
# Initialize FastAPI app
|
||||||
VERSION = "0.12.0"
|
VERSION = "0.12.1"
|
||||||
if ENVIRONMENT == "development":
|
if ENVIRONMENT == "development":
|
||||||
_build = os.getenv("BUILD_NUMBER", "0")
|
_build = os.getenv("BUILD_NUMBER", "0")
|
||||||
if _build and _build != "0":
|
if _build and _build != "0":
|
||||||
|
|||||||
Reference in New Issue
Block a user