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) {