feat(cloud): dashboard rows link to detail + desk Web Audio on critical
This commit is contained in:
parent
55d99602ce
commit
b0d1241da1
1 changed files with 58 additions and 1 deletions
|
|
@ -55,6 +55,55 @@
|
|||
return badge;
|
||||
}
|
||||
|
||||
// --- desk audio alert: repeating beep while any unacknowledged critical exists ---
|
||||
// No binary asset (air-gapped friendly): a WebAudio oscillator tone. The browser
|
||||
// blocks audio until a user gesture, so the context is created on first click.
|
||||
var audioCtx = null;
|
||||
var alarmTimer = null;
|
||||
var beepedCritical = {}; // event_id -> true; each new critical beeps once immediately
|
||||
|
||||
function unlockAudio() {
|
||||
if (!audioCtx) {
|
||||
var AC = window.AudioContext || window.webkitAudioContext;
|
||||
if (AC) audioCtx = new AC();
|
||||
}
|
||||
document.removeEventListener('click', unlockAudio);
|
||||
}
|
||||
|
||||
function beep() {
|
||||
if (!audioCtx) return;
|
||||
try {
|
||||
var osc = audioCtx.createOscillator();
|
||||
var gain = audioCtx.createGain();
|
||||
osc.type = 'sine';
|
||||
osc.frequency.value = 880;
|
||||
gain.gain.value = 0.2;
|
||||
osc.connect(gain);
|
||||
gain.connect(audioCtx.destination);
|
||||
osc.start();
|
||||
osc.stop(audioCtx.currentTime + 0.4);
|
||||
} catch (e) {
|
||||
// audio unavailable; the visual list still surfaces the critical event
|
||||
}
|
||||
}
|
||||
|
||||
function updateAlarm(events) {
|
||||
var hasUnackedCritical = false;
|
||||
events.forEach(function (ev) {
|
||||
var acked = ev.acknowledged_by !== null && ev.acknowledged_by !== undefined && ev.acknowledged_by !== '';
|
||||
if (ev.severity === 'critical' && !acked) {
|
||||
hasUnackedCritical = true;
|
||||
if (!beepedCritical[ev.event_id]) { beepedCritical[ev.event_id] = true; beep(); }
|
||||
}
|
||||
});
|
||||
if (hasUnackedCritical && !alarmTimer) {
|
||||
alarmTimer = setInterval(beep, 3000);
|
||||
} else if (!hasUnackedCritical && alarmTimer) {
|
||||
clearInterval(alarmTimer);
|
||||
alarmTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
function buildRow(ev) {
|
||||
var isAcked = ev.acknowledged_by !== null && ev.acknowledged_by !== undefined && ev.acknowledged_by !== '';
|
||||
|
||||
|
|
@ -68,7 +117,11 @@
|
|||
|
||||
var type = document.createElement('div');
|
||||
type.className = 'event-type';
|
||||
type.textContent = String(ev.event_type || '');
|
||||
var typeLink = document.createElement('a');
|
||||
typeLink.className = 'event-detail-link';
|
||||
typeLink.href = '/events/' + encodeURIComponent(ev.event_id) + '/view';
|
||||
typeLink.textContent = String(ev.event_type || '');
|
||||
type.appendChild(typeLink);
|
||||
meta.appendChild(type);
|
||||
|
||||
var sub = document.createElement('div');
|
||||
|
|
@ -118,6 +171,8 @@
|
|||
return aAcked ? 1 : -1; // unacknowledged first
|
||||
});
|
||||
|
||||
updateAlarm(sorted); // before any early return, so an emptied list also silences the alarm
|
||||
|
||||
root.textContent = '';
|
||||
root.removeAttribute('aria-busy');
|
||||
if (sorted.length === 0) {
|
||||
|
|
@ -154,6 +209,8 @@
|
|||
});
|
||||
}
|
||||
|
||||
document.addEventListener('click', unlockAudio);
|
||||
|
||||
loadCsrfToken();
|
||||
loadEvents();
|
||||
setInterval(loadEvents, POLL_INTERVAL_MS);
|
||||
|
|
|
|||
Loading…
Reference in a new issue