Replace the canvas teardrop pin with an admission-ticket silhouette (side
perforation notches + a dashed tear line, tapering to a bottom point that
anchors on the location) drawn via Path2D at 4x (pixelRatio 4). Keeps every
existing rule: fill = SLA colour, vivid = open / pastel = closed, white outline,
bottom anchor, and the fan-out declutter. Markers now read clearly as tickets
and are distinct from the round vehicle markers.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- New "Closures by engineer" leaderboard panel (metrics.by_owner): engineer,
closed, breached, avg MTTR. Clicking an engineer toggles a drill-down that
filters the closed map pins to only their closures (and ensures the closed
layer is visible).
- Popups now carry the details dispatchers need: open popups show location_name
and the true coordinates (copyable; the fan-out keeps the real coord even when
the pin is offset); closed popups show "closed by <engineer>".
Backed by fn_inc_dashboard migration 12 (owner case-normalized server-side).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Cluster-centroid tickets share an exact coordinate, so the open layer sat on
top of the faded closed pins (23 of 25 closed points were occluded) — the new
closed colouring was correct but invisible. Now pins sharing a coordinate are
fanned into a small deterministic sunflower spiral around it, computed across
BOTH layers so an open and a closed ticket at the same centroid separate.
Active (vivid) and closed (faded) now both show. Also default the Closed layer
on. Offsets are cosmetic (cluster centroids are already approximate).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Previously closed INC tickets all used one flat slate pin, losing the SLA
outcome and reading as inactive/uninformative. Now a closed ticket keeps its
SLA colour but as a light ('pastel') version — Breached → light red, Compliant
→ light green — so active tickets stay vivid and closed ones are a washed-out
same-hue. Makes active-vs-closed and SLA outcome apparent across both layers.
- Faded closed pin images keyed on sla_status (Compliant|Breached, + fallback).
- inc-closed layer matches sla_status → faded pin; popup badge + legend updated
(new "Closed SLA" key); header subtitle reworded.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Vertically centre the cluster/status/window filters against the metric tiles
in the INC overview row.
- Overlay only ISP cost-centre vehicles (the teams handling INC); other cost
centres are filtered out. Layer count + labels updated to "ISP vehicles".
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fold the filter controls into the INC overview card, right-aligned next to the
metric tiles, and remove the standalone filter bar — better visual balance
(fills the previously empty right side of the overview row).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Remove the redundant header KPI strip on the Tickets tab (metrics live in the
INC overview card); header stays empty there.
- Enlarge the map (62vh, min 520px) and size the grid cards to their content
(#tk-main align-items:start) so there's no stretched empty space under the
Closures / By-status cards.
- Split the single 26-row "By cluster" list into "Clusters — Nairobi" and
"Clusters — Mombasa / Voi", classified by cluster name (coast keyword set);
bottom row is now four compact span3 cards.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Render INC tickets as canvas-drawn teardrop map pins via MapLibre symbol layers
(scales to thousands of closed features, unlike DOM markers):
- Open pins coloured by SLA state; larger than the old circles for hierarchy.
- Closed pins use a single muted slate colour irrespective of status (the only
distinction that matters once closed), slightly smaller + under the open layer.
- Legend/popup closed swatch aligned to the new closed colour.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Late async loaders (notably the boot-time logistics loadAll) called their KPI
renderer unconditionally, overwriting the shared header strip after the user had
switched to another tab. Guard renderKpis / renderFuelKpis / renderIncKpis so each
only updates the header when its own tab is active.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Overhaul the Tickets tab into the documented INC operations dashboard,
backed by the new GET /webhook/inc-dashboard endpoint (reporting.fn_inc_dashboard):
- Filterbar (cluster / status / window: today|week|month|custom)
- Metric strip: open now, closed in window, open/closed SLA breakdown,
avg MTTR, closures/day + freshness
- Live map: open INC coloured by SLA state, dimmed closed overlay,
FleetNow vehicle markers, layer toggles + SLA legend
- By-status / by-cluster tables + daily closures chart
- Data load decoupled from the basemap so the dashboard renders even if
WebGL/map init is slow or fails
Removes the old combined INC/CRQ map and the /webhook/tickets call (CRQ deferred).
Adds docs/tickets-inc-{overhaul-plan,implementation-guide}.{md,html}.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New tab backed by dashboard_api /analytics/fuel-fills(+/recent): KPI strip
(litres, KES spend, fills, KES/L, vehicles), spend+litres daily trend, per-vehicle
table (incl. km/L), by-department breakdown, recent fills. Shares the filter state
plus new department/fuel-type dropdowns; lazy-loads on first open. Recent-fills
time renders the Africa/Nairobi wall-clock value directly (no double tz shift).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- #view-tickets is now a MapLibre map: live vehicle DOM markers (ported from
FleetNow) + INC (red) / CRQ (blue) ticket circle layers from /webhook/tickets
- Layers toggle with counts; open/all status filter; lazy-init + map.resize()
- Header KPI strip shows INC/CRQ open + vehicles/moving on the Tickets tab
- Logistics analytics tab unchanged
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Wrap the existing analytics dashboard as the Logistics tab
- Add a scaffolded Tickets tab (per-tab KPIs, recent-tickets + by-status
cards, informative empty state)
- Shared header KPI strip swaps per tab; tickets load lazily on first open
- Ticket data source left as a dashboard_api integration point — no S3
credentials embedded in the static SPA
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Auto-deploy verified (push->Forgejo webhook->Coolify->Traefik). Reverting the
test meta marker.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Harmless <meta> marker to confirm a push to staging triggers a Coolify
redeploy. Safe to revert.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>