Two bugs in the project-merge modal:
1. Dropdown options had the same JSON.stringify quote-collision in
their inline onclick that broke the location Remove button and the
metadata-backfill typeahead earlier this week:
onclick="onMergePickTarget('${id}', ${JSON.stringify(m.name)})"
For 'I-80 Area 1' that renders as onclick="...(\"I-80 Area 1\")" —
the inner double quotes terminate the onclick attribute early,
and the browser never binds the click handler. Operator clicked
items in the dropdown and nothing happened.
Fixed via data-target-id / data-target-name attributes and a
_mergePickFromButton(btn) trampoline.
2. Modal body had `flex-1 overflow-y-auto` with no min-height, so the
container shrunk tight around the input. When the typeahead
dropdown appeared below the input it got clipped by the body's
overflow and the operator had to scroll inside the modal to see
the options.
Fixed by adding min-height: 480px to the modal container + min-h-
[320px] on the body so there's always room for the dropdown + the
preview pane that appears below after a target is picked.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Operator-facing tool for cleaning up duplicate projects. Common after
the metadata-backfill parser auto-creates near-duplicates from operator
name variations ("SR81" vs "SR 81", "Swank-Karns Crossing" vs
"Swank-Karns Crossings", "Trumbull-Bryman Mont.Dam" vs
"Trumbull-Brayman-Mont Dam", etc.).
Workflow: visit the duplicate project's detail page, click "Merge into…"
in the header, search for the canonical target project from a typeahead,
review the preview (what assignments / locations / sessions will move,
any conflicts), confirm. Source is soft-deleted; everything else
re-points to the target. Smart consolidation: same-named locations in
both projects merge into one (source's assignments move to target's
existing location with the same name; source's empty location is then
deleted). Different-named locations move as-is.
Backend:
- backend/services/project_merge.py (new): preview() and execute()
functions. Transaction-safe. Per-assignment UnitHistory audit row
with change_type='assignment_merged' so the deployment timeline shows
the merge. Source modules disabled; missing modules added to target.
Handles edge cases: same project_id rejected, deleted projects rejected,
orphan project-direct assignments (no location) re-pointed defensively.
- backend/routers/projects.py: new endpoints
GET /api/projects/{source_id}/merge_preview?target_id=...
POST /api/projects/{source_id}/merge_into?target_id=...
Frontend (templates/partials/projects/project_header.html):
- "Merge into…" button in Project Actions area.
- Modal with typeahead (reuses /api/admin/metadata_backfill/projects_search)
scoped to existing projects only (no create-new option). Filters out
the source project from candidates so operator can't accidentally pick
it as target.
- Preview pane shows totals + per-location plan (consolidate vs move) +
warnings (mismatched client names, location consolidation note).
- Red "Merge (permanent)" confirm button only enables after a target is
picked and preview loads.
- On success, browser redirects to target project page.
Smoke verified: "Swank-Karns Crossing" (1 assignment) merged into
"Swank-Karns Crossings"; target now has 2 locations + 2 assignments,
source has 0 dangling rows, 1 project_merge audit entry written.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Updated project creation modal to allow selection of optional modules (Sound and Vibration Monitoring).
- Modified project dashboard and header to display active modules and provide options to add/remove them.
- Enhanced project detail view to dynamically adjust UI based on enabled modules.
- Implemented a new migration script to create a `project_modules` table and seed it based on existing project types.
- Adjusted form submissions to handle module selections and ensure proper API interactions for module management.
- Updated reservation list to display estimated units and improved count display.
- Added "Upcoming" status to project dashboard and header with corresponding styles.
- Implemented a dropdown for quick status updates in project header.
- Modified project list compact view to reflect new status labels.
- Updated project overview to include a tab for upcoming projects.
- Added migration script to introduce estimated_units column in job_reservations table.