feat(tickets): center the overview, remove its filter row
The INC/CRQ overview is now a centered "today" snapshot — header + metric tiles centered. Removed the overview filter row (Cluster/Status/Window/Apply/refresh): the Ticket explorer below carries the ad-hoc filtering, so it was redundant. incQs() is fixed to window=today; dropped initIncDropdowns + the removed listeners. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
e58195073d
commit
9fb39aa992
1 changed files with 15 additions and 67 deletions
|
|
@ -225,8 +225,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
/* INC metric strip */
|
/* INC metric strip */
|
||||||
.metric-row { display: flex; flex-wrap: wrap; gap: 26px; }
|
.metric-row { display: flex; flex-wrap: wrap; gap: 26px; justify-content: center; }
|
||||||
.metric { display: flex; flex-direction: column; min-width: 96px; }
|
.metric { display: flex; flex-direction: column; align-items: center; text-align: center; min-width: 96px; }
|
||||||
.metric b { font-size: 22px; line-height: 1.1; font-variant-numeric: tabular-nums; }
|
.metric b { font-size: 22px; line-height: 1.1; font-variant-numeric: tabular-nums; }
|
||||||
.metric b.accent { color: var(--accent); }
|
.metric b.accent { color: var(--accent); }
|
||||||
.metric .lbl { font-size: 9.5px; color: var(--muted); text-transform: uppercase; letter-spacing: .6px; margin-top: 3px; }
|
.metric .lbl { font-size: 9.5px; color: var(--muted); text-transform: uppercase; letter-spacing: .6px; margin-top: 3px; }
|
||||||
|
|
@ -238,9 +238,7 @@
|
||||||
.sla-unknown { color: var(--muted); }
|
.sla-unknown { color: var(--muted); }
|
||||||
|
|
||||||
/* INC overview row: metric tiles (left) + filters (right) on one balanced row */
|
/* INC overview row: metric tiles (left) + filters (right) on one balanced row */
|
||||||
.tk-overview-row { display: flex; align-items: center; justify-content: space-between; gap: 16px 28px; flex-wrap: wrap; }
|
.tk-overview-metrics { min-width: 0; text-align: center; }
|
||||||
.tk-overview-metrics { min-width: 0; }
|
|
||||||
.tk-filters { display: flex; gap: 12px; align-items: flex-end; flex-wrap: wrap; margin-left: auto; }
|
|
||||||
.tk-filters .ff select, .tk-filters .ff input { min-width: 130px; }
|
.tk-filters .ff select, .tk-filters .ff input { min-width: 130px; }
|
||||||
|
|
||||||
/* Live vehicle DOM marker (ported from FleetNow) */
|
/* Live vehicle DOM marker (ported from FleetNow) */
|
||||||
|
|
@ -411,34 +409,9 @@
|
||||||
</div>
|
</div>
|
||||||
<main id="tk-main">
|
<main id="tk-main">
|
||||||
<div class="card span12">
|
<div class="card span12">
|
||||||
<div class="tk-overview-row">
|
<div class="tk-overview-metrics">
|
||||||
<div class="tk-overview-metrics">
|
<h2><span id="tk-ds-ov">INC</span> overview <span class="count" id="tk-fresh"></span></h2>
|
||||||
<h2><span id="tk-ds-ov">INC</span> overview <span class="count" id="tk-fresh"></span></h2>
|
<div class="metric-row" id="tk-metrics"><div class="empty">Loading…</div></div>
|
||||||
<div class="metric-row" id="tk-metrics"><div class="empty">Loading…</div></div>
|
|
||||||
</div>
|
|
||||||
<div class="tk-filters">
|
|
||||||
<div class="ff">
|
|
||||||
<label for="tk-cluster">Cluster</label>
|
|
||||||
<select id="tk-cluster"><option value="">All clusters</option></select>
|
|
||||||
</div>
|
|
||||||
<div class="ff">
|
|
||||||
<label for="tk-status">Status</label>
|
|
||||||
<select id="tk-status"><option value="">All statuses</option></select>
|
|
||||||
</div>
|
|
||||||
<div class="ff">
|
|
||||||
<label for="tk-window">Window</label>
|
|
||||||
<select id="tk-window">
|
|
||||||
<option value="today" selected>Today</option>
|
|
||||||
<option value="week">This week</option>
|
|
||||||
<option value="month">This month</option>
|
|
||||||
<option value="custom">Custom range</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="ff custom" id="tk-ff-start"><label for="tk-start">Start</label><input type="date" id="tk-start"></div>
|
|
||||||
<div class="ff custom" id="tk-ff-end"><label for="tk-end">End</label><input type="date" id="tk-end"></div>
|
|
||||||
<button class="btn" id="tk-apply" type="button">Apply</button>
|
|
||||||
<button class="btn ghost" id="tk-refresh" type="button" title="Reload">↻</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -929,9 +902,9 @@ function setDataset(ds) {
|
||||||
const U = ds.toUpperCase();
|
const U = ds.toUpperCase();
|
||||||
$('tk-ds-ov').textContent = U;
|
$('tk-ds-ov').textContent = U;
|
||||||
$('tk-ds-map').textContent = U;
|
$('tk-ds-map').textContent = U;
|
||||||
// per-dataset dropdowns + explorer results are stale → clear and re-init
|
// per-dataset explorer dropdowns + results are stale → clear and re-init
|
||||||
incDropdownsInit = false; incFilterOptionsInit = false;
|
incFilterOptionsInit = false;
|
||||||
['tk-cluster', 'tk-status', 'tk-x-eng', 'tk-x-cluster'].forEach(resetSelect);
|
['tk-x-eng', 'tk-x-cluster'].forEach(resetSelect);
|
||||||
$('tk-x-id').value = ''; $('tk-x-id-list').innerHTML = '';
|
$('tk-x-id').value = ''; $('tk-x-id-list').innerHTML = '';
|
||||||
$('tk-x-count').textContent = '';
|
$('tk-x-count').textContent = '';
|
||||||
$('tk-x-wrap').innerHTML = '<div class="empty">Search by ticket id, engineer, cluster, state and time.</div>';
|
$('tk-x-wrap').innerHTML = '<div class="empty">Search by ticket id, engineer, cluster, state and time.</div>';
|
||||||
|
|
@ -1009,7 +982,7 @@ let tkMap = null, tkPopup = null, tkLivePoll = null, tkClosureChart = null;
|
||||||
const tkMarkers = new Map(); // imei → maplibregl.Marker
|
const tkMarkers = new Map(); // imei → maplibregl.Marker
|
||||||
const tkLayerState = { open: true, closed: true, vehicles: true };
|
const tkLayerState = { open: true, closed: true, vehicles: true };
|
||||||
let tkOwnerFilter = null; // when set, the closed layer is filtered to this engineer (drill-down)
|
let tkOwnerFilter = null; // when set, the closed layer is filtered to this engineer (drill-down)
|
||||||
let incData = null, incDropdownsInit = false, vehCount = 0;
|
let incData = null, vehCount = 0;
|
||||||
let DS = 'inc'; // active Tickets dataset (inc | crq) — drives /webhook/${DS}-* endpoints + labels
|
let DS = 'inc'; // active Tickets dataset (inc | crq) — drives /webhook/${DS}-* endpoints + labels
|
||||||
let tkLoadedDay = null; // EAT calendar day of the last INC load — drives the midnight auto-rollover
|
let tkLoadedDay = null; // EAT calendar day of the last INC load — drives the midnight auto-rollover
|
||||||
const eatDay = () => new Date().toLocaleDateString('en-CA', { timeZone: 'Africa/Nairobi' });
|
const eatDay = () => new Date().toLocaleDateString('en-CA', { timeZone: 'Africa/Nairobi' });
|
||||||
|
|
@ -1023,18 +996,10 @@ function eatShort(iso) {
|
||||||
}
|
}
|
||||||
function addDay(ymd) { const [y, m, d] = ymd.split('-').map(Number); return new Date(Date.UTC(y, m - 1, d + 1)).toISOString().slice(0, 10); }
|
function addDay(ymd) { const [y, m, d] = ymd.split('-').map(Number); return new Date(Date.UTC(y, m - 1, d + 1)).toISOString().slice(0, 10); }
|
||||||
|
|
||||||
|
// The overview is a fixed "today" snapshot now that its filter row is removed —
|
||||||
|
// ad-hoc cluster / status / time filtering lives in the Ticket explorer below.
|
||||||
function incQs() {
|
function incQs() {
|
||||||
const p = new URLSearchParams();
|
return 'window=today';
|
||||||
if ($('tk-cluster').value) p.set('cluster', $('tk-cluster').value);
|
|
||||||
if ($('tk-status').value) p.set('status', $('tk-status').value);
|
|
||||||
const w = $('tk-window').value;
|
|
||||||
if (w === 'custom') {
|
|
||||||
if ($('tk-start').value) p.set('from', $('tk-start').value + 'T00:00:00+03:00');
|
|
||||||
if ($('tk-end').value) p.set('to', addDay($('tk-end').value) + 'T00:00:00+03:00'); // inclusive end
|
|
||||||
} else {
|
|
||||||
p.set('window', w);
|
|
||||||
}
|
|
||||||
return p.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Squircle + bolt map marker: a rounded squircle tapering to a bottom point (anchors on
|
// Squircle + bolt map marker: a rounded squircle tapering to a bottom point (anchors on
|
||||||
|
|
@ -1125,14 +1090,8 @@ function renderIncMap() {
|
||||||
function initIncMap() {
|
function initIncMap() {
|
||||||
if (tkMap) { tkMap.resize(); return; } // already built — just fix sizing
|
if (tkMap) { tkMap.resize(); return; } // already built — just fix sizing
|
||||||
|
|
||||||
// Filter / control listeners (attached once, with the map).
|
// Control listeners (attached once, with the map). The overview filter row was
|
||||||
$('tk-window').addEventListener('change', () => {
|
// removed (it's a fixed "today" snapshot); the explorer carries its own filters.
|
||||||
const custom = $('tk-window').value === 'custom';
|
|
||||||
$('tk-ff-start').classList.toggle('show', custom);
|
|
||||||
$('tk-ff-end').classList.toggle('show', custom);
|
|
||||||
});
|
|
||||||
$('tk-apply').addEventListener('click', loadInc);
|
|
||||||
$('tk-refresh').addEventListener('click', loadInc);
|
|
||||||
$('tk-layers-toggle').addEventListener('click', () => $('tk-layers').classList.toggle('collapsed'));
|
$('tk-layers-toggle').addEventListener('click', () => $('tk-layers').classList.toggle('collapsed'));
|
||||||
|
|
||||||
// Ticket explorer controls
|
// Ticket explorer controls
|
||||||
|
|
@ -1327,23 +1286,12 @@ async function loadIncSearch() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populate the Cluster / Status filters from the first unfiltered response.
|
|
||||||
function initIncDropdowns(m) {
|
|
||||||
const fill = (id, obj) => {
|
|
||||||
const el = $(id);
|
|
||||||
Object.keys(obj || {}).filter(k => k !== '').sort().forEach(k => el.add(new Option(k, k)));
|
|
||||||
};
|
|
||||||
fill('tk-cluster', m.by_cluster);
|
|
||||||
fill('tk-status', m.by_status);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadInc() {
|
async function loadInc() {
|
||||||
$('tk-main').classList.add('loading');
|
$('tk-main').classList.add('loading');
|
||||||
try {
|
try {
|
||||||
const j = await api(`/webhook/${DS}-dashboard?${incQs()}`);
|
const j = await api(`/webhook/${DS}-dashboard?${incQs()}`);
|
||||||
incData = j;
|
incData = j;
|
||||||
tkLoadedDay = eatDay();
|
tkLoadedDay = eatDay();
|
||||||
if (!incDropdownsInit && j.metrics) { initIncDropdowns(j.metrics); incDropdownsInit = true; }
|
|
||||||
renderIncMetrics(j.metrics, j.freshness);
|
renderIncMetrics(j.metrics, j.freshness);
|
||||||
renderIncMap(); // fan out co-located pins so open (vivid) + closed (faded) both show
|
renderIncMap(); // fan out co-located pins so open (vivid) + closed (faded) both show
|
||||||
buildIncLayers();
|
buildIncLayers();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue