v2.0.14 — oumta-dashboard: self-healing poll loop
Initial-bootstrap failure stopped the poll interval from ever starting, and even once running, refresh() never reset the indicator back to 'polling' on success — so a single upstream blip pinned the plugin in an error state until the user reloaded the page. refresh() now loads namespaces on demand (absorbs bootstrap), the interval is started unconditionally on show(), and every successful poll flips the indicator back to green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
efd3f9d5ae
commit
cdfb6d4ecd
2 files changed
+26
-22
No files matched your search
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
define('APP_NAME', 'hyprcrd');
|
define('APP_NAME', 'hyprcrd');
|
||||||
define('APP_VERSION', '2.0.13');
|
define('APP_VERSION', '2.0.14');
|
||||||
|
|
||||||
// APP_DEBUG: gates verbose error responses (curl traces, upstream bodies).
|
// APP_DEBUG: gates verbose error responses (curl traces, upstream bodies).
|
||||||
// Off by default; enable via env for local troubleshooting only.
|
// Off by default; enable via env for local troubleshooting only.
|
||||||
|
|||||||
@@ -54,11 +54,12 @@ function isOpen() {
|
|||||||
function show() {
|
function show() {
|
||||||
if (!overlay) return;
|
if (!overlay) return;
|
||||||
overlay.classList.add('open');
|
overlay.classList.add('open');
|
||||||
if (!state.namespaces.length) bootstrap();
|
// Always kick off polling — refresh() self-heals: it loads namespaces
|
||||||
else {
|
// if they aren't there yet, and the interval keeps retrying even if
|
||||||
refresh();
|
// the initial poll fails. Previously an initial bootstrap failure
|
||||||
startLive();
|
// stopped the loop entirely and required a page reload to recover.
|
||||||
}
|
refresh();
|
||||||
|
startLive();
|
||||||
}
|
}
|
||||||
function hide() {
|
function hide() {
|
||||||
if (!overlay) return;
|
if (!overlay) return;
|
||||||
@@ -70,21 +71,6 @@ function toggle() {
|
|||||||
}
|
}
|
||||||
window._oumtaToggle = toggle;
|
window._oumtaToggle = toggle;
|
||||||
|
|
||||||
// ── Bootstrap: load namespaces, then first refresh ─────────────
|
|
||||||
|
|
||||||
async function bootstrap() {
|
|
||||||
try {
|
|
||||||
const res = await api('/api/namespaces');
|
|
||||||
state.namespaces = res.items || [];
|
|
||||||
state.activeNamespace = state.namespaces[0] || null;
|
|
||||||
renderNamespaceTabs();
|
|
||||||
await refresh();
|
|
||||||
startLive();
|
|
||||||
} catch (e) {
|
|
||||||
setLive('error', e.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderNamespaceTabs() {
|
function renderNamespaceTabs() {
|
||||||
const host = $('oumta-ns-tabs');
|
const host = $('oumta-ns-tabs');
|
||||||
if (!host) return;
|
if (!host) return;
|
||||||
@@ -125,10 +111,27 @@ function switchView(view) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ── Refresh all data for the active namespace ──────────────────
|
// ── Refresh all data for the active namespace ──────────────────
|
||||||
|
//
|
||||||
|
// Self-healing: if namespaces aren't loaded yet (e.g. initial poll
|
||||||
|
// failed), fetch them first; if upstream is down, leave state as
|
||||||
|
// 'error' and let the next interval tick try again. On any successful
|
||||||
|
// poll we flip back to 'polling' so the indicator recovers without a
|
||||||
|
// page reload.
|
||||||
|
|
||||||
async function refresh() {
|
async function refresh() {
|
||||||
if (!state.activeNamespace) return;
|
|
||||||
try {
|
try {
|
||||||
|
if (!state.activeNamespace) {
|
||||||
|
const res = await api('/api/namespaces');
|
||||||
|
state.namespaces = res.items || [];
|
||||||
|
state.activeNamespace = state.namespaces[0] || null;
|
||||||
|
renderNamespaceTabs();
|
||||||
|
}
|
||||||
|
if (!state.activeNamespace) {
|
||||||
|
// Namespaces endpoint returned empty — nothing to poll yet.
|
||||||
|
// Stay in 'polling' so we keep retrying on the interval.
|
||||||
|
setLive('polling');
|
||||||
|
return;
|
||||||
|
}
|
||||||
const [ov, wl, tl] = await Promise.all([
|
const [ov, wl, tl] = await Promise.all([
|
||||||
api('/api/cluster/overview'),
|
api('/api/cluster/overview'),
|
||||||
api('/api/workloads'),
|
api('/api/workloads'),
|
||||||
@@ -138,6 +141,7 @@ async function refresh() {
|
|||||||
state.data.workloads = wl.items || [];
|
state.data.workloads = wl.items || [];
|
||||||
state.data.timeline = tl.items || [];
|
state.data.timeline = tl.items || [];
|
||||||
renderAll();
|
renderAll();
|
||||||
|
setLive('polling');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setLive('error', e.message);
|
setLive('error', e.message);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user