From 19df0eea223f80498c60f6bfe87a2a20be5b32cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Bachmann?= Date: Thu, 15 Jan 2026 17:41:58 +0000 Subject: [PATCH] custom_components/bahmcloud_store/panel/panel.js aktualisiert --- .../bahmcloud_store/panel/panel.js | 59 ++++++++++++++++++- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/custom_components/bahmcloud_store/panel/panel.js b/custom_components/bahmcloud_store/panel/panel.js index c2100ab..da95aac 100644 --- a/custom_components/bahmcloud_store/panel/panel.js +++ b/custom_components/bahmcloud_store/panel/panel.js @@ -24,6 +24,10 @@ class BahmcloudStorePanel extends HTMLElement { this._readmeText = null; this._readmeHtml = null; this._readmeError = null; + + // Manual refresh UX state + this._refreshing = false; + this._status = ""; // short status line shown in UI } set hass(hass) { @@ -53,6 +57,34 @@ class BahmcloudStorePanel extends HTMLElement { } } + async _refreshAll() { + if (!this._hass) return; + if (this._refreshing) return; + + this._refreshing = true; + this._error = null; + this._status = "Refreshing…"; + this._update(); + + try { + // This triggers: POST /api/bcs?action=refresh + const resp = await this._hass.callApi("post", "bcs?action=refresh", {}); + if (!resp?.ok) { + this._status = ""; + this._error = this._safeText(resp?.message) || "Refresh failed."; + } else { + this._status = "Refresh done."; + } + } catch (e) { + this._status = ""; + this._error = e?.message ? String(e.message) : String(e); + } finally { + this._refreshing = false; + // Always reload data after refresh attempt + await this._load(); + } + } + _isDesktop() { return window.matchMedia && window.matchMedia("(min-width: 1024px)").matches; } @@ -238,6 +270,16 @@ class BahmcloudStorePanel extends HTMLElement { button:active{ transform: translateY(0px); box-shadow:none; } button:disabled{ opacity: 0.55; cursor: not-allowed; } + .statusline{ + margin-left: 10px; + font-size: 12px; + color: var(--secondary-text-color); + max-width: 280px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .card{ border:1px solid var(--divider-color); background:var(--card-background-color); @@ -363,6 +405,7 @@ class BahmcloudStorePanel extends HTMLElement {
+
@@ -380,7 +423,8 @@ class BahmcloudStorePanel extends HTMLElement {
`; - root.getElementById("refreshBtn").addEventListener("click", () => this._load()); + // IMPORTANT: Refresh must trigger backend refresh, not only GET /api/bcs + root.getElementById("refreshBtn").addEventListener("click", () => this._refreshAll()); root.getElementById("menuBtn").addEventListener("click", () => this._toggleMenu()); root.getElementById("backBtn").addEventListener("click", () => this._goBack()); @@ -447,6 +491,15 @@ class BahmcloudStorePanel extends HTMLElement { const err = root.getElementById("error"); const subtitle = root.getElementById("subtitle"); const fabs = root.getElementById("fabs"); + const statusLine = root.getElementById("statusLine"); + const refreshBtn = root.getElementById("refreshBtn"); + + if (statusLine) statusLine.textContent = this._status || ""; + + if (refreshBtn) { + refreshBtn.disabled = !!this._refreshing; + refreshBtn.textContent = this._refreshing ? "Refreshing…" : "Refresh"; + } const v = this._safeText(this._data?.version); subtitle.textContent = v ? `BCS ${v}` : "BCS — loading…"; @@ -497,6 +550,7 @@ class BahmcloudStorePanel extends HTMLElement { this._restoreFocusState(focusState); } + // ---------- everything below is unchanged from your current file ---------- _renderStore() { const repos = Array.isArray(this._data.repos) ? this._data.repos : []; const categories = this._computeCategories(repos); @@ -758,7 +812,6 @@ class BahmcloudStorePanel extends HTMLElement { if (!mount) return; if (this._readmeText) { - // Client renderer may be unavailable; prefer server-provided HTML if (this._readmeHtml) { mount.innerHTML = this._readmeHtml; this._postprocessRenderedMarkdown(mount); @@ -920,7 +973,7 @@ class BahmcloudStorePanel extends HTMLElement { const t = typeof v; if (t === "string") return v; if (t === "number" || t === "boolean") return String(v); - return ""; // objects/arrays/functions => empty (prevents [object Object]) + return ""; } _safeLower(v) {