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._detailRepo = null;
|
||||||
|
|
||||||
this._readmeLoading = false;
|
this._readmeLoading = false;
|
||||||
this._readmeText = null;
|
this._readmeText = null; // markdown string
|
||||||
this._readmeHtml = null;
|
this._readmeHtml = null; // sanitized html string
|
||||||
this._readmeError = null;
|
this._readmeError = null; // string
|
||||||
}
|
}
|
||||||
|
|
||||||
set hass(hass) {
|
set hass(hass) {
|
||||||
@@ -46,7 +46,7 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
const data = await this._hass.callApi("get", "bcs");
|
const data = await this._hass.callApi("get", "bcs");
|
||||||
this._data = data;
|
this._data = data;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this._error = e?.message ? String(e.message) : String(e);
|
this._error = this._toErrString(e);
|
||||||
} finally {
|
} finally {
|
||||||
this._loading = false;
|
this._loading = false;
|
||||||
this._update();
|
this._update();
|
||||||
@@ -106,7 +106,7 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
this._view = "manage";
|
this._view = "manage";
|
||||||
this._update();
|
this._update();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this._error = e?.message ? String(e.message) : String(e);
|
this._error = this._toErrString(e);
|
||||||
this._update();
|
this._update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,7 +120,7 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
this._view = "manage";
|
this._view = "manage";
|
||||||
this._update();
|
this._update();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this._error = e?.message ? String(e.message) : String(e);
|
this._error = this._toErrString(e);
|
||||||
this._update();
|
this._update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -142,9 +142,13 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
this._loadReadme(repoId);
|
this._loadReadme(repoId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- README fetching (hardened) ---
|
||||||
async _loadReadme(repoId) {
|
async _loadReadme(repoId) {
|
||||||
if (!this._hass) return;
|
if (!this._hass) return;
|
||||||
|
|
||||||
this._readmeLoading = true;
|
this._readmeLoading = true;
|
||||||
|
this._readmeText = null;
|
||||||
|
this._readmeHtml = null;
|
||||||
this._readmeError = null;
|
this._readmeError = null;
|
||||||
this._update();
|
this._update();
|
||||||
|
|
||||||
@@ -154,18 +158,37 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
`bcs/readme?repo_id=${encodeURIComponent(repoId)}`
|
`bcs/readme?repo_id=${encodeURIComponent(repoId)}`
|
||||||
);
|
);
|
||||||
|
|
||||||
if (resp?.ok && typeof resp.readme === "string" && resp.readme.trim()) {
|
// Normalize fields strictly (avoid [object Object])
|
||||||
this._readmeText = resp.readme;
|
const ok = resp && resp.ok === true;
|
||||||
this._readmeHtml = typeof resp.html === "string" && resp.html.trim() ? resp.html : null;
|
|
||||||
|
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 {
|
} 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._readmeText = null;
|
||||||
this._readmeHtml = null;
|
this._readmeHtml = null;
|
||||||
this._readmeError = this._safeText(resp?.message) || "README not found.";
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this._readmeText = null;
|
this._readmeText = null;
|
||||||
this._readmeHtml = null;
|
this._readmeHtml = null;
|
||||||
this._readmeError = e?.message ? String(e.message) : String(e);
|
this._readmeError = this._toErrString(e) || "README not found.";
|
||||||
} finally {
|
} finally {
|
||||||
this._readmeLoading = false;
|
this._readmeLoading = false;
|
||||||
this._update();
|
this._update();
|
||||||
@@ -544,10 +567,10 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
|
|
||||||
const creator = this._safeText(r?.owner) ? `Creator: ${this._safeText(r?.owner)}` : "Creator: -";
|
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 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 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 `
|
return `
|
||||||
<div class="card clickable" data-repo="${this._esc(id)}">
|
<div class="card clickable" data-repo="${this._esc(id)}">
|
||||||
@@ -652,7 +675,6 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
|
|
||||||
for (const r of repos) {
|
for (const r of repos) {
|
||||||
s.total += 1;
|
s.total += 1;
|
||||||
|
|
||||||
if (r?.source === "custom") s.custom += 1;
|
if (r?.source === "custom") s.custom += 1;
|
||||||
|
|
||||||
const p = this._safeLower(r?.provider) || "other";
|
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: -",
|
this._safeText(r?.owner) ? `Creator: ${this._safeText(r?.owner)}` : "Creator: -",
|
||||||
latest,
|
latest,
|
||||||
this._safeText(r?.provider) ? `Provider: ${this._safeText(r?.provider)}` : null,
|
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,
|
this._safeText(r?.meta_source) ? `Meta: ${this._safeText(r?.meta_source)}` : null,
|
||||||
].filter(Boolean);
|
].filter(Boolean);
|
||||||
|
|
||||||
@@ -758,8 +777,8 @@ 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
|
// We render server-side; only accept a real string html
|
||||||
if (this._readmeHtml) {
|
if (typeof this._readmeHtml === "string" && this._readmeHtml.trim()) {
|
||||||
mount.innerHTML = this._readmeHtml;
|
mount.innerHTML = this._readmeHtml;
|
||||||
this._postprocessRenderedMarkdown(mount);
|
this._postprocessRenderedMarkdown(mount);
|
||||||
return;
|
return;
|
||||||
@@ -914,13 +933,13 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
return Array.from(set).sort();
|
return Array.from(set).sort();
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- HARDENING HELPERS (fixes [object Object]) ---
|
// --- helpers (prevent [object Object]) ---
|
||||||
_safeText(v) {
|
_safeText(v) {
|
||||||
if (v === null || v === undefined) return "";
|
if (v === null || v === undefined) return "";
|
||||||
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) {
|
||||||
@@ -929,8 +948,18 @@ class BahmcloudStorePanel extends HTMLElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_safeId(v) {
|
_safeId(v) {
|
||||||
const s = this._safeText(v);
|
return this._safeText(v) || "";
|
||||||
return s || "";
|
}
|
||||||
|
|
||||||
|
_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) {
|
_esc(s) {
|
||||||
|
|||||||
Reference in New Issue
Block a user