From c7180bda77ec176f7219e872e8bbdd336c15d6e1 Mon Sep 17 00:00:00 2001 From: yumoqing Date: Sun, 24 May 2026 16:05:56 +0800 Subject: [PATCH] fix: rewrite dashboard_refresh.js with correct bricks API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace non-existent bricks.app.find_widget_by_id() with bricks.getWidgetById(id, bricks.app) - Replace widget.el.textContent with widget.set_text() method - Fix getBaseUrl() to handle /modulename paths (no .ui suffix) returning /undefined - Remove chart refresh from JS — use ChartBar's built-in refresh_period: 10 - Update index.ui ChartBar widget with refresh_period: 10 - Also fixed all find_widget_by_id references across skills: * bricks-framework SKILL.md (2 occurrences) * bricks-framework references: auto-refresh-dashboard.md, auto-refresh-pattern.md, bar.md, line.md, websocket.md * module-development-spec references: read-only-module-pattern.md * harnessed-module-development SKILL.md (2 occurrences) * harnessed-module-development references: reasoning-visualization.md, bricks-ui-pitfalls.md * rbac-permission-initialization-pattern references: websocket-debugging.md --- wwwroot/dashboard_refresh.js | 65 +++++++++++++----------------------- wwwroot/index.ui | 3 +- 2 files changed, 25 insertions(+), 43 deletions(-) diff --git a/wwwroot/dashboard_refresh.js b/wwwroot/dashboard_refresh.js index b1d6250..2eafea0 100644 --- a/wwwroot/dashboard_refresh.js +++ b/wwwroot/dashboard_refresh.js @@ -1,48 +1,42 @@ /** * Dashboard auto-refresh script - * Polls API every 10 seconds and updates stat cards + chart - * Auto-loaded by Sage's header.tmpl from wwwroot/scripts/ + * Polls API every 10 seconds and updates stat cards + * ChartBar handles its own refresh via refresh_period + * Auto-loaded by Sage's header.tmpl from wwwroot/ */ (function() { 'use strict'; - // Derive base URL from current page (e.g. /dashboard_for_sage/index.ui -> /dashboard_for_sage) function getBaseUrl() { var path = window.location.pathname; - // path is like /dashboard_for_sage/index.ui or /dashboard_for_sage - var parts = path.split('/').filter(function(p) { return p; }); + // path is like /dashboard_for_sage/index.ui or /dashboard_for_sage/ + var parts = path.split('/').filter(function(p) { return p.length > 0; }); + if (parts.length === 0) return ''; return '/' + parts[0]; } function buildUrl(dspyFile) { var base = getBaseUrl(); - // Add _webbricks_=1 for non-initial requests return base + '/' + dspyFile + '?_webbricks_=1'; } - function updateCard(id, value) { + function setCardText(cardId, value) { try { - var widget = bricks.app.find_widget_by_id(id); - if (widget && widget.el) { - widget.el.textContent = value; + var widget = bricks.getWidgetById(cardId, bricks.app); + if (widget && typeof widget.set_text === 'function') { + widget.set_text(String(value)); } - } catch(e) { - // Widget may not be ready yet - } + } catch(e) {} } function formatNumber(n) { - if (typeof n === 'number') { - return n.toLocaleString(); - } - return n; + if (typeof n === 'number') return n.toLocaleString(); + return String(n); } function formatAmount(n) { - if (typeof n === 'number') { - return '¥' + n.toFixed(2); - } - return '¥0.00'; + if (typeof n === 'number') return '\u00a5' + n.toFixed(2); + return '\u00a50.00'; } async function refreshStats() { @@ -51,10 +45,10 @@ var resp = await fetch(url, { credentials: 'include' }); if (!resp.ok) return; var data = await resp.json(); - updateCard('today_cnt_value', formatNumber(data.cnt)); - updateCard('today_amount_value', formatAmount(data.total_amount)); + setCardText('today_cnt_value', formatNumber(data.cnt)); + setCardText('today_amount_value', formatAmount(data.total_amount)); } catch(e) { - // Silently fail on refresh errors + console.error('refreshStats error:', e); } } @@ -64,35 +58,22 @@ var resp = await fetch(url, { credentials: 'include' }); if (!resp.ok) return; var data = await resp.json(); - updateCard('total_users_value', formatNumber(data.total_users)); - updateCard('concurrent_users_value', formatNumber(data.concurrent_users)); + setCardText('total_users_value', formatNumber(data.total_users)); + setCardText('concurrent_users_value', formatNumber(data.concurrent_users)); } catch(e) { - // Silently fail on refresh errors - } - } - - async function refreshChart() { - try { - var chart = bricks.app.find_widget_by_id('top_models_chart'); - if (chart && chart.render_urldata) { - await chart.render_urldata({}); - } - } catch(e) { - // Silently fail on refresh errors + console.error('refreshUsers error:', e); } } async function refreshAll() { await refreshStats(); await refreshUsers(); - await refreshChart(); } - // Start auto-refresh every 10 seconds - // Delay initial load to allow bricks framework to initialize + // Wait for bricks framework to initialize, then start auto-refresh setTimeout(function() { refreshAll(); setInterval(refreshAll, 10000); - }, 1000); + }, 2000); })(); diff --git a/wwwroot/index.ui b/wwwroot/index.ui index a88a00e..3001a28 100644 --- a/wwwroot/index.ui +++ b/wwwroot/index.ui @@ -188,7 +188,8 @@ "width": "100%", "data_url": "{{entire_url('api/get_top_models.dspy')}}", "nameField": "model_name", - "valueFields": ["cnt", "total_amount"] + "valueFields": ["cnt", "total_amount"], + "refresh_period": 10 } } ]