Fix blueprint uninstall and restore messaging

This commit is contained in:
2026-03-23 17:14:22 +01:00
parent 80c1c2966f
commit d976ab56e3
2 changed files with 49 additions and 7 deletions

1
.idea/changes.md generated
View File

@@ -22,6 +22,7 @@
- Fixed blueprint update backups: blueprint file updates now create content backups before overwrite and can roll back copied blueprint files if installation fails. - Fixed blueprint update backups: blueprint file updates now create content backups before overwrite and can roll back copied blueprint files if installation fails.
- Kept the no-restart behavior for blueprints, because blueprint deployment does not normally require a Home Assistant restart. - Kept the no-restart behavior for blueprints, because blueprint deployment does not normally require a Home Assistant restart.
- Restored blueprint backup/restore availability in the UI and backend: the restore button is visible again for blueprint installs, blueprint backups can be listed, and blueprint content can now be restored from backup without forcing a restart. - Restored blueprint backup/restore availability in the UI and backend: the restore button is visible again for blueprint installs, blueprint backups can be listed, and blueprint content can now be restored from backup without forcing a restart.
- Fixed category-specific uninstall and restore messaging in the active panel: blueprints now reference `/config/blueprints` and explicitly state that no restart is required, while integrations keep the `/config/custom_components` restart warning.
### Documented ### Documented
- Captured the verified project identity from the repository and README files: Bahmcloud Store is a Home Assistant custom integration intended to behave like a provider-neutral store for custom integrations, similar to HACS but broader than GitHub-only workflows. - Captured the verified project identity from the repository and README files: Bahmcloud Store is a Home Assistant custom integration intended to behave like a provider-neutral store for custom integrations, similar to HACS but broader than GitHub-only workflows.

View File

