diff --git a/telemetry/server/dashboard/dashboard.go b/telemetry/server/dashboard/dashboard.go
index c52236554..5a8b6e077 100644
--- a/telemetry/server/dashboard/dashboard.go
+++ b/telemetry/server/dashboard/dashboard.go
@@ -143,15 +143,24 @@ func (h *Handler) ServeIndex(w http.ResponseWriter, r *http.Request) {
Version Distribution
-
-
+
+
Versions Over Time
+
+
+
+
+
+
Operating System Distribution
-
+
+
+
@@ -204,13 +213,16 @@ func (h *Handler) ServeIndex(w http.ResponseWriter, r *http.Request) {
const versionsResponse = await fetch('/api/versions?days=30&limit=8');
const versions = await versionsResponse.json();
- updateStats(stats);
- createPieChart('osChart', stats.os_distribution || {});
- updateVersions(versions);
- updateClusterSizes(sizes);
-
+ // Show the dashboard before drawing into it: a canvas in a
+ // display:none container measures zero, and a pie sized from
+ // that never grows back.
document.getElementById('loading').style.display = 'none';
document.getElementById('dashboard').style.display = 'block';
+
+ updateStats(stats);
+ updateCharts(stats);
+ updateVersions(versions);
+ updateClusterSizes(sizes);
} catch (error) {
console.error('Error loading dashboard:', error);
showError('Failed to load telemetry data: ' + error.message);
@@ -225,7 +237,12 @@ func (h *Handler) ServeIndex(w http.ResponseWriter, r *http.Request) {
document.getElementById('totalOS').textContent = Object.keys(stats.os_distribution || {}).length;
}
- function createPieChart(canvasId, data) {
+ function updateCharts(stats) {
+ createPieChart('versionChart', 'Version Distribution', stats.versions || {});
+ createPieChart('osChart', 'Operating System Distribution', stats.os_distribution || {});
+ }
+
+ function createPieChart(canvasId, title, data) {
const ctx = document.getElementById(canvasId).getContext('2d');
if (charts[canvasId]) {
@@ -249,6 +266,9 @@ func (h *Handler) ServeIndex(w http.ResponseWriter, r *http.Request) {
},
options: {
responsive: true,
+ // Without this the canvas keeps its 2:1 attribute ratio at
+ // the card's full width, drawing a pie taller than the card.
+ maintainAspectRatio: false,
plugins: {
legend: {
position: 'bottom'
@@ -309,12 +329,13 @@ func (h *Handler) ServeIndex(w http.ResponseWriter, r *http.Request) {
// One stacked band per version: the band is how many clusters ran that
// version that day, the top of the stack is the confirmed fleet, so the
- // chart shows both how it grows and what it upgrades to.
+ // chart shows both how it grows and what it upgrades to. The pie above
+ // it is the same fleet on the last of these days.
function updateVersions(series) {
const versions = series.versions || [];
const dates = series.dates || [];
const total = series.total_clusters || 0;
- document.getElementById('versionTotal').textContent =
+ document.getElementById('versionSeriesTotal').textContent =
total + ' cluster' + (total === 1 ? '' : 's') + ' on ' + (dates[dates.length - 1] || 'no data');
// Newest release on the floor, oldest on top: the current release
@@ -329,7 +350,7 @@ func (h *Handler) ServeIndex(w http.ResponseWriter, r *http.Request) {
'#ffffff', '#9a9a94', 2));
}
- stackedArea('versionChart', dates, datasets, value => value, { plugins: [bandLabels] });
+ stackedArea('versionSeriesChart', dates, datasets, value => value, { plugins: [bandLabels] });
}
// Writes each version into its own band, so the chart reads without