diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index a556ef94a7..c7d3d8fa9c 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -74,11 +74,33 @@ jobs: version=$(echo "${{ github.ref }}" | awk -F"/" '{print $NF}' ) echo "home-assistant-frontend==$version" > ./requirements.txt - - name: Build wheels - uses: home-assistant/wheels@2022.06.7 + - name: Upload requirements.txt + uses: actions/upload-artifact@v2 with: - abi: cp310 - tag: musllinux_1_2 - arch: amd64 + name: requirements + path: ./requirements.txt + + build-wheels: + name: Build wheels for ${{ matrix.arch }} + needs: wheels-init + runs-on: ubuntu-latest + strategy: + matrix: + arch: ["aarch64", "armhf", "armv7", "amd64", "i386"] + tag: + - "3.9-alpine3.14" + steps: + - name: Download requirements.txt + uses: actions/download-artifact@v2 + with: + name: requirements + + - name: Build wheels + uses: home-assistant/wheels@master + with: + tag: ${{ matrix.tag }} + arch: ${{ matrix.arch }} + wheels-host: ${{ secrets.WHEELS_HOST }} wheels-key: ${{ secrets.WHEELS_KEY }} + wheels-user: wheels requirements: "requirements.txt" diff --git a/build-scripts/gulp/gen-icons-json.js b/build-scripts/gulp/gen-icons-json.js index 8a69ba97af..268ccb0ce5 100644 --- a/build-scripts/gulp/gen-icons-json.js +++ b/build-scripts/gulp/gen-icons-json.js @@ -156,12 +156,3 @@ gulp.task("gen-icons-json", (done) => { done(); }); - -gulp.task("gen-dummy-icons-json", (done) => { - if (!fs.existsSync(OUTPUT_DIR)) { - fs.mkdirSync(OUTPUT_DIR, { recursive: true }); - } - - fs.writeFileSync(path.resolve(OUTPUT_DIR, "iconList.json"), "[]"); - done(); -}); diff --git a/build-scripts/gulp/hassio.js b/build-scripts/gulp/hassio.js index 5b5e31650d..08370ad7c6 100644 --- a/build-scripts/gulp/hassio.js +++ b/build-scripts/gulp/hassio.js @@ -9,7 +9,6 @@ require("./compress.js"); require("./rollup.js"); require("./gather-static.js"); require("./translations.js"); -require("./gen-icons-json.js"); gulp.task( "develop-hassio", @@ -18,7 +17,6 @@ gulp.task( process.env.NODE_ENV = "development"; }, "clean-hassio", - "gen-dummy-icons-json", "gen-index-hassio-dev", "build-supervisor-translations", "copy-translations-supervisor", @@ -35,7 +33,6 @@ gulp.task( process.env.NODE_ENV = "production"; }, "clean-hassio", - "gen-dummy-icons-json", "build-supervisor-translations", "copy-translations-supervisor", "build-locale-data", diff --git a/demo/src/configs/kernehed/entities.ts b/demo/src/configs/kernehed/entities.ts index f7020ee719..53d6b74524 100644 --- a/demo/src/configs/kernehed/entities.ts +++ b/demo/src/configs/kernehed/entities.ts @@ -59,7 +59,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () => attributes: { hidden: true, radius: 50, - friendly_name: "School", + friendly_name: "Skolan", icon: "mdi:school", }, }, @@ -137,7 +137,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () => state: "73", attributes: { unit_of_measurement: "%", - friendly_name: "Oskar battery", + friendly_name: "oskar batteri", device_class: "battery", }, }, @@ -146,7 +146,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () => state: "88", attributes: { unit_of_measurement: "%", - friendly_name: "Bella battery", + friendly_name: "bella batteri", device_class: "battery", }, }, @@ -154,7 +154,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () => entity_id: "binary_sensor.unifi_camera", state: "off", attributes: { - friendly_name: "Motion sensor camera", + friendly_name: "R\u00f6relsesensor kamera", icon: "mdi:walk", }, }, @@ -707,7 +707,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () => }, ], cloudiness: 25, - friendly_name: "Weather", + friendly_name: "V\u00e4der", }, }, "binary_sensor.ubiquiti_switch": { @@ -731,7 +731,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () => round_trip_time_max: "0.626", round_trip_time_mdev: "", round_trip_time_min: "0.358", - friendly_name: "Entrance camera", + friendly_name: "Entr\u00e9 kamera", device_class: "connectivity", icon: "mdi:cctv", }, @@ -807,7 +807,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () => attributes: { battery_level: 88, on: true, - friendly_name: "Back door sensor", + friendly_name: "Altand\u00f6rren sensor", device_class: "opening", icon: "mdi:door", }, @@ -841,7 +841,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () => battery_level: 60, on: true, dark: true, - friendly_name: "Laundy room motion sensor", + friendly_name: "R\u00f6relsesensor tv\u00e4ttstugan", device_class: "motion", icon: "mdi:walk", }, diff --git a/demo/src/stubs/config.ts b/demo/src/stubs/config.ts index f77c8d3b09..c51700fb1d 100644 --- a/demo/src/stubs/config.ts +++ b/demo/src/stubs/config.ts @@ -1,7 +1,7 @@ import { MockHomeAssistant } from "../../../src/fake_data/provide_hass"; export const mockConfig = (hass: MockHomeAssistant) => { - hass.mockAPI("config/config_entries/entry?domain=co2signal", () => [ + hass.mockAPI("config/config_entries/entry", () => [ { entry_id: "co2signal", domain: "co2signal", diff --git a/demo/src/stubs/history.ts b/demo/src/stubs/history.ts index 2e2c507ccc..d843c942ac 100644 --- a/demo/src/stubs/history.ts +++ b/demo/src/stubs/history.ts @@ -466,7 +466,6 @@ export const mockHistory = (mockHass: MockHomeAssistant) => { return results; } ); - mockHass.mockWS("recorder/get_statistics_metadata", () => []); mockHass.mockWS("history/list_statistic_ids", () => []); mockHass.mockWS( "history/statistics_during_period", diff --git a/gallery/public/images/clearspace.png b/gallery/public/images/clearspace.png index fe7c1e7824..ffd1aa5f62 100644 Binary files a/gallery/public/images/clearspace.png and b/gallery/public/images/clearspace.png differ diff --git a/gallery/public/images/logo-variants.png b/gallery/public/images/logo-variants.png index d8c17f42a4..2a35152ce5 100644 Binary files a/gallery/public/images/logo-variants.png and b/gallery/public/images/logo-variants.png differ diff --git a/gallery/public/images/logo-with-text.png b/gallery/public/images/logo-with-text.png index 82f6836d10..c47eaa7112 100644 Binary files a/gallery/public/images/logo-with-text.png and b/gallery/public/images/logo-with-text.png differ diff --git a/gallery/public/images/logo.png b/gallery/public/images/logo.png index b62952edde..e3faf04c5a 100644 Binary files a/gallery/public/images/logo.png and b/gallery/public/images/logo.png differ diff --git a/gallery/public/images/sunflowers.jpg b/gallery/public/images/sunflowers.jpg index f2353eb71f..961d2a7bf3 100644 Binary files a/gallery/public/images/sunflowers.jpg and b/gallery/public/images/sunflowers.jpg differ diff --git a/gallery/public/images/using-our-logo.png b/gallery/public/images/using-our-logo.png index 6f264b3bfb..0199a37b64 100644 Binary files a/gallery/public/images/using-our-logo.png and b/gallery/public/images/using-our-logo.png differ diff --git a/hassio/src/addon-store/hassio-addon-repository.ts b/hassio/src/addon-store/hassio-addon-repository.ts index 56c9ecaadf..8d55dbcb8c 100644 --- a/hassio/src/addon-store/hassio-addon-repository.ts +++ b/hassio/src/addon-store/hassio-addon-repository.ts @@ -6,8 +6,10 @@ import { atLeastVersion } from "../../../src/common/config/version"; import { navigate } from "../../../src/common/navigate"; import { caseInsensitiveStringCompare } from "../../../src/common/string/compare"; import "../../../src/components/ha-card"; -import { HassioAddonRepository } from "../../../src/data/hassio/addon"; -import { StoreAddon } from "../../../src/data/supervisor/store"; +import { + HassioAddonInfo, + HassioAddonRepository, +} from "../../../src/data/hassio/addon"; import { Supervisor } from "../../../src/data/supervisor/supervisor"; import { HomeAssistant } from "../../../src/types"; import "../components/hassio-card-content"; @@ -21,16 +23,20 @@ class HassioAddonRepositoryEl extends LitElement { @property({ attribute: false }) public repo!: HassioAddonRepository; - @property({ attribute: false }) public addons!: StoreAddon[]; + @property({ attribute: false }) public addons!: HassioAddonInfo[]; @property() public filter!: string; - private _getAddons = memoizeOne((addons: StoreAddon[], filter?: string) => { - if (filter) { - return filterAndSort(addons, filter); + private _getAddons = memoizeOne( + (addons: HassioAddonInfo[], filter?: string) => { + if (filter) { + return filterAndSort(addons, filter); + } + return addons.sort((a, b) => + caseInsensitiveStringCompare(a.name, b.name) + ); } - return addons.sort((a, b) => caseInsensitiveStringCompare(a.name, b.name)); - }); + ); protected render(): TemplateResult { const repo = this.repo; diff --git a/hassio/src/addon-store/hassio-addon-store.ts b/hassio/src/addon-store/hassio-addon-store.ts index 2c373a4e9f..4d1f5ba1bf 100644 --- a/hassio/src/addon-store/hassio-addon-store.ts +++ b/hassio/src/addon-store/hassio-addon-store.ts @@ -14,15 +14,15 @@ 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 "../../../src/components/search-input"; import { extractSearchParam } from "../../../src/common/url/search-params"; import "../../../src/components/ha-button-menu"; import "../../../src/components/ha-icon-button"; -import "../../../src/components/search-input"; import { + HassioAddonInfo, HassioAddonRepository, reloadHassioAddons, } from "../../../src/data/hassio/addon"; -import { StoreAddon } from "../../../src/data/supervisor/store"; import { Supervisor } from "../../../src/data/supervisor/supervisor"; import "../../../src/layouts/hass-loading-screen"; import "../../../src/layouts/hass-subpage"; @@ -66,10 +66,10 @@ class HassioAddonStore extends LitElement { protected render(): TemplateResult { let repos: TemplateResult[] = []; - if (this.supervisor.store.repositories) { + if (this.supervisor.addon.repositories) { repos = this.addonRepositories( - this.supervisor.store.repositories, - this.supervisor.store.addons, + this.supervisor.addon.repositories, + this.supervisor.addon.addons, this._filter ); } @@ -145,7 +145,7 @@ class HassioAddonStore extends LitElement { private addonRepositories = memoizeOne( ( repositories: HassioAddonRepository[], - addons: StoreAddon[], + addons: HassioAddonInfo[], filter?: string ) => repositories.sort(sortRepos).map((repo) => { diff --git a/hassio/src/addon-view/hassio-addon-dashboard.ts b/hassio/src/addon-view/hassio-addon-dashboard.ts index 98a6c8a843..6f4580870f 100644 --- a/hassio/src/addon-view/hassio-addon-dashboard.ts +++ b/hassio/src/addon-view/hassio-addon-dashboard.ts @@ -12,17 +12,15 @@ import { navigate } from "../../../src/common/navigate"; import { extractSearchParam } from "../../../src/common/url/search-params"; import "../../../src/components/ha-circular-progress"; import { - fetchAddonInfo, fetchHassioAddonInfo, fetchHassioAddonsInfo, HassioAddonDetails, } from "../../../src/data/hassio/addon"; import { extractApiErrorMessage } from "../../../src/data/hassio/common"; import { - addStoreRepository, - fetchSupervisorStore, - StoreAddonDetails, -} from "../../../src/data/supervisor/store"; + fetchHassioSupervisorInfo, + setSupervisorOption, +} from "../../../src/data/hassio/supervisor"; import { Supervisor } from "../../../src/data/supervisor/supervisor"; import { showConfirmationDialog } from "../../../src/dialogs/generic/show-dialog-box"; import "../../../src/layouts/hass-error-screen"; @@ -47,9 +45,7 @@ class HassioAddonDashboard extends LitElement { @property({ attribute: false }) public route!: Route; - @property({ attribute: false }) public addon?: - | HassioAddonDetails - | StoreAddonDetails; + @property({ attribute: false }) public addon?: HassioAddonDetails; @property({ type: Boolean }) public narrow!: boolean; @@ -177,10 +173,10 @@ class HassioAddonDashboard extends LitElement { const requestedAddon = extractSearchParam("addon"); const requestedAddonRepository = extractSearchParam("repository_url"); if (requestedAddonRepository) { - const storeInfo = await fetchSupervisorStore(this.hass); + const supervisorInfo = await fetchHassioSupervisorInfo(this.hass); if ( - !storeInfo.repositories.find( - (repo) => repo.source === requestedAddonRepository + !supervisorInfo.addons_repositories.find( + (repo) => repo === requestedAddonRepository ) ) { if ( @@ -201,7 +197,12 @@ class HassioAddonDashboard extends LitElement { } try { - await addStoreRepository(this.hass, requestedAddonRepository); + await setSupervisorOption(this.hass, { + addons_repositories: [ + ...supervisorInfo.addons_repositories, + requestedAddonRepository, + ], + }); } catch (err: any) { this._error = extractApiErrorMessage(err); } @@ -244,8 +245,6 @@ class HassioAddonDashboard extends LitElement { if (path === "uninstall") { window.history.back(); - } else if (path === "install") { - this.addon = await fetchHassioAddonInfo(this.hass, this.addon!.slug); } else { await this._routeDataChanged(); } @@ -263,7 +262,8 @@ class HassioAddonDashboard extends LitElement { return; } try { - this.addon = await fetchAddonInfo(this.hass, this.supervisor, addon); + const addoninfo = await fetchHassioAddonInfo(this.hass, addon); + this.addon = addoninfo; } catch (err: any) { this._error = `Error fetching addon info: ${extractApiErrorMessage(err)}`; this.addon = undefined; diff --git a/hassio/src/addon-view/hassio-addon-router.ts b/hassio/src/addon-view/hassio-addon-router.ts index 66cf1fb8af..fe0bad9c00 100644 --- a/hassio/src/addon-view/hassio-addon-router.ts +++ b/hassio/src/addon-view/hassio-addon-router.ts @@ -1,6 +1,5 @@ import { customElement, property } from "lit/decorators"; import { HassioAddonDetails } from "../../../src/data/hassio/addon"; -import { StoreAddonDetails } from "../../../src/data/supervisor/store"; import { Supervisor } from "../../../src/data/supervisor/supervisor"; import { HassRouterPage, @@ -21,9 +20,7 @@ class HassioAddonRouter extends HassRouterPage { @property({ attribute: false }) public supervisor!: Supervisor; - @property({ attribute: false }) public addon!: - | HassioAddonDetails - | StoreAddonDetails; + @property({ attribute: false }) public addon!: HassioAddonDetails; protected routerOptions: RouterOptions = { defaultPage: "info", diff --git a/hassio/src/addon-view/info/hassio-addon-info.ts b/hassio/src/addon-view/info/hassio-addon-info.ts index 6675d7fd55..71a0a6f225 100644 --- a/hassio/src/addon-view/info/hassio-addon-info.ts +++ b/hassio/src/addon-view/info/hassio-addon-info.ts @@ -59,10 +59,7 @@ import { fetchHassioStats, HassioStats, } from "../../../../src/data/hassio/common"; -import { - StoreAddon, - StoreAddonDetails, -} from "../../../../src/data/supervisor/store"; +import { StoreAddon } from "../../../../src/data/supervisor/store"; import { Supervisor } from "../../../../src/data/supervisor/supervisor"; import { showAlertDialog, @@ -103,9 +100,7 @@ class HassioAddonInfo extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @property({ attribute: false }) public addon!: - | HassioAddonDetails - | StoreAddonDetails; + @property({ attribute: false }) public addon!: HassioAddonDetails; @property({ attribute: false }) public supervisor!: Supervisor; @@ -148,7 +143,7 @@ class HassioAddonInfo extends LitElement { > ` : ""} - ${"protected" in this.addon && !this.addon.protected + ${!this.addon.protected ? html`
- ${this.addon.version && this.addon.state === "started" + ${this.addon.state === "started" ? html` ${this.supervisor.localize("addon.dashboard.hostname")} @@ -674,7 +669,7 @@ class HassioAddonInfo extends LitElement { } private async _loadData(): Promise { - if ("state" in this.addon && this.addon.state === "started") { + if (this.addon.state === "started") { this._metrics = await fetchHassioStats( this.hass, `addons/${this.addon.slug}` @@ -722,22 +717,18 @@ class HassioAddonInfo extends LitElement { } private get _computeIsRunning(): boolean { - return (this.addon as HassioAddonDetails)?.state === "started"; + return this.addon?.state === "started"; } private get _pathWebui(): string | null { - return (this.addon as HassioAddonDetails).webui!.replace( - "[HOST]", - document.location.hostname + return ( + this.addon.webui && + this.addon.webui.replace("[HOST]", document.location.hostname) ); } private get _computeShowWebUI(): boolean | "" | null { - return ( - !this.addon.ingress && - (this.addon as HassioAddonDetails).webui && - this._computeIsRunning - ); + return !this.addon.ingress && this.addon.webui && this._computeIsRunning; } private _openIngress(): void { @@ -763,8 +754,7 @@ class HassioAddonInfo extends LitElement { private async _startOnBootToggled(): Promise { this._error = undefined; const data: HassioAddonSetOptionParams = { - boot: - (this.addon as HassioAddonDetails).boot === "auto" ? "manual" : "auto", + boot: this.addon.boot === "auto" ? "manual" : "auto", }; try { await setHassioAddonOption(this.hass, this.addon.slug, data); @@ -786,7 +776,7 @@ class HassioAddonInfo extends LitElement { private async _watchdogToggled(): Promise { this._error = undefined; const data: HassioAddonSetOptionParams = { - watchdog: !(this.addon as HassioAddonDetails).watchdog, + watchdog: !this.addon.watchdog, }; try { await setHassioAddonOption(this.hass, this.addon.slug, data); @@ -808,7 +798,7 @@ class HassioAddonInfo extends LitElement { private async _autoUpdateToggled(): Promise { this._error = undefined; const data: HassioAddonSetOptionParams = { - auto_update: !(this.addon as HassioAddonDetails).auto_update, + auto_update: !this.addon.auto_update, }; try { await setHassioAddonOption(this.hass, this.addon.slug, data); @@ -830,7 +820,7 @@ class HassioAddonInfo extends LitElement { private async _protectionToggled(): Promise { this._error = undefined; const data: HassioAddonSetSecurityParams = { - protected: !(this.addon as HassioAddonDetails).protected, + protected: !this.addon.protected, }; try { await setHassioAddonSecurity(this.hass, this.addon.slug, data); @@ -852,7 +842,7 @@ class HassioAddonInfo extends LitElement { private async _panelToggled(): Promise { this._error = undefined; const data: HassioAddonSetOptionParams = { - ingress_panel: !(this.addon as HassioAddonDetails).ingress_panel, + ingress_panel: !this.addon.ingress_panel, }; try { await setHassioAddonOption(this.hass, this.addon.slug, data); @@ -880,7 +870,7 @@ class HassioAddonInfo extends LitElement { showHassioMarkdownDialog(this, { title: this.supervisor.localize("addon.dashboard.changelog"), - content: extractChangelog(this.addon as HassioAddonDetails, content), + content: extractChangelog(this.addon, content), }); } catch (err: any) { showAlertDialog(this, { diff --git a/hassio/src/backups/hassio-backups.ts b/hassio/src/backups/hassio-backups.ts index 99d2869f8b..c8e8e5e30c 100644 --- a/hassio/src/backups/hassio-backups.ts +++ b/hassio/src/backups/hassio-backups.ts @@ -98,8 +98,9 @@ export class HassioBackups extends LitElement { if (backup.content.addons.length !== 0) { for (const addon of backup.content.addons) { content.push( - this.supervisor.addon.addons.find((entry) => entry.slug === addon) - ?.name || addon + this.supervisor.supervisor.addons.find( + (entry) => entry.slug === addon + )?.name || addon ); } } diff --git a/hassio/src/components/hassio-filter-addons.ts b/hassio/src/components/hassio-filter-addons.ts index 6daa1ddbad..ddb56188aa 100644 --- a/hassio/src/components/hassio-filter-addons.ts +++ b/hassio/src/components/hassio-filter-addons.ts @@ -1,8 +1,8 @@ import Fuse from "fuse.js"; -import { StoreAddon } from "../../../src/data/supervisor/store"; +import { HassioAddonInfo } from "../../../src/data/hassio/addon"; -export function filterAndSort(addons: StoreAddon[], filter: string) { - const options: Fuse.IFuseOptions = { +export function filterAndSort(addons: HassioAddonInfo[], filter: string) { + const options: Fuse.IFuseOptions = { keys: ["name", "description", "slug"], isCaseSensitive: false, minMatchCharLength: 2, diff --git a/hassio/src/components/supervisor-backup-content.ts b/hassio/src/components/supervisor-backup-content.ts index dd5c38a178..45faee620f 100644 --- a/hassio/src/components/supervisor-backup-content.ts +++ b/hassio/src/components/supervisor-backup-content.ts @@ -96,7 +96,7 @@ export class SupervisorBackupContent extends LitElement { : ["ssl", "share", "media", "addons/local"] ); this.addons = _computeAddons( - this.backup ? this.backup.addons : this.supervisor?.addon.addons + this.backup ? this.backup.addons : this.supervisor?.supervisor.addons ); this.backupType = this.backup?.type || "full"; this.backupName = this.backup?.name || ""; diff --git a/hassio/src/dashboard/hassio-addons.ts b/hassio/src/dashboard/hassio-addons.ts index cc855ccc69..4e685ef361 100644 --- a/hassio/src/dashboard/hassio-addons.ts +++ b/hassio/src/dashboard/hassio-addons.ts @@ -24,7 +24,7 @@ class HassioAddons extends LitElement { ? html`

${this.supervisor.localize("dashboard.addons")}

` : ""}
- ${!this.supervisor.addon.addons.length + ${!this.supervisor.supervisor.addons?.length ? html`
@@ -34,7 +34,7 @@ class HassioAddons extends LitElement {
` - : this.supervisor.addon.addons + : this.supervisor.supervisor.addons .sort((a, b) => caseInsensitiveStringCompare(a.name, b.name)) .map( (addon) => html` diff --git a/hassio/src/dialogs/repositories/dialog-hassio-repositories.ts b/hassio/src/dialogs/repositories/dialog-hassio-repositories.ts index 82325db788..d42cb05a4b 100644 --- a/hassio/src/dialogs/repositories/dialog-hassio-repositories.ts +++ b/hassio/src/dialogs/repositories/dialog-hassio-repositories.ts @@ -15,18 +15,15 @@ import "../../../../src/components/ha-circular-progress"; import { createCloseHeading } from "../../../../src/components/ha-dialog"; import "../../../../src/components/ha-icon-button"; import { + fetchHassioAddonsInfo, HassioAddonInfo, HassioAddonRepository, } from "../../../../src/data/hassio/addon"; import { extractApiErrorMessage } from "../../../../src/data/hassio/common"; +import { setSupervisorOption } from "../../../../src/data/hassio/supervisor"; import { haStyle, haStyleDialog } from "../../../../src/resources/styles"; import type { HomeAssistant } from "../../../../src/types"; import { HassioRepositoryDialogParams } from "./show-dialog-repositories"; -import { - addStoreRepository, - fetchStoreRepositories, - removeStoreRepository, -} from "../../../../src/data/supervisor/store"; @customElement("dialog-hassio-repositories") class HassioRepositoriesDialog extends LitElement { @@ -61,13 +58,7 @@ class HassioRepositoriesDialog extends LitElement { private _filteredRepositories = memoizeOne((repos: HassioAddonRepository[]) => repos - .filter( - (repo) => - repo.slug !== "core" && // The core add-ons repository - repo.slug !== "local" && // Locally managed add-ons - repo.slug !== "a0d7b954" && // Home Assistant Community Add-ons - repo.slug !== "5c53de3b" // The ESPHome repository - ) + .filter((repo) => repo.slug !== "core" && repo.slug !== "local") .sort((a, b) => caseInsensitiveStringCompare(a.name, b.name)) ); @@ -87,7 +78,7 @@ class HassioRepositoriesDialog extends LitElement { const repositories = this._filteredRepositories(this._repositories); const usedRepositories = this._filteredUsedRepositories( repositories, - this._dialogParams.supervisor.addon.addons + this._dialogParams.supervisor.supervisor.addons ); return html` { try { - this._repositories = await fetchStoreRepositories(this.hass); + const addonsinfo = await fetchHassioAddonsInfo(this.hass); + + this._repositories = addonsinfo.repositories; fireEvent(this, "supervisor-collection-refresh", { collection: "addon" }); } catch (err: any) { @@ -238,9 +231,14 @@ class HassioRepositoriesDialog extends LitElement { return; } this._processing = true; + const repositories = this._filteredRepositories(this._repositories!); + const newRepositories = repositories.map((repo) => repo.source); + newRepositories.push(input.value); try { - await addStoreRepository(this.hass, input.value); + await setSupervisorOption(this.hass, { + addons_repositories: newRepositories, + }); await this._loadData(); input.value = ""; @@ -252,8 +250,19 @@ class HassioRepositoriesDialog extends LitElement { private async _removeRepository(ev: Event) { const slug = (ev.currentTarget as any).slug; + const repositories = this._filteredRepositories(this._repositories!); + const repository = repositories.find((repo) => repo.slug === slug); + if (!repository) { + return; + } + const newRepositories = repositories + .map((repo) => repo.source) + .filter((repo) => repo !== repository.source); + try { - await removeStoreRepository(this.hass, slug); + await setSupervisorOption(this.hass, { + addons_repositories: newRepositories, + }); await this._loadData(); } catch (err: any) { this._error = extractApiErrorMessage(err); diff --git a/pyproject.toml b/pyproject.toml index 62a5a7f846..7ece90691f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "home-assistant-frontend" -version = "20220629.0" +version = "20220601.0" license = {text = "Apache-2.0"} description = "The Home Assistant frontend" readme = "README.md" diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index e14c0e7b08..0000000000 --- a/setup.cfg +++ /dev/null @@ -1,2 +0,0 @@ -# Setuptools v62.3 doesn't support editable installs with just 'pyproject.toml' (PEP 660). -# Keep this file until it does! diff --git a/src/common/entity/domain_icon.ts b/src/common/entity/domain_icon.ts index 82c10c6b48..498b882a4e 100644 --- a/src/common/entity/domain_icon.ts +++ b/src/common/entity/domain_icon.ts @@ -8,7 +8,6 @@ import { mdiCalendar, mdiCast, mdiCastConnected, - mdiChartSankey, mdiCheckCircleOutline, mdiClock, mdiCloseCircleOutline, @@ -25,7 +24,6 @@ import { mdiPowerPlug, mdiPowerPlugOff, mdiRestart, - mdiSwapHorizontal, mdiToggleSwitchVariant, mdiToggleSwitchVariantOff, mdiWeatherNight, @@ -155,12 +153,6 @@ export const domainIconWithoutDefault = ( ? FIXED_DOMAIN_ICONS[domain] : mdiWeatherNight; - case "switch_as_x": - return mdiSwapHorizontal; - - case "threshold": - return mdiChartSankey; - case "update": return compareState === "on" ? updateIsInstalling(stateObj as UpdateEntity) diff --git a/src/common/number/clamp.ts b/src/common/number/clamp.ts index 5591885f2e..3b2488afe8 100644 --- a/src/common/number/clamp.ts +++ b/src/common/number/clamp.ts @@ -5,6 +5,6 @@ export const clamp = (value: number, min: number, max: number) => export const conditionalClamp = (value: number, min?: number, max?: number) => { let result: number; result = min ? Math.max(value, min) : value; - result = max ? Math.min(result, max) : result; + result = max ? Math.min(value, max) : value; return result; }; diff --git a/src/components/chart/ha-chart-base.ts b/src/components/chart/ha-chart-base.ts index 84c4132849..170d933463 100644 --- a/src/components/chart/ha-chart-base.ts +++ b/src/components/chart/ha-chart-base.ts @@ -11,8 +11,6 @@ import { classMap } from "lit/directives/class-map"; import { styleMap } from "lit/directives/style-map"; import { clamp } from "../../common/number/clamp"; -export const MIN_TIME_BETWEEN_UPDATES = 60 * 5 * 1000; - interface Tooltip extends TooltipModel { top: string; left: string; @@ -326,9 +324,6 @@ export default class HaChartBase extends LitElement { width: 16px; flex-shrink: 0; box-sizing: border-box; - margin-inline-end: 6px; - margin-inline-start: initial; - direction: var(--direction); } .chartTooltip .bullet { align-self: baseline; @@ -337,9 +332,6 @@ export default class HaChartBase extends LitElement { :host([rtl]) .chartTooltip .bullet { margin-right: inherit; margin-left: 6px; - margin-inline-end: inherit; - margin-inline-start: 6px; - direction: var(--direction); } .chartTooltip { padding: 8px; diff --git a/src/components/chart/state-history-chart-line.ts b/src/components/chart/state-history-chart-line.ts index 85bb575985..f1ca3f4a19 100644 --- a/src/components/chart/state-history-chart-line.ts +++ b/src/components/chart/state-history-chart-line.ts @@ -8,7 +8,7 @@ import { } from "../../common/number/format_number"; import { LineChartEntity, LineChartState } from "../../data/history"; import { HomeAssistant } from "../../types"; -import { MIN_TIME_BETWEEN_UPDATES } from "./ha-chart-base"; +import "./ha-chart-base"; const safeParseFloat = (value) => { const parsed = parseFloat(value); @@ -34,8 +34,6 @@ class StateHistoryChartLine extends LitElement { @state() private _chartOptions?: ChartOptions; - private _chartTime: Date = new Date(); - protected render() { return html` { diff --git a/src/components/chart/state-history-chart-timeline.ts b/src/components/chart/state-history-chart-timeline.ts index 1f90bc36cd..519ae60b5b 100644 --- a/src/components/chart/state-history-chart-timeline.ts +++ b/src/components/chart/state-history-chart-timeline.ts @@ -9,7 +9,7 @@ import { numberFormatToLocale } from "../../common/number/format_number"; import { computeRTL } from "../../common/util/compute_rtl"; import { TimelineEntity } from "../../data/history"; import { HomeAssistant } from "../../types"; -import { MIN_TIME_BETWEEN_UPDATES } from "./ha-chart-base"; +import "./ha-chart-base"; import type { TimeLineData } from "./timeline-chart/const"; /** Binary sensor device classes for which the static colors for on/off are NOT inverted. @@ -103,8 +103,6 @@ export class StateHistoryChartTimeline extends LitElement { @state() private _chartOptions?: ChartOptions<"timeline">; - private _chartTime: Date = new Date(); - protected render() { return html` addon.version) - .sort((a, b) => stringCompare(a.name, b.name)); + const supervisorInfo = await fetchHassioSupervisorInfo(this.hass); + this._addons = supervisorInfo.addons.sort((a, b) => + stringCompare(a.name, b.name) + ); } else { showAlertDialog(this, { title: this.hass.localize( diff --git a/src/components/ha-chip.ts b/src/components/ha-chip.ts index 88bfc8be3c..cb58ebb75d 100644 --- a/src/components/ha-chip.ts +++ b/src/components/ha-chip.ts @@ -67,7 +67,8 @@ export class HaChip extends LitElement { color: var(--ha-chip-icon-color, var(--ha-chip-text-color)); } .mdc-chip.mdc-chip--selected .mdc-chip__checkmark, - .mdc-chip .mdc-chip__icon--leading:not(.mdc-chip__icon--leading-hidden) { + .mdc-chip.no-text + .mdc-chip__icon--leading:not(.mdc-chip__icon--leading-hidden) { margin-right: -4px; margin-inline-start: -4px; margin-inline-end: 4px; diff --git a/src/components/ha-clickable-list-item.ts b/src/components/ha-clickable-list-item.ts index 43175efd08..71f207a129 100644 --- a/src/components/ha-clickable-list-item.ts +++ b/src/components/ha-clickable-list-item.ts @@ -1,13 +1,17 @@ -import { css, CSSResultGroup, html } from "lit"; +import { ListItemBase } from "@material/mwc-list/mwc-list-item-base"; +import { styles } from "@material/mwc-list/mwc-list-item.css"; +import { css, CSSResult, html } from "lit"; import { customElement, property, query } from "lit/decorators"; -import { HaListItem } from "./ha-list-item"; @customElement("ha-clickable-list-item") -export class HaClickableListItem extends HaListItem { +export class HaClickableListItem extends ListItemBase { @property() public href?: string; @property({ type: Boolean }) public disableHref = false; + // property used only in css + @property({ type: Boolean, reflect: true }) public rtl = false; + @property({ type: Boolean, reflect: true }) public openNewTab = false; @query("a") private _anchor!: HTMLAnchorElement; @@ -35,10 +39,18 @@ export class HaClickableListItem extends HaListItem { }); } - static get styles(): CSSResultGroup { + static get styles(): CSSResult[] { return [ - super.styles, + styles, css` + :host { + padding-left: 0px; + padding-right: 0px; + } + :host([graphic="avatar"]:not([twoLine])), + :host([graphic="icon"]:not([twoLine])) { + height: 48px; + } a { width: 100%; height: 100%; @@ -48,6 +60,19 @@ export class HaClickableListItem extends HaListItem { padding-right: var(--mdc-list-side-padding, 20px); overflow: hidden; } + span.material-icons:first-of-type { + margin-inline-start: 0px !important; + margin-inline-end: var( + --mdc-list-item-graphic-margin, + 16px + ) !important; + direction: var(--direction); + } + span.material-icons:last-of-type { + margin-inline-start: auto !important; + margin-inline-end: 0px !important; + direction: var(--direction); + } `, ]; } diff --git a/src/components/ha-code-editor.ts b/src/components/ha-code-editor.ts index ff1364a934..2ec8a2e627 100644 --- a/src/components/ha-code-editor.ts +++ b/src/components/ha-code-editor.ts @@ -11,7 +11,6 @@ import memoizeOne from "memoize-one"; import { fireEvent } from "../common/dom/fire_event"; import { loadCodeMirror } from "../resources/codemirror.ondemand"; import { HomeAssistant } from "../types"; -import "./ha-icon"; declare global { interface HASSDomEvents { @@ -27,12 +26,6 @@ const saveKeyBinding: KeyBinding = { }, }; -const renderIcon = (completion: Completion) => { - const icon = document.createElement("ha-icon"); - icon.icon = completion.label; - return icon; -}; - @customElement("ha-code-editor") export class HaCodeEditor extends ReactiveElement { public codemirror?: EditorView; @@ -54,8 +47,6 @@ export class HaCodeEditor extends ReactiveElement { private _loadedCodeMirror?: typeof import("../resources/codemirror"); - private _iconList?: Completion[]; - public set value(value: string) { this._value = value; } @@ -163,10 +154,7 @@ export class HaCodeEditor extends ReactiveElement { if (!this.readOnly && this.autocompleteEntities && this.hass) { extensions.push( this._loadedCodeMirror.autocompletion({ - override: [ - this._entityCompletions.bind(this), - this._mdiCompletions.bind(this), - ], + override: [this._entityCompletions.bind(this)], maxRenderedOptions: 10, }) ); @@ -221,47 +209,6 @@ export class HaCodeEditor extends ReactiveElement { }; } - private _getIconItems = async (): Promise => { - if (!this._iconList) { - let iconList: { - name: string; - keywords: string[]; - }[]; - if (__SUPERVISOR__) { - iconList = []; - } else { - iconList = (await import("../../build/mdi/iconList.json")).default; - } - - this._iconList = iconList.map((icon) => ({ - type: "variable", - label: `mdi:${icon.name}`, - detail: icon.keywords.join(", "), - info: renderIcon, - })); - } - - return this._iconList; - }; - - private async _mdiCompletions( - context: CompletionContext - ): Promise { - const match = context.matchBefore(/mdi:/); - - if (!match || (match.from === match.to && !context.explicit)) { - return null; - } - - const iconItems = await this._getIconItems(); - - return { - from: Number(match.from), - options: iconItems, - span: /^\w*.\w*$/, - }; - } - private _blockKeyboardShortcuts() { this.addEventListener("keydown", (ev) => ev.stopPropagation()); } diff --git a/src/components/ha-dialog.ts b/src/components/ha-dialog.ts index 346410aa44..64fcbc4846 100644 --- a/src/components/ha-dialog.ts +++ b/src/components/ha-dialog.ts @@ -91,7 +91,6 @@ export class HaDialog extends DialogBase { .header_title { margin-right: 40px; margin-inline-end: 40px; - margin-inline-start: initial; direction: var(--direction); } .header_button { diff --git a/src/components/ha-fab.ts b/src/components/ha-fab.ts index 2432b9a20d..b36871e381 100644 --- a/src/components/ha-fab.ts +++ b/src/components/ha-fab.ts @@ -19,14 +19,6 @@ export class HaFab extends FabBase { direction: var(--direction); } `, - // safari workaround - must be explicit - document.dir === "rtl" - ? css` - :host .mdc-fab--extended .mdc-fab__icon { - direction: rtl; - } - ` - : css``, ]; } diff --git a/src/components/ha-form/ha-form-multi_select.ts b/src/components/ha-form/ha-form-multi_select.ts index a25de38672..a591f710bc 100644 --- a/src/components/ha-form/ha-form-multi_select.ts +++ b/src/components/ha-form/ha-form-multi_select.ts @@ -205,9 +205,6 @@ export class HaFormMultiSelect extends LitElement implements HaFormElement { ha-formfield { display: block; padding-right: 16px; - padding-inline-end: 16px; - padding-inline-start: initial; - direction: var(--direction); } ha-textfield { display: block; @@ -219,9 +216,6 @@ export class HaFormMultiSelect extends LitElement implements HaFormElement { right: 1em; top: 1em; cursor: pointer; - inset-inline-end: 1em; - inset-inline-start: initial; - direction: var(--direction); } :host([opened]) ha-svg-icon { color: var(--primary-color); diff --git a/src/components/ha-gauge.ts b/src/components/ha-gauge.ts index 1d60da1b3c..c3374d6b97 100644 --- a/src/components/ha-gauge.ts +++ b/src/components/ha-gauge.ts @@ -14,7 +14,6 @@ const getAngle = (value: number, min: number, max: number) => { export interface LevelDefinition { level: number; stroke: string; - label?: string; } @customElement("ha-gauge") @@ -39,31 +38,22 @@ export class Gauge extends LitElement { @state() private _updated = false; - @state() private _segment_label? = ""; - protected firstUpdated(changedProperties: PropertyValues) { super.firstUpdated(changedProperties); // Wait for the first render for the initial animation to work afterNextRender(() => { this._updated = true; this._angle = getAngle(this.value, this.min, this.max); - this._segment_label = this.getSegmentLabel(); this._rescale_svg(); }); } protected updated(changedProperties: PropertyValues) { super.updated(changedProperties); - if ( - !this._updated || - (!changedProperties.has("value") && - !changedProperties.has("label") && - !changedProperties.has("_segment_label")) - ) { + if (!this._updated || !changedProperties.has("value")) { return; } this._angle = getAngle(this.value, this.min, this.max); - this._segment_label = this.getSegmentLabel(); this._rescale_svg(); } @@ -128,11 +118,9 @@ export class Gauge extends LitElement { - ${ - this._segment_label - ? this._segment_label - : this.valueText || formatNumber(this.value, this.locale) - } ${this._segment_label ? "" : this.label} + ${this.valueText || formatNumber(this.value, this.locale)} ${ + this.label + } `; } @@ -149,18 +137,6 @@ export class Gauge extends LitElement { ); } - private getSegmentLabel() { - if (this.levels) { - this.levels.sort((a, b) => a.level - b.level); - for (let i = this.levels.length - 1; i >= 0; i--) { - if (this.value >= this.levels[i].level) { - return this.levels[i].label; - } - } - } - return ""; - } - static get styles() { return css` :host { diff --git a/src/components/ha-list-item.ts b/src/components/ha-list-item.ts deleted file mode 100644 index df3a2e80ee..0000000000 --- a/src/components/ha-list-item.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { ListItemBase } from "@material/mwc-list/mwc-list-item-base"; -import { styles } from "@material/mwc-list/mwc-list-item.css"; -import { css, CSSResultGroup } from "lit"; -import { customElement } from "lit/decorators"; - -@customElement("ha-list-item") -export class HaListItem extends ListItemBase { - static get styles(): CSSResultGroup { - return [ - styles, - css` - :host { - padding-left: var(--mdc-list-side-padding, 20px); - padding-right: var(--mdc-list-side-padding, 20px); - } - :host([graphic="avatar"]:not([twoLine])), - :host([graphic="icon"]:not([twoLine])) { - height: 48px; - } - span.material-icons:first-of-type { - margin-inline-start: 0px !important; - margin-inline-end: var( - --mdc-list-item-graphic-margin, - 16px - ) !important; - direction: var(--direction); - } - span.material-icons:last-of-type { - margin-inline-start: auto !important; - margin-inline-end: 0px !important; - direction: var(--direction); - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "ha-list-item": HaListItem; - } -} diff --git a/src/components/ha-target-picker.ts b/src/components/ha-target-picker.ts index 7545a19a36..1453afa07b 100644 --- a/src/components/ha-target-picker.ts +++ b/src/components/ha-target-picker.ts @@ -79,8 +79,6 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) { @property({ type: Boolean, reflect: true }) public disabled = false; - @property({ type: Boolean }) public horizontal = false; - @state() private _areas?: { [areaId: string]: AreaRegistryEntry }; @state() private _devices?: { @@ -119,55 +117,45 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) { if (!this._areas || !this._devices || !this._entities) { return html``; } - return html`
- ${this.horizontal ? this._renderChips() : this._renderItems()} - ${this._renderPicker()} - ${this.horizontal ? this._renderItems() : this._renderChips()} -
`; - } - - private _renderItems() { return html`
- ${this.value?.area_id - ? ensureArray(this.value.area_id).map((area_id) => { - const area = this._areas![area_id]; - return this._renderChip( - "area_id", - area_id, - area?.name || area_id, - undefined, - mdiSofa - ); - }) - : ""} - ${this.value?.device_id - ? ensureArray(this.value.device_id).map((device_id) => { - const device = this._devices![device_id]; - return this._renderChip( - "device_id", - device_id, - device ? computeDeviceName(device, this.hass) : device_id, - undefined, - mdiDevices - ); - }) - : ""} - ${this.value?.entity_id - ? ensureArray(this.value.entity_id).map((entity_id) => { - const entity = this.hass.states[entity_id]; - return this._renderChip( - "entity_id", - entity_id, - entity ? computeStateName(entity) : entity_id, - entity - ); - }) - : ""} -
`; - } - - private _renderChips() { - return html`
+ ${this.value?.area_id + ? ensureArray(this.value.area_id).map((area_id) => { + const area = this._areas![area_id]; + return this._renderChip( + "area_id", + area_id, + area?.name || area_id, + undefined, + mdiSofa + ); + }) + : ""} + ${this.value?.device_id + ? ensureArray(this.value.device_id).map((device_id) => { + const device = this._devices![device_id]; + return this._renderChip( + "device_id", + device_id, + device ? computeDeviceName(device, this.hass) : device_id, + undefined, + mdiDevices + ); + }) + : ""} + ${this.value?.entity_id + ? ensureArray(this.value.entity_id).map((entity_id) => { + const entity = this.hass.states[entity_id]; + return this._renderChip( + "entity_id", + entity_id, + entity ? computeStateName(entity) : entity_id, + entity + ); + }) + : ""} +
+ ${this._renderPicker()} +
+ ${this.helper ? html`${this.helper}` : ""} `; @@ -332,7 +321,6 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) { .entityFilter=${this.entityRegFilter} .includeDeviceClasses=${this.includeDeviceClasses} .includeDomains=${this.includeDomains} - class=${this.horizontal ? "hidden-picker" : ""} @value-changed=${this._targetPicked} >`; case "device_id": @@ -347,7 +335,6 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) { .entityFilter=${this.entityRegFilter} .includeDeviceClasses=${this.includeDeviceClasses} .includeDomains=${this.includeDomains} - class=${this.horizontal ? "hidden-picker" : ""} @value-changed=${this._targetPicked} >`; case "entity_id": @@ -361,7 +348,6 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) { .entityFilter=${this.entityFilter} .includeDeviceClasses=${this.includeDeviceClasses} .includeDomains=${this.includeDomains} - class=${this.horizontal ? "hidden-picker" : ""} @value-changed=${this._targetPicked} allow-custom-entity >`; @@ -553,16 +539,6 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) { static get styles(): CSSResultGroup { return css` ${unsafeCSS(chipStyles)} - .hidden-picker { - height: 0px; - display: inline-block; - overflow: hidden; - position: absolute; - } - .horizontal-container { - display: flex; - flex-wrap: wrap; - } .mdc-chip { color: var(--primary-text-color); } diff --git a/src/components/ha-textfield.ts b/src/components/ha-textfield.ts index 32c9bbde6f..0e0f3bd804 100644 --- a/src/components/ha-textfield.ts +++ b/src/components/ha-textfield.ts @@ -61,11 +61,6 @@ export class HaTextField extends TextFieldBase { padding-inline-end: var(--text-field-suffix-padding-right, 0px); direction: var(--direction); } - .mdc-text-field--with-leading-icon { - padding-inline-start: var(--text-field-suffix-padding-left, 0px); - padding-inline-end: var(--text-field-suffix-padding-right, 16px); - direction: var(--direction); - } .mdc-text-field:not(.mdc-text-field--disabled) .mdc-text-field__affix--suffix { @@ -76,12 +71,6 @@ export class HaTextField extends TextFieldBase { color: var(--secondary-text-color); } - .mdc-text-field__icon--leading { - margin-inline-start: 16px; - margin-inline-end: 8px; - direction: var(--direction); - } - input { text-align: var(--text-field-text-align); } @@ -121,25 +110,7 @@ export class HaTextField extends TextFieldBase { inset-inline-end: initial !important; direction: var(--direction); } - - .mdc-text-field__input[type="number"] { - direction: var(--direction); - } `, - // safari workaround - must be explicit - document.dir === "rtl" - ? css` - .mdc-text-field__affix--suffix, - .mdc-text-field--with-leading-icon, - .mdc-text-field__icon--leading, - .mdc-floating-label, - .mdc-text-field--with-leading-icon.mdc-text-field--filled - .mdc-floating-label, - .mdc-text-field__input[type="number"] { - direction: rtl; - } - ` - : css``, ]; } diff --git a/src/components/media-player/ha-browse-media-tts.ts b/src/components/media-player/ha-browse-media-tts.ts index 152da17ac6..3cd39d3a73 100644 --- a/src/components/media-player/ha-browse-media-tts.ts +++ b/src/components/media-player/ha-browse-media-tts.ts @@ -36,7 +36,7 @@ declare global { class BrowseMediaTTS extends LitElement { @property() public hass!: HomeAssistant; - @property() public item!: MediaPlayerItem; + @property() public item; @property() public action!: MediaPlayerBrowseAction; diff --git a/src/components/media-player/ha-media-player-browse.ts b/src/components/media-player/ha-media-player-browse.ts index da98917f43..4ee029ee13 100644 --- a/src/components/media-player/ha-media-player-browse.ts +++ b/src/components/media-player/ha-media-player-browse.ts @@ -116,6 +116,9 @@ export class HaMediaPlayerBrowse extends LitElement { private _resizeObserver?: ResizeObserver; + // @ts-ignore + private _intersectionObserver?: IntersectionObserver; + public connectedCallback(): void { super.connectedCallback(); this.updateComplete.then(() => this._attachResizeObserver()); @@ -125,6 +128,9 @@ export class HaMediaPlayerBrowse extends LitElement { if (this._resizeObserver) { this._resizeObserver.disconnect(); } + if (this._intersectionObserver) { + this._intersectionObserver.disconnect(); + } } public async refresh() { @@ -479,10 +485,7 @@ export class HaMediaPlayerBrowse extends LitElement { .layout=${grid({ itemSize: { width: "175px", - height: - childrenMediaClass.thumbnail_ratio === "portrait" - ? "312px" - : "225px", + height: "225px", }, gap: "16px", flex: { preserve: "aspect-ratio" }, diff --git a/src/components/user/ha-user-picker.ts b/src/components/user/ha-user-picker.ts index 6bbc3c1af3..0e7ae97466 100644 --- a/src/components/user/ha-user-picker.ts +++ b/src/components/user/ha-user-picker.ts @@ -8,7 +8,6 @@ import { fetchUsers, User } from "../../data/user"; import { HomeAssistant } from "../../types"; import "../ha-select"; import "./ha-user-badge"; -import "../ha-list-item"; class HaUserPicker extends LitElement { public hass?: HomeAssistant; @@ -49,14 +48,14 @@ class HaUserPicker extends LitElement { : ""} ${this._sortedUsers(this.users).map( (user) => html` - + ${user.name} - + ` )} diff --git a/src/data/application_credential.ts b/src/data/application_credential.ts index 5dee1bd355..075ea5f721 100644 --- a/src/data/application_credential.ts +++ b/src/data/application_credential.ts @@ -1,11 +1,7 @@ import { HomeAssistant } from "../types"; -export interface ApplicationCredentialsDomainConfig { - description_placeholders: string; -} - export interface ApplicationCredentialsConfig { - integrations: Record; + domains: string[]; } export interface ApplicationCredential { diff --git a/src/data/cached-history.ts b/src/data/cached-history.ts index 30fa4956f9..563d3d898b 100644 --- a/src/data/cached-history.ts +++ b/src/data/cached-history.ts @@ -158,14 +158,8 @@ export const getRecentWithCache = ( } const stateHistory = computeHistory(hass, fetchedHistory, localize); if (appendingToCache) { - if (stateHistory.line.length) { - mergeLine(stateHistory.line, cache.data.line); - } - if (stateHistory.timeline.length) { - mergeTimeline(stateHistory.timeline, cache.data.timeline); - // Replace the timeline array to force an update - cache.data.timeline = [...cache.data.timeline]; - } + mergeLine(stateHistory.line, cache.data.line); + mergeTimeline(stateHistory.timeline, cache.data.timeline); pruneStartTime(startTime, cache.data); } else { cache.data = stateHistory; @@ -197,8 +191,6 @@ const mergeLine = ( oldLine.data.push(entity); } }); - // Replace the cached line data to force an update - oldLine.data = [...oldLine.data]; } else { cacheLines.push(line); } diff --git a/src/data/camera.ts b/src/data/camera.ts index cca3671377..48bbe4bc73 100644 --- a/src/data/camera.ts +++ b/src/data/camera.ts @@ -41,12 +41,6 @@ export interface WebRtcAnswer { answer: string; } -export const cameraUrlWithWidthHeight = ( - base_url: string, - width: number, - height: number -) => `${base_url}&width=${width}&height=${height}`; - export const computeMJPEGStreamUrl = (entity: CameraEntity) => `/api/camera_proxy_stream/${entity.entity_id}?token=${entity.attributes.access_token}`; @@ -63,7 +57,7 @@ export const fetchThumbnailUrlWithCache = async ( hass, entityId ); - return cameraUrlWithWidthHeight(base_url, width, height); + return `${base_url}&width=${width}&height=${height}`; }; export const fetchThumbnailUrl = async ( diff --git a/src/data/config_entries.ts b/src/data/config_entries.ts index 88667cf2ab..b9e555998c 100644 --- a/src/data/config_entries.ts +++ b/src/data/config_entries.ts @@ -38,19 +38,19 @@ export const getConfigEntries = ( hass: HomeAssistant, filters?: { type?: "helper" | "integration"; domain?: string } ): Promise => { - const params: any = {}; + const params = new URLSearchParams(); if (filters) { if (filters.type) { - params.type_filter = filters.type; + params.append("type", filters.type); } if (filters.domain) { - params.domain = filters.domain; + params.append("domain", filters.domain); } } - return hass.callWS({ - type: "config_entries/get", - ...params, - }); + return hass.callApi( + "GET", + `config/config_entries/entry?${params.toString()}` + ); }; export const updateConfigEntry = ( diff --git a/src/data/entity_registry.ts b/src/data/entity_registry.ts index 4c7a931d0f..e77d75c2b5 100644 --- a/src/data/entity_registry.ts +++ b/src/data/entity_registry.ts @@ -33,18 +33,6 @@ export interface UpdateEntityRegistryEntryResult { require_restart?: boolean; } -export interface SensorEntityOptions { - unit_of_measurement?: string | null; -} - -export interface WeatherEntityOptions { - precipitation_unit?: string | null; - pressure_unit?: string | null; - temperature_unit?: string | null; - visibility_unit?: string | null; - wind_speed_unit?: string | null; -} - export interface EntityRegistryEntryUpdateParams { name?: string | null; icon?: string | null; @@ -54,7 +42,9 @@ export interface EntityRegistryEntryUpdateParams { hidden_by: string | null; new_entity_id?: string; options_domain?: string; - options?: SensorEntityOptions | WeatherEntityOptions; + options?: { + unit_of_measurement?: string | null; + }; } export const findBatteryEntity = ( diff --git a/src/data/hassio/addon.ts b/src/data/hassio/addon.ts index 5c1e7f49c2..c27d735b0e 100644 --- a/src/data/hassio/addon.ts +++ b/src/data/hassio/addon.ts @@ -1,9 +1,7 @@ import { atLeastVersion } from "../../common/config/version"; import type { HaFormSchema } from "../../components/ha-form/types"; import { HomeAssistant } from "../../types"; -import { supervisorApiCall } from "../supervisor/common"; -import { StoreAddonDetails } from "../supervisor/store"; -import { Supervisor, SupervisorArch } from "../supervisor/supervisor"; +import { SupervisorArch } from "../supervisor/supervisor"; import { extractApiErrorMessage, hassioApiResultExtractor, @@ -365,15 +363,3 @@ export const uninstallHassioAddon = async ( `hassio/addons/${slug}/uninstall` ); }; - -export const fetchAddonInfo = ( - hass: HomeAssistant, - supervisor: Supervisor, - addonSlug: string -): Promise => - supervisorApiCall( - hass, - !supervisor.addon?.addons.find((addon) => addon.slug === addonSlug) - ? `/store/addons/${addonSlug}` // Use /store/addons when add-on is not installed - : `/addons/${addonSlug}/info` // Use /addons when add-on is installed - ); diff --git a/src/data/hassio/supervisor.ts b/src/data/hassio/supervisor.ts index 9f5bcd0f28..e08600098b 100644 --- a/src/data/hassio/supervisor.ts +++ b/src/data/hassio/supervisor.ts @@ -1,6 +1,7 @@ import { atLeastVersion } from "../../common/config/version"; import { HomeAssistant, PanelInfo } from "../../types"; import { SupervisorArch } from "../supervisor/supervisor"; +import { HassioAddonInfo } from "./addon"; import { hassioApiResultExtractor, HassioResponse } from "./common"; export type HassioHomeAssistantInfo = { @@ -21,7 +22,7 @@ export type HassioHomeAssistantInfo = { }; export type HassioSupervisorInfo = { - addons: string[]; + addons: HassioAddonInfo[]; addons_repositories: string[]; arch: SupervisorArch; channel: string; diff --git a/src/data/history.ts b/src/data/history.ts index 0fb7a8857c..7de7651a75 100644 --- a/src/data/history.ts +++ b/src/data/history.ts @@ -223,12 +223,16 @@ export const fetchDate = ( hass: HomeAssistant, startTime: Date, endTime: Date, - entityIds: string[] + entityId?: string ): Promise => hass.callApi( "GET", `history/period/${startTime.toISOString()}?end_time=${endTime.toISOString()}&minimal_response${ - entityIds ? `&filter_entity_id=${entityIds.join(",")}` : `` + entityId ? `&filter_entity_id=${entityId}` : `` + }${ + entityId && !entityIdHistoryNeedsAttributes(hass, entityId) + ? `&no_attributes` + : `` }` ); @@ -236,19 +240,19 @@ export const fetchDateWS = ( hass: HomeAssistant, startTime: Date, endTime: Date, - entityIds: string[] + entityId?: string ) => { const params = { type: "history/history_during_period", start_time: startTime.toISOString(), end_time: endTime.toISOString(), minimal_response: true, - no_attributes: !entityIds - .map((entityId) => entityIdHistoryNeedsAttributes(hass, entityId)) - .reduce((cur, next) => cur || next, false), + no_attributes: !!( + entityId && !entityIdHistoryNeedsAttributes(hass, entityId) + ), }; - if (entityIds.length !== 0) { - return hass.callWS({ ...params, entity_ids: entityIds }); + if (entityId) { + return hass.callWS({ ...params, entity_ids: [entityId] }); } return hass.callWS(params); }; diff --git a/src/data/logbook.ts b/src/data/logbook.ts index 1b1f9ce980..eda3aa4ce6 100644 --- a/src/data/logbook.ts +++ b/src/data/logbook.ts @@ -1,4 +1,4 @@ -import { HassEntity } from "home-assistant-js-websocket"; +import { HassEntity, UnsubscribeFunc } from "home-assistant-js-websocket"; import { BINARY_STATE_OFF, BINARY_STATE_ON, @@ -6,14 +6,12 @@ import { } from "../common/const"; import { computeDomain } from "../common/entity/compute_domain"; import { computeStateDisplay } from "../common/entity/compute_state_display"; -import { computeStateDomain } from "../common/entity/compute_state_domain"; import { LocalizeFunc } from "../common/translations/localize"; -import { HaEntityPickerEntityFilterFunc } from "../components/entity/ha-entity-picker"; import { HomeAssistant } from "../types"; import { UNAVAILABLE_STATES } from "./entity"; const LOGBOOK_LOCALIZE_PATH = "ui.components.logbook.messages"; -export const CONTINUOUS_DOMAINS = ["counter", "proximity", "sensor"]; +export const CONTINUOUS_DOMAINS = ["proximity", "sensor"]; export interface LogbookStreamMessage { events: LogbookEntry[]; @@ -177,7 +175,7 @@ export const subscribeLogbook = ( endDate: string, entityIds?: string[], deviceIds?: string[] -): Promise<() => Promise> => { +): Promise => { // If all specified filters are empty lists, we can return an empty list. if ( (entityIds || deviceIds) && @@ -427,10 +425,3 @@ export const localizeStateMessage = ( : state ); }; - -export const filterLogbookCompatibleEntities: HaEntityPickerEntityFilterFunc = ( - entity -) => - computeStateDomain(entity) !== "sensor" || - (entity.attributes.unit_of_measurement === undefined && - entity.attributes.state_class === undefined); diff --git a/src/data/media-player.ts b/src/data/media-player.ts index a5c780f582..199cbbb386 100644 --- a/src/data/media-player.ts +++ b/src/data/media-player.ts @@ -36,7 +36,6 @@ import { supportsFeature } from "../common/entity/supports-feature"; import { MediaPlayerItemId } from "../components/media-player/ha-media-player-browse"; import type { HomeAssistant } from "../types"; import { UNAVAILABLE_STATES } from "./entity"; -import { isTTSMediaSource } from "./tts"; interface MediaPlayerEntityAttributes extends HassEntityAttributeBase { media_content_id?: string; @@ -442,29 +441,3 @@ export const handleMediaControlClick = ( entity_id: stateObj!.entity_id, } ); - -export const mediaPlayerPlayMedia = ( - hass: HomeAssistant, - entity_id: string, - media_content_id: string, - media_content_type: string, - extra: { - enqueue?: "play" | "next" | "add" | "replace"; - announce?: boolean; - } = {} -) => { - // We set text-to-speech to announce. - if ( - !extra.enqueue && - extra.announce === undefined && - isTTSMediaSource(media_content_id) - ) { - extra.announce = true; - } - return hass.callService("media_player", "play_media", { - entity_id, - media_content_id, - media_content_type, - ...extra, - }); -}; diff --git a/src/data/supervisor/common.ts b/src/data/supervisor/common.ts deleted file mode 100644 index b47f76bc4d..0000000000 --- a/src/data/supervisor/common.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { atLeastVersion } from "../../common/config/version"; -import { HomeAssistant } from "../../types"; -import { hassioApiResultExtractor, HassioResponse } from "../hassio/common"; - -export interface SupervisorApiCallOptions { - method?: "get" | "post" | "delete"; - data?: Record; - timeout?: number; -} - -export const supervisorApiCall = async ( - hass: HomeAssistant, - endpoint: string, - options?: SupervisorApiCallOptions -): Promise => { - if (atLeastVersion(hass.config.version, 2021, 2, 4)) { - // Websockets was added in 2021.2.4 - return hass.callWS({ - type: "supervisor/api", - endpoint, - method: options?.method || "get", - timeout: options?.timeout ?? null, - data: options?.data, - }); - } - return hassioApiResultExtractor( - await hass.callApi>( - // @ts-ignore - (options.method || "get").toUpperCase(), - `hassio${endpoint}`, - options?.data - ) - ); -}; diff --git a/src/data/supervisor/store.ts b/src/data/supervisor/store.ts index d71f96401c..e9e2fbe57f 100644 --- a/src/data/supervisor/store.ts +++ b/src/data/supervisor/store.ts @@ -1,7 +1,7 @@ +import { atLeastVersion } from "../../common/config/version"; import { HomeAssistant } from "../../types"; -import { AddonStage } from "../hassio/addon"; -import { supervisorApiCall } from "./common"; -import { SupervisorArch } from "./supervisor"; +import { AddonRepository, AddonStage } from "../hassio/addon"; +import { hassioApiResultExtractor, HassioResponse } from "../hassio/common"; export interface StoreAddon { advanced: boolean; @@ -13,34 +13,14 @@ export interface StoreAddon { installed: boolean; logo: boolean; name: string; - repository: string; + repository: AddonRepository; slug: string; stage: AddonStage; update_available: boolean; url: string; + version: string | null; version_latest: string; - version: null; } - -export interface StoreAddonDetails extends StoreAddon { - apparmor: boolean; - arch: SupervisorArch[]; - auth_api: boolean; - detached: boolean; - docker_api: boolean; - documentation: boolean; - full_access: boolean; - hassio_api: boolean; - hassio_role: string; - homeassistant_api: boolean; - host_network: boolean; - host_pid: boolean; - ingress: boolean; - long_description: string; - rating: number; - signed: boolean; -} - interface StoreRepository { maintainer: string; name: string; @@ -56,25 +36,16 @@ export interface SupervisorStore { export const fetchSupervisorStore = async ( hass: HomeAssistant -): Promise => supervisorApiCall(hass, "/store"); +): Promise => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + return hass.callWS({ + type: "supervisor/api", + endpoint: "/store", + method: "get", + }); + } -export const fetchStoreRepositories = async ( - hass: HomeAssistant -): Promise => supervisorApiCall(hass, "/store/repositories"); - -export const addStoreRepository = async ( - hass: HomeAssistant, - repository: string -): Promise => - supervisorApiCall(hass, "/store/repositories", { - method: "post", - data: { repository }, - }); - -export const removeStoreRepository = async ( - hass: HomeAssistant, - repository: string -): Promise => - supervisorApiCall(hass, `/store/repositories/${repository}`, { - method: "delete", - }); + return hassioApiResultExtractor( + await hass.callApi>("GET", `hassio/store`) + ); +}; diff --git a/src/data/translation.ts b/src/data/translation.ts index e7c632ea57..7374f40639 100644 --- a/src/data/translation.ts +++ b/src/data/translation.ts @@ -38,8 +38,7 @@ export type TranslationCategory = | "device_automation" | "mfa_setup" | "system_health" - | "device_class" - | "application_credentials"; + | "device_class"; export const fetchTranslationPreferences = (hass: HomeAssistant) => fetchFrontendUserData(hass.connection, "language"); diff --git a/src/data/weather.ts b/src/data/weather.ts index f77da5c9b0..3fb6dca152 100644 --- a/src/data/weather.ts +++ b/src/data/weather.ts @@ -37,24 +37,14 @@ interface ForecastAttribute { humidity?: number; condition?: string; daytime?: boolean; - pressure?: number; - wind_speed?: string; } interface WeatherEntityAttributes extends HassEntityAttributeBase { - attribution?: string; + temperature: number; humidity?: number; forecast?: ForecastAttribute[]; - pressure?: number; - temperature?: number; - visibility?: number; - wind_bearing?: number | string; - wind_speed?: number; - precipitation_unit: string; - pressure_unit: string; - temperature_unit: string; - visibility_unit: string; - wind_speed_unit: string; + wind_speed: string; + wind_bearing: string; } export interface WeatherEntity extends HassEntityBase { @@ -148,16 +138,16 @@ const cardinalDirections = [ "N", ]; -const getWindBearingText = (degree: number | string): string => { - const degreenum = typeof degree === "number" ? degree : parseInt(degree, 10); +const getWindBearingText = (degree: string): string => { + const degreenum = parseInt(degree, 10); if (isFinite(degreenum)) { // eslint-disable-next-line no-bitwise return cardinalDirections[(((degreenum + 11.25) / 22.5) | 0) % 16]; } - return typeof degree === "number" ? degree.toString() : degree; + return degree; }; -const getWindBearing = (bearing: number | string): string => { +const getWindBearing = (bearing: string): string => { if (bearing != null) { return getWindBearingText(bearing); } @@ -166,19 +156,14 @@ const getWindBearing = (bearing: number | string): string => { export const getWind = ( hass: HomeAssistant, - stateObj: WeatherEntity, - speed?: number, - bearing?: number | string + speed: string, + bearing: string ): string => { - const speedText = - speed !== undefined && speed !== null - ? `${formatNumber(speed, hass.locale)} ${getWeatherUnit( - hass!, - stateObj, - "wind_speed" - )}` - : "-"; - if (bearing !== undefined && bearing !== null) { + const speedText = `${formatNumber(speed, hass.locale)} ${getWeatherUnit( + hass!, + "wind_speed" + )}`; + if (bearing !== null) { const cardinalDirection = getWindBearing(bearing); return `${speedText} (${ hass.localize( @@ -191,28 +176,13 @@ export const getWind = ( export const getWeatherUnit = ( hass: HomeAssistant, - stateObj: WeatherEntity, measure: string ): string => { - const lengthUnit = hass.config.unit_system.length || ""; switch (measure) { case "visibility": - return stateObj.attributes.visibility_unit || lengthUnit; + return hass.config.unit_system.length || ""; case "precipitation": - return stateObj.attributes.precipitation_unit || lengthUnit === "km" - ? "mm" - : "in"; - case "pressure": - return stateObj.attributes.pressure_unit || lengthUnit === "km" - ? "hPa" - : "inHg"; - case "temperature": - return ( - stateObj.attributes.temperature_unit || - hass.config.unit_system.temperature - ); - case "wind_speed": - return stateObj.attributes.wind_speed_unit || `${lengthUnit}/h`; + return hass.config.unit_system.accumulated_precipitation || ""; case "humidity": case "precipitation_probability": return "%"; @@ -257,7 +227,7 @@ export const getSecondaryWeatherAttribute = ( ` : hass!.localize(`ui.card.weather.attributes.${attribute}`)} ${formatNumber(value, hass.locale, { maximumFractionDigits: 1 })} - ${getWeatherUnit(hass!, stateObj, attribute)} + ${getWeatherUnit(hass!, attribute)} `; }; @@ -292,7 +262,7 @@ const getWeatherExtrema = ( return undefined; } - const unit = getWeatherUnit(hass!, stateObj, "temperature"); + const unit = getWeatherUnit(hass!, "temperature"); return html` ${tempHigh ? `${formatNumber(tempHigh, hass.locale)} ${unit}` : ""} diff --git a/src/data/zwave_js.ts b/src/data/zwave_js.ts index a99244541d..11bcefa4cb 100644 --- a/src/data/zwave_js.ts +++ b/src/data/zwave_js.ts @@ -1,5 +1,6 @@ import { UnsubscribeFunc } from "home-assistant-js-websocket"; import { HomeAssistant } from "../types"; +import { DeviceRegistryEntry } from "./device_registry"; export enum InclusionState { /** The controller isn't doing anything regarding inclusion. */ @@ -84,23 +85,6 @@ enum Protocols { ZWave = 0, ZWaveLongRange = 1, } - -export enum FirmwareUpdateStatus { - Error_Timeout = -1, - Error_Checksum = 0, - Error_TransmissionFailed = 1, - Error_InvalidManufacturerID = 2, - Error_InvalidFirmwareID = 3, - Error_InvalidFirmwareTarget = 4, - Error_InvalidHeaderInformation = 5, - Error_InvalidHeaderFormat = 6, - Error_InsufficientMemory = 7, - Error_InvalidHardwareVersion = 8, - OK_WaitingForActivation = 0xfd, - OK_NoRestart = 0xfe, - OK_RestartPending = 0xff, -} - export interface QRProvisioningInformation { version: QRCodeVersion; securityClasses: SecurityClass[]; @@ -125,6 +109,10 @@ export interface PlannedProvisioningEntry { export const MINIMUM_QR_STRING_LENGTH = 52; +export interface ZWaveJSNodeIdentifiers { + home_id: string; + node_id: number; +} export interface ZWaveJSNetwork { client: ZWaveJSClient; controller: ZWaveJSController; @@ -163,7 +151,7 @@ export interface ZWaveJSController { export interface ZWaveJSNodeStatus { node_id: number; ready: boolean; - status: NodeStatus; + status: number; is_secure: boolean | string; is_routing: boolean | null; zwave_plus_version: number | null; @@ -256,68 +244,6 @@ export interface ZWaveJSControllerStatisticsUpdatedMessage { timeout_callback: number; } -export enum RssiError { - NotAvailable = 127, - ReceiverSaturated = 126, - NoSignalDetected = 125, -} - -export enum ProtocolDataRate { - ZWave_9k6 = 0x01, - ZWave_40k = 0x02, - ZWave_100k = 0x03, - LongRange_100k = 0x04, -} - -export interface ZWaveJSNodeStatisticsUpdatedMessage { - event: "statistics updated"; - source: "node"; - commands_tx: number; - commands_rx: number; - commands_dropped_tx: number; - commands_dropped_rx: number; - timeout_response: number; - rtt: number | null; - rssi: RssiError | number | null; - lwr: ZWaveJSRouteStatistics | null; - nlwr: ZWaveJSRouteStatistics | null; -} - -export interface ZWaveJSRouteStatistics { - protocol_data_rate: number; - repeaters: string[]; - rssi: RssiError | number | null; - repeater_rssi: (RssiError | number)[]; - route_failed_between: [string, string] | null; -} - -export interface ZWaveJSNodeStatusUpdatedMessage { - event: "ready" | "wake up" | "sleep" | "dead" | "alive"; - ready: boolean; - status: NodeStatus; -} - -export interface ZWaveJSNodeFirmwareUpdateProgressMessage { - event: "firmware update progress"; - sent_fragments: number; - total_fragments: number; -} - -export interface ZWaveJSNodeFirmwareUpdateFinishedMessage { - event: "firmware update finished"; - status: FirmwareUpdateStatus; - wait_time: number; -} - -export type ZWaveJSNodeFirmwareUpdateCapabilities = - | { firmware_upgradable: false } - | { - firmware_upgradable: true; - firmware_targets: number[]; - continues_to_function: boolean | null; - supports_activation: boolean | null; - }; - export interface ZWaveJSRemovedNode { node_id: number; manufacturer: string; @@ -354,6 +280,25 @@ export interface RequestedGrant { export const nodeStatus = ["unknown", "asleep", "awake", "dead", "alive"]; +export interface ZWaveJsMigrationData { + migration_device_map: Record; + zwave_entity_ids: string[]; + zwave_js_entity_ids: string[]; + migration_entity_map: Record; + migrated: boolean; +} + +export const migrateZwave = ( + hass: HomeAssistant, + entry_id: string, + dry_run = true +): Promise => + hass.callWS({ + type: "zwave_js/migrate_zwave", + entry_id, + dry_run, + }); + export const fetchZwaveNetworkStatus = ( hass: HomeAssistant, device_or_entry_id: { @@ -516,19 +461,6 @@ export const fetchZwaveNodeStatus = ( device_id, }); -export const subscribeZwaveNodeStatus = ( - hass: HomeAssistant, - device_id: string, - callbackFunction: (message: ZWaveJSNodeStatusUpdatedMessage) => void -): Promise => - hass.connection.subscribeMessage( - (message: any) => callbackFunction(message), - { - type: "zwave_js/subscribe_node_status", - device_id, - } - ); - export const fetchZwaveNodeMetadata = ( hass: HomeAssistant, device_id: string @@ -626,6 +558,19 @@ export const stopHealZwaveNetwork = ( entry_id, }); +export const subscribeZwaveNodeReady = ( + hass: HomeAssistant, + device_id: string, + callbackFunction: (message) => void +): Promise => + hass.connection.subscribeMessage( + (message: any) => callbackFunction(message), + { + type: "zwave_js/node_ready", + device_id, + } + ); + export const subscribeHealZwaveNetworkProgress = ( hass: HomeAssistant, entry_id: string, @@ -652,96 +597,27 @@ export const subscribeZwaveControllerStatistics = ( } ); -export const subscribeZwaveNodeStatistics = ( - hass: HomeAssistant, - device_id: string, - callbackFunction: (message: ZWaveJSNodeStatisticsUpdatedMessage) => void -): Promise => - hass.connection.subscribeMessage( - (message: any) => callbackFunction(message), - { - type: "zwave_js/subscribe_node_statistics", - device_id, - } - ); - -export const fetchZwaveNodeIsFirmwareUpdateInProgress = ( - hass: HomeAssistant, - device_id: string -): Promise => - hass.callWS({ - type: "zwave_js/get_firmware_update_progress", - device_id, - }); - -export const fetchZwaveIsAnyFirmwareUpdateInProgress = ( - hass: HomeAssistant, - entry_id: string -): Promise => - hass.callWS({ - type: "zwave_js/get_any_firmware_update_progress", - entry_id, - }); - -export const fetchZwaveNodeFirmwareUpdateCapabilities = ( - hass: HomeAssistant, - device_id: string -): Promise => - hass.callWS({ - type: "zwave_js/get_firmware_update_capabilities", - device_id, - }); - -export const uploadFirmwareAndBeginUpdate = async ( - hass: HomeAssistant, - device_id: string, - file: File, - target?: number -) => { - const fd = new FormData(); - fd.append("file", file); - if (target !== undefined) { - fd.append("target", target.toString()); +export const getZwaveJsIdentifiersFromDevice = ( + device: DeviceRegistryEntry +): ZWaveJSNodeIdentifiers | undefined => { + if (!device) { + return undefined; } - const resp = await hass.fetchWithAuth( - `/api/zwave_js/firmware/upload/${device_id}`, - { - method: "POST", - body: fd, - } - ); - if (resp.status !== 200) { - throw new Error(resp.statusText); + const zwaveJSIdentifier = device.identifiers.find( + (identifier) => identifier[0] === "zwave_js" + ); + if (!zwaveJSIdentifier) { + return undefined; } + + const identifiers = zwaveJSIdentifier[1].split("-"); + return { + node_id: parseInt(identifiers[1]), + home_id: identifiers[0], + }; }; -export const subscribeZwaveNodeFirmwareUpdate = ( - hass: HomeAssistant, - device_id: string, - callbackFunction: ( - message: - | ZWaveJSNodeFirmwareUpdateFinishedMessage - | ZWaveJSNodeFirmwareUpdateProgressMessage - ) => void -): Promise => - hass.connection.subscribeMessage( - (message: any) => callbackFunction(message), - { - type: "zwave_js/subscribe_firmware_update_status", - device_id, - } - ); - -export const abortZwaveNodeFirmwareUpdate = ( - hass: HomeAssistant, - device_id: string -): Promise => - hass.callWS({ - type: "zwave_js/abort_firmware_update", - device_id, - }); - export type ZWaveJSLogUpdate = ZWaveJSLogMessageUpdate | ZWaveJSLogConfigUpdate; interface ZWaveJSLogMessageUpdate { diff --git a/src/dialogs/domain-toggler/dialog-domain-toggler.ts b/src/dialogs/domain-toggler/dialog-domain-toggler.ts index fd66cf2940..caff99cf37 100644 --- a/src/dialogs/domain-toggler/dialog-domain-toggler.ts +++ b/src/dialogs/domain-toggler/dialog-domain-toggler.ts @@ -47,14 +47,10 @@ class DomainTogglerDialog hideActions .heading=${createCloseHeading( this.hass, - this._params.title || - this.hass.localize("ui.dialogs.domain_toggler.title") + this.hass.localize("ui.dialogs.domain_toggler.title") )} > - ${this._params.description - ? html`
${this._params.description}
` - : ""} -
+
${domains.map( (domain) => html` @@ -96,10 +92,7 @@ class DomainTogglerDialog ha-dialog { --mdc-dialog-max-width: 500px; } - .description { - margin-bottom: 8px; - } - .domains { + div { display: grid; grid-template-columns: auto auto; grid-row-gap: 8px; diff --git a/src/dialogs/domain-toggler/show-dialog-domain-toggler.ts b/src/dialogs/domain-toggler/show-dialog-domain-toggler.ts index 18426ba68e..702e0e3848 100644 --- a/src/dialogs/domain-toggler/show-dialog-domain-toggler.ts +++ b/src/dialogs/domain-toggler/show-dialog-domain-toggler.ts @@ -1,8 +1,6 @@ import { fireEvent } from "../../common/dom/fire_event"; export interface HaDomainTogglerDialogParams { - title?: string; - description?: string; domains: string[]; exposedDomains: string[] | null; toggleDomain: (domain: string, turnOn: boolean) => void; diff --git a/src/dialogs/generic/dialog-box.ts b/src/dialogs/generic/dialog-box.ts index fdf2107756..4cdb0ef6c9 100644 --- a/src/dialogs/generic/dialog-box.ts +++ b/src/dialogs/generic/dialog-box.ts @@ -8,6 +8,7 @@ import "../../components/ha-dialog"; import "../../components/ha-svg-icon"; import "../../components/ha-switch"; import { HaTextField } from "../../components/ha-textfield"; +import { haStyleDialog } from "../../resources/styles"; import { HomeAssistant } from "../../types"; import { DialogBoxParams } from "./show-dialog-box"; @@ -134,34 +135,34 @@ class DialogBox extends LitElement { } static get styles(): CSSResultGroup { - return css` - :host([inert]) { - pointer-events: initial !important; - cursor: initial !important; - } - a { - color: var(--primary-color); - } - p { - margin: 0; - padding-top: 6px; - padding-bottom: 24px; - color: var(--primary-text-color); - } - .no-bottom-padding { - padding-bottom: 0; - } - .secondary { - color: var(--secondary-text-color); - } - ha-dialog { - --mdc-dialog-heading-ink-color: var(--primary-text-color); - --mdc-dialog-content-ink-color: var(--primary-text-color); - --justify-action-buttons: space-between; - /* Place above other dialogs */ - --dialog-z-index: 104; - } - `; + return [ + haStyleDialog, + css` + :host([inert]) { + pointer-events: initial !important; + cursor: initial !important; + } + a { + color: var(--primary-color); + } + p { + margin: 0; + padding-top: 6px; + padding-bottom: 24px; + color: var(--primary-text-color); + } + .no-bottom-padding { + padding-bottom: 0; + } + .secondary { + color: var(--secondary-text-color); + } + ha-dialog { + /* Place above other dialogs */ + --dialog-z-index: 104; + } + `, + ]; } } diff --git a/src/dialogs/more-info/controls/more-info-alarm_control_panel.ts b/src/dialogs/more-info/controls/more-info-alarm_control_panel.ts index 0fb7401959..de41f1c173 100644 --- a/src/dialogs/more-info/controls/more-info-alarm_control_panel.ts +++ b/src/dialogs/more-info/controls/more-info-alarm_control_panel.ts @@ -37,7 +37,7 @@ export class MoreInfoAlarmControlPanel extends LitElement { id="alarmCode" .label=${this.hass.localize("ui.card.alarm_control_panel.code")} type="password" - .inputMode=${this.stateObj.attributes.code_format === + .inputmode=${this.stateObj.attributes.code_format === FORMAT_NUMBER ? "numeric" : "text"} diff --git a/src/dialogs/more-info/controls/more-info-media_player.ts b/src/dialogs/more-info/controls/more-info-media_player.ts index eb725e4bde..7989c384d8 100644 --- a/src/dialogs/more-info/controls/more-info-media_player.ts +++ b/src/dialogs/more-info/controls/more-info-media_player.ts @@ -11,6 +11,7 @@ import { } from "@mdi/js"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property } from "lit/decorators"; +import { isComponentLoaded } from "../../../common/config/is_component_loaded"; import { stopPropagation } from "../../../common/dom/stop_propagation"; import { supportsFeature } from "../../../common/entity/supports-feature"; import { computeRTLDirection } from "../../../common/util/compute_rtl"; @@ -25,8 +26,8 @@ import { handleMediaControlClick, MediaPickedEvent, MediaPlayerEntity, - mediaPlayerPlayMedia, SUPPORT_BROWSE_MEDIA, + SUPPORT_PLAY_MEDIA, SUPPORT_SELECT_SOUND_MODE, SUPPORT_SELECT_SOURCE, SUPPORT_VOLUME_BUTTONS, @@ -190,6 +191,14 @@ class MoreInfoMediaPlayer extends LitElement {
` : ""} + ${isComponentLoaded(this.hass, "tts") && + supportsFeature(stateObj, SUPPORT_PLAY_MEDIA) + ? html` +
+ Text to speech has moved to the media browser. +
+ ` + : ""} `; } @@ -296,14 +305,20 @@ class MoreInfoMediaPlayer extends LitElement { action: "play", entityId: this.stateObj!.entity_id, mediaPickedCallback: (pickedMedia: MediaPickedEvent) => - mediaPlayerPlayMedia( - this.hass, - this.stateObj!.entity_id, + this._playMedia( pickedMedia.item.media_content_id, pickedMedia.item.media_content_type ), }); } + + private _playMedia(media_content_id: string, media_content_type: string) { + this.hass!.callService("media_player", "play_media", { + entity_id: this.stateObj!.entity_id, + media_content_id, + media_content_type, + }); + } } declare global { diff --git a/src/dialogs/more-info/controls/more-info-weather.ts b/src/dialogs/more-info/controls/more-info-weather.ts index a680dbd754..e93e9cbfe8 100644 --- a/src/dialogs/more-info/controls/more-info-weather.ts +++ b/src/dialogs/more-info/controls/more-info-weather.ts @@ -5,6 +5,7 @@ import { mdiWaterPercent, mdiWeatherWindy, } from "@mdi/js"; +import { HassEntity } from "home-assistant-js-websocket"; import { css, CSSResultGroup, @@ -22,7 +23,6 @@ import { getWeatherUnit, getWind, isForecastHourly, - WeatherEntity, weatherIcons, } from "../../../data/weather"; import { HomeAssistant } from "../../../types"; @@ -31,7 +31,7 @@ import { HomeAssistant } from "../../../types"; class MoreInfoWeather extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @property() public stateObj?: WeatherEntity; + @property() public stateObj?: HassEntity; protected shouldUpdate(changedProps: PropertyValues): boolean { if (changedProps.has("stateObj")) { @@ -58,23 +58,19 @@ class MoreInfoWeather extends LitElement { const hourly = isForecastHourly(this.stateObj.attributes.forecast); return html` - ${this._showValue(this.stateObj.attributes.temperature) - ? html` -
- -
- ${this.hass.localize("ui.card.weather.attributes.temperature")} -
-
- ${formatNumber( - this.stateObj.attributes.temperature!, - this.hass.locale - )} - ${getWeatherUnit(this.hass, this.stateObj, "temperature")} -
-
- ` - : ""} +
+ +
+ ${this.hass.localize("ui.card.weather.attributes.temperature")} +
+
+ ${formatNumber( + this.stateObj.attributes.temperature, + this.hass.locale + )} + ${getWeatherUnit(this.hass, "temperature")} +
+
${this._showValue(this.stateObj.attributes.pressure) ? html`
@@ -84,10 +80,10 @@ class MoreInfoWeather extends LitElement {
${formatNumber( - this.stateObj.attributes.pressure!, + this.stateObj.attributes.pressure, this.hass.locale )} - ${getWeatherUnit(this.hass, this.stateObj, "pressure")} + ${getWeatherUnit(this.hass, "pressure")}
` @@ -101,7 +97,7 @@ class MoreInfoWeather extends LitElement {
${formatNumber( - this.stateObj.attributes.humidity!, + this.stateObj.attributes.humidity, this.hass.locale )} % @@ -119,8 +115,7 @@ class MoreInfoWeather extends LitElement {
${getWind( this.hass, - this.stateObj, - this.stateObj.attributes.wind_speed!, + this.stateObj.attributes.wind_speed, this.stateObj.attributes.wind_bearing )}
@@ -136,10 +131,10 @@ class MoreInfoWeather extends LitElement {
${formatNumber( - this.stateObj.attributes.visibility!, + this.stateObj.attributes.visibility, this.hass.locale )} - ${getWeatherUnit(this.hass, this.stateObj, "visibility")} + ${getWeatherUnit(this.hass, "length")}
` @@ -178,24 +173,16 @@ class MoreInfoWeather extends LitElement { `}
${this._showValue(item.templow) - ? `${formatNumber(item.templow!, this.hass.locale)} - ${getWeatherUnit( - this.hass, - this.stateObj!, - "temperature" - )}` + ? `${formatNumber(item.templow, this.hass.locale)} + ${getWeatherUnit(this.hass, "temperature")}` : hourly ? "" : "—"}
${this._showValue(item.temperature) - ? `${formatNumber(item.temperature!, this.hass.locale)} - ${getWeatherUnit( - this.hass, - this.stateObj!, - "temperature" - )}` + ? `${formatNumber(item.temperature, this.hass.locale)} + ${getWeatherUnit(this.hass, "temperature")}` : "—"}
` @@ -253,7 +240,7 @@ class MoreInfoWeather extends LitElement { `; } - private _showValue(item: number | string | undefined): boolean { + private _showValue(item: string): boolean { return typeof item !== "undefined" && item !== null; } } diff --git a/src/dialogs/quick-bar/ha-quick-bar.ts b/src/dialogs/quick-bar/ha-quick-bar.ts index ee987044ab..c87ef4244b 100644 --- a/src/dialogs/quick-bar/ha-quick-bar.ts +++ b/src/dialogs/quick-bar/ha-quick-bar.ts @@ -34,7 +34,7 @@ import "../../components/ha-circular-progress"; import "../../components/ha-header-bar"; import "../../components/ha-icon-button"; import "../../components/ha-textfield"; -import { fetchHassioAddonsInfo } from "../../data/hassio/addon"; +import { fetchHassioSupervisorInfo } from "../../data/hassio/supervisor"; import { domainToName } from "../../data/integration"; import { getPanelNameTranslationKey } from "../../data/panel"; import { PageNavigation } from "../../layouts/hass-tabs-subpage"; @@ -586,7 +586,7 @@ export class QuickBar extends LitElement { const sectionItems = this._generateNavigationConfigSectionCommands(); const supervisorItems: BaseNavigationCommand[] = []; if (isComponentLoaded(this.hass, "hassio")) { - const addonsInfo = await fetchHassioAddonsInfo(this.hass); + const supervisorInfo = await fetchHassioSupervisorInfo(this.hass); supervisorItems.push({ path: "/hassio/store", primaryText: this.hass.localize( @@ -599,7 +599,7 @@ export class QuickBar extends LitElement { "ui.dialogs.quick-bar.commands.navigation.addon_dashboard" ), }); - for (const addon of addonsInfo.addons.filter((a) => a.version)) { + for (const addon of supervisorInfo.addons) { supervisorItems.push({ path: `/hassio/addon/${addon.slug}`, primaryText: this.hass.localize( @@ -803,9 +803,6 @@ export class QuickBar extends LitElement { span.command-text { margin-left: 8px; - margin-inline-start: 8px; - margin-inline-end: initial; - direction: var(--direction); } mwc-list-item { diff --git a/src/fake_data/provide_hass.ts b/src/fake_data/provide_hass.ts index e71667675e..3fd29bcdbf 100644 --- a/src/fake_data/provide_hass.ts +++ b/src/fake_data/provide_hass.ts @@ -194,7 +194,6 @@ export const provideHass = ( socket: { readyState: WebSocket.OPEN, }, - haVersion: "DEMO", } as any, connected: true, states: {}, diff --git a/src/panels/config/application_credentials/dialog-add-application-credential.ts b/src/panels/config/application_credentials/dialog-add-application-credential.ts index 542fe41c0b..516b762806 100644 --- a/src/panels/config/application_credentials/dialog-add-application-credential.ts +++ b/src/panels/config/application_credentials/dialog-add-application-credential.ts @@ -7,12 +7,10 @@ import { fireEvent } from "../../../common/dom/fire_event"; import "../../../components/ha-circular-progress"; import "../../../components/ha-combo-box"; import { createCloseHeading } from "../../../components/ha-dialog"; -import "../../../components/ha-markdown"; import "../../../components/ha-textfield"; import { fetchApplicationCredentialsConfig, createApplicationCredential, - ApplicationCredentialsConfig, ApplicationCredential, } from "../../../data/application_credential"; import { domainToName } from "../../../data/integration"; @@ -44,22 +42,17 @@ export class DialogAddApplicationCredential extends LitElement { @state() private _name?: string; - @state() private _description?: string; - @state() private _clientId?: string; @state() private _clientSecret?: string; @state() private _domains?: Domain[]; - @state() private _config?: ApplicationCredentialsConfig; - public showDialog(params: AddApplicationCredentialDialogParams) { this._params = params; this._domain = params.selectedDomain !== undefined ? params.selectedDomain : ""; this._name = ""; - this._description = ""; this._clientId = ""; this._clientSecret = ""; this._error = undefined; @@ -68,15 +61,11 @@ export class DialogAddApplicationCredential extends LitElement { } private async _fetchConfig() { - this._config = await fetchApplicationCredentialsConfig(this.hass); - this._domains = Object.keys(this._config.integrations).map((domain) => ({ + const config = await fetchApplicationCredentialsConfig(this.hass); + this._domains = config.domains.map((domain) => ({ id: domain, name: domainToName(this.hass.localize, domain), })); - await this.hass.loadBackendTranslation("application_credentials"); - if (this._domain !== "") { - this._updateDescription(); - } } protected render(): TemplateResult { @@ -114,12 +103,6 @@ export class DialogAddApplicationCredential extends LitElement { required @value-changed=${this._handleDomainPicked} > - ${this._description - ? html`` - : ""} ${this.hass!.localize( - "ui.panel.config.cloud.alexa.manage_defaults" + "ui.panel.config.cloud.alexa.manage_domains" )} ` @@ -402,10 +402,6 @@ class CloudAlexa extends SubscribeMixin(LitElement) { private _openDomainToggler() { showDomainTogglerDialog(this, { - title: this.hass!.localize("ui.panel.config.cloud.alexa.manage_defaults"), - description: this.hass!.localize( - "ui.panel.config.cloud.alexa.manage_defaults_dialog_description" - ), domains: this._entities!.map((entity) => computeDomain(entity.entity_id) ).filter((value, idx, self) => self.indexOf(value) === idx), diff --git a/src/panels/config/cloud/google-assistant/cloud-google-assistant.ts b/src/panels/config/cloud/google-assistant/cloud-google-assistant.ts index f177094f8a..f48fb570e4 100644 --- a/src/panels/config/cloud/google-assistant/cloud-google-assistant.ts +++ b/src/panels/config/cloud/google-assistant/cloud-google-assistant.ts @@ -256,7 +256,7 @@ class CloudGoogleAssistant extends SubscribeMixin(LitElement) { slot="toolbar-icon" @click=${this._openDomainToggler} >${this.hass!.localize( - "ui.panel.config.cloud.google.manage_defaults" + "ui.panel.config.cloud.google.manage_domains" )} ` @@ -442,12 +442,6 @@ class CloudGoogleAssistant extends SubscribeMixin(LitElement) { private _openDomainToggler() { showDomainTogglerDialog(this, { - title: this.hass!.localize( - "ui.panel.config.cloud.google.manage_defaults" - ), - description: this.hass!.localize( - "ui.panel.config.cloud.google.manage_defaults_dialog_description" - ), domains: this._entities!.map((entity) => computeDomain(entity.entity_id) ).filter((value, idx, self) => self.indexOf(value) === idx), diff --git a/src/panels/config/core/ha-config-section-general.ts b/src/panels/config/core/ha-config-section-general.ts index a2123ddf24..2f9588e8ad 100644 --- a/src/panels/config/core/ha-config-section-general.ts +++ b/src/panels/config/core/ha-config-section-general.ts @@ -273,15 +273,6 @@ class HaConfigSectionGeneral extends LitElement { } button.progress = true; - let locationConfig; - - if (this._location) { - locationConfig = { - latitude: this._location[0], - longitude: this._location[1], - }; - } - try { await saveCoreConfig(this.hass, { currency: this._currency, @@ -289,7 +280,6 @@ class HaConfigSectionGeneral extends LitElement { unit_system: this._unitSystem, time_zone: this._timeZone, location_name: this._name, - ...locationConfig, }); button.actionSuccess(); } catch (err: any) { diff --git a/src/panels/config/core/ha-config-system-navigation.ts b/src/panels/config/core/ha-config-system-navigation.ts index 210e9b3bf3..e8a9584326 100644 --- a/src/panels/config/core/ha-config-system-navigation.ts +++ b/src/panels/config/core/ha-config-system-navigation.ts @@ -139,6 +139,12 @@ class HaConfigSystemNavigation extends LitElement { hasSecondary > + ${this.hass.userData?.showAdvanced + ? html` + Looking for YAML Configuration? It has moved to + Developer Tools + ` + : ""} `; diff --git a/src/panels/config/dashboard/ha-config-updates.ts b/src/panels/config/dashboard/ha-config-updates.ts index a24bce31e2..dcb02c4de4 100644 --- a/src/panels/config/dashboard/ha-config-updates.ts +++ b/src/panels/config/dashboard/ha-config-updates.ts @@ -1,5 +1,6 @@ import "@material/mwc-button/mwc-button"; import "@material/mwc-list/mwc-list"; +import "@material/mwc-list/mwc-list-item"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../../common/dom/fire_event"; @@ -9,7 +10,6 @@ import "../../../components/ha-icon-next"; import type { UpdateEntity } from "../../../data/update"; import type { HomeAssistant } from "../../../types"; import "../../../components/ha-circular-progress"; -import "../../../components/ha-list-item"; @customElement("ha-config-updates") class HaConfigUpdates extends LitElement { @@ -39,7 +39,7 @@ class HaConfigUpdates extends LitElement { ${updates.map( (entity) => html` - ` : html`` : ""} - + ` )} @@ -135,7 +135,7 @@ class HaConfigUpdates extends LitElement { outline: none; text-decoration: underline; } - ha-list-item { + mwc-list-item { cursor: pointer; font-size: 16px; } diff --git a/src/panels/config/devices/device-detail/integration-elements/zwave_js/device-actions.ts b/src/panels/config/devices/device-detail/integration-elements/zwave_js/device-actions.ts index d0843bc2ac..004a2a6c95 100644 --- a/src/panels/config/devices/device-detail/integration-elements/zwave_js/device-actions.ts +++ b/src/panels/config/devices/device-detail/integration-elements/zwave_js/device-actions.ts @@ -1,18 +1,10 @@ import { getConfigEntries } from "../../../../../../data/config_entries"; import { DeviceRegistryEntry } from "../../../../../../data/device_registry"; -import { - fetchZwaveIsAnyFirmwareUpdateInProgress, - fetchZwaveNodeFirmwareUpdateCapabilities, - fetchZwaveNodeIsFirmwareUpdateInProgress, - fetchZwaveNodeStatus, -} from "../../../../../../data/zwave_js"; -import { showConfirmationDialog } from "../../../../../../dialogs/generic/show-dialog-box"; +import { fetchZwaveNodeStatus } from "../../../../../../data/zwave_js"; import type { HomeAssistant } from "../../../../../../types"; import { showZWaveJSHealNodeDialog } from "../../../../integrations/integration-panels/zwave_js/show-dialog-zwave_js-heal-node"; -import { showZWaveJSNodeStatisticsDialog } from "../../../../integrations/integration-panels/zwave_js/show-dialog-zwave_js-node-statistics"; import { showZWaveJSReinterviewNodeDialog } from "../../../../integrations/integration-panels/zwave_js/show-dialog-zwave_js-reinterview-node"; import { showZWaveJSRemoveFailedNodeDialog } from "../../../../integrations/integration-panels/zwave_js/show-dialog-zwave_js-remove-failed-node"; -import { showZWaveJUpdateFirmwareNodeDialog } from "../../../../integrations/integration-panels/zwave_js/show-dialog-zwave_js-update-firmware-node"; import type { DeviceAction } from "../../../ha-config-device-page"; export const getZwaveDeviceActions = async ( @@ -34,13 +26,13 @@ export const getZwaveDeviceActions = async ( const entryId = configEntry.entry_id; - const nodeStatus = await fetchZwaveNodeStatus(hass, device.id); + const node = await fetchZwaveNodeStatus(hass, device.id); - if (!nodeStatus || nodeStatus.is_controller_node) { + if (!node || node.is_controller_node) { return []; } - const actions = [ + return [ { label: hass.localize( "ui.panel.config.zwave_js.device_info.device_config" @@ -60,7 +52,7 @@ export const getZwaveDeviceActions = async ( label: hass.localize("ui.panel.config.zwave_js.device_info.heal_node"), action: () => showZWaveJSHealNodeDialog(el, { - device, + device: device, }), }, { @@ -72,57 +64,5 @@ export const getZwaveDeviceActions = async ( device_id: device.id, }), }, - { - label: hass.localize( - "ui.panel.config.zwave_js.device_info.node_statistics" - ), - action: () => - showZWaveJSNodeStatisticsDialog(el, { - device, - }), - }, ]; - - if (!nodeStatus.ready) { - return actions; - } - - const [ - firmwareUpdateCapabilities, - isAnyFirmwareUpdateInProgress, - isNodeFirmwareUpdateInProgress, - ] = await Promise.all([ - fetchZwaveNodeFirmwareUpdateCapabilities(hass, device.id), - fetchZwaveIsAnyFirmwareUpdateInProgress(hass, entryId), - fetchZwaveNodeIsFirmwareUpdateInProgress(hass, device.id), - ]); - - if ( - firmwareUpdateCapabilities.firmware_upgradable && - (!isAnyFirmwareUpdateInProgress || isNodeFirmwareUpdateInProgress) - ) { - actions.push({ - label: hass.localize( - "ui.panel.config.zwave_js.device_info.update_firmware" - ), - action: async () => { - if ( - await showConfirmationDialog(el, { - text: hass.localize( - "ui.panel.config.zwave_js.update_firmware.warning" - ), - dismissText: hass.localize("ui.common.no"), - confirmText: hass.localize("ui.common.yes"), - }) - ) { - showZWaveJUpdateFirmwareNodeDialog(el, { - device, - firmwareUpdateCapabilities, - }); - } - }, - }); - } - - return actions; }; diff --git a/src/panels/config/devices/device-detail/integration-elements/zwave_js/ha-device-info-zwave_js.ts b/src/panels/config/devices/device-detail/integration-elements/zwave_js/ha-device-info-zwave_js.ts index 637b895d62..eae6b47a1b 100644 --- a/src/panels/config/devices/device-detail/integration-elements/zwave_js/ha-device-info-zwave_js.ts +++ b/src/panels/config/devices/device-detail/integration-elements/zwave_js/ha-device-info-zwave_js.ts @@ -8,7 +8,6 @@ import { } from "lit"; import { customElement, property, state } from "lit/decorators"; import "../../../../../../components/ha-expansion-panel"; -import { UnsubscribeFunc } from "home-assistant-js-websocket"; import { ConfigEntry, getConfigEntries, @@ -18,15 +17,13 @@ import { fetchZwaveNodeStatus, nodeStatus, SecurityClass, - subscribeZwaveNodeStatus, ZWaveJSNodeStatus, } from "../../../../../../data/zwave_js"; import { haStyle } from "../../../../../../resources/styles"; import { HomeAssistant } from "../../../../../../types"; -import { SubscribeMixin } from "../../../../../../mixins/subscribe-mixin"; @customElement("ha-device-info-zwave_js") -export class HaDeviceInfoZWaveJS extends SubscribeMixin(LitElement) { +export class HaDeviceInfoZWaveJS extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @property({ attribute: false }) public device!: DeviceRegistryEntry; @@ -44,21 +41,6 @@ export class HaDeviceInfoZWaveJS extends SubscribeMixin(LitElement) { } } - public hassSubscribe(): Array> { - return [ - subscribeZwaveNodeStatus(this.hass, this.device!.id, (message) => { - if (!this._node) { - return; - } - this._node = { - ...this._node, - status: message.status, - ready: message.ready, - }; - }), - ]; - } - protected async _fetchNodeDetails() { if (!this.device) { return; diff --git a/src/panels/config/devices/device-registry-detail/dialog-device-registry-detail.ts b/src/panels/config/devices/device-registry-detail/dialog-device-registry-detail.ts index 662e8f3ca9..cb287db2a1 100644 --- a/src/panels/config/devices/device-registry-detail/dialog-device-registry-detail.ts +++ b/src/panels/config/devices/device-registry-detail/dialog-device-registry-detail.ts @@ -181,9 +181,6 @@ class DialogDeviceRegistryDetail extends LitElement { } ha-switch { margin-right: 16px; - margin-inline-end: 16px; - margin-inline-start: initial; - direction: var(--direction); } .row { margin-top: 8px; diff --git a/src/panels/config/devices/ha-config-device-page.ts b/src/panels/config/devices/ha-config-device-page.ts index a91b6eb9d2..e5cb27109d 100644 --- a/src/panels/config/devices/ha-config-device-page.ts +++ b/src/panels/config/devices/ha-config-device-page.ts @@ -1265,11 +1265,8 @@ export class HaConfigDevicePage extends LitElement { .card-header ha-icon-button { margin-right: -8px; - margin-inline-end: -8px; - margin-inline-start: initial; color: var(--primary-color); height: auto; - direction: var(--direction); } .device-info { @@ -1335,9 +1332,6 @@ export class HaConfigDevicePage extends LitElement { .header-right > *:not(:first-child) { margin-left: 16px; - margin-inline-start: 16px; - margin-inline-end: initial; - direction: var(--direction); } .battery { diff --git a/src/panels/config/entities/entity-registry-settings.ts b/src/panels/config/entities/entity-registry-settings.ts index 799d221004..3750446e0a 100644 --- a/src/panels/config/entities/entity-registry-settings.ts +++ b/src/panels/config/entities/entity-registry-settings.ts @@ -110,14 +110,6 @@ const OVERRIDE_SENSOR_UNITS = { pressure: ["hPa", "Pa", "kPa", "bar", "cbar", "mbar", "mmHg", "inHg", "psi"], }; -const OVERRIDE_WEATHER_UNITS = { - precipitation: ["mm", "in"], - pressure: ["hPa", "mbar", "mmHg", "inHg"], - temperature: ["°C", "°F"], - visibility: ["km", "mi"], - wind_speed: ["ft/s", "km/h", "kn", "mph", "m/s"], -}; - const SWITCH_AS_DOMAINS = ["cover", "fan", "light", "lock", "siren"]; @customElement("entity-registry-settings") @@ -148,16 +140,6 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) { @state() private _unit_of_measurement?: string | null; - @state() private _precipitation_unit?: string | null; - - @state() private _pressure_unit?: string | null; - - @state() private _temperature_unit?: string | null; - - @state() private _visibility_unit?: string | null; - - @state() private _wind_speed_unit?: string | null; - @state() private _error?: string; @state() private _submitting?: boolean; @@ -241,16 +223,6 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) { this._unit_of_measurement = stateObj?.attributes?.unit_of_measurement; } - if (domain === "weather") { - const stateObj: HassEntity | undefined = - this.hass.states[this.entry.entity_id]; - this._precipitation_unit = stateObj?.attributes?.precipitation_unit; - this._pressure_unit = stateObj?.attributes?.pressure_unit; - this._temperature_unit = stateObj?.attributes?.temperature_unit; - this._visibility_unit = stateObj?.attributes?.visibility_unit; - this._wind_speed_unit = stateObj?.attributes?.wind_speed_unit; - } - const deviceClasses: string[][] = OVERRIDE_DEVICE_CLASSES[domain]; if (!deviceClasses) { @@ -361,8 +333,7 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) { ` : ""} - ${domain === "sensor" && - this._deviceClass && + ${this._deviceClass && stateObj?.attributes.unit_of_measurement && OVERRIDE_SENSOR_UNITS[this._deviceClass]?.includes( stateObj?.attributes.unit_of_measurement @@ -386,90 +357,6 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) { ` : ""} - ${domain === "weather" - ? html` - - ${OVERRIDE_WEATHER_UNITS.precipitation.map( - (unit: string) => html` - ${unit} - ` - )} - - - ${OVERRIDE_WEATHER_UNITS.pressure.map( - (unit: string) => html` - ${unit} - ` - )} - - - ${OVERRIDE_WEATHER_UNITS.temperature.map( - (unit: string) => html` - ${unit} - ` - )} - - - ${OVERRIDE_WEATHER_UNITS.visibility.map( - (unit: string) => html` - ${unit} - ` - )} - - - ${OVERRIDE_WEATHER_UNITS.wind_speed.map( - (unit: string) => html` - ${unit} - ` - )} - - ` - : ""} ${domain === "switch" ? html` a[1].localeCompare(b[1])); content = html` - - ${items.map(([domain, label]) => { - // Only OG helpers need to be loaded prior adding one - const isLoaded = - !(domain in HELPERS) || isComponentLoaded(this.hass, domain); - return html` - - - ${label} - - ${!isLoaded - ? html` - ${this.hass.localize( - "ui.dialogs.helper_settings.platform_not_loaded", - "platform", - domain - )} - ` - : ""} - `; - })} - + ${items.map(([domain, label]) => { + // Only OG helpers need to be loaded prior adding one + const isLoaded = + !(domain in HELPERS) || isComponentLoaded(this.hass, domain); + return html` + + + ${label} + + ${!isLoaded + ? html` + ${this.hass.localize( + "ui.dialogs.helper_settings.platform_not_loaded", + "platform", + domain + )} + ` + : ""} + `; + })} ${this.hass!.localize("ui.common.cancel")} @@ -229,6 +220,15 @@ export class DialogHelperDetail extends LitElement { } } + private _handleEnter(ev: KeyboardEvent) { + if (ev.keyCode !== 13) { + return; + } + ev.stopPropagation(); + ev.preventDefault(); + this._domainPicked(ev); + } + private _domainPicked(ev: Event): void { const domain = (ev.currentTarget! as any).domain; diff --git a/src/panels/config/info/ha-config-info.ts b/src/panels/config/info/ha-config-info.ts index 8c9e92cd54..9412160247 100644 --- a/src/panels/config/info/ha-config-info.ts +++ b/src/panels/config/info/ha-config-info.ts @@ -1,18 +1,6 @@ -import "@material/mwc-list/mwc-list"; -import { - mdiBug, - mdiFileDocument, - mdiHandsPray, - mdiHelp, - mdiHomeAssistant, - mdiPower, - mdiTshirtCrew, -} from "@mdi/js"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { property, state } from "lit/decorators"; import { isComponentLoaded } from "../../../common/config/is_component_loaded"; -import "../../../components/ha-card"; -import "../../../components/ha-clickable-list-item"; import "../../../components/ha-logo-svg"; import { fetchHassioHassOsInfo, @@ -21,61 +9,12 @@ import { import { fetchHassioInfo, HassioInfo } from "../../../data/hassio/supervisor"; import "../../../layouts/hass-subpage"; import { haStyle } from "../../../resources/styles"; -import type { HomeAssistant, Route } from "../../../types"; +import { HomeAssistant, Route } from "../../../types"; import { documentationUrl } from "../../../util/documentation-url"; +const JS_TYPE = __BUILD__; const JS_VERSION = __VERSION__; -const PAGES: Array<{ - name: string; - path: string; - iconPath: string; - iconColor: string; -}> = [ - { - name: "change_log", - path: "/latest-release-notes/", - iconPath: mdiPower, - iconColor: "#4A5963", - }, - { - name: "thanks", - path: "/developers/credits/", - iconPath: mdiHandsPray, - iconColor: "#3B808E", - }, - { - name: "merch", - path: "/merch", - iconPath: mdiTshirtCrew, - iconColor: "#C65326", - }, - { - name: "feature", - path: "/feature-requests", - iconPath: mdiHomeAssistant, - iconColor: "#0D47A1", - }, - { - name: "bug", - path: "/issues", - iconPath: mdiBug, - iconColor: "#F1C447", - }, - { - name: "help", - path: "/community", - iconPath: mdiHelp, - iconColor: "#B1345C", - }, - { - name: "license", - path: "/developers/license/", - iconPath: mdiFileDocument, - iconColor: "#518C43", - }, -]; - class HaConfigInfo extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @@ -103,76 +42,96 @@ class HaConfigInfo extends LitElement { back-path="/config" .header=${this.hass.localize("ui.panel.config.info.caption")} > -
- -
- - - - -
- Home Assistant ${hass.connection.haVersion} - ${this._hassioInfo - ? html`Supervisor ${this._hassioInfo.supervisor}` - : ""} - ${this._osInfo?.version - ? html`Operating System ${this._osInfo.version}` - : ""} - - ${this.hass.localize( - "ui.panel.config.info.frontend_version", - "version", - JS_VERSION - )} - -
-
- - ${PAGES.map( - (page) => html` - -
- -
- - ${this.hass.localize( - `ui.panel.config.info.items.${page.name}` - )} - -
- ` +
+ + -

- ${this.hass.localize( - "ui.panel.config.info.path_configuration", - "path", - hass.config.config_dir - )} -

- ${!customUiList.length - ? "" - : html` -
+ > + + +
+

Home Assistant Core ${hass.connection.haVersion}

+ ${this._hassioInfo + ? html` +

+ Home Assistant Supervisor ${this._hassioInfo.supervisor} +

+ ` + : ""} + ${this._osInfo?.version + ? html`

Home Assistant OS ${this._osInfo.version}

` + : ""} +

+ ${this.hass.localize( + "ui.panel.config.info.path_configuration", + "path", + hass.config.config_dir + )} +

+

+ + ${this.hass.localize("ui.panel.config.info.developed_by")} + +

+

+ ${this.hass.localize("ui.panel.config.info.license")}
+ ${this.hass.localize("ui.panel.config.info.source")} + ${this.hass.localize("ui.panel.config.info.server")} + — + ${this.hass.localize("ui.panel.config.info.frontend")} +

+

+ ${this.hass.localize("ui.panel.config.info.built_using")} + Python 3, + Lit, + ${this.hass.localize("ui.panel.config.info.icons_by")} + Google + ${this.hass.localize("ui.common.and")} + Material Design Icons. +

+

+ ${this.hass.localize( + "ui.panel.config.info.frontend_version", + "version", + JS_VERSION, + "type", + JS_TYPE + )} + ${customUiList.length > 0 + ? html` +

${this.hass.localize("ui.panel.config.info.custom_uis")} ${customUiList.map( (item) => html` @@ -183,8 +142,9 @@ class HaConfigInfo extends LitElement { ` )}
- `} - + ` + : ""} +

`; @@ -216,87 +176,40 @@ class HaConfigInfo extends LitElement { this._osInfo = osInfo; } - private _entryClicked(ev) { - ev.currentTarget.blur(); - } - static get styles(): CSSResultGroup { return [ haStyle, css` - .content { - padding: 28px 20px 0; - max-width: 1040px; - margin: 0 auto; + :host { + -ms-user-select: initial; + -webkit-user-select: initial; + -moz-user-select: initial; } + .about { + text-align: center; + line-height: 2em; + } + + .version { + @apply --paper-font-headline; + } + + .develop { + @apply --paper-font-subhead; + } + + .about a { + color: var(--primary-color); + } ha-logo-svg { padding: 12px; - height: 150px; - width: 150px; + height: 180px; + width: 180px; } - ha-card { - padding: 16px; - max-width: 600px; - margin: 0 auto; - margin-bottom: 24px; - margin-bottom: max(24px, env(safe-area-inset-bottom)); - } - - .logo-versions { - display: flex; - justify-content: flex-start; - align-items: center; - } - - .versions { - display: flex; - flex-direction: column; - color: var(--secondary-text-color); - padding: 12px 0; - align-self: stretch; - justify-content: flex-start; - } - - .ha-version { - color: var(--primary-text-color); - font-weight: 500; - font-size: 16px; - } - - mwc-list { - --mdc-list-side-padding: 4px; - } - - ha-svg-icon { - height: 24px; - width: 24px; - display: block; - padding: 8px; - color: #fff; - } - - .icon-background { - border-radius: 50%; - } - - @media all and (max-width: 500px), all and (max-height: 500px) { - ha-logo-svg { - height: 100px; - width: 100px; - } - } - - .config-path { - color: var(--secondary-text-color); - text-align: center; - font-style: italic; - } - - .custom-ui { - color: var(--secondary-text-color); - text-align: center; + h4 { + font-weight: 400; } `, ]; diff --git a/src/panels/config/integrations/integration-panels/zwave_js/dialog-zwave_js-node-statistics.ts b/src/panels/config/integrations/integration-panels/zwave_js/dialog-zwave_js-node-statistics.ts deleted file mode 100644 index b68eb367c0..0000000000 --- a/src/panels/config/integrations/integration-panels/zwave_js/dialog-zwave_js-node-statistics.ts +++ /dev/null @@ -1,477 +0,0 @@ -import { UnsubscribeFunc } from "home-assistant-js-websocket"; -import "@material/mwc-list/mwc-list"; -import "@material/mwc-list/mwc-list-item"; -import "../../../../../components/ha-expansion-panel"; -import "../../../../../components/ha-help-tooltip"; -import "../../../../../components/ha-svg-icon"; -import { mdiSwapHorizontal } from "@mdi/js"; -import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; -import { customElement, property, state } from "lit/decorators"; -import { fireEvent } from "../../../../../common/dom/fire_event"; -import { - DeviceRegistryEntry, - computeDeviceName, - subscribeDeviceRegistry, -} from "../../../../../data/device_registry"; -import { - subscribeZwaveNodeStatistics, - ProtocolDataRate, - ZWaveJSNodeStatisticsUpdatedMessage, - ZWaveJSRouteStatistics, - RssiError, -} from "../../../../../data/zwave_js"; -import { haStyleDialog } from "../../../../../resources/styles"; -import { HomeAssistant } from "../../../../../types"; -import { ZWaveJSNodeStatisticsDialogParams } from "./show-dialog-zwave_js-node-statistics"; -import { createCloseHeading } from "../../../../../components/ha-dialog"; - -type WorkingRouteStatistics = - | (ZWaveJSRouteStatistics & { - repeater_rssi_table?: TemplateResult; - rssi_translated?: TemplateResult | string; - route_failed_between_translated?: [string, string]; - }) - | undefined; - -@customElement("dialog-zwave_js-node-statistics") -class DialogZWaveJSNodeStatistics extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @state() private device?: DeviceRegistryEntry; - - @state() private _nodeStatistics?: ZWaveJSNodeStatisticsUpdatedMessage & { - rssi_translated?: TemplateResult | string; - }; - - @state() private _deviceIDsToName: { [key: string]: string } = {}; - - @state() private _workingRoutes: { - lwr?: WorkingRouteStatistics; - nlwr?: WorkingRouteStatistics; - } = {}; - - private _subscribedNodeStatistics?: Promise; - - private _subscribedDeviceRegistry?: UnsubscribeFunc; - - public showDialog(params: ZWaveJSNodeStatisticsDialogParams): void { - this.device = params.device; - this._subscribeDeviceRegistry(); - this._subscribeNodeStatistics(); - } - - public closeDialog(): void { - this._nodeStatistics = undefined; - this.device = undefined; - - this._unsubscribe(); - - fireEvent(this, "dialog-closed", { dialog: this.localName }); - } - - protected render(): TemplateResult { - if (!this.device) { - return html``; - } - - return html` - - - - - ${this.hass.localize( - "ui.panel.config.zwave_js.node_statistics.commands_tx.label" - )} - - ${this.hass.localize( - "ui.panel.config.zwave_js.node_statistics.commands_tx.tooltip" - )} - - ${this._nodeStatistics?.commands_tx} - - - - ${this.hass.localize( - "ui.panel.config.zwave_js.node_statistics.commands_rx.label" - )} - - ${this.hass.localize( - "ui.panel.config.zwave_js.node_statistics.commands_rx.tooltip" - )} - - ${this._nodeStatistics?.commands_rx} - - - - ${this.hass.localize( - "ui.panel.config.zwave_js.node_statistics.commands_dropped_tx.label" - )} - - ${this.hass.localize( - "ui.panel.config.zwave_js.node_statistics.commands_dropped_tx.tooltip" - )} - - ${this._nodeStatistics?.commands_dropped_tx} - - - - ${this.hass.localize( - "ui.panel.config.zwave_js.node_statistics.commands_dropped_rx.label" - )} - - ${this.hass.localize( - "ui.panel.config.zwave_js.node_statistics.commands_dropped_rx.tooltip" - )} - - ${this._nodeStatistics?.commands_dropped_rx} - - - - ${this.hass.localize( - "ui.panel.config.zwave_js.node_statistics.timeout_response.label" - )} - - ${this.hass.localize( - "ui.panel.config.zwave_js.node_statistics.timeout_response.tooltip" - )} - - ${this._nodeStatistics?.timeout_response} - - ${this._nodeStatistics?.rtt - ? html` - - ${this.hass.localize( - "ui.panel.config.zwave_js.node_statistics.rtt.label" - )} - - ${this.hass.localize( - "ui.panel.config.zwave_js.node_statistics.rtt.tooltip" - )} - - ${this._nodeStatistics.rtt} - ` - : ``} - ${this._nodeStatistics?.rssi_translated - ? html` - - ${this.hass.localize( - "ui.panel.config.zwave_js.node_statistics.rssi.label" - )} - - ${this.hass.localize( - "ui.panel.config.zwave_js.node_statistics.rssi.tooltip" - )} - - ${this._nodeStatistics.rssi_translated} - ` - : ``} - - ${Object.entries(this._workingRoutes).map(([wrKey, wrValue]) => - wrValue - ? html` - -
- - ${this.hass.localize( - "ui.panel.config.zwave_js.route_statistics.protocol.label" - )} - - ${this.hass.localize( - `ui.panel.config.zwave_js.route_statistics.protocol.protocol_data_rate.${ - ProtocolDataRate[wrValue.protocol_data_rate] - }` - )} -
-
- - ${this.hass.localize( - "ui.panel.config.zwave_js.route_statistics.data_rate.label" - )} - - ${this.hass.localize( - `ui.panel.config.zwave_js.route_statistics.data_rate.protocol_data_rate.${ - ProtocolDataRate[wrValue.protocol_data_rate] - }` - )} -
- ${wrValue.rssi_translated - ? html`
- - ${this.hass.localize( - "ui.panel.config.zwave_js.route_statistics.rssi.label" - )} - - ${wrValue.rssi_translated} -
` - : ``} -
- - ${this.hass.localize( - "ui.panel.config.zwave_js.route_statistics.route_failed_between.label" - )} - - - ${wrValue.route_failed_between_translated - ? html`${wrValue - .route_failed_between_translated[0]}${wrValue.route_failed_between_translated[1]}` - : this.hass.localize( - "ui.panel.config.zwave_js.route_statistics.route_failed_between.not_applicable" - )} - -
-
- - ${this.hass.localize( - "ui.panel.config.zwave_js.route_statistics.repeaters.label" - )} - - ${wrValue.repeater_rssi_table - ? html`
- ${this.hass.localize( - "ui.panel.config.zwave_js.route_statistics.repeaters.repeaters" - )}: - ${this.hass.localize( - "ui.panel.config.zwave_js.route_statistics.repeaters.rssi" - )}: -
- ${wrValue.repeater_rssi_table}` - : html`${this.hass.localize( - "ui.panel.config.zwave_js.route_statistics.repeaters.direct" - )}`}
-
-
- ` - : `` - )} -
- `; - } - - private _computeRSSI( - rssi: number, - includeUnit: boolean - ): TemplateResult | string { - if (Object.values(RssiError).includes(rssi)) { - return html``; - } - if (includeUnit) { - return `${rssi} - ${this.hass.localize("ui.panel.config.zwave_js.rssi.unit")}`; - } - return rssi.toString(); - } - - private _computeDeviceNameById(device_id: string): "unknown device" | string { - if (!this._deviceIDsToName) { - return "unknown device"; - } - const device = this._deviceIDsToName[device_id]; - if (!device) { - return "unknown device"; - } - - return this._deviceIDsToName[device_id] || "unknown device"; - } - - private _subscribeNodeStatistics(): void { - if (!this.hass) { - return; - } - this._subscribedNodeStatistics = subscribeZwaveNodeStatistics( - this.hass, - this.device!.id, - (message: ZWaveJSNodeStatisticsUpdatedMessage) => { - this._nodeStatistics = { - ...message, - rssi_translated: message.rssi - ? this._computeRSSI(message.rssi, false) - : undefined, - }; - - const workingRoutesValueMap: [ - string, - WorkingRouteStatistics | null | undefined - ][] = [ - ["lwr", this._nodeStatistics?.lwr], - ["nlwr", this._nodeStatistics?.nlwr], - ]; - - const workingRoutes: { - lwr?: WorkingRouteStatistics; - nlwr?: WorkingRouteStatistics; - } = {}; - workingRoutesValueMap.forEach(([wrKey, wrValue]) => { - workingRoutes[wrKey] = wrValue; - - if (wrValue) { - if (wrValue.rssi) { - wrValue.rssi_translated = this._computeRSSI(wrValue.rssi, true); - } - - if (wrValue.route_failed_between) { - wrValue.route_failed_between_translated = [ - this._computeDeviceNameById(wrValue.route_failed_between[0]), - this._computeDeviceNameById(wrValue.route_failed_between[1]), - ]; - } - - if (wrValue.repeaters && wrValue.repeaters.length) { - wrValue.repeater_rssi_table = html`${wrValue.repeaters.map( - (_, idx) => - html`
- ${this._computeDeviceNameById( - wrValue.repeaters[idx] - )}: - ${this._computeRSSI( - wrValue.repeater_rssi[idx], - true - )} -
` - )}`; - } - } - }); - this._workingRoutes = workingRoutes; - } - ); - } - - private _subscribeDeviceRegistry(): void { - if (!this.hass) { - return; - } - this._subscribedDeviceRegistry = subscribeDeviceRegistry( - this.hass.connection, - (devices: DeviceRegistryEntry[]) => { - const devicesIdToName = {}; - devices.forEach((device) => { - devicesIdToName[device.id] = computeDeviceName(device, this.hass); - }); - this._deviceIDsToName = devicesIdToName; - } - ); - } - - private _unsubscribe(): void { - if (this._subscribedNodeStatistics) { - this._subscribedNodeStatistics.then((unsub) => unsub()); - this._subscribedNodeStatistics = undefined; - } - if (this._subscribedDeviceRegistry) { - this._subscribedDeviceRegistry(); - this._subscribedDeviceRegistry = undefined; - } - } - - static get styles(): CSSResultGroup { - return [ - haStyleDialog, - css` - mwc-list-item { - height: 60px; - } - - .row { - display: flex; - justify-content: space-between; - } - - .table { - display: table; - } - - .key-cell { - display: table-cell; - padding-right: 5px; - } - - .value-cell { - display: table-cell; - padding-left: 5px; - } - - span[slot="meta"] { - font-size: 0.95em; - color: var(--primary-text-color); - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "dialog-zwave_js-node-statistics": DialogZWaveJSNodeStatistics; - } -} diff --git a/src/panels/config/integrations/integration-panels/zwave_js/dialog-zwave_js-update-firmware-node.ts b/src/panels/config/integrations/integration-panels/zwave_js/dialog-zwave_js-update-firmware-node.ts deleted file mode 100644 index b0f76d331d..0000000000 --- a/src/panels/config/integrations/integration-panels/zwave_js/dialog-zwave_js-update-firmware-node.ts +++ /dev/null @@ -1,461 +0,0 @@ -import "../../../../../components/ha-file-upload"; -import "../../../../../components/ha-form/ha-form"; -import "../../../../../components/ha-svg-icon"; -import "@material/mwc-button/mwc-button"; -import "@material/mwc-linear-progress/mwc-linear-progress"; -import { mdiCheckCircle, mdiCloseCircle, mdiFileUpload } from "@mdi/js"; -import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; -import { customElement, property, state } from "lit/decorators"; -import memoizeOne from "memoize-one"; -import { UnsubscribeFunc } from "home-assistant-js-websocket"; -import { fireEvent } from "../../../../../common/dom/fire_event"; -import { createCloseHeading } from "../../../../../components/ha-dialog"; -import { - DeviceRegistryEntry, - computeDeviceName, -} from "../../../../../data/device_registry"; -import { - abortZwaveNodeFirmwareUpdate, - fetchZwaveNodeIsFirmwareUpdateInProgress, - fetchZwaveNodeStatus, - FirmwareUpdateStatus, - NodeStatus, - subscribeZwaveNodeStatus, - subscribeZwaveNodeFirmwareUpdate, - uploadFirmwareAndBeginUpdate, - ZWaveJSNodeFirmwareUpdateFinishedMessage, - ZWaveJSNodeFirmwareUpdateProgressMessage, - ZWaveJSNodeStatusUpdatedMessage, - ZWaveJSNodeFirmwareUpdateCapabilities, - ZWaveJSNodeStatus, -} from "../../../../../data/zwave_js"; -import { haStyleDialog } from "../../../../../resources/styles"; -import { HomeAssistant } from "../../../../../types"; -import { ZWaveJSUpdateFirmwareNodeDialogParams } from "./show-dialog-zwave_js-update-firmware-node"; -import { - showAlertDialog, - showConfirmationDialog, -} from "../../../../../dialogs/generic/show-dialog-box"; -import { HaFormIntegerSchema } from "../../../../../components/ha-form/types"; - -@customElement("dialog-zwave_js-update-firmware-node") -class DialogZWaveJSUpdateFirmwareNode extends LitElement { - @property({ attribute: false }) public hass!: HomeAssistant; - - @state() private device?: DeviceRegistryEntry; - - @state() private _uploading = false; - - @state() - private _updateFinishedMessage?: ZWaveJSNodeFirmwareUpdateFinishedMessage; - - @state() - private _updateProgressMessage?: ZWaveJSNodeFirmwareUpdateProgressMessage; - - @state() private _updateInProgress = false; - - @state() private _firmwareFile?: File; - - @state() private _nodeStatus?: ZWaveJSNodeStatus; - - @state() private _firmwareTarget? = 0; - - private _subscribedNodeStatus?: Promise; - - private _subscribedNodeFirmwareUpdate?: Promise; - - private _deviceName?: string; - - private _firmwareUpdateCapabilities?: ZWaveJSNodeFirmwareUpdateCapabilities; - - public showDialog(params: ZWaveJSUpdateFirmwareNodeDialogParams): void { - this._deviceName = computeDeviceName(params.device, this.hass!); - this.device = params.device; - this._firmwareUpdateCapabilities = params.firmwareUpdateCapabilities; - this._fetchData(); - this._subscribeNodeStatus(); - } - - public closeDialog(): void { - this._unsubscribeNodeFirmwareUpdate(); - this._unsubscribeNodeStatus(); - this.device = - this._updateProgressMessage = - this._updateFinishedMessage = - this._firmwareFile = - this._nodeStatus = - this._firmwareUpdateCapabilities = - undefined; - this._firmwareTarget = 0; - this._uploading = this._updateInProgress = false; - - fireEvent(this, "dialog-closed", { dialog: this.localName }); - } - - private _schema = memoizeOne( - ( - firmwareUpdateCapabilities: ZWaveJSNodeFirmwareUpdateCapabilities - ): HaFormIntegerSchema => { - if (!firmwareUpdateCapabilities.firmware_upgradable) { - // We should never get here, this is to pass type checks - throw new Error(); - } - return { - name: "firmware_target", - type: "integer", - valueMin: Math.min(...firmwareUpdateCapabilities.firmware_targets), - valueMax: Math.max(...firmwareUpdateCapabilities.firmware_targets), - }; - } - ); - - protected render(): TemplateResult { - if ( - !this.device || - !this._nodeStatus || - !this._firmwareUpdateCapabilities || - !this._firmwareUpdateCapabilities.firmware_upgradable || - this._updateInProgress === undefined - ) { - return html``; - } - - const beginFirmwareUpdateHTML = html` - ${this._firmwareUpdateCapabilities.firmware_targets.length > 1 - ? html`

- ${this.hass.localize( - "ui.panel.config.zwave_js.update_firmware.firmware_target_intro" - )} -

- ` - : ""} - - ${this.hass.localize( - "ui.panel.config.zwave_js.update_firmware.begin_update" - )} - `; - - const abortFirmwareUpdateButton = html` - - ${this.hass.localize("ui.panel.config.zwave_js.update_firmware.abort")} - - `; - - const status = this._updateFinishedMessage - ? FirmwareUpdateStatus[this._updateFinishedMessage.status] - .split("_")[0] - .toLowerCase() - : undefined; - - return html` - - ${!this._updateProgressMessage && !this._updateFinishedMessage - ? !this._updateInProgress - ? html` -

- ${this.hass.localize( - "ui.panel.config.zwave_js.update_firmware.introduction", - { - device: html`${this._deviceName}`, - } - )} -

- ${beginFirmwareUpdateHTML} - ` - : html` -

- ${this._nodeStatus.status === NodeStatus.Asleep - ? this.hass.localize( - "ui.panel.config.zwave_js.update_firmware.queued", - { - device: html`${this._deviceName}`, - } - ) - : this.hass.localize( - "ui.panel.config.zwave_js.update_firmware.awake", - { - device: html`${this._deviceName}`, - } - )} -

-

- ${this._nodeStatus.status === NodeStatus.Asleep - ? this.hass.localize( - "ui.panel.config.zwave_js.update_firmware.close_queued", - { - device: html`${this._deviceName}`, - } - ) - : this.hass.localize( - "ui.panel.config.zwave_js.update_firmware.close", - { - device: html`${this._deviceName}`, - } - )} -

- ${abortFirmwareUpdateButton} - ` - : this._updateProgressMessage && !this._updateFinishedMessage - ? html` -

- ${this.hass.localize( - "ui.panel.config.zwave_js.update_firmware.in_progress", - { - device: html`${this._deviceName}`, - progress: ( - (this._updateProgressMessage.sent_fragments * 100) / - this._updateProgressMessage.total_fragments - ).toFixed(2), - } - )} -

- -

- ${this.hass.localize( - "ui.panel.config.zwave_js.update_firmware.close", - { - device: html`${this._deviceName}`, - } - )} -

- ${abortFirmwareUpdateButton} - ` - : html` -
- -
-

- ${this.hass.localize( - `ui.panel.config.zwave_js.update_firmware.finished_status.${status}`, - { - device: html`${this._deviceName}`, - message: this.hass.localize( - `ui.panel.config.zwave_js.update_firmware.finished_status.${ - FirmwareUpdateStatus[ - this._updateFinishedMessage!.status - ] - }` - ), - } - )} -

-
-
- ${status === "ok" - ? html`

- ${this.hass.localize( - "ui.panel.config.zwave_js.update_firmware.finished_status.done" - )} -

` - : html`

- ${this.hass.localize( - "ui.panel.config.zwave_js.update_firmware.finished_status.try_again" - )} -

- ${beginFirmwareUpdateHTML}`} -

- ${this.hass.localize( - "ui.panel.config.zwave_js.update_firmware.finished_status.try_again" - )} -

- ${beginFirmwareUpdateHTML} - `} -
- `; - } - - private async _fetchData(): Promise { - [this._nodeStatus, this._updateInProgress] = await Promise.all([ - fetchZwaveNodeStatus(this.hass, this.device!.id), - fetchZwaveNodeIsFirmwareUpdateInProgress(this.hass, this.device!.id), - ]); - if (this._updateInProgress) { - this._subscribeNodeFirmwareUpdate(); - } - } - - private async _beginFirmwareUpdate(): Promise { - this._uploading = true; - this._updateProgressMessage = this._updateFinishedMessage = undefined; - try { - this._subscribeNodeFirmwareUpdate(); - await uploadFirmwareAndBeginUpdate( - this.hass, - this.device!.id, - this._firmwareFile!, - this._firmwareTarget - ); - this._updateInProgress = true; - this._uploading = false; - } catch (err: any) { - this._unsubscribeNodeFirmwareUpdate(); - this._uploading = false; - showAlertDialog(this, { - title: this.hass.localize( - "ui.panel.config.zwave_js.update_firmware.upload_failed" - ), - text: err.message, - confirmText: this.hass!.localize("ui.common.close"), - }); - } - } - - private async _abortFirmwareUpdate(): Promise { - if ( - await showConfirmationDialog(this, { - text: this.hass.localize( - "ui.panel.config.zwave_js.update_firmware.confirm_abort", - { - device: html`${this._deviceName}`, - } - ), - dismissText: this.hass!.localize("ui.common.no"), - confirmText: this.hass!.localize("ui.common.yes"), - }) - ) { - this._unsubscribeNodeFirmwareUpdate(); - try { - await abortZwaveNodeFirmwareUpdate(this.hass, this.device!.id); - } catch (err: any) { - showAlertDialog(this, { - title: this.hass.localize( - "ui.panel.config.zwave_js.update_firmware.abort_failed" - ), - text: err.message, - confirmText: this.hass!.localize("ui.common.close"), - }); - } - this._firmwareFile = undefined; - this._updateFinishedMessage = undefined; - this._updateProgressMessage = undefined; - this._updateInProgress = false; - } - } - - private _subscribeNodeStatus(): void { - if (!this.hass || !this.device || this._subscribedNodeStatus) { - return; - } - this._subscribedNodeStatus = subscribeZwaveNodeStatus( - this.hass, - this.device.id, - (message: ZWaveJSNodeStatusUpdatedMessage) => { - this._nodeStatus!.status = message.status; - } - ); - } - - private _unsubscribeNodeStatus(): void { - if (!this._subscribedNodeStatus) { - return; - } - this._subscribedNodeStatus.then((unsub) => unsub()); - this._subscribedNodeStatus = undefined; - } - - private _subscribeNodeFirmwareUpdate(): void { - if (!this.hass || !this.device || this._subscribedNodeFirmwareUpdate) { - return; - } - this._subscribedNodeFirmwareUpdate = subscribeZwaveNodeFirmwareUpdate( - this.hass, - this.device.id, - ( - message: - | ZWaveJSNodeFirmwareUpdateFinishedMessage - | ZWaveJSNodeFirmwareUpdateProgressMessage - ) => { - if (message.event === "firmware update progress") { - if (!this._updateFinishedMessage) { - this._updateProgressMessage = message; - } - } else { - this._unsubscribeNodeFirmwareUpdate(); - this._updateProgressMessage = undefined; - this._updateInProgress = false; - this._updateFinishedMessage = message; - } - } - ); - } - - private _unsubscribeNodeFirmwareUpdate(): void { - if (!this._subscribedNodeFirmwareUpdate) { - return; - } - this._subscribedNodeFirmwareUpdate.then((unsub) => unsub()); - this._subscribedNodeFirmwareUpdate = undefined; - } - - private async _firmwareTargetChanged(ev) { - this._firmwareTarget = ev.detail.value.firmware_target; - } - - private async _uploadFile(ev) { - this._firmwareFile = ev.detail.files[0]; - } - - static get styles(): CSSResultGroup { - return [ - haStyleDialog, - css` - .ok { - color: var(--success-color); - } - - .error { - color: var(--error-color); - } - - .flex-container { - display: flex; - align-items: center; - margin-bottom: 5px; - } - - ha-svg-icon { - width: 68px; - height: 48px; - } - `, - ]; - } -} - -declare global { - interface HTMLElementTagNameMap { - "dialog-zwave_js-update-firmware-node": DialogZWaveJSUpdateFirmwareNode; - } -} diff --git a/src/panels/config/integrations/integration-panels/zwave_js/show-dialog-zwave_js-node-statistics.ts b/src/panels/config/integrations/integration-panels/zwave_js/show-dialog-zwave_js-node-statistics.ts deleted file mode 100644 index ec48d7f02c..0000000000 --- a/src/panels/config/integrations/integration-panels/zwave_js/show-dialog-zwave_js-node-statistics.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { fireEvent } from "../../../../../common/dom/fire_event"; -import { DeviceRegistryEntry } from "../../../../../data/device_registry"; - -export interface ZWaveJSNodeStatisticsDialogParams { - device: DeviceRegistryEntry; -} - -export const loadNodeStatisticsDialog = () => - import("./dialog-zwave_js-node-statistics"); - -export const showZWaveJSNodeStatisticsDialog = ( - element: HTMLElement, - nodeStatisticsDialogParams: ZWaveJSNodeStatisticsDialogParams -): void => { - fireEvent(element, "show-dialog", { - dialogTag: "dialog-zwave_js-node-statistics", - dialogImport: loadNodeStatisticsDialog, - dialogParams: nodeStatisticsDialogParams, - }); -}; diff --git a/src/panels/config/integrations/integration-panels/zwave_js/show-dialog-zwave_js-update-firmware-node.ts b/src/panels/config/integrations/integration-panels/zwave_js/show-dialog-zwave_js-update-firmware-node.ts deleted file mode 100644 index dc45f309f6..0000000000 --- a/src/panels/config/integrations/integration-panels/zwave_js/show-dialog-zwave_js-update-firmware-node.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { fireEvent } from "../../../../../common/dom/fire_event"; -import { DeviceRegistryEntry } from "../../../../../data/device_registry"; -import { ZWaveJSNodeFirmwareUpdateCapabilities } from "../../../../../data/zwave_js"; - -export interface ZWaveJSUpdateFirmwareNodeDialogParams { - device: DeviceRegistryEntry; - firmwareUpdateCapabilities: ZWaveJSNodeFirmwareUpdateCapabilities; -} - -export const loadUpdateFirmwareNodeDialog = () => - import("./dialog-zwave_js-update-firmware-node"); - -export const showZWaveJUpdateFirmwareNodeDialog = ( - element: HTMLElement, - updateFirmwareNodeDialogParams: ZWaveJSUpdateFirmwareNodeDialogParams -): void => { - fireEvent(element, "show-dialog", { - dialogTag: "dialog-zwave_js-update-firmware-node", - dialogImport: loadUpdateFirmwareNodeDialog, - dialogParams: updateFirmwareNodeDialogParams, - }); -}; diff --git a/src/panels/config/logs/ha-config-logs.ts b/src/panels/config/logs/ha-config-logs.ts index d8f811fcf4..1981a08a25 100644 --- a/src/panels/config/logs/ha-config-logs.ts +++ b/src/panels/config/logs/ha-config-logs.ts @@ -6,7 +6,7 @@ import { extractSearchParam } from "../../../common/url/search-params"; import "../../../components/ha-button-menu"; import "../../../components/search-input"; import { LogProvider } from "../../../data/error_log"; -import { fetchHassioAddonsInfo } from "../../../data/hassio/addon"; +import { fetchHassioSupervisorInfo } from "../../../data/hassio/supervisor"; import "../../../layouts/hass-subpage"; import "../../../layouts/hass-tabs-subpage"; import { haStyle } from "../../../resources/styles"; @@ -167,15 +167,13 @@ export class HaConfigLogs extends LitElement { private async _getInstalledAddons() { try { - const addonsInfo = await fetchHassioAddonsInfo(this.hass); + const supervisorInfo = await fetchHassioSupervisorInfo(this.hass); this._logProviders = [ ...this._logProviders, - ...addonsInfo.addons - .filter((addon) => addon.version) - .map((addon) => ({ - key: addon.slug, - name: addon.name, - })), + ...supervisorInfo.addons.map((addon) => ({ + key: addon.slug, + name: addon.name, + })), ]; } catch (err) { // Ignore, nothing the user can do anyway diff --git a/src/panels/history/ha-panel-history.ts b/src/panels/history/ha-panel-history.ts index 9deb2cf1b1..7caa849c0a 100644 --- a/src/panels/history/ha-panel-history.ts +++ b/src/panels/history/ha-panel-history.ts @@ -12,7 +12,6 @@ import { } from "date-fns/esm"; import { css, html, LitElement, PropertyValues } from "lit"; import { property, state } from "lit/decorators"; -import { UnsubscribeFunc } from "home-assistant-js-websocket/dist/types"; import { navigate } from "../../common/navigate"; import { createSearchParam, @@ -20,7 +19,7 @@ import { } from "../../common/url/search-params"; import { computeRTL } from "../../common/util/compute_rtl"; import "../../components/chart/state-history-charts"; -import "../../components/ha-target-picker"; +import "../../components/entity/ha-entity-picker"; import "../../components/ha-circular-progress"; import "../../components/ha-date-range-picker"; import type { DateRangePickerRanges } from "../../components/ha-date-range-picker"; @@ -30,15 +29,8 @@ import { computeHistory, fetchDateWS } from "../../data/history"; import "../../layouts/ha-app-layout"; import { haStyle } from "../../resources/styles"; import { HomeAssistant } from "../../types"; -import { - EntityRegistryEntry, - subscribeEntityRegistry, -} from "../../data/entity_registry"; -import { SubscribeMixin } from "../../mixins/subscribe-mixin"; -import { computeStateName } from "../../common/entity/compute_state_name"; -import { computeDomain } from "../../common/entity/compute_domain"; -class HaPanelHistory extends SubscribeMixin(LitElement) { +class HaPanelHistory extends LitElement { @property() hass!: HomeAssistant; @property({ reflect: true, type: Boolean }) narrow!: boolean; @@ -47,7 +39,7 @@ class HaPanelHistory extends SubscribeMixin(LitElement) { @property() _endDate: Date; - @property() _targetPickerValue?; + @property() _entityId = ""; @property() _isLoading = false; @@ -57,10 +49,6 @@ class HaPanelHistory extends SubscribeMixin(LitElement) { @state() private _ranges?: DateRangePickerRanges; - @state() private _entities?: EntityRegistryEntry[]; - - @state() private _stateEntities?: EntityRegistryEntry[]; - public constructor() { super(); @@ -73,14 +61,6 @@ class HaPanelHistory extends SubscribeMixin(LitElement) { this._endDate = end; } - public hassSubscribe(): UnsubscribeFunc[] { - return [ - subscribeEntityRegistry(this.hass.connection!, (entities) => { - this._entities = entities; - }), - ]; - } - protected render() { return html` @@ -100,40 +80,25 @@ class HaPanelHistory extends SubscribeMixin(LitElement) { -
-
- - -
- ${this._isLoading - ? html`
- -
` - : html` - - - `} +
+ + +
${this._isLoading ? html`
@@ -177,13 +142,7 @@ class HaPanelHistory extends SubscribeMixin(LitElement) { [addDays(weekStart, -7), addDays(weekEnd, -7)], }; - const entityIds = extractSearchParam("entity_id"); - if (entityIds) { - const splitEntityIds = entityIds.split(","); - this._targetPickerValue = { - entity_id: splitEntityIds, - }; - } + this._entityId = extractSearchParam("entity_id") ?? ""; const startDate = extractSearchParam("start_date"); if (startDate) { @@ -199,41 +158,16 @@ class HaPanelHistory extends SubscribeMixin(LitElement) { if ( changedProps.has("_startDate") || changedProps.has("_endDate") || - changedProps.has("_targetPickerValue") || - changedProps.has("_entities") + changedProps.has("_entityId") ) { this._getHistory(); } - if (changedProps.has("hass") || changedProps.has("_entities")) { + if (changedProps.has("hass")) { const oldHass = changedProps.get("hass") as HomeAssistant | undefined; if (!oldHass || oldHass.language !== this.hass.language) { this.rtl = computeRTL(this.hass); } - if (this._entities) { - const stateEntities: EntityRegistryEntry[] = []; - const regEntityIds = new Set( - this._entities.map((entity) => entity.entity_id) - ); - for (const entityId of Object.keys(this.hass.states)) { - if (regEntityIds.has(entityId)) { - continue; - } - stateEntities.push({ - name: computeStateName(this.hass.states[entityId]), - entity_id: entityId, - platform: computeDomain(entityId), - disabled_by: null, - hidden_by: null, - area_id: null, - config_entry_id: null, - device_id: null, - icon: null, - entity_category: null, - }); - } - this._stateEntities = stateEntities; - } } } @@ -243,16 +177,12 @@ class HaPanelHistory extends SubscribeMixin(LitElement) { private async _getHistory() { this._isLoading = true; - const entityIds = this._getEntityIds(); - const dateHistory = - entityIds.length === 0 - ? {} - : await fetchDateWS( - this.hass, - this._startDate, - this._endDate, - entityIds - ); + const dateHistory = await fetchDateWS( + this.hass, + this._startDate, + this._endDate, + this._entityId + ); this._stateHistory = computeHistory( this.hass, dateHistory, @@ -261,52 +191,6 @@ class HaPanelHistory extends SubscribeMixin(LitElement) { this._isLoading = false; } - private _filterEntity(entity: EntityRegistryEntry): boolean { - const { area_id, device_id, entity_id } = this._targetPickerValue; - if (area_id !== undefined) { - if (typeof area_id === "string" && area_id === entity.area_id) { - return true; - } - if (Array.isArray(area_id) && area_id.includes(entity.area_id)) { - return true; - } - } - if (device_id !== undefined) { - if (typeof device_id === "string" && device_id === entity.device_id) { - return true; - } - if (Array.isArray(device_id) && device_id.includes(entity.device_id)) { - return true; - } - } - if (entity_id !== undefined) { - if (typeof entity_id === "string" && entity_id === entity.entity_id) { - return true; - } - if (Array.isArray(entity_id) && entity_id.includes(entity.entity_id)) { - return true; - } - } - return false; - } - - private _getEntityIds(): string[] { - if ( - this._targetPickerValue === undefined || - this._entities === undefined || - this._stateEntities === undefined - ) { - return []; - } - const entityIds = this._entities - .filter((entity) => this._filterEntity(entity)) - .map((entity) => entity.entity_id); - const stateEntityIds = this._stateEntities - .filter((entity) => this._filterEntity(entity)) - .map((entity) => entity.entity_id); - return [...entityIds, ...stateEntityIds]; - } - private _dateRangeChanged(ev) { this._startDate = ev.detail.startDate; const endDate = ev.detail.endDate; @@ -319,8 +203,8 @@ class HaPanelHistory extends SubscribeMixin(LitElement) { this._updatePath(); } - private _entitiesChanged(ev) { - this._targetPickerValue = ev.detail.value; + private _entityPicked(ev) { + this._entityId = ev.target.value; this._updatePath(); } @@ -328,8 +212,8 @@ class HaPanelHistory extends SubscribeMixin(LitElement) { private _updatePath() { const params: Record = {}; - if (this._targetPickerValue) { - params.entity_id = this._getEntityIds().join(","); + if (this._entityId) { + params.entity_id = this._entityId; } if (this._startDate) { @@ -371,18 +255,6 @@ class HaPanelHistory extends SubscribeMixin(LitElement) { height: 100%; } - :host([narrow]) .narrow-wrap { - flex-wrap: wrap; - } - - .horizontal { - align-items: center; - } - - :host(:not([narrow])) .selector-padding { - padding-left: 32px; - } - .progress-wrapper { position: relative; } diff --git a/src/panels/logbook/ha-logbook-renderer.ts b/src/panels/logbook/ha-logbook-renderer.ts index e5384b8778..6e382b3cce 100644 --- a/src/panels/logbook/ha-logbook-renderer.ts +++ b/src/panels/logbook/ha-logbook-renderer.ts @@ -1,5 +1,4 @@ import "@lit-labs/virtualizer"; -import { VisibilityChangedEvent } from "@lit-labs/virtualizer/Virtualizer"; import { css, CSSResultGroup, @@ -17,6 +16,7 @@ import { restoreScroll } from "../../common/decorators/restore-scroll"; import { fireEvent } from "../../common/dom/fire_event"; import { computeDomain } from "../../common/entity/compute_domain"; import { isComponentLoaded } from "../../common/config/is_component_loaded"; +import { computeRTL, emitRTLDirection } from "../../common/util/compute_rtl"; import "../../components/entity/state-badge"; import "../../components/ha-circular-progress"; import "../../components/ha-relative-time"; @@ -35,12 +35,6 @@ import { import { HomeAssistant } from "../../types"; import { brandsUrl } from "../../util/brands-url"; -declare global { - interface HASSDomEvents { - "hass-logbook-live": { enable: boolean }; - } -} - const triggerDomains = ["script", "automation"]; const hasContext = (item: LogbookEntry) => @@ -62,6 +56,9 @@ class HaLogbookRenderer extends LitElement { @property({ type: Boolean, attribute: "narrow" }) public narrow = false; + @property({ attribute: "rtl", type: Boolean }) + private _rtl = false; + @property({ type: Boolean, attribute: "virtualize", reflect: true }) public virtualize = false; @@ -89,10 +86,18 @@ class HaLogbookRenderer extends LitElement { ); } + protected updated(_changedProps: PropertyValues) { + const oldHass = _changedProps.get("hass") as HomeAssistant | undefined; + + if (oldHass === undefined || oldHass.language !== this.hass.language) { + this._rtl = computeRTL(this.hass); + } + } + protected render(): TemplateResult { if (!this.entries?.length) { return html` -
+
${this.hass.localize("ui.components.logbook.entries_not_found")}
`; @@ -102,6 +107,7 @@ class HaLogbookRenderer extends LitElement {
${this.virtualize ? html` Promise) | void>; - - private _liveUpdatesEnabled = true; - - private _pendingStreamMessages: LogbookStreamMessage[] = []; + private _subscribed?: Promise; private _throttleGetLogbookEntries = throttle( () => this._getLogBookData(), @@ -130,7 +127,6 @@ export class HaLogbook extends LitElement { .entries=${this._logbookEntries} .traceContexts=${this._traceContexts} .userIdToName=${this._userIdToName} - @hass-logbook-live=${this._handleLogbookLive} > `; } @@ -140,7 +136,7 @@ export class HaLogbook extends LitElement { return; } - this._unsubscribeSetLoading(); + this._unsubscribe(); this._throttleGetLogbookEntries.cancel(); this._updateTraceContexts.cancel(); this._updateUsers.cancel(); @@ -152,23 +148,13 @@ export class HaLogbook extends LitElement { ); } + this._logbookEntries = undefined; this._throttleGetLogbookEntries(); } - protected firstUpdated(changedProps: PropertyValues) { - super.firstUpdated(changedProps); - } - - protected shouldUpdate(changedProps: PropertyValues): boolean { - if (changedProps.size !== 1 || !changedProps.has("hass")) { - return true; - } - // We only respond to hass changes if the translations changed - const oldHass = changedProps.get("hass") as HomeAssistant | undefined; - return !oldHass || oldHass.localize !== this.hass.localize; - } - protected updated(changedProps: PropertyValues): void { + super.updated(changedProps); + let changed = changedProps.has("time"); for (const key of ["entityIds", "deviceIds"]) { @@ -194,17 +180,6 @@ export class HaLogbook extends LitElement { } } - private _handleLogbookLive(ev: CustomEvent) { - if (ev.detail.enable && !this._liveUpdatesEnabled) { - // Process everything we queued up while we were scrolled down - this._pendingStreamMessages.forEach((msg) => - this._processStreamMessage(msg) - ); - this._pendingStreamMessages = []; - } - this._liveUpdatesEnabled = ev.detail.enable; - } - private get _filterAlwaysEmptyResults(): boolean { const entityIds = ensureArray(this.entityIds); const deviceIds = ensureArray(this.deviceIds); @@ -219,15 +194,7 @@ export class HaLogbook extends LitElement { private _unsubscribe(): void { if (this._subscribed) { - this._subscribed.then((unsub) => - unsub - ? unsub().catch(() => { - // The backend will cancel the subscription if - // we subscribe to entities that will all be - // filtered away - }) - : undefined - ); + this._subscribed.then((unsub) => (unsub ? unsub() : undefined)); this._subscribed = undefined; } } @@ -241,26 +208,12 @@ export class HaLogbook extends LitElement { public disconnectedCallback() { super.disconnectedCallback(); - this._unsubscribeSetLoading(); - } - - /** Unsubscribe because we are unloading - * or about to resubscribe. - * Setting this._logbookEntries to undefined - * will put the page in a loading state. - */ - private _unsubscribeSetLoading() { - this._logbookEntries = undefined; this._unsubscribe(); } - /** Unsubscribe because there are no results. - * Setting this._logbookEntries to an empty - * list will show a no results message. - */ - private _unsubscribeNoResults() { + private _unsubscribeAndEmptyEntries() { + this._unsubscribe(); this._logbookEntries = []; - this._unsubscribe(); } private _calculateLogbookPeriod() { @@ -299,19 +252,20 @@ export class HaLogbook extends LitElement { // "recent" means start time is a sliding window // so we need to calculate an expireTime to // purge old events - if (!this._subscribed) { - // Message came in before we had a chance to unload - return; - } - this._processOrQueueStreamMessage(streamMessage); + this._processStreamMessage( + streamMessage, + "recent" in this.time + ? findStartOfRecentTime(new Date(), this.time.recent) + : undefined + ); }, logbookPeriod.startTime.toISOString(), logbookPeriod.endTime.toISOString(), ensureArray(this.entityIds), ensureArray(this.deviceIds) ).catch((err) => { + this._error = err.message; this._subscribed = undefined; - this._error = err; }); return true; } @@ -320,7 +274,7 @@ export class HaLogbook extends LitElement { this._error = undefined; if (this._filterAlwaysEmptyResults) { - this._unsubscribeNoResults(); + this._unsubscribeAndEmptyEntries(); return; } @@ -328,7 +282,7 @@ export class HaLogbook extends LitElement { if (logbookPeriod.startTime > logbookPeriod.now) { // Time Travel not yet invented - this._unsubscribeNoResults(); + this._unsubscribeAndEmptyEntries(); return; } @@ -349,21 +303,10 @@ export class HaLogbook extends LitElement { ) : this._logbookEntries; - private _processOrQueueStreamMessage = ( - streamMessage: LogbookStreamMessage + private _processStreamMessage = ( + streamMessage: LogbookStreamMessage, + purgeBeforePythonTime: number | undefined ) => { - if (this._liveUpdatesEnabled) { - this._processStreamMessage(streamMessage); - return; - } - this._pendingStreamMessages.push(streamMessage); - }; - - private _processStreamMessage = (streamMessage: LogbookStreamMessage) => { - const purgeBeforePythonTime = - "recent" in this.time - ? findStartOfRecentTime(new Date(), this.time.recent) - : undefined; // Put newest ones on top. Reverse works in-place so // make a copy first. const newEntries = [...streamMessage.events].reverse(); diff --git a/src/panels/logbook/ha-panel-logbook.ts b/src/panels/logbook/ha-panel-logbook.ts index 84f330bb94..bcdcb548f7 100644 --- a/src/panels/logbook/ha-panel-logbook.ts +++ b/src/panels/logbook/ha-panel-logbook.ts @@ -12,17 +12,19 @@ import { } from "date-fns/esm"; import { css, html, LitElement, PropertyValues } from "lit"; import { customElement, property, state } from "lit/decorators"; +import { computeStateDomain } from "../../common/entity/compute_state_domain"; import { navigate } from "../../common/navigate"; import { createSearchParam, extractSearchParamsObject, } from "../../common/url/search-params"; +import { computeRTL } from "../../common/util/compute_rtl"; import "../../components/entity/ha-entity-picker"; +import type { HaEntityPickerEntityFilterFunc } from "../../components/entity/ha-entity-picker"; import "../../components/ha-date-range-picker"; import type { DateRangePickerRanges } from "../../components/ha-date-range-picker"; import "../../components/ha-icon-button"; import "../../components/ha-menu-button"; -import { filterLogbookCompatibleEntities } from "../../data/logbook"; import "../../layouts/ha-app-layout"; import { haStyle } from "../../resources/styles"; import { HomeAssistant } from "../../types"; @@ -38,6 +40,8 @@ export class HaPanelLogbook extends LitElement { @state() _entityIds?: string[]; + @property({ reflect: true, type: Boolean }) rtl = false; + @state() private _ranges?: DateRangePickerRanges; public constructor() { @@ -85,7 +89,7 @@ export class HaPanelLogbook extends LitElement { .label=${this.hass.localize( "ui.components.entity.entity-picker.entity" )} - .entityFilter=${filterLogbookCompatibleEntities} + .entityFilter=${this._entityFilter} @change=${this._entityPicked} >
@@ -146,6 +150,15 @@ export class HaPanelLogbook extends LitElement { this._applyURLParams(); }; + protected updated(changedProps: PropertyValues) { + if (changedProps.has("hass")) { + const oldHass = changedProps.get("hass") as HomeAssistant | undefined; + if (!oldHass || oldHass.language !== this.hass.language) { + this.rtl = computeRTL(this.hass); + } + } + } + private _applyURLParams() { const searchParams = new URLSearchParams(location.search); @@ -229,6 +242,17 @@ export class HaPanelLogbook extends LitElement { this.shadowRoot!.querySelector("ha-logbook")?.refresh(); } + private _entityFilter: HaEntityPickerEntityFilterFunc = (entity) => { + if (computeStateDomain(entity) !== "sensor") { + return true; + } + + return ( + entity.attributes.unit_of_measurement === undefined && + entity.attributes.state_class === undefined + ); + }; + static get styles() { return [ haStyle, diff --git a/src/panels/lovelace/cards/energy/hui-energy-compare-card.ts b/src/panels/lovelace/cards/energy/hui-energy-compare-card.ts index 0f8181c44c..0d49566b04 100644 --- a/src/panels/lovelace/cards/energy/hui-energy-compare-card.ts +++ b/src/panels/lovelace/cards/energy/hui-energy-compare-card.ts @@ -56,23 +56,21 @@ export class HuiEnergyCompareCard return html` - ${this.hass.localize("ui.panel.energy.compare.info", { - start: html`${formatDate(this._start!, this.hass.locale)}${dayDifference > 0 - ? ` - - ${formatDate(this._end || endOfDay(new Date()), this.hass.locale)}` - : ""}`, - end: html`${formatDate( - this._startCompare, - this.hass.locale - )}${dayDifference > 0 - ? ` - - ${formatDate(this._endCompare, this.hass.locale)}` - : ""}`, - })} + You are comparing the period + ${formatDate(this._start!, this.hass.locale)}${dayDifference > 0 + ? ` - + ${formatDate(this._end || endOfDay(new Date()), this.hass.locale)}` + : ""} + with period + ${formatDate(this._startCompare, this.hass.locale)}${dayDifference > + 0 + ? ` - + ${formatDate(this._endCompare, this.hass.locale)}` + : ""} `; } diff --git a/src/panels/lovelace/cards/energy/hui-energy-distribution-card.ts b/src/panels/lovelace/cards/energy/hui-energy-distribution-card.ts index c223a65de8..6b10b5b641 100644 --- a/src/panels/lovelace/cards/energy/hui-energy-distribution-card.ts +++ b/src/panels/lovelace/cards/energy/hui-energy-distribution-card.ts @@ -489,8 +489,8 @@ class HuiEnergyDistrubutionCard ${formatNumber(totalBatteryOut || 0, this.hass.locale, { + > + ${formatNumber(totalBatteryOut || 0, this.hass.locale, { maximumFractionDigits: 1, })} kWh ${compare - ? html`${showCosts - ? html`` - : ""} - ${formatNumber( @@ -865,7 +862,10 @@ export class HuiEnergySourcesTableCard currency: this.hass.config.currency!, } )} - ` + + ${showCosts + ? html`` + : ""}` : ""} @@ -346,7 +346,6 @@ class HuiAlarmPanelCard extends LitElement implements LovelaceCard { margin: auto; width: 100%; max-width: 300px; - direction: ltr; } #keypad mwc-button { diff --git a/src/panels/lovelace/cards/hui-area-card.ts b/src/panels/lovelace/cards/hui-area-card.ts index 64104a6335..41d5345728 100644 --- a/src/panels/lovelace/cards/hui-area-card.ts +++ b/src/panels/lovelace/cards/hui-area-card.ts @@ -3,10 +3,8 @@ import { mdiLightbulbMultiple, mdiLightbulbMultipleOff, mdiRun, - mdiThermometer, mdiToggleSwitch, mdiToggleSwitchOff, - mdiWaterAlert, mdiWaterPercent, } from "@mdi/js"; import type { HassEntity, UnsubscribeFunc } from "home-assistant-js-websocket"; @@ -63,21 +61,17 @@ const TOGGLE_DOMAINS = ["light", "switch", "fan"]; const OTHER_DOMAINS = ["camera"]; const DEVICE_CLASSES = { - sensor: ["temperature", "humidity"], - binary_sensor: ["motion", "moisture"], + sensor: ["temperature"], + binary_sensor: ["motion"], }; const DOMAIN_ICONS = { light: { on: mdiLightbulbMultiple, off: mdiLightbulbMultipleOff }, switch: { on: mdiToggleSwitch, off: mdiToggleSwitchOff }, fan: { on: domainIcon("fan"), off: domainIcon("fan") }, - sensor: { - temperature: mdiThermometer, - humidity: mdiWaterPercent, - }, + sensor: { humidity: mdiWaterPercent }, binary_sensor: { motion: mdiRun, - moisture: mdiWaterAlert, }, }; diff --git a/src/panels/lovelace/cards/hui-gauge-card.ts b/src/panels/lovelace/cards/hui-gauge-card.ts index 98bdd36f5b..4a6d1f60d5 100644 --- a/src/panels/lovelace/cards/hui-gauge-card.ts +++ b/src/panels/lovelace/cards/hui-gauge-card.ts @@ -232,7 +232,6 @@ class HuiGaugeCard extends LitElement implements LovelaceCard { return segments.map((segment) => ({ level: segment?.from, stroke: segment?.color, - label: segment?.label, })); } diff --git a/src/panels/lovelace/cards/hui-light-card.ts b/src/panels/lovelace/cards/hui-light-card.ts index 595c299785..ce5e92c062 100644 --- a/src/panels/lovelace/cards/hui-light-card.ts +++ b/src/panels/lovelace/cards/hui-light-card.ts @@ -276,12 +276,9 @@ export class HuiLightCard extends LitElement implements LovelaceCard { cursor: pointer; top: 0; right: 0; - inset-inline-start: initial; - inset-inline-end: 0; border-radius: 100%; color: var(--secondary-text-color); z-index: 1; - direction: var(--direction); } .content { diff --git a/src/panels/lovelace/cards/hui-media-control-card.ts b/src/panels/lovelace/cards/hui-media-control-card.ts index 18bf718876..f1d2793ae0 100644 --- a/src/panels/lovelace/cards/hui-media-control-card.ts +++ b/src/panels/lovelace/cards/hui-media-control-card.ts @@ -31,7 +31,6 @@ import { handleMediaControlClick, MediaPickedEvent, MediaPlayerEntity, - mediaPlayerPlayMedia, SUPPORT_BROWSE_MEDIA, SUPPORT_SEEK, SUPPORT_TURN_ON, @@ -490,15 +489,21 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard { action: "play", entityId: this._config!.entity, mediaPickedCallback: (pickedMedia: MediaPickedEvent) => - mediaPlayerPlayMedia( - this.hass, - this._config!.entity, + this._playMedia( pickedMedia.item.media_content_id, pickedMedia.item.media_content_type ), }); } + private _playMedia(media_content_id: string, media_content_type: string) { + this.hass!.callService("media_player", "play_media", { + entity_id: this._config!.entity, + media_content_id, + media_content_type, + }); + } + private _handleClick(e: MouseEvent): void { handleMediaControlClick( this.hass!, @@ -600,7 +605,6 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard { ); height: 100%; right: 0; - opacity: 1; transition: width 0.8s, opacity 0.8s linear 0.8s; } @@ -669,11 +673,6 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard { transition: padding, color; transition-duration: 0.4s; margin-left: -12px; - margin-inline-start: -12px; - margin-inline-end: initial; - padding-inline-start: 0; - padding-inline-end: 8px; - direction: var(--direction); } .controls > div { @@ -699,9 +698,6 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard { ha-icon-button.browse-media { position: absolute; right: 4px; - inset-inline-start: initial; - inset-inline-end: 4px; - direction: var(--direction); --mdc-icon-size: 24px; } @@ -718,18 +714,12 @@ export class HuiMediaControlCard extends LitElement implements LovelaceCard { .icon-name ha-state-icon { padding-right: 8px; - padding-inline-start: initial; - padding-inline-end: 8px; - direction: var(--direction); } .more-info { position: absolute; top: 4px; right: 4px; - inset-inline-start: initial; - inset-inline-end: 4px; - direction: var(--direction); } .media-info { diff --git a/src/panels/lovelace/cards/hui-thermostat-card.ts b/src/panels/lovelace/cards/hui-thermostat-card.ts index 6d6dbc7dde..564008d158 100644 --- a/src/panels/lovelace/cards/hui-thermostat-card.ts +++ b/src/panels/lovelace/cards/hui-thermostat-card.ts @@ -497,12 +497,9 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard { cursor: pointer; top: 0; right: 0; - inset-inline-end: 0px; - inset-inline-start: initial; border-radius: 100%; color: var(--secondary-text-color); z-index: 1; - direction: var(--direction); } .content { @@ -553,7 +550,6 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard { height: 50%; top: 45%; left: 50%; - direction: ltr; } #set-values { diff --git a/src/panels/lovelace/cards/hui-weather-forecast-card.ts b/src/panels/lovelace/cards/hui-weather-forecast-card.ts index 91e485d284..7ec93b41e7 100644 --- a/src/panels/lovelace/cards/hui-weather-forecast-card.ts +++ b/src/panels/lovelace/cards/hui-weather-forecast-card.ts @@ -228,21 +228,12 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard {
- ${stateObj.attributes.temperature !== undefined && - stateObj.attributes.temperature !== null - ? html` - ${formatNumber( - stateObj.attributes.temperature, - this.hass.locale - )} ${getWeatherUnit( - this.hass, - stateObj, - "temperature" - )} - ` - : html` `} + ${formatNumber( + stateObj.attributes.temperature, + this.hass.locale + )} ${getWeatherUnit(this.hass, "temperature")}
${this._config.secondary_info_attribute !== undefined @@ -264,7 +255,6 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard { "wind_speed" ? getWind( this.hass, - stateObj, stateObj.attributes.wind_speed, stateObj.attributes.wind_bearing ) @@ -277,7 +267,6 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard { )} ${getWeatherUnit( this.hass, - stateObj, this._config.secondary_info_attribute )} `} diff --git a/src/panels/lovelace/cards/types.ts b/src/panels/lovelace/cards/types.ts index bf243f624e..e6189150e1 100644 --- a/src/panels/lovelace/cards/types.ts +++ b/src/panels/lovelace/cards/types.ts @@ -185,7 +185,6 @@ export interface SeverityConfig { export interface GaugeSegment { from: number; color: string; - label?: string; } export interface GaugeCardConfig extends LovelaceCardConfig { diff --git a/src/panels/lovelace/components/hui-energy-period-selector.ts b/src/panels/lovelace/components/hui-energy-period-selector.ts index 38011288fd..6d102da24c 100644 --- a/src/panels/lovelace/components/hui-energy-period-selector.ts +++ b/src/panels/lovelace/components/hui-energy-period-selector.ts @@ -151,9 +151,7 @@ export class HuiEnergyPeriodSelector extends SubscribeMixin(LitElement) { dense outlined > - ${this.hass.localize( - "ui.panel.lovelace.components.energy_period_selector.compare" - )} + Compare data ` : html` - ${this.hass.localize( - "ui.panel.lovelace.components.energy_period_selector.compare" - )} + Compare data `}
diff --git a/src/panels/lovelace/editor/config-elements/hui-conditional-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-conditional-card-editor.ts index 2ec9ab4a01..48c6b52da0 100644 --- a/src/panels/lovelace/editor/config-elements/hui-conditional-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-conditional-card-editor.ts @@ -332,9 +332,6 @@ export class HuiConditionalCardEditor } .condition .state ha-select { margin-right: 16px; - margin-inline-end: 16px; - margin-inline-start: initial; - direction: var(--direction); } .condition .state ha-textfield { flex-grow: 1; diff --git a/src/panels/lovelace/editor/config-elements/hui-gauge-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-gauge-card-editor.ts index 2baa6c32a0..8ae5fcbf5e 100644 --- a/src/panels/lovelace/editor/config-elements/hui-gauge-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-gauge-card-editor.ts @@ -22,7 +22,6 @@ import { baseLovelaceCardConfig } from "../structs/base-card-struct"; const gaugeSegmentStruct = object({ from: number(), color: string(), - label: optional(string()), }); const cardConfigStruct = assign( diff --git a/src/panels/lovelace/editor/config-elements/hui-logbook-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-logbook-card-editor.ts index dcbc6f325b..f789c09bbe 100644 --- a/src/panels/lovelace/editor/config-elements/hui-logbook-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-logbook-card-editor.ts @@ -17,7 +17,6 @@ import type { HomeAssistant } from "../../../../types"; import type { LogbookCardConfig } from "../../cards/types"; import type { LovelaceCardEditor } from "../../types"; import { baseLovelaceCardConfig } from "../structs/base-card-struct"; -import { filterLogbookCompatibleEntities } from "../../../../data/logbook"; const cardConfigStruct = assign( baseLovelaceCardConfig, @@ -82,7 +81,6 @@ export class HuiLogbookCardEditor diff --git a/src/panels/lovelace/entity-rows/hui-input-datetime-entity-row.ts b/src/panels/lovelace/entity-rows/hui-input-datetime-entity-row.ts index c50a2b4958..f542b2ec6d 100644 --- a/src/panels/lovelace/entity-rows/hui-input-datetime-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-input-datetime-entity-row.ts @@ -125,9 +125,6 @@ class HuiInputDatetimeEntityRow extends LitElement implements LovelaceRow { return css` ha-date-input + ha-time-input { margin-left: 4px; - margin-inline-start: 4px; - margin-inline-end: initial; - direction: var(--direction); } `; } diff --git a/src/panels/lovelace/entity-rows/hui-weather-entity-row.ts b/src/panels/lovelace/entity-rows/hui-weather-entity-row.ts index 3b0d17ff37..e2e0971399 100644 --- a/src/panels/lovelace/entity-rows/hui-weather-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-weather-entity-row.ts @@ -114,9 +114,7 @@ class HuiWeatherEntityRow extends LitElement implements LovelaceRow { })} >
- ${UNAVAILABLE_STATES.includes(stateObj.state) || - stateObj.attributes.temperature === undefined || - stateObj.attributes.temperature === null + ${UNAVAILABLE_STATES.includes(stateObj.state) ? computeStateDisplay( this.hass.localize, stateObj, @@ -127,7 +125,7 @@ class HuiWeatherEntityRow extends LitElement implements LovelaceRow { stateObj.attributes.temperature, this.hass.locale )} - ${getWeatherUnit(this.hass, stateObj, "temperature")} + ${getWeatherUnit(this.hass, "temperature")} `}
diff --git a/src/panels/media-browser/ha-panel-media-browser.ts b/src/panels/media-browser/ha-panel-media-browser.ts index 2de0f6c4de..1123806c3a 100644 --- a/src/panels/media-browser/ha-panel-media-browser.ts +++ b/src/panels/media-browser/ha-panel-media-browser.ts @@ -27,7 +27,6 @@ import { BROWSER_PLAYER, MediaPickedEvent, MediaPlayerItem, - mediaPlayerPlayMedia, } from "../../data/media-player"; import { ResolvedMediaSource, @@ -209,12 +208,11 @@ class PanelMediaBrowser extends LitElement { if (this._entityId !== BROWSER_PLAYER) { this._player.showResolvingNewMediaPicked(); try { - await mediaPlayerPlayMedia( - this.hass, - this._entityId, - item.media_content_id, - item.media_content_type - ); + await this.hass!.callService("media_player", "play_media", { + entity_id: this._entityId, + media_content_id: item.media_content_id, + media_content_type: item.media_content_type, + }); } catch (err) { this._player.hideResolvingNewMediaPicked(); } diff --git a/src/state/quick-bar-mixin.ts b/src/state/quick-bar-mixin.ts index b359c70e7f..532ffbe49e 100644 --- a/src/state/quick-bar-mixin.ts +++ b/src/state/quick-bar-mixin.ts @@ -48,9 +48,9 @@ export default >(superClass: T) => private _registerShortcut() { tinykeys(window, { - KeyE: (ev) => this._showQuickBar(ev), - KeyC: (ev) => this._showQuickBar(ev, true), - KeyM: (ev) => this._createMyLink(ev), + e: (ev) => this._showQuickBar(ev), + c: (ev) => this._showQuickBar(ev, true), + m: (ev) => this._createMyLink(ev), }); } diff --git a/src/translations/en.json b/src/translations/en.json index 5d22072f24..28a71bc0c7 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -811,11 +811,6 @@ "icon_error": "Icons should be in the format 'prefix:iconname', e.g. 'mdi:home'", "entity_id": "Entity ID", "unit_of_measurement": "Unit of Measurement", - "precipitation_unit": "Precipitation unit", - "pressure_unit": "Barometric pressure unit", - "temperature_unit": "Temperature unit", - "visibility_unit": "Visibility unit", - "wind_speed_unit": "Wind speed unit", "device_class": "Show as", "device_classes": { "binary_sensor": { @@ -1015,7 +1010,7 @@ }, "domain_toggler": { "title": "Toggle Domains", - "reset_entities": "Reset Entity overrides" + "reset_entities": "Reset Entities" }, "mqtt_device_debug_info": { "title": "{device} debug info", @@ -1165,7 +1160,7 @@ }, "tags": { "main": "Tags", - "secondary": "Set up NFC tags and QR codes" + "secondary": "Setup NFC tags and QR codes" }, "people": { "main": "People", @@ -1601,7 +1596,7 @@ "frontend": "frontend-ui", "built_using": "Built using", "icons_by": "Icons by", - "frontend_version": "Frontend {version} - {type}", + "frontend_version": "Frontend version: {version} - {type}", "custom_uis": "Custom UIs:", "system_health_error": "System Health component is not loaded. Add 'system_health:' to configuration.yaml", "documentation": "Documentation", @@ -1610,15 +1605,6 @@ "system_health": { "manage": "Manage", "more_info": "more info" - }, - "items": { - "change_log": "Change Log", - "thanks": "Thanks To", - "merch": "Merchandise", - "feature": "Feature Requests", - "bug": "Bug Reports", - "help": "Help", - "license": "License" } }, "logs": { @@ -2445,16 +2431,15 @@ }, "alexa": { "title": "Alexa", - "banner": "[%key:ui::panel::config::cloud::google::banner%]", - "exposed_entities": "[%key:ui::panel::config::cloud::google::exposed_entities%]", - "not_exposed_entities": "[%key:ui::panel::config::cloud::google::not_exposed_entities%]", - "manage_defaults": "[%key:ui::panel::config::cloud::google::manage_defaults%]", - "manage_defaults_dialog_description": "[%key:ui::panel::config::cloud::google::manage_defaults_dialog_description%]", - "expose_entity": "[%key:ui::panel::config::cloud::google::expose_entity%]", - "dont_expose_entity": "[%key:ui::panel::config::cloud::google::dont_expose_entity%]", - "follow_domain": "[%key:ui::panel::config::cloud::google::follow_domain%]", - "exposed": "[%key:ui::panel::config::cloud::google::exposed%]", - "not_exposed": "[%key:ui::panel::config::cloud::google::not_exposed%]", + "banner": "Editing which entities are exposed via this UI is disabled because you have configured entity filters in configuration.yaml.", + "exposed_entities": "Exposed entities", + "not_exposed_entities": "Not exposed entities", + "manage_domains": "Manage domains", + "expose_entity": "Expose entity", + "dont_expose_entity": "Don't expose entity", + "follow_domain": "Follow domain", + "exposed": "{selected} exposed", + "not_exposed": "{selected} not exposed", "expose": "Expose to Alexa" }, "dialog_certificate": { @@ -2471,8 +2456,7 @@ "banner": "Editing which entities are exposed via this UI is disabled because you have configured entity filters in configuration.yaml.", "exposed_entities": "Exposed entities", "not_exposed_entities": "Not exposed entities", - "manage_defaults": "Manage defaults", - "manage_defaults_dialog_description": "Entities can be exposed by default based on their type.", + "manage_domains": "Manage domains", "expose_entity": "Expose entity", "dont_expose_entity": "Don't expose entity", "follow_domain": "Follow domain", @@ -3116,91 +3100,10 @@ "reinterview_device": "Re-interview Device", "heal_node": "Heal Device", "remove_failed": "Remove Failed Device", - "update_firmware": "Update Device Firmware", "highest_security": "Highest Security", "unknown": "Unknown", "zwave_plus": "Z-Wave Plus", - "zwave_plus_version": "Version {version}", - "node_statistics": "Show Device Statistics" - }, - "node_statistics": { - "title": "Device Statistics", - "commands_tx": { - "label": "Commands TX", - "tooltip": "# of commands successfully sent to the node" - }, - "commands_rx": { - "label": "Commands RX", - "tooltip": "# of commands received from the node, including responses to sent commands" - }, - "commands_dropped_tx": { - "label": "Commands Dropped TX", - "tooltip": "# of outgoing commands that were dropped because they could not be sent" - }, - "commands_dropped_rx": { - "label": "Commands Dropped RX", - "tooltip": "# of commands from the node that were dropped by the host" - }, - "timeout_response": { - "label": "Timeout Response", - "tooltip": "# of Get-type commands where the node's response did not come in time" - }, - "rtt": { - "label": "RTT", - "tooltip": "Average round-trip-time in ms of commands to this node" - }, - "rssi": { - "label": "RSSI", - "tooltip": "Average RSSI in dBm of frames received by this node" - }, - "lwr": "Last Working Route", - "nlwr": "Next to Last Working Route" - }, - "route_statistics": { - "protocol": { - "label": "Protocol", - "tooltip": "The protocol for this route", - "protocol_data_rate": { - "ZWave_9k6": "Z-Wave", - "ZWave_40k": "Z-Wave", - "ZWave_100k": "Z-Wave", - "LongRange_100k": "Z-Wave Long Range" - } - }, - "data_rate": { - "label": "Data Rate", - "tooltip": "The used data rate for this route", - "protocol_data_rate": { - "ZWave_9k6": "9.6 kbps", - "ZWave_40k": "40 kbps", - "ZWave_100k": "100 kbps", - "LongRange_100k": "100 kbps" - } - }, - "repeaters": { - "label": "Repeaters + RSSI", - "tooltip": "Which nodes are repeaters for this route and their RSSI", - "repeaters": "Repeater Device", - "rssi": "RSSI", - "direct": "None, direct connection" - }, - "rssi": { - "label": "RSSI", - "tooltip": "The RSSI of the ACK frame received by the controller" - }, - "route_failed_between": { - "label": "Route Failed Between", - "tooltip": "The nodes between which the transmission failed most recently", - "not_applicable": "N/A" - } - }, - "rssi": { - "unit": "dBm", - "rssi_error": { - "NotAvailable": "Not available", - "ReceiverSaturated": "Receiver saturated", - "NoSignalDetected": "No signal detected" - } + "zwave_plus_version": "Version {version}" }, "node_config": { "header": "Z-Wave Device Configuration", @@ -3324,43 +3227,6 @@ "in_progress": "{device} healing is in progress.", "network_heal_in_progress": "A Z-Wave network heal is already in progress. Please wait for it to finish before healing an individual device." }, - "update_firmware": { - "title": "Update Device Firmware", - "warning": "WARNING: Firmware updates can brick your device if you do not correctly follow the manufacturer's guidance. The Home Assistant and Z-Wave JS teams do not take any responsibility for any damages to your device as a result of the firmware update and will not be able to help you if you brick your device. Would you still like to continue?", - "introduction": "Select the firmware file you would like to use to update {device}.", - "upload_firmware": "Upload Firmware", - "firmware_target_intro": "Select the firmware target (0 for the Z-Wave chip, ≥1 for other chips if they exist) for this update, or uncheck the box to have the driver attempt to figure it out from the firmware file.", - "firmware_target": "Firmware Target (chip)", - "upload_failed": "Upload Failed", - "begin_update": "Begin Firmware Update", - "queued": "The firmware update is ready to be sent to {device} but the device is asleep, wake the device to start the update.", - "close_queued": "If you close this dialog, the update will continue to be queued in the background and start automatically once the device wakes up.", - "awake": "The firmware update should start being sent to {device} shortly.", - "close": "If you close this dialog, the update will continue in the background.", - "in_progress": "The firmware update on {device} is in progress ({progress}%).", - "abort": "Abort Firmware Update", - "abort_failed": "Abort Failed", - "confirm_abort": "Are you sure you want to abort the firmware update on {device}?", - "finished_status": { - "ok": "Successfully updated firmware on {device}: {message}.", - "error": "Unable to update firmware on {device}: {message}.", - "try_again": "To attempt the firmware update again, select the new firmware file you would like to use.", - "done": "The firmware update is complete! If you want to attempt another firmware update on this device, please wait until it gets re-interviewed.", - "Error_Timeout": "Timed Out", - "Error_Checksum": "Checksum Error", - "Error_TransmissionFailed": "Transmission Failed", - "Error_InvalidManufacturerID": "Invalid Manufacturer ID", - "Error_InvalidFirmwareID": "Invalid Firmware ID", - "Error_InvalidFirmwareTarget": "Invalid Firmware Target", - "Error_InvalidHeaderInformation": "Invalid Header Information", - "Error_InvalidHeaderFormat": "Invalid Header Format", - "Error_InsufficientMemory": "Insufficient Memory", - "Error_InvalidHardwareVersion": "Invalid Hardware Version", - "OK_WaitingForActivation": "Waiting for Activiation", - "OK_NoRestart": "No Restart", - "OK_RestartPending": "Restart Pending" - } - }, "logs": { "title": "Z-Wave JS Logs", "log_level": "Log Level", diff --git a/translations/README.md b/translations/README.md index ac763a0768..689b55fe9d 100644 --- a/translations/README.md +++ b/translations/README.md @@ -1,6 +1,4 @@ # Translation Resources -Translations from English into other languages are managed through [Lokalise](https://developers.home-assistant.io/docs/translations/). If you'd like to contribute, you can [join the project here](https://lokalise.co/signup/3420425759f6d6d241f598.13594006/all/). For more details, see our [translation guidelines documentation](https://developers.home-assistant.io/docs/translations/). +Translations are managed through [Lokalise](https://developers.home-assistant.io/docs/translations/). If you'd like to contribute, you can [join the project here](https://lokalise.co/signup/3420425759f6d6d241f598.13594006/all/). For more details, see our [translation guidelines documentation](https://developers.home-assistant.io/docs/translations/). -Don't make changes to these translation files directly. Instead, use `script/translations_download` to fetch the latest translations from Lokalise. - -The original English translation keys and texts are defined in `src/translations/en.json` and serve as the base for Lokalise. +Don't make changes to these files directly. Instead, use `script/translations_download` to fetch the latest translations from Lokalise. diff --git a/translations/frontend/en.json b/translations/frontend/en.json index 1c192e45aa..16d2933745 100644 --- a/translations/frontend/en.json +++ b/translations/frontend/en.json @@ -2429,10 +2429,6 @@ "title": "Entity not tracked" } } - }, - "compare":{ - "info": "You are comparing the period {start} with {end}" - } }, "entities": { @@ -3856,8 +3852,7 @@ "previous": "Previous", "today": "Today", "week": "Week", - "year": "Year", - "compare": "Compare data" + "year": "Year" }, "timestamp-display": { "invalid": "Invalid timestamp",