custom_components/bahmcloud_store/panel/panel.js aktualisiert
This commit is contained in:
@@ -24,6 +24,10 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
this._readmeText = null;
|
this._readmeText = null;
|
||||||
this._readmeHtml = null;
|
this._readmeHtml = null;
|
||||||
this._readmeError = null;
|
this._readmeError = null;
|
||||||
|
|
||||||
|
// Manual refresh UX state
|
||||||
|
this._refreshing = false;
|
||||||
|
this._status = ""; // short status line shown in UI
|
||||||
}
|
}
|
||||||
|
|
||||||
set hass(hass) {
|
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() {
|
_isDesktop() {
|
||||||
return window.matchMedia && window.matchMedia("(min-width: 1024px)").matches;
|
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:active{ transform: translateY(0px); box-shadow:none; }
|
||||||
button:disabled{ opacity: 0.55; cursor: not-allowed; }
|
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{
|
.card{
|
||||||
border:1px solid var(--divider-color);
|
border:1px solid var(--divider-color);
|
||||||
background:var(--card-background-color);
|
background:var(--card-background-color);
|
||||||
@@ -363,6 +405,7 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
</div>
|
</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<button id="refreshBtn" class="primary">Refresh</button>
|
<button id="refreshBtn" class="primary">Refresh</button>
|
||||||
|
<div class="statusline" id="statusLine"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -380,7 +423,8 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
<div id="fabs"></div>
|
<div id="fabs"></div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
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("menuBtn").addEventListener("click", () => this._toggleMenu());
|
||||||
root.getElementById("backBtn").addEventListener("click", () => this._goBack());
|
root.getElementById("backBtn").addEventListener("click", () => this._goBack());
|
||||||
|
|
||||||
@@ -447,6 +491,15 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
const err = root.getElementById("error");
|
const err = root.getElementById("error");
|
||||||
const subtitle = root.getElementById("subtitle");
|
const subtitle = root.getElementById("subtitle");
|
||||||
const fabs = root.getElementById("fabs");
|
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);
|
const v = this._safeText(this._data?.version);
|
||||||
subtitle.textContent = v ? `BCS ${v}` : "BCS — loading…";
|
subtitle.textContent = v ? `BCS ${v}` : "BCS — loading…";
|
||||||
@@ -497,6 +550,7 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
this._restoreFocusState(focusState);
|
this._restoreFocusState(focusState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------- everything below is unchanged from your current file ----------
|
||||||
_renderStore() {
|
_renderStore() {
|
||||||
const repos = Array.isArray(this._data.repos) ? this._data.repos : [];
|
const repos = Array.isArray(this._data.repos) ? this._data.repos : [];
|
||||||
const categories = this._computeCategories(repos);
|
const categories = this._computeCategories(repos);
|
||||||
@@ -758,7 +812,6 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
if (!mount) return;
|
if (!mount) return;
|
||||||
|
|
||||||
if (this._readmeText) {
|
if (this._readmeText) {
|
||||||
// Client renderer may be unavailable; prefer server-provided HTML
|
|
||||||
if (this._readmeHtml) {
|
if (this._readmeHtml) {
|
||||||
mount.innerHTML = this._readmeHtml;
|
mount.innerHTML = this._readmeHtml;
|
||||||
this._postprocessRenderedMarkdown(mount);
|
this._postprocessRenderedMarkdown(mount);
|
||||||
@@ -920,7 +973,7 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
const t = typeof v;
|
const t = typeof v;
|
||||||
if (t === "string") return v;
|
if (t === "string") return v;
|
||||||
if (t === "number" || t === "boolean") return String(v);
|
if (t === "number" || t === "boolean") return String(v);
|
||||||
return ""; // objects/arrays/functions => empty (prevents [object Object])
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
_safeLower(v) {
|
_safeLower(v) {
|
||||||
|
|||||||
Reference in New Issue
Block a user