diff --git a/build-scripts/bundle.js b/build-scripts/bundle.js index 1183a5ce06..dc4b59b02a 100644 --- a/build-scripts/bundle.js +++ b/build-scripts/bundle.js @@ -52,6 +52,7 @@ module.exports.terserOptions = (latestBuild) => ({ module.exports.babelOptions = ({ latestBuild }) => ({ babelrc: false, + compact: false, presets: [ !latestBuild && [ "@babel/preset-env", @@ -79,12 +80,6 @@ module.exports.babelOptions = ({ latestBuild }) => ({ ].filter(Boolean), }); -// Are already ES5, cause warnings when babelified. -module.exports.babelExclude = () => [ - require.resolve("@mdi/js/mdi.js"), - require.resolve("hls.js"), -]; - const outputPath = (outputRoot, latestBuild) => path.resolve(outputRoot, latestBuild ? "frontend_latest" : "frontend_es5"); diff --git a/build-scripts/rollup.js b/build-scripts/rollup.js index 7d9cf93046..f57e9f7e64 100644 --- a/build-scripts/rollup.js +++ b/build-scripts/rollup.js @@ -57,7 +57,6 @@ const createRollupConfig = ({ babel({ ...bundle.babelOptions({ latestBuild }), extensions, - exclude: bundle.babelExclude(), babelHelpers: isWDS ? "inline" : "bundled", }), string({ diff --git a/build-scripts/webpack.js b/build-scripts/webpack.js index fe025abac2..3dcac91de9 100644 --- a/build-scripts/webpack.js +++ b/build-scripts/webpack.js @@ -47,7 +47,6 @@ const createWebpackConfig = ({ rules: [ { test: /\.m?js$|\.ts$/, - exclude: bundle.babelExclude(), use: { loader: "babel-loader", options: bundle.babelOptions({ latestBuild }), diff --git a/hassio/src/dialogs/hardware/dialog-hassio-hardware.ts b/hassio/src/dialogs/hardware/dialog-hassio-hardware.ts new file mode 100755 index 0000000000..f7ccbd970b --- /dev/null +++ b/hassio/src/dialogs/hardware/dialog-hassio-hardware.ts @@ -0,0 +1,194 @@ +import { mdiClose } from "@mdi/js"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import memoizeOne from "memoize-one"; +import { fireEvent } from "../../../../src/common/dom/fire_event"; +import "../../../../src/common/search/search-input"; +import { compare } from "../../../../src/common/string/compare"; +import "../../../../src/components/ha-dialog"; +import "../../../../src/components/ha-expansion-panel"; +import { HassioHardwareInfo } from "../../../../src/data/hassio/hardware"; +import { dump } from "../../../../src/resources/js-yaml-dump"; +import { haStyle, haStyleDialog } from "../../../../src/resources/styles"; +import { HomeAssistant } from "../../../../src/types"; +import { HassioHardwareDialogParams } from "./show-dialog-hassio-hardware"; + +const _filterDevices = memoizeOne( + (showAdvanced: boolean, hardware: HassioHardwareInfo, filter: string) => + hardware.devices + .filter( + (device) => + (showAdvanced || + ["tty", "gpio", "input"].includes(device.subsystem)) && + (device.by_id?.toLowerCase().includes(filter) || + device.name.toLowerCase().includes(filter) || + device.dev_path.toLocaleLowerCase().includes(filter) || + JSON.stringify(device.attributes) + .toLocaleLowerCase() + .includes(filter)) + ) + .sort((a, b) => compare(a.name, b.name)) +); + +@customElement("dialog-hassio-hardware") +class HassioHardwareDialog extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @state() private _dialogParams?: HassioHardwareDialogParams; + + @state() private _filter?: string; + + public showDialog(params: HassioHardwareDialogParams) { + this._dialogParams = params; + } + + public closeDialog() { + this._dialogParams = undefined; + fireEvent(this, "dialog-closed", { dialog: this.localName }); + } + + protected render(): TemplateResult { + if (!this._dialogParams) { + return html``; + } + + const devices = _filterDevices( + this.hass.userData?.showAdvanced || false, + this._dialogParams.hardware, + (this._filter || "").toLowerCase() + ); + + return html` + +
+

+ ${this._dialogParams.supervisor.localize("dialog.hardware.title")} +

+ + + + + +
+ + ${devices.map( + (device) => + html` +
+ + ${this._dialogParams!.supervisor.localize( + "dialog.hardware.subsystem" + )}: + + ${device.subsystem} +
+
+ + ${this._dialogParams!.supervisor.localize( + "dialog.hardware.device_path" + )}: + + ${device.dev_path} +
+ ${device.by_id + ? html`
+ + ${this._dialogParams!.supervisor.localize( + "dialog.hardware.id" + )}: + + ${device.by_id} +
` + : ""} +
+ + ${this._dialogParams!.supervisor.localize( + "dialog.hardware.attributes" + )}: + +
${dump(device.attributes, { indent: 2 })}
+
+
` + )} +
+ `; + } + + private _handleSearchChange(ev: CustomEvent) { + this._filter = ev.detail.value; + } + + static get styles(): CSSResultGroup { + return [ + haStyle, + haStyleDialog, + css` + mwc-icon-button { + position: absolute; + right: 16px; + top: 10px; + text-decoration: none; + color: var(--primary-text-color); + } + h2 { + margin: 18px 42px 0 18px; + color: var(--primary-text-color); + } + + ha-expansion-panel { + margin: 4px 0; + } + pre, + code { + background-color: var(--markdown-code-background-color, none); + border-radius: 3px; + } + pre { + padding: 16px; + overflow: auto; + line-height: 1.45; + font-family: var(--code-font-family, monospace); + } + code { + font-size: 85%; + padding: 0.2em 0.4em; + } + search-input { + margin: 0 16px; + display: block; + } + .device-property { + display: flex; + justify-content: space-between; + } + .attributes { + margin-top: 12px; + } + `, + ]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "dialog-hassio-hardware": HassioHardwareDialog; + } +} diff --git a/hassio/src/dialogs/hardware/show-dialog-hassio-hardware.ts b/hassio/src/dialogs/hardware/show-dialog-hassio-hardware.ts new file mode 100644 index 0000000000..4ca15734e8 --- /dev/null +++ b/hassio/src/dialogs/hardware/show-dialog-hassio-hardware.ts @@ -0,0 +1,19 @@ +import { fireEvent } from "../../../../src/common/dom/fire_event"; +import { HassioHardwareInfo } from "../../../../src/data/hassio/hardware"; +import { Supervisor } from "../../../../src/data/supervisor/supervisor"; + +export interface HassioHardwareDialogParams { + supervisor: Supervisor; + hardware: HassioHardwareInfo; +} + +export const showHassioHardwareDialog = ( + element: HTMLElement, + dialogParams: HassioHardwareDialogParams +): void => { + fireEvent(element, "show-dialog", { + dialogTag: "dialog-hassio-hardware", + dialogImport: () => import("./dialog-hassio-hardware"), + dialogParams, + }); +}; diff --git a/hassio/src/dialogs/snapshot/dialog-hassio-snapshot.ts b/hassio/src/dialogs/snapshot/dialog-hassio-snapshot.ts index e934bced92..e7afcdbad1 100755 --- a/hassio/src/dialogs/snapshot/dialog-hassio-snapshot.ts +++ b/hassio/src/dialogs/snapshot/dialog-hassio-snapshot.ts @@ -22,6 +22,7 @@ import { import { HassDialog } from "../../../../src/dialogs/make-dialog-manager"; import { haStyle, haStyleDialog } from "../../../../src/resources/styles"; import { HomeAssistant } from "../../../../src/types"; +import { fileDownload } from "../../../../src/util/file_download"; import "../../components/supervisor-snapshot-content"; import type { SupervisorSnapshotContent } from "../../components/supervisor-snapshot-content"; import { HassioSnapshotDialogParams } from "./show-dialog-hassio-snapshot"; @@ -288,12 +289,11 @@ class HassioSnapshotDialog } } - const a = document.createElement("a"); - a.href = signedPath.path; - a.download = `home_assistant_snapshot_${slugify(this._computeName)}.tar`; - this.shadowRoot!.appendChild(a); - a.click(); - this.shadowRoot!.removeChild(a); + fileDownload( + this, + signedPath.path, + `home_assistant_snapshot_${slugify(this._computeName)}.tar` + ); } private get _computeName() { diff --git a/hassio/src/ingress-view/hassio-ingress-view.ts b/hassio/src/ingress-view/hassio-ingress-view.ts index 710cf3b5e3..24d050acb9 100644 --- a/hassio/src/ingress-view/hassio-ingress-view.ts +++ b/hassio/src/ingress-view/hassio-ingress-view.ts @@ -97,16 +97,23 @@ class HassioIngressView extends LitElement { title: requestedAddon, }); await nextRender(); - history.back(); + navigate("/hassio/store", { replace: true }); return; } - if (!addonInfo.ingress) { + if (!addonInfo.version) { + await showAlertDialog(this, { + text: this.supervisor.localize("my.error_addon_not_installed"), + title: addonInfo.name, + }); + await nextRender(); + navigate(`/hassio/addon/${addonInfo.slug}/info`, { replace: true }); + } else if (!addonInfo.ingress) { await showAlertDialog(this, { text: this.supervisor.localize("my.error_addon_no_ingress"), title: addonInfo.name, }); await nextRender(); - history.back(); + navigate(`/hassio/addon/${addonInfo.slug}/info`, { replace: true }); } else { navigate(`/hassio/ingress/${addonInfo.slug}`, { replace: true }); } diff --git a/hassio/src/system/hassio-host-info.ts b/hassio/src/system/hassio-host-info.ts index cde6becf58..1381bf291a 100644 --- a/hassio/src/system/hassio-host-info.ts +++ b/hassio/src/system/hassio-host-info.ts @@ -2,7 +2,6 @@ import "@material/mwc-button"; import { ActionDetail } from "@material/mwc-list/mwc-list-foundation"; import "@material/mwc-list/mwc-list-item"; import { mdiDotsVertical } from "@mdi/js"; -import { dump } from "js-yaml"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property } from "lit/decorators"; import memoizeOne from "memoize-one"; @@ -41,8 +40,8 @@ import { roundWithOneDecimal, } from "../../../src/util/calculate"; import "../components/supervisor-metric"; -import { showHassioMarkdownDialog } from "../dialogs/markdown/show-dialog-hassio-markdown"; import { showNetworkDialog } from "../dialogs/network/show-dialog-network"; +import { showHassioHardwareDialog } from "../dialogs/hardware/show-dialog-hassio-hardware"; import { hassioStyle } from "../resources/hassio-style"; @customElement("hassio-host-info") @@ -229,20 +228,19 @@ class HassioHostInfo extends LitElement { } private async _showHardware(): Promise { + let hardware; try { - const content = await fetchHassioHardwareInfo(this.hass); - showHassioMarkdownDialog(this, { - title: this.supervisor.localize("system.host.hardware"), - content: `
${dump(content, { indent: 2 })}
`, - }); + hardware = await fetchHassioHardwareInfo(this.hass); } catch (err) { - showAlertDialog(this, { + await showAlertDialog(this, { title: this.supervisor.localize( "system.host.failed_to_get_hardware_list" ), text: extractApiErrorMessage(err), }); + return; } + showHassioHardwareDialog(this, { supervisor: this.supervisor, hardware }); } private async _hostReboot(ev: CustomEvent): Promise { diff --git a/lint-staged.config.js b/lint-staged.config.js index 15d6269cbc..2c08d7e620 100644 --- a/lint-staged.config.js +++ b/lint-staged.config.js @@ -1,5 +1,4 @@ module.exports = { - "*.ts": () => "tsc -p tsconfig.json", "*.{js,ts}": "eslint --fix", "!(/translations)*.{js,ts,json,css,md,html}": "prettier --write", }; diff --git a/setup.py b/setup.py index 972990e191..cdb54db937 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup( name="home-assistant-frontend", - version="20210601.1", + version="20210603.0", description="The Home Assistant frontend", url="https://github.com/home-assistant/home-assistant-polymer", author="The Home Assistant Authors", diff --git a/src/components/ha-expansion-panel.ts b/src/components/ha-expansion-panel.ts index f553e3ffc6..705b5a6b81 100644 --- a/src/components/ha-expansion-panel.ts +++ b/src/components/ha-expansion-panel.ts @@ -14,12 +14,17 @@ class HaExpansionPanel extends LitElement { @property() header?: string; + @property() secondary?: string; + @query(".container") private _container!: HTMLDivElement; protected render(): TemplateResult { return html`
- ${this.header} + + ${this.header} + ${this.secondary} + { const percentage = getValueInPercentage(normalize(value, min, max), min, max); return (percentage * 180) / 100; }; -// Workaround for https://github.com/home-assistant/frontend/issues/6467 -const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); - @customElement("ha-gauge") export class Gauge extends LitElement { @property({ type: Number }) public min = 0; diff --git a/src/data/hassio/hardware.ts b/src/data/hassio/hardware.ts index a61311f924..888a6609f4 100644 --- a/src/data/hassio/hardware.ts +++ b/src/data/hassio/hardware.ts @@ -14,12 +14,17 @@ interface HassioHardwareAudioList { }; } +interface HardwareDevice { + attributes: Record; + by_id: null | string; + dev_path: string; + name: string; + subsystem: string; + sysfs: string; +} + export interface HassioHardwareInfo { - serial: string[]; - input: string[]; - disk: string[]; - gpio: string[]; - audio: Record; + devices: HardwareDevice[]; } export const fetchHassioHardwareAudio = async ( diff --git a/src/dialogs/more-info/controls/more-info-person.ts b/src/dialogs/more-info/controls/more-info-person.ts index 328b73dc97..ea7858de78 100644 --- a/src/dialogs/more-info/controls/more-info-person.ts +++ b/src/dialogs/more-info/controls/more-info-person.ts @@ -23,11 +23,6 @@ class MoreInfoPerson extends LitElement { } return html` - ${this.stateObj.attributes.latitude && this.stateObj.attributes.longitude ? html` ` : ""} + `; } diff --git a/src/dialogs/more-info/controls/more-info-timer.ts b/src/dialogs/more-info/controls/more-info-timer.ts index daf2e8e97f..e3ab452ea7 100644 --- a/src/dialogs/more-info/controls/more-info-timer.ts +++ b/src/dialogs/more-info/controls/more-info-timer.ts @@ -17,11 +17,6 @@ class MoreInfoTimer extends LitElement { } return html` -
${this.stateObj.state === "idle" || this.stateObj.state === "paused" ? html` @@ -57,6 +52,11 @@ class MoreInfoTimer extends LitElement { ` : ""}
+ `; } diff --git a/src/html/authorize.html.template b/src/html/authorize.html.template index 1cf1c7bba4..555aea9e0e 100644 --- a/src/html/authorize.html.template +++ b/src/html/authorize.html.template @@ -48,6 +48,9 @@ window.providersPromise = fetch("/auth/providers", { credentials: "same-origin", }); + if (!window.globalThis) { + window.globalThis = window; + }