From dde2910a1d2cef2e8fd02034d32262269850cb4a Mon Sep 17 00:00:00 2001 From: jgor20 <102353650+jgor20@users.noreply.github.com> Date: Sun, 11 Jan 2026 15:34:51 +0000 Subject: [PATCH] perf(ui): optimize dashboard chart updates and rendering Add debouncing to chart updates to prevent rapid flickering, implement checks to avoid redundant history processing and double renders, and disable quota chart animations to fix visual glitches. --- public/js/components/dashboard.js | 26 +++++++++++++++++++----- public/js/components/dashboard/charts.js | 4 ++-- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/public/js/components/dashboard.js b/public/js/components/dashboard.js index 74ccd4b..29b40c7 100644 --- a/public/js/components/dashboard.js +++ b/public/js/components/dashboard.js @@ -45,13 +45,24 @@ window.Components.dashboard = () => ({ this.$watch('$store.data.accounts', () => { if (this.$store.global.activeTab === 'dashboard') { this.updateStats(); - this.$nextTick(() => this.updateCharts()); + // Debounce chart updates to prevent rapid flickering + if (this._debouncedUpdateCharts) { + this._debouncedUpdateCharts(); + } else { + this._debouncedUpdateCharts = window.utils.debounce(() => this.updateCharts(), 100); + this._debouncedUpdateCharts(); + } } }); // Watch for history updates from data-store (automatically loaded with account data) this.$watch('$store.data.usageHistory', (newHistory) => { if (this.$store.global.activeTab === 'dashboard' && newHistory && Object.keys(newHistory).length > 0) { + // Optimization: Skip if data hasn't changed (prevents double render on load) + if (this.historyData && JSON.stringify(newHistory) === JSON.stringify(this.historyData)) { + return; + } + this.historyData = newHistory; this.processHistory(newHistory); this.stats.hasTrendData = true; @@ -59,17 +70,22 @@ window.Components.dashboard = () => ({ }); // Initial update if already on dashboard + // Note: Alpine.store('data') may already have data from cache if initialized before this component if (this.$store.global.activeTab === 'dashboard') { this.$nextTick(() => { this.updateStats(); this.updateCharts(); - // Load history if already in store + // Optimization: Only process history if it hasn't been processed yet + // The usageHistory watcher above will handle updates if data changes const history = Alpine.store('data').usageHistory; if (history && Object.keys(history).length > 0) { - this.historyData = history; - this.processHistory(history); - this.stats.hasTrendData = true; + // Check if we already have this data to avoid redundant chart update + if (!this.historyData || JSON.stringify(history) !== JSON.stringify(this.historyData)) { + this.historyData = history; + this.processHistory(history); + this.stats.hasTrendData = true; + } } }); } diff --git a/public/js/components/dashboard/charts.js b/public/js/components/dashboard/charts.js index cf7578f..3641042 100644 --- a/public/js/components/dashboard/charts.js +++ b/public/js/components/dashboard/charts.js @@ -297,8 +297,8 @@ window.DashboardCharts.updateCharts = function (component) { title: { display: false }, }, animation: { - animateScale: true, - animateRotate: true, + // Disable animation for quota chart to prevent "double refresh" visual glitch + duration: 0 }, }, });