diff --git a/src/data/hardware.ts b/src/data/hardware.ts index 54ea838675..7f0cfc755a 100644 --- a/src/data/hardware.ts +++ b/src/data/hardware.ts @@ -20,3 +20,20 @@ export const BOARD_NAMES: Record = { "intel-nuc": "Intel NUC", yellow: "Home Assistant Yellow", }; + +export interface HardwareInfo { + hardware: HardwareInfoEntry[]; +} + +export interface HardwareInfoEntry { + board: HardwareInfoBoardInfo; + name: string; + url?: string; +} + +export interface HardwareInfoBoardInfo { + manufacturer: string; + model?: string; + revision?: string; + hassio_board_id?: string; +} diff --git a/src/panels/config/hardware/ha-config-hardware.ts b/src/panels/config/hardware/ha-config-hardware.ts index 5a080dae98..f5c09b5022 100644 --- a/src/panels/config/hardware/ha-config-hardware.ts +++ b/src/panels/config/hardware/ha-config-hardware.ts @@ -1,14 +1,18 @@ +import "@material/mwc-list/mwc-list"; import "@material/mwc-list/mwc-list-item"; import { mdiDotsVertical } from "@mdi/js"; import { css, html, LitElement, PropertyValues, TemplateResult } from "lit"; import { customElement, property, state } from "lit/decorators"; +import { ifDefined } from "lit/directives/if-defined"; import { isComponentLoaded } from "../../../common/config/is_component_loaded"; import "../../../components/buttons/ha-progress-button"; import "../../../components/ha-alert"; import "../../../components/ha-button-menu"; import "../../../components/ha-card"; +import "../../../components/ha-clickable-list-item"; +import "../../../components/ha-icon-next"; import "../../../components/ha-settings-row"; -import { BOARD_NAMES } from "../../../data/hardware"; +import { BOARD_NAMES, HardwareInfo } from "../../../data/hardware"; import { extractApiErrorMessage, ignoreSupervisorError, @@ -28,6 +32,8 @@ import { import "../../../layouts/hass-subpage"; import { haStyle } from "../../../resources/styles"; import type { HomeAssistant } from "../../../types"; +import { hardwareBrandsUrl } from "../../../util/brands-url"; +import { showToast } from "../../../util/toast"; import { showhardwareAvailableDialog } from "./show-dialog-hardware-available"; @customElement("ha-config-hardware") @@ -42,14 +48,36 @@ class HaConfigHardware extends LitElement { @state() private _hostData?: HassioHostInfo; + @state() private _hardwareInfo?: HardwareInfo; + protected firstUpdated(changedProps: PropertyValues) { super.firstUpdated(changedProps); - if (isComponentLoaded(this.hass, "hassio")) { - this._load(); - } + this._load(); } protected render(): TemplateResult { + let boardId: string | undefined; + let boardName: string | undefined; + let imageURL: string | undefined; + let documentationURL: string | undefined; + + if (this._hardwareInfo?.hardware.length) { + const boardData = this._hardwareInfo!.hardware[0]; + + boardId = boardData.board.hassio_board_id; + boardName = boardData.name; + documentationURL = boardData.url; + imageURL = hardwareBrandsUrl({ + category: "boards", + manufacturer: boardData.board.manufacturer, + model: boardData.board.model, + darkOptimized: this.hass.themes?.darkMode, + }); + } else if (this._OSData?.board) { + boardId = this._OSData.board; + boardName = BOARD_NAMES[this._OSData.board]; + } + return html` + ${this._hostData + ? html` + ${this.hass.localize( + "ui.panel.config.hardware.reboot_host" + )} + ${this.hass.localize( + "ui.panel.config.hardware.shutdown_host" + )} + ` + : ""} ${this._error ? html` @@ -76,57 +118,55 @@ class HaConfigHardware extends LitElement { > ` : ""} - ${this._OSData || this._hostData + ${boardName ? html`
- ${this._OSData?.board - ? html` -
- - ${BOARD_NAMES[this._OSData.board] || - this.hass.localize( - "ui.panel.config.hardware.board" - )} + + + ${imageURL + ? html`` + : ""} + + ${boardName || + this.hass.localize("ui.panel.config.hardware.board")} + + ${boardId + ? html` + ${boardId} + ` + : ""} + + ${documentationURL + ? html` + -
- ${this._OSData.board} -
-
-
- ` - : ""} - ${this._hostData - ? html` -
- ${this._hostData.features.includes("reboot") - ? html` - - ${this.hass.localize( - "ui.panel.config.hardware.reboot_host" - )} - - ` - : ""} - ${this._hostData.features.includes("shutdown") - ? html` - - ${this.hass.localize( - "ui.panel.config.hardware.shutdown_host" - )} - - ` - : ""} -
- ` - : ""} + ${this.hass.localize( + "ui.panel.config.hardware.documentation" + )} + ${this.hass.localize( + "ui.panel.config.hardware.documentation_description" + )} + + + ` + : ""} + +
` @@ -136,9 +176,17 @@ class HaConfigHardware extends LitElement { } private async _load() { + const isHassioLoaded = isComponentLoaded(this.hass, "hassio"); try { - this._OSData = await fetchHassioHassOsInfo(this.hass); - this._hostData = await fetchHassioHostInfo(this.hass); + if (isComponentLoaded(this.hass, "hardware")) { + this._hardwareInfo = await this.hass.callWS({ type: "hardware/info" }); + } else if (isHassioLoaded) { + this._OSData = await fetchHassioHassOsInfo(this.hass); + } + + if (isHassioLoaded) { + this._hostData = await fetchHassioHostInfo(this.hass); + } } catch (err: any) { this._error = err.message || err; } @@ -148,10 +196,7 @@ class HaConfigHardware extends LitElement { showhardwareAvailableDialog(this); } - private async _hostReboot(ev: CustomEvent): Promise { - const button = ev.currentTarget as any; - button.progress = true; - + private async _hostReboot(): Promise { const confirmed = await showConfirmationDialog(this, { title: this.hass.localize("ui.panel.config.hardware.reboot_host"), text: this.hass.localize("ui.panel.config.hardware.reboot_host_confirm"), @@ -160,10 +205,14 @@ class HaConfigHardware extends LitElement { }); if (!confirmed) { - button.progress = false; return; } + showToast(this, { + message: this.hass.localize("ui.panel.config.hardware.rebooting_host"), + duration: 0, + }); + try { await rebootHost(this.hass); } catch (err: any) { @@ -177,13 +226,9 @@ class HaConfigHardware extends LitElement { }); } } - button.progress = false; } - private async _hostShutdown(ev: CustomEvent): Promise { - const button = ev.currentTarget as any; - button.progress = true; - + private async _hostShutdown(): Promise { const confirmed = await showConfirmationDialog(this, { title: this.hass.localize("ui.panel.config.hardware.shutdown_host"), text: this.hass.localize( @@ -194,10 +239,16 @@ class HaConfigHardware extends LitElement { }); if (!confirmed) { - button.progress = false; return; } + showToast(this, { + message: this.hass.localize( + "ui.panel.config.hardware.host_shutting_down" + ), + duration: 0, + }); + try { await shutdownHost(this.hass); } catch (err: any) { @@ -211,7 +262,6 @@ class HaConfigHardware extends LitElement { }); } } - button.progress = false; } static styles = [ @@ -234,17 +284,18 @@ class HaConfigHardware extends LitElement { display: flex; justify-content: space-between; flex-direction: column; - padding: 16px 16px 0 16px; + padding: 16px; } ha-button-menu { color: var(--secondary-text-color); --mdc-menu-min-width: 200px; } - .card-actions { - height: 48px; - display: flex; - justify-content: space-between; - align-items: center; + + .primary-text { + font-size: 16px; + } + .secondary-text { + font-size: 14px; } `, ]; diff --git a/src/translations/en.json b/src/translations/en.json index 2a933afea7..2d3f00c4ed 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1569,12 +1569,16 @@ "attributes": "Attributes" }, "reboot_host": "Reboot host", + "rebooting_host": "Rebooting host", "reboot_host_confirm": "Are you sure you want to reboot your host?", "failed_to_reboot_host": "Failed to reboot host", "shutdown_host": "Shutdown host", + "host_shutting_down": "Host shutting down", "shutdown_host_confirm": "Are you sure you want to shutdown your host?", "failed_to_shutdown_host": "Failed to shutdown host", - "board": "Board" + "board": "Board", + "documentation": "Documentation", + "documentation_description": "Find extra information about your device" }, "info": { "caption": "About", diff --git a/src/util/brands-url.ts b/src/util/brands-url.ts index 479cd5eb50..e4136bc199 100644 --- a/src/util/brands-url.ts +++ b/src/util/brands-url.ts @@ -5,9 +5,21 @@ export interface BrandsOptions { darkOptimized?: boolean; } +export interface HardwareBrandsOptions { + category: string; + model?: string; + manufacturer: string; + darkOptimized?: boolean; +} + export const brandsUrl = (options: BrandsOptions): string => `https://brands.home-assistant.io/${options.useFallback ? "_/" : ""}${ options.domain }/${options.darkOptimized ? "dark_" : ""}${options.type}.png`; +export const hardwareBrandsUrl = (options: HardwareBrandsOptions): string => + `https://brands.home-assistant.io/hardware/${options.category}/${ + options.darkOptimized ? "dark_" : "" + }${options.manufacturer}${options.model ? `_${options.model}` : ""}.png`; + export const extractDomainFromBrandUrl = (url: string) => url.split("/")[4];