[Perl] DAQ system for the FAPG.
feat grey out stale quick cards instead of hiding
Cards now always display, even with old or missing data: - Stale readings (>10 min) grey out the card (opacity-50) - Last known value still shown with its age - Status pill shows 'Stale' instead of 'Unreachable' - Cards with no data show '— · no data' instead of disappearing
Changed files
roles/dashboard/public/js/dashboard/quick-readings.js
@@ -91,13 +91,22 @@
91
91
const state = qualityState(quality);
92
92
const percent = Number.isFinite(value) ? rangePercent(value, range) : 50;
93
93
const timestamp = reading?.received_at || reading?.timestamp;
94
Removed:
const age = timestamp ? formatAge(ageMs(timestamp)) : "unknown age";
94
Added:
const age = timestamp ? ageMs(timestamp) : null;
95
Added:
const ageText = age !== null ? formatAge(age) : "no data";
95
96
97
Added:
// Determine if the reading is stale (older than 10 minutes)
98
Added:
const isStale = age === null || age > 10 * 60 * 1000;
99
Added:
96
100
configureRange(item, range, unit);
97
Removed:
item.classList.remove("border-success", "border-warning", "border-danger");
98
Removed:
const borderClass = qualityBorderClass(state);
99
Removed:
if (borderClass) item.classList.add(borderClass);
101
Added:
item.classList.remove("border-success", "border-warning", "border-danger", "opacity-50");
100
102
103
Added:
if (isStale) {
104
Added:
item.classList.add("opacity-50");
105
Added:
} else {
106
Added:
const borderClass = qualityBorderClass(state);
107
Added:
if (borderClass) item.classList.add(borderClass);
108
Added:
}
109
Added:
101
110
const marker = item.querySelector("[data-reading-quick-marker]");
102
111
marker.style.left = `${percent}%`;
103
112
marker.style.backgroundColor = Number.isFinite(value) ? markerColor(quality) : "";
@@ -106,8 +115,8 @@
106
115
meter.setAttribute("aria-valuenow", Math.round(percent).toString());
107
116
meter.setAttribute("aria-label", `${label} ${qualityLabel(quality)} at ${formatValue(value, range)} ${unit}`);
108
117
item.querySelector("[data-reading-quick-value]").textContent = Number.isFinite(value)
109
Removed:
? `${formatValue(value, range)} ${unit} · ${age}`
110
Removed:
: "—";
118
Added:
? `${formatValue(value, range)} ${unit} · ${ageText}`
119
Added:
: `— · ${ageText}`;
111
120
}
112
121
113
122
export async function loadQuickReadings() {
roles/dashboard/public/js/dashboard/status.js
@@ -85,6 +85,16 @@
85
85
});
86
86
}
87
87
88
Added:
function quickCardLabel(state) {
89
Added:
return {
90
Added:
healthy: "OK",
91
Added:
stale: "Stale",
92
Added:
"probe-error": "Error",
93
Added:
unreachable: "Stale",
94
Added:
unknown: ""
95
Added:
}[state] || "";
96
Added:
}
97
Added:
88
98
function loadQuickCardStatuses(statuses) {
89
99
const pills = Array.from(document.querySelectorAll("[data-reading-quick-status]"));
90
100
if (!pills.length) return;
@@ -92,8 +102,10 @@
92
102
pills.forEach(pill => {
93
103
const probe = pill.dataset.readingQuickStatus;
94
104
const state = stateForNodeStatus(statuses[probe] || null);
95
Removed:
pill.className = `status-pill is-${state}`;
96
Removed:
pill.textContent = statusLabel(state);
105
Added:
// Use 'stale' styling for unreachable on quick cards (less alarming)
106
Added:
const displayState = state === "unreachable" ? "stale" : state;
107
Added:
pill.className = `status-pill is-${displayState}`;
108
Added:
pill.textContent = quickCardLabel(state);
97
109
});
98
110
}
99
111