import { mdiPower } from "@mdi/js"; import type { CSSResultGroup, TemplateResult } from "lit"; import { css, html, LitElement } from "lit"; import { customElement, property, state } from "lit/decorators"; import { canShowPage } from "../../../common/config/can_show_page"; import { isComponentLoaded } from "../../../common/config/is_component_loaded"; import { relativeTime } from "../../../common/datetime/relative_time"; import { blankBeforePercent } from "../../../common/translations/blank_before_percent"; import "../../../components/ha-card"; import "../../../components/ha-icon-button"; import "../../../components/ha-navigation-list"; import type { BackupContent } from "../../../data/backup"; import { fetchBackupInfo } from "../../../data/backup"; import type { CloudStatus } from "../../../data/cloud"; import { fetchCloudStatus } from "../../../data/cloud"; import type { HardwareInfo } from "../../../data/hardware"; import { BOARD_NAMES } from "../../../data/hardware"; import type { HassioHassOSInfo, HassioHostInfo, } from "../../../data/hassio/host"; import { fetchHassioHassOsInfo, fetchHassioHostInfo, } from "../../../data/hassio/host"; import { showRestartDialog } from "../../../dialogs/restart/show-dialog-restart"; import "../../../layouts/hass-subpage"; import { haStyle } from "../../../resources/styles"; import type { HomeAssistant } from "../../../types"; import "../ha-config-section"; import { configSections } from "../ha-panel-config"; @customElement("ha-config-system-navigation") class HaConfigSystemNavigation extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @property({ type: Boolean, reflect: true }) public narrow = false; @property({ attribute: "is-wide", type: Boolean }) public isWide = false; @property({ attribute: false }) public cloudStatus?: CloudStatus; @property({ attribute: false }) public showAdvanced = false; @state() private _latestBackupDate?: Date; @state() private _boardName?: string; @state() private _storageInfo?: { used: number; free: number; total: number }; @state() private _externalAccess = false; protected render(): TemplateResult { const pages = configSections.general .filter((page) => canShowPage(this.hass, page)) .map((page) => { let description = ""; switch (page.translationKey) { case "backup": description = this._latestBackupDate ? this.hass.localize("ui.panel.config.backup.description", { relative_time: relativeTime( this._latestBackupDate, this.hass.locale ), }) : this.hass.localize( "ui.panel.config.backup.description_no_backup" ); break; case "network": description = this.hass.localize( "ui.panel.config.network.description", { state: this._externalAccess ? this.hass.localize("ui.panel.config.network.enabled") : this.hass.localize("ui.panel.config.network.disabled"), } ); break; case "storage": description = this._storageInfo ? this.hass.localize("ui.panel.config.storage.description", { percent_used: `${Math.round( (this._storageInfo.used / this._storageInfo.total) * 100 )}${blankBeforePercent(this.hass.locale)}%`, free_space: `${this._storageInfo.free} GB`, }) : ""; break; case "hardware": description = this._boardName || this.hass.localize("ui.panel.config.hardware.description"); break; default: description = this.hass.localize( `ui.panel.config.${page.translationKey}.description` ); break; } return { ...page, name: page.translationKey ? this.hass.localize( `ui.panel.config.${page.translationKey}.caption` ) : page.name, description, }; }); return html` `; } protected firstUpdated(_changedProperties): void { super.firstUpdated(_changedProperties); this._fetchNetworkStatus(); const isHassioLoaded = isComponentLoaded(this.hass, "hassio"); this._fetchBackupInfo(); this._fetchHardwareInfo(isHassioLoaded); if (isHassioLoaded) { this._fetchStorageInfo(); } } private async _fetchBackupInfo() { const backups: BackupContent[] = isComponentLoaded(this.hass, "backup") ? await fetchBackupInfo(this.hass).then( (backupData) => backupData.backups ) : []; if (backups.length > 0) { this._latestBackupDate = backups .map((backup) => new Date(backup.date)) .reduce((a, b) => (a > b ? a : b)); } } private async _fetchHardwareInfo(isHassioLoaded: boolean) { if (isComponentLoaded(this.hass, "hardware")) { const hardwareInfo: HardwareInfo = await this.hass.callWS({ type: "hardware/info", }); this._boardName = hardwareInfo?.hardware.find( (hw) => hw.board !== null )?.name; } else if (isHassioLoaded) { const osData: HassioHassOSInfo = await fetchHassioHassOsInfo(this.hass); if (osData.board) { this._boardName = BOARD_NAMES[osData.board]; } } } private async _fetchStorageInfo() { const hostInfo: HassioHostInfo = await fetchHassioHostInfo(this.hass); this._storageInfo = { used: hostInfo.disk_used, free: hostInfo.disk_free, total: hostInfo.disk_total, }; } private async _fetchNetworkStatus() { if (isComponentLoaded(this.hass, "cloud")) { const cloudStatus = await fetchCloudStatus(this.hass); if (cloudStatus.logged_in) { this._externalAccess = true; return; } } this._externalAccess = this.hass.config.external_url !== null; } private async _showRestartDialog() { showRestartDialog(this); } static get styles(): CSSResultGroup { return [ haStyle, css` :host(:not([narrow])) ha-card { margin-bottom: max(24px, var(--safe-area-inset-bottom)); } ha-config-section { margin: auto; margin-top: -32px; max-width: 600px; } ha-card { overflow: hidden; margin-bottom: 24px; margin-bottom: max(24px, var(--safe-area-inset-bottom)); } ha-card a { text-decoration: none; color: var(--primary-text-color); } .title { font-size: var(--ha-font-size-l); padding: 16px; padding-bottom: 0; } .restart-section { display: flex; align-items: center; flex-direction: column; justify-content: center; margin-bottom: 24px; } @media all and (max-width: 600px) { ha-card { border-width: 1px 0; border-radius: 0; box-shadow: unset; } ha-config-section { margin-top: -42px; } } ha-navigation-list { --navigation-list-item-title-font-size: var(--ha-font-size-l); } `, ]; } } declare global { interface HTMLElementTagNameMap { "ha-config-system-navigation": HaConfigSystemNavigation; } }