🐛 fix: dashboard bugs — graceful degradation, dbPath config, auth expiry detection
- fetchWithTimeout now rejects non-2xx HTTP status codes - normalizeStats takes system object, reads dbPath from config - Inventory special-cased (no longer syncs GitHub) - dashboard.html detects HTML/auth redirect and shows reload link - dashboard-systems.json: add dbPath for all UseCaseGen apps
This commit is contained in:
parent
350483c26c
commit
2f60e99efc
3 changed files with 40 additions and 23 deletions
|
|
@ -8,7 +8,7 @@
|
|||
"apiBase": "http://127.0.0.1:3030",
|
||||
"statsEndpoint": "/api/dashboard/internal-stats",
|
||||
"authType": "self",
|
||||
"icon": "\ud83d\udd10"
|
||||
"icon": "🔐"
|
||||
},
|
||||
{
|
||||
"id": "model-service",
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
"apiBase": "http://127.0.0.1:3093",
|
||||
"statsEndpoint": "/health",
|
||||
"authType": "oauth2",
|
||||
"icon": "\ud83e\udd16"
|
||||
"icon": "🤖"
|
||||
},
|
||||
{
|
||||
"id": "inventory",
|
||||
|
|
@ -28,7 +28,7 @@
|
|||
"apiBase": "http://127.0.0.1:3025",
|
||||
"statsEndpoint": "/api/github",
|
||||
"authType": "oauth2",
|
||||
"icon": "\ud83d\udccb"
|
||||
"icon": "📋"
|
||||
},
|
||||
{
|
||||
"id": "incorta-dashboard",
|
||||
|
|
@ -38,7 +38,7 @@
|
|||
"apiBase": "http://127.0.0.1:3013",
|
||||
"statsEndpoint": "/health",
|
||||
"authType": "oauth2",
|
||||
"icon": "\ud83d\udcca"
|
||||
"icon": "📊"
|
||||
},
|
||||
{
|
||||
"id": "eco-usecasegen",
|
||||
|
|
@ -48,7 +48,8 @@
|
|||
"apiBase": "http://127.0.0.1:3090",
|
||||
"statsEndpoint": "/api/admin/usage",
|
||||
"authType": "standalone",
|
||||
"icon": "\ud83c\udf3f"
|
||||
"dbPath": "/var/www/eco-usecasegen/data/users.db",
|
||||
"icon": "🌿"
|
||||
},
|
||||
{
|
||||
"id": "ggl-usecasegen",
|
||||
|
|
@ -58,7 +59,8 @@
|
|||
"apiBase": "http://127.0.0.1:3095",
|
||||
"statsEndpoint": "/api/admin/usage",
|
||||
"authType": "standalone",
|
||||
"icon": "\ud83d\udd0d"
|
||||
"dbPath": "/var/www/ggl-usecasegen/data/users.db",
|
||||
"icon": "🔍"
|
||||
},
|
||||
{
|
||||
"id": "fdx-usecasegen",
|
||||
|
|
@ -68,7 +70,8 @@
|
|||
"apiBase": "http://127.0.0.1:3089",
|
||||
"statsEndpoint": "/health",
|
||||
"authType": "standalone",
|
||||
"icon": "\ud83d\udce6"
|
||||
"dbPath": "/var/www/fedex-cohort-app/data/users.db",
|
||||
"icon": "📦"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,6 +103,11 @@
|
|||
render(cachedData);
|
||||
} else {
|
||||
const res = await fetch('/api/dashboard/stats');
|
||||
const contentType = res.headers.get('content-type') || '';
|
||||
// Detect auth redirect (HTML response from oauth2-proxy)
|
||||
if (contentType.includes('text/html')) {
|
||||
throw new Error('AUTH_EXPIRED');
|
||||
}
|
||||
if (!res.ok) throw new Error('Failed to load stats: ' + res.status);
|
||||
const data = await res.json();
|
||||
cachedData = data;
|
||||
|
|
@ -110,7 +115,14 @@
|
|||
render(data);
|
||||
}
|
||||
} catch (e) {
|
||||
document.getElementById('last-updated').textContent = 'Error: ' + e.message;
|
||||
const msg = e.message === 'AUTH_EXPIRED'
|
||||
? 'Session expired — refresh page to re-authenticate'
|
||||
: 'Error: ' + e.message;
|
||||
document.getElementById('last-updated').textContent = msg;
|
||||
if (e.message === 'AUTH_EXPIRED') {
|
||||
document.getElementById('last-updated').innerHTML =
|
||||
'Session expired — <a href="/dashboard.html" style="color:#3b82f6">reload page</a>';
|
||||
}
|
||||
console.error(e);
|
||||
} finally {
|
||||
btn.disabled = false;
|
||||
|
|
|
|||
30
server.js
30
server.js
|
|
@ -777,6 +777,10 @@ function saveDashboardSystems(systems) {
|
|||
async function fetchWithTimeout(url, timeoutMs = 500) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const req = http.get(url, { timeout: timeoutMs }, (res) => {
|
||||
if (res.statusCode < 200 || res.statusCode >= 300) {
|
||||
reject(new Error(`HTTP ${res.statusCode}`));
|
||||
return;
|
||||
}
|
||||
let data = '';
|
||||
res.on('data', chunk => data += chunk);
|
||||
res.on('end', () => {
|
||||
|
|
@ -793,7 +797,8 @@ async function fetchWithTimeout(url, timeoutMs = 500) {
|
|||
});
|
||||
}
|
||||
|
||||
function normalizeStats(systemId, raw) {
|
||||
function normalizeStats(system, raw) {
|
||||
const systemId = system.id;
|
||||
if (systemId === 'access-manager') {
|
||||
const users = loadUsers();
|
||||
return {
|
||||
|
|
@ -808,21 +813,18 @@ function normalizeStats(systemId, raw) {
|
|||
status: raw.status
|
||||
};
|
||||
}
|
||||
if (systemId === 'inventory') {
|
||||
// Inventory no longer syncs GitHub repos; show online with no metrics
|
||||
return {};
|
||||
}
|
||||
if (systemId.includes('usecasegen')) {
|
||||
// Query actual DB for user count (session counters reset on restart)
|
||||
let dbUsers = 0;
|
||||
try {
|
||||
const Database = require('better-sqlite3');
|
||||
if (systemId === 'eco-usecasegen') {
|
||||
const db = new Database('/var/www/eco-usecasegen/data/users.db', { readonly: true });
|
||||
dbUsers = db.prepare('SELECT COUNT(*) as count FROM users').get()?.count || 0;
|
||||
db.close();
|
||||
} else if (systemId === 'ggl-usecasegen') {
|
||||
const db = new Database('/var/www/ggl-usecasegen/data/users.db', { readonly: true });
|
||||
dbUsers = db.prepare('SELECT COUNT(*) as count FROM users').get()?.count || 0;
|
||||
db.close();
|
||||
} else if (systemId === 'fdx-usecasegen') {
|
||||
const db = new Database('/var/www/fedex-cohort-app/data/users.db', { readonly: true });
|
||||
const dbPath = system.dbPath;
|
||||
if (dbPath) {
|
||||
const Database = require('better-sqlite3');
|
||||
const db = new Database(dbPath, { readonly: true });
|
||||
dbUsers = db.prepare('SELECT COUNT(*) as count FROM users').get()?.count || 0;
|
||||
db.close();
|
||||
}
|
||||
|
|
@ -846,11 +848,11 @@ app.get('/api/dashboard/stats', requireAdmin, async (req, res) => {
|
|||
let stats;
|
||||
if (sys.authType === 'self') {
|
||||
// Local query
|
||||
stats = normalizeStats(sys.id, {});
|
||||
stats = normalizeStats(sys, {});
|
||||
} else {
|
||||
const url = sys.apiBase + sys.statsEndpoint;
|
||||
const raw = await fetchWithTimeout(url, 1000);
|
||||
stats = normalizeStats(sys.id, raw);
|
||||
stats = normalizeStats(sys, raw);
|
||||
}
|
||||
return { ...sys, status: 'ok', stats, error: null };
|
||||
} catch (e) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue