custom_components/bahmcloud_store/panel/panel.js aktualisiert
This commit is contained in:
@@ -21,9 +21,9 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
this._detailRepo = null;
|
||||
|
||||
this._readmeLoading = false;
|
||||
this._readmeText = null;
|
||||
this._readmeHtml = null;
|
||||
this._readmeError = null;
|
||||
this._readmeText = null; // markdown string
|
||||
this._readmeHtml = null; // sanitized html string
|
||||
this._readmeError = null; // string
|
||||
}
|
||||
|
||||
set hass(hass) {
|
||||
@@ -46,7 +46,7 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
const data = await this._hass.callApi("get", "bcs");
|
||||
this._data = data;
|
||||
} catch (e) {
|
||||
this._error = e?.message ? String(e.message) : String(e);
|
||||
this._error = this._toErrString(e);
|
||||
} finally {
|
||||
this._loading = false;
|
||||
this._update();
|
||||
@@ -106,7 +106,7 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
this._view = "manage";
|
||||
this._update();
|
||||
} catch (e) {
|
||||
this._error = e?.message ? String(e.message) : String(e);
|
||||
this._error = this._toErrString(e);
|
||||
this._update();
|
||||
}
|
||||
}
|
||||
@@ -120,7 +120,7 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
this._view = "manage";
|
||||
this._update();
|
||||
} catch (e) {
|
||||
this._error = e?.message ? String(e.message) : String(e);
|
||||
this._error = this._toErrString(e);
|
||||
this._update();
|
||||
}
|
||||
}
|
||||
@@ -142,9 +142,13 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
this._loadReadme(repoId);
|
||||
}
|
||||
|
||||
// --- README fetching (hardened) ---
|
||||
async _loadReadme(repoId) {
|
||||
if (!this._hass) return;
|
||||
|
||||
this._readmeLoading = true;
|
||||
this._readmeText = null;
|
||||
this._readmeHtml = null;
|
||||
this._readmeError = null;
|
||||
this._update();
|
||||
|
||||
@@ -154,18 +158,37 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
`bcs/readme?repo_id=${encodeURIComponent(repoId)}`
|
||||
);
|
||||
|
||||
if (resp?.ok && typeof resp.readme === "string" && resp.readme.trim()) {
|
||||
this._readmeText = resp.readme;
|
||||
this._readmeHtml = typeof resp.html === "string" && resp.html.trim() ? resp.html : null;
|
||||
// Normalize fields strictly (avoid [object Object])
|
||||
const ok = resp && resp.ok === true;
|
||||
|
||||
const readme = (resp && typeof resp.readme === "string") ? resp.readme : null;
|
||||
const html = (resp && typeof resp.html === "string") ? resp.html : null;
|
||||
|
||||
if (ok && readme && readme.trim()) {
|
||||
this._readmeText = readme;
|
||||
this._readmeHtml = html && html.trim() ? html : null;
|
||||
this._readmeError = null;
|
||||
} else {
|
||||
// If backend provided a message, convert it safely
|
||||
const msg =
|
||||
(resp && typeof resp.message === "string" && resp.message.trim())
|
||||
? resp.message.trim()
|
||||
: "README not found.";
|
||||
|
||||
// Extra hint if backend returned unexpected types
|
||||
if (ok && resp && resp.readme && typeof resp.readme !== "string") {
|
||||
this._readmeError = "README has an unsupported format (expected text).";
|
||||
} else {
|
||||
this._readmeError = msg;
|
||||
}
|
||||
|
||||
this._readmeText = null;
|
||||
this._readmeHtml = null;
|
||||
this._readmeError = this._safeText(resp?.message) || "README not found.";
|
||||
}
|
||||
} catch (e) {
|
||||
this._readmeText = null;
|
||||
this._readmeHtml = null;
|
||||
this._readmeError = e?.message ? String(e.message) : String(e);
|
||||
this._readmeError = this._toErrString(e) || "README not found.";
|
||||
} finally {
|
||||
this._readmeLoading = false;
|
||||
this._update();
|
||||
@@ -544,10 +567,10 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
|
||||
const creator = this._safeText(r?.owner) ? `Creator: ${this._safeText(r?.owner)}` : "Creator: -";
|
||||
const latest = this._safeText(r?.latest_version) ? `Latest: ${this._safeText(r?.latest_version)}` : "Latest: unknown";
|
||||
const cat = this._safeText(r?.category) ? `Category: ${this._safeText(r?.category)}` : null;
|
||||
const prov = this._safeText(r?.provider) ? `Provider: ${this._safeText(r?.provider)}` : null;
|
||||
const metaSrc = this._safeText(r?.meta_source) ? `Meta: ${this._safeText(r?.meta_source)}` : null;
|
||||
|
||||
const lineBits = [creator, latest, cat, metaSrc].filter(Boolean);
|
||||
const lineBits = [creator, latest, prov, metaSrc].filter(Boolean);
|
||||
|
||||
return `
|
||||
<div class="card clickable" data-repo="${this._esc(id)}">
|
||||
@@ -652,7 +675,6 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
|
||||
for (const r of repos) {
|
||||
s.total += 1;
|
||||
|
||||
if (r?.source === "custom") s.custom += 1;
|
||||
|
||||
const p = this._safeLower(r?.provider) || "other";
|
||||
@@ -683,9 +705,6 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
this._safeText(r?.owner) ? `Creator: ${this._safeText(r?.owner)}` : "Creator: -",
|
||||
latest,
|
||||
this._safeText(r?.provider) ? `Provider: ${this._safeText(r?.provider)}` : null,
|
||||
this._safeText(r?.category) ? `Category: ${this._safeText(r?.category)}` : null,
|
||||
this._safeText(r?.meta_author) ? `Author: ${this._safeText(r?.meta_author)}` : null,
|
||||
this._safeText(r?.meta_maintainer) ? `Maintainer: ${this._safeText(r?.meta_maintainer)}` : null,
|
||||
this._safeText(r?.meta_source) ? `Meta: ${this._safeText(r?.meta_source)}` : null,
|
||||
].filter(Boolean);
|
||||
|
||||
@@ -758,8 +777,8 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
if (!mount) return;
|
||||
|
||||
if (this._readmeText) {
|
||||
// Client renderer may be unavailable; prefer server-provided HTML
|
||||
if (this._readmeHtml) {
|
||||
// We render server-side; only accept a real string html
|
||||
if (typeof this._readmeHtml === "string" && this._readmeHtml.trim()) {
|
||||
mount.innerHTML = this._readmeHtml;
|
||||
this._postprocessRenderedMarkdown(mount);
|
||||
return;
|
||||
@@ -914,13 +933,13 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
return Array.from(set).sort();
|
||||
}
|
||||
|
||||
// --- HARDENING HELPERS (fixes [object Object]) ---
|
||||
// --- helpers (prevent [object Object]) ---
|
||||
_safeText(v) {
|
||||
if (v === null || v === undefined) return "";
|
||||
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) {
|
||||
@@ -929,8 +948,18 @@ class BahmcloudStorePanel extends HTMLElement {
|
||||
}
|
||||
|
||||
_safeId(v) {
|
||||
const s = this._safeText(v);
|
||||
return s || "";
|
||||
return this._safeText(v) || "";
|
||||
}
|
||||
|
||||
_toErrString(e) {
|
||||
if (!e) return "Unknown error";
|
||||
if (typeof e === "string") return e;
|
||||
if (typeof e?.message === "string") return e.message;
|
||||
try {
|
||||
return JSON.stringify(e);
|
||||
} catch (_) {
|
||||
return "Unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
_esc(s) {
|
||||
|
||||
Reference in New Issue
Block a user