diff --git a/frontend/ssh-docker-panel.js b/frontend/ssh-docker-panel.js
index cfd0fbf..5530d8b 100644
--- a/frontend/ssh-docker-panel.js
+++ b/frontend/ssh-docker-panel.js
@@ -9,6 +9,8 @@ class SshDockerPanel extends HTMLElement {
this._narrow = false;
this._lastSnapshot = null;
this._collapsedHosts = new Set();
+ this._failedEntries = [];
+ this._isFetchingFailedEntries = false;
}
set hass(hass) {
@@ -39,6 +41,7 @@ class SshDockerPanel extends HTMLElement {
if (document.visibilityState === "visible" && this._hass) {
this._lastSnapshot = null; // force re-render
this._render();
+ this._refreshFailedEntries();
}
};
document.addEventListener("visibilitychange", this._visibilityHandler);
@@ -49,6 +52,7 @@ class SshDockerPanel extends HTMLElement {
if (e.persisted && this._hass) {
this._lastSnapshot = null;
this._render();
+ this._refreshFailedEntries();
}
};
window.addEventListener("pageshow", this._pageshowHandler);
@@ -70,6 +74,7 @@ class SshDockerPanel extends HTMLElement {
this._lastSnapshot = null;
}
this._render();
+ this._refreshFailedEntries();
}
disconnectedCallback() {
@@ -97,6 +102,117 @@ class SshDockerPanel extends HTMLElement {
.join(";");
}
+ // Fetches SSH Docker config entries and updates _failedEntries with those that
+ // have a setup_error state. A simple guard prevents concurrent fetches.
+ // Re-renders the panel when the failed entries list changes.
+ async _refreshFailedEntries() {
+ if (!this._hass || this._isFetchingFailedEntries) return;
+ this._isFetchingFailedEntries = true;
+ try {
+ const entries = await this._hass.callApi("GET", "config/config_entries/entry?domain=ssh_docker");
+ const failed = (entries || []).filter((e) => e.state === "setup_error");
+ const changed = JSON.stringify(failed) !== JSON.stringify(this._failedEntries);
+ this._failedEntries = failed;
+ if (changed) this._render();
+ } catch (_err) {
+ // Silently ignore – the failed-entries section is non-critical.
+ } finally {
+ this._isFetchingFailedEntries = false;
+ }
+ }
+
+ // Returns the HTML for the "failed entries" section shown above the container grid.
+ _renderFailedSection() {
+ if (!this._failedEntries || this._failedEntries.length === 0) return "";
+
+ const cards = this._failedEntries.map((entry) => {
+ // Host is sourced from entry.options returned by the config entries API.
+ const host = (entry.options && entry.options.host) || "";
+ const hostHtml = host
+ ? `
+ ${this._renderFailedSection()}
${filterButtons}
${hostFilterHtml}
${hostsHtml}
@@ -554,6 +692,11 @@ class SshDockerPanel extends HTMLElement {
btn.addEventListener("click", () =>
this._showLogs(btn.dataset.entity)
);
+ } else if (btn.classList.contains("open-settings-btn")) {
+ btn.addEventListener("click", () => {
+ history.pushState(null, "", btn.dataset.href);
+ window.dispatchEvent(new CustomEvent("location-changed", { bubbles: true, composed: true }));
+ });
} else {
btn.addEventListener("click", () =>
this._handleAction(btn.dataset.action, btn.dataset.entity)
diff --git a/strings.json b/strings.json
index d64f15e..e93c3dc 100644
--- a/strings.json
+++ b/strings.json
@@ -221,7 +221,11 @@
"all_states": { "name": "All states" },
"updates_filter": { "name": "⬆ Updates" },
"all_hosts": { "name": "All Hosts" },
- "no_containers": { "name": "No Docker containers found." }
+ "no_containers": { "name": "No Docker containers found." },
+ "setup_failed_badge": { "name": "⚠ Setup failed" },
+ "setup_failed_section": { "name": "Failed to set up" },
+ "setup_failed_hint": { "name": "The container may have been removed from the remote host." },
+ "btn_open_settings": { "name": "Open settings" }
}
},
"exceptions": {
diff --git a/translations/de.json b/translations/de.json
index ec04a41..802754e 100644
--- a/translations/de.json
+++ b/translations/de.json
@@ -221,7 +221,11 @@
"all_states": { "name": "Alle Zustände" },
"updates_filter": { "name": "⬆ Updates" },
"all_hosts": { "name": "Alle Hosts" },
- "no_containers": { "name": "Keine Docker-Container gefunden." }
+ "no_containers": { "name": "Keine Docker-Container gefunden." },
+ "setup_failed_badge": { "name": "⚠ Einrichtung fehlgeschlagen" },
+ "setup_failed_section": { "name": "Einrichtung fehlgeschlagen" },
+ "setup_failed_hint": { "name": "Der Container wurde möglicherweise vom entfernten Host entfernt." },
+ "btn_open_settings": { "name": "Einstellungen öffnen" }
}
},
"exceptions": {
diff --git a/translations/en.json b/translations/en.json
index d64f15e..e93c3dc 100644
--- a/translations/en.json
+++ b/translations/en.json
@@ -221,7 +221,11 @@
"all_states": { "name": "All states" },
"updates_filter": { "name": "⬆ Updates" },
"all_hosts": { "name": "All Hosts" },
- "no_containers": { "name": "No Docker containers found." }
+ "no_containers": { "name": "No Docker containers found." },
+ "setup_failed_badge": { "name": "⚠ Setup failed" },
+ "setup_failed_section": { "name": "Failed to set up" },
+ "setup_failed_hint": { "name": "The container may have been removed from the remote host." },
+ "btn_open_settings": { "name": "Open settings" }
}
},
"exceptions": {