diff --git a/internal/control/ui.html b/internal/control/ui.html
index 8445eca..ff13122 100644
--- a/internal/control/ui.html
+++ b/internal/control/ui.html
@@ -1077,6 +1077,8 @@ input.input-error {
+
+
@@ -1714,7 +1716,7 @@ function render() {
updateText('info-fmmod', fmtBool(cfg.fm?.fmModulationEnabled));
updateText('info-live', engine.state ? `${String(engine.state).toUpperCase()} / ${state.server.runtimeOk ? 'runtime ok' : 'runtime pending'}` : (state.server.configOk ? 'config only' : '--'));
- updateHealth(audioStream);
+ updateHealth(engine, audioStream);
updateMeters(engine, driver, audioStream);
drawSparkline('spark-audio', state.charts.audio, 'good', 1);
drawSparkline('spark-underruns', state.charts.underruns, underruns > 0 ? 'err' : 'warn');
@@ -1731,7 +1733,8 @@ function renderToggle(key, toggleId, labelId) {
updateText(labelId, busy ? '...' : (on ? 'ON' : 'OFF'));
}
-function updateHealth(audioStream) {
+function updateHealth(engine, audioStream) {
+ engine = engine || {};
updateText('health-http', state.server.configOk ? 'OK' : 'OFFLINE');
$('health-http').className = 'val ' + (state.server.configOk ? 'good' : 'err');
@@ -1739,6 +1742,31 @@ function updateHealth(audioStream) {
updateText('health-runtime', runtimeState);
$('health-runtime').className = 'val ' + (state.server.runtimeOk ? 'good' : 'warn');
+ const runtimeIndicator = engine.runtimeIndicator;
+ const indicatorLabels = {
+ normal: 'Normal',
+ degraded: 'Degraded',
+ queueCritical: 'Queue critical',
+ };
+ const indicatorText = indicatorLabels[runtimeIndicator] || (runtimeIndicator ? runtimeIndicator : '--');
+ let indicatorSeverity = '';
+ if (runtimeIndicator === 'queueCritical') indicatorSeverity = 'err';
+ else if (runtimeIndicator === 'degraded') indicatorSeverity = 'warn';
+ else if (runtimeIndicator === 'normal') indicatorSeverity = 'good';
+ const indicatorEl = $('health-indicator');
+ if (indicatorEl) {
+ indicatorEl.className = 'val' + (indicatorSeverity ? ' ' + indicatorSeverity : '');
+ }
+ updateText('health-indicator', indicatorText);
+
+ const runtimeAlertRaw = (engine.runtimeAlert || '').trim();
+ const hasAlert = !!runtimeAlertRaw;
+ const alertEl = $('health-alert');
+ if (alertEl) {
+ alertEl.className = 'val ' + (hasAlert ? 'warn' : 'good');
+ }
+ updateText('health-alert', hasAlert ? runtimeAlertRaw : 'None');
+
let audioLabel = 'N/A';
let audioClass = 'val';
if (audioStream) {