UI tweaks + city case fix
- Migration 20: collapse `Nairobi`/`nairobi` in domain.vehicles → 'nairobi' - Remove the SLO panel from the top band (filter + tile rows stay) - Offline vehicles render as solid grey instead of dim-cost-centre tint; opacity now only differentiates moving (1.0) vs parked (0.75) vs offline (0.55) so colour carries identity + state cleanly
This commit is contained in:
parent
20958c0293
commit
de34103f18
3 changed files with 28 additions and 14 deletions
16
db/migrations/20260601000020_normalize_assigned_city.sql
Normal file
16
db/migrations/20260601000020_normalize_assigned_city.sql
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
-- migrate:up
|
||||
--
|
||||
-- Data hygiene: 1 vehicle had `assigned_city = 'Nairobi'` while the other
|
||||
-- 54 had `'nairobi'`. Collapse to lower-case so the filter dropdown shows
|
||||
-- a single canonical option. The projector doesn't set assigned_city (it
|
||||
-- comes from manual edits / roster imports) so no other code change is
|
||||
-- needed to prevent recurrence.
|
||||
|
||||
UPDATE domain.vehicles
|
||||
SET assigned_city = trim(lower(assigned_city)),
|
||||
updated_at = now()
|
||||
WHERE assigned_city IS NOT NULL
|
||||
AND assigned_city != trim(lower(assigned_city));
|
||||
|
||||
-- migrate:down
|
||||
-- No-op: re-introducing inconsistent casing would be a regression.
|
||||
|
|
@ -141,16 +141,19 @@ export function initMap(elementId, opts = {}) {
|
|||
15, 13,
|
||||
18, 20,
|
||||
],
|
||||
// Always tint by cost-centre colour — operational state is shown
|
||||
// via opacity (moving=1, parked=0.7, offline=0.35) so colour stays
|
||||
// a stable identity cue and the filter dropdown can double as a
|
||||
// colour legend.
|
||||
'circle-color': ['coalesce', ['get', 'cost_centre_color'], '#94a3b8'],
|
||||
// Cost-centre tint for moving + parked; offline goes solid grey
|
||||
// (no cost-centre signal worth showing when we haven't heard from
|
||||
// the device). Opacity differentiates moving vs parked.
|
||||
'circle-color': [
|
||||
'case',
|
||||
['==', ['get', 'operational_state'], 'offline'], '#9ca3af',
|
||||
['coalesce', ['get', 'cost_centre_color'], '#94a3b8'],
|
||||
],
|
||||
'circle-opacity': [
|
||||
'case',
|
||||
['==', ['get', 'operational_state'], 'moving'], 1.0,
|
||||
['==', ['get', 'operational_state'], 'parked'], 0.7,
|
||||
0.35,
|
||||
['==', ['get', 'operational_state'], 'parked'], 0.75,
|
||||
0.55,
|
||||
],
|
||||
'circle-stroke-color': '#0b1220',
|
||||
'circle-stroke-width': [
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@
|
|||
/* ─────────── top dashboard band: tiles + slos + filters ─────────── */
|
||||
.top-band {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(260px,auto) minmax(260px,1fr) minmax(280px,auto);
|
||||
grid-template-columns: minmax(260px,1fr) minmax(280px,auto);
|
||||
gap: 16px;
|
||||
padding: 10px 16px;
|
||||
background: var(--panel);
|
||||
|
|
@ -210,10 +210,6 @@
|
|||
<div class="band-title">Fleet now</div>
|
||||
<div class="band-row" id="summary"></div>
|
||||
</div>
|
||||
<div class="band-block">
|
||||
<div class="band-title">SLOs</div>
|
||||
<div class="band-row" id="slos" style="flex-direction:column; gap:4px;"></div>
|
||||
</div>
|
||||
<div class="band-block">
|
||||
<div class="band-title">Filters</div>
|
||||
<div class="band-row" id="filters">
|
||||
|
|
@ -258,7 +254,6 @@
|
|||
|
||||
const map = initMap('map');
|
||||
const summaryEl = document.getElementById('summary');
|
||||
const slosEl = document.getElementById('slos');
|
||||
let currentFilters = {};
|
||||
let activeSelection = { costCentres: [], cities: [] };
|
||||
|
||||
|
|
@ -266,7 +261,7 @@
|
|||
try {
|
||||
const params = Object.keys(currentFilters).length ? { filters: currentFilters } : {};
|
||||
const payload = await apiFetch('/api/views/live', { params });
|
||||
renderView(map, payload, { summaryRoot: summaryEl, sloRoot: slosEl });
|
||||
renderView(map, payload, { summaryRoot: summaryEl });
|
||||
// Repopulate filter dropdowns from the latest features
|
||||
const features = (payload.geojson && payload.geojson.features) || [];
|
||||
filters.updateOptions(features);
|
||||
|
|
|
|||
Loading…
Reference in a new issue