From dcbaa31c96137e24cc075cde22a3450e7c054b48 Mon Sep 17 00:00:00 2001 From: Wendelin <12148533+wendevlin@users.noreply.github.com> Date: Thu, 24 Apr 2025 10:12:34 +0200 Subject: [PATCH] Add system-managed addon info (#25132) * Add system managed addon info dialog * Add system managed alert * Fix translation * Update hassio/src/addon-view/info/hassio-addon-info.ts Co-authored-by: Petar Petrov --------- Co-authored-by: Petar Petrov --- .../addon-view/config/hassio-addon-audio.ts | 28 ++- .../config/hassio-addon-config-tab.ts | 30 ++- .../addon-view/config/hassio-addon-config.ts | 20 +- .../addon-view/config/hassio-addon-network.ts | 23 ++- .../src/addon-view/hassio-addon-dashboard.ts | 9 + hassio/src/addon-view/hassio-addon-router.ts | 4 + .../addon-view/info/hassio-addon-info-tab.ts | 4 + .../src/addon-view/info/hassio-addon-info.ts | 157 +++++++++----- .../info/hassio-addon-system-managed.ts | 60 ++++++ .../markdown/dialog-hassio-markdown.ts | 1 + .../system-managed/dialog-system-managed.ts | 192 ++++++++++++++++++ .../show-dialog-system-managed.ts | 19 ++ src/data/hassio/addon.ts | 2 + src/translations/en.json | 8 + 14 files changed, 490 insertions(+), 67 deletions(-) create mode 100644 hassio/src/addon-view/info/hassio-addon-system-managed.ts create mode 100644 hassio/src/dialogs/system-managed/dialog-system-managed.ts create mode 100644 hassio/src/dialogs/system-managed/show-dialog-system-managed.ts diff --git a/hassio/src/addon-view/config/hassio-addon-audio.ts b/hassio/src/addon-view/config/hassio-addon-audio.ts index 9146f5924a..57a964b48f 100644 --- a/hassio/src/addon-view/config/hassio-addon-audio.ts +++ b/hassio/src/addon-view/config/hassio-addon-audio.ts @@ -1,12 +1,11 @@ -import "@material/mwc-button"; -import "@material/mwc-list/mwc-list-item"; import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit"; -import { css, html, LitElement } from "lit"; +import { css, html, LitElement, nothing } from "lit"; import { customElement, property, state } from "lit/decorators"; import { stopPropagation } from "../../../../src/common/dom/stop_propagation"; import "../../../../src/components/buttons/ha-progress-button"; import "../../../../src/components/ha-alert"; import "../../../../src/components/ha-card"; +import "../../../../src/components/ha-list-item"; import "../../../../src/components/ha-select"; import type { HassioAddonDetails, @@ -29,6 +28,8 @@ class HassioAddonAudio extends LitElement { @property({ attribute: false }) public addon!: HassioAddonDetails; + @property({ type: Boolean }) public disabled = false; + @state() private _error?: string; @state() private _inputDevices?: HassioHardwareAudioDevice[]; @@ -48,7 +49,7 @@ class HassioAddonAudio extends LitElement {
${this._error ? html`${this._error}` - : ""} + : nothing} ${this._inputDevices && html` ${this._inputDevices.map( (item) => html` - + ${item.name} - + ` )} `} @@ -78,18 +80,22 @@ class HassioAddonAudio extends LitElement { fixedMenuPosition naturalMenuWidth .value=${this._selectedOutput!} + .disabled=${this.disabled} > ${this._outputDevices.map( (item) => html` - ${item.name}${item.name} ` )} `}
- + ${this.supervisor.localize("common.save")}
@@ -171,6 +177,10 @@ class HassioAddonAudio extends LitElement { } private async _saveSettings(ev: CustomEvent): Promise { + if (this.disabled) { + return; + } + const button = ev.currentTarget as any; button.progress = true; diff --git a/hassio/src/addon-view/config/hassio-addon-config-tab.ts b/hassio/src/addon-view/config/hassio-addon-config-tab.ts index 6aa4cdd446..0df77b1431 100644 --- a/hassio/src/addon-view/config/hassio-addon-config-tab.ts +++ b/hassio/src/addon-view/config/hassio-addon-config-tab.ts @@ -1,5 +1,5 @@ import type { CSSResultGroup, TemplateResult } from "lit"; -import { css, html, LitElement } from "lit"; +import { css, html, LitElement, nothing } from "lit"; import { customElement, property } from "lit/decorators"; import "../../../../src/components/ha-spinner"; import type { HassioAddonDetails } from "../../../../src/data/hassio/addon"; @@ -7,6 +7,7 @@ import type { Supervisor } from "../../../../src/data/supervisor/supervisor"; import { haStyle } from "../../../../src/resources/styles"; import type { HomeAssistant } from "../../../../src/types"; import { hassioStyle } from "../../resources/hassio-style"; +import "../info/hassio-addon-system-managed"; import "./hassio-addon-audio"; import "./hassio-addon-config"; import "./hassio-addon-network"; @@ -19,6 +20,11 @@ class HassioAddonConfigDashboard extends LitElement { @property({ attribute: false }) public addon?: HassioAddonDetails; + @property({ type: Boolean }) public narrow = false; + + @property({ type: Boolean, attribute: "control-enabled" }) + public controlEnabled = false; + protected render(): TemplateResult { if (!this.addon) { return html``; @@ -29,6 +35,16 @@ class HassioAddonConfigDashboard extends LitElement { return html`
+ ${this.addon.system_managed && + (hasConfiguration || this.addon.network || this.addon.audio) + ? html` + + ` + : nothing} ${hasConfiguration || this.addon.network || this.addon.audio ? html` ${hasConfiguration @@ -37,27 +53,33 @@ class HassioAddonConfigDashboard extends LitElement { .hass=${this.hass} .addon=${this.addon} .supervisor=${this.supervisor} + .disabled=${this.addon.system_managed && + !this.controlEnabled} > ` - : ""} + : nothing} ${this.addon.network ? html` ` - : ""} + : nothing} ${this.addon.audio ? html` ` - : ""} + : nothing} ` : this.supervisor.localize("addon.configuration.no_configuration")}
diff --git a/hassio/src/addon-view/config/hassio-addon-config.ts b/hassio/src/addon-view/config/hassio-addon-config.ts index bd0b3ab5a2..3fbfa9c14b 100644 --- a/hassio/src/addon-view/config/hassio-addon-config.ts +++ b/hassio/src/addon-view/config/hassio-addon-config.ts @@ -61,6 +61,8 @@ class HassioAddonConfig extends LitElement { @property({ attribute: false }) public supervisor!: Supervisor; + @property({ type: Boolean }) public disabled = false; + @state() private _configHasChanged = false; @state() private _valid = true; @@ -176,7 +178,7 @@ class HassioAddonConfig extends LitElement { .path=${mdiDotsVertical} slot="trigger" > - + ${this._yamlMode ? this.supervisor.localize( "addon.configuration.options.edit_in_ui" @@ -185,7 +187,10 @@ class HassioAddonConfig extends LitElement { "addon.configuration.options.edit_in_yaml" )} - + ${this.supervisor.localize("common.reset_defaults")} @@ -195,6 +200,7 @@ class HassioAddonConfig extends LitElement {
${showForm ? html`` - : html` `} @@ -244,7 +250,9 @@ class HassioAddonConfig extends LitElement {
${this.supervisor.localize("common.save")} @@ -346,6 +354,10 @@ class HassioAddonConfig extends LitElement { } private async _saveTapped(ev: CustomEvent): Promise { + if (this.disabled || !this._configHasChanged || !this._valid) { + return; + } + const button = ev.currentTarget as any; const options: Record = this._yamlMode ? this._editor?.value diff --git a/hassio/src/addon-view/config/hassio-addon-network.ts b/hassio/src/addon-view/config/hassio-addon-network.ts index 96d5d2f307..51c225c1dc 100644 --- a/hassio/src/addon-view/config/hassio-addon-network.ts +++ b/hassio/src/addon-view/config/hassio-addon-network.ts @@ -28,6 +28,8 @@ class HassioAddonNetwork extends LitElement { @property({ attribute: false }) public addon!: HassioAddonDetails; + @property({ type: Boolean }) public disabled = false; + @state() private _showOptional = false; @state() private _configHasChanged = false; @@ -65,9 +67,10 @@ class HassioAddonNetwork extends LitElement {

${this._error ? html`${this._error}` - : ""} + : nothing} ` - : ""} + : nothing}
- + ${this.supervisor.localize("common.reset_defaults")} ${this.supervisor.localize("common.save")} @@ -155,6 +162,10 @@ class HassioAddonNetwork extends LitElement { } private async _resetTapped(ev: CustomEvent): Promise { + if (this.disabled) { + return; + } + const button = ev.currentTarget as any; const data: HassioAddonSetOptionParams = { network: null, @@ -186,6 +197,10 @@ class HassioAddonNetwork extends LitElement { } private async _saveTapped(ev: CustomEvent): Promise { + if (!this._configHasChanged || this.disabled) { + return; + } + const button = ev.currentTarget as any; this._error = undefined; diff --git a/hassio/src/addon-view/hassio-addon-dashboard.ts b/hassio/src/addon-view/hassio-addon-dashboard.ts index dc5cdb5d66..9d663659ff 100644 --- a/hassio/src/addon-view/hassio-addon-dashboard.ts +++ b/hassio/src/addon-view/hassio-addon-dashboard.ts @@ -52,6 +52,9 @@ class HassioAddonDashboard extends LitElement { @property({ type: Boolean }) public narrow = false; + @state() + private _controlEnabled = false; + @state() private _error?: string; private _backPath = new URLSearchParams(window.parent.location.search).get( @@ -134,11 +137,17 @@ class HassioAddonDashboard extends LitElement { .hass=${this.hass} .supervisor=${this.supervisor} .addon=${this.addon} + .controlEnabled=${this._controlEnabled} + @system-managed-take-control=${this._enableControl} > `; } + private _enableControl() { + this._controlEnabled = true; + } + static get styles(): CSSResultGroup { return [ haStyle, diff --git a/hassio/src/addon-view/hassio-addon-router.ts b/hassio/src/addon-view/hassio-addon-router.ts index de2c5aa1fd..1213ff9c12 100644 --- a/hassio/src/addon-view/hassio-addon-router.ts +++ b/hassio/src/addon-view/hassio-addon-router.ts @@ -23,6 +23,9 @@ class HassioAddonRouter extends HassRouterPage { | HassioAddonDetails | StoreAddonDetails; + @property({ type: Boolean, attribute: "control-enabled" }) + public controlEnabled = false; + protected routerOptions: RouterOptions = { defaultPage: "info", showLoading: true, @@ -48,6 +51,7 @@ class HassioAddonRouter extends HassRouterPage { el.supervisor = this.supervisor; el.addon = this.addon; el.narrow = this.narrow; + el.controlEnabled = this.controlEnabled; } } diff --git a/hassio/src/addon-view/info/hassio-addon-info-tab.ts b/hassio/src/addon-view/info/hassio-addon-info-tab.ts index e7d5120665..719efb8c75 100644 --- a/hassio/src/addon-view/info/hassio-addon-info-tab.ts +++ b/hassio/src/addon-view/info/hassio-addon-info-tab.ts @@ -21,6 +21,9 @@ class HassioAddonInfoDashboard extends LitElement { @property({ attribute: false }) public addon?: HassioAddonDetails; + @property({ type: Boolean, attribute: "control-enabled" }) + public controlEnabled = false; + protected render(): TemplateResult { if (!this.addon) { return html``; @@ -34,6 +37,7 @@ class HassioAddonInfoDashboard extends LitElement { .hass=${this.hass} .supervisor=${this.supervisor} .addon=${this.addon} + .controlEnabled=${this.controlEnabled} >
`; diff --git a/hassio/src/addon-view/info/hassio-addon-info.ts b/hassio/src/addon-view/info/hassio-addon-info.ts index 02e1f627df..07a92c7b8e 100644 --- a/hassio/src/addon-view/info/hassio-addon-info.ts +++ b/hassio/src/addon-view/info/hassio-addon-info.ts @@ -1,8 +1,6 @@ -import "@material/mwc-button"; import { mdiCheckCircle, mdiChip, - mdiPlayCircle, mdiCircleOffOutline, mdiCursorDefaultClickOutline, mdiDocker, @@ -19,27 +17,30 @@ import { mdiNumeric6, mdiNumeric7, mdiNumeric8, + mdiPlayCircle, mdiPound, mdiShield, } from "@mdi/js"; import type { CSSResultGroup, TemplateResult } from "lit"; -import { LitElement, css, html } from "lit"; +import { LitElement, css, html, nothing } from "lit"; import { customElement, property, state } from "lit/decorators"; import { classMap } from "lit/directives/class-map"; import memoizeOne from "memoize-one"; import { atLeastVersion } from "../../../../src/common/config/version"; import { fireEvent } from "../../../../src/common/dom/fire_event"; import { navigate } from "../../../../src/common/navigate"; +import { capitalizeFirstLetter } from "../../../../src/common/string/capitalize-first-letter"; import "../../../../src/components/buttons/ha-progress-button"; -import "../../../../src/components/ha-alert"; -import "../../../../src/components/ha-card"; -import "../../../../src/components/chips/ha-chip-set"; import "../../../../src/components/chips/ha-assist-chip"; +import "../../../../src/components/chips/ha-chip-set"; +import "../../../../src/components/ha-alert"; +import "../../../../src/components/ha-button"; +import "../../../../src/components/ha-card"; +import "../../../../src/components/ha-formfield"; import "../../../../src/components/ha-markdown"; import "../../../../src/components/ha-settings-row"; import "../../../../src/components/ha-svg-icon"; import "../../../../src/components/ha-switch"; -import "../../../../src/components/ha-formfield"; import type { HaSwitch } from "../../../../src/components/ha-switch"; import type { AddonCapability, @@ -81,10 +82,11 @@ import { bytesToString } from "../../../../src/util/bytes-to-string"; import "../../components/hassio-card-content"; import "../../components/supervisor-metric"; import { showHassioMarkdownDialog } from "../../dialogs/markdown/show-dialog-hassio-markdown"; +import { showSystemManagedDialog } from "../../dialogs/system-managed/show-dialog-system-managed"; import { hassioStyle } from "../../resources/hassio-style"; import "../../update-available/update-available-card"; import { addonArchIsSupported, extractChangelog } from "../../util/addon"; -import { capitalizeFirstLetter } from "../../../../src/common/string/capitalize-first-letter"; +import "./hassio-addon-system-managed"; const STAGE_ICON = { stable: mdiCheckCircle, @@ -117,6 +119,9 @@ class HassioAddonInfo extends LitElement { @property({ attribute: false }) public supervisor!: Supervisor; + @property({ type: Boolean, attribute: "control-enabled" }) + public controlEnabled = false; + @state() private _metrics?: HassioStats; @state() private _error?: string; @@ -155,6 +160,9 @@ class HassioAddonInfo extends LitElement { )}`, }, ]; + + const systemManaged = this._isSystemManaged(this.addon); + return html` ${this.addon.update_available ? html` @@ -166,7 +174,7 @@ class HassioAddonInfo extends LitElement { @update-complete=${this._updateComplete} > ` - : ""} + : nothing} ${"protected" in this.addon && !this.addon.protected ? html` - + ` - : ""} + : nothing} + ${systemManaged + ? html` + + ` + : nothing}
- ${!this.narrow ? this.addon.name : ""} + ${!this.narrow ? this.addon.name : nothing}
${this.addon.version ? html` @@ -266,7 +283,7 @@ class HassioAddonInfo extends LitElement { ` - : ""} + : nothing} ` - : ""} + : nothing} ${this.addon.full_access ? html` ` - : ""} + : nothing} ${this.addon.homeassistant_api ? html` ` - : ""} + : nothing} ${this._computeHassioApi ? html` ` - : ""} + : nothing} ${this.addon.docker_api ? html` ` - : ""} + : nothing} ${this.addon.host_pid ? html` ` - : ""} + : nothing} ${this.addon.apparmor !== "default" ? html` ` - : ""} + : nothing} ${this.addon.auth_api ? html` ` - : ""} + : nothing} ${this.addon.ingress ? html` ` - : ""} + : nothing} ${this.addon.signed ? html` ` - : ""} + : nothing} + ${systemManaged + ? html` + + + + ` + : nothing}
@@ -479,7 +513,7 @@ class HassioAddonInfo extends LitElement { src="/api/hassio/addons/${this.addon.slug}/logo" /> ` - : ""} + : nothing} ${this.addon.version ? html`
` - : ""} + : nothing} ${this.addon.auto_update || this.hass.userData?.showAdvanced ? html` @@ -542,13 +579,15 @@ class HassioAddonInfo extends LitElement { )} ` - : ""} + : nothing} ${!this._computeCannotIngressSidebar && this.addon.ingress ? html` @@ -563,13 +602,15 @@ class HassioAddonInfo extends LitElement { )} ` - : ""} + : nothing} ${this._computeUsesProtectedOptions ? html` @@ -584,16 +625,18 @@ class HassioAddonInfo extends LitElement { )} ` - : ""} + : nothing}
` - : ""} + : nothing}
${this.addon.version && this.addon.state === "started" @@ -612,12 +655,12 @@ class HassioAddonInfo extends LitElement { > ` )}` - : ""} + : nothing}
${this._error ? html`${this._error}` - : ""} + : nothing} ${!this.addon.version && addonStoreInfo && !this.addon.available ? !addonArchIsSupported( this.supervisor.info.supported_arch, @@ -641,7 +684,7 @@ class HassioAddonInfo extends LitElement { )} ` - : ""} + : nothing}
@@ -651,6 +694,7 @@ class HassioAddonInfo extends LitElement { ${this.supervisor.localize("addon.dashboard.stop")} @@ -688,26 +732,27 @@ class HassioAddonInfo extends LitElement { target="_blank" rel="noopener" > - + ${this.supervisor.localize( "addon.dashboard.open_web_ui" )} - + ` - : ""} + : nothing} ${this._computeShowIngressUI ? html` - + ${this.supervisor.localize( "addon.dashboard.open_web_ui" )} - + ` - : ""} + : nothing} ${this.supervisor.localize("addon.dashboard.uninstall")} @@ -720,8 +765,8 @@ class HassioAddonInfo extends LitElement { ${this.supervisor.localize("addon.dashboard.rebuild")} ` - : ""}` - : ""} + : nothing}` + : nothing}
@@ -737,7 +782,7 @@ class HassioAddonInfo extends LitElement {
` - : ""} + : nothing} `; } @@ -822,6 +867,13 @@ class HassioAddonInfo extends LitElement { }); } + private _showSystemManagedDialog() { + showSystemManagedDialog(this, { + addon: this.addon as HassioAddonDetails, + supervisor: this.supervisor, + }); + } + private get _computeIsRunning(): boolean { return (this.addon as HassioAddonDetails)?.state === "started"; } @@ -1014,6 +1066,10 @@ class HassioAddonInfo extends LitElement { } private async _stopClicked(ev: CustomEvent): Promise { + if (this._isSystemManaged(this.addon) && !this.controlEnabled) { + return; + } + const button = ev.currentTarget as any; button.progress = true; @@ -1125,6 +1181,10 @@ class HassioAddonInfo extends LitElement { } private async _uninstallClicked(ev: CustomEvent): Promise { + if (this._isSystemManaged(this.addon) && !this.controlEnabled) { + return; + } + const button = ev.currentTarget as any; button.progress = true; let removeData = false; @@ -1179,6 +1239,11 @@ class HassioAddonInfo extends LitElement { button.progress = false; } + private _isSystemManaged = memoizeOne( + (addon: HassioAddonDetails | StoreAddonDetails) => + "system_managed" in addon && addon.system_managed + ); + static get styles(): CSSResultGroup { return [ haStyle, @@ -1201,7 +1266,7 @@ class HassioAddonInfo extends LitElement { ha-card.warning .card-content { color: white; } - ha-card.warning mwc-button { + ha-card.warning ha-button { --mdc-theme-primary: white !important; } .warning { @@ -1246,7 +1311,7 @@ class HassioAddonInfo extends LitElement { ha-svg-icon.stopped { color: var(--error-color); } - protection-enable mwc-button { + protection-enable ha-button { --mdc-theme-primary: white; } .description a { @@ -1328,7 +1393,7 @@ class HassioAddonInfo extends LitElement { align-self: end; } - ha-alert mwc-button { + ha-alert ha-button { --mdc-theme-primary: var(--primary-text-color); } diff --git a/hassio/src/addon-view/info/hassio-addon-system-managed.ts b/hassio/src/addon-view/info/hassio-addon-system-managed.ts new file mode 100644 index 0000000000..4684e8ebe3 --- /dev/null +++ b/hassio/src/addon-view/info/hassio-addon-system-managed.ts @@ -0,0 +1,60 @@ +import "@material/mwc-button"; +import type { TemplateResult } from "lit"; +import { LitElement, css, html, nothing } from "lit"; +import { customElement, property } from "lit/decorators"; +import { fireEvent } from "../../../../src/common/dom/fire_event"; +import "../../../../src/components/ha-alert"; +import "../../../../src/components/ha-button"; +import type { Supervisor } from "../../../../src/data/supervisor/supervisor"; + +@customElement("hassio-addon-system-managed") +class HassioAddonSystemManaged extends LitElement { + @property({ type: Boolean }) public narrow = false; + + @property({ attribute: false }) public supervisor!: Supervisor; + + @property({ type: Boolean, attribute: "hide-button" }) public hideButton = + false; + + protected render(): TemplateResult { + return html` + + ${this.supervisor.localize("addon.system_managed.description")} + ${!this.hideButton + ? html` + + ${this.supervisor.localize("addon.system_managed.take_control")} + + ` + : nothing} + + `; + } + + private _takeControl() { + fireEvent(this, "system-managed-take-control"); + } + + static styles = css` + ha-alert { + display: block; + margin-bottom: 16px; + } + ha-button { + white-space: nowrap; + } + `; +} +declare global { + interface HTMLElementTagNameMap { + "hassio-addon-system-managed": HassioAddonSystemManaged; + } + + interface HASSDomEvents { + "system-managed-take-control": undefined; + } +} diff --git a/hassio/src/dialogs/markdown/dialog-hassio-markdown.ts b/hassio/src/dialogs/markdown/dialog-hassio-markdown.ts index d7fcc8f889..740ee1dcfc 100644 --- a/hassio/src/dialogs/markdown/dialog-hassio-markdown.ts +++ b/hassio/src/dialogs/markdown/dialog-hassio-markdown.ts @@ -38,6 +38,7 @@ class HassioMarkdownDialog extends LitElement { open @closed=${this.closeDialog} .heading=${createCloseHeading(this.hass, this.title)} + hideactions > { + this._addon = dialogParams.addon; + this._supervisor = dialogParams.supervisor; + this._open = true; + this._loadConfigEntry(); + } + + private _dialogClosed() { + this._addon = undefined; + this._supervisor = undefined; + this._configEntry = undefined; + this._open = false; + } + + public closeDialog() { + this._dialog?.close(); + return true; + } + + protected render() { + if (!this._addon || !this._open || !this._supervisor) { + return nothing; + } + + const addonImage = + atLeastVersion(this.hass.config.version, 0, 105) && this._addon.icon + ? `/api/hassio/addons/${this._addon.slug}/icon` + : undefined; + + return html` + + + + ${this._addon?.name} + +
+
+ + + ${addonImage + ? html`${this._addon.name}` + : html``} +
+ ${this._supervisor.localize("addon.system_managed.title")}.
+ ${this._supervisor.localize("addon.system_managed.description")} + ${this._configEntry + ? html` +

+ ${this._supervisor.localize( + "addon.system_managed.managed_by" + )}: +

+ + + ${this._configEntry.title} + ${this._configEntry.title} + + + + ` + : nothing} +
+
+ `; + } + + private _onImageLoad(ev) { + ev.target.style.visibility = "initial"; + } + + private _onImageError(ev) { + ev.target.style.visibility = "hidden"; + } + + private async _loadConfigEntry() { + if (this._addon?.system_managed_config_entry) { + try { + const { config_entry } = await getConfigEntry( + this.hass, + this._addon.system_managed_config_entry + ); + this._configEntry = config_entry; + } catch (err) { + // eslint-disable-next-line no-console + console.error(err); + } + } + } + + static get styles(): CSSResultGroup { + return [ + haStyle, + css` + .icons { + display: flex; + justify-content: center; + align-items: center; + gap: 16px; + --mdc-icon-size: 48px; + margin-bottom: 32px; + } + .icons img { + width: 48px; + } + .icons .primary { + color: var(--primary-color); + } + .actions { + display: flex; + justify-content: space-between; + } + .integration-icon { + width: 24px; + } + ha-md-list-item { + --md-list-item-leading-space: 4px; + --md-list-item-trailing-space: 4px; + } + `, + ]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "dialog-system-managed": HassioSystemManagedDialog; + } +} diff --git a/hassio/src/dialogs/system-managed/show-dialog-system-managed.ts b/hassio/src/dialogs/system-managed/show-dialog-system-managed.ts new file mode 100644 index 0000000000..3e198d4afb --- /dev/null +++ b/hassio/src/dialogs/system-managed/show-dialog-system-managed.ts @@ -0,0 +1,19 @@ +import { fireEvent } from "../../../../src/common/dom/fire_event"; +import type { HassioAddonDetails } from "../../../../src/data/hassio/addon"; +import type { Supervisor } from "../../../../src/data/supervisor/supervisor"; + +export interface SystemManagedDialogParams { + addon: HassioAddonDetails; + supervisor: Supervisor; +} + +export const showSystemManagedDialog = ( + element: HTMLElement, + dialogParams: SystemManagedDialogParams +): void => { + fireEvent(element, "show-dialog", { + dialogTag: "dialog-system-managed", + dialogImport: () => import("./dialog-system-managed"), + dialogParams, + }); +}; diff --git a/src/data/hassio/addon.ts b/src/data/hassio/addon.ts index 5154f45006..064eaa5613 100644 --- a/src/data/hassio/addon.ts +++ b/src/data/hassio/addon.ts @@ -101,6 +101,8 @@ export interface HassioAddonDetails extends HassioAddonInfo { slug: string; startup: AddonStartup; stdin: boolean; + system_managed: boolean; + system_managed_config_entry: string | null; translations: Record; watchdog: null | boolean; webui: null | string; diff --git a/src/translations/en.json b/src/translations/en.json index c55f4b569b..f450a14c84 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -8932,6 +8932,13 @@ }, "logs": { "get_logs": "Failed to get add-on logs, {error}" + }, + "system_managed": { + "badge": "System-managed", + "title": "This add-on is managed by Home Assistant", + "description": "Manually modifying this configuration may cause the add-on or integration to stop working properly.", + "managed_by": "Managed by", + "take_control": "Take control" } }, "common": { @@ -8955,6 +8962,7 @@ "running_version": "You are currently running version {version}", "save": "[%key:ui::common::save%]", "close": "[%key:ui::common::close%]", + "back": "[%key:ui::common::back%]", "menu": "[%key:ui::common::menu%]", "show": "[%key:ui::panel::config::updates::show%]", "show_more": "Show more information about this",