diff --git a/.idea/changes.md b/.idea/changes.md index 503665f..34179d9 100644 --- a/.idea/changes.md +++ b/.idea/changes.md @@ -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. - 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. +- 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 - 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. diff --git a/custom_components/bahmcloud_store/panel/panel.js b/custom_components/bahmcloud_store/panel/panel.js index 9a4cf56..11ec2e5 100644 --- a/custom_components/bahmcloud_store/panel/panel.js +++ b/custom_components/bahmcloud_store/panel/panel.js @@ -206,7 +206,9 @@ class BahmcloudStorePanel extends HTMLElement { this._error = this._safeText(resp?.message) || "Install failed."; } else { 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) { 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."; } else { 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) { this._error = e?.message ? String(e.message) : String(e); @@ -253,7 +257,11 @@ class BahmcloudStorePanel extends HTMLElement { if (!repoId) 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; this._uninstallingRepoId = repoId; @@ -267,7 +275,9 @@ class BahmcloudStorePanel extends HTMLElement { this._error = this._safeText(resp?.message) || "Uninstall failed."; } else { 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) { this._error = e?.message ? String(e.message) : String(e); @@ -337,7 +347,11 @@ class BahmcloudStorePanel extends HTMLElement { 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; this._restoring = true; @@ -350,7 +364,9 @@ class BahmcloudStorePanel extends HTMLElement { this._restoreError = this._safeText(resp?.message) || "Restore failed."; } else { 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(); } } catch (e) { @@ -981,6 +997,27 @@ class BahmcloudStorePanel extends HTMLElement { 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) { if (!this._hass || !repoId) return; @@ -1626,12 +1663,16 @@ class BahmcloudStorePanel extends HTMLElement { }) .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 ? "Loading backups…" : this._restoreError ? this._safeText(this._restoreError) : opts.length - ? "Select a backup to restore. This will overwrite files under /config/custom_components and requires a restart." + ? actionHint : "No backups found."; return `