Skip to content

Add failure marker in SSH Docker panel for entries that failed to set up#45

Merged
gensyn merged 6 commits intomainfrom
copilot/add-failure-marker-in-settings
Mar 27, 2026
Merged

Add failure marker in SSH Docker panel for entries that failed to set up#45
gensyn merged 6 commits intomainfrom
copilot/add-failure-marker-in-settings

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 27, 2026

When a container is removed from the remote host, its config entry enters setup_error state and HA only surfaces this on the integrations dashboard — the SSH Docker sidebar panel shows nothing.

Changes

frontend/ssh-docker-panel.js

  • _refreshFailedEntries(): async method that calls hass.callApi("GET", "config/config_entries/entry?domain=ssh_docker"), filters for state === "setup_error", and re-renders only on change. A simple concurrent-fetch guard prevents overlapping calls. Triggered only from connectedCallback(), visibilitychange, and pageshow handlers — not on every hass update.
  • _getEntityByEntryId(): looks up hass.entities (entity registry) to build a map of config_entry_id → hass.states entity for all failed entries. Used to retrieve host info from the sensor's attributes and to identify which entities belong to failed entries.
  • _getFailedEntityIds(): derives a Set of entity IDs from _getEntityByEntryId() — used to exclude those entities from the regular container grid so they no longer appear under "Unknown host".
  • _renderFailedSection(): renders a red "⚠ Failed to set up" section above the container grid — one card per failed entry with the container name, host (when available from the entity registry), hint text, and an Open settings button that navigates to the HA integrations page.
  • _getAllContainers(): excludes entities belonging to setup_error entries so they are shown only in the failed section, not also in the regular host-grouped grid.

strings.json / translations/en.json / translations/de.json

  • Added setup_failed_badge, setup_failed_section, setup_failed_hint, btn_open_settings keys.

Result

Entries that fail to set up now appear prominently in the panel above the regular container grid and are no longer duplicated under "Unknown host":

⚠ Failed to set up
┌──────────────────────────────────────┐
│ My Container          ⚠ Setup failed │
│ Host: 192.168.1.100                  │
│ The container may have been removed  │
│ from the remote host.                │
│ [ Open settings ]                    │
└──────────────────────────────────────┘

⌨️ Start Copilot coding agent tasks without leaving your editor — available in VS Code, Visual Studio, JetBrains IDEs and Eclipse.

When a container configured through SSH Docker is removed from the
remote host, its config entry enters the `setup_error` state and the
failure is only visible on the HA integrations dashboard.

This change adds a "Failed to set up" section at the top of the SSH
Docker panel for every entry in that state:

- `_refreshFailedEntries()` fetches SSH Docker config entries via
  `hass.callApi` and filters for `state === "setup_error"`. Throttled
  to one API call per 60 s; called on panel connect, tab visibility
  restore, and on hass state changes.
- `_renderFailedSection()` renders a red card per failed entry showing
  the entry title, an "⚠ Setup failed" badge, a hint text, and an
  "Open settings" button that navigates to the integrations page.
- New CSS classes and translation keys added for all new UI elements.

Agent-Logs-Url: https://github.com/gensyn/ssh_docker/sessions/af576b76-d10a-465d-8fe2-efef6756877e

Co-authored-by: gensyn <36128035+gensyn@users.noreply.github.com>
Copilot AI changed the title [WIP] Add failure marker in settings for SSH Docker integration Add failure marker in SSH Docker panel for entries that failed to set up Mar 27, 2026
Copilot AI requested a review from gensyn March 27, 2026 08:37
@gensyn
Copy link
Copy Markdown
Owner

gensyn commented Mar 27, 2026

@copilot I don't think a periodic refresh is useful for failed entries - remove that. I just realized that failed entries are shown on the panel but under "Unknown host" which is wrong, because the host is always known. It would suffice for me when the entires are prominently displayed on the panel as failed.

- Remove the 60s throttle timer from _refreshFailedEntries(); replace
  with a simple concurrent-fetch guard (_isFetchingFailedEntries).
  _refreshFailedEntries() is no longer called from set hass() — only
  from connectedCallback(), visibilitychange, and pageshow handlers.

- Fix "Unknown host": when a sensor entity still lives in hass.states
  for a setup_error config entry it would appear under "Unknown host"
  in the regular container grid (empty host attribute).  Fix by:
  * _getEntityByEntryId(): single entity-registry loop that maps
    config entry_id → hass.states entity; shared by both callers.
  * _getFailedEntityIds(): derives its Set from _getEntityByEntryId()
    to avoid duplicating the loop.
  * _getAllContainers(): excludes entities belonging to failed entries.
  * _renderFailedSection(): shows host (from entity attributes) as a
    plain <div class="setup-failed-host"> when available.

Agent-Logs-Url: https://github.com/gensyn/ssh_docker/sessions/78d9b250-12e0-4bb7-ac12-618b5effedfe

Co-authored-by: gensyn <36128035+gensyn@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 27, 2026

@copilot I don't think a periodic refresh is useful for failed entries - remove that. I just realized that failed entries are shown on the panel but under "Unknown host" which is wro...

Done in 946859f:

Periodic refresh removed_refreshFailedEntries() is no longer called from set hass() and has no throttle timer. It now only runs on panel connect, tab visibility restore, and page restore.