@@ -206,7 +206,9 @@ class BahmcloudStorePanel extends HTMLElement {
this._error = this._safeText(resp?.message) || "Install failed."; this._error = this._safeText(resp?.message) || "Install failed.";
} else { } else {
this._restartRequired = !!resp.restart_required; this._restartRequired = !!resp.restart_required;
this._lastActionMsg = "Installation finished. Restart required."; this._lastActionMsg = resp?.restart_required
? "Installation finished. Restart required."
: "Installation finished. No restart required.";
} }
} catch (e) { } catch (e) {
this._error = e?.message ? String(e.message) : String(e); this._error = e?.message ? String(e.message) : String(e);
@@ -238,7 +240,9 @@ class BahmcloudStorePanel extends HTMLElement {
this._error = this._safeText(resp?.message) || "Update failed."; this._error = this._safeText(resp?.message) || "Update failed.";
} else { } else {
this._restartRequired = !!resp.restart_required; this._restartRequired = !!resp.restart_required;
this._lastActionMsg = "Update finished. Restart required."; this._lastActionMsg = resp?.restart_required
? "Update finished. Restart required."
: "Update finished. No restart required.";
} }
} catch (e) { } catch (e) {
this._error = e?.message ? String(e.message) : String(e); this._error = e?.message ? String(e.message) : String(e);
@@ -253,7 +257,11 @@ class BahmcloudStorePanel extends HTMLElement {
if (!repoId) return; if (!repoId) return;
if (this._installingRepoId || this._updatingRepoId || this._uninstallingRepoId) return; if (this._installingRepoId || this._updatingRepoId || this._uninstallingRepoId) return;
const ok = window.confirm("Really uninstall this repository? This will remove its files from /config/custom_components and requires a restart."); const details = this._getInstallTypeDetails(repoId);
const uninstallText = details.restartRequired
? `Really uninstall this repository? This will remove its files from ${details.targetPath} and requires a restart.`
: `Really uninstall this repository? This will remove its files from ${details.targetPath}. No restart is required.`;
const ok = window.confirm(uninstallText);
if (!ok) return; if (!ok) return;
this._uninstallingRepoId = repoId; this._uninstallingRepoId = repoId;
@@ -267,7 +275,9 @@ class BahmcloudStorePanel extends HTMLElement {
this._error = this._safeText(resp?.message) || "Uninstall failed."; this._error = this._safeText(resp?.message) || "Uninstall failed.";
} else { } else {
this._restartRequired = !!resp.restart_required; this._restartRequired = !!resp.restart_required;
this._lastActionMsg = "Uninstall finished. Restart required."; this._lastActionMsg = resp?.restart_required
? "Uninstall finished. Restart required."
: "Uninstall finished. No restart required.";
} }
} catch (e) { } catch (e) {
this._error = e?.message ? String(e.message) : String(e); this._error = e?.message ? String(e.message) : String(e);
@@ -337,7 +347,11 @@ class BahmcloudStorePanel extends HTMLElement {
return; return;
} }
const ok = window.confirm("Restore selected backup? This will overwrite the installed files under /config/custom_components and requires a restart."); const details = this._getInstallTypeDetails(this._restoreRepoId);
const restoreText = details.restartRequired
? `Restore selected backup? This will overwrite the installed files under ${details.targetPath} and requires a restart.`
: `Restore selected backup? This will overwrite the installed files under ${details.targetPath}. No restart is required.`;
const ok = window.confirm(restoreText);
if (!ok) return; if (!ok) return;
this._restoring = true; this._restoring = true;
@@ -350,7 +364,9 @@ class BahmcloudStorePanel extends HTMLElement {
this._restoreError = this._safeText(resp?.message) || "Restore failed."; this._restoreError = this._safeText(resp?.message) || "Restore failed.";
} else { } else {
this._restartRequired = !!resp.restart_required; this._restartRequired = !!resp.restart_required;
this._lastActionMsg = "Restore finished. Restart required."; this._lastActionMsg = resp?.restart_required
? "Restore finished. Restart required."
: "Restore finished. No restart required.";
this._closeRestore(); this._closeRestore();
} }
} catch (e) { } catch (e) {
@@ -981,6 +997,27 @@ class BahmcloudStorePanel extends HTMLElement {
return !!id && Array.isArray(this._favoriteRepoIds) && this._favoriteRepoIds.includes(id); return !!id && Array.isArray(this._favoriteRepoIds) && this._favoriteRepoIds.includes(id);
} }
_getRepoById(repoId) {
const id = this._safeId(repoId);
if (!id || !Array.isArray(this._data?.repos)) return null;
return this._data.repos.find((r) => this._safeId(r?.id) === id) || null;
}
_getInstallTypeDetails(repoOrId) {
const repo = typeof repoOrId === "string" ? this._getRepoById(repoOrId) : repoOrId;
const installType = this._safeText(repo?.install_type) || "integration";
if (installType === "blueprint") {
return { installType, targetPath: "/config/blueprints", restartRequired: false };
}
if (installType === "template") {
return { installType, targetPath: "/config", restartRequired: false };
}
if (installType === "lovelace") {
return { installType, targetPath: "/config/www", restartRequired: false };
}
return { installType: "integration", targetPath: "/config/custom_components", restartRequired: true };
}
async _toggleFavorite(repoId) { async _toggleFavorite(repoId) {
if (!this._hass || !repoId) return; if (!this._hass || !repoId) return;
@@ -1626,12 +1663,16 @@ class BahmcloudStorePanel extends HTMLElement {
}) })
.join(""); .join("");
const restoreDetails = this._getInstallTypeDetails(this._restoreRepoId);
const actionHint = restoreDetails.restartRequired
? `Select a backup to restore. This will overwrite files under ${restoreDetails.targetPath} and requires a restart.`
: `Select a backup to restore. This will overwrite files under ${restoreDetails.targetPath}. No restart is required.`;
const msg = this._restoreLoading const msg = this._restoreLoading
? "Loading backups…" ? "Loading backups…"
: this._restoreError : this._restoreError
? this._safeText(this._restoreError) ? this._safeText(this._restoreError)
: opts.length : opts.length
? "Select a backup to restore. This will overwrite files under /config/custom_components and requires a restart." ? actionHint
: "No backups found."; : "No backups found.";
return ` return `