fix(dashboard): add COALESCE to SQL aggregations and empty-state handling for charts
Some checks failed
CI / Check (push) Has been cancelled
CI / Clippy (push) Has been cancelled
CI / Formatting (push) Has been cancelled
CI / Test (push) Has been cancelled
CI / Release Build (push) Has been cancelled

Backend: wrap SUM() queries with COALESCE in handle_time_series,
handle_clients_usage, and handle_detailed_usage to prevent NULL-induced
panics when no data exists for a time window.

Frontend: add showEmptyChart() empty-state messages and error feedback
across overview, analytics, costs, and clients pages. Rewrite analytics
loadCharts() to use Promise.allSettled() so each chart renders
independently on partial API failures.
This commit is contained in:
2026-03-02 11:48:17 -05:00
parent 9c01b97f82
commit e4cf088071
5 changed files with 134 additions and 17 deletions

View File

@@ -78,8 +78,7 @@ class ClientsPage {
const data = await window.api.get('/usage/clients');
if (!data || data.length === 0) {
const canvas = document.getElementById('client-usage-chart');
if (canvas) canvas.closest('.chart-container').style.display = 'none';
this.showEmptyChart('client-usage-chart', 'No client usage data yet');
return;
}
@@ -96,6 +95,24 @@ class ClientsPage {
} catch (error) {
console.error('Error loading client usage chart:', error);
this.showEmptyChart('client-usage-chart', 'Failed to load usage data');
}
}
showEmptyChart(canvasId, message) {
const canvas = document.getElementById(canvasId);
if (!canvas) return;
const container = canvas.closest('.chart-container');
if (container) {
canvas.style.display = 'none';
let msg = container.querySelector('.empty-chart-msg');
if (!msg) {
msg = document.createElement('div');
msg.className = 'empty-chart-msg';
msg.style.cssText = 'display:flex;align-items:center;justify-content:center;height:200px;color:var(--fg4);font-size:0.9rem;';
container.appendChild(msg);
}
msg.textContent = message;
}
}