"Unknown host" fix — When a sensor entity for a setup_error entry still exists in hass.states (e.g. after a failed reload), it was slipping into the regular container grid with an empty host attribute and appearing under "Unknown host". The fix:

  • _getEntityByEntryId(): single loop over hass.entities (entity registry) that maps config_entry_id → hass.states entity for all failed entries.
  • _getFailedEntityIds(): derives its Set from the above — no duplicated loop.
  • _getAllContainers(): filters out entities whose entity_id is in the failed set.
  • _renderFailedSection(): shows Host: <value> (from the entity's host attribute) in the failed card whenever it's available.

@gensyn
Copy link
Copy Markdown
Owner

gensyn commented Mar 27, 2026

@copilot The way the failed entries are shown on the panel is great, but they are still also listed under "Unknown hosts" which is wrong and unncessary. Please show them only as failed.

…ity lookup

Replace single hass.entities lookup with a two-strategy _findEntityForEntry()
helper that first tries the entity registry (hass.entities / config_entry_id)
and falls back to matching sensor entities by attributes.name === entry.title.

This ensures that sensor entities belonging to setup_error config entries are
always excluded from _getAllContainers() and never shown under "Unknown host",
even in panel contexts where hass.entities is unavailable or doesn't expose
config_entry_id.

Agent-Logs-Url: https://github.com/gensyn/ssh_docker/sessions/e7337e42-8c79-4008-ab9f-34af78cb29e3

Co-authored-by: gensyn <36128035+gensyn@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 27, 2026

@copilot The way the failed entries are shown on the panel is great, but they are still also listed under "Unknown hosts" which is wrong and unncessary. Please show them only as fail...

Fixed in 29ea77d.

The root cause: the previous fix relied solely on hass.entities (entity registry) to identify which sensor entities belong to failed config entries. When hass.entities isn't available in the panel context (or doesn't expose config_entry_id), the exclusion silently did nothing — so the entity still showed under "Unknown host".

The new _findEntityForEntry() uses two strategies in order:

  1. hass.entities registry — matched by config_entry_id (most precise when available)
  2. Name-attribute matchstate.attributes.name === entry.title (reliable fallback, since the sensor's name attribute always equals the config entry title)

_getFailedEntityIds() now uses this helper, so entities belonging to setup_error entries are excluded from _getAllContainers() regardless of whether hass.entities is available — they only appear in the "⚠ Failed to set up" section.

@gensyn
Copy link
Copy Markdown
Owner

gensyn commented Mar 27, 2026

@copilot The failed entries still show up under "Unknown host".

…ties from grid

Three bugs in the previous entity-matching chain caused failed entries to keep
leaking into the regular container grid:

1. Strategy 1 required hass.states[entityId] to be truthy — so if the entity
   was in hass.entities but had no restored state, its entity_id was silently
   dropped from the exclusion set.
2. Strategy 2 matched on state.attributes.name, which is empty ({}) for
   restored-but-never-loaded unavailable entities, so the match never fired.
3. Both strategies required a state object, making them useless in the exact
   scenario that causes the bug (unavailable entity, empty attributes).

New _getFailedEntityIds():
  Strategy 1: entity registry (hass.entities) — adds entity_ids directly by
    config_entry_id with no hass.states lookup required; works even when the
    entity has never been loaded.
  Strategy 2: name-attribute match (state.attributes.name === entry.title) —
    fallback for entities with populated attributes when hass.entities is absent.
  Strategy 3: derived entity_id (sensor.ssh_docker_ + _slugify(title)) — covers
    the hardest case: no hass.entities AND empty attributes (restored unavailable).

Strategies 2 and 3 are combined into a single hass.states pass to avoid
redundant iteration. _slugify() mirrors HA Python's slugify exactly.
Also removes the unused _findEntityForEntry() and _getHostForEntry() helpers.

Agent-Logs-Url: https://github.com/gensyn/ssh_docker/sessions/5db279fb-d00e-410e-b802-136c4544053d

Co-authored-by: gensyn <36128035+gensyn@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 27, 2026

@copilot The failed entries still show up under "Unknown host".

Fixed in 890f9c3. There were three bugs in the entity-matching chain that together allowed the entity to slip through:

  1. Strategy 1 required a hass.states lookup — if the entity was in hass.entities (entity registry) with the right config_entry_id but its state hadn't been restored yet, the if (state) guard silently dropped it without ever adding the entity_id to the exclusion set.

  2. Strategy 2 matched on state.attributes.name — restored/unavailable entities have empty attributes ({}), so state.attributes.name is undefined and the match never fired.

  3. Both strategies required a state object — useless for the exact scenario that causes the bug.

The new _getFailedEntityIds() has three truly independent strategies:

  • Strategy 1 (entity registry): adds entity_ids directly from hass.entities by config_entry_idno hass.states lookup required.
  • Strategy 2 (name-attribute): fallback for entities with populated attributes when hass.entities is unavailable.
  • Strategy 3 (derived entity_id): sensor.ssh_docker_ + _slugify(entry.title) — covers the hardest case: hass.entities absent AND attributes empty. Mirrors HA's Python slugify() exactly.

Strategies 2 and 3 are combined into a single hass.states pass.

@gensyn gensyn marked this pull request as ready for review March 27, 2026 10:28
@gensyn gensyn merged commit ba62a0d into main Mar 27, 2026
5 checks passed
@gensyn gensyn deleted the copilot/add-failure-marker-in-settings branch March 27, 2026 10:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants