diff --git a/.eslintrc.json b/.eslintrc.json index b1db8a1786..7294a8b0e5 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -28,9 +28,7 @@ "__BUILD__": false, "__VERSION__": false, "__STATIC_PATH__": false, - "Polymer": true, - "webkitSpeechRecognition": false, - "ResizeObserver": false + "Polymer": true }, "env": { "browser": true, diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 8653bc9644..c753ac8479 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -6,8 +6,8 @@ on: - published env: - WHEELS_TAG: 3.7-alpine3.11 - PYTHON_VERSION: 3.7 + WHEELS_TAG: 3.8-alpine3.12 + PYTHON_VERSION: 3.8 NODE_VERSION: 12.1 jobs: diff --git a/.mocharc.cjs b/.mocharc.cjs new file mode 100644 index 0000000000..c34a155aba --- /dev/null +++ b/.mocharc.cjs @@ -0,0 +1,4 @@ +module.exports = { + require: "test-mocha/testconf.js", + timeout: 10000, +}; diff --git a/build-scripts/bundle.js b/build-scripts/bundle.js index d21b2aea1a..1183a5ce06 100644 --- a/build-scripts/bundle.js +++ b/build-scripts/bundle.js @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ const path = require("path"); const env = require("./env.js"); const paths = require("./paths.js"); @@ -53,13 +54,13 @@ module.exports.babelOptions = ({ latestBuild }) => ({ babelrc: false, presets: [ !latestBuild && [ - require("@babel/preset-env").default, + "@babel/preset-env", { useBuiltIns: "entry", corejs: "3.6", }, ], - require("@babel/preset-typescript").default, + "@babel/preset-typescript", ].filter(Boolean), plugins: [ // Part of ES2018. Converts {...a, b: 2} to Object.assign({}, a, {b: 2}) @@ -72,14 +73,9 @@ module.exports.babelOptions = ({ latestBuild }) => ({ "@babel/plugin-syntax-dynamic-import", "@babel/plugin-proposal-optional-chaining", "@babel/plugin-proposal-nullish-coalescing-operator", - [ - require("@babel/plugin-proposal-decorators").default, - { decoratorsBeforeExport: true }, - ], - [ - require("@babel/plugin-proposal-class-properties").default, - { loose: true }, - ], + ["@babel/plugin-proposal-decorators", { decoratorsBeforeExport: true }], + ["@babel/plugin-proposal-private-methods", { loose: true }], + ["@babel/plugin-proposal-class-properties", { loose: true }], ].filter(Boolean), }); diff --git a/build-scripts/env.js b/build-scripts/env.js index 8b2dea2eb4..bda99cf010 100644 --- a/build-scripts/env.js +++ b/build-scripts/env.js @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ const fs = require("fs"); const path = require("path"); const paths = require("./paths.js"); diff --git a/build-scripts/paths.js b/build-scripts/paths.js index da9d8db190..d89f5f582a 100644 --- a/build-scripts/paths.js +++ b/build-scripts/paths.js @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ const path = require("path"); module.exports = { diff --git a/build-scripts/rollup.js b/build-scripts/rollup.js index c5f8972854..7d9cf93046 100644 --- a/build-scripts/rollup.js +++ b/build-scripts/rollup.js @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ const path = require("path"); const commonjs = require("@rollup/plugin-commonjs"); @@ -32,88 +33,78 @@ const createRollupConfig = ({ publicPath, dontHash, isWDS, -}) => { - return { - /** - * @type { import("rollup").InputOptions } - */ - inputOptions: { - input: entry, - // Some entry points contain no JavaScript. This setting silences a warning about that. - // https://rollupjs.org/guide/en/#preserveentrysignatures - preserveEntrySignatures: false, - plugins: [ - ignore({ - files: bundle.emptyPackages({ latestBuild }), +}) => ({ + /** + * @type { import("rollup").InputOptions } + */ + inputOptions: { + input: entry, + // Some entry points contain no JavaScript. This setting silences a warning about that. + // https://rollupjs.org/guide/en/#preserveentrysignatures + preserveEntrySignatures: false, + plugins: [ + ignore({ + files: bundle.emptyPackages({ latestBuild }), + }), + resolve({ + extensions, + preferBuiltins: false, + browser: true, + rootDir: paths.polymer_dir, + }), + commonjs(), + json(), + babel({ + ...bundle.babelOptions({ latestBuild }), + extensions, + exclude: bundle.babelExclude(), + babelHelpers: isWDS ? "inline" : "bundled", + }), + string({ + // Import certain extensions as strings + include: [path.join(paths.polymer_dir, "node_modules/**/*.css")], + }), + replace(bundle.definedVars({ isProdBuild, latestBuild, defineOverlay })), + !isWDS && + manifest({ + publicPath, }), - resolve({ - extensions, - preferBuiltins: false, - browser: true, - rootDir: paths.polymer_dir, + !isWDS && worker(), + !isWDS && dontHashPlugin({ dontHash }), + !isWDS && isProdBuild && terser(bundle.terserOptions(latestBuild)), + !isWDS && + isStatsBuild && + visualizer({ + // https://github.com/btd/rollup-plugin-visualizer#options + open: true, + sourcemap: true, }), - commonjs({ - namedExports: { - "js-yaml": ["safeDump", "safeLoad"], - }, - }), - json(), - babel({ - ...bundle.babelOptions({ latestBuild }), - extensions, - exclude: bundle.babelExclude(), - babelHelpers: isWDS ? "inline" : "bundled", - }), - string({ - // Import certain extensions as strings - include: [path.join(paths.polymer_dir, "node_modules/**/*.css")], - }), - replace( - bundle.definedVars({ isProdBuild, latestBuild, defineOverlay }) - ), - !isWDS && - manifest({ - publicPath, - }), - !isWDS && worker(), - !isWDS && dontHashPlugin({ dontHash }), - !isWDS && isProdBuild && terser(bundle.terserOptions(latestBuild)), - !isWDS && - isStatsBuild && - visualizer({ - // https://github.com/btd/rollup-plugin-visualizer#options - open: true, - sourcemap: true, - }), - ].filter(Boolean), - }, - /** - * @type { import("rollup").OutputOptions } - */ - outputOptions: { - // https://rollupjs.org/guide/en/#outputdir - dir: outputPath, - // https://rollupjs.org/guide/en/#outputformat - format: latestBuild ? "es" : "systemjs", - // https://rollupjs.org/guide/en/#outputexternallivebindings - externalLiveBindings: false, - // https://rollupjs.org/guide/en/#outputentryfilenames - // https://rollupjs.org/guide/en/#outputchunkfilenames - // https://rollupjs.org/guide/en/#outputassetfilenames - entryFileNames: - isProdBuild && !isStatsBuild ? "[name]-[hash].js" : "[name].js", - chunkFileNames: - isProdBuild && !isStatsBuild ? "c.[hash].js" : "[name].js", - assetFileNames: - isProdBuild && !isStatsBuild ? "a.[hash].js" : "[name].js", - // https://rollupjs.org/guide/en/#outputsourcemap - sourcemap: isProdBuild ? true : "inline", - }, - }; -}; + ].filter(Boolean), + }, + /** + * @type { import("rollup").OutputOptions } + */ + outputOptions: { + // https://rollupjs.org/guide/en/#outputdir + dir: outputPath, + // https://rollupjs.org/guide/en/#outputformat + format: latestBuild ? "es" : "systemjs", + // https://rollupjs.org/guide/en/#outputexternallivebindings + externalLiveBindings: false, + // https://rollupjs.org/guide/en/#outputentryfilenames + // https://rollupjs.org/guide/en/#outputchunkfilenames + // https://rollupjs.org/guide/en/#outputassetfilenames + entryFileNames: + isProdBuild && !isStatsBuild ? "[name]-[hash].js" : "[name].js", + chunkFileNames: isProdBuild && !isStatsBuild ? "c.[hash].js" : "[name].js", + assetFileNames: isProdBuild && !isStatsBuild ? "a.[hash].js" : "[name].js", + // https://rollupjs.org/guide/en/#outputsourcemap + sourcemap: isProdBuild ? true : "inline", + }, +}); -const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild, isWDS }) => { - return createRollupConfig( +const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild, isWDS }) => + createRollupConfig( bundle.config.app({ isProdBuild, latestBuild, @@ -121,31 +112,24 @@ const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild, isWDS }) => { isWDS, }) ); -}; -const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => { - return createRollupConfig( +const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => + createRollupConfig( bundle.config.demo({ isProdBuild, latestBuild, isStatsBuild, }) ); -}; -const createCastConfig = ({ isProdBuild, latestBuild }) => { - return createRollupConfig(bundle.config.cast({ isProdBuild, latestBuild })); -}; +const createCastConfig = ({ isProdBuild, latestBuild }) => + createRollupConfig(bundle.config.cast({ isProdBuild, latestBuild })); -const createHassioConfig = ({ isProdBuild, latestBuild }) => { - return createRollupConfig(bundle.config.hassio({ isProdBuild, latestBuild })); -}; +const createHassioConfig = ({ isProdBuild, latestBuild }) => + createRollupConfig(bundle.config.hassio({ isProdBuild, latestBuild })); -const createGalleryConfig = ({ isProdBuild, latestBuild }) => { - return createRollupConfig( - bundle.config.gallery({ isProdBuild, latestBuild }) - ); -}; +const createGalleryConfig = ({ isProdBuild, latestBuild }) => + createRollupConfig(bundle.config.gallery({ isProdBuild, latestBuild })); module.exports = { createAppConfig, diff --git a/build-scripts/util.js b/build-scripts/util.js index 23efdfb229..91dee49ea3 100644 --- a/build-scripts/util.js +++ b/build-scripts/util.js @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ const path = require("path"); const fs = require("fs"); diff --git a/build-scripts/webpack.js b/build-scripts/webpack.js index e39c3d9ea7..d3e50ebd78 100644 --- a/build-scripts/webpack.js +++ b/build-scripts/webpack.js @@ -1,9 +1,10 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ const webpack = require("webpack"); const path = require("path"); const TerserPlugin = require("terser-webpack-plugin"); const { WebpackManifestPlugin } = require("webpack-manifest-plugin"); const paths = require("./paths.js"); -const bundle = require("./bundle"); +const bundle = require("./bundle.js"); const log = require("fancy-log"); class LogStartCompilePlugin { @@ -94,6 +95,7 @@ const createWebpackConfig = ({ ? path.resolve(context, resource) : require.resolve(resource); } catch (err) { + // eslint-disable-next-line no-console console.error( "Error in Home Assistant ignore plugin", resource, @@ -115,7 +117,7 @@ const createWebpackConfig = ({ new webpack.NormalModuleReplacementPlugin( new RegExp( require.resolve( - "lit-virtualizer/lib/uni-virtualizer/lib/polyfillLoaders/EventTarget.js" + "@lit-labs/virtualizer/lib/uni-virtualizer/lib/polyfillLoaders/EventTarget.js" ) ), path.resolve(paths.polymer_dir, "src/resources/EventTarget-ponyfill.js") @@ -124,6 +126,11 @@ const createWebpackConfig = ({ ].filter(Boolean), resolve: { extensions: [".ts", ".js", ".json"], + alias: { + "lit/decorators$": "lit/decorators.js", + "lit/directive$": "lit/directive.js", + "lit/polyfill-support$": "lit/polyfill-support.js", + }, }, output: { filename: ({ chunk }) => { @@ -144,33 +151,24 @@ const createWebpackConfig = ({ }; }; -const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => { - return createWebpackConfig( +const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => + createWebpackConfig( bundle.config.app({ isProdBuild, latestBuild, isStatsBuild }) ); -}; -const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => { - return createWebpackConfig( +const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => + createWebpackConfig( bundle.config.demo({ isProdBuild, latestBuild, isStatsBuild }) ); -}; -const createCastConfig = ({ isProdBuild, latestBuild }) => { - return createWebpackConfig(bundle.config.cast({ isProdBuild, latestBuild })); -}; +const createCastConfig = ({ isProdBuild, latestBuild }) => + createWebpackConfig(bundle.config.cast({ isProdBuild, latestBuild })); -const createHassioConfig = ({ isProdBuild, latestBuild }) => { - return createWebpackConfig( - bundle.config.hassio({ isProdBuild, latestBuild }) - ); -}; +const createHassioConfig = ({ isProdBuild, latestBuild }) => + createWebpackConfig(bundle.config.hassio({ isProdBuild, latestBuild })); -const createGalleryConfig = ({ isProdBuild, latestBuild }) => { - return createWebpackConfig( - bundle.config.gallery({ isProdBuild, latestBuild }) - ); -}; +const createGalleryConfig = ({ isProdBuild, latestBuild }) => + createWebpackConfig(bundle.config.gallery({ isProdBuild, latestBuild })); module.exports = { createAppConfig, diff --git a/cast/src/launcher/layout/hc-cast.ts b/cast/src/launcher/layout/hc-cast.ts index c91e38f2af..1f349f6371 100644 --- a/cast/src/launcher/layout/hc-cast.ts +++ b/cast/src/launcher/layout/hc-cast.ts @@ -1,16 +1,9 @@ +import "@material/mwc-button/mwc-button"; import "@polymer/paper-item/paper-icon-item"; import "@polymer/paper-listbox/paper-listbox"; import { Auth, Connection } from "home-assistant-js-websocket"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - internalProperty, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { CastManager } from "../../../../src/cast/cast_manager"; import { castSendShowLovelaceView, @@ -32,7 +25,6 @@ import { import "../../../../src/layouts/hass-loading-screen"; import { generateDefaultViewConfig } from "../../../../src/panels/lovelace/common/generate-lovelace-config"; import "./hc-layout"; -import "@material/mwc-button/mwc-button"; @customElement("hc-cast") class HcCast extends LitElement { @@ -42,9 +34,9 @@ class HcCast extends LitElement { @property() public castManager!: CastManager; - @internalProperty() private askWrite = false; + @state() private askWrite = false; - @internalProperty() private lovelaceConfig?: LovelaceConfig | null; + @state() private lovelaceConfig?: LovelaceConfig | null; protected render(): TemplateResult { if (this.lovelaceConfig === undefined) { @@ -204,7 +196,7 @@ class HcCast extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` .center-item { display: flex; diff --git a/cast/src/launcher/layout/hc-connect.ts b/cast/src/launcher/layout/hc-connect.ts index 518c582f2c..dd87cbef64 100644 --- a/cast/src/launcher/layout/hc-connect.ts +++ b/cast/src/launcher/layout/hc-connect.ts @@ -11,15 +11,8 @@ import { getAuth, getAuthOptions, } from "home-assistant-js-websocket"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - TemplateResult, - internalProperty, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, state } from "lit/decorators"; import { CastManager, getCastManager } from "../../../../src/cast/cast_manager"; import { castSendShowDemo } from "../../../../src/cast/receiver_messages"; import { @@ -60,19 +53,19 @@ const INTRO = html` @customElement("hc-connect") export class HcConnect extends LitElement { - @internalProperty() private loading = false; + @state() private loading = false; // If we had stored credentials but we cannot connect, // show a screen asking retry or logout. - @internalProperty() private cannotConnect = false; + @state() private cannotConnect = false; - @internalProperty() private error?: string | TemplateResult; + @state() private error?: string | TemplateResult; - @internalProperty() private auth?: Auth; + @state() private auth?: Auth; - @internalProperty() private connection?: Connection; + @state() private connection?: Connection; - @internalProperty() private castManager?: CastManager | null; + @state() private castManager?: CastManager | null; private openDemo = false; @@ -297,7 +290,7 @@ export class HcConnect extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` .card-content a { color: var(--primary-color); diff --git a/cast/src/launcher/layout/hc-layout.ts b/cast/src/launcher/layout/hc-layout.ts index 76a3af25ef..0d0e8cdb0d 100644 --- a/cast/src/launcher/layout/hc-layout.ts +++ b/cast/src/launcher/layout/hc-layout.ts @@ -4,15 +4,8 @@ import { getUser, HassUser, } from "home-assistant-js-websocket"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import "../../../../src/components/ha-card"; @customElement("hc-layout") @@ -69,7 +62,7 @@ class HcLayout extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { display: flex; diff --git a/cast/src/receiver/layout/hc-demo.ts b/cast/src/receiver/layout/hc-demo.ts index b4ddc41a67..a5822ebe97 100644 --- a/cast/src/receiver/layout/hc-demo.ts +++ b/cast/src/receiver/layout/hc-demo.ts @@ -1,10 +1,5 @@ -import { - customElement, - html, - internalProperty, - property, - TemplateResult, -} from "lit-element"; +import { html, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { mockHistory } from "../../../../demo/src/stubs/history"; import { LovelaceConfig } from "../../../../src/data/lovelace"; import { @@ -21,7 +16,7 @@ import "./hc-lovelace"; class HcDemo extends HassElement { @property({ attribute: false }) public lovelacePath!: string; - @internalProperty() private _lovelaceConfig?: LovelaceConfig; + @state() private _lovelaceConfig?: LovelaceConfig; protected render(): TemplateResult { if (!this._lovelaceConfig) { @@ -38,10 +33,10 @@ class HcDemo extends HassElement { protected firstUpdated(changedProps) { super.firstUpdated(changedProps); - this._initialize(); + this._initializeHass(); } - private async _initialize() { + private async _initializeHass() { const initial: Partial = { // Override updateHass so that the correct hass lifecycle methods are called updateHass: (hassUpdate: Partial) => diff --git a/cast/src/receiver/layout/hc-launch-screen.ts b/cast/src/receiver/layout/hc-launch-screen.ts index 603f70f655..a4d6aa5e4e 100644 --- a/cast/src/receiver/layout/hc-launch-screen.ts +++ b/cast/src/receiver/layout/hc-launch-screen.ts @@ -1,12 +1,5 @@ -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import { HomeAssistant } from "../../../../src/types"; @customElement("hc-launch-screen") @@ -29,7 +22,7 @@ class HcLaunchScreen extends LitElement { `; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { display: block; diff --git a/cast/src/receiver/layout/hc-lovelace.ts b/cast/src/receiver/layout/hc-lovelace.ts index ba94b42394..1b13e18976 100644 --- a/cast/src/receiver/layout/hc-lovelace.ts +++ b/cast/src/receiver/layout/hc-lovelace.ts @@ -1,12 +1,5 @@ -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import { LovelaceConfig } from "../../../../src/data/lovelace"; import { Lovelace } from "../../../../src/panels/lovelace/types"; import "../../../../src/panels/lovelace/views/hui-view"; @@ -91,7 +84,7 @@ class HcLovelace extends LitElement { return undefined; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { min-height: 100vh; diff --git a/cast/src/receiver/layout/hc-main.ts b/cast/src/receiver/layout/hc-main.ts index e8623dfa65..bc4a9320ea 100644 --- a/cast/src/receiver/layout/hc-main.ts +++ b/cast/src/receiver/layout/hc-main.ts @@ -3,12 +3,8 @@ import { getAuth, UnsubscribeFunc, } from "home-assistant-js-websocket"; -import { - customElement, - html, - internalProperty, - TemplateResult, -} from "lit-element"; +import { html, TemplateResult } from "lit"; +import { customElement, state } from "lit/decorators"; import { CAST_NS } from "../../../../src/cast/const"; import { ConnectMessage, @@ -36,13 +32,13 @@ let resourcesLoaded = false; @customElement("hc-main") export class HcMain extends HassElement { - @internalProperty() private _showDemo = false; + @state() private _showDemo = false; - @internalProperty() private _lovelaceConfig?: LovelaceConfig; + @state() private _lovelaceConfig?: LovelaceConfig; - @internalProperty() private _lovelacePath: string | number | null = null; + @state() private _lovelacePath: string | number | null = null; - @internalProperty() private _error?: string; + @state() private _error?: string; private _unsubLovelace?: UnsubscribeFunc; diff --git a/demo/src/configs/teachingbirds/lovelace.ts b/demo/src/configs/teachingbirds/lovelace.ts index 943231353a..9fbf612023 100644 --- a/demo/src/configs/teachingbirds/lovelace.ts +++ b/demo/src/configs/teachingbirds/lovelace.ts @@ -440,57 +440,43 @@ export const demoLovelaceTeachingbirds: DemoConfig["lovelace"] = () => ({ type: "horizontal-stack", }, { + type: "grid", + columns: 2, cards: [ { - cards: [ - { - graph: "line", - type: "sensor", - entity: "sensor.temperature_bedroom", - }, - { - graph: "line", - type: "sensor", - name: "S's room", - entity: "sensor.temperature_stefan", - }, - ], - type: "horizontal-stack", + graph: "line", + type: "sensor", + entity: "sensor.temperature_bedroom", }, { - cards: [ - { - graph: "line", - type: "sensor", - entity: "sensor.temperature_passage", - }, - { - graph: "line", - type: "sensor", - name: "Bathroom", - entity: "sensor.temperature_downstairs_bathroom", - }, - ], - type: "horizontal-stack", + graph: "line", + type: "sensor", + name: "S's room", + entity: "sensor.temperature_stefan", }, { - cards: [ - { - graph: "line", - type: "sensor", - entity: "sensor.temperature_storage", - }, - { - graph: "line", - type: "sensor", - name: "Refrigerator", - entity: "sensor.refrigerator", - }, - ], - type: "horizontal-stack", + graph: "line", + type: "sensor", + entity: "sensor.temperature_passage", + }, + { + graph: "line", + type: "sensor", + name: "Bathroom", + entity: "sensor.temperature_downstairs_bathroom", + }, + { + graph: "line", + type: "sensor", + entity: "sensor.temperature_storage", + }, + { + graph: "line", + type: "sensor", + name: "Refrigerator", + entity: "sensor.refrigerator", }, ], - type: "vertical-stack", }, { entities: [ diff --git a/demo/src/custom-cards/card-modder.js b/demo/src/custom-cards/card-modder.js index c915a95668..6ada982486 100644 --- a/demo/src/custom-cards/card-modder.js +++ b/demo/src/custom-cards/card-modder.js @@ -1,5 +1,5 @@ /* eslint-disable */ -import { LitElement } from "lit-element"; +import { LitElement } from "lit"; import "./card-tools"; class CardModder extends LitElement { diff --git a/demo/src/custom-cards/card-tools.js b/demo/src/custom-cards/card-tools.js index 39cf7598fb..27b37cabeb 100644 --- a/demo/src/custom-cards/card-tools.js +++ b/demo/src/custom-cards/card-tools.js @@ -1,5 +1,5 @@ /* eslint-disable */ -import { html, LitElement } from "lit-element"; +import { html, LitElement } from "lit"; if (!window.cardTools) { const version = 0.2; diff --git a/demo/src/custom-cards/cast-demo-row.ts b/demo/src/custom-cards/cast-demo-row.ts index ea0f3033a3..8fbecb4eb5 100644 --- a/demo/src/custom-cards/cast-demo-row.ts +++ b/demo/src/custom-cards/cast-demo-row.ts @@ -1,12 +1,5 @@ -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, state } from "lit/decorators"; import { CastManager } from "../../../src/cast/cast_manager"; import { castSendShowDemo } from "../../../src/cast/receiver_messages"; import "../../../src/components/ha-icon"; @@ -20,7 +13,7 @@ import { HomeAssistant } from "../../../src/types"; class CastDemoRow extends LitElement implements LovelaceRow { public hass!: HomeAssistant; - @internalProperty() private _castManager?: CastManager | null; + @state() private _castManager?: CastManager | null; public setConfig(_config: CastConfig): void { // No config possible. @@ -73,7 +66,7 @@ class CastDemoRow extends LitElement implements LovelaceRow { this.style.display = this._castManager ? "" : "none"; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { display: flex; diff --git a/demo/src/custom-cards/ha-demo-card.ts b/demo/src/custom-cards/ha-demo-card.ts index 8da813d7bd..fcd48a90ab 100644 --- a/demo/src/custom-cards/ha-demo-card.ts +++ b/demo/src/custom-cards/ha-demo-card.ts @@ -1,14 +1,7 @@ import "@material/mwc-button"; -import { - css, - CSSResult, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import { until } from "lit-html/directives/until"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { property, state } from "lit/decorators"; +import { until } from "lit/directives/until"; import "../../../src/components/ha-card"; import "../../../src/components/ha-circular-progress"; import { LovelaceCardConfig } from "../../../src/data/lovelace"; @@ -26,7 +19,7 @@ export class HADemoCard extends LitElement implements LovelaceCard { @property({ attribute: false }) public hass!: MockHomeAssistant; - @internalProperty() private _switching?: boolean; + @state() private _switching?: boolean; private _hidden = localStorage.hide_demo_card; @@ -113,7 +106,7 @@ export class HADemoCard extends LitElement implements LovelaceCard { } } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ css` a { diff --git a/demo/src/ha-demo.ts b/demo/src/ha-demo.ts index 921420e45b..349968e28d 100644 --- a/demo/src/ha-demo.ts +++ b/demo/src/ha-demo.ts @@ -22,9 +22,9 @@ import { mockTemplate } from "./stubs/template"; import { mockTranslations } from "./stubs/translations"; class HaDemo extends HomeAssistantAppEl { - protected async _initialize() { + protected async _initializeHass() { const initial: Partial = { - panelUrl: (this as any).panelUrl, + panelUrl: (this as any)._panelUrl, // Override updateHass so that the correct hass lifecycle methods are called updateHass: (hassUpdate: Partial) => this._updateHass(hassUpdate), @@ -70,7 +70,7 @@ class HaDemo extends HomeAssistantAppEl { } e.preventDefault(); - navigate(this, href); + navigate(href); }, { capture: true } ); diff --git a/gallery/src/components/demo-card.js b/gallery/src/components/demo-card.js index c6137fc9ed..4d9ce53899 100644 --- a/gallery/src/components/demo-card.js +++ b/gallery/src/components/demo-card.js @@ -1,7 +1,7 @@ import { html } from "@polymer/polymer/lib/utils/html-tag"; /* eslint-plugin-disable lit */ import { PolymerElement } from "@polymer/polymer/polymer-element"; -import { safeLoad } from "js-yaml"; +import { load } from "js-yaml"; import { createCardElement } from "../../../src/panels/lovelace/create-element/create-card-element"; class DemoCard extends PolymerElement { @@ -80,7 +80,7 @@ class DemoCard extends PolymerElement { card.removeChild(card.lastChild); } - const el = this._createCardElement(safeLoad(config.config)[0]); + const el = this._createCardElement(load(config.config)[0]); card.appendChild(el); this._getSize(el); } diff --git a/gallery/src/demos/demo-automation-describe-action.ts b/gallery/src/demos/demo-automation-describe-action.ts index 642bcfb58c..ea9b13fff5 100644 --- a/gallery/src/demos/demo-automation-describe-action.ts +++ b/gallery/src/demos/demo-automation-describe-action.ts @@ -1,12 +1,6 @@ -import { safeDump } from "js-yaml"; -import { - customElement, - html, - css, - LitElement, - TemplateResult, - property, -} from "lit-element"; +import { dump } from "js-yaml"; +import { html, css, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import "../../../src/components/ha-card"; import { describeAction } from "../../../src/data/script_i18n"; import { provideHass } from "../../../src/fake_data/provide_hass"; @@ -62,7 +56,7 @@ export class DemoAutomationDescribeAction extends LitElement { (conf) => html`
${describeAction(this.hass, conf as any)} -
${safeDump(conf)}
+
${dump(conf)}
` )} diff --git a/gallery/src/demos/demo-automation-describe-condition.ts b/gallery/src/demos/demo-automation-describe-condition.ts index ef57b9a1e5..60f42d78e2 100644 --- a/gallery/src/demos/demo-automation-describe-condition.ts +++ b/gallery/src/demos/demo-automation-describe-condition.ts @@ -1,11 +1,6 @@ -import { safeDump } from "js-yaml"; -import { - customElement, - html, - css, - LitElement, - TemplateResult, -} from "lit-element"; +import { dump } from "js-yaml"; +import { html, css, LitElement, TemplateResult } from "lit"; +import { customElement } from "lit/decorators"; import "../../../src/components/ha-card"; import { describeCondition } from "../../../src/data/automation_i18n"; @@ -31,7 +26,7 @@ export class DemoAutomationDescribeCondition extends LitElement { (conf) => html`
${describeCondition(conf as any)} -
${safeDump(conf)}
+
${dump(conf)}
` )} diff --git a/gallery/src/demos/demo-automation-describe-trigger.ts b/gallery/src/demos/demo-automation-describe-trigger.ts index f870db44d7..8a409386c0 100644 --- a/gallery/src/demos/demo-automation-describe-trigger.ts +++ b/gallery/src/demos/demo-automation-describe-trigger.ts @@ -1,11 +1,6 @@ -import { safeDump } from "js-yaml"; -import { - customElement, - html, - css, - LitElement, - TemplateResult, -} from "lit-element"; +import { dump } from "js-yaml"; +import { html, css, LitElement, TemplateResult } from "lit"; +import { customElement } from "lit/decorators"; import "../../../src/components/ha-card"; import { describeTrigger } from "../../../src/data/automation_i18n"; @@ -34,7 +29,7 @@ export class DemoAutomationDescribeTrigger extends LitElement { (conf) => html`
${describeTrigger(conf as any)} -
${safeDump(conf)}
+
${dump(conf)}
` )} diff --git a/gallery/src/demos/demo-automation-trace-timeline.ts b/gallery/src/demos/demo-automation-trace-timeline.ts index 740c589023..50461fca6d 100644 --- a/gallery/src/demos/demo-automation-trace-timeline.ts +++ b/gallery/src/demos/demo-automation-trace-timeline.ts @@ -1,11 +1,5 @@ -import { - customElement, - html, - css, - LitElement, - TemplateResult, - property, -} from "lit-element"; +import { html, css, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import "../../../src/components/ha-card"; import "../../../src/components/trace/hat-script-graph"; import "../../../src/components/trace/hat-trace-timeline"; diff --git a/gallery/src/demos/demo-automation-trace.ts b/gallery/src/demos/demo-automation-trace.ts index 8187c01630..7b96d81c00 100644 --- a/gallery/src/demos/demo-automation-trace.ts +++ b/gallery/src/demos/demo-automation-trace.ts @@ -1,12 +1,4 @@ -import { - customElement, - html, - css, - LitElement, - TemplateResult, - internalProperty, - property, -} from "lit-element"; +import { html, css, LitElement, TemplateResult } from "lit"; import "../../../src/components/ha-card"; import "../../../src/components/trace/hat-script-graph"; import "../../../src/components/trace/hat-trace-timeline"; @@ -15,6 +7,7 @@ import { HomeAssistant } from "../../../src/types"; import { DemoTrace } from "../data/traces/types"; import { basicTrace } from "../data/traces/basic_trace"; import { motionLightTrace } from "../data/traces/motion-light-trace"; +import { customElement, property, state } from "lit/decorators"; const traces: DemoTrace[] = [basicTrace, motionLightTrace]; @@ -22,7 +15,7 @@ const traces: DemoTrace[] = [basicTrace, motionLightTrace]; export class DemoAutomationTrace extends LitElement { @property({ attribute: false }) hass?: HomeAssistant; - @internalProperty() private _selected = {}; + @state() private _selected = {}; protected render(): TemplateResult { if (!this.hass) { diff --git a/gallery/src/demos/demo-hui-alarm-panel-card.ts b/gallery/src/demos/demo-hui-alarm-panel-card.ts index 0042b31874..be9a5a22e2 100644 --- a/gallery/src/demos/demo-hui-alarm-panel-card.ts +++ b/gallery/src/demos/demo-hui-alarm-panel-card.ts @@ -1,11 +1,5 @@ -import { - customElement, - html, - LitElement, - PropertyValues, - query, - TemplateResult, -} from "lit-element"; +import { html, LitElement, PropertyValues, TemplateResult } from "lit"; +import { customElement, query } from "lit/decorators"; import { getEntity } from "../../../src/fake_data/entity"; import { provideHass } from "../../../src/fake_data/provide_hass"; import "../components/demo-cards"; diff --git a/gallery/src/demos/demo-hui-conditional-card.ts b/gallery/src/demos/demo-hui-conditional-card.ts index 9d91c76f88..5977ee3c09 100644 --- a/gallery/src/demos/demo-hui-conditional-card.ts +++ b/gallery/src/demos/demo-hui-conditional-card.ts @@ -1,11 +1,5 @@ -import { - customElement, - html, - LitElement, - PropertyValues, - query, - TemplateResult, -} from "lit-element"; +import { html, LitElement, PropertyValues, TemplateResult } from "lit"; +import { customElement, query } from "lit/decorators"; import { getEntity } from "../../../src/fake_data/entity"; import { provideHass } from "../../../src/fake_data/provide_hass"; import "../components/demo-cards"; diff --git a/gallery/src/demos/demo-hui-entities-card.ts b/gallery/src/demos/demo-hui-entities-card.ts index 8f030ec6cb..c6ed878c0f 100644 --- a/gallery/src/demos/demo-hui-entities-card.ts +++ b/gallery/src/demos/demo-hui-entities-card.ts @@ -1,11 +1,5 @@ -import { - customElement, - html, - LitElement, - PropertyValues, - query, - TemplateResult, -} from "lit-element"; +import { html, LitElement, PropertyValues, TemplateResult } from "lit"; +import { customElement, query } from "lit/decorators"; import { getEntity } from "../../../src/fake_data/entity"; import { provideHass } from "../../../src/fake_data/provide_hass"; import "../components/demo-cards"; diff --git a/gallery/src/demos/demo-hui-entity-button-card.ts b/gallery/src/demos/demo-hui-entity-button-card.ts index 56d7018e36..320eb8f8c1 100644 --- a/gallery/src/demos/demo-hui-entity-button-card.ts +++ b/gallery/src/demos/demo-hui-entity-button-card.ts @@ -1,11 +1,5 @@ -import { - customElement, - html, - LitElement, - PropertyValues, - query, - TemplateResult, -} from "lit-element"; +import { html, LitElement, PropertyValues, TemplateResult } from "lit"; +import { customElement, query } from "lit/decorators"; import { getEntity } from "../../../src/fake_data/entity"; import { provideHass } from "../../../src/fake_data/provide_hass"; import "../components/demo-cards"; diff --git a/gallery/src/demos/demo-hui-entity-filter-card.ts b/gallery/src/demos/demo-hui-entity-filter-card.ts index 309e43f7dd..3a0162ae7b 100644 --- a/gallery/src/demos/demo-hui-entity-filter-card.ts +++ b/gallery/src/demos/demo-hui-entity-filter-card.ts @@ -1,11 +1,5 @@ -import { - customElement, - html, - LitElement, - PropertyValues, - query, - TemplateResult, -} from "lit-element"; +import { html, LitElement, PropertyValues, TemplateResult } from "lit"; +import { customElement, query } from "lit/decorators"; import { getEntity } from "../../../src/fake_data/entity"; import { provideHass } from "../../../src/fake_data/provide_hass"; import "../components/demo-cards"; diff --git a/gallery/src/demos/demo-hui-gauge-card.ts b/gallery/src/demos/demo-hui-gauge-card.ts index 659955354b..fdcf07188d 100644 --- a/gallery/src/demos/demo-hui-gauge-card.ts +++ b/gallery/src/demos/demo-hui-gauge-card.ts @@ -1,11 +1,5 @@ -import { - customElement, - html, - LitElement, - PropertyValues, - query, - TemplateResult, -} from "lit-element"; +import { html, LitElement, PropertyValues, TemplateResult } from "lit"; +import { customElement, query } from "lit/decorators"; import { getEntity } from "../../../src/fake_data/entity"; import { provideHass } from "../../../src/fake_data/provide_hass"; import "../components/demo-cards"; diff --git a/gallery/src/demos/demo-hui-glance-card.ts b/gallery/src/demos/demo-hui-glance-card.ts index 9f407307eb..c078ba5f61 100644 --- a/gallery/src/demos/demo-hui-glance-card.ts +++ b/gallery/src/demos/demo-hui-glance-card.ts @@ -1,11 +1,5 @@ -import { - customElement, - html, - LitElement, - PropertyValues, - query, - TemplateResult, -} from "lit-element"; +import { html, LitElement, PropertyValues, TemplateResult } from "lit"; +import { customElement, query } from "lit/decorators"; import { getEntity } from "../../../src/fake_data/entity"; import { provideHass } from "../../../src/fake_data/provide_hass"; import "../components/demo-cards"; diff --git a/gallery/src/demos/demo-hui-grid-and-stack-card.ts b/gallery/src/demos/demo-hui-grid-and-stack-card.ts index 4891d6626e..6b743b243f 100644 --- a/gallery/src/demos/demo-hui-grid-and-stack-card.ts +++ b/gallery/src/demos/demo-hui-grid-and-stack-card.ts @@ -1,11 +1,5 @@ -import { - customElement, - html, - LitElement, - PropertyValues, - query, - TemplateResult, -} from "lit-element"; +import { html, LitElement, PropertyValues, TemplateResult } from "lit"; +import { customElement, query } from "lit/decorators"; import { mockHistory } from "../../../demo/src/stubs/history"; import { getEntity } from "../../../src/fake_data/entity"; import { provideHass } from "../../../src/fake_data/provide_hass"; diff --git a/gallery/src/demos/demo-hui-iframe-card.ts b/gallery/src/demos/demo-hui-iframe-card.ts index f4497e9428..811d858e44 100644 --- a/gallery/src/demos/demo-hui-iframe-card.ts +++ b/gallery/src/demos/demo-hui-iframe-card.ts @@ -1,4 +1,5 @@ -import { customElement, html, LitElement, TemplateResult } from "lit-element"; +import { html, LitElement, TemplateResult } from "lit"; +import { customElement } from "lit/decorators"; import "../components/demo-cards"; const CONFIGS = [ diff --git a/gallery/src/demos/demo-hui-light-card.ts b/gallery/src/demos/demo-hui-light-card.ts index 26c419f9e5..8cae0ff9d7 100644 --- a/gallery/src/demos/demo-hui-light-card.ts +++ b/gallery/src/demos/demo-hui-light-card.ts @@ -1,11 +1,5 @@ -import { - customElement, - html, - LitElement, - PropertyValues, - query, - TemplateResult, -} from "lit-element"; +import { html, LitElement, PropertyValues, TemplateResult } from "lit"; +import { customElement, query } from "lit/decorators"; import { getEntity } from "../../../src/fake_data/entity"; import { provideHass } from "../../../src/fake_data/provide_hass"; import "../components/demo-cards"; diff --git a/gallery/src/demos/demo-hui-map-card.ts b/gallery/src/demos/demo-hui-map-card.ts index ccb47deabb..68912a6e77 100644 --- a/gallery/src/demos/demo-hui-map-card.ts +++ b/gallery/src/demos/demo-hui-map-card.ts @@ -1,11 +1,5 @@ -import { - customElement, - html, - LitElement, - PropertyValues, - query, - TemplateResult, -} from "lit-element"; +import { html, LitElement, PropertyValues, TemplateResult } from "lit"; +import { customElement, query } from "lit/decorators"; import { getEntity } from "../../../src/fake_data/entity"; import { provideHass } from "../../../src/fake_data/provide_hass"; import "../components/demo-cards"; diff --git a/gallery/src/demos/demo-hui-markdown-card.ts b/gallery/src/demos/demo-hui-markdown-card.ts index 94f63f404d..6e34a04c6f 100644 --- a/gallery/src/demos/demo-hui-markdown-card.ts +++ b/gallery/src/demos/demo-hui-markdown-card.ts @@ -1,11 +1,5 @@ -import { - customElement, - html, - LitElement, - PropertyValues, - query, - TemplateResult, -} from "lit-element"; +import { html, LitElement, PropertyValues, TemplateResult } from "lit"; +import { customElement, query } from "lit/decorators"; import { mockTemplate } from "../../../demo/src/stubs/template"; import { provideHass } from "../../../src/fake_data/provide_hass"; import "../components/demo-cards"; diff --git a/gallery/src/demos/demo-hui-media-control-card.ts b/gallery/src/demos/demo-hui-media-control-card.ts index 3b032c409e..0b963f36e8 100644 --- a/gallery/src/demos/demo-hui-media-control-card.ts +++ b/gallery/src/demos/demo-hui-media-control-card.ts @@ -1,11 +1,5 @@ -import { - customElement, - html, - LitElement, - PropertyValues, - query, - TemplateResult, -} from "lit-element"; +import { html, LitElement, PropertyValues, TemplateResult } from "lit"; +import { customElement, query } from "lit/decorators"; import { provideHass } from "../../../src/fake_data/provide_hass"; import "../components/demo-cards"; import { createMediaPlayerEntities } from "../data/media_players"; diff --git a/gallery/src/demos/demo-hui-media-player-rows.ts b/gallery/src/demos/demo-hui-media-player-rows.ts index 500bfca693..988d232e49 100644 --- a/gallery/src/demos/demo-hui-media-player-rows.ts +++ b/gallery/src/demos/demo-hui-media-player-rows.ts @@ -1,11 +1,5 @@ -import { - customElement, - html, - LitElement, - PropertyValues, - query, - TemplateResult, -} from "lit-element"; +import { html, LitElement, PropertyValues, TemplateResult } from "lit"; +import { customElement, query } from "lit/decorators"; import { provideHass } from "../../../src/fake_data/provide_hass"; import "../components/demo-cards"; import { createMediaPlayerEntities } from "../data/media_players"; diff --git a/gallery/src/demos/demo-hui-picture-elements-card.ts b/gallery/src/demos/demo-hui-picture-elements-card.ts index 5ab818911c..c3fcc7d61b 100644 --- a/gallery/src/demos/demo-hui-picture-elements-card.ts +++ b/gallery/src/demos/demo-hui-picture-elements-card.ts @@ -1,11 +1,5 @@ -import { - customElement, - html, - LitElement, - PropertyValues, - query, - TemplateResult, -} from "lit-element"; +import { html, LitElement, PropertyValues, TemplateResult } from "lit"; +import { customElement, query } from "lit/decorators"; import { getEntity } from "../../../src/fake_data/entity"; import { provideHass } from "../../../src/fake_data/provide_hass"; import "../components/demo-cards"; diff --git a/gallery/src/demos/demo-hui-picture-entity-card.ts b/gallery/src/demos/demo-hui-picture-entity-card.ts index 3a1b64f76e..6b8d8418e1 100644 --- a/gallery/src/demos/demo-hui-picture-entity-card.ts +++ b/gallery/src/demos/demo-hui-picture-entity-card.ts @@ -1,11 +1,5 @@ -import { - customElement, - html, - LitElement, - PropertyValues, - query, - TemplateResult, -} from "lit-element"; +import { html, LitElement, PropertyValues, TemplateResult } from "lit"; +import { customElement, query } from "lit/decorators"; import { getEntity } from "../../../src/fake_data/entity"; import { provideHass } from "../../../src/fake_data/provide_hass"; import "../components/demo-cards"; diff --git a/gallery/src/demos/demo-hui-picture-glance-card.ts b/gallery/src/demos/demo-hui-picture-glance-card.ts index f6790efc3d..b82c2a2fa9 100644 --- a/gallery/src/demos/demo-hui-picture-glance-card.ts +++ b/gallery/src/demos/demo-hui-picture-glance-card.ts @@ -1,11 +1,5 @@ -import { - customElement, - html, - LitElement, - PropertyValues, - query, - TemplateResult, -} from "lit-element"; +import { html, LitElement, PropertyValues, TemplateResult } from "lit"; +import { customElement, query } from "lit/decorators"; import { getEntity } from "../../../src/fake_data/entity"; import { provideHass } from "../../../src/fake_data/provide_hass"; import "../components/demo-cards"; diff --git a/gallery/src/demos/demo-hui-plant-card.ts b/gallery/src/demos/demo-hui-plant-card.ts index 9e8aff318e..683d0c6a37 100644 --- a/gallery/src/demos/demo-hui-plant-card.ts +++ b/gallery/src/demos/demo-hui-plant-card.ts @@ -1,11 +1,5 @@ -import { - customElement, - html, - LitElement, - PropertyValues, - query, - TemplateResult, -} from "lit-element"; +import { html, LitElement, PropertyValues, TemplateResult } from "lit"; +import { customElement, query } from "lit/decorators"; import { provideHass } from "../../../src/fake_data/provide_hass"; import "../components/demo-cards"; import { createPlantEntities } from "../data/plants"; diff --git a/gallery/src/demos/demo-hui-shopping-list-card.ts b/gallery/src/demos/demo-hui-shopping-list-card.ts index 61f9aa9062..034c150abd 100644 --- a/gallery/src/demos/demo-hui-shopping-list-card.ts +++ b/gallery/src/demos/demo-hui-shopping-list-card.ts @@ -1,11 +1,5 @@ -import { - customElement, - html, - LitElement, - PropertyValues, - query, - TemplateResult, -} from "lit-element"; +import { html, LitElement, PropertyValues, TemplateResult } from "lit"; +import { customElement, query } from "lit/decorators"; import { provideHass } from "../../../src/fake_data/provide_hass"; import "../components/demo-cards"; diff --git a/gallery/src/demos/demo-hui-thermostat-card.ts b/gallery/src/demos/demo-hui-thermostat-card.ts index e6cdaae788..86216da564 100644 --- a/gallery/src/demos/demo-hui-thermostat-card.ts +++ b/gallery/src/demos/demo-hui-thermostat-card.ts @@ -1,11 +1,5 @@ -import { - customElement, - html, - LitElement, - PropertyValues, - query, - TemplateResult, -} from "lit-element"; +import { html, LitElement, PropertyValues, TemplateResult } from "lit"; +import { customElement, query } from "lit/decorators"; import { getEntity } from "../../../src/fake_data/entity"; import { provideHass } from "../../../src/fake_data/provide_hass"; import "../components/demo-cards"; diff --git a/gallery/src/demos/demo-integration-card.ts b/gallery/src/demos/demo-integration-card.ts index 7fb8607930..1e23303bc4 100644 --- a/gallery/src/demos/demo-integration-card.ts +++ b/gallery/src/demos/demo-integration-card.ts @@ -1,12 +1,4 @@ -import { - customElement, - html, - css, - internalProperty, - LitElement, - TemplateResult, - property, -} from "lit-element"; +import { html, css, LitElement, TemplateResult } from "lit"; import "../../../src/components/ha-formfield"; import "../../../src/components/ha-switch"; @@ -23,7 +15,8 @@ import type { } from "../../../src/panels/config/integrations/ha-config-integrations"; import { DeviceRegistryEntry } from "../../../src/data/device_registry"; import { EntityRegistryEntry } from "../../../src/data/entity_registry"; -import { classMap } from "lit-html/directives/class-map"; +import { classMap } from "lit/directives/class-map"; +import { customElement, property, state } from "lit/decorators"; const createConfigEntry = ( title: string, @@ -220,9 +213,9 @@ const createDeviceRegistryEntries = ( export class DemoIntegrationCard extends LitElement { @property({ attribute: false }) hass?: HomeAssistant; - @internalProperty() isCustomIntegration = false; + @state() isCustomIntegration = false; - @internalProperty() isCloud = false; + @state() isCloud = false; protected render(): TemplateResult { if (!this.hass) { diff --git a/gallery/src/demos/demo-more-info-light.ts b/gallery/src/demos/demo-more-info-light.ts index 399873aa9c..a3107a5df3 100644 --- a/gallery/src/demos/demo-more-info-light.ts +++ b/gallery/src/demos/demo-more-info-light.ts @@ -1,12 +1,5 @@ -import { - customElement, - html, - LitElement, - property, - PropertyValues, - query, - TemplateResult, -} from "lit-element"; +import { html, LitElement, PropertyValues, TemplateResult } from "lit"; +import { customElement, property, query } from "lit/decorators"; import "../../../src/components/ha-card"; import { LightColorModes, diff --git a/gallery/src/demos/demo-util-long-press.ts b/gallery/src/demos/demo-util-long-press.ts index 9fa774918f..f4fddb45ac 100644 --- a/gallery/src/demos/demo-util-long-press.ts +++ b/gallery/src/demos/demo-util-long-press.ts @@ -1,5 +1,6 @@ import "@material/mwc-button"; -import { customElement, html, LitElement, TemplateResult } from "lit-element"; +import { html, LitElement, TemplateResult } from "lit"; +import { customElement } from "lit/decorators"; import "../../../src/components/ha-card"; import { ActionHandlerEvent } from "../../../src/data/lovelace"; import { actionHandler } from "../../../src/panels/lovelace/common/directives/action-handler-directive"; diff --git a/hassio/src/addon-store/hassio-addon-repository.ts b/hassio/src/addon-store/hassio-addon-repository.ts index 4e33f15e8b..513f053d1c 100644 --- a/hassio/src/addon-store/hassio-addon-repository.ts +++ b/hassio/src/addon-store/hassio-addon-repository.ts @@ -1,12 +1,6 @@ import { mdiArrowUpBoldCircle, mdiPuzzle } from "@mdi/js"; -import { - css, - CSSResultArray, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { property } from "lit/decorators"; import memoizeOne from "memoize-one"; import { atLeastVersion } from "../../../src/common/config/version"; import { navigate } from "../../../src/common/navigate"; @@ -126,10 +120,10 @@ class HassioAddonRepositoryEl extends LitElement { } private _addonTapped(ev) { - navigate(this, `/hassio/addon/${ev.currentTarget.addon.slug}`); + navigate(`/hassio/addon/${ev.currentTarget.addon.slug}`); } - static get styles(): CSSResultArray { + static get styles(): CSSResultGroup { return [ hassioStyle, css` diff --git a/hassio/src/addon-store/hassio-addon-store.ts b/hassio/src/addon-store/hassio-addon-store.ts index fd41a504db..a1dbe3237f 100644 --- a/hassio/src/addon-store/hassio-addon-store.ts +++ b/hassio/src/addon-store/hassio-addon-store.ts @@ -4,13 +4,13 @@ import "@material/mwc-list/mwc-list-item"; import { mdiDotsVertical } from "@mdi/js"; import { css, - CSSResult, - internalProperty, + CSSResultGroup, + html, LitElement, - property, PropertyValues, -} from "lit-element"; -import { html, TemplateResult } from "lit-html"; + TemplateResult, +} from "lit"; +import { property, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import { atLeastVersion } from "../../../src/common/config/version"; import { fireEvent } from "../../../src/common/dom/fire_event"; @@ -58,7 +58,7 @@ class HassioAddonStore extends LitElement { @property({ attribute: false }) public route!: Route; - @internalProperty() private _filter?: string; + @state() private _filter?: string; public async refreshData() { await reloadHassioAddons(this.hass); @@ -138,7 +138,7 @@ class HassioAddonStore extends LitElement { protected firstUpdated(changedProps: PropertyValues) { super.firstUpdated(changedProps); const repositoryUrl = extractSearchParam("repository_url"); - navigate(this, "/hassio/store", true); + navigate("/hassio/store", { replace: true }); if (repositoryUrl) { this._manageRepositories(repositoryUrl); } @@ -218,7 +218,7 @@ class HassioAddonStore extends LitElement { this._filter = e.detail.value; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` hassio-addon-repository { margin-top: 24px; diff --git a/hassio/src/addon-view/config/hassio-addon-audio.ts b/hassio/src/addon-view/config/hassio-addon-audio.ts index 79275a39cf..ad6238c429 100644 --- a/hassio/src/addon-view/config/hassio-addon-audio.ts +++ b/hassio/src/addon-view/config/hassio-addon-audio.ts @@ -4,15 +4,13 @@ import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; import "web-animations-js/web-animations-next-lite.min"; import "../../../../src/components/buttons/ha-progress-button"; import "../../../../src/components/ha-card"; @@ -39,15 +37,15 @@ class HassioAddonAudio extends LitElement { @property({ attribute: false }) public addon!: HassioAddonDetails; - @internalProperty() private _error?: string; + @state() private _error?: string; - @internalProperty() private _inputDevices?: HassioHardwareAudioDevice[]; + @state() private _inputDevices?: HassioHardwareAudioDevice[]; - @internalProperty() private _outputDevices?: HassioHardwareAudioDevice[]; + @state() private _outputDevices?: HassioHardwareAudioDevice[]; - @internalProperty() private _selectedInput!: null | string; + @state() private _selectedInput!: null | string; - @internalProperty() private _selectedOutput!: null | string; + @state() private _selectedOutput!: null | string; protected render(): TemplateResult { return html` @@ -109,7 +107,7 @@ class HassioAddonAudio extends LitElement { `; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, hassioStyle, diff --git a/hassio/src/addon-view/config/hassio-addon-config-tab.ts b/hassio/src/addon-view/config/hassio-addon-config-tab.ts index b9a5907075..3b3e1961ec 100644 --- a/hassio/src/addon-view/config/hassio-addon-config-tab.ts +++ b/hassio/src/addon-view/config/hassio-addon-config-tab.ts @@ -1,12 +1,5 @@ -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import "../../../../src/components/ha-circular-progress"; import { HassioAddonDetails } from "../../../../src/data/hassio/addon"; import { Supervisor } from "../../../../src/data/supervisor/supervisor"; @@ -70,7 +63,7 @@ class HassioAddonConfigDashboard extends LitElement { `; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, hassioStyle, diff --git a/hassio/src/addon-view/config/hassio-addon-config.ts b/hassio/src/addon-view/config/hassio-addon-config.ts index 56ebbfa5f5..52c3d73930 100644 --- a/hassio/src/addon-view/config/hassio-addon-config.ts +++ b/hassio/src/addon-view/config/hassio-addon-config.ts @@ -5,16 +5,13 @@ import { mdiDotsVertical } from "@mdi/js"; import "@polymer/iron-autogrow-textarea/iron-autogrow-textarea"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, - query, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state, query } from "lit/decorators"; import memoizeOne from "memoize-one"; import { fireEvent } from "../../../../src/common/dom/fire_event"; import "../../../../src/components/buttons/ha-progress-button"; @@ -53,15 +50,15 @@ class HassioAddonConfig extends LitElement { @property({ type: Boolean }) private _valid = true; - @internalProperty() private _canShowSchema = false; + @state() private _canShowSchema = false; - @internalProperty() private _showOptional = false; + @state() private _showOptional = false; - @internalProperty() private _error?: string; + @state() private _error?: string; - @internalProperty() private _options?: Record; + @state() private _options?: Record; - @internalProperty() private _yamlMode = false; + @state() private _yamlMode = false; @query("ha-yaml-editor") private _editor?: HaYamlEditor; @@ -262,6 +259,11 @@ class HassioAddonConfig extends LitElement { private async _saveTapped(ev: CustomEvent): Promise { const button = ev.currentTarget as any; + const eventdata = { + success: true, + response: undefined, + path: "options", + }; button.progress = true; this._error = undefined; @@ -272,26 +274,22 @@ class HassioAddonConfig extends LitElement { }); this._configHasChanged = false; - const eventdata = { - success: true, - response: undefined, - path: "options", - }; - fireEvent(this, "hass-api-called", eventdata); if (this.addon?.state === "started") { await suggestAddonRestart(this, this.hass, this.supervisor, this.addon); } } catch (err) { this._error = this.supervisor.localize( - "addon.configuration.options.failed_to_save", + "addon.failed_to_save", "error", extractApiErrorMessage(err) ); + eventdata.success = false; } button.progress = false; + fireEvent(this, "hass-api-called", eventdata); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, hassioStyle, diff --git a/hassio/src/addon-view/config/hassio-addon-network.ts b/hassio/src/addon-view/config/hassio-addon-network.ts index 256f81175f..9eb8541bdd 100644 --- a/hassio/src/addon-view/config/hassio-addon-network.ts +++ b/hassio/src/addon-view/config/hassio-addon-network.ts @@ -1,15 +1,13 @@ import { PaperInputElement } from "@polymer/paper-input/paper-input"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../../../src/common/dom/fire_event"; import "../../../../src/components/buttons/ha-progress-button"; import "../../../../src/components/ha-card"; @@ -43,9 +41,9 @@ class HassioAddonNetwork extends LitElement { @property({ attribute: false }) public addon!: HassioAddonDetails; - @internalProperty() private _error?: string; + @state() private _error?: string; - @internalProperty() private _config?: NetworkItem[]; + @state() private _config?: NetworkItem[]; public connectedCallback(): void { super.connectedCallback(); @@ -216,7 +214,7 @@ class HassioAddonNetwork extends LitElement { button.progress = false; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, hassioStyle, diff --git a/hassio/src/addon-view/documentation/hassio-addon-documentation-tab.ts b/hassio/src/addon-view/documentation/hassio-addon-documentation-tab.ts index 0cb15c1842..179598f099 100644 --- a/hassio/src/addon-view/documentation/hassio-addon-documentation-tab.ts +++ b/hassio/src/addon-view/documentation/hassio-addon-documentation-tab.ts @@ -1,14 +1,5 @@ import "../../../../src/components/ha-card"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import "../../../../src/components/ha-circular-progress"; import "../../../../src/components/ha-markdown"; import { @@ -21,6 +12,7 @@ import { haStyle } from "../../../../src/resources/styles"; import { HomeAssistant } from "../../../../src/types"; import { hassioStyle } from "../../resources/hassio-style"; import { Supervisor } from "../../../../src/data/supervisor/supervisor"; +import { customElement, property, state } from "lit/decorators"; @customElement("hassio-addon-documentation-tab") class HassioAddonDocumentationDashboard extends LitElement { @@ -30,9 +22,9 @@ class HassioAddonDocumentationDashboard extends LitElement { @property({ attribute: false }) public addon?: HassioAddonDetails; - @internalProperty() private _error?: string; + @state() private _error?: string; - @internalProperty() private _content?: string; + @state() private _content?: string; public async connectedCallback(): Promise { super.connectedCallback(); @@ -57,7 +49,7 @@ class HassioAddonDocumentationDashboard extends LitElement { `; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, hassioStyle, diff --git a/hassio/src/addon-view/hassio-addon-dashboard.ts b/hassio/src/addon-view/hassio-addon-dashboard.ts index 6287c7907d..47c5fdeac1 100644 --- a/hassio/src/addon-view/hassio-addon-dashboard.ts +++ b/hassio/src/addon-view/hassio-addon-dashboard.ts @@ -4,16 +4,8 @@ import { mdiInformationVariant, mdiMathLog, } from "@mdi/js"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import { fireEvent } from "../../../src/common/dom/fire_event"; import { navigate } from "../../../src/common/navigate"; @@ -52,7 +44,7 @@ class HassioAddonDashboard extends LitElement { @property({ type: Boolean }) public narrow!: boolean; - @internalProperty() _error?: string; + @state() _error?: string; private _computeTail = memoizeOne((route: Route) => { const dividerPos = route.path.indexOf("/", 1); @@ -133,7 +125,7 @@ class HassioAddonDashboard extends LitElement { `; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, hassioStyle, @@ -183,7 +175,7 @@ class HassioAddonDashboard extends LitElement { if (!validAddon) { this._error = this.supervisor.localize("my.error_addon_not_found"); } else { - navigate(this, `/hassio/addon/${requestedAddon}`, true); + navigate(`/hassio/addon/${requestedAddon}`, { replace: true }); } } } @@ -191,6 +183,10 @@ class HassioAddonDashboard extends LitElement { } private async _apiCalled(ev): Promise { + if (!ev.detail.success) { + return; + } + const pathSplit: string[] = ev.detail.path?.split("/"); if (!pathSplit || pathSplit.length === 0) { diff --git a/hassio/src/addon-view/hassio-addon-router.ts b/hassio/src/addon-view/hassio-addon-router.ts index e2d540527d..fe0bad9c00 100644 --- a/hassio/src/addon-view/hassio-addon-router.ts +++ b/hassio/src/addon-view/hassio-addon-router.ts @@ -1,4 +1,4 @@ -import { customElement, property } from "lit-element"; +import { customElement, property } from "lit/decorators"; import { HassioAddonDetails } from "../../../src/data/hassio/addon"; import { Supervisor } from "../../../src/data/supervisor/supervisor"; import { diff --git a/hassio/src/addon-view/info/hassio-addon-info-tab.ts b/hassio/src/addon-view/info/hassio-addon-info-tab.ts index dffd2a8b66..6b31e546b7 100644 --- a/hassio/src/addon-view/info/hassio-addon-info-tab.ts +++ b/hassio/src/addon-view/info/hassio-addon-info-tab.ts @@ -1,12 +1,5 @@ -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import "../../../../src/components/ha-circular-progress"; import { HassioAddonDetails } from "../../../../src/data/hassio/addon"; import { Supervisor } from "../../../../src/data/supervisor/supervisor"; @@ -42,7 +35,7 @@ class HassioAddonInfoDashboard extends LitElement { `; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, hassioStyle, diff --git a/hassio/src/addon-view/info/hassio-addon-info.ts b/hassio/src/addon-view/info/hassio-addon-info.ts index 20af66c7ce..0fe37230bb 100644 --- a/hassio/src/addon-view/info/hassio-addon-info.ts +++ b/hassio/src/addon-view/info/hassio-addon-info.ts @@ -14,17 +14,9 @@ import { mdiPound, mdiShield, } from "@mdi/js"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import memoizeOne from "memoize-one"; import { atLeastVersion } from "../../../../src/common/config/version"; import { fireEvent } from "../../../../src/common/dom/fire_event"; @@ -90,9 +82,9 @@ class HassioAddonInfo extends LitElement { @property({ attribute: false }) public supervisor!: Supervisor; - @internalProperty() private _metrics?: HassioStats; + @state() private _metrics?: HassioStats; - @internalProperty() private _error?: string; + @state() private _error?: string; private _addonStoreInfo = memoizeOne( (slug: string, storeAddons: StoreAddon[]) => @@ -171,16 +163,16 @@ class HassioAddonInfo extends LitElement { : ""}
- - ${this.supervisor.localize("common.update")} - ${this.addon.changelog ? html` ${this.supervisor.localize("addon.dashboard.changelog")} ` - : ""} + : html``} + + ${this.supervisor.localize("common.update")} +
` @@ -769,7 +761,7 @@ class HassioAddonInfo extends LitElement { } private _openIngress(): void { - navigate(this, `/hassio/ingress/${this.addon.slug}`); + navigate(`/hassio/ingress/${this.addon.slug}`); } private get _computeShowIngressUI(): boolean { @@ -1059,7 +1051,7 @@ class HassioAddonInfo extends LitElement { } private _openConfiguration(): void { - navigate(this, `/hassio/addon/${this.addon.slug}/config`); + navigate(`/hassio/addon/${this.addon.slug}/config`); } private async _uninstallClicked(ev: CustomEvent): Promise { @@ -1098,7 +1090,7 @@ class HassioAddonInfo extends LitElement { button.progress = false; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, hassioStyle, diff --git a/hassio/src/addon-view/log/hassio-addon-log-tab.ts b/hassio/src/addon-view/log/hassio-addon-log-tab.ts index 7b93e38a5b..3690d75c64 100644 --- a/hassio/src/addon-view/log/hassio-addon-log-tab.ts +++ b/hassio/src/addon-view/log/hassio-addon-log-tab.ts @@ -1,12 +1,5 @@ -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import "../../../../src/components/ha-circular-progress"; import { HassioAddonDetails } from "../../../../src/data/hassio/addon"; import { Supervisor } from "../../../../src/data/supervisor/supervisor"; @@ -38,7 +31,7 @@ class HassioAddonLogDashboard extends LitElement { `; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, hassioStyle, diff --git a/hassio/src/addon-view/log/hassio-addon-logs.ts b/hassio/src/addon-view/log/hassio-addon-logs.ts index c380c0b92e..a8ed8f3529 100644 --- a/hassio/src/addon-view/log/hassio-addon-logs.ts +++ b/hassio/src/addon-view/log/hassio-addon-logs.ts @@ -1,14 +1,6 @@ import "@material/mwc-button"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import "../../../../src/components/ha-card"; import { fetchHassioAddonLogs, @@ -29,9 +21,9 @@ class HassioAddonLogs extends LitElement { @property({ attribute: false }) public addon!: HassioAddonDetails; - @internalProperty() private _error?: string; + @state() private _error?: string; - @internalProperty() private _content?: string; + @state() private _content?: string; public async connectedCallback(): Promise { super.connectedCallback(); @@ -59,7 +51,7 @@ class HassioAddonLogs extends LitElement { `; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, hassioStyle, diff --git a/hassio/src/components/hassio-ansi-to-html.ts b/hassio/src/components/hassio-ansi-to-html.ts index b957b172b4..416be07388 100644 --- a/hassio/src/components/hassio-ansi-to-html.ts +++ b/hassio/src/components/hassio-ansi-to-html.ts @@ -1,12 +1,5 @@ -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; interface State { bold: boolean; @@ -25,7 +18,7 @@ class HassioAnsiToHtml extends LitElement { return html`${this._parseTextToColoredPre(this.content)}`; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` pre { overflow-x: auto; diff --git a/hassio/src/components/hassio-card-content.ts b/hassio/src/components/hassio-card-content.ts index 03884e6b94..d4b9508009 100644 --- a/hassio/src/components/hassio-card-content.ts +++ b/hassio/src/components/hassio-card-content.ts @@ -1,13 +1,6 @@ import { mdiHelpCircle } from "@mdi/js"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import "../../../src/components/ha-relative-time"; import "../../../src/components/ha-svg-icon"; import { HomeAssistant } from "../../../src/types"; @@ -77,7 +70,7 @@ class HassioCardContent extends LitElement { `; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` ha-svg-icon { margin-right: 24px; diff --git a/hassio/src/components/hassio-upload-snapshot.ts b/hassio/src/components/hassio-upload-snapshot.ts index 834281d911..5347e9a796 100644 --- a/hassio/src/components/hassio-upload-snapshot.ts +++ b/hassio/src/components/hassio-upload-snapshot.ts @@ -2,13 +2,8 @@ import "@material/mwc-icon-button/mwc-icon-button"; import { mdiFolderUpload } from "@mdi/js"; import "@polymer/iron-input/iron-input"; import "@polymer/paper-input/paper-input-container"; -import { - customElement, - html, - internalProperty, - LitElement, - TemplateResult, -} from "lit-element"; +import { html, LitElement, TemplateResult } from "lit"; +import { customElement, state } from "lit/decorators"; import { fireEvent } from "../../../src/common/dom/fire_event"; import "../../../src/components/ha-circular-progress"; import "../../../src/components/ha-file-upload"; @@ -33,9 +28,9 @@ const MAX_FILE_SIZE = 1 * 1024 * 1024 * 1024; // 1GB export class HassioUploadSnapshot extends LitElement { public hass!: HomeAssistant; - @internalProperty() public value: string | null = null; + @state() public value: string | null = null; - @internalProperty() private _uploading = false; + @state() private _uploading = false; public render(): TemplateResult { return html` diff --git a/hassio/src/components/supervisor-formfield-label.ts b/hassio/src/components/supervisor-formfield-label.ts new file mode 100644 index 0000000000..e173c0c44c --- /dev/null +++ b/hassio/src/components/supervisor-formfield-label.ts @@ -0,0 +1,55 @@ +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; +import "../../../src/components/ha-svg-icon"; + +@customElement("supervisor-formfield-label") +class SupervisorFormfieldLabel extends LitElement { + @property({ type: String }) public label!: string; + + @property({ type: String }) public imageUrl?: string; + + @property({ type: String }) public iconPath?: string; + + @property({ type: String }) public version?: string; + + protected render(): TemplateResult { + return html` + ${this.imageUrl + ? html`` + : this.iconPath + ? html`` + : ""} + ${this.label} + ${this.version + ? html`(${this.version})` + : ""} + `; + } + + static get styles(): CSSResultGroup { + return css` + :host { + cursor: pointer; + display: flex; + align-items: center; + } + .label { + margin-right: 4px; + } + .version { + color: var(--secondary-text-color); + } + .icon { + max-height: 22px; + max-width: 22px; + margin-right: 8px; + } + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "supervisor-formfield-label": SupervisorFormfieldLabel; + } +} diff --git a/hassio/src/components/supervisor-metric.ts b/hassio/src/components/supervisor-metric.ts index bf6246876c..af31344e44 100644 --- a/hassio/src/components/supervisor-metric.ts +++ b/hassio/src/components/supervisor-metric.ts @@ -1,13 +1,6 @@ -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import "../../../src/components/ha-bar"; import "../../../src/components/ha-settings-row"; import { roundWithOneDecimal } from "../../../src/util/calculate"; @@ -37,7 +30,7 @@ class SupervisorMetric extends LitElement { `; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` ha-settings-row { padding: 0; @@ -71,6 +64,7 @@ class SupervisorMetric extends LitElement { .value { width: 48px; padding-right: 4px; + flex-shrink: 0; } `; } diff --git a/hassio/src/components/supervisor-snapshot-content.ts b/hassio/src/components/supervisor-snapshot-content.ts new file mode 100644 index 0000000000..8c87976329 --- /dev/null +++ b/hassio/src/components/supervisor-snapshot-content.ts @@ -0,0 +1,418 @@ +import { mdiFolder, mdiHomeAssistant, mdiPuzzle } from "@mdi/js"; +import { PaperInputElement } from "@polymer/paper-input/paper-input"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; +import { atLeastVersion } from "../../../src/common/config/version"; +import { formatDate } from "../../../src/common/datetime/format_date"; +import { formatDateTime } from "../../../src/common/datetime/format_date_time"; +import "../../../src/components/ha-checkbox"; +import "../../../src/components/ha-formfield"; +import "../../../src/components/ha-radio"; +import type { HaRadio } from "../../../src/components/ha-radio"; +import { + HassioFullSnapshotCreateParams, + HassioPartialSnapshotCreateParams, + HassioSnapshotDetail, +} from "../../../src/data/hassio/snapshot"; +import { Supervisor } from "../../../src/data/supervisor/supervisor"; +import { PolymerChangedEvent } from "../../../src/polymer-types"; +import { HomeAssistant } from "../../../src/types"; +import "./supervisor-formfield-label"; + +interface CheckboxItem { + slug: string; + checked: boolean; + name: string; +} + +interface AddonCheckboxItem extends CheckboxItem { + version: string; +} + +const _computeFolders = (folders): CheckboxItem[] => { + const list: CheckboxItem[] = []; + if (folders.includes("homeassistant")) { + list.push({ + slug: "homeassistant", + name: "Home Assistant configuration", + checked: false, + }); + } + if (folders.includes("ssl")) { + list.push({ slug: "ssl", name: "SSL", checked: false }); + } + if (folders.includes("share")) { + list.push({ slug: "share", name: "Share", checked: false }); + } + if (folders.includes("addons/local")) { + list.push({ slug: "addons/local", name: "Local add-ons", checked: false }); + } + return list.sort((a, b) => (a.name > b.name ? 1 : -1)); +}; + +const _computeAddons = (addons): AddonCheckboxItem[] => + addons + .map((addon) => ({ + slug: addon.slug, + name: addon.name, + version: addon.version, + checked: false, + })) + .sort((a, b) => (a.name > b.name ? 1 : -1)); + +@customElement("supervisor-snapshot-content") +export class SupervisorSnapshotContent extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property({ attribute: false }) public supervisor?: Supervisor; + + @property({ attribute: false }) public snapshot?: HassioSnapshotDetail; + + @property() public snapshotType: HassioSnapshotDetail["type"] = "full"; + + @property({ attribute: false }) public folders?: CheckboxItem[]; + + @property({ attribute: false }) public addons?: AddonCheckboxItem[]; + + @property({ type: Boolean }) public homeAssistant = false; + + @property({ type: Boolean }) public snapshotHasPassword = false; + + @property() public snapshotName = ""; + + @property() public snapshotPassword = ""; + + public willUpdate(changedProps) { + super.willUpdate(changedProps); + if (!this.hasUpdated) { + this.folders = _computeFolders( + this.snapshot + ? this.snapshot.folders + : ["homeassistant", "ssl", "share", "media", "addons/local"] + ); + this.addons = _computeAddons( + this.snapshot + ? this.snapshot.addons + : this.supervisor?.supervisor.addons + ); + this.snapshotType = this.snapshot?.type || "full"; + this.snapshotName = this.snapshot?.name || ""; + this.snapshotHasPassword = this.snapshot?.protected || false; + } + } + + protected render(): TemplateResult { + if (!this.supervisor) { + return html``; + } + const foldersSection = + this.snapshotType === "partial" ? this._getSection("folders") : undefined; + const addonsSection = + this.snapshotType === "partial" ? this._getSection("addons") : undefined; + + return html` + ${this.snapshot + ? html`
+ ${this.snapshot.type === "full" + ? this.supervisor.localize("snapshot.full_snapshot") + : this.supervisor.localize("snapshot.partial_snapshot")} + (${Math.ceil(this.snapshot.size * 10) / 10 + " MB"})
+ ${formatDateTime(new Date(this.snapshot.date), this.hass.locale)} +
` + : html` + `} + ${!this.snapshot || this.snapshot.type === "full" + ? html`
+ ${!this.snapshot + ? this.supervisor.localize("snapshot.type") + : this.supervisor.localize("snapshot.select_type")} +
+
+ + + + + + + + +
` + : ""} + ${this.snapshot && this.snapshotType === "partial" + ? html` + ${this.snapshot.homeassistant + ? html` + + `} + > + { + this.homeAssistant = !this.homeAssistant; + }} + > + + + ` + : ""} + ` + : ""} + ${this.snapshotType === "partial" + ? html` + ${foldersSection?.templates.length + ? html` + + `} + > + + + +
${foldersSection.templates}
+ ` + : ""} + ${addonsSection?.templates.length + ? html` + + `} + > + + + +
${addonsSection.templates}
+ ` + : ""} + ` + : ""} + ${!this.snapshot + ? html` + + ` + : ""} + ${this.snapshotHasPassword + ? html` + + + ` + : ""} + `; + } + + static get styles(): CSSResultGroup { + return css` + ha-checkbox { + --mdc-checkbox-touch-target-size: 16px; + display: block; + margin: 4px 12px 8px 0; + } + ha-formfield { + display: contents; + } + supervisor-formfield-label { + display: inline-flex; + align-items: center; + } + paper-input[type="password"] { + display: block; + margin: 4px 0 4px 16px; + } + .details { + color: var(--secondary-text-color); + } + .section-content { + display: flex; + flex-direction: column; + margin-left: 16px; + } + .security { + margin-top: 16px; + } + .snapshot-types { + display: flex; + } + .sub-header { + margin-top: 8px; + } + `; + } + + public snapshotDetails(): + | HassioPartialSnapshotCreateParams + | HassioFullSnapshotCreateParams { + const data: any = {}; + + if (!this.snapshot) { + data.name = this.snapshotName || formatDate(new Date(), this.hass.locale); + } + + if (this.snapshotHasPassword) { + data.password = this.snapshotPassword; + } + + if (this.snapshotType === "full") { + return data; + } + + const addons = this.addons + ?.filter((addon) => addon.checked) + .map((addon) => addon.slug); + const folders = this.folders + ?.filter((folder) => folder.checked) + .map((folder) => folder.slug); + + if (addons?.length) { + data.addons = addons; + } + if (folders?.length) { + data.folders = folders; + } + if (this.homeAssistant) { + data.homeassistant = this.homeAssistant; + } + + return data; + } + + private _getSection(section: string) { + const templates: TemplateResult[] = []; + const addons = + section === "addons" + ? new Map( + this.supervisor!.addon.addons.map((item) => [item.slug, item]) + ) + : undefined; + let checkedItems = 0; + this[section].forEach((item) => { + templates.push(html` + `} + > + + + `); + + if (item.checked) { + checkedItems++; + } + }); + + const checked = checkedItems === this[section].length; + + return { + templates, + checked, + indeterminate: !checked && checkedItems !== 0, + }; + } + + private _handleRadioValueChanged(ev: CustomEvent) { + const input = ev.currentTarget as HaRadio; + this[input.name] = input.value; + } + + private _handleTextValueChanged(ev: PolymerChangedEvent) { + const input = ev.currentTarget as PaperInputElement; + this[input.name!] = ev.detail.value; + } + + private _toggleHasPassword(): void { + this.snapshotHasPassword = !this.snapshotHasPassword; + } + + private _toggleSection(ev): void { + const section = ev.currentTarget.section; + + this[section] = (section === "addons" ? this.addons : this.folders)!.map( + (item) => ({ + ...item, + checked: ev.currentTarget.checked, + }) + ); + } + + private _updateSectionEntry(ev): void { + const item = ev.currentTarget.item; + const section = ev.currentTarget.section; + this[section] = this[section].map((entry) => + entry.slug === item.slug + ? { + ...entry, + checked: ev.currentTarget.checked, + } + : entry + ); + } +} + +declare global { + interface HTMLElementTagNameMap { + "supervisor-snapshot-content": SupervisorSnapshotContent; + } +} diff --git a/hassio/src/dashboard/hassio-addons.ts b/hassio/src/dashboard/hassio-addons.ts index 3a578581ab..06abd3e4d5 100644 --- a/hassio/src/dashboard/hassio-addons.ts +++ b/hassio/src/dashboard/hassio-addons.ts @@ -1,13 +1,6 @@ import { mdiArrowUpBoldCircle, mdiPuzzle } from "@mdi/js"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import { atLeastVersion } from "../../../src/common/config/version"; import { navigate } from "../../../src/common/navigate"; import { compare } from "../../../src/common/string/compare"; @@ -90,7 +83,7 @@ class HassioAddons extends LitElement { `; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, hassioStyle, @@ -103,11 +96,11 @@ class HassioAddons extends LitElement { } private _addonTapped(ev: any): void { - navigate(this, `/hassio/addon/${ev.currentTarget.addon.slug}/info`); + navigate(`/hassio/addon/${ev.currentTarget.addon.slug}/info`); } private _openStore(): void { - navigate(this, "/hassio/store"); + navigate("/hassio/store"); } } diff --git a/hassio/src/dashboard/hassio-dashboard.ts b/hassio/src/dashboard/hassio-dashboard.ts index 1a4c373eda..6b98c759ce 100644 --- a/hassio/src/dashboard/hassio-dashboard.ts +++ b/hassio/src/dashboard/hassio-dashboard.ts @@ -1,12 +1,5 @@ -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import { Supervisor } from "../../../src/data/supervisor/supervisor"; import "../../../src/layouts/hass-tabs-subpage"; import { haStyle } from "../../../src/resources/styles"; @@ -53,7 +46,7 @@ class HassioDashboard extends LitElement { `; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/hassio/src/dashboard/hassio-update.ts b/hassio/src/dashboard/hassio-update.ts index 1a11ee99e4..21836b1c1a 100644 --- a/hassio/src/dashboard/hassio-update.ts +++ b/hassio/src/dashboard/hassio-update.ts @@ -1,14 +1,7 @@ import "@material/mwc-button"; import { mdiHomeAssistant } from "@mdi/js"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import memoizeOne from "memoize-one"; import { atLeastVersion } from "../../../src/common/config/version"; import { fireEvent } from "../../../src/common/dom/fire_event"; @@ -233,7 +226,7 @@ export class HassioUpdate extends LitElement { }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, hassioStyle, diff --git a/hassio/src/dialogs/markdown/dialog-hassio-markdown.ts b/hassio/src/dialogs/markdown/dialog-hassio-markdown.ts index 95177a18f5..b1b2f06226 100644 --- a/hassio/src/dialogs/markdown/dialog-hassio-markdown.ts +++ b/hassio/src/dialogs/markdown/dialog-hassio-markdown.ts @@ -1,13 +1,5 @@ -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { createCloseHeading } from "../../../../src/components/ha-dialog"; import "../../../../src/components/ha-markdown"; import { haStyleDialog } from "../../../../src/resources/styles"; @@ -23,7 +15,7 @@ class HassioMarkdownDialog extends LitElement { @property() public content!: string; - @internalProperty() private _opened = false; + @state() private _opened = false; public showDialog(params: HassioMarkdownDialogParams) { this.title = params.title; @@ -50,7 +42,7 @@ class HassioMarkdownDialog extends LitElement { `; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyleDialog, hassioStyle, diff --git a/hassio/src/dialogs/network/dialog-hassio-network.ts b/hassio/src/dialogs/network/dialog-hassio-network.ts index 04f2710465..36adbabf45 100644 --- a/hassio/src/dialogs/network/dialog-hassio-network.ts +++ b/hassio/src/dialogs/network/dialog-hassio-network.ts @@ -6,17 +6,9 @@ import "@material/mwc-tab"; import "@material/mwc-tab-bar"; import { mdiClose } from "@mdi/js"; import { PaperInputElement } from "@polymer/paper-input/paper-input"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import { cache } from "lit-html/directives/cache"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { cache } from "lit/directives/cache"; import { fireEvent } from "../../../../src/common/dom/fire_event"; import "../../../../src/components/ha-circular-progress"; import "../../../../src/components/ha-dialog"; @@ -54,23 +46,23 @@ export class DialogHassioNetwork @property({ attribute: false }) public supervisor!: Supervisor; - @internalProperty() private _accessPoints?: AccessPoints; + @state() private _accessPoints?: AccessPoints; - @internalProperty() private _curTabIndex = 0; + @state() private _curTabIndex = 0; - @internalProperty() private _dirty = false; + @state() private _dirty = false; - @internalProperty() private _interface?: NetworkInterface; + @state() private _interface?: NetworkInterface; - @internalProperty() private _interfaces!: NetworkInterface[]; + @state() private _interfaces!: NetworkInterface[]; - @internalProperty() private _params?: HassioNetworkDialogParams; + @state() private _params?: HassioNetworkDialogParams; - @internalProperty() private _processing = false; + @state() private _processing = false; - @internalProperty() private _scanning = false; + @state() private _scanning = false; - @internalProperty() private _wifiConfiguration?: WifiConfiguration; + @state() private _wifiConfiguration?: WifiConfiguration; public async showDialog(params: HassioNetworkDialogParams): Promise { this._params = params; @@ -543,7 +535,7 @@ export class DialogHassioNetwork this._wifiConfiguration![id] = value; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyleDialog, css` diff --git a/hassio/src/dialogs/registries/dialog-hassio-registries.ts b/hassio/src/dialogs/registries/dialog-hassio-registries.ts index 4b77b41436..6cd738119a 100644 --- a/hassio/src/dialogs/registries/dialog-hassio-registries.ts +++ b/hassio/src/dialogs/registries/dialog-hassio-registries.ts @@ -3,16 +3,8 @@ import "@material/mwc-icon-button/mwc-icon-button"; import "@material/mwc-list/mwc-list-item"; import { mdiDelete } from "@mdi/js"; import { PaperInputElement } from "@polymer/paper-input/paper-input"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import "../../../../src/components/ha-circular-progress"; import { createCloseHeading } from "../../../../src/components/ha-dialog"; import "../../../../src/components/ha-svg-icon"; @@ -39,21 +31,21 @@ class HassioRegistriesDialog extends LitElement { username: string; }[]; - @internalProperty() private _registry?: string; + @state() private _registry?: string; - @internalProperty() private _username?: string; + @state() private _username?: string; - @internalProperty() private _password?: string; + @state() private _password?: string; - @internalProperty() private _opened = false; + @state() private _opened = false; - @internalProperty() private _addingRegistry = false; + @state() private _addingRegistry = false; protected render(): TemplateResult { return html` + ${this._creatingSnapshot + ? html` ` + : html` + `} + ${this._error ? html`

Error: ${this._error}

` : ""} + + ${this._dialogParams.supervisor.localize("common.close")} + + + ${this._dialogParams.supervisor.localize("snapshot.create")} + +
+ `; + } + + private async _createSnapshot(): Promise { + if (this._dialogParams!.supervisor.info.state !== "running") { + showAlertDialog(this, { + title: this._dialogParams!.supervisor.localize( + "snapshot.could_not_create" + ), + text: this._dialogParams!.supervisor.localize( + "snapshot.create_blocked_not_running", + "state", + this._dialogParams!.supervisor.info.state + ), + }); + return; + } + const snapshotDetails = this._snapshotContent.snapshotDetails(); + this._creatingSnapshot = true; + + this._error = ""; + if ( + this._snapshotContent.snapshotHasPassword && + !this._snapshotContent.snapshotPassword.length + ) { + this._error = this._dialogParams!.supervisor.localize( + "snapshot.enter_password" + ); + this._creatingSnapshot = false; + return; + } + + try { + if (this._snapshotContent.snapshotType === "full") { + await createHassioFullSnapshot(this.hass, snapshotDetails); + } else { + await createHassioPartialSnapshot(this.hass, snapshotDetails); + } + + this._dialogParams!.onCreate(); + this.closeDialog(); + } catch (err) { + this._error = extractApiErrorMessage(err); + } + this._creatingSnapshot = false; + } + + static get styles(): CSSResultGroup { + return [ + haStyle, + haStyleDialog, + css` + ha-circular-progress { + display: block; + text-align: center; + } + `, + ]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "dialog-hassio-create-snapshot": HassioCreateSnapshotDialog; + } +} diff --git a/hassio/src/dialogs/snapshot/dialog-hassio-snapshot-upload.ts b/hassio/src/dialogs/snapshot/dialog-hassio-snapshot-upload.ts index d4948bd553..d2ffb1f035 100644 --- a/hassio/src/dialogs/snapshot/dialog-hassio-snapshot-upload.ts +++ b/hassio/src/dialogs/snapshot/dialog-hassio-snapshot-upload.ts @@ -1,14 +1,6 @@ import { mdiClose } from "@mdi/js"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../../../src/common/dom/fire_event"; import "../../../../src/components/ha-header-bar"; import { HassDialog } from "../../../../src/dialogs/make-dialog-manager"; @@ -23,7 +15,7 @@ export class DialogHassioSnapshotUpload implements HassDialog { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _params?: HassioSnapshotUploadDialogParams; + @state() private _params?: HassioSnapshotUploadDialogParams; public async showDialog( params: HassioSnapshotUploadDialogParams @@ -78,7 +70,7 @@ export class DialogHassioSnapshotUpload this.closeDialog(); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyleDialog, css` diff --git a/hassio/src/dialogs/snapshot/dialog-hassio-snapshot.ts b/hassio/src/dialogs/snapshot/dialog-hassio-snapshot.ts index b44c9eb6c3..d6ea47f34c 100755 --- a/hassio/src/dialogs/snapshot/dialog-hassio-snapshot.ts +++ b/hassio/src/dialogs/snapshot/dialog-hassio-snapshot.ts @@ -1,20 +1,12 @@ -import "@material/mwc-button"; -import { mdiClose, mdiDelete, mdiDownload, mdiHistory } from "@mdi/js"; -import "@polymer/paper-checkbox/paper-checkbox"; -import type { PaperCheckboxElement } from "@polymer/paper-checkbox/paper-checkbox"; -import "@polymer/paper-input/paper-input"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { ActionDetail } from "@material/mwc-list"; +import "@material/mwc-list/mwc-list-item"; +import { mdiDotsVertical } from "@mdi/js"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, query, state } from "lit/decorators"; import { fireEvent } from "../../../../src/common/dom/fire_event"; -import "../../../../src/components/ha-header-bar"; +import "../../../../src/components/buttons/ha-progress-button"; +import "../../../../src/components/ha-button-menu"; +import { createCloseHeading } from "../../../../src/components/ha-dialog"; import "../../../../src/components/ha-svg-icon"; import { getSignedPath } from "../../../../src/data/auth"; import { extractApiErrorMessage } from "../../../../src/data/hassio/common"; @@ -22,95 +14,46 @@ import { fetchHassioSnapshotInfo, HassioSnapshotDetail, } from "../../../../src/data/hassio/snapshot"; -import { Supervisor } from "../../../../src/data/supervisor/supervisor"; import { showAlertDialog, showConfirmationDialog, } from "../../../../src/dialogs/generic/show-dialog-box"; -import { PolymerChangedEvent } from "../../../../src/polymer-types"; +import { HassDialog } from "../../../../src/dialogs/make-dialog-manager"; import { haStyle, haStyleDialog } from "../../../../src/resources/styles"; import { HomeAssistant } from "../../../../src/types"; +import "../../components/supervisor-snapshot-content"; +import type { SupervisorSnapshotContent } from "../../components/supervisor-snapshot-content"; import { HassioSnapshotDialogParams } from "./show-dialog-hassio-snapshot"; -const _computeFolders = (folders) => { - const list: Array<{ slug: string; name: string; checked: boolean }> = []; - if (folders.includes("homeassistant")) { - list.push({ - slug: "homeassistant", - name: "Home Assistant configuration", - checked: true, - }); - } - if (folders.includes("ssl")) { - list.push({ slug: "ssl", name: "SSL", checked: true }); - } - if (folders.includes("share")) { - list.push({ slug: "share", name: "Share", checked: true }); - } - if (folders.includes("addons/local")) { - list.push({ slug: "addons/local", name: "Local add-ons", checked: true }); - } - return list; -}; - -const _computeAddons = (addons) => - addons.map((addon) => ({ - slug: addon.slug, - name: addon.name, - version: addon.version, - checked: true, - })); - -interface AddonItem { - slug: string; - name: string; - version: string; - checked: boolean | null | undefined; -} - -interface FolderItem { - slug: string; - name: string; - checked: boolean | null | undefined; -} - @customElement("dialog-hassio-snapshot") -class HassioSnapshotDialog extends LitElement { +class HassioSnapshotDialog + extends LitElement + implements HassDialog { @property({ attribute: false }) public hass!: HomeAssistant; - @property({ attribute: false }) public supervisor?: Supervisor; + @state() private _error?: string; - @internalProperty() private _error?: string; + @state() private _snapshot?: HassioSnapshotDetail; - @internalProperty() private _onboarding = false; + @state() private _dialogParams?: HassioSnapshotDialogParams; - @internalProperty() private _snapshot?: HassioSnapshotDetail; + @state() private _restoringSnapshot = false; - @internalProperty() private _folders!: FolderItem[]; - - @internalProperty() private _addons!: AddonItem[]; - - @internalProperty() private _dialogParams?: HassioSnapshotDialogParams; - - @internalProperty() private _snapshotPassword!: string; - - @internalProperty() private _restoreHass = true; + @query("supervisor-snapshot-content") + private _snapshotContent!: SupervisorSnapshotContent; public async showDialog(params: HassioSnapshotDialogParams) { this._snapshot = await fetchHassioSnapshotInfo(this.hass, params.slug); - this._folders = _computeFolders( - this._snapshot?.folders - ).sort((a: FolderItem, b: FolderItem) => (a.name > b.name ? 1 : -1)); - this._addons = _computeAddons( - this._snapshot?.addons - ).sort((a: AddonItem, b: AddonItem) => (a.name > b.name ? 1 : -1)); - this._dialogParams = params; - this._onboarding = params.onboarding ?? false; - this.supervisor = params.supervisor; - if (!this._snapshot.homeassistant) { - this._restoreHass = false; - } + this._restoringSnapshot = false; + } + + public closeDialog() { + this._snapshot = undefined; + this._dialogParams = undefined; + this._restoringSnapshot = false; + this._error = undefined; + fireEvent(this, "dialog-closed", { dialog: this.localName }); } protected render(): TemplateResult { @@ -118,202 +61,92 @@ class HassioSnapshotDialog extends LitElement { return html``; } return html` - -
- - ${this._computeName} - - - - -
-
- ${this._snapshot.type === "full" - ? "Full snapshot" - : "Partial snapshot"} - (${this._computeSize})
- ${this._formatDatetime(this._snapshot.date)} -
- ${this._snapshot.homeassistant - ? html`
Home Assistant:
- - Home Assistant ${this._snapshot.homeassistant} - ` - : ""} - ${this._folders.length - ? html` -
Folders:
- - ${this._folders.map( - (item) => html` - - ${item.name} - - ` - )} - - ` - : ""} - ${this._addons.length - ? html` -
Add-on:
- - ${this._addons.map( - (item) => html` - - ${item.name} - - ` - )} - - ` - : ""} - ${this._snapshot.protected - ? html` - - ` - : ""} - ${this._error ? html`

Error: ${this._error}

` : ""} + + ${this._restoringSnapshot + ? html` ` + : html` + `} + ${this._error ? html`

Error: ${this._error}

` : ""} -
- - - Restore Selected - - ${!this._onboarding - ? html` - - - - Delete Snapshot - - ` - : ""} -
-
- ${this._snapshot.type === "full" - ? html` - - - Restore Everything - - ` - : ""} - ${!this._onboarding - ? html` - - Download Snapshot - ` - : ""} -
+ + Restore + + + ev.stopPropagation()} + > + + + + Download Snapshot + Delete Snapshot +
`; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, haStyleDialog, css` - paper-checkbox { + ha-svg-icon { + color: var(--primary-text-color); + } + ha-circular-progress { display: block; - margin: 4px; - } - mwc-button ha-svg-icon { - margin-right: 4px; - } - .button-row { - display: grid; - gap: 8px; - margin-right: 8px; - } - .details { - color: var(--secondary-text-color); - } - .warning, - .error { - color: var(--error-color); - } - .buttons li { - list-style-type: none; - } - .buttons .icon { - margin-right: 16px; - } - .no-margin-top { - margin-top: 0; - } - ha-header-bar { - --mdc-theme-on-primary: var(--primary-text-color); - --mdc-theme-primary: var(--mdc-theme-surface); - flex-shrink: 0; - } - /* overrule the ha-style-dialog max-height on small screens */ - @media all and (max-width: 450px), all and (max-height: 500px) { - ha-header-bar { - --mdc-theme-primary: var(--app-header-background-color); - --mdc-theme-on-primary: var(--app-header-text-color, white); - } + text-align: center; } `, ]; } - private _updateFolders(item: FolderItem, value: boolean | null | undefined) { - this._folders = this._folders.map((folder) => { - if (folder.slug === item.slug) { - folder.checked = value; - } - return folder; - }); + private _handleMenuAction(ev: CustomEvent) { + switch (ev.detail.index) { + case 0: + this._downloadClicked(); + break; + case 1: + this._deleteClicked(); + break; + } } - private _updateAddons(item: AddonItem, value: boolean | null | undefined) { - this._addons = this._addons.map((addon) => { - if (addon.slug === item.slug) { - addon.checked = value; - } - return addon; - }); + private async _restoreClicked() { + const snapshotDetails = this._snapshotContent.snapshotDetails(); + this._restoringSnapshot = true; + if (this._snapshotContent.snapshotType === "full") { + await this._fullRestoreClicked(snapshotDetails); + } else { + await this._partialRestoreClicked(snapshotDetails); + } + this._restoringSnapshot = false; } - private _passwordInput(ev: PolymerChangedEvent) { - this._snapshotPassword = ev.detail.value; - } - - private async _partialRestoreClicked() { + private async _partialRestoreClicked(snapshotDetails) { if ( - this.supervisor !== undefined && - this.supervisor.info.state !== "running" + this._dialogParams?.supervisor !== undefined && + this._dialogParams?.supervisor.info.state !== "running" ) { await showAlertDialog(this, { title: "Could not restore snapshot", - text: `Restoring a snapshot is not possible right now because the system is in ${this.supervisor.info.state} state.`, + text: `Restoring a snapshot is not possible right now because the system is in ${this._dialogParams?.supervisor.info.state} state.`, }); return; } @@ -327,41 +160,17 @@ class HassioSnapshotDialog extends LitElement { return; } - const addons = this._addons - .filter((addon) => addon.checked) - .map((addon) => addon.slug); - - const folders = this._folders - .filter((folder) => folder.checked) - .map((folder) => folder.slug); - - const data: { - homeassistant: boolean; - addons: any; - folders: any; - password?: string; - } = { - homeassistant: this._restoreHass, - addons, - folders, - }; - - if (this._snapshot!.protected) { - data.password = this._snapshotPassword; - } - - if (!this._onboarding) { + if (!this._dialogParams?.onboarding) { this.hass .callApi( "POST", `hassio/snapshots/${this._snapshot!.slug}/restore/partial`, - data + snapshotDetails ) .then( () => { - alert("Snapshot restored!"); - this._closeDialog(); + this.closeDialog(); }, (error) => { this._error = error.body.message; @@ -371,20 +180,20 @@ class HassioSnapshotDialog extends LitElement { fireEvent(this, "restoring"); fetch(`/api/hassio/snapshots/${this._snapshot!.slug}/restore/partial`, { method: "POST", - body: JSON.stringify(data), + body: JSON.stringify(snapshotDetails), }); - this._closeDialog(); + this.closeDialog(); } } - private async _fullRestoreClicked() { + private async _fullRestoreClicked(snapshotDetails) { if ( - this.supervisor !== undefined && - this.supervisor.info.state !== "running" + this._dialogParams?.supervisor !== undefined && + this._dialogParams?.supervisor.info.state !== "running" ) { await showAlertDialog(this, { title: "Could not restore snapshot", - text: `Restoring a snapshot is not possible right now because the system is in ${this.supervisor.info.state} state.`, + text: `Restoring a snapshot is not possible right now because the system is in ${this._dialogParams?.supervisor.info.state} state.`, }); return; } @@ -399,20 +208,16 @@ class HassioSnapshotDialog extends LitElement { return; } - const data = this._snapshot!.protected - ? { password: this._snapshotPassword } - : undefined; - if (!this._onboarding) { + if (!this._dialogParams?.onboarding) { this.hass .callApi( "POST", `hassio/snapshots/${this._snapshot!.slug}/restore/full`, - data + snapshotDetails ) .then( () => { - alert("Snapshot restored!"); - this._closeDialog(); + this.closeDialog(); }, (error) => { this._error = error.body.message; @@ -422,9 +227,9 @@ class HassioSnapshotDialog extends LitElement { fireEvent(this, "restoring"); fetch(`/api/hassio/snapshots/${this._snapshot!.slug}/restore/full`, { method: "POST", - body: JSON.stringify(data), + body: JSON.stringify(snapshotDetails), }); - this._closeDialog(); + this.closeDialog(); } } @@ -447,7 +252,7 @@ class HassioSnapshotDialog extends LitElement { if (this._dialogParams!.onDelete) { this._dialogParams!.onDelete(); } - this._closeDialog(); + this.closeDialog(); }, (error) => { this._error = error.body.message; @@ -463,7 +268,9 @@ class HassioSnapshotDialog extends LitElement { `/api/hassio/snapshots/${this._snapshot!.slug}/download` ); } catch (err) { - alert(`Error: ${extractApiErrorMessage(err)}`); + await showAlertDialog(this, { + text: extractApiErrorMessage(err), + }); return; } @@ -494,29 +301,6 @@ class HassioSnapshotDialog extends LitElement { ? this._snapshot.name || this._snapshot.slug : "Unnamed snapshot"; } - - private get _computeSize() { - return Math.ceil(this._snapshot!.size * 10) / 10 + " MB"; - } - - private _formatDatetime(datetime) { - return new Date(datetime).toLocaleDateString(navigator.language, { - weekday: "long", - year: "numeric", - month: "short", - day: "numeric", - hour: "numeric", - minute: "2-digit", - }); - } - - private _closeDialog() { - this._dialogParams = undefined; - this._snapshot = undefined; - this._snapshotPassword = ""; - this._folders = []; - this._addons = []; - } } declare global { diff --git a/hassio/src/dialogs/snapshot/show-dialog-hassio-create-snapshot.ts b/hassio/src/dialogs/snapshot/show-dialog-hassio-create-snapshot.ts new file mode 100644 index 0000000000..353caf31a2 --- /dev/null +++ b/hassio/src/dialogs/snapshot/show-dialog-hassio-create-snapshot.ts @@ -0,0 +1,18 @@ +import { fireEvent } from "../../../../src/common/dom/fire_event"; +import { Supervisor } from "../../../../src/data/supervisor/supervisor"; + +export interface HassioCreateSnapshotDialogParams { + supervisor: Supervisor; + onCreate: () => void; +} + +export const showHassioCreateSnapshotDialog = ( + element: HTMLElement, + dialogParams: HassioCreateSnapshotDialogParams +): void => { + fireEvent(element, "show-dialog", { + dialogTag: "dialog-hassio-create-snapshot", + dialogImport: () => import("./dialog-hassio-create-snapshot"), + dialogParams, + }); +}; diff --git a/hassio/src/dialogs/suggestAddonRestart.ts b/hassio/src/dialogs/suggestAddonRestart.ts index 12b8d383d7..d3bb5b1653 100644 --- a/hassio/src/dialogs/suggestAddonRestart.ts +++ b/hassio/src/dialogs/suggestAddonRestart.ts @@ -1,4 +1,4 @@ -import type { LitElement } from "lit-element"; +import type { LitElement } from "lit"; import { HassioAddonDetails, restartHassioAddon, diff --git a/hassio/src/dialogs/update/dialog-supervisor-update.ts b/hassio/src/dialogs/update/dialog-supervisor-update.ts index 47f509331d..e017c9d2f9 100644 --- a/hassio/src/dialogs/update/dialog-supervisor-update.ts +++ b/hassio/src/dialogs/update/dialog-supervisor-update.ts @@ -1,13 +1,6 @@ import "@material/mwc-button/mwc-button"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, state } from "lit/decorators"; import { fireEvent } from "../../../../src/common/dom/fire_event"; import "../../../../src/components/ha-circular-progress"; import "../../../../src/components/ha-dialog"; @@ -27,15 +20,15 @@ import { SupervisorDialogSupervisorUpdateParams } from "./show-dialog-update"; class DialogSupervisorUpdate extends LitElement { public hass!: HomeAssistant; - @internalProperty() private _opened = false; + @state() private _opened = false; - @internalProperty() private _createSnapshot = true; + @state() private _createSnapshot = true; - @internalProperty() private _action: "snapshot" | "update" | null = null; + @state() private _action: "snapshot" | "update" | null = null; - @internalProperty() private _error?: string; + @state() private _error?: string; - @internalProperty() + @state() private _dialogParams?: SupervisorDialogSupervisorUpdateParams; public async showDialog( @@ -173,7 +166,7 @@ class DialogSupervisorUpdate extends LitElement { this.closeDialog(); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, haStyleDialog, diff --git a/hassio/src/entrypoint.ts b/hassio/src/entrypoint.ts index 24d3e45359..48c4a33180 100644 --- a/hassio/src/entrypoint.ts +++ b/hassio/src/entrypoint.ts @@ -15,5 +15,11 @@ body { padding: 0; height: 100vh; } +@media (prefers-color-scheme: dark) { + body { + background-color: #111111; + color: #e1e1e1; + } +} `; document.head.appendChild(styleEl); diff --git a/hassio/src/hassio-main.ts b/hassio/src/hassio-main.ts index e5b8f89530..280654bf7d 100644 --- a/hassio/src/hassio-main.ts +++ b/hassio/src/hassio-main.ts @@ -1,7 +1,11 @@ -import { customElement, html, property, PropertyValues } from "lit-element"; +import { html, PropertyValues } from "lit"; +import { customElement, property } from "lit/decorators"; import { atLeastVersion } from "../../src/common/config/version"; import { applyThemesOnElement } from "../../src/common/dom/apply_themes_on_element"; import { fireEvent } from "../../src/common/dom/fire_event"; +import { isNavigationClick } from "../../src/common/dom/is-navigation-click"; +import { mainWindow } from "../../src/common/dom/get_main_window"; +import { navigate } from "../../src/common/navigate"; import { HassioPanelInfo } from "../../src/data/hassio/supervisor"; import { Supervisor } from "../../src/data/supervisor/supervisor"; import { makeDialogManager } from "../../src/dialogs/make-dialog-manager"; @@ -46,14 +50,23 @@ export class HassioMain extends SupervisorBaseElement { // listen on this element for navigation events, so we need to forward them. // Joakim - April 26, 2021 - // Due to changes in behavior in Google Chrome, we changed navigate to fire on the top element - top.addEventListener("location-changed", (ev) => + // Due to changes in behavior in Google Chrome, we changed navigate to listen on the top element + mainWindow.addEventListener("location-changed", (ev) => // @ts-ignore fireEvent(this, ev.type, ev.detail, { bubbles: false, }) ); + // Paulus - May 17, 2021 + // Convert the tags to native nav in Home Assistant < 2021.6 + document.body.addEventListener("click", (ev) => { + const href = isNavigationClick(ev); + if (href) { + navigate(href); + } + }); + // Forward haptic events to parent window. window.addEventListener("haptic", (ev) => { // @ts-ignore @@ -90,25 +103,27 @@ export class HassioMain extends SupervisorBaseElement { private _applyTheme() { let themeName: string; - let options: Partial | undefined; + let themeSettings: + | Partial + | undefined; if (atLeastVersion(this.hass.config.version, 0, 114)) { themeName = - this.hass.selectedTheme?.theme || + this.hass.selectedThemeSettings?.theme || (this.hass.themes.darkMode && this.hass.themes.default_dark_theme ? this.hass.themes.default_dark_theme! : this.hass.themes.default_theme); - options = this.hass.selectedTheme; - if (themeName === "default" && options?.dark === undefined) { - options = { - ...this.hass.selectedTheme, + themeSettings = this.hass.selectedThemeSettings; + if (themeSettings?.dark === undefined) { + themeSettings = { + ...this.hass.selectedThemeSettings, dark: this.hass.themes.darkMode, }; } } else { themeName = - ((this.hass.selectedTheme as unknown) as string) || + ((this.hass.selectedThemeSettings as unknown) as string) || this.hass.themes.default_theme; } @@ -116,7 +131,7 @@ export class HassioMain extends SupervisorBaseElement { this.parentElement, this.hass.themes, themeName, - options + themeSettings ); } } diff --git a/hassio/src/hassio-my-redirect.ts b/hassio/src/hassio-my-redirect.ts index ff9a40b399..54d0d928ca 100644 --- a/hassio/src/hassio-my-redirect.ts +++ b/hassio/src/hassio-my-redirect.ts @@ -1,11 +1,4 @@ -import { - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { html, LitElement, TemplateResult } from "lit"; import { sanitizeUrl } from "@braintree/sanitize-url"; import { createSearchParam, @@ -20,6 +13,7 @@ import { import { navigate } from "../../src/common/navigate"; import { HomeAssistant, Route } from "../../src/types"; import { Supervisor } from "../../src/data/supervisor/supervisor"; +import { customElement, property, state } from "lit/decorators"; const REDIRECTS: Redirects = { supervisor: { @@ -43,6 +37,12 @@ const REDIRECTS: Redirects = { addon: "string", }, }, + supervisor_ingress: { + redirect: "/hassio/ingress", + params: { + addon: "string", + }, + }, supervisor_add_addon_repository: { redirect: "/hassio/store", params: { @@ -59,7 +59,7 @@ class HassioMyRedirect extends LitElement { @property({ attribute: false }) public route!: Route; - @internalProperty() public _error?: TemplateResult | string; + @state() public _error?: TemplateResult | string; connectedCallback() { super.connectedCallback(); @@ -89,7 +89,7 @@ class HassioMyRedirect extends LitElement { return; } - navigate(this, url, true); + navigate(url, { replace: true }); } protected render(): TemplateResult { diff --git a/hassio/src/hassio-panel-router.ts b/hassio/src/hassio-panel-router.ts index 7207d70c7b..28d9f24519 100644 --- a/hassio/src/hassio-panel-router.ts +++ b/hassio/src/hassio-panel-router.ts @@ -1,4 +1,4 @@ -import { customElement, property } from "lit-element"; +import { customElement, property } from "lit/decorators"; import { Supervisor } from "../../src/data/supervisor/supervisor"; import { HassRouterPage, diff --git a/hassio/src/hassio-panel.ts b/hassio/src/hassio-panel.ts index c52339821e..6c6dc54c7c 100644 --- a/hassio/src/hassio-panel.ts +++ b/hassio/src/hassio-panel.ts @@ -1,12 +1,5 @@ -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import { Supervisor, supervisorCollection, @@ -46,7 +39,7 @@ class HassioPanel extends LitElement { `; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { --app-header-background-color: var(--sidebar-background-color); diff --git a/hassio/src/hassio-router.ts b/hassio/src/hassio-router.ts index 4e71ca7ca6..082688399e 100644 --- a/hassio/src/hassio-router.ts +++ b/hassio/src/hassio-router.ts @@ -1,4 +1,4 @@ -import { customElement, property } from "lit-element"; +import { customElement, property } from "lit/decorators"; import { HassioPanelInfo } from "../../src/data/hassio/supervisor"; import { Supervisor } from "../../src/data/supervisor/supervisor"; import { @@ -61,11 +61,10 @@ class HassioRouter extends HassRouterPage { el.hass = this.hass; el.narrow = this.narrow; el.route = route; + el.supervisor = this.supervisor; if (el.localName === "hassio-ingress-view") { el.ingressPanel = this.panel.config && this.panel.config.ingress; - } else { - el.supervisor = this.supervisor; } } diff --git a/hassio/src/ingress-view/hassio-ingress-view.ts b/hassio/src/ingress-view/hassio-ingress-view.ts index 531673ac2f..710cf3b5e3 100644 --- a/hassio/src/ingress-view/hassio-ingress-view.ts +++ b/hassio/src/ingress-view/hassio-ingress-view.ts @@ -1,25 +1,27 @@ import { mdiMenu } from "@mdi/js"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../../src/common/dom/fire_event"; import { navigate } from "../../../src/common/navigate"; +import { extractSearchParam } from "../../../src/common/url/search-params"; +import { nextRender } from "../../../src/common/util/render-status"; import { fetchHassioAddonInfo, HassioAddonDetails, } from "../../../src/data/hassio/addon"; +import { extractApiErrorMessage } from "../../../src/data/hassio/common"; import { createHassioSession, validateHassioSession, } from "../../../src/data/hassio/ingress"; +import { Supervisor } from "../../../src/data/supervisor/supervisor"; import { showAlertDialog } from "../../../src/dialogs/generic/show-dialog-box"; import "../../../src/layouts/hass-loading-screen"; import "../../../src/layouts/hass-subpage"; @@ -29,11 +31,13 @@ import { HomeAssistant, Route } from "../../../src/types"; class HassioIngressView extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; + @property({ attribute: false }) public supervisor!: Supervisor; + @property() public route!: Route; @property() public ingressPanel = false; - @internalProperty() private _addon?: HassioAddonDetails; + @state() private _addon?: HassioAddonDetails; @property({ type: Boolean }) public narrow = false; @@ -80,6 +84,36 @@ class HassioIngressView extends LitElement { : iframe}`; } + protected async firstUpdated(): Promise { + if (this.route.path === "") { + const requestedAddon = extractSearchParam("addon"); + let addonInfo: HassioAddonDetails; + if (requestedAddon) { + try { + addonInfo = await fetchHassioAddonInfo(this.hass, requestedAddon); + } catch (err) { + await showAlertDialog(this, { + text: extractApiErrorMessage(err), + title: requestedAddon, + }); + await nextRender(); + history.back(); + return; + } + if (!addonInfo.ingress) { + await showAlertDialog(this, { + text: this.supervisor.localize("my.error_addon_no_ingress"), + title: addonInfo.name, + }); + await nextRender(); + history.back(); + } else { + navigate(`/hassio/ingress/${addonInfo.slug}`, { replace: true }); + } + } + } + } + protected updated(changedProps: PropertyValues) { super.updated(changedProps); @@ -109,6 +143,7 @@ class HassioIngressView extends LitElement { text: "Unable to fetch add-on info to start Ingress", title: "Supervisor", }); + await nextRender(); history.back(); return; } @@ -118,6 +153,7 @@ class HassioIngressView extends LitElement { text: "Add-on does not support Ingress", title: addon.name, }); + await nextRender(); history.back(); return; } @@ -127,7 +163,8 @@ class HassioIngressView extends LitElement { text: "Add-on is not running. Please start it first", title: addon.name, }); - navigate(this, `/hassio/addon/${addon.slug}/info`, true); + await nextRender(); + navigate(`/hassio/addon/${addon.slug}/info`, { replace: true }); return; } @@ -140,6 +177,7 @@ class HassioIngressView extends LitElement { text: "Unable to create an Ingress session", title: addon.name, }); + await nextRender(); history.back(); return; } @@ -162,7 +200,7 @@ class HassioIngressView extends LitElement { fireEvent(this, "hass-toggle-menu"); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` iframe { display: block; diff --git a/hassio/src/resources/hassio-style.ts b/hassio/src/resources/hassio-style.ts index 99329ee08f..5d52f618da 100644 --- a/hassio/src/resources/hassio-style.ts +++ b/hassio/src/resources/hassio-style.ts @@ -1,4 +1,4 @@ -import { css } from "lit-element"; +import { css } from "lit"; export const hassioStyle = css` .content { diff --git a/hassio/src/snapshots/hassio-snapshots.ts b/hassio/src/snapshots/hassio-snapshots.ts index cf44e561b4..a13f37c9d2 100644 --- a/hassio/src/snapshots/hassio-snapshots.ts +++ b/hassio/src/snapshots/hassio-snapshots.ts @@ -1,118 +1,163 @@ import "@material/mwc-button"; -import "@material/mwc-icon-button"; -import { ActionDetail } from "@material/mwc-list/mwc-list-foundation"; +import { ActionDetail } from "@material/mwc-list"; import "@material/mwc-list/mwc-list-item"; +import { mdiDotsVertical, mdiPlus } from "@mdi/js"; import { - mdiDotsVertical, - mdiPackageVariant, - mdiPackageVariantClosed, -} from "@mdi/js"; -import "@polymer/paper-checkbox/paper-checkbox"; -import type { PaperCheckboxElement } from "@polymer/paper-checkbox/paper-checkbox"; -import "@polymer/paper-input/paper-input"; -import type { PaperInputElement } from "@polymer/paper-input/paper-input"; -import "@polymer/paper-radio-button/paper-radio-button"; -import "@polymer/paper-radio-group/paper-radio-group"; -import type { PaperRadioGroupElement } from "@polymer/paper-radio-group/paper-radio-group"; -import { - css, - CSSResultArray, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; +import memoizeOne from "memoize-one"; import { atLeastVersion } from "../../../src/common/config/version"; -import "../../../src/components/buttons/ha-progress-button"; -import "../../../src/components/ha-button-menu"; -import "../../../src/components/ha-card"; -import "../../../src/components/ha-svg-icon"; -import { extractApiErrorMessage } from "../../../src/data/hassio/common"; +import relativeTime from "../../../src/common/datetime/relative_time"; +import { HASSDomEvent } from "../../../src/common/dom/fire_event"; +import { + DataTableColumnContainer, + RowClickedEvent, +} from "../../../src/components/data-table/ha-data-table"; +import "../../../src/components/ha-button-menu"; +import "../../../src/components/ha-fab"; import { - createHassioFullSnapshot, - createHassioPartialSnapshot, fetchHassioSnapshots, - HassioFullSnapshotCreateParams, - HassioPartialSnapshotCreateParams, + friendlyFolderName, HassioSnapshot, reloadHassioSnapshots, } from "../../../src/data/hassio/snapshot"; import { Supervisor } from "../../../src/data/supervisor/supervisor"; import { showAlertDialog } from "../../../src/dialogs/generic/show-dialog-box"; -import "../../../src/layouts/hass-tabs-subpage"; -import { PolymerChangedEvent } from "../../../src/polymer-types"; +import "../../../src/layouts/hass-tabs-subpage-data-table"; import { haStyle } from "../../../src/resources/styles"; import { HomeAssistant, Route } from "../../../src/types"; -import "../components/hassio-card-content"; -import "../components/hassio-upload-snapshot"; +import { showHassioCreateSnapshotDialog } from "../dialogs/snapshot/show-dialog-hassio-create-snapshot"; import { showHassioSnapshotDialog } from "../dialogs/snapshot/show-dialog-hassio-snapshot"; import { showSnapshotUploadDialog } from "../dialogs/snapshot/show-dialog-snapshot-upload"; import { supervisorTabs } from "../hassio-tabs"; import { hassioStyle } from "../resources/hassio-style"; -interface CheckboxItem { - slug: string; - checked: boolean; - name?: string; -} - @customElement("hassio-snapshots") -class HassioSnapshots extends LitElement { +export class HassioSnapshots extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @property({ type: Boolean }) public narrow!: boolean; - - @property({ attribute: false }) public route!: Route; - @property({ attribute: false }) public supervisor!: Supervisor; - @internalProperty() private _snapshotName = ""; + @property({ type: Object }) public route!: Route; - @internalProperty() private _snapshotPassword = ""; + @property({ type: Boolean }) public narrow!: boolean; - @internalProperty() private _snapshotHasPassword = false; + @property({ type: Boolean }) public isWide!: boolean; - @internalProperty() private _snapshotType: HassioSnapshot["type"] = "full"; + private _firstUpdatedCalled = false; - @internalProperty() private _snapshots?: HassioSnapshot[] = []; + @state() private _snapshots?: HassioSnapshot[] = []; - @internalProperty() private _addonList: CheckboxItem[] = []; - - @internalProperty() private _folderList: CheckboxItem[] = [ - { - slug: "homeassistant", - checked: true, - }, - { slug: "ssl", checked: true }, - { slug: "share", checked: true }, - { slug: "media", checked: true }, - { slug: "addons/local", checked: true }, - ]; - - @internalProperty() private _error = ""; + public connectedCallback(): void { + super.connectedCallback(); + if (this.hass && this._firstUpdatedCalled) { + this.refreshData(); + } + } public async refreshData() { await reloadHassioSnapshots(this.hass); - await this._updateSnapshots(); + await this.fetchSnapshots(); } + private _computeSnapshotContent = (snapshot: HassioSnapshot): string => { + if (snapshot.type === "full") { + return this.supervisor.localize("snapshot.full_snapshot"); + } + const content: string[] = []; + if (snapshot.content.homeassistant) { + content.push("Home Assistant"); + } + if (snapshot.content.folders.length !== 0) { + for (const folder of snapshot.content.folders) { + content.push(friendlyFolderName[folder] || folder); + } + } + + if (snapshot.content.addons.length !== 0) { + for (const addon of snapshot.content.addons) { + content.push( + this.supervisor.supervisor.addons.find( + (entry) => entry.slug === addon + )?.name || addon + ); + } + } + + return content.join(", "); + }; + + protected firstUpdated(changedProperties: PropertyValues): void { + super.firstUpdated(changedProperties); + if (this.hass && this.isConnected) { + this.refreshData(); + } + this._firstUpdatedCalled = true; + } + + private _columns = memoizeOne( + (narrow: boolean): DataTableColumnContainer => ({ + name: { + title: this.supervisor?.localize("snapshot.name") || "", + sortable: true, + filterable: true, + grows: true, + template: (entry: string, snapshot: any) => + html`${entry || snapshot.slug} +
${snapshot.secondary}
`, + }, + date: { + title: this.supervisor?.localize("snapshot.created") || "", + width: "15%", + direction: "desc", + hidden: narrow, + filterable: true, + sortable: true, + template: (entry: string) => + relativeTime(new Date(entry), this.hass.localize), + }, + secondary: { + title: "", + hidden: true, + filterable: true, + }, + }) + ); + + private _snapshotData = memoizeOne((snapshots: HassioSnapshot[]) => + snapshots.map((snapshot) => ({ + ...snapshot, + secondary: this._computeSnapshotContent(snapshot), + })) + ); + protected render(): TemplateResult { + if (!this.supervisor) { + return html``; + } return html` - - - ${this.supervisor.localize("panel.snapshots")} - - ${this.supervisor.localize("common.reload")} + ${this.supervisor?.localize("common.reload")} ${atLeastVersion(this.hass.config.version, 0, 116) ? html` - ${this.supervisor.localize("snapshot.upload_snapshot")} + ${this.supervisor?.localize("snapshot.upload_snapshot")} ` : ""} -
-

${this.supervisor.localize("snapshot.create_snapshot")}

-

- ${this.supervisor.localize("snapshot.description")} -

-
- -
- - ${this.supervisor.localize("snapshot.type")}: - - - ${this.supervisor.localize("snapshot.full_snapshot")} - - - ${this.supervisor.localize("snapshot.partial_snapshot")} - - - ${this._snapshotType === "full" - ? undefined - : html` - ${this.supervisor.localize("snapshot.folders")}: - ${this._folderList.map( - (folder, idx) => html` - - ${this.supervisor.localize( - `snapshot.folder.${folder.slug}` - )} - - ` - )} - ${this.supervisor.localize("snapshot.addons")}: - ${this._addonList.map( - (addon, idx) => html` - - ${addon.name} - - ` - )} - `} - ${this.supervisor.localize("snapshot.security")}: - - ${this.supervisor.localize("snapshot.password_protection")} - - ${this._snapshotHasPassword - ? html` - - ` - : undefined} - ${this._error !== "" - ? html`

${this._error}

` - : undefined} -
-
- - ${this.supervisor.localize("snapshot.create")} - -
-
-
- -

${this.supervisor.localize("snapshot.available_snapshots")}

-
- ${this._snapshots === undefined - ? undefined - : this._snapshots.length === 0 - ? html` - -
- ${this.supervisor.localize("snapshot.no_snapshots")} -
-
- ` - : this._snapshots.map( - (snapshot) => html` - -
- -
-
- ` - )} -
-
-
+ + + + `; } - protected firstUpdated(changedProps: PropertyValues) { - super.firstUpdated(changedProps); - this.refreshData(); - } - - protected updated(changedProps: PropertyValues) { - if (changedProps.has("supervisor")) { - this._addonList = this.supervisor.supervisor.addons - .map((addon) => ({ - slug: addon.slug, - name: addon.name, - checked: true, - })) - .sort((a, b) => (a.name < b.name ? -1 : 1)); - } - } - private _handleAction(ev: CustomEvent) { switch (ev.detail.index) { case 0: @@ -299,157 +199,52 @@ class HassioSnapshots extends LitElement { } } - private _handleTextValueChanged(ev: PolymerChangedEvent) { - const input = ev.currentTarget as PaperInputElement; - this[`_${input.name}`] = ev.detail.value; - } - - private _handleCheckboxValueChanged(ev) { - const input = ev.currentTarget as PaperCheckboxElement; - this[`_${input.name}`] = input.checked; - } - - private _handleRadioValueChanged(ev: PolymerChangedEvent) { - const input = ev.currentTarget as PaperRadioGroupElement; - this[`_${input.getAttribute("name")}`] = ev.detail.value; - } - - private _folderChecked(ev) { - const { idx, checked } = ev.currentTarget!; - this._folderList = this._folderList.map((folder, curIdx) => - curIdx === idx ? { ...folder, checked } : folder - ); - } - - private _addonChecked(ev) { - const { idx, checked } = ev.currentTarget!; - this._addonList = this._addonList.map((addon, curIdx) => - curIdx === idx ? { ...addon, checked } : addon - ); - } - - private async _updateSnapshots() { - try { - this._snapshots = await fetchHassioSnapshots(this.hass); - this._snapshots.sort((a, b) => (a.date < b.date ? 1 : -1)); - } catch (err) { - this._error = extractApiErrorMessage(err); - } - } - - private async _createSnapshot(ev: CustomEvent): Promise { - if (this.supervisor.info.state !== "running") { - await showAlertDialog(this, { - title: this.supervisor.localize("snapshot.could_not_create"), - text: this.supervisor.localize( - "snapshot.create_blocked_not_running", - "state", - this.supervisor.info.state - ), - }); - } - const button = ev.currentTarget as any; - button.progress = true; - - this._error = ""; - if (this._snapshotHasPassword && !this._snapshotPassword.length) { - this._error = this.supervisor.localize("snapshot.enter_password"); - button.progress = false; - return; - } - await this.updateComplete; - - const name = - this._snapshotName || - new Date().toLocaleDateString(navigator.language, { - weekday: "long", - year: "numeric", - month: "short", - day: "numeric", - }); - - try { - if (this._snapshotType === "full") { - const data: HassioFullSnapshotCreateParams = { name }; - if (this._snapshotHasPassword) { - data.password = this._snapshotPassword; - } - await createHassioFullSnapshot(this.hass, data); - } else { - const addons = this._addonList - .filter((addon) => addon.checked) - .map((addon) => addon.slug); - const folders = this._folderList - .filter((folder) => folder.checked) - .map((folder) => folder.slug); - - const data: HassioPartialSnapshotCreateParams = { - name, - folders, - addons, - }; - if (this._snapshotHasPassword) { - data.password = this._snapshotPassword; - } - await createHassioPartialSnapshot(this.hass, data); - } - this._updateSnapshots(); - } catch (err) { - this._error = extractApiErrorMessage(err); - } - button.progress = false; - } - - private _computeDetails(snapshot: HassioSnapshot) { - const type = - snapshot.type === "full" - ? this.supervisor.localize("snapshot.full_snapshot") - : this.supervisor.localize("snapshot.partial_snapshot"); - return snapshot.protected ? `${type}, password protected` : type; - } - - private _snapshotClicked(ev) { - showHassioSnapshotDialog(this, { - slug: ev.currentTarget!.snapshot.slug, - supervisor: this.supervisor, - onDelete: () => this._updateSnapshots(), - }); - } - private _showUploadSnapshotDialog() { showSnapshotUploadDialog(this, { showSnapshot: (slug: string) => showHassioSnapshotDialog(this, { slug, supervisor: this.supervisor, - onDelete: () => this._updateSnapshots(), + onDelete: () => this.fetchSnapshots(), }), reloadSnapshot: () => this.refreshData(), }); } - static get styles(): CSSResultArray { - return [ - haStyle, - hassioStyle, - css` - paper-radio-group { - display: block; - } - paper-radio-button { - padding: 0 0 2px 2px; - } - paper-radio-button, - paper-checkbox, - paper-input[type="password"] { - display: block; - margin: 4px 0 4px 48px; - } - .pointer { - cursor: pointer; - } - `, - ]; + private async fetchSnapshots() { + await reloadHassioSnapshots(this.hass); + this._snapshots = await fetchHassioSnapshots(this.hass); + } + + private _handleRowClicked(ev: HASSDomEvent) { + const slug = ev.detail.id; + showHassioSnapshotDialog(this, { + slug, + supervisor: this.supervisor, + onDelete: () => this.fetchSnapshots(), + }); + } + + private _createSnapshot() { + if (this.supervisor!.info.state !== "running") { + showAlertDialog(this, { + title: this.supervisor!.localize("snapshot.could_not_create"), + text: this.supervisor!.localize( + "snapshot.create_blocked_not_running", + "state", + this.supervisor!.info.state + ), + }); + return; + } + showHassioCreateSnapshotDialog(this, { + supervisor: this.supervisor!, + onCreate: () => this.fetchSnapshots(), + }); + } + + static get styles(): CSSResultGroup { + return [haStyle, hassioStyle]; } } diff --git a/hassio/src/supervisor-base-element.ts b/hassio/src/supervisor-base-element.ts index 2043a8a2ae..9811f36266 100644 --- a/hassio/src/supervisor-base-element.ts +++ b/hassio/src/supervisor-base-element.ts @@ -1,10 +1,6 @@ import { Collection, UnsubscribeFunc } from "home-assistant-js-websocket"; -import { - internalProperty, - LitElement, - property, - PropertyValues, -} from "lit-element"; +import { LitElement, PropertyValues } from "lit"; +import { property, state } from "lit/decorators"; import { atLeastVersion } from "../../src/common/config/version"; import { computeLocalize } from "../../src/common/translations/localize"; import { fetchHassioAddonsInfo } from "../../src/data/hassio/addon"; @@ -46,14 +42,11 @@ export class SupervisorBaseElement extends urlSyncMixin( localize: () => "", }; - @internalProperty() private _unsubs: Record = {}; + @state() private _unsubs: Record = {}; - @internalProperty() private _collections: Record< - string, - Collection - > = {}; + @state() private _collections: Record> = {}; - @internalProperty() private _language = "en"; + @state() private _language = "en"; public connectedCallback(): void { super.connectedCallback(); diff --git a/hassio/src/system/hassio-core-info.ts b/hassio/src/system/hassio-core-info.ts index bdb156fe20..e335a1df78 100644 --- a/hassio/src/system/hassio-core-info.ts +++ b/hassio/src/system/hassio-core-info.ts @@ -1,15 +1,7 @@ import "@material/mwc-button"; import "@material/mwc-list/mwc-list-item"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../../src/common/dom/fire_event"; import "../../../src/components/buttons/ha-progress-button"; import "../../../src/components/ha-button-menu"; @@ -39,7 +31,7 @@ class HassioCoreInfo extends LitElement { @property({ attribute: false }) public supervisor!: Supervisor; - @internalProperty() private _metrics?: HassioStats; + @state() private _metrics?: HassioStats; protected render(): TemplateResult | void { const metrics = [ @@ -189,7 +181,7 @@ class HassioCoreInfo extends LitElement { }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, hassioStyle, diff --git a/hassio/src/system/hassio-host-info.ts b/hassio/src/system/hassio-host-info.ts index db5e4e2f7e..cde6becf58 100644 --- a/hassio/src/system/hassio-host-info.ts +++ b/hassio/src/system/hassio-host-info.ts @@ -2,16 +2,9 @@ import "@material/mwc-button"; import { ActionDetail } from "@material/mwc-list/mwc-list-foundation"; import "@material/mwc-list/mwc-list-item"; import { mdiDotsVertical } from "@mdi/js"; -import { safeDump } from "js-yaml"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { dump } from "js-yaml"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import memoizeOne from "memoize-one"; import { atLeastVersion } from "../../../src/common/config/version"; import { fireEvent } from "../../../src/common/dom/fire_event"; @@ -240,7 +233,7 @@ class HassioHostInfo extends LitElement { const content = await fetchHassioHardwareInfo(this.hass); showHassioMarkdownDialog(this, { title: this.supervisor.localize("system.host.hardware"), - content: `
${safeDump(content, { indent: 2 })}
`, + content: `
${dump(content, { indent: 2 })}
`, }); } catch (err) { showAlertDialog(this, { @@ -415,7 +408,7 @@ class HassioHostInfo extends LitElement { } } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, hassioStyle, diff --git a/hassio/src/system/hassio-supervisor-info.ts b/hassio/src/system/hassio-supervisor-info.ts index db60abcdc5..62baf5809e 100644 --- a/hassio/src/system/hassio-supervisor-info.ts +++ b/hassio/src/system/hassio-supervisor-info.ts @@ -1,13 +1,5 @@ -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { atLeastVersion } from "../../../src/common/config/version"; import { fireEvent } from "../../../src/common/dom/fire_event"; import "../../../src/components/buttons/ha-progress-button"; @@ -67,7 +59,7 @@ class HassioSupervisorInfo extends LitElement { @property({ attribute: false }) public supervisor!: Supervisor; - @internalProperty() private _metrics?: HassioStats; + @state() private _metrics?: HassioStats; protected render(): TemplateResult | void { const metrics = [ @@ -504,7 +496,7 @@ class HassioSupervisorInfo extends LitElement { } } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, hassioStyle, diff --git a/hassio/src/system/hassio-supervisor-log.ts b/hassio/src/system/hassio-supervisor-log.ts index 29ce5a242a..ac0f3e8cdc 100644 --- a/hassio/src/system/hassio-supervisor-log.ts +++ b/hassio/src/system/hassio-supervisor-log.ts @@ -2,16 +2,8 @@ import "@material/mwc-button"; import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import "../../../src/components/buttons/ha-progress-button"; import "../../../src/components/ha-card"; import { extractApiErrorMessage } from "../../../src/data/hassio/common"; @@ -61,11 +53,11 @@ class HassioSupervisorLog extends LitElement { @property({ attribute: false }) public supervisor!: Supervisor; - @internalProperty() private _error?: string; + @state() private _error?: string; - @internalProperty() private _selectedLogProvider = "supervisor"; + @state() private _selectedLogProvider = "supervisor"; - @internalProperty() private _content?: string; + @state() private _content?: string; public async connectedCallback(): Promise { super.connectedCallback(); @@ -146,7 +138,7 @@ class HassioSupervisorLog extends LitElement { } } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, hassioStyle, diff --git a/hassio/src/system/hassio-system.ts b/hassio/src/system/hassio-system.ts index 5c02662932..22704fcc4a 100644 --- a/hassio/src/system/hassio-system.ts +++ b/hassio/src/system/hassio-system.ts @@ -1,12 +1,5 @@ -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import { Supervisor } from "../../../src/data/supervisor/supervisor"; import "../../../src/layouts/hass-tabs-subpage"; import { haStyle } from "../../../src/resources/styles"; @@ -64,7 +57,7 @@ class HassioSystem extends LitElement { `; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, hassioStyle, diff --git a/lint-staged.config.js b/lint-staged.config.js new file mode 100644 index 0000000000..15d6269cbc --- /dev/null +++ b/lint-staged.config.js @@ -0,0 +1,5 @@ +module.exports = { + "*.ts": () => "tsc -p tsconfig.json", + "*.{js,ts}": "eslint --fix", + "!(/translations)*.{js,ts,json,css,md,html}": "prettier --write", +}; diff --git a/package.json b/package.json index 3a3708fa12..af32469d89 100644 --- a/package.json +++ b/package.json @@ -16,13 +16,13 @@ "lint:lit": "lit-analyzer \"**/src/**/*.ts\" --format markdown --outFile result.md", "lint": "yarn run lint:eslint && yarn run lint:prettier && yarn run lint:types", "format": "yarn run format:eslint && yarn run format:prettier", - "mocha": "node_modules/.bin/ts-mocha -p test-mocha/tsconfig.test.json --opts test-mocha/mocha.opts", + "mocha": "ts-mocha -p test-mocha/tsconfig.test.json \"test-mocha/**/*.ts\"", "test": "yarn run lint && yarn run mocha" }, "author": "Paulus Schoutsen (http://paulusschoutsen.nl)", "license": "Apache-2.0", "dependencies": { - "@braintree/sanitize-url": "^5.0.0", + "@braintree/sanitize-url": "^5.0.1", "@codemirror/commands": "^0.18.0", "@codemirror/gutter": "^0.18.0", "@codemirror/highlight": "^0.18.0", @@ -34,33 +34,34 @@ "@codemirror/stream-parser": "^0.18.0", "@codemirror/text": "^0.18.0", "@codemirror/view": "^0.18.0", - "@formatjs/intl-getcanonicallocales": "^1.4.6", - "@formatjs/intl-pluralrules": "^3.4.10", + "@formatjs/intl-getcanonicallocales": "^1.5.10", + "@formatjs/intl-locale": "^2.4.28", + "@formatjs/intl-pluralrules": "^4.0.22", "@fullcalendar/common": "5.1.0", "@fullcalendar/core": "5.1.0", "@fullcalendar/daygrid": "5.1.0", "@fullcalendar/interaction": "5.1.0", "@fullcalendar/list": "5.1.0", - "@material/chips": "=9.0.0-canary.1c156d69d.0", - "@material/mwc-button": "^0.20.0", - "@material/mwc-checkbox": "^0.20.0", - "@material/mwc-circular-progress": "^0.20.0", - "@material/mwc-dialog": "^0.20.0", - "@material/mwc-fab": "^0.20.0", - "@material/mwc-formfield": "^0.20.0", - "@material/mwc-icon-button": "^0.20.0", - "@material/mwc-list": "^0.20.0", - "@material/mwc-menu": "^0.20.0", - "@material/mwc-radio": "^0.20.0", - "@material/mwc-ripple": "^0.20.0", - "@material/mwc-switch": "^0.20.0", - "@material/mwc-tab": "^0.20.0", - "@material/mwc-tab-bar": "^0.20.0", - "@material/top-app-bar": "=9.0.0-canary.1c156d69d.0", + "@lit-labs/virtualizer": "^0.6.0", + "@material/chips": "=12.0.0-canary.1a8d06483.0", + "@material/mwc-button": "canary", + "@material/mwc-checkbox": "canary", + "@material/mwc-circular-progress": "canary", + "@material/mwc-dialog": "canary", + "@material/mwc-fab": "canary", + "@material/mwc-formfield": "canary", + "@material/mwc-icon-button": "canary", + "@material/mwc-list": "canary", + "@material/mwc-menu": "canary", + "@material/mwc-radio": "canary", + "@material/mwc-ripple": "canary", + "@material/mwc-switch": "canary", + "@material/mwc-tab": "canary", + "@material/mwc-tab-bar": "canary", + "@material/top-app-bar": "=12.0.0-canary.1a8d06483.0", "@mdi/js": "5.9.55", "@mdi/svg": "5.9.55", "@polymer/app-layout": "^3.0.2", - "@polymer/app-route": "^3.0.2", "@polymer/app-storage": "^3.0.2", "@polymer/iron-autogrow-textarea": "^3.0.1", "@polymer/iron-flex-layout": "^3.0.1", @@ -98,29 +99,28 @@ "@vibrant/quantizer-mmcq": "^3.2.1-alpha.1", "@vue/web-component-wrapper": "^1.2.0", "@webcomponents/webcomponentsjs": "^2.2.7", - "chart.js": "~2.8.0", - "chartjs-chart-timeline": "^0.3.0", - "comlink": "^4.3.0", + "chart.js": "^2.9.4", + "chartjs-chart-timeline": "^0.4.0", + "comlink": "^4.3.1", "core-js": "^3.6.5", - "cropperjs": "^1.5.7", + "cropperjs": "^1.5.11", "deep-clone-simple": "^1.1.1", "deep-freeze": "^0.0.1", "fecha": "^4.2.0", "fuse.js": "^6.0.0", "google-timezones-json": "^1.0.2", - "hls.js": "^1.0.1", - "home-assistant-js-websocket": "^5.9.0", - "idb-keyval": "^3.2.0", - "intl-messageformat": "^8.3.9", - "js-yaml": "^3.13.1", - "leaflet": "^1.4.0", + "hls.js": "^1.0.4", + "home-assistant-js-websocket": "^5.10.0", + "idb-keyval": "^5.0.5", + "intl-messageformat": "^9.6.16", + "js-yaml": "^4.1.0", + "leaflet": "^1.7.1", "leaflet-draw": "^1.0.4", - "lit-element": "^2.5.0", - "lit-html": "^1.4.0", - "lit-virtualizer": "^0.4.2", - "marked": "2.0.0", + "lit": "^2.0.0-rc.2", + "lit-vaadin-helpers": "^0.1.3", + "marked": "^2.0.5", "mdn-polyfills": "^5.16.0", - "memoize-one": "^5.0.2", + "memoize-one": "^5.2.1", "node-vibrant": "3.2.1-alpha.1", "proxy-polyfill": "^0.3.1", "punycode": "^2.1.1", @@ -129,13 +129,13 @@ "resize-observer-polyfill": "^1.5.1", "roboto-fontface": "^0.10.0", "sortablejs": "^1.10.2", - "superstruct": "^0.10.13", - "tinykeys": "^1.1.1", + "superstruct": "^0.15.2", + "tinykeys": "^1.1.3", "tsparticles": "^1.19.2", "unfetch": "^4.1.0", - "vis-data": "^7.1.1", + "vis-data": "^7.1.2", "vis-network": "^8.5.4", - "vue": "^2.6.11", + "vue": "^2.6.12", "vue2-daterange-picker": "^0.5.1", "web-animations-js": "^2.3.2", "workbox-cacheable-response": "^6.1.5", @@ -144,10 +144,10 @@ "workbox-precaching": "^6.1.5", "workbox-routing": "^6.1.5", "workbox-strategies": "^6.1.5", - "xss": "^1.0.6" + "xss": "^1.0.9" }, "devDependencies": { - "@babel/core": "^7.14.0", + "@babel/core": "^7.14.3", "@babel/plugin-external-helpers": "^7.12.13", "@babel/plugin-proposal-class-properties": "^7.13.0", "@babel/plugin-proposal-decorators": "^7.13.15", @@ -156,7 +156,7 @@ "@babel/plugin-proposal-optional-chaining": "^7.13.12", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/preset-env": "^7.14.0", + "@babel/preset-env": "^7.14.2", "@babel/preset-typescript": "^7.13.0", "@koa/cors": "^3.1.0", "@open-wc/dev-server-hmr": "^0.0.2", @@ -165,16 +165,13 @@ "@rollup/plugin-json": "^4.0.3", "@rollup/plugin-node-resolve": "^7.1.3", "@rollup/plugin-replace": "^2.3.2", - "@types/chai": "^4.1.7", - "@types/chromecast-caf-receiver": "^5.0.11", + "@types/chromecast-caf-receiver": "5.0.12", "@types/chromecast-caf-sender": "^1.0.3", - "@types/js-yaml": "^3.12.1", - "@types/leaflet": "^1.4.3", - "@types/leaflet-draw": "^1.0.1", - "@types/marked": "^1.2.2", - "@types/memoize-one": "4.1.0", - "@types/mocha": "^7.0.2", - "@types/resize-observer-browser": "^0.1.3", + "@types/js-yaml": "^4.0.1", + "@types/leaflet": "^1.7.0", + "@types/leaflet-draw": "^1.0.3", + "@types/marked": "^2.0.3", + "@types/mocha": "^8.2.2", "@types/sortablejs": "^1.10.6", "@types/webspeechapi": "^0.0.29", "@typescript-eslint/eslint-plugin": "^4.22.0", @@ -182,7 +179,7 @@ "@web/dev-server": "^0.0.24", "@web/dev-server-rollup": "^0.2.11", "babel-loader": "^8.1.0", - "chai": "^4.2.0", + "chai": "^4.3.4", "cpx": "^1.5.0", "del": "^4.0.0", "eslint": "^7.25.0", @@ -196,7 +193,7 @@ "eslint-plugin-wc": "^1.3.0", "fancy-log": "^1.3.3", "fs-extra": "^7.0.1", - "gulp": "^4.0.0", + "gulp": "^4.0.2", "gulp-foreach": "^0.1.0", "gulp-json-transform": "^0.4.6", "gulp-merge-json": "^1.3.1", @@ -204,13 +201,13 @@ "gulp-zopfli-green": "^3.0.1", "html-minifier": "^4.0.0", "husky": "^1.3.1", - "lint-staged": "^8.1.5", + "lint-staged": "^10.5.4", "lit-analyzer": "^1.2.1", "lodash.template": "^4.5.0", "magic-string": "^0.25.7", "map-stream": "^0.0.7", "merge-stream": "^1.0.1", - "mocha": "^7.2.0", + "mocha": "^8.4.0", "object-hash": "^2.0.3", "open": "^7.0.4", "prettier": "^2.0.4", @@ -220,13 +217,13 @@ "rollup-plugin-string": "^3.0.0", "rollup-plugin-terser": "^5.3.0", "rollup-plugin-visualizer": "^4.0.4", - "serve": "^11.3.0", - "sinon": "^7.3.1", + "serve": "^11.3.2", + "sinon": "^11.0.0", "source-map-url": "^0.4.0", "systemjs": "^6.3.2", - "terser-webpack-plugin": "^5.1.1", + "terser-webpack-plugin": "^5.1.2", "ts-lit-plugin": "^1.2.1", - "ts-mocha": "^7.0.0", + "ts-mocha": "^8.0.0", "typescript": "^4.2.4", "vinyl-buffer": "^1.0.1", "vinyl-source-stream": "^2.0.0", @@ -241,8 +238,8 @@ "resolutions": { "@webcomponents/webcomponentsjs": "^2.2.10", "@polymer/polymer": "3.1.0", - "lit-html": "1.4.0", - "lit-element": "2.5.0" + "lit-html": "2.0.0-rc.3", + "lit-element": "3.0.0-rc.2" }, "main": "src/home-assistant.js", "husky": { @@ -250,17 +247,6 @@ "pre-commit": "lint-staged" } }, - "lint-staged": { - "linters": { - "*.{js,ts,json,css,md}": [ - "prettier --write", - "git add" - ] - }, - "ignore": [ - "translations/**" - ] - }, "prettier": { "trailingComma": "es5", "arrowParens": "always" diff --git a/setup.py b/setup.py index b2cbfd5720..152002c007 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup( name="home-assistant-frontend", - version="20210504.0", + version="20210526.0", description="The Home Assistant frontend", url="https://github.com/home-assistant/home-assistant-polymer", author="The Home Assistant Authors", diff --git a/src/auth/ha-auth-flow.ts b/src/auth/ha-auth-flow.ts index 3164b6dafb..85dcf053e9 100644 --- a/src/auth/ha-auth-flow.ts +++ b/src/auth/ha-auth-flow.ts @@ -1,14 +1,13 @@ import "@material/mwc-button"; import { css, - CSSResult, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { property, state } from "lit/decorators"; import "../components/ha-form/ha-form"; import "../components/ha-markdown"; import { AuthProvider } from "../data/auth"; @@ -29,13 +28,13 @@ class HaAuthFlow extends litLocalizeLiteMixin(LitElement) { @property() public oauth2State?: string; - @internalProperty() private _state: State = "loading"; + @state() private _state: State = "loading"; - @internalProperty() private _stepData: any = {}; + @state() private _stepData: any = {}; - @internalProperty() private _step?: DataEntryFlowStep; + @state() private _step?: DataEntryFlowStep; - @internalProperty() private _errorMessage?: string; + @state() private _errorMessage?: string; protected render() { return html`
${this._renderForm()}
`; @@ -313,7 +312,7 @@ class HaAuthFlow extends litLocalizeLiteMixin(LitElement) { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { /* So we can set min-height to avoid jumping during loading */ diff --git a/src/auth/ha-authorize.ts b/src/auth/ha-authorize.ts index ceabc2b409..9d51431102 100644 --- a/src/auth/ha-authorize.ts +++ b/src/auth/ha-authorize.ts @@ -1,12 +1,5 @@ -import { - css, - CSSResult, - html, - internalProperty, - LitElement, - property, - PropertyValues, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit"; +import { property, state } from "lit/decorators"; import punycode from "punycode"; import { applyThemesOnElement } from "../common/dom/apply_themes_on_element"; import { extractSearchParamsObject } from "../common/url/search-params"; @@ -32,11 +25,11 @@ class HaAuthorize extends litLocalizeLiteMixin(LitElement) { @property() public oauth2State?: string; - @internalProperty() private _authProvider?: AuthProvider; + @state() private _authProvider?: AuthProvider; - @internalProperty() private _authProviders?: AuthProvider[]; + @state() private _authProviders?: AuthProvider[]; - @internalProperty() private _discovery?: DiscoveryInformation; + @state() private _discovery?: DiscoveryInformation; constructor() { super(); @@ -189,7 +182,7 @@ class HaAuthorize extends litLocalizeLiteMixin(LitElement) { this._authProvider = ev.detail; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` ha-pick-auth-provider { display: block; diff --git a/src/auth/ha-pick-auth-provider.ts b/src/auth/ha-pick-auth-provider.ts index 63e213e6d1..e471cb6908 100644 --- a/src/auth/ha-pick-auth-provider.ts +++ b/src/auth/ha-pick-auth-provider.ts @@ -1,6 +1,7 @@ import "@polymer/paper-item/paper-item"; import "@polymer/paper-item/paper-item-body"; -import { html, LitElement, property } from "lit-element"; +import { html, LitElement } from "lit"; +import { property } from "lit/decorators"; import { fireEvent } from "../common/dom/fire_event"; import "../components/ha-icon-next"; import { AuthProvider } from "../data/auth"; diff --git a/src/common/datetime/format_date.ts b/src/common/datetime/format_date.ts index c7c02d38fe..fa82187a46 100644 --- a/src/common/datetime/format_date.ts +++ b/src/common/datetime/format_date.ts @@ -1,21 +1,32 @@ import { format } from "fecha"; -import { FrontendTranslationData } from "../../data/translation"; +import memoizeOne from "memoize-one"; +import { FrontendLocaleData } from "../../data/translation"; import { toLocaleDateStringSupportsOptions } from "./check_options_support"; +const formatDateMem = memoizeOne( + (locale: FrontendLocaleData) => + new Intl.DateTimeFormat(locale.language, { + year: "numeric", + month: "long", + day: "numeric", + }) +); + export const formatDate = toLocaleDateStringSupportsOptions - ? (dateObj: Date, locales: FrontendTranslationData) => - dateObj.toLocaleDateString(locales.language, { - year: "numeric", - month: "long", - day: "numeric", - }) + ? (dateObj: Date, locale: FrontendLocaleData) => + formatDateMem(locale).format(dateObj) : (dateObj: Date) => format(dateObj, "longDate"); +const formatDateWeekdayMem = memoizeOne( + (locale: FrontendLocaleData) => + new Intl.DateTimeFormat(locale.language, { + weekday: "long", + month: "long", + day: "numeric", + }) +); + export const formatDateWeekday = toLocaleDateStringSupportsOptions - ? (dateObj: Date, locales: FrontendTranslationData) => - dateObj.toLocaleDateString(locales.language, { - weekday: "long", - month: "short", - day: "numeric", - }) + ? (dateObj: Date, locale: FrontendLocaleData) => + formatDateWeekdayMem(locale).format(dateObj) : (dateObj: Date) => format(dateObj, "dddd, MMM D"); diff --git a/src/common/datetime/format_date_time.ts b/src/common/datetime/format_date_time.ts index d4b76a1da6..850e82b185 100644 --- a/src/common/datetime/format_date_time.ts +++ b/src/common/datetime/format_date_time.ts @@ -1,26 +1,42 @@ import { format } from "fecha"; -import { FrontendTranslationData } from "../../data/translation"; +import memoizeOne from "memoize-one"; +import { FrontendLocaleData } from "../../data/translation"; import { toLocaleStringSupportsOptions } from "./check_options_support"; +import { useAmPm } from "./use_am_pm"; + +const formatDateTimeMem = memoizeOne( + (locale: FrontendLocaleData) => + new Intl.DateTimeFormat(locale.language, { + year: "numeric", + month: "long", + day: "numeric", + hour: "numeric", + minute: "2-digit", + hour12: useAmPm(locale), + }) +); export const formatDateTime = toLocaleStringSupportsOptions - ? (dateObj: Date, locales: FrontendTranslationData) => - dateObj.toLocaleString(locales.language, { - year: "numeric", - month: "long", - day: "numeric", - hour: "numeric", - minute: "2-digit", - }) - : (dateObj: Date) => format(dateObj, "MMMM D, YYYY, HH:mm"); + ? (dateObj: Date, locale: FrontendLocaleData) => + formatDateTimeMem(locale).format(dateObj) + : (dateObj: Date, locale: FrontendLocaleData) => + format(dateObj, "MMMM D, YYYY, HH:mm" + useAmPm(locale) ? " A" : ""); + +const formatDateTimeWithSecondsMem = memoizeOne( + (locale: FrontendLocaleData) => + new Intl.DateTimeFormat(locale.language, { + year: "numeric", + month: "long", + day: "numeric", + hour: "numeric", + minute: "2-digit", + second: "2-digit", + hour12: useAmPm(locale), + }) +); export const formatDateTimeWithSeconds = toLocaleStringSupportsOptions - ? (dateObj: Date, locales: FrontendTranslationData) => - dateObj.toLocaleString(locales.language, { - year: "numeric", - month: "long", - day: "numeric", - hour: "numeric", - minute: "2-digit", - second: "2-digit", - }) - : (dateObj: Date) => format(dateObj, "MMMM D, YYYY, HH:mm:ss"); + ? (dateObj: Date, locale: FrontendLocaleData) => + formatDateTimeWithSecondsMem(locale).format(dateObj) + : (dateObj: Date, locale: FrontendLocaleData) => + format(dateObj, "MMMM D, YYYY, HH:mm:ss" + useAmPm(locale) ? " A" : ""); diff --git a/src/common/datetime/format_time.ts b/src/common/datetime/format_time.ts index d2068f7638..14bbdf8e53 100644 --- a/src/common/datetime/format_time.ts +++ b/src/common/datetime/format_time.ts @@ -1,29 +1,52 @@ import { format } from "fecha"; -import { FrontendTranslationData } from "../../data/translation"; +import memoizeOne from "memoize-one"; +import { FrontendLocaleData } from "../../data/translation"; import { toLocaleTimeStringSupportsOptions } from "./check_options_support"; +import { useAmPm } from "./use_am_pm"; + +const formatTimeMem = memoizeOne( + (locale: FrontendLocaleData) => + new Intl.DateTimeFormat(locale.language, { + hour: "numeric", + minute: "2-digit", + hour12: useAmPm(locale), + }) +); export const formatTime = toLocaleTimeStringSupportsOptions - ? (dateObj: Date, locales: FrontendTranslationData) => - dateObj.toLocaleTimeString(locales.language, { - hour: "numeric", - minute: "2-digit", - }) - : (dateObj: Date) => format(dateObj, "shortTime"); + ? (dateObj: Date, locale: FrontendLocaleData) => + formatTimeMem(locale).format(dateObj) + : (dateObj: Date, locale: FrontendLocaleData) => + format(dateObj, "shortTime" + useAmPm(locale) ? " A" : ""); + +const formatTimeWithSecondsMem = memoizeOne( + (locale: FrontendLocaleData) => + new Intl.DateTimeFormat(locale.language, { + hour: "numeric", + minute: "2-digit", + second: "2-digit", + hour12: useAmPm(locale), + }) +); export const formatTimeWithSeconds = toLocaleTimeStringSupportsOptions - ? (dateObj: Date, locales: FrontendTranslationData) => - dateObj.toLocaleTimeString(locales.language, { - hour: "numeric", - minute: "2-digit", - second: "2-digit", - }) - : (dateObj: Date) => format(dateObj, "mediumTime"); + ? (dateObj: Date, locale: FrontendLocaleData) => + formatTimeWithSecondsMem(locale).format(dateObj) + : (dateObj: Date, locale: FrontendLocaleData) => + format(dateObj, "mediumTime" + useAmPm(locale) ? " A" : ""); + +const formatTimeWeekdayMem = memoizeOne( + (locale: FrontendLocaleData) => + new Intl.DateTimeFormat(locale.language, { + weekday: "long", + hour: "numeric", + minute: "2-digit", + hour12: useAmPm(locale), + }) +); export const formatTimeWeekday = toLocaleTimeStringSupportsOptions - ? (dateObj: Date, locales: FrontendTranslationData) => - dateObj.toLocaleTimeString(locales.language, { - weekday: "long", - hour: "numeric", - minute: "2-digit", - }) - : (dateObj: Date) => format(dateObj, "dddd, HH:mm"); + ? (dateObj: Date, locale: FrontendLocaleData) => + formatTimeWeekdayMem(locale).format(dateObj) + : (dateObj: Date, locale: FrontendLocaleData) => + format(dateObj, "dddd, HH:mm" + useAmPm(locale) ? " A" : ""); diff --git a/src/common/datetime/use_am_pm.ts b/src/common/datetime/use_am_pm.ts new file mode 100644 index 0000000000..cf5b2c124e --- /dev/null +++ b/src/common/datetime/use_am_pm.ts @@ -0,0 +1,15 @@ +import { FrontendLocaleData, TimeFormat } from "../../data/translation"; + +export const useAmPm = (locale: FrontendLocaleData): boolean => { + if ( + locale.time_format === TimeFormat.language || + locale.time_format === TimeFormat.system + ) { + const testLanguage = + locale.time_format === TimeFormat.language ? locale.language : undefined; + const test = new Date().toLocaleString(testLanguage); + return test.includes("AM") || test.includes("PM"); + } + + return locale.time_format === TimeFormat.am_pm; +}; diff --git a/src/common/decorators/local-storage.ts b/src/common/decorators/local-storage.ts index e72c9f0657..8456c5be48 100644 --- a/src/common/decorators/local-storage.ts +++ b/src/common/decorators/local-storage.ts @@ -1,5 +1,5 @@ import { UnsubscribeFunc } from "home-assistant-js-websocket"; -import { PropertyDeclaration, UpdatingElement } from "lit-element"; +import { PropertyDeclaration, ReactiveElement } from "lit"; import type { ClassElement } from "../../types"; type Callback = (oldValue: any, newValue: any) => void; @@ -93,7 +93,7 @@ export const LocalStorage = ( storage.addFromStorage(storageKey); - const subscribe = (el: UpdatingElement): UnsubscribeFunc => + const subscribe = (el: ReactiveElement): UnsubscribeFunc => storage.subscribeChanges(storageKey!, (oldValue) => { el.requestUpdate(clsElement.key, oldValue); }); @@ -101,7 +101,7 @@ export const LocalStorage = ( const getValue = (): any => storage.hasKey(storageKey!) ? storage.getValue(storageKey!) : initVal; - const setValue = (el: UpdatingElement, value: any) => { + const setValue = (el: ReactiveElement, value: any) => { let oldValue: unknown | undefined; if (property) { oldValue = getValue(); @@ -117,7 +117,7 @@ export const LocalStorage = ( placement: "prototype", key: clsElement.key, descriptor: { - set(this: UpdatingElement, value: unknown) { + set(this: ReactiveElement, value: unknown) { setValue(this, value); }, get() { @@ -126,7 +126,7 @@ export const LocalStorage = ( enumerable: true, configurable: true, }, - finisher(cls: typeof UpdatingElement) { + finisher(cls: typeof ReactiveElement) { if (property) { const connectedCallback = cls.prototype.connectedCallback; const disconnectedCallback = cls.prototype.disconnectedCallback; diff --git a/src/common/decorators/restore-scroll.ts b/src/common/decorators/restore-scroll.ts index 059c83966e..e7353e729f 100644 --- a/src/common/decorators/restore-scroll.ts +++ b/src/common/decorators/restore-scroll.ts @@ -1,4 +1,4 @@ -import type { LitElement } from "lit-element"; +import type { LitElement } from "lit"; import type { ClassElement } from "../../types"; export const restoreScroll = (selector: string): any => ( diff --git a/src/common/dom/apply_themes_on_element.ts b/src/common/dom/apply_themes_on_element.ts index 176068c92b..90143f9bcf 100644 --- a/src/common/dom/apply_themes_on_element.ts +++ b/src/common/dom/apply_themes_on_element.ts @@ -1,4 +1,4 @@ -import { Theme } from "../../data/ws-themes"; +import { ThemeVars } from "../../data/ws-themes"; import { darkStyles, derivedStyles } from "../../resources/styles"; import type { HomeAssistant } from "../../types"; import { @@ -23,62 +23,90 @@ let PROCESSED_THEMES: Record = {}; * Apply a theme to an element by setting the CSS variables on it. * * element: Element to apply theme on. - * themes: HASS Theme information - * selectedTheme: selected theme. + * themes: HASS theme information. + * selectedTheme: Selected theme. + * themeSettings: Settings such as selected dark mode and colors. */ export const applyThemesOnElement = ( element, themes: HomeAssistant["themes"], selectedTheme?: string, - themeOptions?: Partial + themeSettings?: Partial ) => { let cacheKey = selectedTheme; - let themeRules: Partial = {}; + let themeRules: Partial = {}; - if (selectedTheme === "default" && themeOptions) { - if (themeOptions.dark) { + if (themeSettings) { + if (themeSettings.dark) { cacheKey = `${cacheKey}__dark`; - themeRules = darkStyles; - if (themeOptions.primaryColor) { + themeRules = { ...darkStyles }; + } + + if (selectedTheme === "default") { + // Determine the primary and accent colors from the current settings. + // Fallbacks are implicitly the HA default blue and orange or the + // derived "darkStyles" values, depending on the light vs dark mode. + const primaryColor = themeSettings.primaryColor; + const accentColor = themeSettings.accentColor; + + if (themeSettings.dark && primaryColor) { themeRules["app-header-background-color"] = hexBlend( - themeOptions.primaryColor, + primaryColor, "#121212", 8 ); } - } - if (themeOptions.primaryColor) { - cacheKey = `${cacheKey}__primary_${themeOptions.primaryColor}`; - const rgbPrimaryColor = hex2rgb(themeOptions.primaryColor); - const labPrimaryColor = rgb2lab(rgbPrimaryColor); - themeRules["primary-color"] = themeOptions.primaryColor; - const rgbLigthPrimaryColor = lab2rgb(labBrighten(labPrimaryColor)); - themeRules["light-primary-color"] = rgb2hex(rgbLigthPrimaryColor); - themeRules["dark-primary-color"] = lab2hex(labDarken(labPrimaryColor)); - themeRules["text-primary-color"] = - rgbContrast(rgbPrimaryColor, [33, 33, 33]) < 6 ? "#fff" : "#212121"; - themeRules["text-light-primary-color"] = - rgbContrast(rgbLigthPrimaryColor, [33, 33, 33]) < 6 - ? "#fff" - : "#212121"; - themeRules["state-icon-color"] = themeRules["dark-primary-color"]; - } - if (themeOptions.accentColor) { - cacheKey = `${cacheKey}__accent_${themeOptions.accentColor}`; - themeRules["accent-color"] = themeOptions.accentColor; - const rgbAccentColor = hex2rgb(themeOptions.accentColor); - themeRules["text-accent-color"] = - rgbContrast(rgbAccentColor, [33, 33, 33]) < 6 ? "#fff" : "#212121"; - } - // Nothing was changed - if (element._themes?.cacheKey === cacheKey) { - return; + if (primaryColor) { + cacheKey = `${cacheKey}__primary_${primaryColor}`; + const rgbPrimaryColor = hex2rgb(primaryColor); + const labPrimaryColor = rgb2lab(rgbPrimaryColor); + themeRules["primary-color"] = primaryColor; + const rgbLightPrimaryColor = lab2rgb(labBrighten(labPrimaryColor)); + themeRules["light-primary-color"] = rgb2hex(rgbLightPrimaryColor); + themeRules["dark-primary-color"] = lab2hex(labDarken(labPrimaryColor)); + themeRules["text-primary-color"] = + rgbContrast(rgbPrimaryColor, [33, 33, 33]) < 6 ? "#fff" : "#212121"; + themeRules["text-light-primary-color"] = + rgbContrast(rgbLightPrimaryColor, [33, 33, 33]) < 6 + ? "#fff" + : "#212121"; + themeRules["state-icon-color"] = themeRules["dark-primary-color"]; + } + if (accentColor) { + cacheKey = `${cacheKey}__accent_${accentColor}`; + themeRules["accent-color"] = accentColor; + const rgbAccentColor = hex2rgb(accentColor); + themeRules["text-accent-color"] = + rgbContrast(rgbAccentColor, [33, 33, 33]) < 6 ? "#fff" : "#212121"; + } + + // Nothing was changed + if (element._themes?.cacheKey === cacheKey) { + return; + } } } - if (selectedTheme && themes.themes[selectedTheme]) { - themeRules = themes.themes[selectedTheme]; + // Custom theme logic (not relevant for default theme, since it would override + // the derived calculations from above) + if ( + selectedTheme && + selectedTheme !== "default" && + themes.themes[selectedTheme] + ) { + // Apply theme vars that are relevant for all modes (but extract the "modes" section first) + const { modes, ...baseThemeRules } = themes.themes[selectedTheme]; + themeRules = { ...themeRules, ...baseThemeRules }; + + // Apply theme vars for the specific mode if available + if (modes) { + if (themeSettings?.dark) { + themeRules = { ...themeRules, ...modes.dark }; + } else { + themeRules = { ...themeRules, ...modes.light }; + } + } } if (!element._themes?.keys && !Object.keys(themeRules).length) { @@ -106,12 +134,12 @@ export const applyThemesOnElement = ( const processTheme = ( cacheKey: string, - theme: Partial + theme: Partial ): ProcessedTheme | undefined => { if (!theme || !Object.keys(theme).length) { return undefined; } - const combinedTheme: Partial = { + const combinedTheme: Partial = { ...derivedStyles, ...theme, }; diff --git a/src/common/dom/dynamic-element-directive.ts b/src/common/dom/dynamic-element-directive.ts index e3e48e57af..a1ffb33ff3 100644 --- a/src/common/dom/dynamic-element-directive.ts +++ b/src/common/dom/dynamic-element-directive.ts @@ -1,30 +1,46 @@ -import { directive, NodePart, Part } from "lit-html"; +import { noChange } from "lit"; +import { + ChildPart, + Directive, + directive, + DirectiveParameters, + PartInfo, + PartType, +} from "lit/directive"; export const dynamicElement = directive( - (tag: string, properties?: Record) => (part: Part): void => { - if (!(part instanceof NodePart)) { - throw new Error( - "dynamicElementDirective can only be used in content bindings" - ); + class extends Directive { + private _element?: HTMLElement; + + constructor(partInfo: PartInfo) { + super(partInfo); + if (partInfo.type !== PartType.CHILD) { + throw new Error( + "dynamicElementDirective can only be used in content bindings" + ); + } } - let element = part.value as HTMLElement | undefined; + update(_part: ChildPart, [tag, properties]: DirectiveParameters) { + if (this._element && this._element.localName === tag) { + if (properties) { + Object.entries(properties).forEach(([key, value]) => { + this._element![key] = value; + }); + } + return noChange; + } + return this.render(tag, properties); + } - if (tag === element?.localName) { + render(tag: string, properties?: Record): HTMLElement { + this._element = document.createElement(tag); if (properties) { Object.entries(properties).forEach(([key, value]) => { - element![key] = value; + this._element![key] = value; }); } - return; + return this._element; } - - element = document.createElement(tag); - if (properties) { - Object.entries(properties).forEach(([key, value]) => { - element![key] = value; - }); - } - part.setValue(element); } ); diff --git a/src/common/dom/get_main_window.ts b/src/common/dom/get_main_window.ts new file mode 100644 index 0000000000..5bf9e2687b --- /dev/null +++ b/src/common/dom/get_main_window.ts @@ -0,0 +1,8 @@ +import { MAIN_WINDOW_NAME } from "../../data/main_window"; + +export const mainWindow = + window.name === MAIN_WINDOW_NAME + ? window + : parent.name === MAIN_WINDOW_NAME + ? parent + : top; diff --git a/src/common/dom/speech-recognition.ts b/src/common/dom/speech-recognition.ts index a3003974fb..6efec5b8a2 100644 --- a/src/common/dom/speech-recognition.ts +++ b/src/common/dom/speech-recognition.ts @@ -1,14 +1,7 @@ -/* eslint-disable */ -// @ts-ignore export const SpeechRecognition = - // @ts-ignore window.SpeechRecognition || window.webkitSpeechRecognition; -// @ts-ignore export const SpeechGrammarList = - // @ts-ignore window.SpeechGrammarList || window.webkitSpeechGrammarList; -// @ts-ignore export const SpeechRecognitionEvent = - // @ts-ignore + // @ts-expect-error window.SpeechRecognitionEvent || window.webkitSpeechRecognitionEvent; -/* eslint-enable */ diff --git a/src/common/entity/compute_state_display.ts b/src/common/entity/compute_state_display.ts index d4e77ce4e9..8165f6daf7 100644 --- a/src/common/entity/compute_state_display.ts +++ b/src/common/entity/compute_state_display.ts @@ -1,6 +1,6 @@ import { HassEntity } from "home-assistant-js-websocket"; import { UNAVAILABLE, UNKNOWN } from "../../data/entity"; -import { FrontendTranslationData } from "../../data/translation"; +import { FrontendLocaleData } from "../../data/translation"; import { formatDate } from "../datetime/format_date"; import { formatDateTime } from "../datetime/format_date_time"; import { formatTime } from "../datetime/format_time"; @@ -11,7 +11,7 @@ import { computeStateDomain } from "./compute_state_domain"; export const computeStateDisplay = ( localize: LocalizeFunc, stateObj: HassEntity, - locale: FrontendTranslationData, + locale: FrontendLocaleData, state?: string ): string => { const compareState = state !== undefined ? state : stateObj.state; diff --git a/src/common/entity/timer_time_remaining.ts b/src/common/entity/timer_time_remaining.ts deleted file mode 100644 index 5b2f54654d..0000000000 --- a/src/common/entity/timer_time_remaining.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { HassEntity } from "home-assistant-js-websocket"; -import durationToSeconds from "../datetime/duration_to_seconds"; - -export const timerTimeRemaining = ( - stateObj: HassEntity -): undefined | number => { - if (!stateObj.attributes.remaining) { - return undefined; - } - let timeRemaining = durationToSeconds(stateObj.attributes.remaining); - - if (stateObj.state === "active") { - const now = new Date().getTime(); - const madeActive = new Date(stateObj.last_changed).getTime(); - timeRemaining = Math.max(timeRemaining - (now - madeActive) / 1000, 0); - } - - return timeRemaining; -}; diff --git a/src/common/image/extract_color.ts b/src/common/image/extract_color.ts index d63ed963d8..f37652ce7b 100644 --- a/src/common/image/extract_color.ts +++ b/src/common/image/extract_color.ts @@ -1,7 +1,7 @@ // We import the minified bundle because the unminified bundle // has some quirks that break wds. See #7784 for unminified version. -import Vibrant from "node-vibrant/dist/vibrant"; import type { Swatch, Vec3 } from "@vibrant/color"; +import Vibrant from "node-vibrant/dist/vibrant"; import { getRGBContrastRatio } from "../color/rgb"; const CONTRAST_RATIO = 4.5; diff --git a/src/common/navigate.ts b/src/common/navigate.ts index 7bbc589f29..e2e0f26dd0 100644 --- a/src/common/navigate.ts +++ b/src/common/navigate.ts @@ -1,35 +1,40 @@ import { fireEvent } from "./dom/fire_event"; +import { mainWindow } from "./dom/get_main_window"; declare global { // for fire event interface HASSDomEvents { - "location-changed": { - replace: boolean; - }; + "location-changed": NavigateOptions; } } -export const navigate = (_node: any, path: string, replace = false) => { +export interface NavigateOptions { + replace?: boolean; +} + +export const navigate = (path: string, options?: NavigateOptions) => { + const replace = options?.replace || false; + if (__DEMO__) { if (replace) { - top.history.replaceState( - top.history.state?.root ? { root: true } : null, + mainWindow.history.replaceState( + mainWindow.history.state?.root ? { root: true } : null, "", - `${top.location.pathname}#${path}` + `${mainWindow.location.pathname}#${path}` ); } else { - top.location.hash = path; + mainWindow.location.hash = path; } } else if (replace) { - top.history.replaceState( - top.history.state?.root ? { root: true } : null, + mainWindow.history.replaceState( + mainWindow.history.state?.root ? { root: true } : null, "", path ); } else { - top.history.pushState(null, "", path); + mainWindow.history.pushState(null, "", path); } - fireEvent(top, "location-changed", { + fireEvent(mainWindow, "location-changed", { replace, }); }; diff --git a/src/common/search/search-input.ts b/src/common/search/search-input.ts index aff3a1a2a7..bde0c9ab5c 100644 --- a/src/common/search/search-input.ts +++ b/src/common/search/search-input.ts @@ -1,15 +1,9 @@ import "@material/mwc-icon-button/mwc-icon-button"; import { mdiClose, mdiMagnify } from "@mdi/js"; import "@polymer/paper-input/paper-input"; -import { - css, - CSSResult, - customElement, - LitElement, - property, -} from "lit-element"; -import { html, TemplateResult } from "lit-html"; -import { classMap } from "lit-html/directives/class-map"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import "../../components/ha-svg-icon"; import { fireEvent } from "../dom/fire_event"; @@ -80,7 +74,7 @@ class SearchInput extends LitElement { this._filterChanged(""); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` ha-svg-icon, mwc-icon-button { diff --git a/src/common/string/filter/filter.ts b/src/common/string/filter/filter.ts index ff42c20393..fc99bc10b8 100644 --- a/src/common/string/filter/filter.ts +++ b/src/common/string/filter/filter.ts @@ -92,7 +92,7 @@ function isUpperCaseAtPos(pos: number, word: string, wordLow: string): boolean { return word[pos] !== wordLow[pos]; } -function isPatternInWord( +export function isPatternInWord( patternLow: string, patternPos: number, patternLen: number, @@ -121,7 +121,7 @@ enum Arrow { } /** - * An array representating a fuzzy match. + * An array representing a fuzzy match. * * 0. the score * 1. the offset at which matching started diff --git a/src/common/string/filter/sequence-matching.ts b/src/common/string/filter/sequence-matching.ts index 77edc39805..d502cec350 100644 --- a/src/common/string/filter/sequence-matching.ts +++ b/src/common/string/filter/sequence-matching.ts @@ -5,7 +5,7 @@ import { fuzzyScore } from "./filter"; * in that order, allowing for skipping. Ex: "chdr" exists in "chandelier") * * @param {string} filter - Sequence of letters to check for - * @param {string} word - Word to check for sequence + * @param {ScorableTextItem} item - Item against whose strings will be checked * * @return {number} Score representing how well the word matches the filter. Return of 0 means no match. */ diff --git a/src/common/string/format_number.ts b/src/common/string/format_number.ts index da8af2798a..2cfa22458b 100644 --- a/src/common/string/format_number.ts +++ b/src/common/string/format_number.ts @@ -1,4 +1,4 @@ -import { FrontendTranslationData, NumberFormat } from "../../data/translation"; +import { FrontendLocaleData, NumberFormat } from "../../data/translation"; /** * Formats a number based on the user's preference with thousands separator(s) and decimal character for better legibility. @@ -9,7 +9,7 @@ import { FrontendTranslationData, NumberFormat } from "../../data/translation"; */ export const formatNumber = ( num: string | number, - locale?: FrontendTranslationData, + locale?: FrontendLocaleData, options?: Intl.NumberFormatOptions ): string => { let format: string | string[] | undefined; diff --git a/src/common/string/is_date.ts b/src/common/string/is_date.ts new file mode 100644 index 0000000000..b075efc1e4 --- /dev/null +++ b/src/common/string/is_date.ts @@ -0,0 +1,11 @@ +// https://regex101.com/r/kc5C14/2 +const regExpString = "^\\d{4}-(0[1-9]|1[0-2])-([12]\\d|0[1-9]|3[01])"; + +const regExp = new RegExp(regExpString + "$"); +// 2nd expression without the "end of string" enforced, so it can be used +// to just verify the start of a string and then based on that result e.g. +// check for a full timestamp string efficiently. +const regExpNoStringEnd = new RegExp(regExpString); + +export const isDate = (input: string, allowCharsAfterDate = false): boolean => + allowCharsAfterDate ? regExpNoStringEnd.test(input) : regExp.test(input); diff --git a/src/common/string/is_timestamp.ts b/src/common/string/is_timestamp.ts new file mode 100644 index 0000000000..e4b7649529 --- /dev/null +++ b/src/common/string/is_timestamp.ts @@ -0,0 +1,11 @@ +// https://stackoverflow.com/a/14322189/1947205 +// Changes: +// 1. Do not allow a plus or minus at the start. +// 2. Enforce that we have a "T" or a blank after the date portion +// to ensure we have a timestamp and not only a date. +// 3. Disallow dates based on week number. +// 4. Disallow dates only consisting of a year. +// https://regex101.com/r/kc5C14/3 +const regexp = /^\d{4}-(0[1-9]|1[0-2])-([12]\d|0[1-9]|3[01])[T| ](((([01]\d|2[0-3])((:?)[0-5]\d)?|24:?00)([.,]\d+(?!:))?)(\8[0-5]\d([.,]\d+)?)?([zZ]|([+-])([01]\d|2[0-3]):?([0-5]\d)?)?)$/; + +export const isTimestamp = (input: string): boolean => regexp.test(input); diff --git a/src/common/structs/handle-errors.ts b/src/common/structs/handle-errors.ts index 7aa8889045..96c82081c5 100644 --- a/src/common/structs/handle-errors.ts +++ b/src/common/structs/handle-errors.ts @@ -27,6 +27,20 @@ export const handleStructError = ( failure.path.join(".") ) ); + } else if (failure.type === "union") { + continue; + } else if (failure.type === "enums") { + warnings.push( + hass.localize( + "ui.errors.config.key_wrong_type", + "key", + failure.path.join("."), + "type_correct", + failure.message.replace("Expected ", "").split(", ")[0], + "type_wrong", + JSON.stringify(failure.value) + ) + ); } else { warnings.push( hass.localize( @@ -34,7 +48,7 @@ export const handleStructError = ( "key", failure.path.join("."), "type_correct", - failure.type, + failure.refinement || failure.type, "type_wrong", JSON.stringify(failure.value) ) diff --git a/src/common/structs/is-entity-id.ts b/src/common/structs/is-entity-id.ts index c408187e84..8d71f01694 100644 --- a/src/common/structs/is-entity-id.ts +++ b/src/common/structs/is-entity-id.ts @@ -1,30 +1,22 @@ -import { struct, StructContext, StructResult } from "superstruct"; +import { refine, string } from "superstruct"; -const isEntityId = (value: unknown, context: StructContext): StructResult => { - if (typeof value !== "string") { - return [context.fail({ type: "string" })]; - } +const isEntityId = (value: string): boolean => { if (!value.includes(".")) { - return [ - context.fail({ - type: "Entity ID should be in the format 'domain.entity'", - }), - ]; + return false; } return true; }; -export const EntityId = struct("entity-id", isEntityId); +export const entityId = () => + refine(string(), "entity ID (domain.entity)", isEntityId); -const isEntityIdOrAll = ( - value: unknown, - context: StructContext -): StructResult => { - if (typeof value === "string" && value === "all") { +const isEntityIdOrAll = (value: string): boolean => { + if (value === "all") { return true; } - return isEntityId(value, context); + return isEntityId(value); }; -export const EntityIdOrAll = struct("entity-id-all", isEntityIdOrAll); +export const entityIdOrAll = () => + refine(string(), "entity ID (domain.entity or all)", isEntityIdOrAll); diff --git a/src/common/structs/is-icon.ts b/src/common/structs/is-icon.ts index 7ca4ff9ed5..db97d69ec2 100644 --- a/src/common/structs/is-icon.ts +++ b/src/common/structs/is-icon.ts @@ -1,17 +1,10 @@ -import { struct, StructContext, StructResult } from "superstruct"; +import { refine, string } from "superstruct"; -const isIcon = (value: unknown, context: StructContext): StructResult => { - if (typeof value !== "string") { - return [context.fail({ type: "string" })]; - } +const isIcon = (value: string) => { if (!value.includes(":")) { - return [ - context.fail({ - type: "icon should be in the format 'mdi:icon'", - }), - ]; + return false; } return true; }; -export const Icon = struct("icon", isIcon); +export const icon = () => refine(string(), "icon (mdi:icon-name)", isIcon); diff --git a/src/common/style/icon_color_css.ts b/src/common/style/icon_color_css.ts index 4672d0ca9c..fbc663653a 100644 --- a/src/common/style/icon_color_css.ts +++ b/src/common/style/icon_color_css.ts @@ -1,4 +1,4 @@ -import { css } from "lit-element"; +import { css } from "lit"; export const iconColorCSS = css` ha-icon[data-domain="alert"][data-state="on"], diff --git a/src/common/translations/localize.ts b/src/common/translations/localize.ts index 94edcc8a7a..ee9522e141 100644 --- a/src/common/translations/localize.ts +++ b/src/common/translations/localize.ts @@ -1,9 +1,8 @@ -import { shouldPolyfill } from "@formatjs/intl-pluralrules/should-polyfill"; +import { shouldPolyfill } from "@formatjs/intl-pluralrules/lib/should-polyfill"; import IntlMessageFormat from "intl-messageformat"; import { Resources } from "../../types"; export type LocalizeFunc = (key: string, ...args: any[]) => string; - interface FormatType { [format: string]: any; } @@ -13,12 +12,17 @@ export interface FormatsType { time: FormatType; } +let loadedPolyfillLocale: Set | undefined; + let polyfillLoaded = !shouldPolyfill(); const polyfillProm = polyfillLoaded ? undefined - : import("@formatjs/intl-pluralrules/polyfill-locales").then(() => { - polyfillLoaded = true; - }); + : import("@formatjs/intl-locale/polyfill") + .then(() => import("@formatjs/intl-pluralrules/polyfill")) + .then(() => { + loadedPolyfillLocale = new Set(); + polyfillLoaded = true; + }); /** * Adapted from Polymer app-localize-behavior. @@ -51,6 +55,15 @@ export const computeLocalize = async ( await polyfillProm; } + if (loadedPolyfillLocale && !loadedPolyfillLocale.has(language)) { + try { + loadedPolyfillLocale.add(language); + await import("@formatjs/intl-pluralrules/locale-data/en"); + } catch (_e) { + // Ignore + } + } + // Everytime any of the parameters change, invalidate the strings cache. cache._localizationCache = {}; @@ -68,7 +81,9 @@ export const computeLocalize = async ( } const messageKey = key + translatedValue; - let translatedMessage = cache._localizationCache[messageKey]; + let translatedMessage = cache._localizationCache[messageKey] as + | IntlMessageFormat + | undefined; if (!translatedMessage) { translatedMessage = new IntlMessageFormat( @@ -79,37 +94,19 @@ export const computeLocalize = async ( cache._localizationCache[messageKey] = translatedMessage; } - const argObject = {}; - for (let i = 0; i < args.length; i += 2) { - argObject[args[i]] = args[i + 1]; + let argObject = {}; + if (args.length === 1 && typeof args[0] === "object") { + argObject = args[0]; + } else { + for (let i = 0; i < args.length; i += 2) { + argObject[args[i]] = args[i + 1]; + } } try { - return translatedMessage.format(argObject); + return translatedMessage.format(argObject) as string; } catch (err) { return "Translation " + err; } }; }; - -/** - * Silly helper function that converts an object of placeholders to array so we - * can convert it back to an object again inside the localize func. - * @param localize - * @param key - * @param placeholders - */ -export const localizeKey = ( - localize: LocalizeFunc, - key: string, - placeholders?: Record -) => { - const args: [string, ...string[]] = [key]; - if (placeholders) { - Object.keys(placeholders).forEach((placeholderKey) => { - args.push(placeholderKey); - args.push(placeholders[placeholderKey]); - }); - } - return localize(...args); -}; diff --git a/src/components/buttons/ha-call-api-button.ts b/src/components/buttons/ha-call-api-button.ts index ab5d075373..6bf9e92d4d 100644 --- a/src/components/buttons/ha-call-api-button.ts +++ b/src/components/buttons/ha-call-api-button.ts @@ -1,4 +1,5 @@ -import { css, CSSResult, html, LitElement, property, query } from "lit-element"; +import { css, CSSResultGroup, html, LitElement } from "lit"; +import { property, query } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import { HomeAssistant } from "../../types"; import "./ha-progress-button"; @@ -59,7 +60,7 @@ class HaCallApiButton extends LitElement { fireEvent(this, "hass-api-called", eventData as any); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host([disabled]) { pointer-events: none; diff --git a/src/components/buttons/ha-progress-button.ts b/src/components/buttons/ha-progress-button.ts index bb431cf7cb..259ee75310 100644 --- a/src/components/buttons/ha-progress-button.ts +++ b/src/components/buttons/ha-progress-button.ts @@ -1,15 +1,7 @@ import "@material/mwc-button"; import type { Button } from "@material/mwc-button"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - query, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, query } from "lit/decorators"; import "../ha-circular-progress"; @customElement("ha-progress-button") @@ -60,7 +52,7 @@ class HaProgressButton extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { outline: none; diff --git a/src/components/data-table/ha-data-table.ts b/src/components/data-table/ha-data-table.ts index cca0ddf896..b3b8080e07 100644 --- a/src/components/data-table/ha-data-table.ts +++ b/src/components/data-table/ha-data-table.ts @@ -1,27 +1,30 @@ +import { Layout1d, scroll } from "@lit-labs/virtualizer"; import deepClone from "deep-clone-simple"; import { css, - CSSResult, - customElement, - eventOptions, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, - query, TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; -import { ifDefined } from "lit-html/directives/if-defined"; -import { styleMap } from "lit-html/directives/style-map"; -import { scroll } from "lit-virtualizer"; +} from "lit"; +import { + customElement, + property, + state, + query, + eventOptions, +} from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; +import { ifDefined } from "lit/directives/if-defined"; +import { styleMap } from "lit/directives/style-map"; import memoizeOne from "memoize-one"; import { restoreScroll } from "../../common/decorators/restore-scroll"; import { fireEvent } from "../../common/dom/fire_event"; import "../../common/search/search-input"; import { debounce } from "../../common/util/debounce"; import { nextRender } from "../../common/util/render-status"; +import { haStyleScrollbar } from "../../resources/styles"; import "../ha-checkbox"; import type { HaCheckbox } from "../ha-checkbox"; import "../ha-icon"; @@ -118,21 +121,21 @@ export class HaDataTable extends LitElement { @property({ type: String }) public filter = ""; - @internalProperty() private _filterable = false; + @state() private _filterable = false; - @internalProperty() private _filter = ""; + @state() private _filter = ""; - @internalProperty() private _sortColumn?: string; + @state() private _sortColumn?: string; - @internalProperty() private _sortDirection: SortingDirection = null; + @state() private _sortDirection: SortingDirection = null; - @internalProperty() private _filteredData: DataTableRowData[] = []; + @state() private _filteredData: DataTableRowData[] = []; - @internalProperty() private _headerHeight = 0; + @state() private _headerHeight = 0; @query("slot[name='header']") private _header!: HTMLSlotElement; - @internalProperty() private _items: DataTableRowData[] = []; + @state() private _items: DataTableRowData[] = []; private _checkableRowsCount?: number; @@ -166,8 +169,12 @@ export class HaDataTable extends LitElement { } } - protected updated(properties: PropertyValues) { - super.updated(properties); + protected firstUpdated() { + this.updateComplete.then(() => this._calcTableHeight()); + } + + public willUpdate(properties: PropertyValues) { + super.willUpdate(properties); if (properties.has("columns")) { this._filterable = Object.values(this.columns).some( @@ -327,12 +334,18 @@ export class HaDataTable extends LitElement { ` : html`
${scroll({ items: this._items, + layout: Layout1d, + // @ts-expect-error renderItem: (row: DataTableRowData, index) => { + // not sure how this happens... + if (!row) { + return ""; + } if (row.append) { return html`
${row.content}
@@ -465,15 +478,16 @@ export class HaDataTable extends LitElement { } if (this.appendRow || this.hasFab) { - this._items = [...data]; + const items = [...data]; if (this.appendRow) { - this._items.push({ append: true, content: this.appendRow }); + items.push({ append: true, content: this.appendRow }); } if (this.hasFab) { - this._items.push({ empty: true }); + items.push({ empty: true }); } + this._items = items; } else { this._items = data; } @@ -573,355 +587,359 @@ export class HaDataTable extends LitElement { this._savedScrollPos = (e.target as HTMLDivElement).scrollTop; } - static get styles(): CSSResult { - return css` - /* default mdc styles, colors changed, without checkbox styles */ - :host { - height: 100%; - } - .mdc-data-table__content { - font-family: Roboto, sans-serif; - -moz-osx-font-smoothing: grayscale; - -webkit-font-smoothing: antialiased; - font-size: 0.875rem; - line-height: 1.25rem; - font-weight: 400; - letter-spacing: 0.0178571429em; - text-decoration: inherit; - text-transform: inherit; - } + static get styles(): CSSResultGroup { + return [ + haStyleScrollbar, + css` + /* default mdc styles, colors changed, without checkbox styles */ + :host { + height: 100%; + } + .mdc-data-table__content { + font-family: Roboto, sans-serif; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + font-size: 0.875rem; + line-height: 1.25rem; + font-weight: 400; + letter-spacing: 0.0178571429em; + text-decoration: inherit; + text-transform: inherit; + } - .mdc-data-table { - background-color: var(--data-table-background-color); - border-radius: 4px; - border-width: 1px; - border-style: solid; - border-color: var(--divider-color); - display: inline-flex; - flex-direction: column; - box-sizing: border-box; - overflow: hidden; - } + .mdc-data-table { + background-color: var(--data-table-background-color); + border-radius: 4px; + border-width: 1px; + border-style: solid; + border-color: var(--divider-color); + display: inline-flex; + flex-direction: column; + box-sizing: border-box; + overflow: hidden; + } - .mdc-data-table__row--selected { - background-color: rgba(var(--rgb-primary-color), 0.04); - } + .mdc-data-table__row--selected { + background-color: rgba(var(--rgb-primary-color), 0.04); + } - .mdc-data-table__row { - display: flex; - width: 100%; - height: 52px; - } + .mdc-data-table__row { + display: flex; + width: 100%; + height: 52px; + } - .mdc-data-table__row ~ .mdc-data-table__row { - border-top: 1px solid var(--divider-color); - } + .mdc-data-table__row ~ .mdc-data-table__row { + border-top: 1px solid var(--divider-color); + } - .mdc-data-table__row:not(.mdc-data-table__row--selected):hover { - background-color: rgba(var(--rgb-primary-text-color), 0.04); - } + .mdc-data-table__row:not(.mdc-data-table__row--selected):hover { + background-color: rgba(var(--rgb-primary-text-color), 0.04); + } - .mdc-data-table__header-cell { - color: var(--primary-text-color); - } + .mdc-data-table__header-cell { + color: var(--primary-text-color); + } - .mdc-data-table__cell { - color: var(--primary-text-color); - } + .mdc-data-table__cell { + color: var(--primary-text-color); + } - .mdc-data-table__header-row { - height: 56px; - display: flex; - width: 100%; - border-bottom: 1px solid var(--divider-color); - overflow-x: auto; - } + .mdc-data-table__header-row { + height: 56px; + display: flex; + width: 100%; + border-bottom: 1px solid var(--divider-color); + overflow-x: auto; + } - .mdc-data-table__header-row::-webkit-scrollbar { - display: none; - } + .mdc-data-table__header-row::-webkit-scrollbar { + display: none; + } - .mdc-data-table__cell, - .mdc-data-table__header-cell { - padding-right: 16px; - padding-left: 16px; - align-self: center; - overflow: hidden; - text-overflow: ellipsis; - flex-shrink: 0; - box-sizing: border-box; - } + .mdc-data-table__cell, + .mdc-data-table__header-cell { + padding-right: 16px; + padding-left: 16px; + align-self: center; + overflow: hidden; + text-overflow: ellipsis; + flex-shrink: 0; + box-sizing: border-box; + } - .mdc-data-table__cell.mdc-data-table__cell--icon { - overflow: initial; - } + .mdc-data-table__cell.mdc-data-table__cell--icon { + overflow: initial; + } - .mdc-data-table__header-cell--checkbox, - .mdc-data-table__cell--checkbox { - /* @noflip */ - padding-left: 16px; - /* @noflip */ - padding-right: 0; - width: 56px; - } - :host([dir="rtl"]) .mdc-data-table__header-cell--checkbox, - :host([dir="rtl"]) .mdc-data-table__cell--checkbox { - /* @noflip */ - padding-left: 0; - /* @noflip */ - padding-right: 16px; - } + .mdc-data-table__header-cell--checkbox, + .mdc-data-table__cell--checkbox { + /* @noflip */ + padding-left: 16px; + /* @noflip */ + padding-right: 0; + width: 56px; + } + :host([dir="rtl"]) .mdc-data-table__header-cell--checkbox, + :host([dir="rtl"]) .mdc-data-table__cell--checkbox { + /* @noflip */ + padding-left: 0; + /* @noflip */ + padding-right: 16px; + } - .mdc-data-table__table { - height: 100%; - width: 100%; - border: 0; - white-space: nowrap; - } + .mdc-data-table__table { + height: 100%; + width: 100%; + border: 0; + white-space: nowrap; + } - .mdc-data-table__cell { - font-family: Roboto, sans-serif; - -moz-osx-font-smoothing: grayscale; - -webkit-font-smoothing: antialiased; - font-size: 0.875rem; - line-height: 1.25rem; - font-weight: 400; - letter-spacing: 0.0178571429em; - text-decoration: inherit; - text-transform: inherit; - } + .mdc-data-table__cell { + font-family: Roboto, sans-serif; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + font-size: 0.875rem; + line-height: 1.25rem; + font-weight: 400; + letter-spacing: 0.0178571429em; + text-decoration: inherit; + text-transform: inherit; + } - .mdc-data-table__cell a { - color: inherit; - text-decoration: none; - } + .mdc-data-table__cell a { + color: inherit; + text-decoration: none; + } - .mdc-data-table__cell--numeric { - text-align: right; - } - :host([dir="rtl"]) .mdc-data-table__cell--numeric { - /* @noflip */ - text-align: left; - } + .mdc-data-table__cell--numeric { + text-align: right; + } + :host([dir="rtl"]) .mdc-data-table__cell--numeric { + /* @noflip */ + text-align: left; + } - .mdc-data-table__cell--icon { - color: var(--secondary-text-color); - text-align: center; - } + .mdc-data-table__cell--icon { + color: var(--secondary-text-color); + text-align: center; + } - .mdc-data-table__header-cell--icon, - .mdc-data-table__cell--icon { - width: 54px; - } + .mdc-data-table__header-cell--icon, + .mdc-data-table__cell--icon { + width: 54px; + } - .mdc-data-table__header-cell.mdc-data-table__header-cell--icon { - text-align: center; - } + .mdc-data-table__header-cell.mdc-data-table__header-cell--icon { + text-align: center; + } - .mdc-data-table__header-cell.sortable.mdc-data-table__header-cell--icon:hover, - .mdc-data-table__header-cell.sortable.mdc-data-table__header-cell--icon:not(.not-sorted) { - text-align: left; - } - :host([dir="rtl"]) .mdc-data-table__header-cell.sortable.mdc-data-table__header-cell--icon:hover, - :host([dir="rtl"]) .mdc-data-table__header-cell.sortable.mdc-data-table__header-cell--icon:not(.not-sorted) { - text-align: right; - } + text-align: left; + } + :host([dir="rtl"]) + .mdc-data-table__header-cell.sortable.mdc-data-table__header-cell--icon:hover, + :host([dir="rtl"]) + .mdc-data-table__header-cell.sortable.mdc-data-table__header-cell--icon:not(.not-sorted) { + text-align: right; + } - .mdc-data-table__cell--icon:first-child ha-icon { - margin-left: 8px; - } - :host([dir="rtl"]) .mdc-data-table__cell--icon:first-child ha-icon { - margin-left: auto; - margin-right: 8px; - } + .mdc-data-table__cell--icon:first-child ha-icon { + margin-left: 8px; + } + :host([dir="rtl"]) .mdc-data-table__cell--icon:first-child ha-icon { + margin-left: auto; + margin-right: 8px; + } - .mdc-data-table__cell--icon:first-child state-badge { - margin-right: -8px; - } - :host([dir="rtl"]) .mdc-data-table__cell--icon:first-child state-badge { - margin-right: auto; - margin-left: -8px; - } + .mdc-data-table__cell--icon:first-child state-badge { + margin-right: -8px; + } + :host([dir="rtl"]) .mdc-data-table__cell--icon:first-child state-badge { + margin-right: auto; + margin-left: -8px; + } - .mdc-data-table__header-cell--icon-button, - .mdc-data-table__cell--icon-button { - width: 56px; - padding: 8px; - } + .mdc-data-table__header-cell--icon-button, + .mdc-data-table__cell--icon-button { + width: 56px; + padding: 8px; + } - .mdc-data-table__cell--icon-button { - color: var(--secondary-text-color); - text-overflow: clip; - } + .mdc-data-table__cell--icon-button { + color: var(--secondary-text-color); + text-overflow: clip; + } - .mdc-data-table__header-cell--icon-button:first-child, - .mdc-data-table__cell--icon-button:first-child { - width: 64px; - padding-left: 16px; - } - :host([dir="rtl"]) .mdc-data-table__header-cell--icon-button:first-child, - :host([dir="rtl"]) .mdc-data-table__cell--icon-button:first-child { - padding-left: auto; - padding-right: 16px; - } + .mdc-data-table__header-cell--icon-button:first-child, + .mdc-data-table__cell--icon-button:first-child { + width: 64px; + padding-left: 16px; + } + :host([dir="rtl"]) + .mdc-data-table__header-cell--icon-button:first-child, + :host([dir="rtl"]) .mdc-data-table__cell--icon-button:first-child { + padding-left: auto; + padding-right: 16px; + } - .mdc-data-table__header-cell--icon-button:last-child, - .mdc-data-table__cell--icon-button:last-child { - width: 64px; - padding-right: 16px; - } - :host([dir="rtl"]) .mdc-data-table__header-cell--icon-button:last-child, - :host([dir="rtl"]) .mdc-data-table__cell--icon-button:last-child { - padding-right: auto; - padding-left: 16px; - } + .mdc-data-table__header-cell--icon-button:last-child, + .mdc-data-table__cell--icon-button:last-child { + width: 64px; + padding-right: 16px; + } + :host([dir="rtl"]) .mdc-data-table__header-cell--icon-button:last-child, + :host([dir="rtl"]) .mdc-data-table__cell--icon-button:last-child { + padding-right: auto; + padding-left: 16px; + } - .mdc-data-table__cell--icon-button a { - color: var(--secondary-text-color); - } + .mdc-data-table__cell--icon-button a { + color: var(--secondary-text-color); + } - .mdc-data-table__header-cell { - font-family: Roboto, sans-serif; - -moz-osx-font-smoothing: grayscale; - -webkit-font-smoothing: antialiased; - font-size: 0.875rem; - line-height: 1.375rem; - font-weight: 500; - letter-spacing: 0.0071428571em; - text-decoration: inherit; - text-transform: inherit; - text-align: left; - } - :host([dir="rtl"]) .mdc-data-table__header-cell { - /* @noflip */ - text-align: right; - } + .mdc-data-table__header-cell { + font-family: Roboto, sans-serif; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + font-size: 0.875rem; + line-height: 1.375rem; + font-weight: 500; + letter-spacing: 0.0071428571em; + text-decoration: inherit; + text-transform: inherit; + text-align: left; + } + :host([dir="rtl"]) .mdc-data-table__header-cell { + /* @noflip */ + text-align: right; + } - .mdc-data-table__header-cell--numeric { - text-align: right; - } - .mdc-data-table__header-cell--numeric.sortable:hover, - .mdc-data-table__header-cell--numeric.sortable:not(.not-sorted) { - text-align: left; - } - :host([dir="rtl"]) .mdc-data-table__header-cell--numeric { - /* @noflip */ - text-align: left; - } - :host([dir="rtl"]) .mdc-data-table__header-cell--numeric.sortable:hover, - :host([dir="rtl"]) + .mdc-data-table__header-cell--numeric { + text-align: right; + } + .mdc-data-table__header-cell--numeric.sortable:hover, .mdc-data-table__header-cell--numeric.sortable:not(.not-sorted) { - text-align: right; - } + text-align: left; + } + :host([dir="rtl"]) .mdc-data-table__header-cell--numeric { + /* @noflip */ + text-align: left; + } + :host([dir="rtl"]) .mdc-data-table__header-cell--numeric.sortable:hover, + :host([dir="rtl"]) + .mdc-data-table__header-cell--numeric.sortable:not(.not-sorted) { + text-align: right; + } - /* custom from here */ + /* custom from here */ - :host { - display: block; - } + :host { + display: block; + } - .mdc-data-table { - display: block; - border-width: var(--data-table-border-width, 1px); - height: 100%; - } - .mdc-data-table__header-cell { - overflow: hidden; - position: relative; - } - .mdc-data-table__header-cell span { - position: relative; - left: 0px; - } - :host([dir="rtl"]) .mdc-data-table__header-cell span { - left: auto; - right: 0px; - } + .mdc-data-table { + display: block; + border-width: var(--data-table-border-width, 1px); + height: 100%; + } + .mdc-data-table__header-cell { + overflow: hidden; + position: relative; + } + .mdc-data-table__header-cell span { + position: relative; + left: 0px; + } + :host([dir="rtl"]) .mdc-data-table__header-cell span { + left: auto; + right: 0px; + } - .mdc-data-table__header-cell.sortable { - cursor: pointer; - } - .mdc-data-table__header-cell > * { - transition: left 0.2s ease; - } - :host([dir="rtl"]) .mdc-data-table__header-cell > * { - transition: right 0.2s ease; - } - .mdc-data-table__header-cell ha-icon { - top: -3px; - position: absolute; - } - .mdc-data-table__header-cell.not-sorted ha-icon { - left: -20px; - } - :host([dir="rtl"]) .mdc-data-table__header-cell.not-sorted ha-icon { - right: -20px; - } - .mdc-data-table__header-cell.sortable:not(.not-sorted) span, - .mdc-data-table__header-cell.sortable.not-sorted:hover span { - left: 24px; - } - :host([dir="rtl"]) - .mdc-data-table__header-cell.sortable:not(.not-sorted) - span, - :host([dir="rtl"]) - .mdc-data-table__header-cell.sortable.not-sorted:hover - span { - left: auto; - right: 24px; - } - .mdc-data-table__header-cell.sortable:not(.not-sorted) ha-icon, - .mdc-data-table__header-cell.sortable:hover.not-sorted ha-icon { - left: 12px; - } - :host([dir="rtl"]) - .mdc-data-table__header-cell.sortable:not(.not-sorted) - ha-icon, - :host([dir="rtl"]) - .mdc-data-table__header-cell.sortable:hover.not-sorted - ha-icon { - left: auto; - right: 12px; - } - .table-header { - border-bottom: 1px solid var(--divider-color); - padding: 0 16px; - } - search-input { - position: relative; - top: 2px; - } - slot[name="header"] { - display: block; - } - .center { - text-align: center; - } - .secondary { - color: var(--secondary-text-color); - } - .scroller { - display: flex; - position: relative; - contain: strict; - height: calc(100% - 57px); - } - .mdc-data-table__table:not(.auto-height) .scroller { - overflow: auto; - } - .grows { - flex-grow: 1; - flex-shrink: 1; - } - .forceLTR { - direction: ltr; - } - .clickable { - cursor: pointer; - } - `; + .mdc-data-table__header-cell.sortable { + cursor: pointer; + } + .mdc-data-table__header-cell > * { + transition: left 0.2s ease; + } + :host([dir="rtl"]) .mdc-data-table__header-cell > * { + transition: right 0.2s ease; + } + .mdc-data-table__header-cell ha-icon { + top: -3px; + position: absolute; + } + .mdc-data-table__header-cell.not-sorted ha-icon { + left: -20px; + } + :host([dir="rtl"]) .mdc-data-table__header-cell.not-sorted ha-icon { + right: -20px; + } + .mdc-data-table__header-cell.sortable:not(.not-sorted) span, + .mdc-data-table__header-cell.sortable.not-sorted:hover span { + left: 24px; + } + :host([dir="rtl"]) + .mdc-data-table__header-cell.sortable:not(.not-sorted) + span, + :host([dir="rtl"]) + .mdc-data-table__header-cell.sortable.not-sorted:hover + span { + left: auto; + right: 24px; + } + .mdc-data-table__header-cell.sortable:not(.not-sorted) ha-icon, + .mdc-data-table__header-cell.sortable:hover.not-sorted ha-icon { + left: 12px; + } + :host([dir="rtl"]) + .mdc-data-table__header-cell.sortable:not(.not-sorted) + ha-icon, + :host([dir="rtl"]) + .mdc-data-table__header-cell.sortable:hover.not-sorted + ha-icon { + left: auto; + right: 12px; + } + .table-header { + border-bottom: 1px solid var(--divider-color); + padding: 0 16px; + } + search-input { + position: relative; + top: 2px; + } + slot[name="header"] { + display: block; + } + .center { + text-align: center; + } + .secondary { + color: var(--secondary-text-color); + } + .scroller { + display: flex; + position: relative; + contain: strict; + height: calc(100% - 57px); + } + .mdc-data-table__table:not(.auto-height) .scroller { + overflow: auto; + } + .grows { + flex-grow: 1; + flex-shrink: 1; + } + .forceLTR { + direction: ltr; + } + .clickable { + cursor: pointer; + } + `, + ]; } } diff --git a/src/components/date-range-picker.ts b/src/components/date-range-picker.ts index f7ec87169e..6ad2905564 100644 --- a/src/components/date-range-picker.ts +++ b/src/components/date-range-picker.ts @@ -1,8 +1,8 @@ -// @ts-nocheck import wrap from "@vue/web-component-wrapper"; -import { customElement } from "lit-element/lib/decorators"; +import { customElement } from "lit/decorators"; import Vue from "vue"; import DateRangePicker from "vue2-daterange-picker"; +// @ts-ignore import dateRangePickerStyles from "vue2-daterange-picker/dist/vue2-daterange-picker.css"; import { fireEvent } from "../common/dom/fire_event"; import { Constructor } from "../types"; @@ -35,22 +35,29 @@ const Component = Vue.extend({ }, }, render(createElement) { + // @ts-ignore return createElement(DateRangePicker, { props: { "time-picker": true, "auto-apply": false, opens: "right", "show-dropdowns": false, + // @ts-ignore "time-picker24-hour": this.twentyfourHours, + // @ts-ignore disabled: this.disabled, + // @ts-ignore ranges: this.ranges ? {} : false, }, model: { value: { + // @ts-ignore startDate: this.startDate, + // @ts-ignore endDate: this.endDate, }, callback: (value) => { + // @ts-ignore fireEvent(this.$el as HTMLElement, "change", value); }, expression: "dateRange", diff --git a/src/components/device/ha-area-devices-picker.ts b/src/components/device/ha-area-devices-picker.ts index 6e635d0720..712e1b1bb3 100644 --- a/src/components/device/ha-area-devices-picker.ts +++ b/src/components/device/ha-area-devices-picker.ts @@ -9,15 +9,13 @@ import "@vaadin/vaadin-combo-box/theme/material/vaadin-combo-box-light"; import { UnsubscribeFunc } from "home-assistant-js-websocket"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import { fireEvent } from "../../common/dom/fire_event"; import { computeDomain } from "../../common/entity/compute_domain"; @@ -40,6 +38,7 @@ import { PolymerChangedEvent } from "../../polymer-types"; import { HomeAssistant } from "../../types"; import "../ha-svg-icon"; import "./ha-devices-picker"; +import { ComboBoxLitRenderer, comboBoxRenderer } from "lit-vaadin-helpers"; interface DevicesByArea { [areaId: string]: AreaDevices; @@ -51,42 +50,28 @@ interface AreaDevices { devices: string[]; } -const rowRenderer = ( - root: HTMLElement, - _owner, - model: { item: AreaDevices } -) => { - if (!root.firstElementChild) { - root.innerHTML = ` - - - -
[[item.name]]
-
[[item.devices.length]] devices
-
-
- `; - } - root.querySelector(".name")!.textContent = model.item.name!; - root.querySelector( - "[secondary]" - )!.textContent = `${model.item.devices.length.toString()} devices`; -}; +const rowRenderer: ComboBoxLitRenderer = (item) => html` + + +
${item.name}
+
${item.devices.length} devices
+
+
`; @customElement("ha-area-devices-picker") export class HaAreaDevicesPicker extends SubscribeMixin(LitElement) { @@ -127,13 +112,13 @@ export class HaAreaDevicesPicker extends SubscribeMixin(LitElement) { @property({ type: Boolean }) private _opened?: boolean; - @internalProperty() private _areaPicker = true; + @state() private _areaPicker = true; - @internalProperty() private _devices?: DeviceRegistryEntry[]; + @state() private _devices?: DeviceRegistryEntry[]; - @internalProperty() private _areas?: AreaRegistryEntry[]; + @state() private _areas?: AreaRegistryEntry[]; - @internalProperty() private _entities?: EntityRegistryEntry[]; + @state() private _entities?: EntityRegistryEntry[]; private _selectedDevices: string[] = []; @@ -312,7 +297,7 @@ export class HaAreaDevicesPicker extends SubscribeMixin(LitElement) { item-label-path="name" .items=${areas} .value=${this._value} - .renderer=${rowRenderer} + ${comboBoxRenderer(rowRenderer)} @opened-changed=${this._openedChanged} @value-changed=${this._areaPicked} > @@ -407,7 +392,7 @@ export class HaAreaDevicesPicker extends SubscribeMixin(LitElement) { }, 0); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` .suffix { display: flex; diff --git a/src/components/device/ha-device-action-picker.ts b/src/components/device/ha-device-action-picker.ts index e8e50f5b47..ce053d45cf 100644 --- a/src/components/device/ha-device-action-picker.ts +++ b/src/components/device/ha-device-action-picker.ts @@ -1,4 +1,4 @@ -import { customElement } from "lit-element"; +import { customElement } from "lit/decorators"; import { DeviceAction, fetchDeviceActions, diff --git a/src/components/device/ha-device-automation-picker.ts b/src/components/device/ha-device-automation-picker.ts index 98e79035b6..e4cc705dce 100644 --- a/src/components/device/ha-device-automation-picker.ts +++ b/src/components/device/ha-device-automation-picker.ts @@ -2,15 +2,8 @@ import "@polymer/paper-input/paper-input"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-item/paper-item-body"; import "@polymer/paper-listbox/paper-listbox"; -import { - css, - CSSResult, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { property, state } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import { DeviceAutomation, @@ -33,11 +26,11 @@ export abstract class HaDeviceAutomationPicker< @property() public value?: T; - @internalProperty() private _automations: T[] = []; + @state() private _automations: T[] = []; // Trigger an empty render so we start with a clean DOM. // paper-listbox does not like changing things around. - @internalProperty() private _renderEmpty = false; + @state() private _renderEmpty = false; protected get NO_AUTOMATION_TEXT() { return this.hass.localize( @@ -188,7 +181,7 @@ export abstract class HaDeviceAutomationPicker< fireEvent(this, "value-changed", { value: automation }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` ha-paper-dropdown-menu { width: 100%; diff --git a/src/components/device/ha-device-condition-picker.ts b/src/components/device/ha-device-condition-picker.ts index 3ab706e73d..977a4ee05f 100644 --- a/src/components/device/ha-device-condition-picker.ts +++ b/src/components/device/ha-device-condition-picker.ts @@ -1,4 +1,4 @@ -import { customElement } from "lit-element"; +import { customElement } from "lit/decorators"; import { DeviceCondition, fetchDeviceConditions, diff --git a/src/components/device/ha-device-picker.ts b/src/components/device/ha-device-picker.ts index 3644ad9405..1333f9fb82 100644 --- a/src/components/device/ha-device-picker.ts +++ b/src/components/device/ha-device-picker.ts @@ -3,16 +3,13 @@ import "@polymer/paper-item/paper-item-body"; import { UnsubscribeFunc } from "home-assistant-js-websocket"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, - query, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state, query } from "lit/decorators"; import memoizeOne from "memoize-one"; import { fireEvent } from "../../common/dom/fire_event"; import { computeDomain } from "../../common/entity/compute_domain"; @@ -34,8 +31,9 @@ import { import { SubscribeMixin } from "../../mixins/subscribe-mixin"; import { PolymerChangedEvent } from "../../polymer-types"; import { HomeAssistant } from "../../types"; -import type { HaComboBox } from "../ha-combo-box"; import "../ha-combo-box"; +import type { HaComboBox } from "../ha-combo-box"; +import { ComboBoxLitRenderer } from "lit-vaadin-helpers"; interface Device { name: string; @@ -47,27 +45,18 @@ export type HaDevicePickerDeviceFilterFunc = ( device: DeviceRegistryEntry ) => boolean; -const rowRenderer = (root: HTMLElement, _owner, model: { item: Device }) => { - if (!root.firstElementChild) { - root.innerHTML = ` - - - -
[[item.name]]
-
[[item.area]]
-
-
- `; - } - - root.querySelector(".name")!.textContent = model.item.name!; - root.querySelector("[secondary]")!.textContent = model.item.area!; -}; +const rowRenderer: ComboBoxLitRenderer = (item) => html` + + + ${item.name} + ${item.area} + + `; @customElement("ha-device-picker") export class HaDevicePicker extends SubscribeMixin(LitElement) { @@ -111,7 +100,7 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) { @property({ type: Boolean }) public disabled?: boolean; - @internalProperty() private _opened?: boolean; + @state() private _opened?: boolean; @query("ha-combo-box", true) public comboBox!: HaComboBox; @@ -326,7 +315,7 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) { }, 0); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` paper-input > mwc-icon-button { --mdc-icon-button-size: 24px; diff --git a/src/components/device/ha-device-trigger-picker.ts b/src/components/device/ha-device-trigger-picker.ts index d1ff66d37e..142955b24a 100644 --- a/src/components/device/ha-device-trigger-picker.ts +++ b/src/components/device/ha-device-trigger-picker.ts @@ -1,4 +1,4 @@ -import { customElement } from "lit-element"; +import { customElement } from "lit/decorators"; import { DeviceTrigger, fetchDeviceTriggers, diff --git a/src/components/device/ha-devices-picker.ts b/src/components/device/ha-devices-picker.ts index 9106521d1d..1b437da780 100644 --- a/src/components/device/ha-devices-picker.ts +++ b/src/components/device/ha-devices-picker.ts @@ -1,10 +1,5 @@ -import { - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import { PolymerChangedEvent } from "../../polymer-types"; import { HomeAssistant } from "../../types"; diff --git a/src/components/entity/ha-battery-icon.ts b/src/components/entity/ha-battery-icon.ts index 45f4f7d553..40233ec4a3 100644 --- a/src/components/entity/ha-battery-icon.ts +++ b/src/components/entity/ha-battery-icon.ts @@ -1,4 +1,5 @@ -import { customElement, html, LitElement, property } from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { batteryIcon } from "../../common/entity/battery_icon"; import "../ha-icon"; diff --git a/src/components/entity/ha-entities-picker.ts b/src/components/entity/ha-entities-picker.ts index 0ac66ed8fa..3f754e464c 100644 --- a/src/components/entity/ha-entities-picker.ts +++ b/src/components/entity/ha-entities-picker.ts @@ -1,11 +1,6 @@ import type { HassEntity } from "home-assistant-js-websocket"; -import { - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import { isValidEntityId } from "../../common/entity/valid_entity_id"; import type { PolymerChangedEvent } from "../../polymer-types"; diff --git a/src/components/entity/ha-entity-attribute-picker.ts b/src/components/entity/ha-entity-attribute-picker.ts index 784ea421f8..b0b07b40ea 100644 --- a/src/components/entity/ha-entity-attribute-picker.ts +++ b/src/components/entity/ha-entity-attribute-picker.ts @@ -6,15 +6,14 @@ import "@vaadin/vaadin-combo-box/theme/material/vaadin-combo-box-light"; import { HassEntity } from "home-assistant-js-websocket"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, LitElement, - property, PropertyValues, - query, TemplateResult, -} from "lit-element"; +} from "lit"; +import { ComboBoxLitRenderer, comboBoxRenderer } from "lit-vaadin-helpers"; +import { customElement, property, query } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import { PolymerChangedEvent } from "../../polymer-types"; import { HomeAssistant } from "../../types"; @@ -24,22 +23,13 @@ import "./state-badge"; export type HaEntityPickerEntityFilterFunc = (entityId: HassEntity) => boolean; -const rowRenderer = (root: HTMLElement, _owner, model: { item: string }) => { - if (!root.firstElementChild) { - root.innerHTML = ` - - - `; - } - root.querySelector("paper-item")!.textContent = formatAttributeName( - model.item - ); -}; +const rowRenderer: ComboBoxLitRenderer = (item) => html` + ${formatAttributeName(item)}`; @customElement("ha-entity-attribute-picker") class HaEntityAttributePicker extends LitElement { @@ -84,8 +74,8 @@ class HaEntityAttributePicker extends LitElement { @@ -165,7 +155,7 @@ class HaEntityAttributePicker extends LitElement { }, 0); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` .suffix { display: flex; diff --git a/src/components/entity/ha-entity-picker.ts b/src/components/entity/ha-entity-picker.ts index dfaeecd570..e17393a775 100644 --- a/src/components/entity/ha-entity-picker.ts +++ b/src/components/entity/ha-entity-picker.ts @@ -7,15 +7,14 @@ import "@vaadin/vaadin-combo-box/theme/material/vaadin-combo-box-light"; import { HassEntity } from "home-assistant-js-websocket"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, LitElement, - property, PropertyValues, - query, TemplateResult, -} from "lit-element"; +} from "lit"; +import { ComboBoxLitRenderer, comboBoxRenderer } from "lit-vaadin-helpers"; +import { customElement, property, query } from "lit/decorators"; import memoizeOne from "memoize-one"; import { fireEvent } from "../../common/dom/fire_event"; import { computeDomain } from "../../common/entity/compute_domain"; @@ -27,32 +26,19 @@ import "./state-badge"; export type HaEntityPickerEntityFilterFunc = (entityId: HassEntity) => boolean; -const rowRenderer = ( - root: HTMLElement, - _owner, - model: { item: HassEntity } -) => { - if (!root.firstElementChild) { - root.innerHTML = ` - - - - -
-
-
-
- `; - } - root.querySelector("state-badge")!.stateObj = model.item; - root.querySelector(".name")!.textContent = computeStateName(model.item); - root.querySelector("[secondary]")!.textContent = model.item.entity_id; -}; +const rowRenderer: ComboBoxLitRenderer = (item) => html` + + + + ${computeStateName(item)} + ${item.entity_id} + + `; @customElement("ha-entity-picker") export class HaEntityPicker extends LitElement { @@ -223,7 +209,7 @@ export class HaEntityPicker extends LitElement { item-label-path="entity_id" .value=${this._value} .allowCustomValue=${this.allowCustomEntity} - .renderer=${rowRenderer} + ${comboBoxRenderer(rowRenderer)} @opened-changed=${this._openedChanged} @value-changed=${this._valueChanged} @filter-changed=${this._filterChanged} @@ -311,7 +297,7 @@ export class HaEntityPicker extends LitElement { }, 0); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` .suffix { display: flex; diff --git a/src/components/entity/ha-entity-toggle.ts b/src/components/entity/ha-entity-toggle.ts index 10fb56e096..5a3942d5d3 100644 --- a/src/components/entity/ha-entity-toggle.ts +++ b/src/components/entity/ha-entity-toggle.ts @@ -1,23 +1,22 @@ import { HassEntity } from "home-assistant-js-websocket"; import { css, - CSSResult, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { property, state } from "lit/decorators"; import { STATES_OFF } from "../../common/const"; import { computeStateDomain } from "../../common/entity/compute_state_domain"; import { computeStateName } from "../../common/entity/compute_state_name"; import { UNAVAILABLE, UNAVAILABLE_STATES } from "../../data/entity"; import { forwardHaptic } from "../../data/haptics"; import { HomeAssistant } from "../../types"; +import "../ha-formfield"; import "../ha-icon-button"; import "../ha-switch"; -import "../ha-formfield"; const isOn = (stateObj?: HassEntity) => stateObj !== undefined && @@ -32,7 +31,7 @@ export class HaEntityToggle extends LitElement { @property() public label?: string; - @internalProperty() private _isOn = false; + @state() private _isOn = false; protected render(): TemplateResult { if (!this.stateObj) { @@ -81,7 +80,8 @@ export class HaEntityToggle extends LitElement { this.addEventListener("click", (ev) => ev.stopPropagation()); } - protected updated(changedProps: PropertyValues): void { + public willUpdate(changedProps: PropertyValues): void { + super.willUpdate(changedProps); if (changedProps.has("stateObj")) { this._isOn = isOn(this.stateObj); } @@ -148,7 +148,7 @@ export class HaEntityToggle extends LitElement { }, 2000); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { white-space: nowrap; diff --git a/src/components/entity/ha-state-label-badge.ts b/src/components/entity/ha-state-label-badge.ts index 340677ff41..eaa8f89c53 100644 --- a/src/components/entity/ha-state-label-badge.ts +++ b/src/components/entity/ha-state-label-badge.ts @@ -1,23 +1,21 @@ import { HassEntity } from "home-assistant-js-websocket"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import secondsToDuration from "../../common/datetime/seconds_to_duration"; import { computeStateDisplay } from "../../common/entity/compute_state_display"; import { computeStateDomain } from "../../common/entity/compute_state_domain"; import { computeStateName } from "../../common/entity/compute_state_name"; import { domainIcon } from "../../common/entity/domain_icon"; import { stateIcon } from "../../common/entity/state_icon"; -import { timerTimeRemaining } from "../../common/entity/timer_time_remaining"; +import { timerTimeRemaining } from "../../data/timer"; import { formatNumber } from "../../common/string/format_number"; import { UNAVAILABLE, UNKNOWN } from "../../data/entity"; import { HomeAssistant } from "../../types"; @@ -35,7 +33,7 @@ export class HaStateLabelBadge extends LitElement { @property() public image?: string; - @internalProperty() private _timerTimeRemaining?: number; + @state() private _timerTimeRemaining?: number; private _connected?: boolean; @@ -54,9 +52,9 @@ export class HaStateLabelBadge extends LitElement { } protected render(): TemplateResult { - const state = this.state; + const entityState = this.state; - if (!state) { + if (!entityState) { return html` `; } @@ -99,7 +104,7 @@ export class HaStateLabelBadge extends LitElement { } } - private _computeValue(domain: string, state: HassEntity) { + private _computeValue(domain: string, entityState: HassEntity) { switch (domain) { case "binary_sensor": case "device_tracker": @@ -111,77 +116,81 @@ export class HaStateLabelBadge extends LitElement { return null; case "sensor": default: - return state.attributes.device_class === "moon__phase" + return entityState.attributes.device_class === "moon__phase" ? null - : state.state === UNKNOWN + : entityState.state === UNKNOWN ? "-" - : state.attributes.unit_of_measurement - ? formatNumber(state.state, this.hass!.locale) - : computeStateDisplay(this.hass!.localize, state, this.hass!.locale); + : entityState.attributes.unit_of_measurement + ? formatNumber(entityState.state, this.hass!.locale) + : computeStateDisplay( + this.hass!.localize, + entityState, + this.hass!.locale + ); } } - private _computeIcon(domain: string, state: HassEntity) { - if (state.state === UNAVAILABLE) { + private _computeIcon(domain: string, entityState: HassEntity) { + if (entityState.state === UNAVAILABLE) { return null; } switch (domain) { case "alarm_control_panel": - if (state.state === "pending") { + if (entityState.state === "pending") { return "hass:clock-fast"; } - if (state.state === "armed_away") { + if (entityState.state === "armed_away") { return "hass:nature"; } - if (state.state === "armed_home") { + if (entityState.state === "armed_home") { return "hass:home-variant"; } - if (state.state === "armed_night") { + if (entityState.state === "armed_night") { return "hass:weather-night"; } - if (state.state === "armed_custom_bypass") { + if (entityState.state === "armed_custom_bypass") { return "hass:shield-home"; } - if (state.state === "triggered") { + if (entityState.state === "triggered") { return "hass:alert-circle"; } // state == 'disarmed' - return domainIcon(domain, state); + return domainIcon(domain, entityState); case "binary_sensor": case "device_tracker": case "updater": case "person": case "sun": - return stateIcon(state); + return stateIcon(entityState); case "timer": - return state.state === "active" + return entityState.state === "active" ? "hass:timer-outline" : "hass:timer-off-outline"; default: - return state?.attributes.device_class === "moon__phase" - ? stateIcon(state) + return entityState?.attributes.device_class === "moon__phase" + ? stateIcon(entityState) : null; } } - private _computeLabel(domain, state, _timerTimeRemaining) { + private _computeLabel(domain, entityState, _timerTimeRemaining) { if ( - state.state === UNAVAILABLE || + entityState.state === UNAVAILABLE || ["device_tracker", "alarm_control_panel", "person"].includes(domain) ) { // Localize the state with a special state_badge namespace, which has variations of // the state translations that are truncated to fit within the badge label. Translations // are only added for device_tracker, alarm_control_panel and person. return ( - this.hass!.localize(`state_badge.${domain}.${state.state}`) || - this.hass!.localize(`state_badge.default.${state.state}`) || - state.state + this.hass!.localize(`state_badge.${domain}.${entityState.state}`) || + this.hass!.localize(`state_badge.default.${entityState.state}`) || + entityState.state ); } if (domain === "timer") { return secondsToDuration(_timerTimeRemaining); } - return state.attributes.unit_of_measurement || null; + return entityState.attributes.unit_of_measurement || null; } private clearInterval() { @@ -209,7 +218,7 @@ export class HaStateLabelBadge extends LitElement { this._timerTimeRemaining = timerTimeRemaining(stateObj); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { cursor: pointer; diff --git a/src/components/entity/state-badge.ts b/src/components/entity/state-badge.ts index 46886fa909..8dea329c93 100644 --- a/src/components/entity/state-badge.ts +++ b/src/components/entity/state-badge.ts @@ -1,16 +1,15 @@ import type { HassEntity } from "home-assistant-js-websocket"; import { css, - CSSResult, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; -import { ifDefined } from "lit-html/directives/if-defined"; -import { styleMap } from "lit-html/directives/style-map"; +} from "lit"; +import { property, state } from "lit/decorators"; +import { ifDefined } from "lit/directives/if-defined"; +import { styleMap } from "lit/directives/style-map"; import { computeActiveState } from "../../common/entity/compute_active_state"; import { computeStateDomain } from "../../common/entity/compute_state_domain"; import { stateIcon } from "../../common/entity/state_icon"; @@ -32,7 +31,7 @@ export class StateBadge extends LitElement { @property({ type: Boolean, reflect: true, attribute: "icon" }) private _showIcon = true; - @internalProperty() private _iconStyle: { [name: string]: string } = {}; + @state() private _iconStyle: { [name: string]: string } = {}; protected render(): TemplateResult { const stateObj = this.stateObj; @@ -64,7 +63,8 @@ export class StateBadge extends LitElement { `; } - protected updated(changedProps: PropertyValues) { + public willUpdate(changedProps: PropertyValues) { + super.willUpdate(changedProps); if ( !changedProps.has("stateObj") && !changedProps.has("overrideImage") && @@ -128,7 +128,7 @@ export class StateBadge extends LitElement { Object.assign(this.style, hostStyle); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { position: relative; diff --git a/src/components/entity/state-info.ts b/src/components/entity/state-info.ts index 0bb035cc7f..a4dbd8b87e 100644 --- a/src/components/entity/state-info.ts +++ b/src/components/entity/state-info.ts @@ -1,14 +1,7 @@ import "@polymer/paper-tooltip/paper-tooltip"; import type { HassEntity } from "home-assistant-js-websocket"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import { computeStateName } from "../../common/entity/compute_state_name"; import { computeRTL } from "../../common/util/compute_rtl"; import type { HomeAssistant } from "../../types"; @@ -73,7 +66,7 @@ class StateInfo extends LitElement {
` - : html`
`} + : html`
`} `; } @@ -89,7 +82,7 @@ class StateInfo extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { min-width: 120px; @@ -106,6 +99,10 @@ class StateInfo extends LitElement { .info { margin-left: 56px; + display: flex; + flex-direction: column; + justify-content: center; + height: 100%; } :host([rtl]) .info { diff --git a/src/components/ha-addon-picker.ts b/src/components/ha-addon-picker.ts index 582eaefcff..f868d5ead6 100644 --- a/src/components/ha-addon-picker.ts +++ b/src/components/ha-addon-picker.ts @@ -1,12 +1,5 @@ -import { - customElement, - html, - internalProperty, - LitElement, - property, - query, - TemplateResult, -} from "lit-element"; +import { html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state, query } from "lit/decorators"; import { isComponentLoaded } from "../common/config/is_component_loaded"; import { fireEvent } from "../common/dom/fire_event"; import { compare } from "../common/string/compare"; @@ -16,32 +9,20 @@ import { showAlertDialog } from "../dialogs/generic/show-dialog-box"; import { PolymerChangedEvent } from "../polymer-types"; import { HomeAssistant } from "../types"; import { HaComboBox } from "./ha-combo-box"; +import { ComboBoxLitRenderer } from "lit-vaadin-helpers"; -const rowRenderer = ( - root: HTMLElement, - _owner, - model: { item: HassioAddonInfo } -) => { - if (!root.firstElementChild) { - root.innerHTML = ` - - - -
[[item.name]]
-
[[item.slug]]
-
-
- `; - } - - root.querySelector(".name")!.textContent = model.item.name; - root.querySelector("[secondary]")!.textContent = model.item.slug; -}; +const rowRenderer: ComboBoxLitRenderer = (item) => html` + + + ${item.name} + ${item.slug} + + `; @customElement("ha-addon-picker") class HaAddonPicker extends LitElement { @@ -51,7 +32,7 @@ class HaAddonPicker extends LitElement { @property() public value = ""; - @internalProperty() private _addons?: HassioAddonInfo[]; + @state() private _addons?: HassioAddonInfo[]; @property({ type: Boolean }) public disabled = false; diff --git a/src/components/ha-analytics-learn-more.ts b/src/components/ha-analytics-learn-more.ts index 75acdab0b5..e806b2e459 100644 --- a/src/components/ha-analytics-learn-more.ts +++ b/src/components/ha-analytics-learn-more.ts @@ -1,4 +1,4 @@ -import { html } from "lit-element"; +import { html } from "lit"; import { HomeAssistant } from "../types"; import { documentationUrl } from "../util/documentation-url"; diff --git a/src/components/ha-analytics.ts b/src/components/ha-analytics.ts index e3f5ae6858..d81cbf379c 100644 --- a/src/components/ha-analytics.ts +++ b/src/components/ha-analytics.ts @@ -1,13 +1,6 @@ import "@polymer/paper-tooltip/paper-tooltip"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../common/dom/fire_event"; import { Analytics, AnalyticsPreferences } from "../data/analytics"; import { haStyle } from "../resources/styles"; @@ -151,7 +144,7 @@ export class HaAnalytics extends LitElement { fireEvent(this, "analytics-preferences-changed", { preferences }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/components/ha-area-picker.ts b/src/components/ha-area-picker.ts index 35f7fc00bb..f6d99c4510 100644 --- a/src/components/ha-area-picker.ts +++ b/src/components/ha-area-picker.ts @@ -8,16 +8,15 @@ import "@vaadin/vaadin-combo-box/theme/material/vaadin-combo-box-light"; import { UnsubscribeFunc } from "home-assistant-js-websocket"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, - query, TemplateResult, -} from "lit-element"; +} from "lit"; +import { ComboBoxLitRenderer, comboBoxRenderer } from "lit-vaadin-helpers"; +import { customElement, property, query, state } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import memoizeOne from "memoize-one"; import { fireEvent } from "../common/dom/fire_event"; import { computeDomain } from "../common/entity/compute_domain"; @@ -45,36 +44,20 @@ import { HomeAssistant } from "../types"; import type { HaDevicePickerDeviceFilterFunc } from "./device/ha-device-picker"; import "./ha-svg-icon"; -const rowRenderer = ( - root: HTMLElement, - _owner, - model: { item: AreaRegistryEntry } -) => { - if (!root.firstElementChild) { - root.innerHTML = ` - - - -
[[item.name]]
-
-
- `; - } - root.querySelector(".name")!.textContent = model.item.name!; - if (model.item.area_id === "add_new") { - root.querySelector("paper-item")!.className = "add-new"; - } else { - root.querySelector("paper-item")!.classList.remove("add-new"); - } -}; +const rowRenderer: ComboBoxLitRenderer = ( + item +) => html` + + ${item.name} + `; @customElement("ha-area-picker") export class HaAreaPicker extends SubscribeMixin(LitElement) { @@ -119,13 +102,13 @@ export class HaAreaPicker extends SubscribeMixin(LitElement) { @property({ type: Boolean }) public disabled?: boolean; - @internalProperty() private _areas?: AreaRegistryEntry[]; + @state() private _areas?: AreaRegistryEntry[]; - @internalProperty() private _devices?: DeviceRegistryEntry[]; + @state() private _devices?: DeviceRegistryEntry[]; - @internalProperty() private _entities?: EntityRegistryEntry[]; + @state() private _entities?: EntityRegistryEntry[]; - @internalProperty() private _opened?: boolean; + @state() private _opened?: boolean; @query("vaadin-combo-box-light", true) public comboBox!: HTMLElement; @@ -343,8 +326,8 @@ export class HaAreaPicker extends SubscribeMixin(LitElement) { item-id-path="area_id" item-label-path="name" .value=${this._value} - .renderer=${rowRenderer} .disabled=${this.disabled} + ${comboBoxRenderer(rowRenderer)} @opened-changed=${this._openedChanged} @value-changed=${this._areaChanged} > @@ -457,7 +440,7 @@ export class HaAreaPicker extends SubscribeMixin(LitElement) { }, 0); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` paper-input > mwc-icon-button { --mdc-icon-button-size: 24px; diff --git a/src/components/ha-attributes.ts b/src/components/ha-attributes.ts index e18910ef1d..5c75269a0b 100644 --- a/src/components/ha-attributes.ts +++ b/src/components/ha-attributes.ts @@ -1,27 +1,24 @@ import { HassEntity } from "home-assistant-js-websocket"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import { until } from "lit-html/directives/until"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { haStyle } from "../resources/styles"; +import { HomeAssistant } from "../types"; import hassAttributeUtil, { formatAttributeName, + formatAttributeValue, } from "../util/hass-attributes-util"; -import { haStyle } from "../resources/styles"; - -let jsYamlPromise: Promise; +import "./ha-expansion-panel"; @customElement("ha-attributes") class HaAttributes extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + @property() public stateObj?: HassEntity; @property({ attribute: "extra-filters" }) public extraFilters?: string; + @state() private _expanded = false; + protected render(): TemplateResult { if (!this.stateObj) { return html``; @@ -37,31 +34,47 @@ class HaAttributes extends LitElement { } return html` -
-
- ${attributes.map( - (attribute) => html` -
-
${formatAttributeName(attribute)}
-
${this.formatAttribute(attribute)}
-
- ` + - ${this.stateObj.attributes.attribution} -
- ` - : ""} - + outlined + @expanded-will-change=${this.expandedChanged} + > +
+ ${this._expanded + ? html` + ${attributes.map( + (attribute) => html` +
+
${formatAttributeName(attribute)}
+
+ ${this.formatAttribute(attribute)} +
+
+ ` + )} + ${this.stateObj.attributes.attribution + ? html` +
+ ${this.stateObj.attributes.attribution} +
+ ` + : ""} + ` + : ""} +
+ `; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` + .attribute-container { + margin-bottom: 8px; + } .data-entry { display: flex; flex-direction: row; @@ -109,38 +122,11 @@ class HaAttributes extends LitElement { return "-"; } const value = this.stateObj.attributes[attribute]; - return this.formatAttributeValue(value); + return formatAttributeValue(this.hass, value); } - private formatAttributeValue(value: any): string | TemplateResult { - if (value === null) { - return "-"; - } - // YAML handling - if ( - (Array.isArray(value) && value.some((val) => val instanceof Object)) || - (!Array.isArray(value) && value instanceof Object) - ) { - if (!jsYamlPromise) { - jsYamlPromise = import("js-yaml"); - } - const yaml = jsYamlPromise.then((jsYaml) => jsYaml.safeDump(value)); - return html`
${until(yaml, "")}
`; - } - // URL handling - if (typeof value === "string" && value.startsWith("http")) { - try { - // If invalid URL, exception will be raised - const url = new URL(value); - if (url.protocol === "http:" || url.protocol === "https:") - return html`
${value}`; - } catch (_) { - // Nothing to do here - } - } - return Array.isArray(value) ? value.join(", ") : value; + private expandedChanged(ev) { + this._expanded = ev.detail.expanded; } } diff --git a/src/components/ha-bar.ts b/src/components/ha-bar.ts index 3378958a56..d53abb15c7 100644 --- a/src/components/ha-bar.ts +++ b/src/components/ha-bar.ts @@ -1,12 +1,5 @@ -import { - css, - CSSResult, - customElement, - LitElement, - property, - svg, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, LitElement, svg, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import { getValueInPercentage, normalize, @@ -40,7 +33,7 @@ export class HaBar extends LitElement { `; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` rect { height: 100%; diff --git a/src/components/ha-blueprint-picker.ts b/src/components/ha-blueprint-picker.ts index 716d85ba17..2f3a302c35 100644 --- a/src/components/ha-blueprint-picker.ts +++ b/src/components/ha-blueprint-picker.ts @@ -1,15 +1,8 @@ import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import memoizeOne from "memoize-one"; import { fireEvent } from "../common/dom/fire_event"; import { compare } from "../common/string/compare"; @@ -98,7 +91,7 @@ class HaBluePrintPicker extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { display: inline-block; @@ -108,11 +101,9 @@ class HaBluePrintPicker extends LitElement { min-width: 200px; display: block; } - paper-listbox { - min-width: 200px; - } paper-item { cursor: pointer; + min-width: 200px; } `; } diff --git a/src/components/ha-button-menu.ts b/src/components/ha-button-menu.ts index de50f7bd42..8223b68d1c 100644 --- a/src/components/ha-button-menu.ts +++ b/src/components/ha-button-menu.ts @@ -1,15 +1,7 @@ import "@material/mwc-menu"; import type { Corner, Menu } from "@material/mwc-menu"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - query, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, query } from "lit/decorators"; @customElement("ha-button-menu") export class HaButtonMenu extends LitElement { @property() public corner: Corner = "TOP_START"; @@ -20,6 +12,8 @@ export class HaButtonMenu extends LitElement { @property({ type: Boolean }) public disabled = false; + @property({ type: Boolean }) public fixed = false; + @query("mwc-menu", true) private _menu?: Menu; public get items() { @@ -37,6 +31,7 @@ export class HaButtonMenu extends LitElement { @@ -53,7 +48,7 @@ export class HaButtonMenu extends LitElement { this._menu!.show(); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { display: inline-block; diff --git a/src/components/ha-button-related-filter-menu.ts b/src/components/ha-button-related-filter-menu.ts index 1e4cde248d..02db7f1e20 100644 --- a/src/components/ha-button-related-filter-menu.ts +++ b/src/components/ha-button-related-filter-menu.ts @@ -1,26 +1,18 @@ import "@material/mwc-icon-button"; import type { Corner } from "@material/mwc-menu"; -import { mdiFilterVariant } from "@mdi/js"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; import "@material/mwc-menu/mwc-menu-surface"; +import { mdiFilterVariant } 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 { findRelated, RelatedResult } from "../data/search"; -import type { HomeAssistant } from "../types"; -import "./ha-svg-icon"; -import "./ha-area-picker"; -import "./device/ha-device-picker"; -import "./entity/ha-entity-picker"; import { computeStateName } from "../common/entity/compute_state_name"; import { computeDeviceName } from "../data/device_registry"; +import { findRelated, RelatedResult } from "../data/search"; +import type { HomeAssistant } from "../types"; +import "./device/ha-device-picker"; +import "./entity/ha-entity-picker"; +import "./ha-area-picker"; +import "./ha-svg-icon"; declare global { // for fire event @@ -59,7 +51,7 @@ export class HaRelatedFilterButtonMenu extends LitElement { @property({ type: Array, attribute: "exclude-domains" }) public excludeDomains?: string[]; - @internalProperty() private _open = false; + @state() private _open = false; protected render(): TemplateResult { return html` @@ -175,7 +167,7 @@ export class HaRelatedFilterButtonMenu extends LitElement { }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { display: inline-block; diff --git a/src/components/ha-button-toggle-group.ts b/src/components/ha-button-toggle-group.ts index 8facec61bf..374be87341 100644 --- a/src/components/ha-button-toggle-group.ts +++ b/src/components/ha-button-toggle-group.ts @@ -1,15 +1,8 @@ import "@material/mwc-button/mwc-button"; import "@material/mwc-icon-button/mwc-icon-button"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import { styleMap } from "lit-html/directives/style-map"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; +import { styleMap } from "lit/directives/style-map"; import { fireEvent } from "../common/dom/fire_event"; import type { ToggleButton } from "../types"; import "./ha-svg-icon"; @@ -56,7 +49,7 @@ export class HaButtonToggleGroup extends LitElement { fireEvent(this, "value-changed", { value: this.active }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` div { display: flex; diff --git a/src/components/ha-camera-stream.ts b/src/components/ha-camera-stream.ts index adc3913644..9d91e81ffd 100644 --- a/src/components/ha-camera-stream.ts +++ b/src/components/ha-camera-stream.ts @@ -1,18 +1,16 @@ import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { isComponentLoaded } from "../common/config/is_component_loaded"; import { fireEvent } from "../common/dom/fire_event"; import { computeStateName } from "../common/entity/compute_state_name"; import { supportsFeature } from "../common/entity/supports-feature"; -import { isComponentLoaded } from "../common/config/is_component_loaded"; import { CameraEntity, CAMERA_SUPPORT_STREAM, @@ -39,9 +37,9 @@ class HaCameraStream extends LitElement { // We keep track if we should force MJPEG with a string // that way it automatically resets if we change entity. - @internalProperty() private _forceMJPEG?: string; + @state() private _forceMJPEG?: string; - @internalProperty() private _url?: string; + @state() private _url?: string; protected render(): TemplateResult { if (!this.stateObj) { @@ -113,7 +111,7 @@ class HaCameraStream extends LitElement { fireEvent(this, "iron-resize"); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host, img { diff --git a/src/components/ha-card.ts b/src/components/ha-card.ts index 157d663bfe..a5a6702b5b 100644 --- a/src/components/ha-card.ts +++ b/src/components/ha-card.ts @@ -1,12 +1,5 @@ -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; @customElement("ha-card") export class HaCard extends LitElement { @@ -14,7 +7,7 @@ export class HaCard extends LitElement { @property({ type: Boolean, reflect: true }) public outlined = false; - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { background: var( diff --git a/src/components/ha-checkbox.ts b/src/components/ha-checkbox.ts index 713d62d1d9..b3f5a1a2f4 100644 --- a/src/components/ha-checkbox.ts +++ b/src/components/ha-checkbox.ts @@ -1,12 +1,8 @@ -import "@material/mwc-checkbox"; -import type { Checkbox } from "@material/mwc-checkbox"; -import { customElement } from "lit-element"; -import type { Constructor } from "../types"; - -const MwcCheckbox = customElements.get("mwc-checkbox") as Constructor; +import { Checkbox } from "@material/mwc-checkbox"; +import { customElement } from "lit/decorators"; @customElement("ha-checkbox") -export class HaCheckbox extends MwcCheckbox { +export class HaCheckbox extends Checkbox { public firstUpdated() { super.firstUpdated(); this.style.setProperty("--mdc-theme-secondary", "var(--primary-color)"); diff --git a/src/components/ha-chip-set.ts b/src/components/ha-chip-set.ts index 9f1e237188..2b2bb6a9e9 100644 --- a/src/components/ha-chip-set.ts +++ b/src/components/ha-chip-set.ts @@ -2,14 +2,13 @@ import chipStyles from "@material/chips/dist/mdc.chips.min.css"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, LitElement, - property, TemplateResult, unsafeCSS, -} from "lit-element"; +} from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../common/dom/fire_event"; import "./ha-chip"; @@ -48,7 +47,7 @@ export class HaChipSet extends LitElement { }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` ${unsafeCSS(chipStyles)} diff --git a/src/components/ha-chip.ts b/src/components/ha-chip.ts index 2f57b6c943..0c8dce7edc 100644 --- a/src/components/ha-chip.ts +++ b/src/components/ha-chip.ts @@ -1,17 +1,15 @@ // @ts-ignore import chipStyles from "@material/chips/dist/mdc.chips.min.css"; -import { ripple } from "@material/mwc-ripple/ripple-directive"; -import "./ha-icon"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, LitElement, - property, TemplateResult, unsafeCSS, -} from "lit-element"; +} from "lit"; +import { customElement, property } from "lit/decorators"; +import "./ha-icon"; declare global { // for fire event @@ -34,7 +32,7 @@ export class HaChip extends LitElement { ` : null} -
+
@@ -44,7 +42,7 @@ export class HaChip extends LitElement { `; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` ${unsafeCSS(chipStyles)} .mdc-chip { diff --git a/src/components/ha-circular-progress.ts b/src/components/ha-circular-progress.ts index 7b69afa6b8..d493c04c5d 100644 --- a/src/components/ha-circular-progress.ts +++ b/src/components/ha-circular-progress.ts @@ -1,5 +1,6 @@ import { CircularProgress } from "@material/mwc-circular-progress"; -import { customElement, property } from "lit-element"; +import { CSSResultGroup, css } from "lit"; +import { customElement, property } from "lit/decorators"; @customElement("ha-circular-progress") // @ts-ignore @@ -41,6 +42,17 @@ export class HaCircularProgress extends CircularProgress { public get indeterminate() { return this.active; } + + static get styles(): CSSResultGroup { + return [ + super.styles, + css` + :host { + overflow: hidden; + } + `, + ]; + } } declare global { diff --git a/src/components/ha-climate-state.ts b/src/components/ha-climate-state.ts index aac651d6af..e9a14f653c 100644 --- a/src/components/ha-climate-state.ts +++ b/src/components/ha-climate-state.ts @@ -1,13 +1,6 @@ import { HassEntity } from "home-assistant-js-websocket"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import { formatNumber } from "../common/string/format_number"; import { CLIMATE_PRESET_NONE } from "../data/climate"; import type { HomeAssistant } from "../types"; @@ -126,7 +119,7 @@ class HaClimateState extends LitElement { : stateString; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { display: flex; diff --git a/src/components/ha-code-editor.ts b/src/components/ha-code-editor.ts index d830e06e08..7ea60707c3 100644 --- a/src/components/ha-code-editor.ts +++ b/src/components/ha-code-editor.ts @@ -1,11 +1,6 @@ import type { EditorView, KeyBinding, ViewUpdate } from "@codemirror/view"; -import { - customElement, - internalProperty, - property, - PropertyValues, - UpdatingElement, -} from "lit-element"; +import { css, CSSResultGroup, PropertyValues, ReactiveElement } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../common/dom/fire_event"; import { loadCodeMirror } from "../resources/codemirror.ondemand"; @@ -24,7 +19,7 @@ const saveKeyBinding: KeyBinding = { }; @customElement("ha-code-editor") -export class HaCodeEditor extends UpdatingElement { +export class HaCodeEditor extends ReactiveElement { public codemirror?: EditorView; @property() public mode = "yaml"; @@ -35,7 +30,7 @@ export class HaCodeEditor extends UpdatingElement { @property() public error = false; - @internalProperty() private _value = ""; + @state() private _value = ""; private _loadedCodeMirror?: typeof import("../resources/codemirror"); @@ -116,14 +111,6 @@ export class HaCodeEditor extends UpdatingElement { private async _load(): Promise { this._loadedCodeMirror = await loadCodeMirror(); - const shadowRoot = this.attachShadow({ mode: "open" }); - - shadowRoot!.innerHTML = ``; - this.codemirror = new this._loadedCodeMirror.EditorView({ state: this._loadedCodeMirror.EditorState.create({ doc: this._value, @@ -155,8 +142,8 @@ export class HaCodeEditor extends UpdatingElement { ), ], }), - root: shadowRoot, - parent: shadowRoot, + root: this.shadowRoot!, + parent: this.shadowRoot!, }); } @@ -175,6 +162,15 @@ export class HaCodeEditor extends UpdatingElement { this._value = newValue; fireEvent(this, "value-changed", { value: this._value }); } + + // Only Lit 2.0 will use this + static get styles(): CSSResultGroup { + return css` + :host(.error-state) div.cm-wrap .cm-gutters { + border-color: var(--error-state-color, red); + } + `; + } } declare global { diff --git a/src/components/ha-color-picker.js b/src/components/ha-color-picker.js index e692ef3076..f94018ab71 100644 --- a/src/components/ha-color-picker.js +++ b/src/components/ha-color-picker.js @@ -1,8 +1,8 @@ import { html } from "@polymer/polymer/lib/utils/html-tag"; /* eslint-plugin-disable lit */ import { PolymerElement } from "@polymer/polymer/polymer-element"; -import { EventsMixin } from "../mixins/events-mixin"; import { hs2rgb, rgb2hs } from "../common/color/convert-color"; +import { EventsMixin } from "../mixins/events-mixin"; /** * Color-picker custom element * diff --git a/src/components/ha-combo-box.ts b/src/components/ha-combo-box.ts index 19f89bd410..f1e4650d7c 100644 --- a/src/components/ha-combo-box.ts +++ b/src/components/ha-combo-box.ts @@ -5,41 +5,21 @@ import "@polymer/paper-item/paper-item"; import "@polymer/paper-item/paper-item-body"; import "@polymer/paper-listbox/paper-listbox"; import "@vaadin/vaadin-combo-box/theme/material/vaadin-combo-box-light"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - query, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { ComboBoxLitRenderer, comboBoxRenderer } from "lit-vaadin-helpers"; +import { customElement, property, query, state } from "lit/decorators"; import { fireEvent } from "../common/dom/fire_event"; import { PolymerChangedEvent } from "../polymer-types"; import { HomeAssistant } from "../types"; import "./ha-svg-icon"; -const defaultRowRenderer = ( - root: HTMLElement, - _owner, - model: { item: any } -) => { - if (!root.firstElementChild) { - root.innerHTML = ` - - - `; - } - - root.querySelector("paper-item")!.textContent = model.item; -}; +const defaultRowRenderer: ComboBoxLitRenderer = (item) => html` + ${item}`; @customElement("ha-combo-box") export class HaComboBox extends LitElement { @@ -62,15 +42,11 @@ export class HaComboBox extends LitElement { @property({ attribute: "item-id-path" }) public itemIdPath?: string; - @property() public renderer?: ( - root: HTMLElement, - owner: HTMLElement, - model: { item: any } - ) => void; + @property() public renderer?: ComboBoxLitRenderer; @property({ type: Boolean }) public disabled?: boolean; - @internalProperty() private _opened?: boolean; + @state() private _opened?: boolean; @query("vaadin-combo-box-light", true) private _comboBox!: HTMLElement; @@ -99,9 +75,9 @@ export class HaComboBox extends LitElement { .value=${this.value} .items=${this.items} .filteredItems=${this.filteredItems} - .renderer=${this.renderer || defaultRowRenderer} .allowCustomValue=${this.allowCustomValue} .disabled=${this.disabled} + ${comboBoxRenderer(this.renderer || defaultRowRenderer)} @opened-changed=${this._openedChanged} @filter-changed=${this._filterChanged} @value-changed=${this._valueChanged} @@ -167,7 +143,7 @@ export class HaComboBox extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` paper-input > mwc-icon-button { --mdc-icon-button-size: 24px; diff --git a/src/components/ha-cover-controls.ts b/src/components/ha-cover-controls.ts index 08910a7735..dbc4018322 100644 --- a/src/components/ha-cover-controls.ts +++ b/src/components/ha-cover-controls.ts @@ -1,16 +1,14 @@ import type { HassEntity } from "home-assistant-js-websocket"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import { computeCloseIcon, computeOpenIcon } from "../common/entity/cover_icon"; import { UNAVAILABLE } from "../data/entity"; import type { HomeAssistant } from "../types"; @@ -23,10 +21,10 @@ class HaCoverControls extends LitElement { @property({ attribute: false }) public stateObj!: HassEntity; - @internalProperty() private _entityObj?: CoverEntity; + @state() private _entityObj?: CoverEntity; - protected updated(changedProperties: PropertyValues): void { - super.updated(changedProperties); + public willUpdate(changedProperties: PropertyValues): void { + super.willUpdate(changedProperties); if (changedProperties.has("stateObj")) { this._entityObj = new CoverEntity(this.hass, this.stateObj); @@ -114,7 +112,7 @@ class HaCoverControls extends LitElement { this._entityObj.stopCover(); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` .state { white-space: nowrap; diff --git a/src/components/ha-cover-tilt-controls.ts b/src/components/ha-cover-tilt-controls.ts index be2f6f4087..d2c3d97eb7 100644 --- a/src/components/ha-cover-tilt-controls.ts +++ b/src/components/ha-cover-tilt-controls.ts @@ -1,16 +1,14 @@ import { HassEntity } from "home-assistant-js-websocket"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import { UNAVAILABLE } from "../data/entity"; import { HomeAssistant } from "../types"; import CoverEntity from "../util/cover-model"; @@ -22,10 +20,10 @@ class HaCoverTiltControls extends LitElement { @property({ attribute: false }) stateObj!: HassEntity; - @internalProperty() private _entityObj?: CoverEntity; + @state() private _entityObj?: CoverEntity; - protected updated(changedProperties: PropertyValues): void { - super.updated(changedProperties); + public willUpdate(changedProperties: PropertyValues): void { + super.willUpdate(changedProperties); if (changedProperties.has("stateObj")) { this._entityObj = new CoverEntity(this.hass, this.stateObj); @@ -101,7 +99,7 @@ class HaCoverTiltControls extends LitElement { this._entityObj.stopCoverTilt(); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { white-space: nowrap; diff --git a/src/components/ha-date-input.ts b/src/components/ha-date-input.ts index 40493d1345..d2289c464b 100644 --- a/src/components/ha-date-input.ts +++ b/src/components/ha-date-input.ts @@ -1,17 +1,9 @@ -import "@vaadin/vaadin-date-picker/theme/material/vaadin-date-picker-light"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - PropertyValues, - query, -} from "lit-element"; -import "@polymer/paper-input/paper-input"; -import { fireEvent } from "../common/dom/fire_event"; import { mdiCalendar } from "@mdi/js"; +import "@polymer/paper-input/paper-input"; +import "@vaadin/vaadin-date-picker/theme/material/vaadin-date-picker-light"; +import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit"; +import { customElement, property, query } from "lit/decorators"; +import { fireEvent } from "../common/dom/fire_event"; import "./ha-svg-icon"; const i18n = { @@ -134,7 +126,7 @@ export class HaDateInput extends LitElement { return true; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` paper-input { width: 110px; diff --git a/src/components/ha-date-range-picker.ts b/src/components/ha-date-range-picker.ts index d0d1442f87..2940c3a883 100644 --- a/src/components/ha-date-range-picker.ts +++ b/src/components/ha-date-range-picker.ts @@ -6,15 +6,15 @@ import { mdiCalendar } from "@mdi/js"; import "@polymer/paper-input/paper-input"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property } from "lit/decorators"; import { formatDateTime } from "../common/datetime/format_date_time"; +import { useAmPm } from "../common/datetime/use_am_pm"; import { computeRTLDirection } from "../common/util/compute_rtl"; import { HomeAssistant } from "../types"; import "./date-range-picker"; @@ -44,7 +44,7 @@ export class HaDateRangePicker extends LitElement { if (changedProps.has("hass")) { const oldHass = changedProps.get("hass") as HomeAssistant | undefined; if (!oldHass || oldHass.locale !== this.hass.locale) { - this._hour24format = this._compute24hourFormat(); + this._hour24format = !useAmPm(this.hass.locale); this._rtlDirection = computeRTLDirection(this.hass); } } @@ -107,16 +107,6 @@ export class HaDateRangePicker extends LitElement { `; } - private _compute24hourFormat() { - return ( - new Intl.DateTimeFormat(this.hass.language, { - hour: "numeric", - }) - .formatToParts(new Date(2020, 0, 1, 13)) - .find((part) => part.type === "hour")!.value.length === 2 - ); - } - private _setDateRange(ev: CustomEvent) { const dateRange = Object.values(this.ranges!)[ev.detail.index]; const dateRangePicker = this._dateRangePicker; @@ -146,7 +136,7 @@ export class HaDateRangePicker extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` ha-svg-icon { margin-right: 8px; diff --git a/src/components/ha-dialog.ts b/src/components/ha-dialog.ts index 40e0f736db..b776bdf6cb 100644 --- a/src/components/ha-dialog.ts +++ b/src/components/ha-dialog.ts @@ -1,14 +1,11 @@ -import "@material/mwc-dialog"; -import type { Dialog } from "@material/mwc-dialog"; -import { style } from "@material/mwc-dialog/mwc-dialog-css"; +import { Dialog } from "@material/mwc-dialog"; import { mdiClose } from "@mdi/js"; -import { css, CSSResult, customElement, html } from "lit-element"; +import { css, CSSResultGroup, html } from "lit"; +import { customElement } from "lit/decorators"; import { computeRTLDirection } from "../common/util/compute_rtl"; -import type { Constructor, HomeAssistant } from "../types"; +import type { HomeAssistant } from "../types"; import "./ha-icon-button"; -const MwcDialog = customElements.get("mwc-dialog") as Constructor; - export const createCloseHeading = (hass: HomeAssistant, title: string) => html` ${title} html` `; @customElement("ha-dialog") -export class HaDialog extends MwcDialog { +// @ts-expect-error +export class HaDialog extends Dialog { public scrollToPos(x: number, y: number) { this.contentElement.scrollTo(x, y); } @@ -31,9 +29,9 @@ export class HaDialog extends MwcDialog { return html` ${super.renderHeading()} `; } - protected static get styles(): CSSResult[] { + protected static get styles(): CSSResultGroup { return [ - style, + Dialog.styles, css` .mdc-dialog { --mdc-dialog-scroll-divider-color: var(--divider-color); diff --git a/src/components/ha-expansion-panel.ts b/src/components/ha-expansion-panel.ts index be3dc4f77d..f553e3ffc6 100644 --- a/src/components/ha-expansion-panel.ts +++ b/src/components/ha-expansion-panel.ts @@ -1,16 +1,9 @@ import { mdiChevronDown } from "@mdi/js"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - query, - TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, query } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import { fireEvent } from "../common/dom/fire_event"; +import { nextRender } from "../common/util/render-status"; import "./ha-svg-icon"; @customElement("ha-expansion-panel") @@ -45,21 +38,29 @@ class HaExpansionPanel extends LitElement { this._container.style.removeProperty("height"); } - private _toggleContainer(): void { + private async _toggleContainer(): Promise { + const newExpanded = !this.expanded; + fireEvent(this, "expanded-will-change", { expanded: newExpanded }); + + if (newExpanded) { + // allow for dynamic content to be rendered + await nextRender(); + } + const scrollHeight = this._container.scrollHeight; this._container.style.height = `${scrollHeight}px`; - if (this.expanded) { + if (!newExpanded) { setTimeout(() => { this._container.style.height = "0px"; }, 0); } - this.expanded = !this.expanded; + this.expanded = newExpanded; fireEvent(this, "expanded-changed", { expanded: this.expanded }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { display: block; @@ -119,5 +120,8 @@ declare global { "expanded-changed": { expanded: boolean; }; + "expanded-will-change": { + expanded: boolean; + }; } } diff --git a/src/components/ha-fab.ts b/src/components/ha-fab.ts index 9725630b6c..c2f58b8f0f 100644 --- a/src/components/ha-fab.ts +++ b/src/components/ha-fab.ts @@ -1,12 +1,8 @@ -import "@material/mwc-fab"; -import type { Fab } from "@material/mwc-fab"; -import { customElement } from "lit-element"; -import { Constructor } from "../types"; - -const MwcFab = customElements.get("mwc-fab") as Constructor; +import { Fab } from "@material/mwc-fab"; +import { customElement } from "lit/decorators"; @customElement("ha-fab") -export class HaFab extends MwcFab { +export class HaFab extends Fab { protected firstUpdated(changedProperties) { super.firstUpdated(changedProperties); this.style.setProperty("--mdc-theme-secondary", "var(--primary-color)"); diff --git a/src/components/ha-file-upload.ts b/src/components/ha-file-upload.ts index 0fa12a6ed9..2eec7319c0 100644 --- a/src/components/ha-file-upload.ts +++ b/src/components/ha-file-upload.ts @@ -2,18 +2,9 @@ import "@material/mwc-icon-button/mwc-icon-button"; import { mdiClose } from "@mdi/js"; import "@polymer/iron-input/iron-input"; import "@polymer/paper-input/paper-input-container"; -import { - css, - customElement, - html, - internalProperty, - LitElement, - property, - PropertyValues, - query, - TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +import { css, html, LitElement, PropertyValues, TemplateResult } from "lit"; +import { customElement, property, state, query } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import { fireEvent } from "../common/dom/fire_event"; import "./ha-circular-progress"; import "./ha-svg-icon"; @@ -39,7 +30,7 @@ export class HaFileUpload extends LitElement { @property({ type: Boolean, attribute: "auto-open-file-dialog" }) private autoOpenFileDialog = false; - @internalProperty() private _drag = false; + @state() private _drag = false; @query("#input") private _input?: HTMLInputElement; diff --git a/src/components/ha-form/ha-form-boolean.ts b/src/components/ha-form/ha-form-boolean.ts index 454a01e718..2bf264a498 100644 --- a/src/components/ha-form/ha-form-boolean.ts +++ b/src/components/ha-form/ha-form-boolean.ts @@ -1,15 +1,7 @@ import "@polymer/paper-checkbox/paper-checkbox"; import type { PaperCheckboxElement } from "@polymer/paper-checkbox/paper-checkbox"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - query, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, query } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import type { HaFormBooleanData, @@ -49,7 +41,7 @@ export class HaFormBoolean extends LitElement implements HaFormElement { }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` paper-checkbox { display: block; diff --git a/src/components/ha-form/ha-form-constant.ts b/src/components/ha-form/ha-form-constant.ts index 4e6d6e21b4..d05e9ac5f6 100644 --- a/src/components/ha-form/ha-form-constant.ts +++ b/src/components/ha-form/ha-form-constant.ts @@ -1,13 +1,12 @@ import { css, - CSSResult, - customElement, + CSSResultGroup, html, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import { HaFormConstantSchema, HaFormElement } from "./ha-form"; @@ -28,7 +27,7 @@ export class HaFormConstant extends LitElement implements HaFormElement { return html`${this.label}: ${this.schema.value}`; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { display: block; diff --git a/src/components/ha-form/ha-form-float.ts b/src/components/ha-form/ha-form-float.ts index 9720f0ffd2..edf3c13576 100644 --- a/src/components/ha-form/ha-form-float.ts +++ b/src/components/ha-form/ha-form-float.ts @@ -1,13 +1,7 @@ import "@polymer/paper-input/paper-input"; import type { PaperInputElement } from "@polymer/paper-input/paper-input"; -import { - customElement, - html, - LitElement, - property, - query, - TemplateResult, -} from "lit-element"; +import { html, LitElement, TemplateResult } from "lit"; +import { customElement, property, query } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import { HaFormElement, HaFormFloatData, HaFormFloatSchema } from "./ha-form"; diff --git a/src/components/ha-form/ha-form-integer.ts b/src/components/ha-form/ha-form-integer.ts index 9fab3cabc0..6f0ec4cfab 100644 --- a/src/components/ha-form/ha-form-integer.ts +++ b/src/components/ha-form/ha-form-integer.ts @@ -2,16 +2,8 @@ import "@polymer/paper-input/paper-input"; import type { PaperInputElement } from "@polymer/paper-input/paper-input"; import "@polymer/paper-slider/paper-slider"; import type { PaperSliderElement } from "@polymer/paper-slider/paper-slider"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - query, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, query } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import { HaCheckbox } from "../ha-checkbox"; import "../ha-slider"; @@ -107,7 +99,7 @@ export class HaFormInteger extends LitElement implements HaFormElement { }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` .flex { display: flex; diff --git a/src/components/ha-form/ha-form-multi_select.ts b/src/components/ha-form/ha-form-multi_select.ts index 117dbe927e..93ad92bd65 100644 --- a/src/components/ha-form/ha-form-multi_select.ts +++ b/src/components/ha-form/ha-form-multi_select.ts @@ -4,17 +4,8 @@ import "@polymer/paper-item/paper-icon-item"; import "@polymer/paper-listbox/paper-listbox"; import "@polymer/paper-menu-button/paper-menu-button"; import "@polymer/paper-ripple/paper-ripple"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - query, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state, query } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import "../ha-icon"; import { @@ -33,7 +24,7 @@ export class HaFormMultiSelect extends LitElement implements HaFormElement { @property() public suffix!: string; - @internalProperty() private _init = false; + @state() private _init = false; @query("paper-menu-button", true) private _input?: HTMLElement; @@ -140,7 +131,7 @@ export class HaFormMultiSelect extends LitElement implements HaFormElement { ); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` paper-menu-button { display: block; diff --git a/src/components/ha-form/ha-form-positive_time_period_dict.ts b/src/components/ha-form/ha-form-positive_time_period_dict.ts index 453eaf2a68..04ec575981 100644 --- a/src/components/ha-form/ha-form-positive_time_period_dict.ts +++ b/src/components/ha-form/ha-form-positive_time_period_dict.ts @@ -1,11 +1,5 @@ -import { - customElement, - html, - LitElement, - property, - query, - TemplateResult, -} from "lit-element"; +import { html, LitElement, TemplateResult } from "lit"; +import { customElement, property, query } from "lit/decorators"; import "../ha-time-input"; import { HaFormElement, HaFormTimeData, HaFormTimeSchema } from "./ha-form"; diff --git a/src/components/ha-form/ha-form-select.ts b/src/components/ha-form/ha-form-select.ts index 398de2afda..5cf9dc013d 100644 --- a/src/components/ha-form/ha-form-select.ts +++ b/src/components/ha-form/ha-form-select.ts @@ -1,15 +1,7 @@ import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - query, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, query } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import "../ha-paper-dropdown-menu"; import { HaFormElement, HaFormSelectData, HaFormSelectSchema } from "./ha-form"; @@ -74,7 +66,7 @@ export class HaFormSelect extends LitElement implements HaFormElement { }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` ha-paper-dropdown-menu { display: block; diff --git a/src/components/ha-form/ha-form-string.ts b/src/components/ha-form/ha-form-string.ts index a376520783..82e4520bfa 100644 --- a/src/components/ha-form/ha-form-string.ts +++ b/src/components/ha-form/ha-form-string.ts @@ -1,17 +1,9 @@ +import "@material/mwc-icon-button/mwc-icon-button"; import { mdiEye, mdiEyeOff } from "@mdi/js"; import "@polymer/paper-input/paper-input"; import type { PaperInputElement } from "@polymer/paper-input/paper-input"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - query, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state, query } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import "../ha-svg-icon"; import type { @@ -19,7 +11,6 @@ import type { HaFormStringData, HaFormStringSchema, } from "./ha-form"; -import "@material/mwc-icon-button/mwc-icon-button"; @customElement("ha-form-string") export class HaFormString extends LitElement implements HaFormElement { @@ -31,7 +22,7 @@ export class HaFormString extends LitElement implements HaFormElement { @property() public suffix!: string; - @internalProperty() private _unmaskedPassword = false; + @state() private _unmaskedPassword = false; @query("paper-input") private _input?: HTMLElement; @@ -104,7 +95,7 @@ export class HaFormString extends LitElement implements HaFormElement { return "text"; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` mwc-icon-button { --mdc-icon-button-size: 24px; diff --git a/src/components/ha-form/ha-form.ts b/src/components/ha-form/ha-form.ts index adfe4fd71f..1a4c02e319 100644 --- a/src/components/ha-form/ha-form.ts +++ b/src/components/ha-form/ha-form.ts @@ -1,11 +1,5 @@ -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { dynamicElement } from "../../common/dom/dynamic-element-directive"; import { fireEvent } from "../../common/dom/fire_event"; import { HaTimeData } from "../ha-time-input"; @@ -207,7 +201,7 @@ export class HaForm extends LitElement implements HaFormElement { }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` .error { color: var(--error-color); diff --git a/src/components/ha-formfield.ts b/src/components/ha-formfield.ts index 96187b8803..e7c9232f1d 100644 --- a/src/components/ha-formfield.ts +++ b/src/components/ha-formfield.ts @@ -1,18 +1,12 @@ -import "@material/mwc-formfield"; -import type { Formfield } from "@material/mwc-formfield"; -import { style } from "@material/mwc-formfield/mwc-formfield-css"; -import { css, CSSResult, customElement } from "lit-element"; -import { Constructor } from "../types"; - -const MwcFormfield = customElements.get( - "mwc-formfield" -) as Constructor; - +import { Formfield } from "@material/mwc-formfield"; +import { css, CSSResultGroup } from "lit"; +import { customElement } from "lit/decorators"; @customElement("ha-formfield") -export class HaFormfield extends MwcFormfield { - protected static get styles(): CSSResult[] { +// @ts-expect-error +export class HaFormfield extends Formfield { + protected static get styles(): CSSResultGroup { return [ - style, + Formfield.styles, css` :host(:not([alignEnd])) ::slotted(ha-switch) { margin-right: 10px; diff --git a/src/components/ha-gauge.ts b/src/components/ha-gauge.ts index 0628cb2243..26b4ae52aa 100644 --- a/src/components/ha-gauge.ts +++ b/src/components/ha-gauge.ts @@ -1,17 +1,10 @@ -import { - css, - customElement, - internalProperty, - LitElement, - property, - PropertyValues, - svg, -} from "lit-element"; -import { ifDefined } from "lit-html/directives/if-defined"; -import { styleMap } from "lit-html/directives/style-map"; +import { css, LitElement, PropertyValues, svg } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { ifDefined } from "lit/directives/if-defined"; +import { styleMap } from "lit/directives/style-map"; import { formatNumber } from "../common/string/format_number"; import { afterNextRender } from "../common/util/render-status"; -import { FrontendTranslationData } from "../data/translation"; +import { FrontendLocaleData } from "../data/translation"; import { getValueInPercentage, normalize } from "../util/calculate"; const getAngle = (value: number, min: number, max: number) => { @@ -30,13 +23,13 @@ export class Gauge extends LitElement { @property({ type: Number }) public value = 0; - @property() public locale!: FrontendTranslationData; + @property() public locale!: FrontendLocaleData; @property() public label = ""; - @internalProperty() private _angle = 0; + @state() private _angle = 0; - @internalProperty() private _updated = false; + @state() private _updated = false; protected firstUpdated(changedProperties: PropertyValues) { super.firstUpdated(changedProperties); diff --git a/src/components/ha-header-bar.ts b/src/components/ha-header-bar.ts index 0677e96673..68111455af 100644 --- a/src/components/ha-header-bar.ts +++ b/src/components/ha-header-bar.ts @@ -1,6 +1,7 @@ // @ts-ignore import topAppBarStyles from "@material/top-app-bar/dist/mdc.top-app-bar.min.css"; -import { css, customElement, html, LitElement, unsafeCSS } from "lit-element"; +import { css, html, LitElement, unsafeCSS } from "lit"; +import { customElement } from "lit/decorators"; @customElement("ha-header-bar") export class HaHeaderBar extends LitElement { diff --git a/src/components/ha-help-tooltip.ts b/src/components/ha-help-tooltip.ts index 73e60e5799..1194f77b98 100644 --- a/src/components/ha-help-tooltip.ts +++ b/src/components/ha-help-tooltip.ts @@ -1,13 +1,7 @@ import { mdiHelpCircle } from "@mdi/js"; import "@polymer/paper-tooltip/paper-tooltip"; -import { - css, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import "./ha-svg-icon"; @customElement("ha-help-tooltip") diff --git a/src/components/ha-hls-player.ts b/src/components/ha-hls-player.ts index e841993c1b..857e2c1874 100644 --- a/src/components/ha-hls-player.ts +++ b/src/components/ha-hls-player.ts @@ -1,16 +1,13 @@ import type HlsType from "hls.js"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, - query, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, query, state } from "lit/decorators"; import { fireEvent } from "../common/dom/fire_event"; import { nextRender } from "../common/util/render-status"; import { getExternalConfig } from "../external_app/external_config"; @@ -40,7 +37,7 @@ class HaHLSPlayer extends LitElement { // don't cache this, as we remove it on disconnects @query("video") private _videoEl!: HTMLVideoElement; - @internalProperty() private _attached = false; + @state() private _attached = false; private _hlsPolyfillInstance?: HlsType; @@ -220,7 +217,7 @@ class HaHLSPlayer extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host, video { diff --git a/src/components/ha-icon-button-arrow-next.ts b/src/components/ha-icon-button-arrow-next.ts index 85bc2d245f..a0c58a48ef 100644 --- a/src/components/ha-icon-button-arrow-next.ts +++ b/src/components/ha-icon-button-arrow-next.ts @@ -1,13 +1,7 @@ import "@material/mwc-icon-button/mwc-icon-button"; import { mdiArrowLeft, mdiArrowRight } from "@mdi/js"; -import { - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { HomeAssistant } from "../types"; import "./ha-svg-icon"; @@ -19,7 +13,7 @@ export class HaIconButtonArrowNext extends LitElement { @property() public label?: string; - @internalProperty() private _icon = mdiArrowRight; + @state() private _icon = mdiArrowRight; public connectedCallback() { super.connectedCallback(); diff --git a/src/components/ha-icon-button-arrow-prev.ts b/src/components/ha-icon-button-arrow-prev.ts index c426c589a7..dc192b88fe 100644 --- a/src/components/ha-icon-button-arrow-prev.ts +++ b/src/components/ha-icon-button-arrow-prev.ts @@ -1,13 +1,7 @@ import "@material/mwc-icon-button/mwc-icon-button"; import { mdiArrowLeft, mdiArrowRight } from "@mdi/js"; -import { - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { HomeAssistant } from "../types"; import "./ha-svg-icon"; @@ -19,7 +13,7 @@ export class HaIconButtonArrowPrev extends LitElement { @property() public label?: string; - @internalProperty() private _icon = mdiArrowLeft; + @state() private _icon = mdiArrowLeft; public connectedCallback() { super.connectedCallback(); diff --git a/src/components/ha-icon-button-next.ts b/src/components/ha-icon-button-next.ts index 04213393eb..8f3a039ca0 100644 --- a/src/components/ha-icon-button-next.ts +++ b/src/components/ha-icon-button-next.ts @@ -1,13 +1,7 @@ import "@material/mwc-icon-button"; import { mdiChevronLeft, mdiChevronRight } from "@mdi/js"; -import { - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { HomeAssistant } from "../types"; import "./ha-svg-icon"; @@ -19,7 +13,7 @@ export class HaIconButtonNext extends LitElement { @property() public label?: string; - @internalProperty() private _icon = mdiChevronRight; + @state() private _icon = mdiChevronRight; public connectedCallback() { super.connectedCallback(); diff --git a/src/components/ha-icon-button-prev.ts b/src/components/ha-icon-button-prev.ts index 6384039f13..9bad876137 100644 --- a/src/components/ha-icon-button-prev.ts +++ b/src/components/ha-icon-button-prev.ts @@ -1,13 +1,7 @@ import "@material/mwc-icon-button/mwc-icon-button"; import { mdiChevronLeft, mdiChevronRight } from "@mdi/js"; -import { - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { HomeAssistant } from "../types"; import "./ha-svg-icon"; @@ -19,7 +13,7 @@ export class HaIconButtonPrev extends LitElement { @property() public label?: string; - @internalProperty() private _icon = mdiChevronLeft; + @state() private _icon = mdiChevronLeft; public connectedCallback() { super.connectedCallback(); diff --git a/src/components/ha-icon-button.ts b/src/components/ha-icon-button.ts index e8cc62ab55..1195a8517a 100644 --- a/src/components/ha-icon-button.ts +++ b/src/components/ha-icon-button.ts @@ -1,13 +1,6 @@ import "@material/mwc-icon-button"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import "./ha-icon"; @customElement("ha-icon-button") @@ -18,9 +11,10 @@ export class HaIconButton extends LitElement { @property({ type: String }) label = ""; - protected createRenderRoot() { - return this.attachShadow({ mode: "open", delegatesFocus: true }); - } + static shadowRootOptions: ShadowRootInit = { + mode: "open", + delegatesFocus: true, + }; protected render(): TemplateResult { return html` @@ -30,7 +24,7 @@ export class HaIconButton extends LitElement { `; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { display: inline-block; diff --git a/src/components/ha-icon-input.ts b/src/components/ha-icon-input.ts index 11f310c91f..fb62e3addb 100644 --- a/src/components/ha-icon-input.ts +++ b/src/components/ha-icon-input.ts @@ -1,12 +1,6 @@ import "@polymer/paper-input/paper-input"; -import { - css, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../common/dom/fire_event"; import "./ha-icon"; diff --git a/src/components/ha-icon.ts b/src/components/ha-icon.ts index 2cb7e0bdf6..73563d26f6 100644 --- a/src/components/ha-icon.ts +++ b/src/components/ha-icon.ts @@ -1,15 +1,13 @@ import "@polymer/iron-icon/iron-icon"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../common/dom/fire_event"; import { debounce } from "../common/util/debounce"; import { CustomIcon, customIconsets } from "../data/custom_iconsets"; @@ -45,13 +43,14 @@ const cachedIcons: Record = {}; export class HaIcon extends LitElement { @property() public icon?: string; - @internalProperty() private _path?: string; + @state() private _path?: string; - @internalProperty() private _viewBox?; + @state() private _viewBox?; - @internalProperty() private _legacy = false; + @state() private _legacy = false; - protected updated(changedProps: PropertyValues) { + public willUpdate(changedProps: PropertyValues) { + super.willUpdate(changedProps); if (changedProps.has("icon")) { this._path = undefined; this._viewBox = undefined; @@ -161,7 +160,7 @@ export class HaIcon extends LitElement { cachedIcons[iconName] = iconPack[iconName]; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { fill: currentcolor; diff --git a/src/components/ha-label-badge.ts b/src/components/ha-label-badge.ts index 49ecff7bf2..67569aeecb 100644 --- a/src/components/ha-label-badge.ts +++ b/src/components/ha-label-badge.ts @@ -1,13 +1,13 @@ import { css, - CSSResult, + CSSResultGroup, html, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +} from "lit"; +import { property } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import "./ha-icon"; class HaLabelBadge extends LitElement { @@ -60,7 +60,7 @@ class HaLabelBadge extends LitElement { `; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ css` .badge-container { diff --git a/src/components/ha-markdown-element.ts b/src/components/ha-markdown-element.ts index cd07cf0a01..e0df4e40b7 100644 --- a/src/components/ha-markdown-element.ts +++ b/src/components/ha-markdown-element.ts @@ -1,15 +1,20 @@ -import { customElement, property, UpdatingElement } from "lit-element"; +import { ReactiveElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../common/dom/fire_event"; import { renderMarkdown } from "../resources/render-markdown"; @customElement("ha-markdown-element") -class HaMarkdownElement extends UpdatingElement { +class HaMarkdownElement extends ReactiveElement { @property() public content?; @property({ type: Boolean }) public allowSvg = false; @property({ type: Boolean }) public breaks = false; + protected createRenderRoot() { + return this; + } + protected update(changedProps) { super.update(changedProps); if (this.content !== undefined) { diff --git a/src/components/ha-markdown.ts b/src/components/ha-markdown.ts index c98f5d07a9..0f192bac32 100644 --- a/src/components/ha-markdown.ts +++ b/src/components/ha-markdown.ts @@ -1,12 +1,5 @@ -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import "./ha-markdown-element"; @customElement("ha-markdown") @@ -29,7 +22,7 @@ class HaMarkdown extends LitElement { >`; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { display: block; diff --git a/src/components/ha-menu-button.ts b/src/components/ha-menu-button.ts index b95d012938..9737b2427d 100644 --- a/src/components/ha-menu-button.ts +++ b/src/components/ha-menu-button.ts @@ -1,16 +1,8 @@ import "@material/mwc-icon-button"; import { mdiMenu } from "@mdi/js"; import { UnsubscribeFunc } from "home-assistant-js-websocket"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../common/dom/fire_event"; import { computeDomain } from "../common/entity/compute_domain"; import { subscribeNotifications } from "../data/persistent_notification"; @@ -25,7 +17,7 @@ class HaMenuButton extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _hasNotifications = false; + @state() private _hasNotifications = false; private _alwaysVisible = false; @@ -101,7 +93,6 @@ class HaMenuButton extends LitElement { this.style.display = newNarrow || this._alwaysVisible ? "initial" : "none"; if (!newNarrow) { - this._hasNotifications = false; if (this._unsubNotifications) { this._unsubNotifications(); this._unsubNotifications = undefined; @@ -125,7 +116,7 @@ class HaMenuButton extends LitElement { fireEvent(this, "hass-toggle-menu"); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { position: relative; diff --git a/src/components/ha-network.ts b/src/components/ha-network.ts new file mode 100644 index 0000000000..a4163ae720 --- /dev/null +++ b/src/components/ha-network.ts @@ -0,0 +1,172 @@ +import "@polymer/paper-tooltip/paper-tooltip"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, state, property } from "lit/decorators"; +import { + Adapter, + NetworkConfig, + IPv6ConfiguredAddress, + IPv4ConfiguredAddress, +} from "../data/network"; +import { fireEvent } from "../common/dom/fire_event"; +import { haStyle } from "../resources/styles"; +import { HomeAssistant } from "../types"; +import "./ha-checkbox"; +import type { HaCheckbox } from "./ha-checkbox"; +import "./ha-settings-row"; +import "./ha-icon"; + +const format_addresses = ( + addresses: IPv6ConfiguredAddress[] | IPv4ConfiguredAddress[] +): TemplateResult[] => + addresses.map( + (address) => html`${address.address}/${address.network_prefix}` + ); + +const format_auto_detected_interfaces = ( + adapters: Adapter[] +): Array => + adapters.map((adapter) => + adapter.auto + ? html`${adapter.name} (${format_addresses(adapter.ipv4)} + ${format_addresses(adapter.ipv6)} )` + : "" + ); + +declare global { + interface HASSDomEvents { + "network-config-changed": { configured_adapters: string[] }; + } +} +@customElement("ha-network") +export class HaNetwork extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property({ attribute: false }) public networkConfig?: NetworkConfig; + + @state() private _expanded?: boolean; + + protected render(): TemplateResult { + if (this.networkConfig === undefined) { + return html``; + } + const configured_adapters = this.networkConfig.configured_adapters || []; + return html` + + + + + + Auto Configure + + Detected: + ${format_auto_detected_interfaces(this.networkConfig.adapters)} + + + ${configured_adapters.length || this._expanded + ? this.networkConfig.adapters.map( + (adapter) => + html` + + + + + + Adapter: ${adapter.name} + ${adapter.default + ? html` (Default)` + : ""} + + + ${format_addresses(adapter.ipv4)} + ${format_addresses(adapter.ipv6)} + + ` + ) + : ""} + `; + } + + private _handleAutoConfigureCheckboxClick(ev: Event) { + const checkbox = ev.currentTarget as HaCheckbox; + if (this.networkConfig === undefined) { + return; + } + + let configured_adapters = [...this.networkConfig.configured_adapters]; + + if (checkbox.checked) { + this._expanded = false; + configured_adapters = []; + } else { + this._expanded = true; + for (const adapter of this.networkConfig.adapters) { + if (adapter.default) { + configured_adapters = [adapter.name]; + break; + } + } + } + + fireEvent(this, "network-config-changed", { + configured_adapters: configured_adapters, + }); + } + + private _handleAdapterCheckboxClick(ev: Event) { + const checkbox = ev.currentTarget as HaCheckbox; + const adapter_name = (checkbox as any).name; + if (this.networkConfig === undefined) { + return; + } + + const configured_adapters = [...this.networkConfig.configured_adapters]; + + if (checkbox.checked) { + configured_adapters.push(adapter_name); + } else { + const index = configured_adapters.indexOf(adapter_name, 0); + configured_adapters.splice(index, 1); + } + + fireEvent(this, "network-config-changed", { + configured_adapters: configured_adapters, + }); + } + + static get styles(): CSSResultGroup { + return [ + haStyle, + css` + .error { + color: var(--error-color); + } + + ha-settings-row { + padding: 0; + } + + span[slot="heading"], + span[slot="description"] { + cursor: pointer; + } + `, + ]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-network": HaNetwork; + } +} diff --git a/src/components/ha-picture-upload.ts b/src/components/ha-picture-upload.ts index 0ac990c667..5111b07644 100644 --- a/src/components/ha-picture-upload.ts +++ b/src/components/ha-picture-upload.ts @@ -2,14 +2,8 @@ import "@material/mwc-icon-button/mwc-icon-button"; import { mdiImagePlus } from "@mdi/js"; import "@polymer/iron-input/iron-input"; import "@polymer/paper-input/paper-input-container"; -import { - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../common/dom/fire_event"; import { createImage, generateImageThumbnailUrl } from "../data/image"; import { showAlertDialog } from "../dialogs/generic/show-dialog-box"; @@ -36,7 +30,7 @@ export class HaPictureUpload extends LitElement { @property({ type: Number }) public size = 512; - @internalProperty() private _uploading = false; + @state() private _uploading = false; public render(): TemplateResult { return html` diff --git a/src/components/ha-radio.ts b/src/components/ha-radio.ts index 8796750a74..f1269e5a9f 100644 --- a/src/components/ha-radio.ts +++ b/src/components/ha-radio.ts @@ -1,12 +1,7 @@ -import "@material/mwc-radio"; -import type { Radio } from "@material/mwc-radio"; -import { customElement } from "lit-element"; -import type { Constructor } from "../types"; - -const MwcRadio = customElements.get("mwc-radio") as Constructor; - +import { Radio } from "@material/mwc-radio"; +import { customElement } from "lit/decorators"; @customElement("ha-radio") -export class HaRadio extends MwcRadio { +export class HaRadio extends Radio { public firstUpdated() { super.firstUpdated(); this.style.setProperty("--mdc-theme-secondary", "var(--primary-color)"); diff --git a/src/components/ha-related-items.ts b/src/components/ha-related-items.ts index 3d2cc72c27..4da2605b80 100644 --- a/src/components/ha-related-items.ts +++ b/src/components/ha-related-items.ts @@ -1,15 +1,13 @@ import { HassEntity, UnsubscribeFunc } from "home-assistant-js-websocket"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../common/dom/fire_event"; import { AreaRegistryEntry, @@ -34,13 +32,13 @@ export class HaRelatedItems extends SubscribeMixin(LitElement) { @property() public itemId!: string; - @internalProperty() private _entries?: ConfigEntry[]; + @state() private _entries?: ConfigEntry[]; - @internalProperty() private _devices?: DeviceRegistryEntry[]; + @state() private _devices?: DeviceRegistryEntry[]; - @internalProperty() private _areas?: AreaRegistryEntry[]; + @state() private _areas?: AreaRegistryEntry[]; - @internalProperty() private _related?: RelatedResult; + @state() private _related?: RelatedResult; public hassSubscribe(): UnsubscribeFunc[] { return [ @@ -303,7 +301,7 @@ export class HaRelatedItems extends SubscribeMixin(LitElement) { fireEvent(this, "hass-more-info", { entityId }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` a { color: var(--primary-color); diff --git a/src/components/ha-relative-time.ts b/src/components/ha-relative-time.ts index 98b9228dec..36da1ab190 100644 --- a/src/components/ha-relative-time.ts +++ b/src/components/ha-relative-time.ts @@ -1,14 +1,10 @@ -import { - customElement, - property, - PropertyValues, - UpdatingElement, -} from "lit-element"; +import { PropertyValues, ReactiveElement } from "lit"; +import { customElement, property } from "lit/decorators"; import relativeTime from "../common/datetime/relative_time"; import type { HomeAssistant } from "../types"; @customElement("ha-relative-time") -class HaRelativeTime extends UpdatingElement { +class HaRelativeTime extends ReactiveElement { @property({ attribute: false }) public hass!: HomeAssistant; @property({ attribute: false }) public datetime?: string | Date; @@ -27,6 +23,10 @@ class HaRelativeTime extends UpdatingElement { } } + protected createRenderRoot() { + return this; + } + protected firstUpdated(changedProps: PropertyValues) { super.firstUpdated(changedProps); this._updateRelative(); diff --git a/src/components/ha-selector/ha-selector-action.ts b/src/components/ha-selector/ha-selector-action.ts index 8b2ca84fca..5a6fd5f6c3 100644 --- a/src/components/ha-selector/ha-selector-action.ts +++ b/src/components/ha-selector/ha-selector-action.ts @@ -1,11 +1,5 @@ -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { Action } from "../../data/script"; import { ActionSelector } from "../../data/selector"; import "../../panels/config/automation/action/ha-automation-action"; @@ -31,7 +25,7 @@ export class HaActionSelector extends LitElement { >`; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` ha-automation-action { display: block; diff --git a/src/components/ha-selector/ha-selector-addon.ts b/src/components/ha-selector/ha-selector-addon.ts index 923fb4c29e..30214933f1 100644 --- a/src/components/ha-selector/ha-selector-addon.ts +++ b/src/components/ha-selector/ha-selector-addon.ts @@ -1,4 +1,5 @@ -import { customElement, html, LitElement, property } from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { AddonSelector } from "../../data/selector"; import { HomeAssistant } from "../../types"; import "../ha-addon-picker"; diff --git a/src/components/ha-selector/ha-selector-area.ts b/src/components/ha-selector/ha-selector-area.ts index c3443291d6..5d619bf0e8 100644 --- a/src/components/ha-selector/ha-selector-area.ts +++ b/src/components/ha-selector/ha-selector-area.ts @@ -1,10 +1,5 @@ -import { - customElement, - html, - internalProperty, - LitElement, - property, -} from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { ConfigEntry, getConfigEntries } from "../../data/config_entries"; import { DeviceRegistryEntry } from "../../data/device_registry"; import { EntityRegistryEntry } from "../../data/entity_registry"; @@ -22,7 +17,7 @@ export class HaAreaSelector extends LitElement { @property() public label?: string; - @internalProperty() public _configEntries?: ConfigEntry[]; + @state() public _configEntries?: ConfigEntry[]; @property({ type: Boolean }) public disabled = false; diff --git a/src/components/ha-selector/ha-selector-boolean.ts b/src/components/ha-selector/ha-selector-boolean.ts index 0f56180fe5..154ecc4c9a 100644 --- a/src/components/ha-selector/ha-selector-boolean.ts +++ b/src/components/ha-selector/ha-selector-boolean.ts @@ -1,11 +1,5 @@ -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import { HomeAssistant } from "../../types"; import "../ha-formfield"; @@ -39,7 +33,7 @@ export class HaBooleanSelector extends LitElement { fireEvent(this, "value-changed", { value }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` ha-formfield { width: 100%; diff --git a/src/components/ha-selector/ha-selector-device.ts b/src/components/ha-selector/ha-selector-device.ts index 9446c16a51..bdf945899c 100644 --- a/src/components/ha-selector/ha-selector-device.ts +++ b/src/components/ha-selector/ha-selector-device.ts @@ -1,10 +1,5 @@ -import { - customElement, - html, - internalProperty, - LitElement, - property, -} from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { ConfigEntry, getConfigEntries } from "../../data/config_entries"; import { DeviceRegistryEntry } from "../../data/device_registry"; import { DeviceSelector } from "../../data/selector"; @@ -21,7 +16,7 @@ export class HaDeviceSelector extends LitElement { @property() public label?: string; - @internalProperty() public _configEntries?: ConfigEntry[]; + @state() public _configEntries?: ConfigEntry[]; @property({ type: Boolean }) public disabled = false; diff --git a/src/components/ha-selector/ha-selector-entity.ts b/src/components/ha-selector/ha-selector-entity.ts index 21977aa46c..a2cb042c72 100644 --- a/src/components/ha-selector/ha-selector-entity.ts +++ b/src/components/ha-selector/ha-selector-entity.ts @@ -1,11 +1,6 @@ import { HassEntity, UnsubscribeFunc } from "home-assistant-js-websocket"; -import { - customElement, - html, - internalProperty, - LitElement, - property, -} from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { computeStateDomain } from "../../common/entity/compute_state_domain"; import { subscribeEntityRegistry } from "../../data/entity_registry"; import { EntitySelector } from "../../data/selector"; @@ -19,7 +14,7 @@ export class HaEntitySelector extends SubscribeMixin(LitElement) { @property() public selector!: EntitySelector; - @internalProperty() private _entityPlaformLookup?: Record; + @state() private _entityPlaformLookup?: Record; @property() public value?: any; diff --git a/src/components/ha-selector/ha-selector-number.ts b/src/components/ha-selector/ha-selector-number.ts index 6360ed1568..244f97e2ce 100644 --- a/src/components/ha-selector/ha-selector-number.ts +++ b/src/components/ha-selector/ha-selector-number.ts @@ -1,13 +1,7 @@ import "@polymer/paper-input/paper-input"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +import { css, CSSResultGroup, html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import { fireEvent } from "../../common/dom/fire_event"; import { NumberSelector } from "../../data/selector"; import { HomeAssistant } from "../../types"; @@ -29,12 +23,12 @@ export class HaNumberSelector extends LitElement { protected render() { return html`${this.label} - ${this.selector.number.mode === "slider" + ${this.selector.number.mode !== "box" ? html`; + @state() private _entityPlaformLookup?: Record; - @internalProperty() private _configEntries?: ConfigEntry[]; + @state() private _configEntries?: ConfigEntry[]; @property({ type: Boolean }) public disabled = false; @@ -153,7 +146,7 @@ export class HaTargetSelector extends SubscribeMixin(LitElement) { ); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` ha-target-picker { display: block; diff --git a/src/components/ha-selector/ha-selector-text.ts b/src/components/ha-selector/ha-selector-text.ts index 9d2fbbd248..25cddf58d8 100644 --- a/src/components/ha-selector/ha-selector-text.ts +++ b/src/components/ha-selector/ha-selector-text.ts @@ -1,9 +1,10 @@ -import { customElement, html, LitElement, property } from "lit-element"; -import { fireEvent } from "../../common/dom/fire_event"; -import { HomeAssistant } from "../../types"; -import "@polymer/paper-input/paper-textarea"; import "@polymer/paper-input/paper-input"; +import "@polymer/paper-input/paper-textarea"; +import { html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; +import { fireEvent } from "../../common/dom/fire_event"; import { StringSelector } from "../../data/selector"; +import { HomeAssistant } from "../../types"; @customElement("ha-selector-text") export class HaTextSelector extends LitElement { diff --git a/src/components/ha-selector/ha-selector-time.ts b/src/components/ha-selector/ha-selector-time.ts index 8fb0d530c0..84ab97c8da 100644 --- a/src/components/ha-selector/ha-selector-time.ts +++ b/src/components/ha-selector/ha-selector-time.ts @@ -1,9 +1,13 @@ -import { customElement, html, LitElement, property } from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import memoizeOne from "memoize-one"; +import { useAmPm } from "../../common/datetime/use_am_pm"; import { fireEvent } from "../../common/dom/fire_event"; import { TimeSelector } from "../../data/selector"; +import { FrontendLocaleData } from "../../data/translation"; import { HomeAssistant } from "../../types"; import "../paper-time-input"; + @customElement("ha-selector-time") export class HaTimeSelector extends LitElement { @property() public hass!: HomeAssistant; @@ -16,13 +20,12 @@ export class HaTimeSelector extends LitElement { @property({ type: Boolean }) public disabled = false; - private _useAmPm = memoizeOne((language: string) => { - const test = new Date().toLocaleString(language); - return test.includes("AM") || test.includes("PM"); - }); + private _useAmPmMem = memoizeOne((locale: FrontendLocaleData): boolean => + useAmPm(locale) + ); protected render() { - const useAMPM = this._useAmPm(this.hass.locale.language); + const useAMPM = this._useAmPmMem(this.hass.locale); const parts = this.value?.split(":") || []; const hours = parts[0]; @@ -47,7 +50,7 @@ export class HaTimeSelector extends LitElement { private _timeChanged(ev) { let value = ev.target.value; - const useAMPM = this._useAmPm(this.hass.locale.language); + const useAMPM = this._useAmPmMem(this.hass.locale); let hours = Number(ev.target.hour || 0); if (value && useAMPM) { if (ev.target.amPm === "PM") { diff --git a/src/components/ha-selector/ha-selector.ts b/src/components/ha-selector/ha-selector.ts index 9982e33831..d426ec0b49 100644 --- a/src/components/ha-selector/ha-selector.ts +++ b/src/components/ha-selector/ha-selector.ts @@ -1,4 +1,5 @@ -import { customElement, html, LitElement, property } from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { dynamicElement } from "../../common/dom/dynamic-element-directive"; import { Selector } from "../../data/selector"; import { HomeAssistant } from "../../types"; @@ -9,11 +10,11 @@ import "./ha-selector-boolean"; import "./ha-selector-device"; import "./ha-selector-entity"; import "./ha-selector-number"; -import "./ha-selector-target"; -import "./ha-selector-time"; import "./ha-selector-object"; -import "./ha-selector-text"; import "./ha-selector-select"; +import "./ha-selector-target"; +import "./ha-selector-text"; +import "./ha-selector-time"; @customElement("ha-selector") export class HaSelector extends LitElement { diff --git a/src/components/ha-service-control.ts b/src/components/ha-service-control.ts index 48fb03011e..a93b7aba26 100644 --- a/src/components/ha-service-control.ts +++ b/src/components/ha-service-control.ts @@ -1,21 +1,15 @@ import { mdiHelpCircle } from "@mdi/js"; -import { HassService, HassServiceTarget } from "home-assistant-js-websocket"; import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - PropertyValues, - query, -} from "lit-element"; + HassService, + HassServices, + HassServiceTarget, +} from "home-assistant-js-websocket"; +import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit"; +import { customElement, property, state, query } from "lit/decorators"; import memoizeOne from "memoize-one"; import { fireEvent } from "../common/dom/fire_event"; import { computeDomain } from "../common/entity/compute_domain"; import { computeObjectId } from "../common/entity/compute_object_id"; -import { ENTITY_COMPONENT_DOMAINS } from "../data/entity"; import { Selector } from "../data/selector"; import { PolymerChangedEvent } from "../polymer-types"; import { HomeAssistant } from "../types"; @@ -51,13 +45,13 @@ export class HaServiceControl extends LitElement { data?: Record; }; - @internalProperty() private _value!: this["value"]; + @state() private _value!: this["value"]; @property({ reflect: true, type: Boolean }) public narrow!: boolean; @property({ type: Boolean }) public showAdvanced?: boolean; - @internalProperty() private _checkedKeys = new Set(); + @state() private _checkedKeys = new Set(); @query("ha-yaml-editor") private _yamlEditor?: HaYamlEditor; @@ -73,7 +67,10 @@ export class HaServiceControl extends LitElement { this._checkedKeys = new Set(); } - const serviceData = this._getServiceInfo(this.value?.service); + const serviceData = this._getServiceInfo( + this.value?.service, + this.hass.services + ); if ( serviceData && @@ -117,45 +114,45 @@ export class HaServiceControl extends LitElement { } } - private _domainFilter = memoizeOne((service: string) => { - const domain = computeDomain(service); - return ENTITY_COMPONENT_DOMAINS.includes(domain) ? [domain] : null; - }); + private _getServiceInfo = memoizeOne( + ( + service?: string, + serviceDomains?: HassServices + ): ExtHassService | undefined => { + if (!service || !serviceDomains) { + return undefined; + } + const domain = computeDomain(service); + const serviceName = computeObjectId(service); + if (!(domain in serviceDomains)) { + return undefined; + } + if (!(serviceName in serviceDomains[domain])) { + return undefined; + } - private _getServiceInfo = memoizeOne((service?: string): - | ExtHassService - | undefined => { - if (!service) { - return undefined; + const fields = Object.entries( + serviceDomains[domain][serviceName].fields + ).map(([key, value]) => ({ + key, + ...value, + selector: value.selector as Selector | undefined, + })); + return { + ...serviceDomains[domain][serviceName], + fields, + hasSelector: fields.length + ? fields.filter((field) => field.selector).map((field) => field.key) + : [], + }; } - const domain = computeDomain(service); - const serviceName = computeObjectId(service); - const serviceDomains = this.hass.services; - if (!(domain in serviceDomains)) { - return undefined; - } - if (!(serviceName in serviceDomains[domain])) { - return undefined; - } - - const fields = Object.entries( - serviceDomains[domain][serviceName].fields - ).map(([key, value]) => ({ - key, - ...value, - selector: value.selector as Selector | undefined, - })); - return { - ...serviceDomains[domain][serviceName], - fields, - hasSelector: fields.length - ? fields.filter((field) => field.selector).map((field) => field.key) - : [], - }; - }); + ); protected render() { - const serviceData = this._getServiceInfo(this._value?.service); + const serviceData = this._getServiceInfo( + this._value?.service, + this.hass.services + ); const shouldRenderServiceDataYaml = (serviceData?.fields.length && !serviceData.hasSelector.length) || @@ -219,11 +216,7 @@ export class HaServiceControl extends LitElement { .hass=${this.hass} .selector=${serviceData.target ? { target: serviceData.target } - : { - target: { - entity: { domain: computeDomain(this._value!.service) }, - }, - }} + : { target: {} }} @value-changed=${this._targetChanged} .value=${this._value?.target} >` @@ -395,7 +387,7 @@ export class HaServiceControl extends LitElement { }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` ha-settings-row { padding: var(--service-control-padding, 0 16px); diff --git a/src/components/ha-service-picker.ts b/src/components/ha-service-picker.ts index 17bff6027f..10755ca50e 100644 --- a/src/components/ha-service-picker.ts +++ b/src/components/ha-service-picker.ts @@ -1,44 +1,34 @@ -import { html, internalProperty, LitElement, property } from "lit-element"; +import { html, LitElement } from "lit"; +import { property, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import { fireEvent } from "../common/dom/fire_event"; import { LocalizeFunc } from "../common/translations/localize"; import { domainToName } from "../data/integration"; import { HomeAssistant } from "../types"; import "./ha-combo-box"; +import { ComboBoxLitRenderer } from "lit-vaadin-helpers"; -const rowRenderer = ( - root: HTMLElement, - _owner, - model: { item: { service: string; name: string } } -) => { - if (!root.firstElementChild) { - root.innerHTML = ` - - - -
[[item.name]]
-
[[item.service]]
-
-
- `; - } - - root.querySelector(".name")!.textContent = model.item.name; - root.querySelector("[secondary]")!.textContent = - model.item.name === model.item.service ? "" : model.item.service; -}; +const rowRenderer: ComboBoxLitRenderer<{ service: string; name: string }> = ( + item +) => html` + + + ${item.name} + ${item.name === item.service ? "" : item.service} + + `; class HaServicePicker extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @property() public value?: string; - @internalProperty() private _filter?: string; + @state() private _filter?: string; protected render() { return html` diff --git a/src/components/ha-settings-row.ts b/src/components/ha-settings-row.ts index 12f37bfe79..a28738b265 100644 --- a/src/components/ha-settings-row.ts +++ b/src/components/ha-settings-row.ts @@ -1,13 +1,6 @@ import "@polymer/paper-item/paper-item-body"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; @customElement("ha-settings-row") export class HaSettingsRow extends LitElement { @@ -32,7 +25,7 @@ export class HaSettingsRow extends LitElement { `; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { display: flex; diff --git a/src/components/ha-sidebar.ts b/src/components/ha-sidebar.ts index 83502db730..0a56b4df48 100644 --- a/src/components/ha-sidebar.ts +++ b/src/components/ha-sidebar.ts @@ -16,19 +16,18 @@ import "@polymer/paper-listbox/paper-listbox"; import { css, CSSResult, - customElement, - eventOptions, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; -import { guard } from "lit-html/directives/guard"; +} from "lit"; +import { customElement, eventOptions, property, state } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; +import { guard } from "lit/directives/guard"; import memoizeOne from "memoize-one"; import { LocalStorage } from "../common/decorators/local-storage"; import { fireEvent } from "../common/dom/fire_event"; +import { toggleAttribute } from "../common/dom/toggle_attribute"; import { computeDomain } from "../common/entity/compute_domain"; import { compare } from "../common/string/compare"; import { computeRTL } from "../common/util/compute_rtl"; @@ -167,19 +166,13 @@ class HaSidebar extends LitElement { @property({ type: Boolean }) public alwaysExpand = false; - @property({ type: Boolean, reflect: true }) public expanded = false; - @property({ type: Boolean }) public editMode = false; - @internalProperty() private _externalConfig?: ExternalConfig; + @state() private _externalConfig?: ExternalConfig; - @internalProperty() private _notifications?: PersistentNotification[]; + @state() private _notifications?: PersistentNotification[]; - // property used only in css - // @ts-ignore - @property({ type: Boolean, reflect: true }) public rtl = false; - - @internalProperty() private _renderEmptySortable = false; + @state() private _renderEmptySortable = false; private _mouseLeaveTimeout?: number; @@ -267,7 +260,7 @@ class HaSidebar extends LitElement { protected updated(changedProps) { super.updated(changedProps); if (changedProps.has("alwaysExpand")) { - this.expanded = this.alwaysExpand; + toggleAttribute(this, "expanded", this.alwaysExpand); } if (changedProps.has("editMode")) { if (this.editMode) { @@ -282,7 +275,7 @@ class HaSidebar extends LitElement { const oldHass = changedProps.get("hass") as HomeAssistant | undefined; if (!oldHass || oldHass.locale !== this.hass.locale) { - this.rtl = computeRTL(this.hass); + toggleAttribute(this, "rtl", computeRTL(this.hass)); } if (!SUPPORT_SCROLL_IF_NEEDED) { @@ -430,7 +423,7 @@ class HaSidebar extends LitElement { @click=${this._handleShowNotificationDrawer} > - ${!this.expanded && notificationCount > 0 + ${!this.alwaysExpand && notificationCount > 0 ? html` ${notificationCount} @@ -440,7 +433,7 @@ class HaSidebar extends LitElement { ${this.hass.localize("ui.notification_drawer.title")} - ${this.expanded && notificationCount > 0 + ${this.alwaysExpand && notificationCount > 0 ? html` ${notificationCount} ` : ""} @@ -524,7 +517,7 @@ class HaSidebar extends LitElement { ]); const style = document.createElement("style"); - style.innerHTML = sortStylesImport.sortableStyles.cssText; + style.innerHTML = (sortStylesImport.sortableStyles as CSSResult).cssText; this.shadowRoot!.appendChild(style); Sortable = sortableImport.Sortable; @@ -595,7 +588,7 @@ class HaSidebar extends LitElement { // for 100ms so that we ignore it when pressing down arrow scrolls the // sidebar causing the mouse to hover a new icon if ( - this.expanded || + this.alwaysExpand || new Date().getTime() < this._recentKeydownActiveUntil ) { return; @@ -617,7 +610,7 @@ class HaSidebar extends LitElement { } private _listboxFocusIn(ev) { - if (this.expanded || ev.target.nodeName !== "A") { + if (this.alwaysExpand || ev.target.nodeName !== "A") { return; } this._showTooltip(ev.target.querySelector("paper-icon-item")); @@ -741,7 +734,7 @@ class HaSidebar extends LitElement { `; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyleScrollbar, css` diff --git a/src/components/ha-svg-icon.ts b/src/components/ha-svg-icon.ts index ecc95d0d44..b8f6a3b5c7 100644 --- a/src/components/ha-svg-icon.ts +++ b/src/components/ha-svg-icon.ts @@ -1,12 +1,5 @@ -import { - css, - CSSResult, - customElement, - LitElement, - property, - svg, - SVGTemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, LitElement, svg, SVGTemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; @customElement("ha-svg-icon") export class HaSvgIcon extends LitElement { @@ -26,7 +19,7 @@ export class HaSvgIcon extends LitElement { `; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { display: var(--ha-icon-display, inline-flex); diff --git a/src/components/ha-switch.ts b/src/components/ha-switch.ts index ed5c123a1d..2ab7106190 100644 --- a/src/components/ha-switch.ts +++ b/src/components/ha-switch.ts @@ -1,14 +1,10 @@ -import "@material/mwc-switch"; -import type { Switch } from "@material/mwc-switch"; -import { style } from "@material/mwc-switch/mwc-switch-css"; -import { css, CSSResult, customElement, property } from "lit-element"; +import { Switch } from "@material/mwc-switch"; +import { css, CSSResultGroup } from "lit"; +import { customElement, property } from "lit/decorators"; import { forwardHaptic } from "../data/haptics"; -import { Constructor } from "../types"; - -const MwcSwitch = customElements.get("mwc-switch") as Constructor; - @customElement("ha-switch") -export class HaSwitch extends MwcSwitch { +// @ts-expect-error +export class HaSwitch extends Switch { // Generate a haptic vibration. // Only set to true if the new value of the switch is applied right away when toggling. // Do not add haptic when a user is required to press save. @@ -27,9 +23,9 @@ export class HaSwitch extends MwcSwitch { }); } - protected static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ - style, + Switch.styles, css` .mdc-switch.mdc-switch--checked .mdc-switch__thumb { background-color: var(--switch-checked-button-color); diff --git a/src/components/ha-tab.ts b/src/components/ha-tab.ts index c887c6c440..fe391171ba 100644 --- a/src/components/ha-tab.ts +++ b/src/components/ha-tab.ts @@ -1,19 +1,15 @@ import type { Ripple } from "@material/mwc-ripple"; import "@material/mwc-ripple/mwc-ripple"; import { RippleHandlers } from "@material/mwc-ripple/ripple-handlers"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { - css, - CSSResult, customElement, eventOptions, - html, - internalProperty, - LitElement, property, queryAsync, - TemplateResult, -} from "lit-element"; -import { ifDefined } from "lit-html/directives/if-defined"; + state, +} from "lit/decorators"; +import { ifDefined } from "lit/directives/if-defined"; import "./ha-icon"; import "./ha-svg-icon"; @@ -27,7 +23,7 @@ export class HaTab extends LitElement { @queryAsync("mwc-ripple") private _ripple!: Promise; - @internalProperty() private _shouldRenderRipple = false; + @state() private _shouldRenderRipple = false; protected render(): TemplateResult { return html` @@ -92,7 +88,7 @@ export class HaTab extends LitElement { this._rippleHandlers.endFocus(); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` div { padding: 0 32px; @@ -121,9 +117,10 @@ export class HaTab extends LitElement { } :host([narrow]) { - padding: 0 16px; - width: 20%; min-width: 0; + display: flex; + justify-content: center; + overflow: hidden; } `; } diff --git a/src/components/ha-tabs.ts b/src/components/ha-tabs.ts index 491d36462f..035663190f 100644 --- a/src/components/ha-tabs.ts +++ b/src/components/ha-tabs.ts @@ -2,7 +2,7 @@ import type { PaperIconButtonElement } from "@polymer/paper-icon-button/paper-ic import type { PaperTabElement } from "@polymer/paper-tabs/paper-tab"; import "@polymer/paper-tabs/paper-tabs"; import type { PaperTabsElement } from "@polymer/paper-tabs/paper-tabs"; -import { customElement } from "lit-element"; +import { customElement } from "lit/decorators"; import { Constructor } from "../types"; const PaperTabs = customElements.get( diff --git a/src/components/ha-target-picker.ts b/src/components/ha-target-picker.ts index d082962d9b..3e2e40260f 100644 --- a/src/components/ha-target-picker.ts +++ b/src/components/ha-target-picker.ts @@ -14,18 +14,9 @@ import { HassServiceTarget, UnsubscribeFunc, } from "home-assistant-js-websocket"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - query, - unsafeCSS, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +import { css, CSSResultGroup, html, LitElement, unsafeCSS } from "lit"; +import { customElement, property, state, query } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import { fireEvent } from "../common/dom/fire_event"; import { ensureArray } from "../common/ensure-array"; import { computeDomain } from "../common/entity/compute_domain"; @@ -86,15 +77,15 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) { @property({ type: Boolean, reflect: true }) public disabled = false; - @internalProperty() private _areas?: { [areaId: string]: AreaRegistryEntry }; + @state() private _areas?: { [areaId: string]: AreaRegistryEntry }; - @internalProperty() private _devices?: { + @state() private _devices?: { [deviceId: string]: DeviceRegistryEntry; }; - @internalProperty() private _entities?: EntityRegistryEntry[]; + @state() private _entities?: EntityRegistryEntry[]; - @internalProperty() private _addMode?: "area_id" | "entity_id" | "device_id"; + @state() private _addMode?: "area_id" | "entity_id" | "device_id"; @query("#input") private _inputElement?; @@ -534,7 +525,7 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) { return true; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` ${unsafeCSS(chipStyles)} .mdc-chip { diff --git a/src/components/ha-time-input.ts b/src/components/ha-time-input.ts index e72e1a09d9..382ea4d569 100644 --- a/src/components/ha-time-input.ts +++ b/src/components/ha-time-input.ts @@ -1,11 +1,5 @@ -import { - customElement, - html, - LitElement, - property, - query, - TemplateResult, -} from "lit-element"; +import { html, LitElement, TemplateResult } from "lit"; +import { customElement, property, query } from "lit/decorators"; import { fireEvent } from "../common/dom/fire_event"; import "./paper-time-input"; diff --git a/src/components/ha-yaml-editor.ts b/src/components/ha-yaml-editor.ts index a702be77ac..8d79034c3e 100644 --- a/src/components/ha-yaml-editor.ts +++ b/src/components/ha-yaml-editor.ts @@ -1,12 +1,6 @@ -import { safeDump, safeLoad } from "js-yaml"; -import { - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { dump, load } from "js-yaml"; +import { html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../common/dom/fire_event"; import "./ha-code-editor"; @@ -32,11 +26,11 @@ export class HaYamlEditor extends LitElement { @property() public label?: string; - @internalProperty() private _yaml = ""; + @state() private _yaml = ""; public setValue(value): void { try { - this._yaml = value && !isEmpty(value) ? safeDump(value) : ""; + this._yaml = value && !isEmpty(value) ? dump(value) : ""; } catch (err) { // eslint-disable-next-line no-console console.error(err, value); @@ -73,7 +67,7 @@ export class HaYamlEditor extends LitElement { if (this._yaml) { try { - parsed = safeLoad(this._yaml); + parsed = load(this._yaml); } catch (err) { // Invalid YAML isValid = false; diff --git a/src/components/map/ha-location-editor.ts b/src/components/map/ha-location-editor.ts index 8ba1ec3c2b..4ee130d52d 100644 --- a/src/components/map/ha-location-editor.ts +++ b/src/components/map/ha-location-editor.ts @@ -10,14 +10,13 @@ import { } from "leaflet"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import { LeafletModuleType, @@ -109,7 +108,7 @@ class LocationEditor extends LitElement { if (changedProps.has("hass")) { const oldHass = changedProps.get("hass") as HomeAssistant | undefined; - if (!oldHass || oldHass.themes?.darkMode === this.hass.themes?.darkMode) { + if (!oldHass || oldHass.themes.darkMode === this.hass.themes.darkMode) { return; } if (!this._leafletMap || !this._tileLayer) { @@ -119,7 +118,7 @@ class LocationEditor extends LitElement { this.Leaflet, this._leafletMap, this._tileLayer, - this.hass.themes?.darkMode + this.hass.themes.darkMode ); } } @@ -131,7 +130,7 @@ class LocationEditor extends LitElement { private async _initMap(): Promise { [this._leafletMap, this.Leaflet, this._tileLayer] = await setupLeafletMap( this._mapEl, - this.darkMode ?? this.hass.themes?.darkMode, + this.darkMode ?? this.hass.themes.darkMode, Boolean(this.radius) ); this._leafletMap.addEventListener( @@ -271,7 +270,7 @@ class LocationEditor extends LitElement { (this._locationMarker as Circle).setStyle({ color: this.radiusColor }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { display: block; diff --git a/src/components/map/ha-locations-editor.ts b/src/components/map/ha-locations-editor.ts index 184813c32e..b0b8008906 100644 --- a/src/components/map/ha-locations-editor.ts +++ b/src/components/map/ha-locations-editor.ts @@ -10,14 +10,13 @@ import { } from "leaflet"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import { LeafletModuleType, @@ -286,12 +285,11 @@ export class HaLocationsEditor extends LitElement { [location.latitude, location.longitude], options ) - .addEventListener( - "dragend", - // @ts-ignore - (ev: DragEndEvent) => this._updateLocation(ev) + .addEventListener("dragend", (ev: DragEndEvent) => + this._updateLocation(ev) ) .addEventListener( + // @ts-ignore "click", // @ts-ignore (ev: MouseEvent) => this._markerClicked(ev) @@ -304,7 +302,7 @@ export class HaLocationsEditor extends LitElement { }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { display: block; diff --git a/src/components/map/ha-map.ts b/src/components/map/ha-map.ts index 98113ab100..fd29d2a268 100644 --- a/src/components/map/ha-map.ts +++ b/src/components/map/ha-map.ts @@ -1,14 +1,13 @@ import { Circle, Layer, Map, Marker, TileLayer } from "leaflet"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property } from "lit/decorators"; import { LeafletModuleType, replaceTileLayer, @@ -326,7 +325,7 @@ class HaMap extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { display: block; diff --git a/src/components/media-player/dialog-media-player-browse.ts b/src/components/media-player/dialog-media-player-browse.ts index 3ef4f00c04..6e5a54d973 100644 --- a/src/components/media-player/dialog-media-player-browse.ts +++ b/src/components/media-player/dialog-media-player-browse.ts @@ -1,13 +1,5 @@ -import { - css, - CSSResultArray, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent, HASSDomEvent } from "../../common/dom/fire_event"; import type { MediaPickedEvent, @@ -23,15 +15,15 @@ import { MediaPlayerBrowseDialogParams } from "./show-media-browser-dialog"; class DialogMediaPlayerBrowse extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _entityId!: string; + @state() private _entityId!: string; - @internalProperty() private _mediaContentId?: string; + @state() private _mediaContentId?: string; - @internalProperty() private _mediaContentType?: string; + @state() private _mediaContentType?: string; - @internalProperty() private _action?: MediaPlayerBrowseAction; + @state() private _action?: MediaPlayerBrowseAction; - @internalProperty() private _params?: MediaPlayerBrowseDialogParams; + @state() private _params?: MediaPlayerBrowseDialogParams; public showDialog(params: MediaPlayerBrowseDialogParams): void { this._params = params; @@ -81,7 +73,7 @@ class DialogMediaPlayerBrowse extends LitElement { } } - static get styles(): CSSResultArray { + static get styles(): CSSResultGroup { return [ haStyleDialog, css` diff --git a/src/components/media-player/ha-media-player-browse.ts b/src/components/media-player/ha-media-player-browse.ts index 88ccff39d1..db5b8af6b3 100644 --- a/src/components/media-player/ha-media-player-browse.ts +++ b/src/components/media-player/ha-media-player-browse.ts @@ -7,20 +7,22 @@ import "@polymer/paper-listbox/paper-listbox"; import "@polymer/paper-tooltip/paper-tooltip"; import { css, - CSSResultArray, - customElement, - eventOptions, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, - query, TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; -import { ifDefined } from "lit-html/directives/if-defined"; -import { styleMap } from "lit-html/directives/style-map"; +} from "lit"; +import { + customElement, + property, + state, + query, + eventOptions, +} from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; +import { ifDefined } from "lit/directives/if-defined"; +import { styleMap } from "lit/directives/style-map"; import { fireEvent } from "../../common/dom/fire_event"; import { computeRTLDirection } from "../../common/util/compute_rtl"; import { debounce } from "../../common/util/debounce"; @@ -72,11 +74,11 @@ export class HaMediaPlayerBrowse extends LitElement { @property({ type: Boolean, attribute: "scroll", reflect: true }) private _scrolled = false; - @internalProperty() private _loading = false; + @state() private _loading = false; - @internalProperty() private _error?: { message: string; code: string }; + @state() private _error?: { message: string; code: string }; - @internalProperty() private _mediaPlayerItems: MediaPlayerItem[] = []; + @state() private _mediaPlayerItems: MediaPlayerItem[] = []; @query(".header") private _header?: HTMLDivElement; @@ -610,7 +612,7 @@ export class HaMediaPlayerBrowse extends LitElement { return html`${err.message}`; } - static get styles(): CSSResultArray { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/components/state-history-chart-timeline.js b/src/components/state-history-chart-timeline.js index 12fe3ca416..816425aa25 100644 --- a/src/components/state-history-chart-timeline.js +++ b/src/components/state-history-chart-timeline.js @@ -194,7 +194,10 @@ class StateHistoryChartTimeline extends LocalizeMixin(PolymerElement) { invertOnOff, ]); } - datasets.push({ data: dataRow, entity_id: stateInfo.entity_id }); + datasets.push({ + data: dataRow, + entity_id: stateInfo.entity_id, + }); labels.push(entityDisplay); }); @@ -234,6 +237,9 @@ class StateHistoryChartTimeline extends LocalizeMixin(PolymerElement) { fontStyle: "bold", }, }, + categoryPercentage: undefined, + barPercentage: undefined, + time: { format: undefined }, }, ], yAxes: [ @@ -242,10 +248,17 @@ class StateHistoryChartTimeline extends LocalizeMixin(PolymerElement) { yaxe.maxWidth = yaxe.chart.width * 0.18; }, position: this._computeRTL ? "right" : "left", + categoryPercentage: undefined, + barPercentage: undefined, + time: { format: undefined }, }, ], }, }, + datasets: { + categoryPercentage: 0.8, + barPercentage: 0.9, + }, data: { labels: labels, datasets: datasets, diff --git a/src/components/state-history-charts.ts b/src/components/state-history-charts.ts index 49ac8049c5..9be40220da 100644 --- a/src/components/state-history-charts.ts +++ b/src/components/state-history-charts.ts @@ -1,19 +1,18 @@ -import "./ha-circular-progress"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property } from "lit/decorators"; +import { isComponentLoaded } from "../common/config/is_component_loaded"; +import { HistoryResult } from "../data/history"; +import type { HomeAssistant } from "../types"; +import "./ha-circular-progress"; import "./state-history-chart-line"; import "./state-history-chart-timeline"; -import { isComponentLoaded } from "../common/config/is_component_loaded"; -import type { HomeAssistant } from "../types"; -import { HistoryResult } from "../data/history"; @customElement("state-history-charts") class StateHistoryCharts extends LitElement { @@ -98,7 +97,7 @@ class StateHistoryCharts extends LitElement { return !this.isLoadingData && historyDataEmpty; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { display: block; diff --git a/src/components/trace/ha-timeline.ts b/src/components/trace/ha-timeline.ts index d9572c4a67..3ca99b56d2 100644 --- a/src/components/trace/ha-timeline.ts +++ b/src/components/trace/ha-timeline.ts @@ -1,13 +1,6 @@ import { mdiCircleOutline } from "@mdi/js"; -import { - LitElement, - customElement, - html, - css, - property, - TemplateResult, - internalProperty, -} from "lit-element"; +import { css, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { buttonLinkStyle } from "../../resources/styles"; import "../ha-svg-icon"; @@ -23,7 +16,7 @@ export class HaTimeline extends LitElement { @property({ attribute: false }) public moreItems?: TemplateResult[]; - @internalProperty() private _showMore = false; + @state() private _showMore = false; protected render() { return html` diff --git a/src/components/trace/hat-graph-node.ts b/src/components/trace/hat-graph-node.ts index ae0b59aa87..5b0ba7ca64 100644 --- a/src/components/trace/hat-graph-node.ts +++ b/src/components/trace/hat-graph-node.ts @@ -1,5 +1,5 @@ -import { css, customElement, LitElement, property, svg } from "lit-element"; - +import { css, LitElement, svg } from "lit"; +import { customElement, property } from "lit/decorators"; import { NODE_SIZE, SPACING } from "./hat-graph"; @customElement("hat-graph-node") diff --git a/src/components/trace/hat-graph-spacer.ts b/src/components/trace/hat-graph-spacer.ts index 22c6770a1b..e30c05bd5a 100644 --- a/src/components/trace/hat-graph-spacer.ts +++ b/src/components/trace/hat-graph-spacer.ts @@ -1,5 +1,5 @@ -import { css, customElement, LitElement, property, svg } from "lit-element"; - +import { css, LitElement, svg } from "lit"; +import { customElement, property } from "lit/decorators"; import { NODE_SIZE, SPACING } from "./hat-graph"; @customElement("hat-graph-spacer") diff --git a/src/components/trace/hat-graph.ts b/src/components/trace/hat-graph.ts index c7e06ae663..93ecdf015e 100644 --- a/src/components/trace/hat-graph.ts +++ b/src/components/trace/hat-graph.ts @@ -1,12 +1,6 @@ -import { - css, - customElement, - html, - LitElement, - property, - svg, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +import { css, html, LitElement, svg } from "lit"; +import { customElement, property } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; export const BRANCH_HEIGHT = 20; export const SPACING = 10; diff --git a/src/components/trace/hat-logbook-note.ts b/src/components/trace/hat-logbook-note.ts index 5d5b1f9df7..8df890bbf5 100644 --- a/src/components/trace/hat-logbook-note.ts +++ b/src/components/trace/hat-logbook-note.ts @@ -1,4 +1,5 @@ -import { LitElement, css, html, customElement } from "lit-element"; +import { css, html, LitElement } from "lit"; +import { customElement } from "lit/decorators"; @customElement("hat-logbook-note") class HatLogbookNote extends LitElement { diff --git a/src/components/trace/hat-script-graph.ts b/src/components/trace/hat-script-graph.ts index cecb0feb28..aff37a1032 100644 --- a/src/components/trace/hat-script-graph.ts +++ b/src/components/trace/hat-script-graph.ts @@ -1,19 +1,4 @@ -import { - html, - LitElement, - property, - customElement, - PropertyValues, - css, -} from "lit-element"; import "@material/mwc-icon-button/mwc-icon-button"; -import { fireEvent } from "../../common/dom/fire_event"; -import "../ha-svg-icon"; -import { - AutomationTraceExtended, - ChooseActionTraceStep, - ConditionTraceStep, -} from "../../data/trace"; import { mdiAbTesting, mdiArrowUp, @@ -32,9 +17,11 @@ import { mdiTimerOutline, mdiTrafficLight, } from "@mdi/js"; -import "./hat-graph-node"; -import { classMap } from "lit-html/directives/class-map"; -import { NODE_SIZE, SPACING, NodeInfo } from "./hat-graph"; +import { css, html, LitElement, PropertyValues } from "lit"; +import { customElement, property } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; +import { fireEvent } from "../../common/dom/fire_event"; +import { ensureArray } from "../../common/ensure-array"; import { Condition, Trigger } from "../../data/automation"; import { Action, @@ -48,7 +35,14 @@ import { WaitAction, WaitForTriggerAction, } from "../../data/script"; -import { ensureArray } from "../../common/ensure-array"; +import { + AutomationTraceExtended, + ChooseActionTraceStep, + ConditionTraceStep, +} from "../../data/trace"; +import "../ha-svg-icon"; +import { NodeInfo, NODE_SIZE, SPACING } from "./hat-graph"; +import "./hat-graph-node"; import "./hat-graph-spacer"; declare global { @@ -63,6 +57,8 @@ class HatScriptGraph extends LitElement { @property({ attribute: false }) public selected; + @property() renderedNodes: Record = {}; + @property() trackedNodes: Record = {}; private selectNode(config, path) { @@ -74,8 +70,9 @@ class HatScriptGraph extends LitElement { private render_trigger(config: Trigger, i: number) { const path = `trigger/${i}`; const tracked = this.trace && path in this.trace.trace; + this.renderedNodes[path] = { config, path }; if (tracked) { - this.trackedNodes[path] = { config, path }; + this.trackedNodes[path] = this.renderedNodes[path]; } return html` @@ -411,8 +412,9 @@ class HatScriptGraph extends LitElement { const type = Object.keys(NODE_TYPES).find((key) => key in node) || "other"; const nodeEl = NODE_TYPES[type].bind(this)(node, path); + this.renderedNodes[path] = { config: node, path }; if (this.trace && path in this.trace.trace) { - this.trackedNodes[path] = { config: node, path }; + this.trackedNodes[path] = this.renderedNodes[path]; } return nodeEl; } @@ -483,6 +485,7 @@ class HatScriptGraph extends LitElement { protected update(changedProps: PropertyValues) { if (changedProps.has("trace")) { + this.renderedNodes = {}; this.trackedNodes = {}; } super.update(changedProps); @@ -493,7 +496,7 @@ class HatScriptGraph extends LitElement { // Select first node if new trace loaded but no selection given. if (changedProps.has("trace")) { - const tracked = this.getTrackedNodes(); + const tracked = this.trackedNodes; const paths = Object.keys(tracked); // If trace changed and we have no or an invalid selection, select first option. @@ -509,42 +512,44 @@ class HatScriptGraph extends LitElement { if (this.trace) { const sortKeys = Object.keys(this.trace.trace); - const keys = Object.keys(this.trackedNodes).sort( + const keys = Object.keys(this.renderedNodes).sort( (a, b) => sortKeys.indexOf(a) - sortKeys.indexOf(b) ); - const sortedTrackedNodes = keys.reduce((obj, key) => { - obj[key] = this.trackedNodes[key]; - return obj; - }, {}); + const sortedTrackedNodes = {}; + const sortedRenderedNodes = {}; + for (const key of keys) { + sortedRenderedNodes[key] = this.renderedNodes[key]; + if (key in this.trackedNodes) { + sortedTrackedNodes[key] = this.trackedNodes[key]; + } + } + this.renderedNodes = sortedRenderedNodes; this.trackedNodes = sortedTrackedNodes; } } } - public getTrackedNodes() { - return this.trackedNodes; - } - public previousTrackedNode() { - const tracked = this.getTrackedNodes(); - const nodes = Object.keys(tracked); - - for (let i = nodes.indexOf(this.selected) - 1; i >= 0; i--) { - if (tracked[nodes[i]]) { - fireEvent(this, "graph-node-selected", tracked[nodes[i]]); - break; - } + const nodes = Object.keys(this.trackedNodes); + const prevIndex = nodes.indexOf(this.selected) - 1; + if (prevIndex >= 0) { + fireEvent( + this, + "graph-node-selected", + this.trackedNodes[nodes[prevIndex]] + ); } } public nextTrackedNode() { - const tracked = this.getTrackedNodes(); - const nodes = Object.keys(tracked); - for (let i = nodes.indexOf(this.selected) + 1; i < nodes.length; i++) { - if (tracked[nodes[i]]) { - fireEvent(this, "graph-node-selected", tracked[nodes[i]]); - break; - } + const nodes = Object.keys(this.trackedNodes); + const nextIndex = nodes.indexOf(this.selected) + 1; + if (nextIndex < nodes.length) { + fireEvent( + this, + "graph-node-selected", + this.trackedNodes[nodes[nextIndex]] + ); } } diff --git a/src/components/trace/hat-trace-timeline.ts b/src/components/trace/hat-trace-timeline.ts index 49898be86f..c56332f30b 100644 --- a/src/components/trace/hat-trace-timeline.ts +++ b/src/components/trace/hat-trace-timeline.ts @@ -1,24 +1,3 @@ -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - PropertyValues, - TemplateResult, -} from "lit-element"; -import { formatDateTimeWithSeconds } from "../../common/datetime/format_date_time"; -import { - AutomationTraceExtended, - ChooseActionTraceStep, - getDataFromPath, - TriggerTraceStep, - isTriggerPath, -} from "../../data/trace"; -import { HomeAssistant } from "../../types"; -import "./ha-timeline"; -import type { HaTimeline } from "./ha-timeline"; import { mdiAlertCircle, mdiCircle, @@ -27,16 +6,36 @@ import { mdiProgressWrench, mdiRecordCircleOutline, } from "@mdi/js"; +import { + css, + CSSResultGroup, + html, + LitElement, + PropertyValues, + TemplateResult, +} from "lit"; +import { customElement, property } from "lit/decorators"; +import { ifDefined } from "lit/directives/if-defined"; +import { formatDateTimeWithSeconds } from "../../common/datetime/format_date_time"; +import relativeTime from "../../common/datetime/relative_time"; +import { fireEvent } from "../../common/dom/fire_event"; import { LogbookEntry } from "../../data/logbook"; import { ChooseAction, ChooseActionChoice, getActionType, } from "../../data/script"; -import relativeTime from "../../common/datetime/relative_time"; -import { fireEvent } from "../../common/dom/fire_event"; import { describeAction } from "../../data/script_i18n"; -import { ifDefined } from "lit-html/directives/if-defined"; +import { + AutomationTraceExtended, + ChooseActionTraceStep, + getDataFromPath, + isTriggerPath, + TriggerTraceStep, +} from "../../data/trace"; +import { HomeAssistant } from "../../types"; +import "./ha-timeline"; +import type { HaTimeline } from "./ha-timeline"; const LOGBOOK_ENTRIES_BEFORE_FOLD = 2; @@ -245,13 +244,15 @@ class ActionRenderer { try { data = getDataFromPath(this.trace.config, path); } catch (err) { - this.entries.push( - html`Unable to extract path ${path}. Download trace and report as bug` + this._renderEntry( + path, + `Unable to extract path ${path}. Download trace and report as bug` ); return index + 1; } - const isTopLevel = path.split("/").length === 2; + const parts = path.split("/"); + const isTopLevel = parts.length === 2; if (!isTopLevel && !actionType) { this._renderEntry(path, path.replace(/\//g, " ")); @@ -267,7 +268,16 @@ class ActionRenderer { } this._renderEntry(path, describeAction(this.hass, data, actionType)); - return index + 1; + + let i = index + 1; + + for (; i < this.keys.length; i++) { + if (this.keys[i].split("/").length === parts.length) { + break; + } + } + + return i; } private _handleTrigger(index: number, triggerStep: TriggerTraceStep): number { @@ -303,7 +313,7 @@ class ActionRenderer { // +4: executed sequence const choosePath = this.keys[index]; - const startLevel = choosePath.split("/").length - 1; + const startLevel = choosePath.split("/").length; const chooseTrace = this._getItem(index)[0] as ChooseActionTraceStep; const defaultExecuted = chooseTrace.result?.choice === "default"; @@ -568,7 +578,7 @@ export class HaAutomationTracer extends LitElement { } } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ css` ha-timeline[lastItem].condition { diff --git a/src/components/user/ha-person-badge.ts b/src/components/user/ha-person-badge.ts index eead0784c2..9074ea7c9f 100644 --- a/src/components/user/ha-person-badge.ts +++ b/src/components/user/ha-person-badge.ts @@ -1,14 +1,7 @@ -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; -import { styleMap } from "lit-html/directives/style-map"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; +import { styleMap } from "lit/directives/style-map"; import { Person } from "../../data/person"; import { computeInitials } from "./ha-user-badge"; @@ -37,7 +30,7 @@ class PersonBadge extends LitElement { `; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { display: contents; diff --git a/src/components/user/ha-user-badge.ts b/src/components/user/ha-user-badge.ts index cb978dd004..dc1692c35c 100644 --- a/src/components/user/ha-user-badge.ts +++ b/src/components/user/ha-user-badge.ts @@ -1,15 +1,14 @@ import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, + PropertyValues, TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; -import { styleMap } from "lit-html/directives/style-map"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; +import { styleMap } from "lit/directives/style-map"; import { computeStateDomain } from "../../common/entity/compute_state_domain"; import { User } from "../../data/user"; import { CurrentUser, HomeAssistant } from "../../types"; @@ -36,26 +35,26 @@ class UserBadge extends LitElement { @property({ attribute: false }) public user?: User | CurrentUser; - @internalProperty() private _personPicture?: string; + @state() private _personPicture?: string; private _personEntityId?: string; - protected updated(changedProps) { - super.updated(changedProps); + public willUpdate(changedProps: PropertyValues) { + super.willUpdate(changedProps); if (changedProps.has("user")) { this._getPersonPicture(); return; } - const oldHass = changedProps.get("hass"); + const oldHass = changedProps.get("hass") as HomeAssistant | undefined; if ( this._personEntityId && oldHass && this.hass.states[this._personEntityId] !== oldHass.states[this._personEntityId] ) { - const state = this.hass.states[this._personEntityId]; - if (state) { - this._personPicture = state.attributes.entity_picture; + const entityState = this.hass.states[this._personEntityId]; + if (entityState) { + this._personPicture = entityState.attributes.entity_picture; } else { this._getPersonPicture(); } @@ -102,7 +101,7 @@ class UserBadge extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { display: contents; diff --git a/src/components/user/ha-user-picker.ts b/src/components/user/ha-user-picker.ts index e8cd417bc6..89e779d3cc 100644 --- a/src/components/user/ha-user-picker.ts +++ b/src/components/user/ha-user-picker.ts @@ -3,14 +3,8 @@ import "@polymer/paper-input/paper-input"; import "@polymer/paper-item/paper-icon-item"; import "@polymer/paper-item/paper-item-body"; import "@polymer/paper-listbox/paper-listbox"; -import { - css, - CSSResult, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { property } from "lit/decorators"; import memoizeOne from "memoize-one"; import { fireEvent } from "../../common/dom/fire_event"; import { compare } from "../../common/string/compare"; @@ -96,7 +90,7 @@ class HaUserPicker extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { display: inline-block; diff --git a/src/components/user/ha-users-picker.ts b/src/components/user/ha-users-picker.ts index 36a8012596..d0420b82dd 100644 --- a/src/components/user/ha-users-picker.ts +++ b/src/components/user/ha-users-picker.ts @@ -1,14 +1,7 @@ import { mdiClose } from "@mdi/js"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import { guard } from "lit-html/directives/guard"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; +import { guard } from "lit/directives/guard"; import memoizeOne from "memoize-one"; import { fireEvent } from "../../common/dom/fire_event"; import { fetchUsers, User } from "../../data/user"; @@ -149,7 +142,7 @@ class HaUsersPickerLight extends LitElement { this._updateUsers(this._currentUsers.filter((user) => user !== userId)); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { display: block; diff --git a/src/data/automation.ts b/src/data/automation.ts index 21bd303a62..d6e308ccf3 100644 --- a/src/data/automation.ts +++ b/src/data/automation.ts @@ -241,12 +241,9 @@ let inititialAutomationEditorData: Partial | undefined; export const getAutomationConfig = (hass: HomeAssistant, id: string) => hass.callApi("GET", `config/automation/config/${id}`); -export const showAutomationEditor = ( - el: HTMLElement, - data?: Partial -) => { +export const showAutomationEditor = (data?: Partial) => { inititialAutomationEditorData = data; - navigate(el, "/config/automation/edit/new"); + navigate("/config/automation/edit/new"); }; export const getAutomationEditorInitData = () => { diff --git a/src/data/automation_i18n.ts b/src/data/automation_i18n.ts index 7b0caf842f..c819ee340e 100644 --- a/src/data/automation_i18n.ts +++ b/src/data/automation_i18n.ts @@ -1,4 +1,4 @@ -import { Trigger, Condition } from "./automation"; +import { Condition, Trigger } from "./automation"; export const describeTrigger = (trigger: Trigger) => `${trigger.platform} trigger`; @@ -7,8 +7,8 @@ export const describeCondition = (condition: Condition) => { if (condition.alias) { return condition.alias; } - if (condition.condition === "template") { - return "Test a template"; + if (["or", "and", "not"].includes(condition.condition)) { + return `multiple conditions using "${condition.condition}"`; } return `${condition.condition} condition`; }; diff --git a/src/data/config_flow.ts b/src/data/config_flow.ts index 04ecff9915..caa61f48bc 100644 --- a/src/data/config_flow.ts +++ b/src/data/config_flow.ts @@ -13,6 +13,7 @@ export const DISCOVERY_SOURCES = [ "zeroconf", "discovery", "mqtt", + "hassio", ]; export const ATTENTION_SOURCES = ["reauth"]; diff --git a/src/data/device_automation.ts b/src/data/device_automation.ts index 339bf61a16..4392fa529e 100644 --- a/src/data/device_automation.ts +++ b/src/data/device_automation.ts @@ -17,7 +17,7 @@ export interface DeviceAction extends DeviceAutomation { } export interface DeviceCondition extends DeviceAutomation { - condition: string; + condition: "device"; } export interface DeviceTrigger extends DeviceAutomation { diff --git a/src/data/entity.ts b/src/data/entity.ts index 0ade5b2d15..829ee58c35 100644 --- a/src/data/entity.ts +++ b/src/data/entity.ts @@ -2,45 +2,3 @@ export const UNAVAILABLE = "unavailable"; export const UNKNOWN = "unknown"; export const UNAVAILABLE_STATES = [UNAVAILABLE, UNKNOWN]; - -export const ENTITY_COMPONENT_DOMAINS = [ - "air_quality", - "alarm_control_panel", - "alert", - "automation", - "binary_sensor", - "calendar", - "camera", - "counter", - "cover", - "dominos", - "fan", - "geo_location", - "group", - "image_processing", - "input_boolean", - "input_datetime", - "input_number", - "input_select", - "input_text", - "light", - "lock", - "mailbox", - "media_player", - "number", - "person", - "plant", - "remember_the_milk", - "remote", - "scene", - "script", - "sensor", - "switch", - "timer", - "utility_meter", - "vacuum", - "weather", - "wink", - "zha", - "zwave", -]; diff --git a/src/data/hassio/addon.ts b/src/data/hassio/addon.ts index e403d28ba7..902bd88816 100644 --- a/src/data/hassio/addon.ts +++ b/src/data/hassio/addon.ts @@ -2,7 +2,11 @@ import { atLeastVersion } from "../../common/config/version"; import { HaFormSchema } from "../../components/ha-form/ha-form"; import { HomeAssistant } from "../../types"; import { SupervisorArch } from "../supervisor/supervisor"; -import { hassioApiResultExtractor, HassioResponse } from "./common"; +import { + extractApiErrorMessage, + hassioApiResultExtractor, + HassioResponse, +} from "./common"; export type AddonStage = "stable" | "experimental" | "deprecated"; export type AddonAppArmour = "disable" | "default" | "profile"; @@ -186,16 +190,20 @@ export const setHassioAddonOption = async ( data: HassioAddonSetOptionParams ) => { if (atLeastVersion(hass.config.version, 2021, 2, 4)) { - await hass.callWS({ + const response = await hass.callWS>({ type: "supervisor/api", endpoint: `/addons/${slug}/options`, method: "post", data, }); - return; + + if (response.result === "error") { + throw Error(extractApiErrorMessage(response)); + } + return response; } - await hass.callApi>( + return hass.callApi>( "POST", `hassio/addons/${slug}/options`, data diff --git a/src/data/hassio/common.ts b/src/data/hassio/common.ts index b6f7decb25..6c1c254a1c 100644 --- a/src/data/hassio/common.ts +++ b/src/data/hassio/common.ts @@ -3,7 +3,8 @@ import { HomeAssistant } from "../../types"; export interface HassioResponse { data: T; - result: "ok"; + message?: string; + result: "ok" | "error"; } export interface HassioStats { diff --git a/src/data/hassio/snapshot.ts b/src/data/hassio/snapshot.ts index 77df1be76e..ba34776228 100644 --- a/src/data/hassio/snapshot.ts +++ b/src/data/hassio/snapshot.ts @@ -2,12 +2,27 @@ import { atLeastVersion } from "../../common/config/version"; import { HomeAssistant } from "../../types"; import { hassioApiResultExtractor, HassioResponse } from "./common"; +export const friendlyFolderName = { + ssl: "SSL", + homeassistant: "Configuration", + "addons/local": "Local add-ons", + media: "Media", + share: "Share", +}; + +interface SnapshotContent { + homeassistant: boolean; + folders: string[]; + addons: string[]; +} + export interface HassioSnapshot { slug: string; date: string; name: string; type: "full" | "partial"; protected: boolean; + content: SnapshotContent; } export interface HassioSnapshotDetail extends HassioSnapshot { @@ -27,11 +42,10 @@ export interface HassioFullSnapshotCreateParams { name: string; password?: string; } -export interface HassioPartialSnapshotCreateParams { - name: string; +export interface HassioPartialSnapshotCreateParams + extends HassioFullSnapshotCreateParams { folders?: string[]; addons?: string[]; - password?: string; homeassistant?: boolean; } diff --git a/src/data/history.ts b/src/data/history.ts index 6bd1f3359d..636698caf7 100644 --- a/src/data/history.ts +++ b/src/data/history.ts @@ -4,7 +4,7 @@ import { computeStateDomain } from "../common/entity/compute_state_domain"; import { computeStateName } from "../common/entity/compute_state_name"; import { LocalizeFunc } from "../common/translations/localize"; import { HomeAssistant } from "../types"; -import { FrontendTranslationData } from "./translation"; +import { FrontendLocaleData } from "./translation"; const DOMAINS_USE_LAST_UPDATED = ["climate", "humidifier", "water_heater"]; const LINE_ATTRIBUTES_TO_KEEP = [ @@ -109,7 +109,7 @@ const equalState = (obj1: LineChartState, obj2: LineChartState) => const processTimelineEntity = ( localize: LocalizeFunc, - language: FrontendTranslationData, + language: FrontendLocaleData, states: HassEntity[] ): TimelineEntity => { const data: TimelineState[] = []; @@ -224,12 +224,15 @@ export const computeHistory = ( if (stateWithUnit) { unit = stateWithUnit.attributes.unit_of_measurement; - } else if (computeStateDomain(stateInfo[0]) === "climate") { - unit = hass.config.unit_system.temperature; - } else if (computeStateDomain(stateInfo[0]) === "water_heater") { - unit = hass.config.unit_system.temperature; - } else if (computeStateDomain(stateInfo[0]) === "humidifier") { - unit = "%"; + } else { + unit = { + climate: hass.config.unit_system.temperature, + counter: "#", + humidifier: "%", + input_number: "#", + number: "#", + water_heater: hass.config.unit_system.temperature, + }[computeStateDomain(stateInfo[0])]; } if (!unit) { diff --git a/src/data/iconsets.ts b/src/data/iconsets.ts index 2e6df41914..8b92ddbfa3 100644 --- a/src/data/iconsets.ts +++ b/src/data/iconsets.ts @@ -1,4 +1,4 @@ -import { clear, get, set, Store } from "idb-keyval"; +import { clear, get, set, createStore } from "idb-keyval"; import { iconMetadata } from "../resources/icon-metadata"; import { IconMeta } from "../types"; @@ -10,11 +10,11 @@ export interface Chunks { [key: string]: Promise; } -export const iconStore = new Store("hass-icon-db", "mdi-icon-store"); +export const iconStore = createStore("hass-icon-db", "mdi-icon-store"); export const MDI_PREFIXES = ["mdi", "hass", "hassio", "hademo"]; -let toRead: Array<[string, (string) => void, () => void]> = []; +let toRead: Array<[string, (iconPath: string) => void, () => void]> = []; // Queue up as many icon fetches in 1 transaction export const getIcon = (iconName: string) => @@ -25,15 +25,13 @@ export const getIcon = (iconName: string) => return; } - const results: Array<[(string) => void, IDBRequest]> = []; + const results: Array<[(iconPath: string) => void, IDBRequest]> = []; - iconStore - ._withIDBStore("readonly", (store) => { - for (const [iconName_, resolve_] of toRead) { - results.push([resolve_, store.get(iconName_)]); - } - toRead = []; - }) + iconStore("readonly", (store) => { + for (const [iconName_, resolve_] of toRead) { + results.push([resolve_, store.get(iconName_)]); + } + }) .then(() => { for (const [resolve_, request] of results) { resolve_(request.result); @@ -44,11 +42,13 @@ export const getIcon = (iconName: string) => for (const [, , reject_] of toRead) { reject_(); } + }) + .finally(() => { toRead = []; }); }); -export const findIconChunk = (icon): string => { +export const findIconChunk = (icon: string): string => { let lastChunk: IconMeta; for (const chunk of iconMetadata.parts) { if (chunk.start !== undefined && icon < chunk.start) { @@ -63,7 +63,7 @@ export const writeCache = async (chunks: Chunks) => { const keys = Object.keys(chunks); const iconsSets: Icons[] = await Promise.all(Object.values(chunks)); // We do a batch opening the store just once, for (considerable) performance - iconStore._withIDBStore("readwrite", (store) => { + iconStore("readwrite", (store) => { iconsSets.forEach((icons, idx) => { Object.entries(icons).forEach(([name, path]) => { store.put(path, name); @@ -73,14 +73,13 @@ export const writeCache = async (chunks: Chunks) => { }); }; -export const checkCacheVersion = () => { - get("_version", iconStore).then((version) => { - if (!version) { - set("_version", iconMetadata.version, iconStore); - } else if (version !== iconMetadata.version) { - clear(iconStore).then(() => - set("_version", iconMetadata.version, iconStore) - ); - } - }); +export const checkCacheVersion = async () => { + const version = await get("_version", iconStore); + + if (!version) { + set("_version", iconMetadata.version, iconStore); + } else if (version !== iconMetadata.version) { + await clear(iconStore); + set("_version", iconMetadata.version, iconStore); + } }; diff --git a/src/data/light.ts b/src/data/light.ts index df67709783..9ef41c284f 100644 --- a/src/data/light.ts +++ b/src/data/light.ts @@ -51,9 +51,7 @@ export const lightSupportsDimming = (entity: LightEntity) => modesSupportingDimming.includes(mode) ); -export const getLightCurrentModeRgbColor = ( - entity: LightEntity -): number[] | undefined => +export const getLightCurrentModeRgbColor = (entity: LightEntity): number[] => entity.attributes.color_mode === LightColorModes.RGBWW ? entity.attributes.rgbww_color : entity.attributes.color_mode === LightColorModes.RGBW diff --git a/src/data/main_window.ts b/src/data/main_window.ts new file mode 100644 index 0000000000..2a6a6d3e30 --- /dev/null +++ b/src/data/main_window.ts @@ -0,0 +1 @@ +export const MAIN_WINDOW_NAME = "ha-main-window"; diff --git a/src/data/network.ts b/src/data/network.ts new file mode 100644 index 0000000000..5bfb391c00 --- /dev/null +++ b/src/data/network.ts @@ -0,0 +1,43 @@ +import { HomeAssistant } from "../types"; + +export interface IPv6ConfiguredAddress { + address: string; + flowinfo: number; + scope_id: number; + network_prefix: number; +} + +export interface IPv4ConfiguredAddress { + address: string; + network_prefix: number; +} + +export interface Adapter { + name: string; + enabled: boolean; + auto: boolean; + default: boolean; + ipv6: IPv6ConfiguredAddress[]; + ipv4: IPv4ConfiguredAddress[]; +} + +export interface NetworkConfig { + adapters: Adapter[]; + configured_adapters: string[]; +} + +export const getNetworkConfig = (hass: HomeAssistant) => + hass.callWS({ + type: "network", + }); + +export const setNetworkConfig = ( + hass: HomeAssistant, + configured_adapters: string[] +) => + hass.callWS({ + type: "network/configure", + config: { + configured_adapters: configured_adapters, + }, + }); diff --git a/src/data/scene.ts b/src/data/scene.ts index 6b029412c4..5851c48584 100644 --- a/src/data/scene.ts +++ b/src/data/scene.ts @@ -20,12 +20,9 @@ export const SCENE_IGNORED_DOMAINS = [ let inititialSceneEditorData: Partial | undefined; -export const showSceneEditor = ( - el: HTMLElement, - data?: Partial -) => { +export const showSceneEditor = (data?: Partial) => { inititialSceneEditorData = data; - navigate(el, "/config/scene/edit/new"); + navigate("/config/scene/edit/new"); }; export const getSceneEditorInitData = () => { @@ -39,6 +36,7 @@ export interface SceneEntity extends HassEntityBase { } export interface SceneConfig { + id?: string; name: string; icon?: string; entities: SceneEntities; diff --git a/src/data/script.ts b/src/data/script.ts index dc7858768b..559af3a4e3 100644 --- a/src/data/script.ts +++ b/src/data/script.ts @@ -182,12 +182,9 @@ export const deleteScript = (hass: HomeAssistant, objectId: string) => let inititialScriptEditorData: Partial | undefined; -export const showScriptEditor = ( - el: HTMLElement, - data?: Partial -) => { +export const showScriptEditor = (data?: Partial) => { inititialScriptEditorData = data; - navigate(el, "/config/script/edit/new"); + navigate("/config/script/edit/new"); }; export const getScriptEditorInitData = () => { diff --git a/src/data/script_i18n.ts b/src/data/script_i18n.ts index 3b20e12865..338cb7c234 100644 --- a/src/data/script_i18n.ts +++ b/src/data/script_i18n.ts @@ -7,13 +7,13 @@ import { Condition } from "./automation"; import { describeCondition, describeTrigger } from "./automation_i18n"; import { ActionType, - getActionType, - DelayAction, - SceneAction, - WaitForTriggerAction, ActionTypes, - VariablesAction, + DelayAction, EventAction, + getActionType, + SceneAction, + VariablesAction, + WaitForTriggerAction, } from "./script"; export const describeAction = ( diff --git a/src/data/selector.ts b/src/data/selector.ts index 7722d56de8..3bb2999877 100644 --- a/src/data/selector.ts +++ b/src/data/selector.ts @@ -72,8 +72,8 @@ export interface NumberSelector { number: { min: number; max: number; - step: number; - mode: "box" | "slider"; + step?: number; + mode?: "box" | "slider"; unit_of_measurement?: string; }; } diff --git a/src/data/timer.ts b/src/data/timer.ts index a963d64ea3..cff601b60a 100644 --- a/src/data/timer.ts +++ b/src/data/timer.ts @@ -1,7 +1,11 @@ import { + HassEntity, HassEntityAttributeBase, HassEntityBase, } from "home-assistant-js-websocket"; +import durationToSeconds from "../common/datetime/duration_to_seconds"; +import secondsToDuration from "../common/datetime/seconds_to_duration"; +import { computeStateDisplay } from "../common/entity/compute_state_display"; import { HomeAssistant } from "../types"; export type TimerEntity = HassEntityBase & { @@ -55,3 +59,46 @@ export const deleteTimer = (hass: HomeAssistant, id: string) => type: "timer/delete", timer_id: id, }); + +export const timerTimeRemaining = ( + stateObj: HassEntity +): undefined | number => { + if (!stateObj.attributes.remaining) { + return undefined; + } + let timeRemaining = durationToSeconds(stateObj.attributes.remaining); + + if (stateObj.state === "active") { + const now = new Date().getTime(); + const madeActive = new Date(stateObj.last_changed).getTime(); + timeRemaining = Math.max(timeRemaining - (now - madeActive) / 1000, 0); + } + + return timeRemaining; +}; + +export const computeDisplayTimer = ( + hass: HomeAssistant, + stateObj: HassEntity, + timeRemaining?: number +): string | null => { + if (!stateObj) { + return null; + } + + if (stateObj.state === "idle" || timeRemaining === 0) { + return computeStateDisplay(hass.localize, stateObj, hass.locale); + } + + let display = secondsToDuration(timeRemaining || 0); + + if (stateObj.state === "paused") { + display = `${display} (${computeStateDisplay( + hass.localize, + stateObj, + hass.locale + )})`; + } + + return display; +}; diff --git a/src/data/trace.ts b/src/data/trace.ts index cf5f18e6c2..a8d294454d 100644 --- a/src/data/trace.ts +++ b/src/data/trace.ts @@ -1,5 +1,5 @@ import { strStartsWith } from "../common/string/starts-with"; -import { HomeAssistant, Context } from "../types"; +import { Context, HomeAssistant } from "../types"; import { BlueprintAutomationConfig, ManualAutomationConfig, diff --git a/src/data/translation.ts b/src/data/translation.ts index d2fc74e560..65f98a059d 100644 --- a/src/data/translation.ts +++ b/src/data/translation.ts @@ -10,14 +10,22 @@ export enum NumberFormat { none = "none", } -export interface FrontendTranslationData { +export enum TimeFormat { + language = "language", + system = "system", + am_pm = "12", + twenty_four = "24", +} + +export interface FrontendLocaleData { language: string; number_format: NumberFormat; + time_format: TimeFormat; } declare global { interface FrontendUserData { - language: FrontendTranslationData; + language: FrontendLocaleData; } } @@ -36,7 +44,7 @@ export const fetchTranslationPreferences = (hass: HomeAssistant) => export const saveTranslationPreferences = ( hass: HomeAssistant, - data: FrontendTranslationData + data: FrontendLocaleData ) => saveFrontendUserData(hass.connection, "language", data); export const getHassTranslations = async ( diff --git a/src/data/weather.ts b/src/data/weather.ts index e15844c9f4..3c27c13418 100644 --- a/src/data/weather.ts +++ b/src/data/weather.ts @@ -9,8 +9,8 @@ import { HassEntityAttributeBase, HassEntityBase, } from "home-assistant-js-websocket"; -import { css, html, svg, SVGTemplateResult, TemplateResult } from "lit-element"; -import { styleMap } from "lit-html/directives/style-map"; +import { css, html, svg, SVGTemplateResult, TemplateResult } from "lit"; +import { styleMap } from "lit/directives/style-map"; import { formatNumber } from "../common/string/format_number"; import "../components/ha-icon"; import "../components/ha-svg-icon"; diff --git a/src/data/ws-themes.ts b/src/data/ws-themes.ts index d758c27b1a..99a44064f9 100644 --- a/src/data/ws-themes.ts +++ b/src/data/ws-themes.ts @@ -1,6 +1,6 @@ import { Connection, createCollection } from "home-assistant-js-websocket"; -export interface Theme { +export interface ThemeVars { // Incomplete "primary-color": string; "text-primary-color": string; @@ -8,10 +8,20 @@ export interface Theme { [key: string]: string; } +export type Theme = ThemeVars & { + modes?: { + light?: ThemeVars; + dark?: ThemeVars; + }; +}; + export interface Themes { default_theme: string; default_dark_theme: string | null; themes: Record; + // Currently effective dark mode. Will never be undefined. If user selected "auto" + // in theme picker, this property will still contain either true or false based on + // what has been determined via system preferences and support from the selected theme. darkMode: boolean; } diff --git a/src/data/zone.ts b/src/data/zone.ts index 92151c4a58..737ae07dd8 100644 --- a/src/data/zone.ts +++ b/src/data/zone.ts @@ -1,8 +1,12 @@ import { navigate } from "../common/navigate"; +import { + DEFAULT_ACCENT_COLOR, + DEFAULT_PRIMARY_COLOR, +} from "../resources/ha-style"; import { HomeAssistant } from "../types"; -export const defaultRadiusColor = "#FF9800"; -export const homeRadiusColor = "#03a9f4"; +export const defaultRadiusColor = DEFAULT_ACCENT_COLOR; +export const homeRadiusColor = DEFAULT_PRIMARY_COLOR; export const passiveRadiusColor = "#9b9b9b"; export interface Zone { @@ -52,12 +56,9 @@ export const deleteZone = (hass: HomeAssistant, zoneId: string) => let inititialZoneEditorData: Partial | undefined; -export const showZoneEditor = ( - el: HTMLElement, - data?: Partial -) => { +export const showZoneEditor = (data?: Partial) => { inititialZoneEditorData = data; - navigate(el, "/config/zone/new"); + navigate("/config/zone/new"); }; export const getZoneEditorInitData = () => { diff --git a/src/dialogs/config-entry-system-options/dialog-config-entry-system-options.ts b/src/dialogs/config-entry-system-options/dialog-config-entry-system-options.ts index ece523c8fa..bd1f6bbcd1 100644 --- a/src/dialogs/config-entry-system-options/dialog-config-entry-system-options.ts +++ b/src/dialogs/config-entry-system-options/dialog-config-entry-system-options.ts @@ -1,14 +1,6 @@ import "@material/mwc-button/mwc-button"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import { computeRTLDirection } from "../../common/util/compute_rtl"; import "../../components/ha-circular-progress"; @@ -28,15 +20,15 @@ import { ConfigEntrySystemOptionsDialogParams } from "./show-dialog-config-entry class DialogConfigEntrySystemOptions extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _disableNewEntities!: boolean; + @state() private _disableNewEntities!: boolean; - @internalProperty() private _error?: string; + @state() private _error?: string; - @internalProperty() private _params?: ConfigEntrySystemOptionsDialogParams; + @state() private _params?: ConfigEntrySystemOptionsDialogParams; - @internalProperty() private _loading = false; + @state() private _loading = false; - @internalProperty() private _submitting = false; + @state() private _submitting = false; public async showDialog( params: ConfigEntrySystemOptionsDialogParams @@ -154,7 +146,7 @@ class DialogConfigEntrySystemOptions extends LitElement { } } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyleDialog, css` diff --git a/src/dialogs/config-flow/dialog-data-entry-flow.ts b/src/dialogs/config-flow/dialog-data-entry-flow.ts index c4cb084fab..abe31c81be 100644 --- a/src/dialogs/config-flow/dialog-data-entry-flow.ts +++ b/src/dialogs/config-flow/dialog-data-entry-flow.ts @@ -3,14 +3,13 @@ import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable"; import type { UnsubscribeFunc } from "home-assistant-js-websocket"; import { css, - CSSResultArray, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, state } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import { computeRTL } from "../../common/util/compute_rtl"; import "../../components/ha-circular-progress"; @@ -41,9 +40,9 @@ import "./step-flow-create-entry"; import "./step-flow-external"; import "./step-flow-form"; import "./step-flow-loading"; +import "./step-flow-pick-flow"; import "./step-flow-pick-handler"; import "./step-flow-progress"; -import "./step-flow-pick-flow"; let instance = 0; @@ -61,27 +60,27 @@ declare global { class DataEntryFlowDialog extends LitElement { public hass!: HomeAssistant; - @internalProperty() private _params?: DataEntryFlowDialogParams; + @state() private _params?: DataEntryFlowDialogParams; - @internalProperty() private _loading = true; + @state() private _loading = true; private _instance = instance; - @internalProperty() private _step: + @state() private _step: | DataEntryFlowStep | undefined // Null means we need to pick a config flow | null; - @internalProperty() private _devices?: DeviceRegistryEntry[]; + @state() private _devices?: DeviceRegistryEntry[]; - @internalProperty() private _areas?: AreaRegistryEntry[]; + @state() private _areas?: AreaRegistryEntry[]; - @internalProperty() private _handlers?: string[]; + @state() private _handlers?: string[]; - @internalProperty() private _handler?: string; + @state() private _handler?: string; - @internalProperty() private _flowsInProgress?: DataEntryFlowProgress[]; + @state() private _flowsInProgress?: DataEntryFlowProgress[]; private _unsubAreas?: UnsubscribeFunc; @@ -400,7 +399,7 @@ class DataEntryFlowDialog extends LitElement { this._step = step; } - static get styles(): CSSResultArray { + static get styles(): CSSResultGroup { return [ haStyleDialog, css` diff --git a/src/dialogs/config-flow/show-dialog-config-flow.ts b/src/dialogs/config-flow/show-dialog-config-flow.ts index 452d83cb22..fc49d0bf1f 100644 --- a/src/dialogs/config-flow/show-dialog-config-flow.ts +++ b/src/dialogs/config-flow/show-dialog-config-flow.ts @@ -1,6 +1,5 @@ -import { html } from "lit-element"; +import { html } from "lit"; import { caseInsensitiveCompare } from "../../common/string/compare"; -import { localizeKey } from "../../common/translations/localize"; import { createConfigFlow, deleteConfigFlow, @@ -52,8 +51,7 @@ export const showConfigFlowDialog = ( deleteFlow: deleteConfigFlow, renderAbortDescription(hass, step) { - const description = localizeKey( - hass.localize, + const description = hass.localize( `component.${step.handler}.config.abort.${step.reason}`, step.description_placeholders ); @@ -74,8 +72,7 @@ export const showConfigFlowDialog = ( }, renderShowFormStepDescription(hass, step) { - const description = localizeKey( - hass.localize, + const description = hass.localize( `component.${step.handler}.config.step.${step.step_id}.description`, step.description_placeholders ); @@ -108,8 +105,7 @@ export const showConfigFlowDialog = ( }, renderExternalStepDescription(hass, step) { - const description = localizeKey( - hass.localize, + const description = hass.localize( `component.${step.handler}.config.${step.step_id}.description`, step.description_placeholders ); @@ -133,8 +129,7 @@ export const showConfigFlowDialog = ( }, renderCreateEntryDescription(hass, step) { - const description = localizeKey( - hass.localize, + const description = hass.localize( `component.${step.handler}.config.create_entry.${ step.description || "default" }`, @@ -170,8 +165,7 @@ export const showConfigFlowDialog = ( }, renderShowFormProgressDescription(hass, step) { - const description = localizeKey( - hass.localize, + const description = hass.localize( `component.${step.handler}.config.progress.${step.progress_action}`, step.description_placeholders ); diff --git a/src/dialogs/config-flow/show-dialog-data-entry-flow.ts b/src/dialogs/config-flow/show-dialog-data-entry-flow.ts index 23c3961378..1f48db7e77 100644 --- a/src/dialogs/config-flow/show-dialog-data-entry-flow.ts +++ b/src/dialogs/config-flow/show-dialog-data-entry-flow.ts @@ -1,4 +1,4 @@ -import { TemplateResult } from "lit-html"; +import { TemplateResult } from "lit"; import { fireEvent } from "../../common/dom/fire_event"; import { HaFormSchema } from "../../components/ha-form/ha-form"; import { diff --git a/src/dialogs/config-flow/show-dialog-options-flow.ts b/src/dialogs/config-flow/show-dialog-options-flow.ts index 1113b939a6..c138272920 100644 --- a/src/dialogs/config-flow/show-dialog-options-flow.ts +++ b/src/dialogs/config-flow/show-dialog-options-flow.ts @@ -1,5 +1,4 @@ -import { html } from "lit-element"; -import { localizeKey } from "../../common/translations/localize"; +import { html } from "lit"; import { ConfigEntry } from "../../data/config_entries"; import { createOptionsFlow, @@ -43,8 +42,7 @@ export const showOptionsFlowDialog = ( deleteFlow: deleteOptionsFlow, renderAbortDescription(hass, step) { - const description = localizeKey( - hass.localize, + const description = hass.localize( `component.${configEntry.domain}.options.abort.${step.reason}`, step.description_placeholders ); @@ -69,8 +67,7 @@ export const showOptionsFlowDialog = ( }, renderShowFormStepDescription(hass, step) { - const description = localizeKey( - hass.localize, + const description = hass.localize( `component.${configEntry.domain}.options.step.${step.step_id}.description`, step.description_placeholders ); diff --git a/src/dialogs/config-flow/step-flow-abort.ts b/src/dialogs/config-flow/step-flow-abort.ts index 7309ff2226..b581717f8b 100644 --- a/src/dialogs/config-flow/step-flow-abort.ts +++ b/src/dialogs/config-flow/step-flow-abort.ts @@ -1,12 +1,6 @@ import "@material/mwc-button"; -import { - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import { DataEntryFlowStepAbort } from "../../data/data_entry_flow"; import { HomeAssistant } from "../../types"; @@ -47,7 +41,7 @@ class StepFlowAbort extends LitElement { fireEvent(this, "flow-update", { step: undefined }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return configFlowContentStyles; } } diff --git a/src/dialogs/config-flow/step-flow-create-entry.ts b/src/dialogs/config-flow/step-flow-create-entry.ts index 46b67ab1a6..2d08078c88 100644 --- a/src/dialogs/config-flow/step-flow-create-entry.ts +++ b/src/dialogs/config-flow/step-flow-create-entry.ts @@ -2,15 +2,8 @@ import "@material/mwc-button"; import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; -import { - css, - CSSResultArray, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import "../../components/ha-area-picker"; import { DataEntryFlowStepCreateEntry } from "../../data/data_entry_flow"; @@ -109,7 +102,7 @@ class StepFlowCreateEntry extends LitElement { } } - static get styles(): CSSResultArray { + static get styles(): CSSResultGroup { return [ configFlowContentStyles, css` diff --git a/src/dialogs/config-flow/step-flow-external.ts b/src/dialogs/config-flow/step-flow-external.ts index 3f9c84bbc7..419d9bcde5 100644 --- a/src/dialogs/config-flow/step-flow-external.ts +++ b/src/dialogs/config-flow/step-flow-external.ts @@ -1,13 +1,6 @@ import "@material/mwc-button"; -import { - css, - CSSResultArray, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import { DataEntryFlowStepExternal } from "../../data/data_entry_flow"; import { HomeAssistant } from "../../types"; import { FlowConfig } from "./show-dialog-data-entry-flow"; @@ -48,7 +41,7 @@ class StepFlowExternal extends LitElement { window.open(this.step.url); } - static get styles(): CSSResultArray { + static get styles(): CSSResultGroup { return [ configFlowContentStyles, css` diff --git a/src/dialogs/config-flow/step-flow-form.ts b/src/dialogs/config-flow/step-flow-form.ts index 5c569873d6..403eccb3c8 100644 --- a/src/dialogs/config-flow/step-flow-form.ts +++ b/src/dialogs/config-flow/step-flow-form.ts @@ -2,14 +2,13 @@ import "@material/mwc-button"; import "@polymer/paper-tooltip/paper-tooltip"; import { css, - CSSResultArray, - customElement, + CSSResultGroup, html, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import "../../components/ha-circular-progress"; import "../../components/ha-form/ha-form"; @@ -183,7 +182,7 @@ class StepFlowForm extends LitElement { private _errorCallback = (error: string) => this.flowConfig.renderShowFormStepFieldError(this.hass, this.step, error); - static get styles(): CSSResultArray { + static get styles(): CSSResultGroup { return [ configFlowContentStyles, css` diff --git a/src/dialogs/config-flow/step-flow-loading.ts b/src/dialogs/config-flow/step-flow-loading.ts index 8b4d28735b..bc10d71c7a 100644 --- a/src/dialogs/config-flow/step-flow-loading.ts +++ b/src/dialogs/config-flow/step-flow-loading.ts @@ -1,12 +1,5 @@ -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import "../../components/ha-circular-progress"; @customElement("step-flow-loading") @@ -22,7 +15,7 @@ class StepFlowLoading extends LitElement { `; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` .init-spinner { padding: 50px 100px; diff --git a/src/dialogs/config-flow/step-flow-pick-flow.ts b/src/dialogs/config-flow/step-flow-pick-flow.ts index b75f2e3b38..0e407fad89 100644 --- a/src/dialogs/config-flow/step-flow-pick-flow.ts +++ b/src/dialogs/config-flow/step-flow-pick-flow.ts @@ -1,15 +1,8 @@ -import "@polymer/paper-item/paper-icon-item"; import "@polymer/paper-item"; +import "@polymer/paper-item/paper-icon-item"; import "@polymer/paper-item/paper-item-body"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import "../../components/ha-icon-next"; import { localizeConfigFlowTitle } from "../../data/config_flow"; @@ -89,7 +82,7 @@ class StepFlowPickFlow extends LitElement { }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ configFlowContentStyles, css` diff --git a/src/dialogs/config-flow/step-flow-pick-handler.ts b/src/dialogs/config-flow/step-flow-pick-handler.ts index 660416a71e..421478857c 100644 --- a/src/dialogs/config-flow/step-flow-pick-handler.ts +++ b/src/dialogs/config-flow/step-flow-pick-handler.ts @@ -1,18 +1,10 @@ import "@polymer/paper-item/paper-icon-item"; import "@polymer/paper-item/paper-item-body"; import Fuse from "fuse.js"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; -import { styleMap } from "lit-html/directives/style-map"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; +import { styleMap } from "lit/directives/style-map"; import memoizeOne from "memoize-one"; import { fireEvent } from "../../common/dom/fire_event"; import "../../common/search/search-input"; @@ -46,7 +38,7 @@ class StepFlowPickHandler extends LitElement { @property() public showAdvanced?: boolean; - @internalProperty() private _filter?: string; + @state() private _filter?: string; private _width?: number; @@ -175,7 +167,7 @@ class StepFlowPickHandler extends LitElement { }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ configFlowContentStyles, css` diff --git a/src/dialogs/config-flow/step-flow-progress.ts b/src/dialogs/config-flow/step-flow-progress.ts index fc12f9b5c5..3235ec55cb 100644 --- a/src/dialogs/config-flow/step-flow-progress.ts +++ b/src/dialogs/config-flow/step-flow-progress.ts @@ -1,13 +1,6 @@ import "@material/mwc-button"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import "../../components/ha-circular-progress"; import { DataEntryFlowStepProgress } from "../../data/data_entry_flow"; import { HomeAssistant } from "../../types"; @@ -39,7 +32,7 @@ class StepFlowProgress extends LitElement { `; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ configFlowContentStyles, css` diff --git a/src/dialogs/config-flow/styles.ts b/src/dialogs/config-flow/styles.ts index b6e2b8d831..008fed7c1b 100644 --- a/src/dialogs/config-flow/styles.ts +++ b/src/dialogs/config-flow/styles.ts @@ -1,4 +1,4 @@ -import { css } from "lit-element"; +import { css } from "lit"; export const configFlowContentStyles = css` h2 { diff --git a/src/dialogs/domain-toggler/dialog-domain-toggler.ts b/src/dialogs/domain-toggler/dialog-domain-toggler.ts index 4b2aa3aea4..82307abfe1 100644 --- a/src/dialogs/domain-toggler/dialog-domain-toggler.ts +++ b/src/dialogs/domain-toggler/dialog-domain-toggler.ts @@ -1,13 +1,6 @@ import "@material/mwc-button/mwc-button"; -import { - css, - CSSResultArray, - customElement, - html, - internalProperty, - LitElement, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, state } from "lit/decorators"; import { fireEvent } from "../../common/dom/fire_event"; import { createCloseHeading } from "../../components/ha-dialog"; import "../../components/ha-formfield"; @@ -24,7 +17,7 @@ class DomainTogglerDialog implements HassDialog { public hass!: HomeAssistant; - @internalProperty() private _params?: HaDomainTogglerDialogParams; + @state() private _params?: HaDomainTogglerDialogParams; public showDialog(params: HaDomainTogglerDialogParams): void { this._params = params; @@ -91,7 +84,7 @@ class DomainTogglerDialog ev.currentTarget.blur(); } - static get styles(): CSSResultArray { + static get styles(): CSSResultGroup { return [ haStyleDialog, css` diff --git a/src/dialogs/generic/dialog-box.ts b/src/dialogs/generic/dialog-box.ts index 3dcbbd37f8..4fc1c09cde 100644 --- a/src/dialogs/generic/dialog-box.ts +++ b/src/dialogs/generic/dialog-box.ts @@ -1,16 +1,8 @@ import "@material/mwc-button/mwc-button"; import "@polymer/paper-input/paper-input"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import { fireEvent } from "../../common/dom/fire_event"; import "../../components/ha-dialog"; import "../../components/ha-switch"; @@ -23,9 +15,9 @@ import { DialogBoxParams } from "./show-dialog-box"; class DialogBox extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _params?: DialogBoxParams; + @state() private _params?: DialogBoxParams; - @internalProperty() private _value?: string; + @state() private _value?: string; public async showDialog(params: DialogBoxParams): Promise { this._params = params; @@ -57,7 +49,7 @@ class DialogBox extends LitElement { open ?scrimClickAction=${confirmPrompt} ?escapeKeyAction=${confirmPrompt} - @closing=${this._dialogClosed} + @closed=${this._dialogClosed} defaultAction="ignore" .heading=${this._params.title ? this._params.title @@ -154,7 +146,7 @@ class DialogBox extends LitElement { fireEvent(this, "dialog-closed", { dialog: this.localName }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyleDialog, css` diff --git a/src/dialogs/generic/show-dialog-box.ts b/src/dialogs/generic/show-dialog-box.ts index bd3210c5fd..1350c91d18 100644 --- a/src/dialogs/generic/show-dialog-box.ts +++ b/src/dialogs/generic/show-dialog-box.ts @@ -1,4 +1,4 @@ -import { TemplateResult } from "lit-html"; +import { TemplateResult } from "lit"; import { fireEvent } from "../../common/dom/fire_event"; interface BaseDialogBoxParams { diff --git a/src/dialogs/image-cropper-dialog/image-cropper-dialog.ts b/src/dialogs/image-cropper-dialog/image-cropper-dialog.ts index 82dd0bc958..f8709344e3 100644 --- a/src/dialogs/image-cropper-dialog/image-cropper-dialog.ts +++ b/src/dialogs/image-cropper-dialog/image-cropper-dialog.ts @@ -4,18 +4,15 @@ import Cropper from "cropperjs"; import cropperCss from "cropperjs/dist/cropper.css"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, - query, TemplateResult, unsafeCSS, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +} from "lit"; +import { customElement, property, state, query } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import "../../components/ha-dialog"; import { haStyleDialog } from "../../resources/styles"; import type { HomeAssistant } from "../../types"; @@ -25,9 +22,9 @@ import { HaImageCropperDialogParams } from "./show-image-cropper-dialog"; export class HaImagecropperDialog extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _params?: HaImageCropperDialogParams; + @state() private _params?: HaImageCropperDialogParams; - @internalProperty() private _open = false; + @state() private _open = false; @query("img", true) private _image!: HTMLImageElement; @@ -104,7 +101,7 @@ export class HaImagecropperDialog extends LitElement { ); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyleDialog, css` diff --git a/src/dialogs/make-dialog-manager.ts b/src/dialogs/make-dialog-manager.ts index bc32b08050..2acfe6473f 100644 --- a/src/dialogs/make-dialog-manager.ts +++ b/src/dialogs/make-dialog-manager.ts @@ -1,4 +1,5 @@ import { HASSDomEvent, ValidHassDomEvent } from "../common/dom/fire_event"; +import { mainWindow } from "../common/dom/get_main_window"; import { ProvideHassElement } from "../mixins/provide-hass-lit-mixin"; declare global { @@ -50,6 +51,12 @@ export const showDialog = async ( ) => { if (!(dialogTag in LOADED)) { if (!dialogImport) { + if (__DEV__) { + // eslint-disable-next-line + console.warn( + "Asked to show dialog that's not loaded and can't be imported" + ); + } return; } LOADED[dialogTag] = dialogImport().then(() => { @@ -61,25 +68,26 @@ export const showDialog = async ( } if (addHistory) { - top.history.replaceState( + mainWindow.history.replaceState( { dialog: dialogTag, open: false, oldState: - top.history.state?.open && top.history.state?.dialog !== dialogTag - ? top.history.state + mainWindow.history.state?.open && + mainWindow.history.state?.dialog !== dialogTag + ? mainWindow.history.state : null, }, "" ); try { - top.history.pushState( + mainWindow.history.pushState( { dialog: dialogTag, dialogParams: dialogParams, open: true }, "" ); } catch (err) { // dialogParams could not be cloned, probably contains callback - top.history.pushState( + mainWindow.history.pushState( { dialog: dialogTag, dialogParams: null, open: true }, "" ); @@ -90,14 +98,17 @@ export const showDialog = async ( }; export const replaceDialog = () => { - top.history.replaceState({ ...top.history.state, replaced: true }, ""); + mainWindow.history.replaceState( + { ...mainWindow.history.state, replaced: true }, + "" + ); }; export const closeDialog = async (dialogTag: string): Promise => { if (!(dialogTag in LOADED)) { return true; } - const dialogElement = await LOADED[dialogTag]; + const dialogElement: HassDialog = await LOADED[dialogTag]; if (dialogElement.closeDialog) { return dialogElement.closeDialog() !== false; } diff --git a/src/dialogs/more-info/controls/more-info-automation.ts b/src/dialogs/more-info/controls/more-info-automation.ts index 293b56f6ad..0584b977ed 100644 --- a/src/dialogs/more-info/controls/more-info-automation.ts +++ b/src/dialogs/more-info/controls/more-info-automation.ts @@ -1,14 +1,7 @@ import "@material/mwc-button"; import { HassEntity } from "home-assistant-js-websocket"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import "../../../components/ha-relative-time"; import { triggerAutomationActions } from "../../../data/automation"; import { UNAVAILABLE_STATES } from "../../../data/entity"; @@ -50,7 +43,7 @@ class MoreInfoAutomation extends LitElement { triggerAutomationActions(this.hass, this.stateObj!.entity_id); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` .flex { display: flex; diff --git a/src/dialogs/more-info/controls/more-info-camera.ts b/src/dialogs/more-info/controls/more-info-camera.ts index 64808f950f..bc571b4bc8 100644 --- a/src/dialogs/more-info/controls/more-info-camera.ts +++ b/src/dialogs/more-info/controls/more-info-camera.ts @@ -2,16 +2,15 @@ import "@polymer/paper-checkbox/paper-checkbox"; import type { PaperCheckboxElement } from "@polymer/paper-checkbox/paper-checkbox"; import { css, - CSSResult, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; -import { supportsFeature } from "../../../common/entity/supports-feature"; +} from "lit"; +import { property, state } from "lit/decorators"; import { isComponentLoaded } from "../../../common/config/is_component_loaded"; +import { supportsFeature } from "../../../common/entity/supports-feature"; import "../../../components/ha-camera-stream"; import { CameraEntity, @@ -27,9 +26,9 @@ class MoreInfoCamera extends LitElement { @property() public stateObj?: CameraEntity; - @internalProperty() private _cameraPrefs?: CameraPreferences; + @state() private _cameraPrefs?: CameraPreferences; - @internalProperty() private _attached = false; + @state() private _attached = false; public connectedCallback() { super.connectedCallback(); @@ -113,15 +112,19 @@ class MoreInfoCamera extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` + :host { + display: block; + position: relative; + } paper-checkbox { position: absolute; top: 0; right: 0; background-color: var(--secondary-background-color); padding: 5px; - border-bottom-left-radius: 6px; + border-bottom-left-radius: 4px; } `; } diff --git a/src/dialogs/more-info/controls/more-info-climate.ts b/src/dialogs/more-info/controls/more-info-climate.ts index 02d48e8a1b..7d21934698 100644 --- a/src/dialogs/more-info/controls/more-info-climate.ts +++ b/src/dialogs/more-info/controls/more-info-climate.ts @@ -3,14 +3,14 @@ import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; import { css, - CSSResult, + CSSResultGroup, html, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +} from "lit"; +import { property } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import { fireEvent } from "../../../common/dom/fire_event"; import { supportsFeature } from "../../../common/entity/supports-feature"; import { computeRTLDirection } from "../../../common/util/compute_rtl"; @@ -437,7 +437,7 @@ class MoreInfoClimate extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { color: var(--primary-text-color); diff --git a/src/dialogs/more-info/controls/more-info-counter.ts b/src/dialogs/more-info/controls/more-info-counter.ts index 330f504f50..3e08b0e522 100644 --- a/src/dialogs/more-info/controls/more-info-counter.ts +++ b/src/dialogs/more-info/controls/more-info-counter.ts @@ -1,14 +1,7 @@ import "@material/mwc-button"; import { HassEntity } from "home-assistant-js-websocket"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import { UNAVAILABLE_STATES } from "../../../data/entity"; import { HomeAssistant } from "../../../types"; @@ -59,7 +52,7 @@ class MoreInfoCounter extends LitElement { }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` .actions { margin: 8px 0; diff --git a/src/dialogs/more-info/controls/more-info-cover.js b/src/dialogs/more-info/controls/more-info-cover.js index 4e26d57e86..6431959047 100644 --- a/src/dialogs/more-info/controls/more-info-cover.js +++ b/src/dialogs/more-info/controls/more-info-cover.js @@ -65,6 +65,7 @@ class MoreInfoCover extends LocalizeMixin(PolymerElement) { diff --git a/src/dialogs/more-info/controls/more-info-default.ts b/src/dialogs/more-info/controls/more-info-default.ts index 443b39ed43..381454bf9d 100644 --- a/src/dialogs/more-info/controls/more-info-default.ts +++ b/src/dialogs/more-info/controls/more-info-default.ts @@ -1,11 +1,6 @@ import { HassEntity } from "home-assistant-js-websocket"; -import { - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import "../../../components/ha-attributes"; import { HomeAssistant } from "../../../types"; @@ -20,7 +15,10 @@ class MoreInfoDefault extends LitElement { return html``; } - return html` `; + return html``; } } diff --git a/src/dialogs/more-info/controls/more-info-fan.js b/src/dialogs/more-info/controls/more-info-fan.js index 93bbe59396..5ef80331c1 100644 --- a/src/dialogs/more-info/controls/more-info-fan.js +++ b/src/dialogs/more-info/controls/more-info-fan.js @@ -11,9 +11,9 @@ import "../../../components/ha-icon-button"; import "../../../components/ha-labeled-slider"; import "../../../components/ha-paper-dropdown-menu"; import "../../../components/ha-switch"; +import { SUPPORT_SET_SPEED } from "../../../data/fan"; import { EventsMixin } from "../../../mixins/events-mixin"; import LocalizeMixin from "../../../mixins/localize-mixin"; -import { SUPPORT_SET_SPEED } from "../../../data/fan"; /* * @appliesMixin EventsMixin @@ -113,6 +113,7 @@ class MoreInfoFan extends LocalizeMixin(EventsMixin(PolymerElement)) { diff --git a/src/dialogs/more-info/controls/more-info-group.ts b/src/dialogs/more-info/controls/more-info-group.ts index 615bf3314d..c8b2e7bdbb 100644 --- a/src/dialogs/more-info/controls/more-info-group.ts +++ b/src/dialogs/more-info/controls/more-info-group.ts @@ -1,13 +1,13 @@ import { HassEntity } from "home-assistant-js-websocket"; import { css, - CSSResult, - internalProperty, + CSSResultGroup, + html, LitElement, - property, PropertyValues, -} from "lit-element"; -import { html, TemplateResult } from "lit-html"; + TemplateResult, +} from "lit"; +import { property, state } from "lit/decorators"; import { dynamicElement } from "../../../common/dom/dynamic-element-directive"; import { computeStateDomain } from "../../../common/entity/compute_state_domain"; import { GroupEntity } from "../../../data/group"; @@ -23,9 +23,9 @@ class MoreInfoGroup extends LitElement { @property() public stateObj?: GroupEntity; - @internalProperty() private _groupDomainStateObj?: HassEntity; + @state() private _groupDomainStateObj?: HassEntity; - @internalProperty() private _moreInfoType?: string; + @state() private _moreInfoType?: string; protected updated(changedProperties: PropertyValues) { if ( @@ -38,7 +38,7 @@ class MoreInfoGroup extends LitElement { const states = this.stateObj.attributes.entity_id .map((entity_id) => this.hass.states[entity_id]) - .filter((state) => state); + .filter((entityState) => entityState); if (!states.length) { this._groupDomainStateObj = undefined; @@ -53,7 +53,9 @@ class MoreInfoGroup extends LitElement { // first child above the children of the current group if ( groupDomain !== "group" && - states.every((state) => groupDomain === computeStateDomain(state)) + states.every( + (entityState) => groupDomain === computeStateDomain(entityState) + ) ) { this._groupDomainStateObj = { ...baseStateObj, @@ -80,20 +82,20 @@ class MoreInfoGroup extends LitElement { }) : ""} ${this.stateObj.attributes.entity_id.map((entity_id) => { - const state = this.hass!.states[entity_id]; - if (!state) { + const entityState = this.hass!.states[entity_id]; + if (!entityState) { return ""; } return html` `; })}`; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` state-card-content { display: block; diff --git a/src/dialogs/more-info/controls/more-info-humidifier.ts b/src/dialogs/more-info/controls/more-info-humidifier.ts index 56f89af45d..43da799a16 100644 --- a/src/dialogs/more-info/controls/more-info-humidifier.ts +++ b/src/dialogs/more-info/controls/more-info-humidifier.ts @@ -3,14 +3,14 @@ import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; import { css, - CSSResult, + CSSResultGroup, html, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +} from "lit"; +import { property } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import { fireEvent } from "../../../common/dom/fire_event"; import { supportsFeature } from "../../../common/entity/supports-feature"; import { computeRTLDirection } from "../../../common/util/compute_rtl"; @@ -171,7 +171,7 @@ class MoreInfoHumidifier extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { color: var(--primary-text-color); diff --git a/src/dialogs/more-info/controls/more-info-light.ts b/src/dialogs/more-info/controls/more-info-light.ts index 63520d1947..3ac4d2e143 100644 --- a/src/dialogs/more-info/controls/more-info-light.ts +++ b/src/dialogs/more-info/controls/more-info-light.ts @@ -2,17 +2,16 @@ import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; import { supportsFeature } from "../../../common/entity/supports-feature"; import "../../../components/ha-attributes"; +import "../../../components/ha-button-toggle-group"; import "../../../components/ha-color-picker"; import "../../../components/ha-icon-button"; import "../../../components/ha-labeled-slider"; @@ -28,7 +27,6 @@ import { SUPPORT_EFFECT, } from "../../../data/light"; import type { HomeAssistant } from "../../../types"; -import "../../../components/ha-button-toggle-group"; const toggleButtons = [ { label: "Color", value: "color" }, @@ -41,27 +39,27 @@ class MoreInfoLight extends LitElement { @property({ attribute: false }) public stateObj?: LightEntity; - @internalProperty() private _brightnessSliderValue = 0; + @state() private _brightnessSliderValue = 0; - @internalProperty() private _ctSliderValue?: number; + @state() private _ctSliderValue?: number; - @internalProperty() private _cwSliderValue?: number; + @state() private _cwSliderValue?: number; - @internalProperty() private _wwSliderValue?: number; + @state() private _wwSliderValue?: number; - @internalProperty() private _wvSliderValue?: number; + @state() private _wvSliderValue?: number; - @internalProperty() private _colorBrightnessSliderValue?: number; + @state() private _colorBrightnessSliderValue?: number; - @internalProperty() private _brightnessAdjusted?: number; + @state() private _brightnessAdjusted?: number; - @internalProperty() private _hueSegments = 24; + @state() private _hueSegments = 24; - @internalProperty() private _saturationSegments = 8; + @state() private _saturationSegments = 8; - @internalProperty() private _colorPickerColor?: [number, number, number]; + @state() private _colorPickerColor?: [number, number, number]; - @internalProperty() private _mode?: "color" | LightColorModes.COLOR_TEMP; + @state() private _mode?: "color" | LightColorModes.COLOR_TEMP; protected render(): TemplateResult { if (!this.hass || !this.stateObj) { @@ -154,7 +152,7 @@ class MoreInfoLight extends LitElement { )} icon="hass:brightness-7" max="100" - .value=${this._colorBrightnessSliderValue ?? 100} + .value=${this._colorBrightnessSliderValue} @change=${this._colorBrightnessSliderChanged} pin >` @@ -228,6 +226,7 @@ class MoreInfoLight extends LitElement { ` : ""} @@ -235,7 +234,9 @@ class MoreInfoLight extends LitElement { `; } - protected updated(changedProps: PropertyValues) { + public willUpdate(changedProps: PropertyValues) { + super.willUpdate(changedProps); + if (!changedProps.has("stateObj")) { return; } @@ -282,23 +283,18 @@ class MoreInfoLight extends LitElement { stateObj.attributes.color_mode === LightColorModes.RGBWW ? Math.round((stateObj.attributes.rgbww_color[4] * 100) / 255) : undefined; - this._colorBrightnessSliderValue = - stateObj.attributes.color_mode === LightColorModes.RGBWW - ? Math.round( - (Math.max(...stateObj.attributes.rgbww_color.slice(0, 3)) * 100) / - 255 - ) - : stateObj.attributes.color_mode === LightColorModes.RGBW - ? Math.round( - (Math.max(...stateObj.attributes.rgbw_color.slice(0, 3)) * 100) / - 255 - ) - : undefined; - this._colorPickerColor = getLightCurrentModeRgbColor(stateObj)?.slice( - 0, - 3 - ) as [number, number, number] | undefined; + const currentRgbColor = getLightCurrentModeRgbColor(stateObj); + + this._colorBrightnessSliderValue = currentRgbColor + ? Math.round((Math.max(...currentRgbColor.slice(0, 3)) * 100) / 255) + : undefined; + + this._colorPickerColor = currentRgbColor?.slice(0, 3) as [ + number, + number, + number + ]; } else { this._brightnessSliderValue = 0; } @@ -328,6 +324,8 @@ class MoreInfoLight extends LitElement { return; } + this._brightnessSliderValue = bri; + if (this._brightnessAdjusted) { const rgb = this.stateObj!.attributes.rgb_color || @@ -358,6 +356,8 @@ class MoreInfoLight extends LitElement { return; } + this._ctSliderValue = ct; + this.hass.callService("light", "turn_on", { entity_id: this.stateObj!.entity_id, color_temp: ct, @@ -373,6 +373,14 @@ class MoreInfoLight extends LitElement { return; } + if (name === "wv") { + this._wvSliderValue = wv; + } else if (name === "cw") { + this._cwSliderValue = wv; + } else if (name === "ww") { + this._wwSliderValue = wv; + } + wv = Math.min(255, Math.round((wv * 255) / 100)); const rgb = getLightCurrentModeRgbColor(this.stateObj!); @@ -406,6 +414,9 @@ class MoreInfoLight extends LitElement { return; } + const oldValue = this._colorBrightnessSliderValue; + this._colorBrightnessSliderValue = value; + value = (value * 255) / 100; const rgb = (getLightCurrentModeRgbColor(this.stateObj!)?.slice(0, 3) || [ @@ -417,12 +428,8 @@ class MoreInfoLight extends LitElement { this._setRgbWColor( this._adjustColorBrightness( // first normalize the value - this._colorBrightnessSliderValue - ? this._adjustColorBrightness( - rgb, - (this._colorBrightnessSliderValue * 255) / 100, - true - ) + oldValue + ? this._adjustColorBrightness(rgb, (oldValue * 255) / 100, true) : rgb, value ) @@ -488,6 +495,12 @@ class MoreInfoLight extends LitElement { rgb: { r: number; g: number; b: number }; }> ) { + this._colorPickerColor = [ + ev.detail.rgb.r, + ev.detail.rgb.g, + ev.detail.rgb.b, + ]; + if ( lightSupportsColorMode(this.stateObj!, LightColorModes.RGBWW) || lightSupportsColorMode(this.stateObj!, LightColorModes.RGBW) @@ -530,7 +543,7 @@ class MoreInfoLight extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` .content { display: flex; @@ -540,8 +553,6 @@ class MoreInfoLight extends LitElement { .content > * { width: 100%; - max-height: 84px; - overflow: hidden; } .color_temp { diff --git a/src/dialogs/more-info/controls/more-info-lock.js b/src/dialogs/more-info/controls/more-info-lock.js index 7c7fe6f3c7..346e1a8625 100644 --- a/src/dialogs/more-info/controls/more-info-lock.js +++ b/src/dialogs/more-info/controls/more-info-lock.js @@ -39,6 +39,7 @@ class MoreInfoLock extends LocalizeMixin(PolymerElement) { > 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 95ebc74d26..89bb143d3f 100644 --- a/src/dialogs/more-info/controls/more-info-media_player.ts +++ b/src/dialogs/more-info/controls/more-info-media_player.ts @@ -4,16 +4,8 @@ import { mdiPlayBoxMultiple } from "@mdi/js"; import "@polymer/paper-input/paper-input"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - query, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, query } from "lit/decorators"; import { isComponentLoaded } from "../../../common/config/is_component_loaded"; import { supportsFeature } from "../../../common/entity/supports-feature"; import { computeRTLDirection } from "../../../common/util/compute_rtl"; @@ -203,7 +195,7 @@ class MoreInfoMediaPlayer extends LitElement { `; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` ha-icon-button[action="turn_off"], ha-icon-button[action="turn_on"], diff --git a/src/dialogs/more-info/controls/more-info-person.ts b/src/dialogs/more-info/controls/more-info-person.ts index 4caa2ea3d3..328b73dc97 100644 --- a/src/dialogs/more-info/controls/more-info-person.ts +++ b/src/dialogs/more-info/controls/more-info-person.ts @@ -1,14 +1,7 @@ import "@material/mwc-button"; import { HassEntity } from "home-assistant-js-websocket"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import memoizeOne from "memoize-one"; import { fireEvent } from "../../../common/dom/fire_event"; import "../../../components/ha-attributes"; @@ -31,6 +24,7 @@ class MoreInfoPerson extends LitElement { return html` @@ -61,14 +55,14 @@ class MoreInfoPerson extends LitElement { } private _handleAction() { - showZoneEditor(this, { + showZoneEditor({ latitude: this.stateObj!.attributes.latitude, longitude: this.stateObj!.attributes.longitude, }); fireEvent(this, "hass-more-info", { entityId: null }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` .flex { display: flex; diff --git a/src/dialogs/more-info/controls/more-info-remote.ts b/src/dialogs/more-info/controls/more-info-remote.ts index 276b862b33..421537bf67 100644 --- a/src/dialogs/more-info/controls/more-info-remote.ts +++ b/src/dialogs/more-info/controls/more-info-remote.ts @@ -1,14 +1,7 @@ import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import { supportsFeature } from "../../../common/entity/supports-feature"; import "../../../components/ha-attributes"; import "../../../components/ha-paper-dropdown-menu"; @@ -55,6 +48,7 @@ class MoreInfoRemote extends LitElement { : ""} @@ -75,7 +69,7 @@ class MoreInfoRemote extends LitElement { }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` paper-item { cursor: pointer; diff --git a/src/dialogs/more-info/controls/more-info-script.ts b/src/dialogs/more-info/controls/more-info-script.ts index 1c364318b9..39ce62214e 100644 --- a/src/dialogs/more-info/controls/more-info-script.ts +++ b/src/dialogs/more-info/controls/more-info-script.ts @@ -1,13 +1,6 @@ import { HassEntity } from "home-assistant-js-websocket"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import "../../../components/ha-relative-time"; import { HomeAssistant } from "../../../types"; @@ -42,7 +35,7 @@ class MoreInfoScript extends LitElement { `; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` .flex { display: flex; diff --git a/src/dialogs/more-info/controls/more-info-sun.ts b/src/dialogs/more-info/controls/more-info-sun.ts index 22904234d5..9de886b619 100644 --- a/src/dialogs/more-info/controls/more-info-sun.ts +++ b/src/dialogs/more-info/controls/more-info-sun.ts @@ -1,13 +1,6 @@ import { HassEntity } from "home-assistant-js-websocket"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import { formatTime } from "../../../common/datetime/format_time"; import { formatNumber } from "../../../common/string/format_number"; import "../../../components/ha-relative-time"; @@ -68,7 +61,7 @@ class MoreInfoSun extends LitElement { `; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` .row { margin: 0; diff --git a/src/dialogs/more-info/controls/more-info-timer.ts b/src/dialogs/more-info/controls/more-info-timer.ts index 80f8819009..daf2e8e97f 100644 --- a/src/dialogs/more-info/controls/more-info-timer.ts +++ b/src/dialogs/more-info/controls/more-info-timer.ts @@ -1,13 +1,6 @@ import "@material/mwc-button"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import "../../../components/ha-attributes"; import { TimerEntity } from "../../../data/timer"; import { HomeAssistant } from "../../../types"; @@ -25,6 +18,7 @@ class MoreInfoTimer extends LitElement { return html` @@ -73,7 +67,7 @@ class MoreInfoTimer extends LitElement { }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` .actions { margin: 8px 0; diff --git a/src/dialogs/more-info/controls/more-info-vacuum.ts b/src/dialogs/more-info/controls/more-info-vacuum.ts index f6285c28d2..c1841b7a5f 100644 --- a/src/dialogs/more-info/controls/more-info-vacuum.ts +++ b/src/dialogs/more-info/controls/more-info-vacuum.ts @@ -1,14 +1,7 @@ import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import { supportsFeature } from "../../../common/entity/supports-feature"; import "../../../components/ha-attributes"; import "../../../components/ha-icon"; @@ -197,6 +190,7 @@ class MoreInfoVacuum extends LitElement { : ""} @@ -224,7 +218,7 @@ class MoreInfoVacuum extends LitElement { }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { line-height: 1.5; diff --git a/src/dialogs/more-info/controls/more-info-weather.ts b/src/dialogs/more-info/controls/more-info-weather.ts index 0f2b63313d..3b69a35a7a 100644 --- a/src/dialogs/more-info/controls/more-info-weather.ts +++ b/src/dialogs/more-info/controls/more-info-weather.ts @@ -22,13 +22,13 @@ import { import { HassEntity } from "home-assistant-js-websocket"; import { css, - CSSResult, - customElement, + CSSResultGroup, + html, LitElement, - property, PropertyValues, -} from "lit-element"; -import { html, TemplateResult } from "lit-html"; + TemplateResult, +} from "lit"; +import { customElement, property } from "lit/decorators"; import { formatDateWeekday } from "../../../common/datetime/format_date"; import { formatTimeWeekday } from "../../../common/datetime/format_time"; import { formatNumber } from "../../../common/string/format_number"; @@ -224,7 +224,7 @@ class MoreInfoWeather extends LitElement { `; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` ha-svg-icon { color: var(--paper-item-icon-color); diff --git a/src/dialogs/more-info/ha-more-info-dialog.ts b/src/dialogs/more-info/ha-more-info-dialog.ts index 0e57bc9112..b5c72f87da 100644 --- a/src/dialogs/more-info/ha-more-info-dialog.ts +++ b/src/dialogs/more-info/ha-more-info-dialog.ts @@ -3,15 +3,9 @@ import "@material/mwc-icon-button"; import "@material/mwc-tab"; import "@material/mwc-tab-bar"; import { mdiClose, mdiCog, mdiPencil } from "@mdi/js"; -import { - css, - customElement, - html, - internalProperty, - LitElement, - property, -} from "lit-element"; -import { cache } from "lit-html/directives/cache"; +import { css, html, LitElement } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { cache } from "lit/directives/cache"; import { isComponentLoaded } from "../../common/config/is_component_loaded"; import { DOMAINS_MORE_INFO_NO_HISTORY, @@ -31,11 +25,11 @@ import { haStyleDialog } from "../../resources/styles"; import "../../state-summary/state-card-content"; import { HomeAssistant } from "../../types"; import { showConfirmationDialog } from "../generic/show-dialog-box"; +import { replaceDialog } from "../make-dialog-manager"; import "./controls/more-info-default"; import "./ha-more-info-history"; import "./ha-more-info-logbook"; import "./more-info-content"; -import { replaceDialog } from "../make-dialog-manager"; const DOMAINS_NO_INFO = ["camera", "configurator"]; /** @@ -58,9 +52,9 @@ export class MoreInfoDialog extends LitElement { @property({ type: Boolean, reflect: true }) public large = false; - @internalProperty() private _entityId?: string | null; + @state() private _entityId?: string | null; - @internalProperty() private _currTabIndex = 0; + @state() private _currTabIndex = 0; public showDialog(params: MoreInfoDialogParams) { this._entityId = params.entityId; @@ -312,7 +306,7 @@ export class MoreInfoDialog extends LitElement { idToPassThroughUrl = stateObj.attributes.id; } - navigate(this, `/config/${domain}/edit/${idToPassThroughUrl}`); + navigate(`/config/${domain}/edit/${idToPassThroughUrl}`); this.closeDialog(); } diff --git a/src/dialogs/more-info/ha-more-info-history.ts b/src/dialogs/more-info/ha-more-info-history.ts index eb393e3395..6dcb3144de 100644 --- a/src/dialogs/more-info/ha-more-info-history.ts +++ b/src/dialogs/more-info/ha-more-info-history.ts @@ -1,12 +1,5 @@ -import { - customElement, - html, - internalProperty, - LitElement, - property, - PropertyValues, - TemplateResult, -} from "lit-element"; +import { html, LitElement, PropertyValues, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { isComponentLoaded } from "../../common/config/is_component_loaded"; import { throttle } from "../../common/util/throttle"; import "../../components/state-history-charts"; @@ -20,7 +13,7 @@ export class MoreInfoHistory extends LitElement { @property() public entityId!: string; - @internalProperty() private _stateHistory?: HistoryResult; + @state() private _stateHistory?: HistoryResult; private _throttleGetStateHistory = throttle(() => { this._getStateHistory(); diff --git a/src/dialogs/more-info/ha-more-info-logbook.ts b/src/dialogs/more-info/ha-more-info-logbook.ts index 397dc10fc4..3a307e9370 100644 --- a/src/dialogs/more-info/ha-more-info-logbook.ts +++ b/src/dialogs/more-info/ha-more-info-logbook.ts @@ -1,24 +1,16 @@ -import { - css, - customElement, - html, - internalProperty, - LitElement, - property, - PropertyValues, - TemplateResult, -} from "lit-element"; +import { css, html, LitElement, PropertyValues, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { isComponentLoaded } from "../../common/config/is_component_loaded"; -import { closeDialog } from "../make-dialog-manager"; import { computeStateDomain } from "../../common/entity/compute_state_domain"; import { throttle } from "../../common/util/throttle"; import "../../components/ha-circular-progress"; import "../../components/state-history-charts"; -import { TraceContexts, loadTraceContexts } from "../../data/trace"; import { getLogbookData, LogbookEntry } from "../../data/logbook"; +import { loadTraceContexts, TraceContexts } from "../../data/trace"; import "../../panels/logbook/ha-logbook"; -import { haStyle, haStyleScrollbar } from "../../resources/styles"; +import { haStyle } from "../../resources/styles"; import { HomeAssistant } from "../../types"; +import { closeDialog } from "../make-dialog-manager"; @customElement("ha-more-info-logbook") export class MoreInfoLogbook extends LitElement { @@ -26,11 +18,11 @@ export class MoreInfoLogbook extends LitElement { @property() public entityId!: string; - @internalProperty() private _logbookEntries?: LogbookEntry[]; + @state() private _logbookEntries?: LogbookEntry[]; - @internalProperty() private _traceContexts?: TraceContexts; + @state() private _traceContexts?: TraceContexts; - @internalProperty() private _persons = {}; + @state() private _persons = {}; private _lastLogbookDate?: Date; @@ -60,7 +52,6 @@ export class MoreInfoLogbook extends LitElement { : this._logbookEntries.length ? html` ${scroll({ items, - renderItem: (item: QuickBarItem, index?: number) => + layout: Layout1d, + // @ts-expect-error + renderItem: (item: QuickBarItem, index) => this._renderItem(item, index), })} `} @@ -228,6 +223,9 @@ export class QuickBar extends LitElement { } private _renderItem(item: QuickBarItem, index?: number) { + if (!item) { + return undefined; + } return isCommandItem(item) ? this._renderCommandItem(item, index) : this._renderEntityItem(item as EntityItem, index); @@ -562,7 +560,7 @@ export class QuickBar extends LitElement { categoryText: this.hass.localize( `ui.dialogs.quick-bar.commands.types.${categoryKey}` ), - action: () => navigate(this, item.path), + action: () => navigate(item.path), }; return { diff --git a/src/dialogs/voice-command-dialog/ha-voice-command-dialog.ts b/src/dialogs/voice-command-dialog/ha-voice-command-dialog.ts index 31c573e52d..649c209678 100644 --- a/src/dialogs/voice-command-dialog/ha-voice-command-dialog.ts +++ b/src/dialogs/voice-command-dialog/ha-voice-command-dialog.ts @@ -4,17 +4,14 @@ import "@polymer/paper-input/paper-input"; import type { PaperInputElement } from "@polymer/paper-input/paper-input"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, - query, TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +} from "lit"; +import { customElement, property, state, query } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import { fireEvent } from "../../common/dom/fire_event"; import { SpeechRecognition } from "../../common/dom/speech-recognition"; import { uid } from "../../common/util/uid"; @@ -46,16 +43,16 @@ export class HaVoiceCommandDialog extends LitElement { @property() public results: Results | null = null; - @internalProperty() private _conversation: Message[] = [ + @state() private _conversation: Message[] = [ { who: "hass", text: "", }, ]; - @internalProperty() private _opened = false; + @state() private _opened = false; - @internalProperty() private _agentInfo?: AgentInfo; + @state() private _agentInfo?: AgentInfo; @query("#messages", true) private messages!: PaperDialogScrollableElement; @@ -120,9 +117,13 @@ export class HaVoiceCommandDialog extends LitElement { href="${this._agentInfo.onboarding.url}" target="_blank" rel="noreferrer" - >Yes!${this.hass.localize("ui.common.yes")}! + ${this.hass.localize("ui.common.no")} - No ` @@ -158,7 +159,7 @@ export class HaVoiceCommandDialog extends LitElement {
{ + const href = isNavigationClick(ev); + if (href) { + navigate(href); + } + }); } document.addEventListener( diff --git a/src/entrypoints/service_worker.ts b/src/entrypoints/service_worker.ts index 0748a15e1f..e3f141fa54 100644 --- a/src/entrypoints/service_worker.ts +++ b/src/entrypoints/service_worker.ts @@ -2,7 +2,9 @@ // eslint-disable-next-line spaced-comment /// /* eslint-env serviceworker */ +import { CacheableResponsePlugin } from "workbox-cacheable-response"; import { cacheNames, RouteHandler } from "workbox-core"; +import { ExpirationPlugin } from "workbox-expiration"; import { cleanupOutdatedCaches, precacheAndRoute } from "workbox-precaching"; import { registerRoute, setCatchHandler } from "workbox-routing"; import { @@ -10,8 +12,6 @@ import { NetworkOnly, StaleWhileRevalidate, } from "workbox-strategies"; -import { CacheableResponsePlugin } from "workbox-cacheable-response"; -import { ExpirationPlugin } from "workbox-expiration"; const noFallBackRegEx = new RegExp( "/(api|static|auth|frontend_latest|frontend_es5|local)/.*" diff --git a/src/fake_data/provide_hass.ts b/src/fake_data/provide_hass.ts index e74cb69152..d074f4c9ab 100644 --- a/src/fake_data/provide_hass.ts +++ b/src/fake_data/provide_hass.ts @@ -5,10 +5,10 @@ import { } from "../common/dom/apply_themes_on_element"; import { computeLocalize } from "../common/translations/localize"; import { DEFAULT_PANEL } from "../data/panel"; -import { NumberFormat } from "../data/translation"; +import { NumberFormat, TimeFormat } from "../data/translation"; import { translationMetadata } from "../resources/translations-metadata"; import { HomeAssistant } from "../types"; -import { getTranslation, getLocalLanguage } from "../util/hass-translation"; +import { getLocalLanguage, getTranslation } from "../util/hass-translation"; import { demoConfig } from "./demo_config"; import { demoPanels } from "./demo_panels"; import { demoServices } from "./demo_services"; @@ -215,6 +215,7 @@ export const provideHass = ( locale: { language: localLanguage, number_format: NumberFormat.language, + time_format: TimeFormat.language, }, resources: null as any, localize: () => "", @@ -276,7 +277,7 @@ export const provideHass = ( mockTheme(theme) { invalidateThemeCache(); hass().updateHass({ - selectedTheme: { theme: theme ? "mock" : "default" }, + selectedThemeSettings: { theme: theme ? "mock" : "default" }, themes: { ...hass().themes, themes: { @@ -284,11 +285,11 @@ export const provideHass = ( }, }, }); - const { themes, selectedTheme } = hass(); + const { themes, selectedThemeSettings } = hass(); applyThemesOnElement( document.documentElement, themes, - selectedTheme!.theme + selectedThemeSettings!.theme ); }, diff --git a/src/layouts/ha-init-page.ts b/src/layouts/ha-init-page.ts index e0fa8384c5..0a4e730fde 100644 --- a/src/layouts/ha-init-page.ts +++ b/src/layouts/ha-init-page.ts @@ -1,5 +1,6 @@ import "@material/mwc-button"; -import { css, CSSResult, html, LitElement, property } from "lit-element"; +import { css, CSSResultGroup, html, LitElement } from "lit"; +import { property } from "lit/decorators"; import "../components/ha-circular-progress"; import { removeInitSkeleton } from "../util/init-skeleton"; @@ -43,7 +44,7 @@ class HaInitPage extends LitElement { location.reload(); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` div { height: 100%; diff --git a/src/layouts/hass-error-screen.ts b/src/layouts/hass-error-screen.ts index b335218f03..de0b3f1fcf 100644 --- a/src/layouts/hass-error-screen.ts +++ b/src/layouts/hass-error-screen.ts @@ -1,16 +1,9 @@ import "@material/mwc-button"; -import { - css, - CSSResultArray, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import { HomeAssistant } from "../types"; -import "../components/ha-menu-button"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import "../components/ha-icon-button-arrow-prev"; +import "../components/ha-menu-button"; +import { HomeAssistant } from "../types"; @customElement("hass-error-screen") class HassErrorScreen extends LitElement { @@ -58,7 +51,7 @@ class HassErrorScreen extends LitElement { history.back(); } - static get styles(): CSSResultArray { + static get styles(): CSSResultGroup { return [ css` :host { diff --git a/src/layouts/hass-loading-screen.ts b/src/layouts/hass-loading-screen.ts index 763622b3c1..529659ba0a 100644 --- a/src/layouts/hass-loading-screen.ts +++ b/src/layouts/hass-loading-screen.ts @@ -1,13 +1,6 @@ import "@polymer/app-layout/app-toolbar/app-toolbar"; -import { - css, - CSSResultArray, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import "../components/ha-circular-progress"; import "../components/ha-icon-button-arrow-prev"; import "../components/ha-menu-button"; @@ -54,7 +47,7 @@ class HassLoadingScreen extends LitElement { history.back(); } - static get styles(): CSSResultArray { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/layouts/hass-router-page.ts b/src/layouts/hass-router-page.ts index 450e331a73..5c37cd577c 100644 --- a/src/layouts/hass-router-page.ts +++ b/src/layouts/hass-router-page.ts @@ -1,4 +1,5 @@ -import { property, PropertyValues, UpdatingElement } from "lit-element"; +import { PropertyValues, ReactiveElement } from "lit"; +import { property } from "lit/decorators"; import memoizeOne from "memoize-one"; import { navigate } from "../common/navigate"; import { Route } from "../types"; @@ -46,7 +47,7 @@ export interface RouterOptions { // Time to wait for code to load before we show loading screen. const LOADING_SCREEN_THRESHOLD = 400; // ms -export class HassRouterPage extends UpdatingElement { +export class HassRouterPage extends ReactiveElement { @property() public route?: Route; protected routerOptions!: RouterOptions; @@ -72,6 +73,10 @@ export class HassRouterPage extends UpdatingElement { }; }); + protected createRenderRoot() { + return this; + } + protected update(changedProps: PropertyValues) { super.update(changedProps); @@ -94,7 +99,7 @@ export class HassRouterPage extends UpdatingElement { const defaultPage = routerOptions.defaultPage; if (route && route.path === "" && defaultPage !== undefined) { - navigate(this, `${route.prefix}/${defaultPage}`, true); + navigate(`${route.prefix}/${defaultPage}`, { replace: true }); } let newPage = route @@ -122,7 +127,7 @@ export class HassRouterPage extends UpdatingElement { // Update the url if we know where we're mounted. if (route) { - navigate(this, `${route.prefix}/${result}`, true); + navigate(`${route.prefix}/${result}`, { replace: true }); } } } diff --git a/src/layouts/hass-subpage.ts b/src/layouts/hass-subpage.ts index 780fdb068b..58c4c376aa 100644 --- a/src/layouts/hass-subpage.ts +++ b/src/layouts/hass-subpage.ts @@ -1,13 +1,5 @@ -import { - css, - CSSResult, - customElement, - eventOptions, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, eventOptions, property } from "lit/decorators"; import { restoreScroll } from "../common/decorators/restore-scroll"; import "../components/ha-icon-button-arrow-prev"; import "../components/ha-menu-button"; @@ -62,7 +54,7 @@ class HassSubpage extends LitElement { history.back(); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { display: block; diff --git a/src/layouts/hass-tabs-subpage-data-table.ts b/src/layouts/hass-tabs-subpage-data-table.ts index 1c46a6caba..5ecfa2b722 100644 --- a/src/layouts/hass-tabs-subpage-data-table.ts +++ b/src/layouts/hass-tabs-subpage-data-table.ts @@ -1,17 +1,10 @@ import "@material/mwc-button/mwc-button"; import { mdiFilterVariant } from "@mdi/js"; import "@polymer/paper-tooltip/paper-tooltip"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - query, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, query } from "lit/decorators"; import { fireEvent } from "../common/dom/fire_event"; +import { LocalizeFunc } from "../common/translations/localize"; import { computeRTLDirection } from "../common/util/compute_rtl"; import "../components/data-table/ha-data-table"; import type { @@ -35,10 +28,16 @@ declare global { export class HaTabsSubpageDataTable extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; + @property({ attribute: false }) public localizeFunc?: LocalizeFunc; + @property({ type: Boolean }) public isWide = false; @property({ type: Boolean, reflect: true }) public narrow = false; + @property({ type: Boolean }) public supervisor = false; + + @property({ type: Boolean, attribute: "main-page" }) public mainPage = false; + /** * Object with the columns. * @type {Object} @@ -185,12 +184,15 @@ export class HaTabsSubpageDataTable extends LitElement { return html`
${this.narrow @@ -238,7 +240,7 @@ export class HaTabsSubpageDataTable extends LitElement { fireEvent(this, "clear-filter"); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` ha-data-table { width: 100%; diff --git a/src/layouts/hass-tabs-subpage.ts b/src/layouts/hass-tabs-subpage.ts index 23c599e613..ea691e1766 100644 --- a/src/layouts/hass-tabs-subpage.ts +++ b/src/layouts/hass-tabs-subpage.ts @@ -1,21 +1,17 @@ import "@material/mwc-ripple"; import { css, - CSSResult, - customElement, - eventOptions, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +} from "lit"; +import { customElement, eventOptions, property, state } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import memoizeOne from "memoize-one"; import { isComponentLoaded } from "../common/config/is_component_loaded"; import { restoreScroll } from "../common/decorators/restore-scroll"; -import { navigate } from "../common/navigate"; import { LocalizeFunc } from "../common/translations/localize"; import { computeRTL } from "../common/util/compute_rtl"; import "../components/ha-icon"; @@ -62,7 +58,7 @@ class HassTabsSubpage extends LitElement { @property({ type: Boolean, reflect: true }) public rtl = false; - @internalProperty() private _activeTab?: PageNavigation; + @state() private _activeTab?: PageNavigation; // @ts-ignore @restoreScroll(".content") private _savedScrollPos?: number; @@ -88,30 +84,29 @@ class HassTabsSubpage extends LitElement { return shownTabs.map( (page) => html` - - ${page.iconPath - ? html`` - : html``} - + + + ${page.iconPath + ? html`` + : html``} + + ` ); } ); - protected updated(changedProperties: PropertyValues) { - super.updated(changedProperties); + public willUpdate(changedProperties: PropertyValues) { if (changedProperties.has("route")) { this._activeTab = this.tabs.find((tab) => `${this.route.prefix}${this.route.path}`.includes(tab.path) @@ -125,6 +120,7 @@ class HassTabsSubpage extends LitElement { this.rtl = computeRTL(this.hass); } } + super.willUpdate(changedProperties); } protected render(): TemplateResult { @@ -148,6 +144,14 @@ class HassTabsSubpage extends LitElement { .narrow=${this.narrow} > ` + : this.backPath + ? html` + + + + ` : html` { + this.narrow = matches; + }); + } protected render(): TemplateResult { const hass = this.hass; - - if (!hass) { - return html``; - } - const sidebarNarrow = this._sidebarNarrow; - const disableSwipe = this._sidebarEditMode || !sidebarNarrow || @@ -144,13 +143,9 @@ class HomeAssistantMain extends LitElement { this.addEventListener("hass-show-notifications", () => { showNotificationDrawer(this, { - narrow: this.narrow!, + narrow: this.narrow, }); }); - - listenMediaQuery("(max-width: 870px)", (matches) => { - this.narrow = matches; - }); } protected updated(changedProps: PropertyValues) { @@ -186,7 +181,7 @@ class HomeAssistantMain extends LitElement { return this.shadowRoot!.querySelector("app-drawer-layout")!; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { color: var(--primary-text-color); diff --git a/src/layouts/home-assistant.ts b/src/layouts/home-assistant.ts index 42abe399ce..6b4004938d 100644 --- a/src/layouts/home-assistant.ts +++ b/src/layouts/home-assistant.ts @@ -1,10 +1,6 @@ -import "@polymer/app-route/app-location"; -import { - customElement, - html, - internalProperty, - PropertyValues, -} from "lit-element"; +import { isNavigationClick } from "../common/dom/is-navigation-click"; +import { html, PropertyValues } from "lit"; +import { customElement, state } from "lit/decorators"; import { navigate } from "../common/navigate"; import { getStorageDefaultPanelUrlPath } from "../data/panel"; import "../resources/custom-card-support"; @@ -19,13 +15,24 @@ import { import "./ha-init-page"; import "./home-assistant-main"; +const useHash = __DEMO__; +const curPath = () => + window.decodeURIComponent( + useHash ? location.hash.substr(1) : location.pathname + ); + +const panelUrl = (path: string) => { + const dividerPos = path.indexOf("/", 1); + return dividerPos === -1 ? path.substr(1) : path.substr(1, dividerPos - 1); +}; + @customElement("home-assistant") export class HomeAssistantAppEl extends QuickBarMixin(HassElement) { - @internalProperty() private _route?: Route; + @state() private _route: Route; - @internalProperty() private _error = false; + @state() private _error = false; - @internalProperty() private _panelUrl?: string; + private _panelUrl: string; private _haVersion?: string; @@ -33,30 +40,36 @@ export class HomeAssistantAppEl extends QuickBarMixin(HassElement) { private _visiblePromiseResolve?: () => void; + constructor() { + super(); + const path = curPath(); + + if (["", "/"].includes(path)) { + navigate(`/${getStorageDefaultPanelUrlPath()}`, { replace: true }); + } + this._route = { + prefix: "", + path, + }; + this._panelUrl = panelUrl(path); + } + protected render() { const hass = this.hass; - return html` - - ${this._panelUrl === undefined || this._route === undefined - ? "" - : hass && hass.states && hass.config && hass.services - ? html` - - ` - : html` `} - `; + return hass && hass.states && hass.config && hass.services + ? html` + + ` + : html``; } protected firstUpdated(changedProps) { super.firstUpdated(changedProps); - this._initialize(); + this._initializeHass(); setTimeout(() => registerServiceWorker(this), 1000); /* polyfill for paper-dropdown */ import("web-animations-js/web-animations-next-lite.min"); @@ -64,14 +77,42 @@ export class HomeAssistantAppEl extends QuickBarMixin(HassElement) { this._updateHass({ suspendWhenHidden: ev.detail.suspend }); storeState(this.hass!); }); + + // Navigation + const updateRoute = (path = curPath()) => { + if (this._route && path === this._route.path) { + return; + } + this._route = { + prefix: "", + path: path, + }; + + this._panelUrl = panelUrl(path); + this.panelUrlChanged(this._panelUrl!); + this._updateHass({ panelUrl: this._panelUrl }); + }; + + window.addEventListener("location-changed", () => updateRoute()); + + // Handle history changes + if (useHash) { + window.addEventListener("hashchange", () => updateRoute()); + } else { + window.addEventListener("popstate", () => updateRoute()); + } + + // Handle clicking on links + window.addEventListener("click", (ev) => { + const href = isNavigationClick(ev); + if (href) { + navigate(href); + } + }); } protected updated(changedProps: PropertyValues): void { super.updated(changedProps); - if (changedProps.has("_panelUrl")) { - this.panelUrlChanged(this._panelUrl!); - this._updateHass({ panelUrl: this._panelUrl }); - } if (changedProps.has("hass")) { this.hassChanged( this.hass!, @@ -113,7 +154,7 @@ export class HomeAssistantAppEl extends QuickBarMixin(HassElement) { } } - protected async _initialize() { + protected async _initializeHass() { try { let result; @@ -134,31 +175,6 @@ export class HomeAssistantAppEl extends QuickBarMixin(HassElement) { } } - private async _routeChanged(ev) { - // routeChangged event listener is called while we're doing the fist render, - // causing the update to be ignored. So delay it to next task (Lit render is sync). - await new Promise((resolve) => setTimeout(resolve, 0)); - - const route = ev.detail.value as Route; - // If it's the first route that we process, - // check if we should navigate away from / - if ( - this._route === undefined && - (route.path === "" || route.path === "/") - ) { - navigate(window, `/${getStorageDefaultPanelUrlPath()}`, true); - return; - } - - this._route = route; - - const dividerPos = route.path.indexOf("/", 1); - this._panelUrl = - dividerPos === -1 - ? route.path.substr(1) - : route.path.substr(1, dividerPos - 1); - } - protected _checkVisibility() { if (document.hidden) { // If the document is hidden, we will prevent reconnects until we are visible again diff --git a/src/layouts/partial-panel-resolver.ts b/src/layouts/partial-panel-resolver.ts index cbc3cdfefb..6035c27713 100644 --- a/src/layouts/partial-panel-resolver.ts +++ b/src/layouts/partial-panel-resolver.ts @@ -4,7 +4,8 @@ import { STATE_RUNNING, STATE_STARTING, } from "home-assistant-js-websocket"; -import { customElement, property, PropertyValues } from "lit-element"; +import { PropertyValues } from "lit"; +import { customElement, property } from "lit/decorators"; import { deepActiveElement } from "../common/dom/deep-active-element"; import { deepEqual } from "../common/util/deep-equal"; import { getDefaultPanel } from "../data/panel"; @@ -64,8 +65,8 @@ class PartialPanelResolver extends HassRouterPage { document.addEventListener("resume", () => this._checkVisibility()); } - protected updated(changedProps: PropertyValues) { - super.updated(changedProps); + public willUpdate(changedProps: PropertyValues) { + super.willUpdate(changedProps); if (!changedProps.has("hass")) { return; diff --git a/src/layouts/supervisor-error-screen.ts b/src/layouts/supervisor-error-screen.ts index dab453f236..29bafefbc8 100644 --- a/src/layouts/supervisor-error-screen.ts +++ b/src/layouts/supervisor-error-screen.ts @@ -1,20 +1,19 @@ -import "../components/ha-card"; import "@material/mwc-button"; import { css, - CSSResultArray, - customElement, + CSSResultGroup, html, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; -import { HomeAssistant } from "../types"; +} from "lit"; +import { customElement, property } from "lit/decorators"; +import { atLeastVersion } from "../common/config/version"; +import { applyThemesOnElement } from "../common/dom/apply_themes_on_element"; +import "../components/ha-card"; import "../resources/ha-style"; import { haStyle } from "../resources/styles"; -import { applyThemesOnElement } from "../common/dom/apply_themes_on_element"; -import { atLeastVersion } from "../common/config/version"; +import { HomeAssistant } from "../types"; import "./hass-subpage"; @customElement("supervisor-error-screen") @@ -82,25 +81,27 @@ class SupervisorErrorScreen extends LitElement { private _applyTheme() { let themeName: string; - let options: Partial | undefined; + let themeSettings: + | Partial + | undefined; if (atLeastVersion(this.hass.config.version, 0, 114)) { themeName = - this.hass.selectedTheme?.theme || + this.hass.selectedThemeSettings?.theme || (this.hass.themes.darkMode && this.hass.themes.default_dark_theme ? this.hass.themes.default_dark_theme! : this.hass.themes.default_theme); - options = this.hass.selectedTheme; - if (themeName === "default" && options?.dark === undefined) { - options = { - ...this.hass.selectedTheme, + themeSettings = this.hass.selectedThemeSettings; + if (themeName === "default" && themeSettings?.dark === undefined) { + themeSettings = { + ...this.hass.selectedThemeSettings, dark: this.hass.themes.darkMode, }; } } else { themeName = - ((this.hass.selectedTheme as unknown) as string) || + ((this.hass.selectedThemeSettings as unknown) as string) || this.hass.themes.default_theme; } @@ -108,11 +109,11 @@ class SupervisorErrorScreen extends LitElement { this.parentElement, this.hass.themes, themeName, - options + themeSettings ); } - static get styles(): CSSResultArray { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/managers/notification-manager.ts b/src/managers/notification-manager.ts index a282adfd78..7eb9b410cd 100644 --- a/src/managers/notification-manager.ts +++ b/src/managers/notification-manager.ts @@ -1,14 +1,6 @@ import "@material/mwc-button"; -import { - css, - CSSResult, - html, - internalProperty, - LitElement, - property, - query, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { property, state, query } from "lit/decorators"; import { computeRTL } from "../common/util/compute_rtl"; import "../components/ha-toast"; import type { HaToast } from "../components/ha-toast"; @@ -29,9 +21,9 @@ export interface ToastActionParams { class NotificationManager extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _action?: ToastActionParams; + @state() private _action?: ToastActionParams; - @internalProperty() private _noCancelOnOutsideClick = false; + @state() private _noCancelOnOutsideClick = false; @query("ha-toast") private _toast!: HaToast; @@ -80,7 +72,7 @@ class NotificationManager extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` ha-toast { display: flex; diff --git a/src/mixins/keyboard-shortcut-mixin.ts b/src/mixins/keyboard-shortcut-mixin.ts index 359f386dc8..c319135b94 100644 --- a/src/mixins/keyboard-shortcut-mixin.ts +++ b/src/mixins/keyboard-shortcut-mixin.ts @@ -1,4 +1,4 @@ -import { LitElement } from "lit-element"; +import { LitElement } from "lit"; import { Constructor } from "../types"; export const KeyboardShortcutMixin = >( diff --git a/src/mixins/lit-localize-lite-mixin.ts b/src/mixins/lit-localize-lite-mixin.ts index cc723a36ac..c9751e1837 100644 --- a/src/mixins/lit-localize-lite-mixin.ts +++ b/src/mixins/lit-localize-lite-mixin.ts @@ -1,7 +1,8 @@ -import { LitElement, property, PropertyValues } from "lit-element"; +import { LitElement, PropertyValues } from "lit"; +import { property } from "lit/decorators"; import { computeLocalize, LocalizeFunc } from "../common/translations/localize"; import { Constructor, Resources } from "../types"; -import { getTranslation, getLocalLanguage } from "../util/hass-translation"; +import { getLocalLanguage, getTranslation } from "../util/hass-translation"; const empty = () => ""; diff --git a/src/mixins/navigate-mixin.js b/src/mixins/navigate-mixin.js index 7b8764c65b..2a2f8aac5d 100644 --- a/src/mixins/navigate-mixin.js +++ b/src/mixins/navigate-mixin.js @@ -9,7 +9,7 @@ export default dedupingMixin( (superClass) => class extends superClass { navigate(...args) { - navigate(this, ...args); + navigate(...args); } } ); diff --git a/src/mixins/provide-hass-lit-mixin.ts b/src/mixins/provide-hass-lit-mixin.ts index ba9ab227c3..361d4e281c 100644 --- a/src/mixins/provide-hass-lit-mixin.ts +++ b/src/mixins/provide-hass-lit-mixin.ts @@ -1,11 +1,11 @@ -import { PropertyValues, UpdatingElement } from "lit-element"; +import { PropertyValues, ReactiveElement } from "lit"; import { Constructor, HomeAssistant } from "../types"; export interface ProvideHassElement { provideHass(element: HTMLElement); } -export const ProvideHassLitMixin = >( +export const ProvideHassLitMixin = >( superClass: T ) => class extends superClass { diff --git a/src/mixins/subscribe-mixin.ts b/src/mixins/subscribe-mixin.ts index 88c54eaf3c..701d524175 100644 --- a/src/mixins/subscribe-mixin.ts +++ b/src/mixins/subscribe-mixin.ts @@ -1,12 +1,13 @@ import { UnsubscribeFunc } from "home-assistant-js-websocket"; -import { property, PropertyValues, UpdatingElement } from "lit-element"; +import { PropertyValues, ReactiveElement } from "lit"; +import { property } from "lit/decorators"; import { Constructor, HomeAssistant } from "../types"; export interface HassSubscribeElement { hassSubscribe(): UnsubscribeFunc[]; } -export const SubscribeMixin = >( +export const SubscribeMixin = >( superClass: T ) => { class SubscribeClass extends superClass { diff --git a/src/onboarding/action-badge.ts b/src/onboarding/action-badge.ts index 45d69b0c72..e97c9c5bd8 100644 --- a/src/onboarding/action-badge.ts +++ b/src/onboarding/action-badge.ts @@ -1,12 +1,5 @@ -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import "../components/ha-icon"; @customElement("action-badge") @@ -31,7 +24,7 @@ class ActionBadge extends LitElement { `; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { display: inline-flex; diff --git a/src/onboarding/ha-onboarding.ts b/src/onboarding/ha-onboarding.ts index 64ff66bf5a..2a7c66bd9f 100644 --- a/src/onboarding/ha-onboarding.ts +++ b/src/onboarding/ha-onboarding.ts @@ -5,14 +5,9 @@ import { getAuth, subscribeConfig, } from "home-assistant-js-websocket"; -import { - customElement, - html, - internalProperty, - property, - PropertyValues, - TemplateResult, -} from "lit-element"; +import { html, PropertyValues, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { applyThemesOnElement } from "../common/dom/apply_themes_on_element"; import { HASSDomEvent } from "../common/dom/fire_event"; import { extractSearchParamsObject } from "../common/url/search-params"; import { subscribeOne } from "../common/util/subscribe-one"; @@ -29,10 +24,9 @@ import { litLocalizeLiteMixin } from "../mixins/lit-localize-lite-mixin"; import { HassElement } from "../state/hass-element"; import { HomeAssistant } from "../types"; import { registerServiceWorker } from "../util/register-service-worker"; +import "./onboarding-analytics"; import "./onboarding-create-user"; import "./onboarding-loading"; -import "./onboarding-analytics"; -import { applyThemesOnElement } from "../common/dom/apply_themes_on_element"; type OnboardingEvent = | { @@ -66,13 +60,13 @@ class HaOnboarding extends litLocalizeLiteMixin(HassElement) { public translationFragment = "page-onboarding"; - @internalProperty() private _loading = false; + @state() private _loading = false; - @internalProperty() private _restoring = false; + @state() private _restoring = false; - @internalProperty() private _supervisor?: boolean; + @state() private _supervisor?: boolean; - @internalProperty() private _steps?: OnboardingStep[]; + @state() private _steps?: OnboardingStep[]; protected render(): TemplateResult { const step = this._curStep()!; diff --git a/src/onboarding/integration-badge.ts b/src/onboarding/integration-badge.ts index 341c3f6219..7958ca7080 100644 --- a/src/onboarding/integration-badge.ts +++ b/src/onboarding/integration-badge.ts @@ -1,12 +1,5 @@ -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import "../components/ha-icon"; import { brandsUrl } from "../util/brands-url"; @@ -35,7 +28,7 @@ class IntegrationBadge extends LitElement { `; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { display: inline-flex; diff --git a/src/onboarding/onboarding-analytics.ts b/src/onboarding/onboarding-analytics.ts index 78c20b485f..60783b95f7 100644 --- a/src/onboarding/onboarding-analytics.ts +++ b/src/onboarding/onboarding-analytics.ts @@ -1,14 +1,6 @@ import "@material/mwc-button/mwc-button"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../common/dom/fire_event"; import { LocalizeFunc } from "../common/translations/localize"; import "../components/ha-analytics"; @@ -23,9 +15,9 @@ class OnboardingAnalytics extends LitElement { @property() public localize!: LocalizeFunc; - @internalProperty() private _error?: string; + @state() private _error?: string; - @internalProperty() private _analyticsDetails: Analytics = { + @state() private _analyticsDetails: Analytics = { preferences: {}, }; @@ -85,7 +77,7 @@ class OnboardingAnalytics extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` .error { color: var(--error-color); diff --git a/src/onboarding/onboarding-core-config.ts b/src/onboarding/onboarding-core-config.ts index a983a2288b..f1bc58a83d 100644 --- a/src/onboarding/onboarding-core-config.ts +++ b/src/onboarding/onboarding-core-config.ts @@ -3,16 +3,8 @@ import "@polymer/paper-input/paper-input"; import type { PaperInputElement } from "@polymer/paper-input/paper-input"; import "@polymer/paper-radio-button/paper-radio-button"; import "@polymer/paper-radio-group/paper-radio-group"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../common/dom/fire_event"; import type { LocalizeFunc } from "../common/translations/localize"; import "../components/map/ha-location-editor"; @@ -35,17 +27,17 @@ class OnboardingCoreConfig extends LitElement { @property() public onboardingLocalize!: LocalizeFunc; - @internalProperty() private _working = false; + @state() private _working = false; - @internalProperty() private _name!: ConfigUpdateValues["location_name"]; + @state() private _name!: ConfigUpdateValues["location_name"]; - @internalProperty() private _location!: [number, number]; + @state() private _location!: [number, number]; - @internalProperty() private _elevation!: string; + @state() private _elevation!: string; - @internalProperty() private _unitSystem!: ConfigUpdateValues["unit_system"]; + @state() private _unitSystem!: ConfigUpdateValues["unit_system"]; - @internalProperty() private _timeZone!: string; + @state() private _timeZone!: string; protected render(): TemplateResult { return html` @@ -278,7 +270,7 @@ class OnboardingCoreConfig extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` .row { display: flex; diff --git a/src/onboarding/onboarding-create-user.ts b/src/onboarding/onboarding-create-user.ts index 63cff1ca6e..c0c23aafdc 100644 --- a/src/onboarding/onboarding-create-user.ts +++ b/src/onboarding/onboarding-create-user.ts @@ -3,15 +3,13 @@ import "@polymer/paper-input/paper-input"; import { genClientId } from "home-assistant-js-websocket"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../common/dom/fire_event"; import { LocalizeFunc } from "../common/translations/localize"; import { onboardUserStep } from "../data/onboarding"; @@ -23,17 +21,17 @@ class OnboardingCreateUser extends LitElement { @property() public language!: string; - @internalProperty() private _name = ""; + @state() private _name = ""; - @internalProperty() private _username = ""; + @state() private _username = ""; - @internalProperty() private _password = ""; + @state() private _password = ""; - @internalProperty() private _passwordConfirm = ""; + @state() private _passwordConfirm = ""; - @internalProperty() private _loading = false; + @state() private _loading = false; - @internalProperty() private _errorMsg?: string = undefined; + @state() private _errorMsg?: string = undefined; protected render(): TemplateResult { return html` @@ -199,7 +197,7 @@ class OnboardingCreateUser extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` .error { color: red; diff --git a/src/onboarding/onboarding-integrations.ts b/src/onboarding/onboarding-integrations.ts index 0ea9a94ff5..9426c88ad4 100644 --- a/src/onboarding/onboarding-integrations.ts +++ b/src/onboarding/onboarding-integrations.ts @@ -1,15 +1,13 @@ import "@material/mwc-button/mwc-button"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, LitElement, - property, - internalProperty, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../common/dom/fire_event"; import { compare } from "../common/string/compare"; import { LocalizeFunc } from "../common/translations/localize"; @@ -37,9 +35,9 @@ class OnboardingIntegrations extends LitElement { @property() public onboardingLocalize!: LocalizeFunc; - @internalProperty() private _entries?: ConfigEntry[]; + @state() private _entries?: ConfigEntry[]; - @internalProperty() private _discovered?: DataEntryFlowProgress[]; + @state() private _discovered?: DataEntryFlowProgress[]; private _unsubEvents?: () => void; @@ -175,7 +173,7 @@ class OnboardingIntegrations extends LitElement { }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` .badges { margin-top: 24px; diff --git a/src/onboarding/onboarding-loading.ts b/src/onboarding/onboarding-loading.ts index 96703c6a6c..e9182332ec 100644 --- a/src/onboarding/onboarding-loading.ts +++ b/src/onboarding/onboarding-loading.ts @@ -1,11 +1,5 @@ -import { - css, - CSSResult, - customElement, - html, - LitElement, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement } from "lit/decorators"; @customElement("onboarding-loading") class OnboardingLoading extends LitElement { @@ -13,7 +7,7 @@ class OnboardingLoading extends LitElement { return html`
`; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` /* MIT License (MIT). Copyright (c) 2014 Luke Haas */ .loader, diff --git a/src/onboarding/onboarding-restore-snapshot.ts b/src/onboarding/onboarding-restore-snapshot.ts index 6fb86da28e..32d604c7ac 100644 --- a/src/onboarding/onboarding-restore-snapshot.ts +++ b/src/onboarding/onboarding-restore-snapshot.ts @@ -1,13 +1,6 @@ import "@material/mwc-button/mwc-button"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import "../../hassio/src/components/hassio-ansi-to-html"; import { showHassioSnapshotDialog } from "../../hassio/src/dialogs/snapshot/show-dialog-hassio-snapshot"; import { showSnapshotUploadDialog } from "../../hassio/src/dialogs/snapshot/show-dialog-snapshot-upload"; @@ -70,7 +63,7 @@ class OnboardingRestoreSnapshot extends ProvideHassLitMixin(LitElement) { }); if (response.status === 401) { // If we get a unauthorized response, the restore is done - navigate(this, "/", true); + navigate("/", { replace: true }); location.reload(); } } catch (err) { @@ -86,7 +79,7 @@ class OnboardingRestoreSnapshot extends ProvideHassLitMixin(LitElement) { }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/calendar/ha-full-calendar.ts b/src/panels/calendar/ha-full-calendar.ts index 9d11cff9d2..5b737d529c 100644 --- a/src/panels/calendar/ha-full-calendar.ts +++ b/src/panels/calendar/ha-full-calendar.ts @@ -14,15 +14,14 @@ import "@material/mwc-button"; import { mdiViewAgenda, mdiViewDay, mdiViewModule, mdiViewWeek } from "@mdi/js"; import { css, - CSSResult, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, unsafeCSS, -} from "lit-element"; +} from "lit"; +import { property, state } from "lit/decorators"; import memoize from "memoize-one"; import { fireEvent } from "../../common/dom/fire_event"; import "../../components/ha-button-toggle-group"; @@ -91,9 +90,9 @@ export class HAFullCalendar extends LitElement { @property() public initialView: FullCalendarView = "dayGridMonth"; - @internalProperty() private calendar?: Calendar; + private calendar?: Calendar; - @internalProperty() private _activeView?: FullCalendarView; + @state() private _activeView = this.initialView; public updateSize(): void { this.calendar?.updateSize(); @@ -182,8 +181,8 @@ export class HAFullCalendar extends LitElement { `; } - protected updated(changedProps: PropertyValues): void { - super.updated(changedProps); + public willUpdate(changedProps: PropertyValues): void { + super.willUpdate(changedProps); if (!this.calendar) { return; @@ -217,8 +216,6 @@ export class HAFullCalendar extends LitElement { initialView: this.initialView, }; - this._activeView = this.initialView; - config.dateClick = (info) => this._handleDateClick(info); config.eventClick = (info) => this._handleEventClick(info); @@ -285,7 +282,7 @@ export class HAFullCalendar extends LitElement { ) ); - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/calendar/ha-panel-calendar.ts b/src/panels/calendar/ha-panel-calendar.ts index 636c9fb117..91cad5b3a6 100644 --- a/src/panels/calendar/ha-panel-calendar.ts +++ b/src/panels/calendar/ha-panel-calendar.ts @@ -4,16 +4,14 @@ import "@polymer/app-layout/app-header/app-header"; import "@polymer/app-layout/app-toolbar/app-toolbar"; import { css, - CSSResultArray, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; -import { styleMap } from "lit-html/directives/style-map"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { styleMap } from "lit/directives/style-map"; import { LocalStorage } from "../../common/decorators/local-storage"; import { HASSDomEvent } from "../../common/dom/fire_event"; import "../../components/ha-card"; @@ -39,9 +37,9 @@ class PanelCalendar extends LitElement { @property({ type: Boolean, reflect: true }) public narrow!: boolean; - @internalProperty() private _calendars: Calendar[] = []; + @state() private _calendars: Calendar[] = []; - @internalProperty() private _events: CalendarEvent[] = []; + @state() private _events: CalendarEvent[] = []; @LocalStorage("deSelectedCalendars", true) private _deSelectedCalendars: string[] = []; @@ -50,9 +48,11 @@ class PanelCalendar extends LitElement { private _end?: Date; - protected firstUpdated(changedProps: PropertyValues): void { - super.firstUpdated(changedProps); - this._calendars = getCalendars(this.hass); + public willUpdate(changedProps: PropertyValues): void { + super.willUpdate(changedProps); + if (!this.hasUpdated) { + this._calendars = getCalendars(this.hass); + } } protected render(): TemplateResult { @@ -175,7 +175,7 @@ class PanelCalendar extends LitElement { ); } - static get styles(): CSSResultArray { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/areas/dialog-area-registry-detail.ts b/src/panels/config/areas/dialog-area-registry-detail.ts index e0c5c48467..0add7268b5 100644 --- a/src/panels/config/areas/dialog-area-registry-detail.ts +++ b/src/panels/config/areas/dialog-area-registry-detail.ts @@ -1,15 +1,8 @@ import "@material/mwc-button"; import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable"; import "@polymer/paper-input/paper-input"; -import { - css, - CSSResult, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { property, state } from "lit/decorators"; import { fireEvent } from "../../../common/dom/fire_event"; import { navigate } from "../../../common/navigate"; import "../../../components/ha-dialog"; @@ -22,13 +15,13 @@ import { AreaRegistryDetailDialogParams } from "./show-dialog-area-registry-deta class DialogAreaDetail extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _name!: string; + @state() private _name!: string; - @internalProperty() private _error?: string; + @state() private _error?: string; - @internalProperty() private _params?: AreaRegistryDetailDialogParams; + @state() private _params?: AreaRegistryDetailDialogParams; - @internalProperty() private _submitting?: boolean; + @state() private _submitting?: boolean; public async showDialog( params: AreaRegistryDetailDialogParams @@ -156,10 +149,10 @@ class DialogAreaDetail extends LitElement { this._submitting = false; } - navigate(this, "/config/areas/dashboard"); + navigate("/config/areas/dashboard"); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyleDialog, css` diff --git a/src/panels/config/areas/ha-config-area-page.ts b/src/panels/config/areas/ha-config-area-page.ts index d1356ef014..6b3e35a783 100644 --- a/src/panels/config/areas/ha-config-area-page.ts +++ b/src/panels/config/areas/ha-config-area-page.ts @@ -1,15 +1,7 @@ import "@material/mwc-button"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import { ifDefined } from "lit-html/directives/if-defined"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { ifDefined } from "lit/directives/if-defined"; import memoizeOne from "memoize-one"; import { isComponentLoaded } from "../../../common/config/is_component_loaded"; import { computeStateName } from "../../../common/entity/compute_state_name"; @@ -58,7 +50,7 @@ class HaConfigAreaPage extends LitElement { @property() public route!: Route; - @internalProperty() private _related?: RelatedResult; + @state() private _related?: RelatedResult; private _area = memoizeOne((areaId: string, areas: AreaRegistryEntry[]): | AreaRegistryEntry @@ -215,27 +207,27 @@ class HaConfigAreaPage extends LitElement { )} >${this._related?.automation?.length ? this._related.automation.map((automation) => { - const state = this.hass.states[automation]; - return state + const entityState = this.hass.states[automation]; + return entityState ? html`
- ${computeStateName(state)} + ${computeStateName(entityState)} - ${!state.attributes.id + ${!entityState.attributes.id ? html` ${this.hass.localize( @@ -268,27 +260,27 @@ class HaConfigAreaPage extends LitElement { )} >${this._related?.scene?.length ? this._related.scene.map((scene) => { - const state = this.hass.states[scene]; - return state + const entityState = this.hass.states[scene]; + return entityState ? html`
- ${computeStateName(state)} + ${computeStateName(entityState)} - ${!state.attributes.id + ${!entityState.attributes.id ? html` ${this.hass.localize( @@ -319,15 +311,15 @@ class HaConfigAreaPage extends LitElement { )} >${this._related?.script?.length ? this._related.script.map((script) => { - const state = this.hass.states[script]; - return state + const entityState = this.hass.states[script]; + return entityState ? html` - ${computeStateName(state)} + ${computeStateName(entityState)} @@ -399,7 +391,7 @@ class HaConfigAreaPage extends LitElement { }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/areas/ha-config-areas-dashboard.ts b/src/panels/config/areas/ha-config-areas-dashboard.ts index 7ba5201c97..92bdbe225b 100644 --- a/src/panels/config/areas/ha-config-areas-dashboard.ts +++ b/src/panels/config/areas/ha-config-areas-dashboard.ts @@ -1,15 +1,8 @@ import { mdiPlus } from "@mdi/js"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-item/paper-item-body"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import memoizeOne from "memoize-one"; import { HASSDomEvent } from "../../../common/dom/fire_event"; import { navigate } from "../../../common/navigate"; @@ -199,7 +192,7 @@ export class HaConfigAreasDashboard extends LitElement { private _handleRowClicked(ev: HASSDomEvent) { const areaId = ev.detail.id; - navigate(this, `/config/areas/area/${areaId}`); + navigate(`/config/areas/area/${areaId}`); } private _openDialog(entry?: AreaRegistryEntry) { @@ -210,7 +203,7 @@ export class HaConfigAreasDashboard extends LitElement { }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` hass-loading-screen { --app-header-background-color: var(--sidebar-background-color); diff --git a/src/panels/config/areas/ha-config-areas.ts b/src/panels/config/areas/ha-config-areas.ts index c742b304d0..dd9378e321 100644 --- a/src/panels/config/areas/ha-config-areas.ts +++ b/src/panels/config/areas/ha-config-areas.ts @@ -1,10 +1,6 @@ import { UnsubscribeFunc } from "home-assistant-js-websocket"; -import { - customElement, - internalProperty, - property, - PropertyValues, -} from "lit-element"; +import { PropertyValues } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { compare } from "../../../common/string/compare"; import { AreaRegistryEntry, @@ -50,15 +46,15 @@ class HaConfigAreas extends HassRouterPage { }, }; - @internalProperty() private _configEntries: ConfigEntry[] = []; + @state() private _configEntries: ConfigEntry[] = []; - @internalProperty() + @state() private _deviceRegistryEntries: DeviceRegistryEntry[] = []; - @internalProperty() + @state() private _entityRegistryEntries: EntityRegistryEntry[] = []; - @internalProperty() private _areas: AreaRegistryEntry[] = []; + @state() private _areas: AreaRegistryEntry[] = []; private _unsubs?: UnsubscribeFunc[]; diff --git a/src/panels/config/automation/action/ha-automation-action-row.ts b/src/panels/config/automation/action/ha-automation-action-row.ts index 87556b3a75..96719a003f 100644 --- a/src/panels/config/automation/action/ha-automation-action-row.ts +++ b/src/panels/config/automation/action/ha-automation-action-row.ts @@ -6,19 +6,11 @@ import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; import type { PaperListboxElement } from "@polymer/paper-listbox/paper-listbox"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - PropertyValues, - query, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit"; +import { customElement, property, state, query } from "lit/decorators"; import { dynamicElement } from "../../../../common/dom/dynamic-element-directive"; import { fireEvent } from "../../../../common/dom/fire_event"; +import { handleStructError } from "../../../../common/structs/handle-errors"; import "../../../../components/ha-button-menu"; import "../../../../components/ha-card"; import "../../../../components/ha-svg-icon"; @@ -27,7 +19,6 @@ import type { Action } from "../../../../data/script"; import { showConfirmationDialog } from "../../../../dialogs/generic/show-dialog-box"; import { haStyle } from "../../../../resources/styles"; import type { HomeAssistant } from "../../../../types"; -import { handleStructError } from "../../../../common/structs/handle-errors"; import "./types/ha-automation-action-choose"; import "./types/ha-automation-action-condition"; import "./types/ha-automation-action-delay"; @@ -99,11 +90,11 @@ export default class HaAutomationActionRow extends LitElement { @property({ type: Boolean }) public narrow = false; - @internalProperty() private _warnings?: string[]; + @state() private _warnings?: string[]; - @internalProperty() private _uiModeAvailable = true; + @state() private _uiModeAvailable = true; - @internalProperty() private _yamlMode = false; + @state() private _yamlMode = false; @query("ha-yaml-editor") private _yamlEditor?: HaYamlEditor; @@ -339,7 +330,7 @@ export default class HaAutomationActionRow extends LitElement { this._yamlMode = !this._yamlMode; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/automation/action/ha-automation-action.ts b/src/panels/config/automation/action/ha-automation-action.ts index 568dc9676b..dfdf25b215 100644 --- a/src/panels/config/automation/action/ha-automation-action.ts +++ b/src/panels/config/automation/action/ha-automation-action.ts @@ -1,12 +1,6 @@ import "@material/mwc-button"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../../../common/dom/fire_event"; import "../../../../components/ha-card"; import { Action } from "../../../../data/script"; @@ -90,7 +84,7 @@ export default class HaAutomationAction extends LitElement { }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` ha-automation-action-row, ha-card { diff --git a/src/panels/config/automation/action/types/ha-automation-action-choose.ts b/src/panels/config/automation/action/types/ha-automation-action-choose.ts index 2a04f9e022..584d217b90 100644 --- a/src/panels/config/automation/action/types/ha-automation-action-choose.ts +++ b/src/panels/config/automation/action/types/ha-automation-action-choose.ts @@ -1,14 +1,8 @@ import { mdiDelete } from "@mdi/js"; import "@polymer/paper-input/paper-input"; import "@polymer/paper-listbox/paper-listbox"; -import { - css, - CSSResult, - customElement, - LitElement, - property, -} from "lit-element"; -import { html } from "lit-html"; +import { css, CSSResultGroup, html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../../../../common/dom/fire_event"; import { ensureArray } from "../../../../../common/ensure-array"; import { Condition } from "../../../../../data/automation"; @@ -156,7 +150,7 @@ export class HaChooseAction extends LitElement implements ActionElement { }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/automation/action/types/ha-automation-action-condition.ts b/src/panels/config/automation/action/types/ha-automation-action-condition.ts index 03eb234832..6509d71c6c 100644 --- a/src/panels/config/automation/action/types/ha-automation-action-condition.ts +++ b/src/panels/config/automation/action/types/ha-automation-action-condition.ts @@ -1,4 +1,5 @@ -import { customElement, html, LitElement, property } from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../../../../common/dom/fire_event"; import { Condition } from "../../../../../data/automation"; import { HomeAssistant } from "../../../../../types"; diff --git a/src/panels/config/automation/action/types/ha-automation-action-delay.ts b/src/panels/config/automation/action/types/ha-automation-action-delay.ts index b805a68b2d..ab9a3ed8ab 100644 --- a/src/panels/config/automation/action/types/ha-automation-action-delay.ts +++ b/src/panels/config/automation/action/types/ha-automation-action-delay.ts @@ -1,11 +1,6 @@ import "@polymer/paper-input/paper-input"; -import { - customElement, - html, - LitElement, - property, - PropertyValues, -} from "lit-element"; +import { html, LitElement, PropertyValues } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../../../../common/dom/fire_event"; import { hasTemplate } from "../../../../../common/string/has-template"; import "../../../../../components/entity/ha-entity-picker"; diff --git a/src/panels/config/automation/action/types/ha-automation-action-device_id.ts b/src/panels/config/automation/action/types/ha-automation-action-device_id.ts index 051b3a8889..1a4565f870 100644 --- a/src/panels/config/automation/action/types/ha-automation-action-device_id.ts +++ b/src/panels/config/automation/action/types/ha-automation-action-device_id.ts @@ -1,10 +1,5 @@ -import { - customElement, - html, - internalProperty, - LitElement, - property, -} from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import { fireEvent } from "../../../../../common/dom/fire_event"; import "../../../../../components/device/ha-device-action-picker"; @@ -24,9 +19,9 @@ export class HaDeviceAction extends LitElement { @property({ type: Object }) public action!: DeviceAction; - @internalProperty() private _deviceId?: string; + @state() private _deviceId?: string; - @internalProperty() private _capabilities?: DeviceCapabilities; + @state() private _capabilities?: DeviceCapabilities; private _origAction?: DeviceAction; diff --git a/src/panels/config/automation/action/types/ha-automation-action-event.ts b/src/panels/config/automation/action/types/ha-automation-action-event.ts index 81fc2c10da..92b64fe634 100644 --- a/src/panels/config/automation/action/types/ha-automation-action-event.ts +++ b/src/panels/config/automation/action/types/ha-automation-action-event.ts @@ -1,12 +1,6 @@ import "@polymer/paper-input/paper-input"; -import { - customElement, - LitElement, - property, - PropertyValues, - query, -} from "lit-element"; -import { html } from "lit-html"; +import { html, LitElement, PropertyValues } from "lit"; +import { customElement, property, query } from "lit/decorators"; import { fireEvent } from "../../../../../common/dom/fire_event"; import "../../../../../components/entity/ha-entity-picker"; import "../../../../../components/ha-service-picker"; diff --git a/src/panels/config/automation/action/types/ha-automation-action-repeat.ts b/src/panels/config/automation/action/types/ha-automation-action-repeat.ts index 807aa2fefa..07249aeaf8 100644 --- a/src/panels/config/automation/action/types/ha-automation-action-repeat.ts +++ b/src/panels/config/automation/action/types/ha-automation-action-repeat.ts @@ -1,8 +1,8 @@ import "@polymer/paper-input/paper-input"; import type { PaperListboxElement } from "@polymer/paper-listbox"; import "@polymer/paper-listbox/paper-listbox"; -import { CSSResult, customElement, LitElement, property } from "lit-element"; -import { html } from "lit-html"; +import { CSSResultGroup, html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../../../../common/dom/fire_event"; import { Action, @@ -165,7 +165,7 @@ export class HaRepeatAction extends LitElement implements ActionElement { }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return haStyle; } } diff --git a/src/panels/config/automation/action/types/ha-automation-action-scene.ts b/src/panels/config/automation/action/types/ha-automation-action-scene.ts index 9b0610b187..6af3f06c40 100644 --- a/src/panels/config/automation/action/types/ha-automation-action-scene.ts +++ b/src/panels/config/automation/action/types/ha-automation-action-scene.ts @@ -1,4 +1,5 @@ -import { customElement, html, LitElement, property } from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../../../../common/dom/fire_event"; import "../../../../../components/entity/ha-entity-picker"; import { SceneAction } from "../../../../../data/script"; diff --git a/src/panels/config/automation/action/types/ha-automation-action-service.ts b/src/panels/config/automation/action/types/ha-automation-action-service.ts index 4930c86b9b..eafbc88b60 100644 --- a/src/panels/config/automation/action/types/ha-automation-action-service.ts +++ b/src/panels/config/automation/action/types/ha-automation-action-service.ts @@ -1,26 +1,18 @@ import "@polymer/paper-input/paper-input"; -import { - css, - CSSResult, - customElement, - internalProperty, - LitElement, - property, - PropertyValues, -} from "lit-element"; -import { html } from "lit-html"; +import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { any, assert, object, optional, string } from "superstruct"; import { fireEvent } from "../../../../../common/dom/fire_event"; +import { hasTemplate } from "../../../../../common/string/has-template"; +import { entityIdOrAll } from "../../../../../common/structs/is-entity-id"; +import "../../../../../components/ha-service-control"; import { ServiceAction } from "../../../../../data/script"; import type { HomeAssistant } from "../../../../../types"; -import { EntityIdOrAll } from "../../../../../common/structs/is-entity-id"; import { ActionElement } from "../ha-automation-action-row"; -import "../../../../../components/ha-service-control"; -import { hasTemplate } from "../../../../../common/string/has-template"; const actionStruct = object({ service: optional(string()), - entity_id: optional(EntityIdOrAll), + entity_id: optional(entityIdOrAll()), target: optional(any()), data: optional(any()), }); @@ -33,7 +25,7 @@ export class HaServiceAction extends LitElement implements ActionElement { @property({ type: Boolean }) public narrow = false; - @internalProperty() private _action!: ServiceAction; + @state() private _action!: ServiceAction; public static get defaultConfig() { return { service: "", data: {} }; @@ -86,7 +78,7 @@ export class HaServiceAction extends LitElement implements ActionElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` ha-service-control { display: block; diff --git a/src/panels/config/automation/action/types/ha-automation-action-wait_for_trigger.ts b/src/panels/config/automation/action/types/ha-automation-action-wait_for_trigger.ts index 0d28d05c77..223eb40d9c 100644 --- a/src/panels/config/automation/action/types/ha-automation-action-wait_for_trigger.ts +++ b/src/panels/config/automation/action/types/ha-automation-action-wait_for_trigger.ts @@ -1,7 +1,7 @@ import "@polymer/paper-input/paper-input"; import "@polymer/paper-input/paper-textarea"; -import { customElement, LitElement, property } from "lit-element"; -import { html } from "lit-html"; +import { html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../../../../common/dom/fire_event"; import "../../../../../components/ha-formfield"; import { WaitForTriggerAction } from "../../../../../data/script"; diff --git a/src/panels/config/automation/action/types/ha-automation-action-wait_template.ts b/src/panels/config/automation/action/types/ha-automation-action-wait_template.ts index ed6326a381..62e7a5bbb9 100644 --- a/src/panels/config/automation/action/types/ha-automation-action-wait_template.ts +++ b/src/panels/config/automation/action/types/ha-automation-action-wait_template.ts @@ -1,7 +1,7 @@ import "@polymer/paper-input/paper-input"; import "@polymer/paper-input/paper-textarea"; -import { customElement, LitElement, property } from "lit-element"; -import { html } from "lit-html"; +import { html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../../../../common/dom/fire_event"; import { WaitAction } from "../../../../../data/script"; import { HomeAssistant } from "../../../../../types"; diff --git a/src/panels/config/automation/blueprint-automation-editor.ts b/src/panels/config/automation/blueprint-automation-editor.ts index 75a7019d27..a7ccc8c07c 100644 --- a/src/panels/config/automation/blueprint-automation-editor.ts +++ b/src/panels/config/automation/blueprint-automation-editor.ts @@ -2,15 +2,8 @@ import "@material/mwc-button/mwc-button"; import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light"; import "@polymer/paper-input/paper-textarea"; import { HassEntity } from "home-assistant-js-websocket"; -import { - css, - CSSResult, - customElement, - internalProperty, - LitElement, - property, -} from "lit-element"; -import { html } from "lit-html"; +import { css, CSSResultGroup, html, LitElement } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../../common/dom/fire_event"; import "../../../components/entity/ha-entity-toggle"; import "../../../components/ha-blueprint-picker"; @@ -44,7 +37,7 @@ export class HaBlueprintAutomationEditor extends LitElement { @property() public stateObj?: HassEntity; - @internalProperty() private _blueprints?: Blueprints; + @state() private _blueprints?: Blueprints; protected firstUpdated(changedProps) { super.firstUpdated(changedProps); @@ -270,7 +263,7 @@ export class HaBlueprintAutomationEditor extends LitElement { }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/automation/condition/ha-automation-condition-editor.ts b/src/panels/config/automation/condition/ha-automation-condition-editor.ts index e7a1c2f691..014e40c55b 100644 --- a/src/panels/config/automation/condition/ha-automation-condition-editor.ts +++ b/src/panels/config/automation/condition/ha-automation-condition-editor.ts @@ -2,13 +2,8 @@ import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; import type { PaperListboxElement } from "@polymer/paper-listbox/paper-listbox"; -import { - CSSResult, - customElement, - html, - LitElement, - property, -} from "lit-element"; +import { CSSResultGroup, html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { dynamicElement } from "../../../../common/dom/dynamic-element-directive"; import { fireEvent } from "../../../../common/dom/fire_event"; import "../../../../components/ha-card"; @@ -134,7 +129,7 @@ export default class HaAutomationConditionEditor extends LitElement { fireEvent(this, "value-changed", { value: ev.detail.value }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return haStyle; } } diff --git a/src/panels/config/automation/condition/ha-automation-condition-row.ts b/src/panels/config/automation/condition/ha-automation-condition-row.ts index 6b824a60fc..8015055358 100644 --- a/src/panels/config/automation/condition/ha-automation-condition-row.ts +++ b/src/panels/config/automation/condition/ha-automation-condition-row.ts @@ -2,24 +2,17 @@ import { ActionDetail } from "@material/mwc-list/mwc-list-foundation"; import "@material/mwc-list/mwc-list-item"; import { mdiDotsVertical } from "@mdi/js"; import "@polymer/paper-item/paper-item"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../../../common/dom/fire_event"; import "../../../../components/ha-button-menu"; import "../../../../components/ha-card"; import "../../../../components/ha-icon-button"; import { Condition } from "../../../../data/automation"; import { showConfirmationDialog } from "../../../../dialogs/generic/show-dialog-box"; +import { haStyle } from "../../../../resources/styles"; import { HomeAssistant } from "../../../../types"; import "./ha-automation-condition-editor"; -import { haStyle } from "../../../../resources/styles"; export interface ConditionElement extends LitElement { condition: Condition; @@ -56,7 +49,7 @@ export default class HaAutomationConditionRow extends LitElement { @property() public condition!: Condition; - @internalProperty() private _yamlMode = false; + @state() private _yamlMode = false; protected render() { if (!this.condition) { @@ -135,7 +128,7 @@ export default class HaAutomationConditionRow extends LitElement { this._yamlMode = !this._yamlMode; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/automation/condition/ha-automation-condition.ts b/src/panels/config/automation/condition/ha-automation-condition.ts index b4529c4650..513ca4c361 100644 --- a/src/panels/config/automation/condition/ha-automation-condition.ts +++ b/src/panels/config/automation/condition/ha-automation-condition.ts @@ -1,13 +1,6 @@ import "@material/mwc-button"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - PropertyValues, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../../../common/dom/fire_event"; import "../../../../components/ha-card"; import { Condition } from "../../../../data/automation"; @@ -107,7 +100,7 @@ export default class HaAutomationCondition extends LitElement { }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` ha-automation-condition-row, ha-card { diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-and.ts b/src/panels/config/automation/condition/types/ha-automation-condition-and.ts index 92148e5ffb..482d593d91 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-and.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-and.ts @@ -1,4 +1,4 @@ -import { customElement } from "lit-element"; +import { customElement } from "lit/decorators"; import { HaLogicalCondition } from "./ha-automation-condition-logical"; @customElement("ha-automation-condition-and") diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-device.ts b/src/panels/config/automation/condition/types/ha-automation-condition-device.ts index 4470724548..74277a4680 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-device.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-device.ts @@ -1,10 +1,5 @@ -import { - customElement, - html, - internalProperty, - LitElement, - property, -} from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import { fireEvent } from "../../../../../common/dom/fire_event"; import "../../../../../components/device/ha-device-condition-picker"; @@ -24,9 +19,9 @@ export class HaDeviceCondition extends LitElement { @property({ type: Object }) public condition!: DeviceCondition; - @internalProperty() private _deviceId?: string; + @state() private _deviceId?: string; - @internalProperty() private _capabilities?: DeviceCapabilities; + @state() private _capabilities?: DeviceCapabilities; private _origCondition?: DeviceCondition; diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-logical.ts b/src/panels/config/automation/condition/types/ha-automation-condition-logical.ts index 6d6fc40f77..47fbba8de6 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-logical.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-logical.ts @@ -1,4 +1,5 @@ -import { customElement, html, LitElement, property } from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../../../../common/dom/fire_event"; import { LogicalCondition } from "../../../../../data/automation"; import { HomeAssistant } from "../../../../../types"; diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-not.ts b/src/panels/config/automation/condition/types/ha-automation-condition-not.ts index 586346765e..82f8a95049 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-not.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-not.ts @@ -1,4 +1,4 @@ -import { customElement } from "lit-element"; +import { customElement } from "lit/decorators"; import { HaLogicalCondition } from "./ha-automation-condition-logical"; @customElement("ha-automation-condition-not") diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-numeric_state.ts b/src/panels/config/automation/condition/types/ha-automation-condition-numeric_state.ts index 71259efe5d..d953eb7c72 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-numeric_state.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-numeric_state.ts @@ -1,6 +1,7 @@ import "@polymer/paper-input/paper-input"; import "@polymer/paper-input/paper-textarea"; -import { customElement, html, LitElement, property } from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import "../../../../../components/entity/ha-entity-picker"; import { NumericStateCondition } from "../../../../../data/automation"; import { HomeAssistant } from "../../../../../types"; diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-or.ts b/src/panels/config/automation/condition/types/ha-automation-condition-or.ts index 38152f3bbc..ca770ee816 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-or.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-or.ts @@ -1,4 +1,4 @@ -import { customElement } from "lit-element"; +import { customElement } from "lit/decorators"; import { HaLogicalCondition } from "./ha-automation-condition-logical"; @customElement("ha-automation-condition-or") diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-state.ts b/src/panels/config/automation/condition/types/ha-automation-condition-state.ts index d0f18b1ab7..1b841f0af9 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-state.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-state.ts @@ -1,5 +1,6 @@ import "@polymer/paper-input/paper-input"; -import { customElement, html, LitElement, property } from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import "../../../../../components/entity/ha-entity-attribute-picker"; import "../../../../../components/entity/ha-entity-picker"; import { ForDict, StateCondition } from "../../../../../data/automation"; diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-sun.ts b/src/panels/config/automation/condition/types/ha-automation-condition-sun.ts index becb62bf8c..bda9399539 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-sun.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-sun.ts @@ -2,7 +2,8 @@ import "@polymer/paper-input/paper-input"; import "@polymer/paper-radio-button/paper-radio-button"; import "@polymer/paper-radio-group/paper-radio-group"; import type { PaperRadioGroupElement } from "@polymer/paper-radio-group/paper-radio-group"; -import { customElement, html, LitElement, property } from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../../../../common/dom/fire_event"; import type { SunCondition } from "../../../../../data/automation"; import type { HomeAssistant } from "../../../../../types"; diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-template.ts b/src/panels/config/automation/condition/types/ha-automation-condition-template.ts index 6f8fe2329e..d83eea64e2 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-template.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-template.ts @@ -1,5 +1,6 @@ import "@polymer/paper-input/paper-textarea"; -import { customElement, html, LitElement, property } from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { TemplateCondition } from "../../../../../data/automation"; import { HomeAssistant } from "../../../../../types"; import { handleChangeEvent } from "../ha-automation-condition-row"; diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-time.ts b/src/panels/config/automation/condition/types/ha-automation-condition-time.ts index 87b22ef223..5b0e56b350 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-time.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-time.ts @@ -1,14 +1,7 @@ import { Radio } from "@material/mwc-radio"; import "@polymer/paper-input/paper-input"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../../../../common/dom/fire_event"; import { computeRTLDirection } from "../../../../../common/util/compute_rtl"; import "../../../../../components/ha-formfield"; @@ -43,9 +36,9 @@ export class HaTimeCondition extends LitElement implements ConditionElement { @property({ attribute: false }) public condition!: TimeCondition; - @internalProperty() private _inputModeBefore?: boolean; + @state() private _inputModeBefore?: boolean; - @internalProperty() private _inputModeAfter?: boolean; + @state() private _inputModeAfter?: boolean; public static get defaultConfig() { return {}; @@ -210,7 +203,7 @@ export class HaTimeCondition extends LitElement implements ConditionElement { }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` .weekday-toggle { display: flex; diff --git a/src/panels/config/automation/condition/types/ha-automation-condition-zone.ts b/src/panels/config/automation/condition/types/ha-automation-condition-zone.ts index e84bd7766d..7511b1ff0d 100644 --- a/src/panels/config/automation/condition/types/ha-automation-condition-zone.ts +++ b/src/panels/config/automation/condition/types/ha-automation-condition-zone.ts @@ -1,5 +1,6 @@ import "@polymer/paper-radio-button/paper-radio-button"; -import { customElement, html, LitElement, property } from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../../../../common/dom/fire_event"; import { computeStateDomain } from "../../../../../common/entity/compute_state_domain"; import { hasLocation } from "../../../../../common/entity/has_location"; diff --git a/src/panels/config/automation/dialog-new-automation.ts b/src/panels/config/automation/dialog-new-automation.ts index 3815eee8b0..a86d06bc19 100644 --- a/src/panels/config/automation/dialog-new-automation.ts +++ b/src/panels/config/automation/dialog-new-automation.ts @@ -1,33 +1,30 @@ import "@material/mwc-button"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { isComponentLoaded } from "../../../common/config/is_component_loaded"; import { fireEvent } from "../../../common/dom/fire_event"; +import { nextRender } from "../../../common/util/render-status"; import "../../../components/ha-blueprint-picker"; import "../../../components/ha-card"; import "../../../components/ha-circular-progress"; -import "../../../components/ha-dialog"; +import { createCloseHeading } from "../../../components/ha-dialog"; import { AutomationConfig, showAutomationEditor, } from "../../../data/automation"; +import { + HassDialog, + replaceDialog, +} from "../../../dialogs/make-dialog-manager"; import { haStyle, haStyleDialog } from "../../../resources/styles"; import type { HomeAssistant } from "../../../types"; import { showThingtalkDialog } from "./thingtalk/show-dialog-thingtalk"; @customElement("ha-dialog-new-automation") -class DialogNewAutomation extends LitElement { +class DialogNewAutomation extends LitElement implements HassDialog { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _opened = false; + @state() private _opened = false; public showDialog(): void { this._opened = true; @@ -46,8 +43,9 @@ class DialogNewAutomation extends LitElement {
@@ -107,25 +105,28 @@ class DialogNewAutomation extends LitElement { } private _thingTalk() { - this.closeDialog(); + replaceDialog(); showThingtalkDialog(this, { callback: (config: Partial | undefined) => - showAutomationEditor(this, config), + showAutomationEditor(config), input: this.shadowRoot!.querySelector("paper-input")!.value as string, }); - } - - private _blueprintPicked(ev: CustomEvent) { - showAutomationEditor(this, { use_blueprint: { path: ev.detail.value } }); this.closeDialog(); } - private _blank() { - showAutomationEditor(this); + private async _blueprintPicked(ev: CustomEvent) { this.closeDialog(); + await nextRender(); + showAutomationEditor({ use_blueprint: { path: ev.detail.value } }); } - static get styles(): CSSResult[] { + private async _blank() { + this.closeDialog(); + await nextRender(); + showAutomationEditor(); + } + + static get styles(): CSSResultGroup { return [ haStyle, haStyleDialog, diff --git a/src/panels/config/automation/ha-automation-editor.ts b/src/panels/config/automation/ha-automation-editor.ts index 19c73ac31b..8d6057762d 100644 --- a/src/panels/config/automation/ha-automation-editor.ts +++ b/src/panels/config/automation/ha-automation-editor.ts @@ -13,16 +13,14 @@ import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light"; import "@polymer/paper-input/paper-textarea"; import { css, - CSSResult, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, - query, TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +} from "lit"; +import { property, state, query } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import { navigate } from "../../../common/navigate"; import { copyToClipboard } from "../../../common/util/copy-clipboard"; import "../../../components/ha-button-menu"; @@ -75,7 +73,7 @@ declare global { export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { @property({ attribute: false }) public hass!: HomeAssistant; - @property() public automationId!: string; + @property() public automationId: string | null = null; @property() public automations!: AutomationEntity[]; @@ -85,15 +83,15 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { @property() public route!: Route; - @internalProperty() private _config?: AutomationConfig; + @state() private _config?: AutomationConfig; - @internalProperty() private _dirty = false; + @state() private _dirty = false; - @internalProperty() private _errors?: string; + @state() private _errors?: string; - @internalProperty() private _entityId?: string; + @state() private _entityId?: string; - @internalProperty() private _mode: "gui" | "yaml" = "gui"; + @state() private _mode: "gui" | "yaml" = "gui"; @query("ha-yaml-editor", true) private _editor?: HaYamlEditor; @@ -178,14 +176,14 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { aria-label=${this.hass.localize( "ui.panel.config.automation.picker.delete_automation" )} - class=${classMap({ warning: this.automationId })} + class=${classMap({ warning: Boolean(this.automationId) })} graphic="icon" > ${this.hass.localize( "ui.panel.config.automation.picker.delete_automation" )} @@ -349,7 +347,10 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { private async _loadConfig() { try { - const config = await getAutomationConfig(this.hass, this.automationId); + const config = await getAutomationConfig( + this.hass, + this.automationId as string + ); // Normalize data: ensure trigger, action and condition are lists // Happens when people copy paste their automations into the config @@ -449,7 +450,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { // Wait for dialog to complate closing await new Promise((resolve) => setTimeout(resolve, 0)); } - showAutomationEditor(this, { + showAutomationEditor({ ...this._config, id: undefined, alias: `${this._config?.alias} (${this.hass.localize( @@ -470,7 +471,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { } private async _delete() { - await deleteAutomation(this.hass, this.automationId); + await deleteAutomation(this.hass, this.automationId as string); history.back(); } @@ -502,7 +503,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { this._dirty = false; if (!this.automationId) { - navigate(this, `/config/automation/edit/${id}`, true); + navigate(`/config/automation/edit/${id}`, { replace: true }); } }, (errors) => { @@ -519,7 +520,7 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) { this._saveAutomation(); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/automation/ha-automation-picker.ts b/src/panels/config/automation/ha-automation-picker.ts index 03dd102f45..e2970fc3a5 100644 --- a/src/panels/config/automation/ha-automation-picker.ts +++ b/src/panels/config/automation/ha-automation-picker.ts @@ -8,16 +8,9 @@ import { mdiPlus, } from "@mdi/js"; import "@polymer/paper-tooltip/paper-tooltip"; -import { - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import { ifDefined } from "lit-html/directives/if-defined"; +import { CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { ifDefined } from "lit/directives/if-defined"; import memoizeOne from "memoize-one"; import { isComponentLoaded } from "../../../common/config/is_component_loaded"; import { formatDateTime } from "../../../common/datetime/format_date_time"; @@ -26,9 +19,9 @@ import { computeStateName } from "../../../common/entity/compute_state_name"; import { navigate } from "../../../common/navigate"; import { DataTableColumnContainer } from "../../../components/data-table/ha-data-table"; import "../../../components/entity/ha-entity-toggle"; +import "../../../components/ha-button-related-filter-menu"; import "../../../components/ha-fab"; import "../../../components/ha-svg-icon"; -import "../../../components/ha-button-related-filter-menu"; import { AutomationEntity, triggerAutomationActions, @@ -56,9 +49,9 @@ class HaAutomationPicker extends LitElement { @property() private _activeFilters?: string[]; - @internalProperty() private _filteredAutomations?: string[] | null; + @state() private _filteredAutomations?: string[] | null; - @internalProperty() private _filterValue?; + @state() private _filterValue?; private _automations = memoizeOne( ( @@ -331,11 +324,11 @@ class HaAutomationPicker extends LitElement { ) { showNewAutomationDialog(this); } else { - navigate(this, "/config/automation/edit/new"); + navigate("/config/automation/edit/new"); } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return haStyle; } } diff --git a/src/panels/config/automation/ha-config-automation.ts b/src/panels/config/automation/ha-config-automation.ts index d9db28fac1..8a61fabf57 100644 --- a/src/panels/config/automation/ha-config-automation.ts +++ b/src/panels/config/automation/ha-config-automation.ts @@ -1,5 +1,6 @@ import { HassEntities } from "home-assistant-js-websocket"; -import { customElement, property, PropertyValues } from "lit-element"; +import { PropertyValues } from "lit"; +import { customElement, property } from "lit/decorators"; import memoizeOne from "memoize-one"; import { computeStateDomain } from "../../../common/entity/compute_state_domain"; import { debounce } from "../../../common/util/debounce"; @@ -9,8 +10,8 @@ import { RouterOptions, } from "../../../layouts/hass-router-page"; import { HomeAssistant } from "../../../types"; -import "./ha-automation-picker"; import "./ha-automation-editor"; +import "./ha-automation-picker"; const equal = (a: AutomationEntity[], b: AutomationEntity[]): boolean => { if (a.length !== b.length) { diff --git a/src/panels/config/automation/manual-automation-editor.ts b/src/panels/config/automation/manual-automation-editor.ts index 8828066792..9dfdf01ec4 100644 --- a/src/panels/config/automation/manual-automation-editor.ts +++ b/src/panels/config/automation/manual-automation-editor.ts @@ -3,14 +3,8 @@ import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light"; import "@polymer/paper-input/paper-textarea"; import { PaperListboxElement } from "@polymer/paper-listbox"; import { HassEntity } from "home-assistant-js-websocket"; -import { - css, - CSSResult, - customElement, - LitElement, - property, -} from "lit-element"; -import { html } from "lit-html"; +import { css, CSSResultGroup, html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../../common/dom/fire_event"; import "../../../components/entity/ha-entity-toggle"; import "../../../components/ha-card"; @@ -317,7 +311,7 @@ export class HaManualAutomationEditor extends LitElement { }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/automation/thingtalk/dialog-thingtalk.ts b/src/panels/config/automation/thingtalk/dialog-thingtalk.ts index 5c09ed45cd..467e293e6d 100644 --- a/src/panels/config/automation/thingtalk/dialog-thingtalk.ts +++ b/src/panels/config/automation/thingtalk/dialog-thingtalk.ts @@ -2,17 +2,9 @@ import "@material/mwc-button"; import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable"; import "@polymer/paper-input/paper-input"; import type { PaperInputElement } from "@polymer/paper-input/paper-input"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - query, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state, query } from "lit/decorators"; +import { fireEvent } from "../../../../common/dom/fire_event"; import "../../../../components/dialog/ha-paper-dialog"; import "../../../../components/ha-circular-progress"; import type { AutomationConfig } from "../../../../data/automation"; @@ -40,15 +32,15 @@ export interface PlaceholderContainer { class DialogThingtalk extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _error?: string; + @state() private _error?: string; - @internalProperty() private _params?: ThingtalkDialogParams; + @state() private _params?: ThingtalkDialogParams; - @internalProperty() private _submitting = false; + @state() private _submitting = false; - @internalProperty() private _opened = false; + @state() private _opened = false; - @internalProperty() private _placeholders?: PlaceholderContainer; + @state() private _placeholders?: PlaceholderContainer; @query("#input") private _input?: PaperInputElement; @@ -67,6 +59,15 @@ class DialogThingtalk extends LitElement { } } + public closeDialog() { + this._placeholders = undefined; + if (this._input) { + this._input.value = null; + } + this._opened = false; + fireEvent(this, "dialog-closed", { dialog: this.localName }); + } + protected render(): TemplateResult { if (!this._params) { return html``; @@ -225,25 +226,17 @@ class DialogThingtalk extends LitElement { private _sendConfig(input, config) { this._params!.callback({ alias: input, ...config }); - this._closeDialog(); + this.closeDialog(); } private _skip() { this._params!.callback(undefined); - this._closeDialog(); - } - - private _closeDialog() { - this._placeholders = undefined; - if (this._input) { - this._input.value = null; - } - this._opened = false; + this.closeDialog(); } private _openedChanged(ev: PolymerChangedEvent): void { if (!ev.detail.value) { - this._closeDialog(); + this.closeDialog(); } } @@ -257,7 +250,7 @@ class DialogThingtalk extends LitElement { this._input!.value = (ev.target as HTMLAnchorElement).innerText; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, haStyleDialog, diff --git a/src/panels/config/automation/thingtalk/ha-thingtalk-placeholders.ts b/src/panels/config/automation/thingtalk/ha-thingtalk-placeholders.ts index f71d8a8ab9..af00652e8f 100644 --- a/src/panels/config/automation/thingtalk/ha-thingtalk-placeholders.ts +++ b/src/panels/config/automation/thingtalk/ha-thingtalk-placeholders.ts @@ -1,15 +1,13 @@ import { HassEntity } from "home-assistant-js-websocket"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../../../common/dom/fire_event"; import { computeDomain } from "../../../../common/entity/compute_domain"; import { applyPatch, getPath } from "../../../../common/util/patch"; @@ -72,13 +70,13 @@ export class ThingTalkPlaceholders extends SubscribeMixin(LitElement) { @property() public placeholders!: PlaceholderContainer; - @internalProperty() private _error?: string; + @state() private _error?: string; private _deviceEntityLookup: DeviceEntitiesLookup = {}; - @internalProperty() private _extraInfo: ExtraInfo = {}; + @state() private _extraInfo: ExtraInfo = {}; - @internalProperty() private _placeholderValues: PlaceholderValues = {}; + @state() private _placeholderValues: PlaceholderValues = {}; private _devices?: DeviceRegistryEntry[]; @@ -198,13 +196,13 @@ export class ThingTalkPlaceholders extends SubscribeMixin(LitElement) { "device_id", ]) )}`} - .entityFilter=${(state: HassEntity) => { + .entityFilter=${(entityState: HassEntity) => { const devId = this._placeholderValues[type][ placeholder.index ][idx].device_id; return this._deviceEntityLookup[ devId - ].includes(state.entity_id); + ].includes(entityState.entity_id); }} > ` @@ -470,7 +468,7 @@ export class ThingTalkPlaceholders extends SubscribeMixin(LitElement) { this.dispatchEvent(new CustomEvent(ev.type, ev)); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyleDialog, css` diff --git a/src/panels/config/automation/trace/ha-automation-trace-blueprint-config.ts b/src/panels/config/automation/trace/ha-automation-trace-blueprint-config.ts index 4f9d02403e..bc3117114b 100644 --- a/src/panels/config/automation/trace/ha-automation-trace-blueprint-config.ts +++ b/src/panels/config/automation/trace/ha-automation-trace-blueprint-config.ts @@ -1,15 +1,10 @@ -import { safeDump } from "js-yaml"; -import { - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import "../../../../components/ha-icon-button"; +import { dump } from "js-yaml"; +import { html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import "../../../../components/ha-code-editor"; -import { HomeAssistant } from "../../../../types"; +import "../../../../components/ha-icon-button"; import { AutomationTraceExtended } from "../../../../data/trace"; +import { HomeAssistant } from "../../../../types"; @customElement("ha-automation-trace-blueprint-config") export class HaAutomationTraceBlueprintConfig extends LitElement { @@ -20,7 +15,7 @@ export class HaAutomationTraceBlueprintConfig extends LitElement { protected render(): TemplateResult { return html` `; diff --git a/src/panels/config/automation/trace/ha-automation-trace-config.ts b/src/panels/config/automation/trace/ha-automation-trace-config.ts index f579e30815..c97bb47f8b 100644 --- a/src/panels/config/automation/trace/ha-automation-trace-config.ts +++ b/src/panels/config/automation/trace/ha-automation-trace-config.ts @@ -1,16 +1,9 @@ -import { safeDump } from "js-yaml"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import { AutomationTraceExtended } from "../../../../data/trace"; -import "../../../../components/ha-icon-button"; +import { dump } from "js-yaml"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import "../../../../components/ha-code-editor"; +import "../../../../components/ha-icon-button"; +import { AutomationTraceExtended } from "../../../../data/trace"; import { HomeAssistant } from "../../../../types"; @customElement("ha-automation-trace-config") @@ -22,13 +15,13 @@ export class HaAutomationTraceConfig extends LitElement { protected render(): TemplateResult { return html` `; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [css``]; } } diff --git a/src/panels/config/automation/trace/ha-automation-trace-logbook.ts b/src/panels/config/automation/trace/ha-automation-trace-logbook.ts index b18d83d1be..675d355662 100644 --- a/src/panels/config/automation/trace/ha-automation-trace-logbook.ts +++ b/src/panels/config/automation/trace/ha-automation-trace-logbook.ts @@ -1,15 +1,8 @@ -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import type { HomeAssistant } from "../../../../types"; -import type { LogbookEntry } from "../../../../data/logbook"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import "../../../../components/trace/hat-logbook-note"; +import type { LogbookEntry } from "../../../../data/logbook"; +import type { HomeAssistant } from "../../../../types"; import "../../../logbook/ha-logbook"; @customElement("ha-automation-trace-logbook") @@ -36,7 +29,7 @@ export class HaAutomationTraceLogbook extends LitElement {
`; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ css` .padded-box { diff --git a/src/panels/config/automation/trace/ha-automation-trace-path-details.ts b/src/panels/config/automation/trace/ha-automation-trace-path-details.ts index 51ebbdab7f..dc0412b149 100644 --- a/src/panels/config/automation/trace/ha-automation-trace-path-details.ts +++ b/src/panels/config/automation/trace/ha-automation-trace-path-details.ts @@ -1,30 +1,22 @@ -import { safeDump } from "js-yaml"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +import { dump } from "js-yaml"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; +import { formatDateTimeWithSeconds } from "../../../../common/datetime/format_date_time"; +import "../../../../components/ha-code-editor"; +import "../../../../components/ha-icon-button"; +import type { NodeInfo } from "../../../../components/trace/hat-graph"; +import "../../../../components/trace/hat-logbook-note"; +import { LogbookEntry } from "../../../../data/logbook"; import { ActionTraceStep, AutomationTraceExtended, ChooseActionTraceStep, getDataFromPath, } from "../../../../data/trace"; -import "../../../../components/ha-icon-button"; -import "../../../../components/ha-code-editor"; -import type { NodeInfo } from "../../../../components/trace/hat-graph"; -import "../../../../components/trace/hat-logbook-note"; import { HomeAssistant } from "../../../../types"; -import { formatDateTimeWithSeconds } from "../../../../common/datetime/format_date_time"; -import { LogbookEntry } from "../../../../data/logbook"; -import { traceTabStyles } from "./styles"; import "../../../logbook/ha-logbook"; +import { traceTabStyles } from "./styles"; @customElement("ha-automation-trace-path-details") export class HaAutomationTracePathDetails extends LitElement { @@ -38,12 +30,11 @@ export class HaAutomationTracePathDetails extends LitElement { @property() public logbookEntries!: LogbookEntry[]; + @property() renderedNodes: Record = {}; + @property() public trackedNodes!: Record; - @internalProperty() private _view: - | "config" - | "changed_variables" - | "logbook" = "config"; + @state() private _view: "config" | "changed_variables" | "logbook" = "config"; protected render(): TemplateResult { return html` @@ -102,12 +93,12 @@ export class HaAutomationTracePathDetails extends LitElement { const parts: TemplateResult[][] = []; let active = false; - const childConditionsPrefix = `${this.selected.path}/conditions/`; for (const curPath of Object.keys(this.trace.trace)) { - // Include all child conditions too + // Include all trace results until the next rendered node. + // Rendered nodes also include non-chosen choose paths. if (active) { - if (!curPath.startsWith(childConditionsPrefix)) { + if (curPath in this.renderedNodes) { break; } } else if (curPath === this.selected.path) { @@ -132,9 +123,7 @@ export class HaAutomationTracePathDetails extends LitElement { return html` ${curPath === this.selected.path ? "" - : html`

- Condition ${curPath.substr(childConditionsPrefix.length)} -

`} + : html`

${curPath.substr(this.selected.path.length + 1)}

`} ${data.length === 1 ? "" : html`

Iteration ${idx + 1}

`} Executed: ${formatDateTimeWithSeconds( @@ -143,13 +132,13 @@ export class HaAutomationTracePathDetails extends LitElement { )}
${result ? html`Result: -
${safeDump(result)}
` +
${dump(result)}
` : error ? html`
Error: ${error}
` : ""} ${Object.keys(rest).length === 0 ? "" - : html`
${safeDump(rest)}
`} + : html`
${dump(rest)}
`} `; }) ); @@ -165,7 +154,7 @@ export class HaAutomationTracePathDetails extends LitElement { const config = getDataFromPath(this.trace!.config, this.selected.path); return config ? html`` : "Unable to find config"; @@ -182,9 +171,7 @@ export class HaAutomationTracePathDetails extends LitElement { ${idx > 0 ? html`

Iteration ${idx + 1}

` : ""} ${Object.keys(trace.changed_variables || {}).length === 0 ? "No variables changed" - : html`
-${safeDump(trace.changed_variables).trimRight()}
`} + : html`
${dump(trace.changed_variables).trimRight()}
`} ` )}
@@ -254,7 +241,7 @@ ${safeDump(trace.changed_variables).trimRight()} ` : this._view === "config" @@ -442,15 +435,14 @@ export class HaAutomationTrace extends LitElement { private _timelinePathPicked(ev) { const path = ev.detail.value; - const nodes = this.shadowRoot!.querySelector( - "hat-script-graph" - )!.getTrackedNodes(); + const nodes = this.shadowRoot!.querySelector("hat-script-graph")! + .trackedNodes; if (nodes[path]) { this._selected = nodes[path]; } } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, traceTabStyles, diff --git a/src/panels/config/automation/trace/styles.ts b/src/panels/config/automation/trace/styles.ts index 4f236499c1..40878d304f 100644 --- a/src/panels/config/automation/trace/styles.ts +++ b/src/panels/config/automation/trace/styles.ts @@ -1,4 +1,4 @@ -import { css } from "lit-element"; +import { css } from "lit"; export const traceTabStyles = css` .tabs { diff --git a/src/panels/config/automation/trigger/ha-automation-trigger-row.ts b/src/panels/config/automation/trigger/ha-automation-trigger-row.ts index d60c801216..07b8b7373f 100644 --- a/src/panels/config/automation/trigger/ha-automation-trigger-row.ts +++ b/src/panels/config/automation/trigger/ha-automation-trigger-row.ts @@ -5,15 +5,8 @@ import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; import type { PaperListboxElement } from "@polymer/paper-listbox/paper-listbox"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { dynamicElement } from "../../../../common/dom/dynamic-element-directive"; import { fireEvent } from "../../../../common/dom/fire_event"; import "../../../../components/ha-button-menu"; @@ -87,7 +80,7 @@ export default class HaAutomationTriggerRow extends LitElement { @property() public trigger!: Trigger; - @internalProperty() private _yamlMode = false; + @state() private _yamlMode = false; protected render() { const selected = OPTIONS.indexOf(this.trigger.platform); @@ -240,7 +233,7 @@ export default class HaAutomationTriggerRow extends LitElement { this._yamlMode = !this._yamlMode; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/automation/trigger/ha-automation-trigger.ts b/src/panels/config/automation/trigger/ha-automation-trigger.ts index 953ec67037..612780c9d4 100644 --- a/src/panels/config/automation/trigger/ha-automation-trigger.ts +++ b/src/panels/config/automation/trigger/ha-automation-trigger.ts @@ -1,12 +1,6 @@ import "@material/mwc-button"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../../../common/dom/fire_event"; import "../../../../components/ha-card"; import { Trigger } from "../../../../data/automation"; @@ -77,7 +71,7 @@ export default class HaAutomationTrigger extends LitElement { }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` ha-automation-trigger-row, ha-card { diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-device.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-device.ts index 4bd1d68f36..51a579c2c6 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-device.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-device.ts @@ -1,10 +1,5 @@ -import { - customElement, - html, - internalProperty, - LitElement, - property, -} from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import { fireEvent } from "../../../../../common/dom/fire_event"; import "../../../../../components/device/ha-device-picker"; @@ -24,9 +19,9 @@ export class HaDeviceTrigger extends LitElement { @property({ type: Object }) public trigger!: DeviceTrigger; - @internalProperty() private _deviceId?: string; + @state() private _deviceId?: string; - @internalProperty() private _capabilities?: DeviceCapabilities; + @state() private _capabilities?: DeviceCapabilities; private _origTrigger?: DeviceTrigger; diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-event.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-event.ts index 9d53e8ea0e..de11702140 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-event.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-event.ts @@ -1,6 +1,6 @@ import "@polymer/paper-input/paper-input"; -import { customElement, LitElement, property } from "lit-element"; -import { html } from "lit-html"; +import { html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../../../../common/dom/fire_event"; import "../../../../../components/ha-yaml-editor"; import "../../../../../components/user/ha-users-picker"; diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-geo_location.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-geo_location.ts index b65fac6d92..55e08598d1 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-geo_location.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-geo_location.ts @@ -1,7 +1,8 @@ import "@polymer/paper-radio-button/paper-radio-button"; import "@polymer/paper-radio-group/paper-radio-group"; import type { PaperRadioGroupElement } from "@polymer/paper-radio-group/paper-radio-group"; -import { customElement, html, LitElement, property } from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../../../../common/dom/fire_event"; import "../../../../../components/entity/ha-entity-picker"; import type { GeoLocationTrigger } from "../../../../../data/automation"; diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-homeassistant.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-homeassistant.ts index f811e20f0b..1d45e6c5f6 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-homeassistant.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-homeassistant.ts @@ -1,7 +1,8 @@ import "@polymer/paper-radio-button/paper-radio-button"; import "@polymer/paper-radio-group/paper-radio-group"; import type { PaperRadioGroupElement } from "@polymer/paper-radio-group/paper-radio-group"; -import { customElement, html, LitElement, property } from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../../../../common/dom/fire_event"; import type { HassTrigger } from "../../../../../data/automation"; import type { HomeAssistant } from "../../../../../types"; diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-mqtt.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-mqtt.ts index 0450f37ff2..e3e997771f 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-mqtt.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-mqtt.ts @@ -1,5 +1,6 @@ import "@polymer/paper-input/paper-input"; -import { customElement, html, LitElement, property } from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { MqttTrigger } from "../../../../../data/automation"; import { HomeAssistant } from "../../../../../types"; import { diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-numeric_state.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-numeric_state.ts index 0c54205b2b..cf7cf64115 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-numeric_state.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-numeric_state.ts @@ -1,6 +1,7 @@ import "@polymer/paper-input/paper-input"; import "@polymer/paper-input/paper-textarea"; -import { customElement, html, LitElement, property } from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import "../../../../../components/entity/ha-entity-picker"; import { ForDict, NumericStateTrigger } from "../../../../../data/automation"; import { HomeAssistant } from "../../../../../types"; diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-state.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-state.ts index c128904318..1ad3b18555 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-state.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-state.ts @@ -1,5 +1,6 @@ import "@polymer/paper-input/paper-input"; -import { customElement, html, LitElement, property } from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import "../../../../../components/entity/ha-entity-attribute-picker"; import "../../../../../components/entity/ha-entity-picker"; import { ForDict, StateTrigger } from "../../../../../data/automation"; diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-sun.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-sun.ts index 3c2bb9cf62..d940a3e1cc 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-sun.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-sun.ts @@ -2,7 +2,8 @@ import "@polymer/paper-input/paper-input"; import "@polymer/paper-radio-button/paper-radio-button"; import "@polymer/paper-radio-group/paper-radio-group"; import type { PaperRadioGroupElement } from "@polymer/paper-radio-group/paper-radio-group"; -import { customElement, html, LitElement, property } from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../../../../common/dom/fire_event"; import type { SunTrigger } from "../../../../../data/automation"; import type { HomeAssistant } from "../../../../../types"; diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-tag.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-tag.ts index bd40b48e21..5accba1a25 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-tag.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-tag.ts @@ -1,12 +1,6 @@ import "@polymer/paper-input/paper-input"; -import { - customElement, - html, - internalProperty, - LitElement, - property, - PropertyValues, -} from "lit-element"; +import { html, LitElement, PropertyValues } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../../../../common/dom/fire_event"; import { TagTrigger } from "../../../../../data/automation"; import { fetchTags, Tag } from "../../../../../data/tag"; @@ -19,7 +13,7 @@ export class HaTagTrigger extends LitElement implements TriggerElement { @property() public trigger!: TagTrigger; - @internalProperty() private _tags: Tag[] = []; + @state() private _tags: Tag[] = []; public static get defaultConfig() { return { tag_id: "" }; diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-template.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-template.ts index 5e9483e0c8..2a40c2fc9d 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-template.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-template.ts @@ -1,5 +1,6 @@ import "@polymer/paper-input/paper-textarea"; -import { customElement, html, LitElement, property } from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { TemplateTrigger } from "../../../../../data/automation"; import { HomeAssistant } from "../../../../../types"; import { handleChangeEvent } from "../ha-automation-trigger-row"; diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-time.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-time.ts index 5b18ff0e20..ddb0404907 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-time.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-time.ts @@ -1,11 +1,6 @@ import "@polymer/paper-input/paper-input"; -import { - customElement, - html, - internalProperty, - LitElement, - property, -} from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property, state } from "lit/decorators"; import "../../../../../components/entity/ha-entity-picker"; import "../../../../../components/ha-formfield"; import "../../../../../components/ha-radio"; @@ -24,7 +19,7 @@ export class HaTimeTrigger extends LitElement implements TriggerElement { @property() public trigger!: TimeTrigger; - @internalProperty() private _inputMode?: boolean; + @state() private _inputMode?: boolean; public static get defaultConfig() { return { at: "" }; diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-time_pattern.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-time_pattern.ts index 1f0f081ad9..b1b0a74f4c 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-time_pattern.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-time_pattern.ts @@ -1,5 +1,6 @@ import "@polymer/paper-input/paper-input"; -import { customElement, html, LitElement, property } from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { TimePatternTrigger } from "../../../../../data/automation"; import { HomeAssistant } from "../../../../../types"; import { diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-webhook.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-webhook.ts index 3eb56a805e..4d90ec0219 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-webhook.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-webhook.ts @@ -1,5 +1,6 @@ import "@polymer/paper-input/paper-input"; -import { customElement, html, LitElement, property } from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { WebhookTrigger } from "../../../../../data/automation"; import { HomeAssistant } from "../../../../../types"; import { handleChangeEvent } from "../ha-automation-trigger-row"; diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-zone.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-zone.ts index 4d93d61f6c..a8b4ba457e 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-zone.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-zone.ts @@ -1,7 +1,8 @@ import "@polymer/paper-radio-button/paper-radio-button"; import "@polymer/paper-radio-group/paper-radio-group"; import type { PaperRadioGroupElement } from "@polymer/paper-radio-group/paper-radio-group"; -import { customElement, html, LitElement, property } from "lit-element"; +import { html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../../../../common/dom/fire_event"; import { computeStateDomain } from "../../../../../common/entity/compute_state_domain"; import { hasLocation } from "../../../../../common/entity/has_location"; diff --git a/src/panels/config/blueprint/dialog-import-blueprint.ts b/src/panels/config/blueprint/dialog-import-blueprint.ts index 325fccc460..db171c6449 100644 --- a/src/panels/config/blueprint/dialog-import-blueprint.ts +++ b/src/panels/config/blueprint/dialog-import-blueprint.ts @@ -1,21 +1,14 @@ -import "../../../components/ha-markdown"; import "@material/mwc-button"; import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable"; import "@polymer/paper-input/paper-input"; import type { PaperInputElement } from "@polymer/paper-input/paper-input"; -import { - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - query, - TemplateResult, -} from "lit-element"; +import { CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state, query } from "lit/decorators"; import { fireEvent } from "../../../common/dom/fire_event"; import "../../../components/ha-circular-progress"; +import { createCloseHeading } from "../../../components/ha-dialog"; import "../../../components/ha-expansion-panel"; +import "../../../components/ha-markdown"; import { BlueprintImportResult, importBlueprint, @@ -23,23 +16,22 @@ import { } from "../../../data/blueprint"; import { haStyleDialog } from "../../../resources/styles"; import type { HomeAssistant } from "../../../types"; -import { createCloseHeading } from "../../../components/ha-dialog"; @customElement("ha-dialog-import-blueprint") class DialogImportBlueprint extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _params?; + @state() private _params?; - @internalProperty() private _importing = false; + @state() private _importing = false; - @internalProperty() private _saving = false; + @state() private _saving = false; - @internalProperty() private _error?: string; + @state() private _error?: string; - @internalProperty() private _result?: BlueprintImportResult; + @state() private _result?: BlueprintImportResult; - @internalProperty() private _url?: string; + @state() private _url?: string; @query("#input") private _input?: PaperInputElement; @@ -221,7 +213,7 @@ class DialogImportBlueprint extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return haStyleDialog; } } diff --git a/src/panels/config/blueprint/ha-blueprint-overview.ts b/src/panels/config/blueprint/ha-blueprint-overview.ts index 68b1e0cf32..37b4fba05f 100644 --- a/src/panels/config/blueprint/ha-blueprint-overview.ts +++ b/src/panels/config/blueprint/ha-blueprint-overview.ts @@ -8,14 +8,13 @@ import { } from "@mdi/js"; import "@polymer/paper-tooltip/paper-tooltip"; import { - CSSResult, - customElement, + CSSResultGroup, html, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property } from "lit/decorators"; import memoizeOne from "memoize-one"; import { fireEvent } from "../../../common/dom/fire_event"; import { navigate } from "../../../common/navigate"; @@ -47,11 +46,8 @@ interface BlueprintMetaDataPath extends BlueprintMetaData { } const createNewFunctions = { - automation: ( - context: HaBlueprintOverview, - blueprintMeta: BlueprintMetaDataPath - ) => { - showAutomationEditor(context, { + automation: (blueprintMeta: BlueprintMetaDataPath) => { + showAutomationEditor({ alias: blueprintMeta.name, use_blueprint: { path: blueprintMeta.path }, }); @@ -184,7 +180,7 @@ class HaBlueprintOverview extends LitElement { super.firstUpdated(changedProps); if (this.route.path === "/import") { const url = extractSearchParam("blueprint_url"); - navigate(this, "/config/blueprint/dashboard", true); + navigate("/config/blueprint/dashboard", { replace: true }); if (url) { this._addBlueprint(url); } @@ -281,7 +277,7 @@ class HaBlueprintOverview extends LitElement { private _createNew(ev) { const blueprint = ev.currentTarget.blueprint as BlueprintMetaDataPath; - createNewFunctions[blueprint.domain](this, blueprint); + createNewFunctions[blueprint.domain](blueprint); } private _share(ev) { @@ -312,7 +308,7 @@ class HaBlueprintOverview extends LitElement { fireEvent(this, "reload-blueprints"); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return haStyle; } } diff --git a/src/panels/config/blueprint/ha-config-blueprint.ts b/src/panels/config/blueprint/ha-config-blueprint.ts index efe7e82645..3ea73842da 100644 --- a/src/panels/config/blueprint/ha-config-blueprint.ts +++ b/src/panels/config/blueprint/ha-config-blueprint.ts @@ -1,4 +1,5 @@ -import { customElement, property, PropertyValues } from "lit-element"; +import { PropertyValues } from "lit"; +import { customElement, property } from "lit/decorators"; import { Blueprints, fetchBlueprints } from "../../../data/blueprint"; import { HassRouterPage, diff --git a/src/panels/config/cloud/account/cloud-account.js b/src/panels/config/cloud/account/cloud-account.js index ae3d8823ca..9670794dfc 100644 --- a/src/panels/config/cloud/account/cloud-account.js +++ b/src/panels/config/cloud/account/cloud-account.js @@ -92,7 +92,9 @@ class CloudAccount extends EventsMixin(LocalizeMixin(PolymerElement)) { [[localize('ui.panel.config.cloud.account.connection_status')]] -
[[cloudStatus.cloud]]
+
+ [[_computeConnectionStatus(cloudStatus.cloud)]] +
@@ -189,10 +191,12 @@ class CloudAccount extends EventsMixin(LocalizeMixin(PolymerElement)) { this._fetchSubscriptionInfo(); } - _computeRemoteConnected(connected) { - return connected + _computeConnectionStatus(status) { + return status === "connected" ? this.hass.localize("ui.panel.config.cloud.account.connected") - : this.hass.localize("ui.panel.config.cloud.account.not_connected"); + : status === "disconnected" + ? this.hass.localize("ui.panel.config.cloud.account.not_connected") + : this.hass.localize("ui.panel.config.cloud.account.connecting"); } async _fetchSubscriptionInfo() { diff --git a/src/panels/config/cloud/account/cloud-alexa-pref.ts b/src/panels/config/cloud/account/cloud-alexa-pref.ts index 8d6c190d7d..9b98f7d560 100644 --- a/src/panels/config/cloud/account/cloud-alexa-pref.ts +++ b/src/panels/config/cloud/account/cloud-alexa-pref.ts @@ -1,13 +1,6 @@ import "@material/mwc-button"; -import { - css, - CSSResult, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { property, state } from "lit/decorators"; import { fireEvent } from "../../../../common/dom/fire_event"; import "../../../../components/ha-card"; import "../../../../components/ha-switch"; @@ -21,7 +14,7 @@ export class CloudAlexaPref extends LitElement { @property() public cloudStatus?: CloudStatusLoggedIn; - @internalProperty() private _syncing = false; + @state() private _syncing = false; protected render(): TemplateResult { if (!this.cloudStatus) { @@ -161,7 +154,7 @@ export class CloudAlexaPref extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` a { color: var(--primary-color); diff --git a/src/panels/config/cloud/account/cloud-google-pref.ts b/src/panels/config/cloud/account/cloud-google-pref.ts index b0c86ea7f5..b572e7a67e 100644 --- a/src/panels/config/cloud/account/cloud-google-pref.ts +++ b/src/panels/config/cloud/account/cloud-google-pref.ts @@ -1,14 +1,8 @@ import "@material/mwc-button"; import "@polymer/paper-input/paper-input"; import type { PaperInputElement } from "@polymer/paper-input/paper-input"; -import { - css, - CSSResult, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { property } from "lit/decorators"; import { fireEvent } from "../../../../common/dom/fire_event"; import "../../../../components/buttons/ha-call-api-button"; import "../../../../components/ha-card"; @@ -220,7 +214,7 @@ export class CloudGooglePref extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` a { color: var(--primary-color); diff --git a/src/panels/config/cloud/account/cloud-remote-pref.ts b/src/panels/config/cloud/account/cloud-remote-pref.ts index 223f58dd1a..a2973d250b 100644 --- a/src/panels/config/cloud/account/cloud-remote-pref.ts +++ b/src/panels/config/cloud/account/cloud-remote-pref.ts @@ -1,14 +1,7 @@ import "@material/mwc-button"; import "@polymer/paper-item/paper-item-body"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../../../common/dom/fire_event"; import "../../../../components/ha-card"; import "../../../../components/ha-switch"; @@ -156,7 +149,7 @@ export class CloudRemotePref extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` .preparing { padding: 0 16px 16px; diff --git a/src/panels/config/cloud/account/cloud-tts-pref.ts b/src/panels/config/cloud/account/cloud-tts-pref.ts index b55b070333..1b57e7b113 100644 --- a/src/panels/config/cloud/account/cloud-tts-pref.ts +++ b/src/panels/config/cloud/account/cloud-tts-pref.ts @@ -1,32 +1,24 @@ +import "@material/mwc-button"; import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; -import "@material/mwc-button"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import memoizeOne from "memoize-one"; +import { fireEvent } from "../../../../common/dom/fire_event"; +import { caseInsensitiveCompare } from "../../../../common/string/compare"; import "../../../../components/ha-card"; -import "../../../../components/ha-switch"; import "../../../../components/ha-svg-icon"; +import "../../../../components/ha-switch"; import { CloudStatusLoggedIn, CloudTTSInfo, getCloudTTSInfo, updateCloudPref, } from "../../../../data/cloud"; -import type { HomeAssistant } from "../../../../types"; import { showAlertDialog } from "../../../../dialogs/generic/show-dialog-box"; import { translationMetadata } from "../../../../resources/translations-metadata"; -import { caseInsensitiveCompare } from "../../../../common/string/compare"; -import memoizeOne from "memoize-one"; -import { fireEvent } from "../../../../common/dom/fire_event"; +import type { HomeAssistant } from "../../../../types"; import { showTryTtsDialog } from "./show-dialog-cloud-tts-try"; @customElement("cloud-tts-pref") @@ -35,9 +27,9 @@ export class CloudTTSPref extends LitElement { @property() public cloudStatus?: CloudStatusLoggedIn; - @internalProperty() private savingPreferences = false; + @state() private savingPreferences = false; - @internalProperty() private ttsInfo?: CloudTTSInfo; + @state() private ttsInfo?: CloudTTSInfo; protected render(): TemplateResult { if (!this.cloudStatus) { @@ -231,7 +223,7 @@ export class CloudTTSPref extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` a { color: var(--primary-color); diff --git a/src/panels/config/cloud/account/cloud-webhooks.ts b/src/panels/config/cloud/account/cloud-webhooks.ts index 57f4ee24ac..309e78b651 100644 --- a/src/panels/config/cloud/account/cloud-webhooks.ts +++ b/src/panels/config/cloud/account/cloud-webhooks.ts @@ -1,20 +1,12 @@ import "@polymer/paper-item/paper-item"; import "@polymer/paper-item/paper-item-body"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - PropertyValues, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { isComponentLoaded } from "../../../../common/config/is_component_loaded"; import "../../../../components/ha-card"; import "../../../../components/ha-circular-progress"; import "../../../../components/ha-settings-row"; import "../../../../components/ha-switch"; -import { isComponentLoaded } from "../../../../common/config/is_component_loaded"; import { CloudStatusLoggedIn, CloudWebhook, @@ -34,13 +26,13 @@ export class CloudWebhooks extends LitElement { @property({ type: Boolean }) public narrow!: boolean; - @internalProperty() private _cloudHooks?: { + @state() private _cloudHooks?: { [webhookId: string]: CloudWebhook; }; - @internalProperty() private _localHooks?: Webhook[]; + @state() private _localHooks?: Webhook[]; - @internalProperty() private _progress: string[] = []; + @state() private _progress: string[] = []; public connectedCallback() { super.connectedCallback(); @@ -208,7 +200,7 @@ export class CloudWebhooks extends LitElement { : []; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/cloud/account/dialog-cloud-tts-try.ts b/src/panels/config/cloud/account/dialog-cloud-tts-try.ts index e4d340d46d..9da9b5ca10 100644 --- a/src/panels/config/cloud/account/dialog-cloud-tts-try.ts +++ b/src/panels/config/cloud/account/dialog-cloud-tts-try.ts @@ -1,42 +1,33 @@ import "@material/mwc-button"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - query, - TemplateResult, -} from "lit-element"; -import { HomeAssistant } from "../../../../types"; -import { TryTtsDialogParams } from "./show-dialog-cloud-tts-try"; -import { haStyleDialog } from "../../../../resources/styles"; -import { fireEvent } from "../../../../common/dom/fire_event"; -import { convertTextToSpeech } from "../../../../data/tts"; -import { showAlertDialog } from "../../../../dialogs/generic/show-dialog-box"; +import { mdiPlayCircleOutline } from "@mdi/js"; import "@polymer/paper-input/paper-textarea"; -import "../../../../components/ha-paper-dropdown-menu"; -import { computeStateDomain } from "../../../../common/entity/compute_state_domain"; -import { computeStateName } from "../../../../common/entity/compute_state_name"; +import type { PaperTextareaElement } from "@polymer/paper-input/paper-textarea"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; -import { supportsFeature } from "../../../../common/entity/supports-feature"; -import { SUPPORT_PLAY_MEDIA } from "../../../../data/media-player"; -import { createCloseHeading } from "../../../../components/ha-dialog"; -import { mdiPlayCircleOutline } from "@mdi/js"; import type { PaperListboxElement } from "@polymer/paper-listbox/paper-listbox"; -import type { PaperTextareaElement } from "@polymer/paper-input/paper-textarea"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state, query } from "lit/decorators"; import { LocalStorage } from "../../../../common/decorators/local-storage"; +import { fireEvent } from "../../../../common/dom/fire_event"; +import { computeStateDomain } from "../../../../common/entity/compute_state_domain"; +import { computeStateName } from "../../../../common/entity/compute_state_name"; +import { supportsFeature } from "../../../../common/entity/supports-feature"; +import { createCloseHeading } from "../../../../components/ha-dialog"; +import "../../../../components/ha-paper-dropdown-menu"; +import { SUPPORT_PLAY_MEDIA } from "../../../../data/media-player"; +import { convertTextToSpeech } from "../../../../data/tts"; +import { showAlertDialog } from "../../../../dialogs/generic/show-dialog-box"; +import { haStyleDialog } from "../../../../resources/styles"; +import { HomeAssistant } from "../../../../types"; +import { TryTtsDialogParams } from "./show-dialog-cloud-tts-try"; @customElement("dialog-cloud-try-tts") export class DialogTryTts extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _loadingExample = false; + @state() private _loadingExample = false; - @internalProperty() private _params?: TryTtsDialogParams; + @state() private _params?: TryTtsDialogParams; @query("#target") private _targetInput?: PaperListboxElement; @@ -189,7 +180,7 @@ export class DialogTryTts extends LitElement { }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyleDialog, css` diff --git a/src/panels/config/cloud/alexa/cloud-alexa.ts b/src/panels/config/cloud/alexa/cloud-alexa.ts index 079ebdef10..f3cdda6971 100644 --- a/src/panels/config/cloud/alexa/cloud-alexa.ts +++ b/src/panels/config/cloud/alexa/cloud-alexa.ts @@ -6,17 +6,9 @@ import { mdiCloseBox, mdiCloseBoxMultiple, } from "@mdi/js"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import memoizeOne from "memoize-one"; import { fireEvent } from "../../../../common/dom/fire_event"; import { computeDomain } from "../../../../common/entity/compute_domain"; @@ -59,7 +51,7 @@ class CloudAlexa extends LitElement { @property({ type: Boolean }) public narrow!: boolean; - @internalProperty() private _entities?: AlexaEntity[]; + @state() private _entities?: AlexaEntity[]; @property() private _entityConfigs: CloudPreferences["alexa_entity_configs"] = {}; @@ -440,7 +432,7 @@ class CloudAlexa extends LitElement { ); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/cloud/dialog-cloud-certificate/dialog-cloud-certificate.ts b/src/panels/config/cloud/dialog-cloud-certificate/dialog-cloud-certificate.ts index 3a5e6811b2..8351c20cc0 100644 --- a/src/panels/config/cloud/dialog-cloud-certificate/dialog-cloud-certificate.ts +++ b/src/panels/config/cloud/dialog-cloud-certificate/dialog-cloud-certificate.ts @@ -1,12 +1,6 @@ import "@material/mwc-button"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import { formatDateTime } from "../../../../common/datetime/format_date_time"; import "../../../../components/dialog/ha-paper-dialog"; import type { HaPaperDialog } from "../../../../components/dialog/ha-paper-dialog"; @@ -81,7 +75,7 @@ class DialogCloudCertificate extends LitElement { this._dialog.close(); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/cloud/dialog-manage-cloudhook/dialog-manage-cloudhook.ts b/src/panels/config/cloud/dialog-manage-cloudhook/dialog-manage-cloudhook.ts index 3a1c744c41..2fea1ef018 100644 --- a/src/panels/config/cloud/dialog-manage-cloudhook/dialog-manage-cloudhook.ts +++ b/src/panels/config/cloud/dialog-manage-cloudhook/dialog-manage-cloudhook.ts @@ -2,13 +2,8 @@ import "@material/mwc-button"; import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable"; import "@polymer/paper-input/paper-input"; import type { PaperInputElement } from "@polymer/paper-input/paper-input"; -import { - css, - CSSResult, - html, - internalProperty, - LitElement, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement } from "lit"; +import { state } from "lit/decorators"; import "../../../../components/dialog/ha-paper-dialog"; import type { HaPaperDialog } from "../../../../components/dialog/ha-paper-dialog"; import { showConfirmationDialog } from "../../../../dialogs/generic/show-dialog-box"; @@ -22,7 +17,7 @@ const inputLabel = "Public URL – Click to copy to clipboard"; export class DialogManageCloudhook extends LitElement { protected hass?: HomeAssistant; - @internalProperty() private _params?: WebhookDialogParams; + @state() private _params?: WebhookDialogParams; public async showDialog(params: WebhookDialogParams) { this._params = params; @@ -148,7 +143,7 @@ export class DialogManageCloudhook extends LitElement { this._paperInput.label = inputLabel; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` 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 3ba045e6a5..29068eeb71 100644 --- a/src/panels/config/cloud/google-assistant/cloud-google-assistant.ts +++ b/src/panels/config/cloud/google-assistant/cloud-google-assistant.ts @@ -6,17 +6,9 @@ import { mdiCloseBox, mdiCloseBoxMultiple, } from "@mdi/js"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import memoizeOne from "memoize-one"; import { fireEvent } from "../../../../common/dom/fire_event"; import { computeDomain } from "../../../../common/entity/compute_domain"; @@ -64,7 +56,7 @@ class CloudGoogleAssistant extends LitElement { @property() public narrow!: boolean; - @internalProperty() private _entities?: GoogleEntity[]; + @state() private _entities?: GoogleEntity[]; @property() private _entityConfigs: CloudPreferences["google_entity_configs"] = {}; @@ -486,7 +478,7 @@ class CloudGoogleAssistant extends LitElement { ); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/cloud/ha-config-cloud.ts b/src/panels/config/cloud/ha-config-cloud.ts index 1bf79fac77..8fe5c0a085 100644 --- a/src/panels/config/cloud/ha-config-cloud.ts +++ b/src/panels/config/cloud/ha-config-cloud.ts @@ -1,5 +1,5 @@ import { PolymerElement } from "@polymer/polymer"; -import { customElement, internalProperty, property } from "lit-element"; +import { customElement, property, state } from "lit/decorators"; import { navigate } from "../../../common/navigate"; import { CloudStatus } from "../../../data/cloud"; import { @@ -67,9 +67,9 @@ class HaConfigCloud extends HassRouterPage { }, }; - @internalProperty() private _flashMessage = ""; + @state() private _flashMessage = ""; - @internalProperty() private _loginEmail = ""; + @state() private _loginEmail = ""; private _resolveCloudStatusLoaded!: () => void; @@ -81,7 +81,7 @@ class HaConfigCloud extends HassRouterPage { super.firstUpdated(changedProps); this.addEventListener("cloud-done", (ev) => { this._flashMessage = (ev as any).detail.flashMessage; - navigate(this, "/config/cloud/login"); + navigate("/config/cloud/login"); }); } @@ -95,7 +95,7 @@ class HaConfigCloud extends HassRouterPage { if (oldStatus === undefined) { this._resolveCloudStatusLoaded(); } else if (oldStatus.logged_in !== this.cloudStatus.logged_in) { - navigate(this, this.route.prefix, true); + navigate(this.route.prefix, { replace: true }); } } } diff --git a/src/panels/config/core/ha-config-analytics.ts b/src/panels/config/core/ha-config-analytics.ts index ee145e9f64..1050e7f8ca 100644 --- a/src/panels/config/core/ha-config-analytics.ts +++ b/src/panels/config/core/ha-config-analytics.ts @@ -1,15 +1,13 @@ import "@material/mwc-button/mwc-button"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; import { isComponentLoaded } from "../../../common/config/is_component_loaded"; import "../../../components/ha-analytics"; import { analyticsLearnMore } from "../../../components/ha-analytics-learn-more"; @@ -28,9 +26,9 @@ import type { HomeAssistant } from "../../../types"; class ConfigAnalytics extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _analyticsDetails?: Analytics; + @state() private _analyticsDetails?: Analytics; - @internalProperty() private _error?: string; + @state() private _error?: string; protected render(): TemplateResult { const error = this._error @@ -101,7 +99,7 @@ class ConfigAnalytics extends LitElement { }; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/core/ha-config-core-form.ts b/src/panels/config/core/ha-config-core-form.ts index f14b1ca526..322c2697c1 100644 --- a/src/panels/config/core/ha-config-core-form.ts +++ b/src/panels/config/core/ha-config-core-form.ts @@ -3,16 +3,9 @@ import "@polymer/paper-input/paper-input"; import type { PaperInputElement } from "@polymer/paper-input/paper-input"; import "@polymer/paper-radio-button/paper-radio-button"; import "@polymer/paper-radio-group/paper-radio-group"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import memoizeOne from "memoize-one"; import { UNIT_C } from "../../../common/const"; import "../../../components/ha-card"; import "../../../components/map/ha-location-editor"; @@ -25,15 +18,15 @@ import type { HomeAssistant } from "../../../types"; class ConfigCoreForm extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _working = false; + @state() private _working = false; - @internalProperty() private _location!: [number, number]; + @state() private _location!: [number, number]; - @internalProperty() private _elevation!: string; + @state() private _elevation!: string; - @internalProperty() private _unitSystem!: ConfigUpdateValues["unit_system"]; + @state() private _unitSystem!: ConfigUpdateValues["unit_system"]; - @internalProperty() private _timeZone!: string; + @state() private _timeZone!: string; protected render(): TemplateResult { const canEdit = ["storage", "default"].includes( @@ -62,7 +55,11 @@ class ConfigCoreForm extends LitElement {
@@ -165,11 +162,9 @@ class ConfigCoreForm extends LitElement { input.inputElement.appendChild(createTimezoneListEl()); } - private get _locationValue() { - return this._location !== undefined - ? this._location - : [Number(this.hass.config.latitude), Number(this.hass.config.longitude)]; - } + private _locationValue = memoizeOne( + (location, lat, lng) => location || [Number(lat), Number(lng)] + ); private get _elevationValue() { return this._elevation !== undefined @@ -209,7 +204,11 @@ class ConfigCoreForm extends LitElement { private async _save() { this._working = true; try { - const location = this._locationValue; + const location = this._locationValue( + this._location, + this.hass.config.latitude, + this.hass.config.longitude + ); await saveCoreConfig(this.hass, { latitude: location[0], longitude: location[1], @@ -224,7 +223,7 @@ class ConfigCoreForm extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` .row { display: flex; diff --git a/src/panels/config/core/ha-config-name-form.ts b/src/panels/config/core/ha-config-name-form.ts index 3dbdefb1ed..f99e073cb8 100644 --- a/src/panels/config/core/ha-config-name-form.ts +++ b/src/panels/config/core/ha-config-name-form.ts @@ -3,15 +3,8 @@ import "@polymer/paper-input/paper-input"; import type { PaperInputElement } from "@polymer/paper-input/paper-input"; import "@polymer/paper-radio-button/paper-radio-button"; import "@polymer/paper-radio-group/paper-radio-group"; -import { - css, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import "../../../components/ha-card"; import { ConfigUpdateValues, saveCoreConfig } from "../../../data/core"; import type { PolymerChangedEvent } from "../../../polymer-types"; @@ -21,9 +14,9 @@ import type { HomeAssistant } from "../../../types"; class ConfigNameForm extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _working = false; + @state() private _working = false; - @internalProperty() private _name!: ConfigUpdateValues["location_name"]; + @state() private _name!: ConfigUpdateValues["location_name"]; protected render(): TemplateResult { const canEdit = ["storage", "default"].includes( diff --git a/src/panels/config/core/ha-config-network.ts b/src/panels/config/core/ha-config-network.ts new file mode 100644 index 0000000000..6793673711 --- /dev/null +++ b/src/panels/config/core/ha-config-network.ts @@ -0,0 +1,128 @@ +import "@material/mwc-button/mwc-button"; +import { + css, + CSSResultGroup, + html, + LitElement, + PropertyValues, + TemplateResult, +} from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { isComponentLoaded } from "../../../common/config/is_component_loaded"; +import "../../../components/ha-network"; +import "../../../components/ha-card"; +import "../../../components/ha-checkbox"; +import "../../../components/ha-settings-row"; +import { + NetworkConfig, + getNetworkConfig, + setNetworkConfig, +} from "../../../data/network"; +import { haStyle } from "../../../resources/styles"; +import type { HomeAssistant } from "../../../types"; + +@customElement("ha-config-network") +class ConfigNetwork extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @state() private _networkConfig?: NetworkConfig; + + @state() private _error?: string; + + protected render(): TemplateResult { + if ( + !this.hass.userData?.showAdvanced || + !isComponentLoaded(this.hass, "network") + ) { + return html``; + } + + return html` + +
+ ${this._error ? html`
${this._error}
` : ""} +

+ Configure which network adapters integrations will use. Currently + this setting only affects multicast traffic. A restart is required + for these settings to apply. +

+ +
+
+ + ${this.hass.localize( + "ui.panel.config.core.section.core.core_config.save_button" + )} + +
+
+ `; + } + + protected firstUpdated(changedProps: PropertyValues) { + super.firstUpdated(changedProps); + if (isComponentLoaded(this.hass, "network")) { + this._load(); + } + } + + private async _load() { + this._error = undefined; + try { + this._networkConfig = await getNetworkConfig(this.hass); + } catch (err) { + this._error = err.message || err; + } + } + + private async _save() { + this._error = undefined; + try { + await setNetworkConfig( + this.hass, + this._networkConfig?.configured_adapters || [] + ); + } catch (err) { + this._error = err.message || err; + } + } + + private _configChanged(event: CustomEvent): void { + this._networkConfig = { + ...this._networkConfig!, + configured_adapters: event.detail.configured_adapters, + }; + } + + static get styles(): CSSResultGroup { + return [ + haStyle, + css` + .error { + color: var(--error-color); + } + + ha-settings-row { + padding: 0; + } + + .card-actions { + display: flex; + flex-direction: row-reverse; + justify-content: space-between; + align-items: center; + } + `, // row-reverse so we tab first to "save" + ]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-config-network": ConfigNetwork; + } +} diff --git a/src/panels/config/core/ha-config-section-core.js b/src/panels/config/core/ha-config-section-core.js index 4e50ab56c4..6c74b6f539 100644 --- a/src/panels/config/core/ha-config-section-core.js +++ b/src/panels/config/core/ha-config-section-core.js @@ -11,6 +11,7 @@ import "../ha-config-section"; import "./ha-config-analytics"; import "./ha-config-core-form"; import "./ha-config-name-form"; +import "./ha-config-network"; import "./ha-config-url-form"; /* @@ -30,6 +31,7 @@ class HaConfigSectionCore extends LocalizeMixin(PolymerElement) { + `; diff --git a/src/panels/config/core/ha-config-url-form.ts b/src/panels/config/core/ha-config-url-form.ts index 778fa18a66..6c7e9f0468 100644 --- a/src/panels/config/core/ha-config-url-form.ts +++ b/src/panels/config/core/ha-config-url-form.ts @@ -1,16 +1,8 @@ import "@material/mwc-button/mwc-button"; import "@polymer/paper-input/paper-input"; import type { PaperInputElement } from "@polymer/paper-input/paper-input"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import "../../../components/ha-card"; import { saveCoreConfig } from "../../../data/core"; import type { PolymerChangedEvent } from "../../../polymer-types"; @@ -20,13 +12,13 @@ import type { HomeAssistant } from "../../../types"; class ConfigUrlForm extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _error?: string; + @state() private _error?: string; - @internalProperty() private _working = false; + @state() private _working = false; - @internalProperty() private _external_url?: string; + @state() private _external_url?: string; - @internalProperty() private _internal_url?: string; + @state() private _internal_url?: string; protected render(): TemplateResult { const canEdit = ["storage", "default"].includes( @@ -135,7 +127,7 @@ class ConfigUrlForm extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` .row { display: flex; diff --git a/src/panels/config/customize/ha-config-customize.ts b/src/panels/config/customize/ha-config-customize.ts index c1802cc6aa..d6109546fc 100644 --- a/src/panels/config/customize/ha-config-customize.ts +++ b/src/panels/config/customize/ha-config-customize.ts @@ -1,11 +1,5 @@ -import { - css, - CSSResult, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { property } from "lit/decorators"; import "../../../components/ha-card"; import "../../../layouts/hass-loading-screen"; import "../../../layouts/hass-tabs-subpage"; @@ -80,7 +74,7 @@ class HaConfigCustomize extends LitElement { this._selectedEntityId = routeSegments.length > 1 ? routeSegments[1] : ""; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` a { color: var(--primary-color); diff --git a/src/panels/config/dashboard/ha-config-dashboard.ts b/src/panels/config/dashboard/ha-config-dashboard.ts index 9e740eea4a..f81527cce0 100644 --- a/src/panels/config/dashboard/ha-config-dashboard.ts +++ b/src/panels/config/dashboard/ha-config-dashboard.ts @@ -1,15 +1,8 @@ import { mdiCloudLock } from "@mdi/js"; import "@polymer/app-layout/app-header/app-header"; import "@polymer/app-layout/app-toolbar/app-toolbar"; -import { - css, - CSSResultArray, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import { isComponentLoaded } from "../../../common/config/is_component_loaded"; import "../../../components/ha-card"; import "../../../components/ha-icon-next"; @@ -111,7 +104,7 @@ class HaConfigDashboard extends LitElement { `; } - static get styles(): CSSResultArray { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/dashboard/ha-config-navigation.ts b/src/panels/config/dashboard/ha-config-navigation.ts index f1b958a4fe..ee08290b06 100644 --- a/src/panels/config/dashboard/ha-config-navigation.ts +++ b/src/panels/config/dashboard/ha-config-navigation.ts @@ -1,14 +1,7 @@ import "@polymer/paper-item/paper-icon-item"; import "@polymer/paper-item/paper-item-body"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import { canShowPage } from "../../../common/config/can_show_page"; import "../../../components/ha-card"; import "../../../components/ha-icon-next"; @@ -76,7 +69,7 @@ class HaConfigNavigation extends LitElement { `; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` a { text-decoration: none; diff --git a/src/panels/config/devices/device-detail/ha-device-actions-card.ts b/src/panels/config/devices/device-detail/ha-device-actions-card.ts index a5d5e4507f..bec915a9e3 100644 --- a/src/panels/config/devices/device-detail/ha-device-actions-card.ts +++ b/src/panels/config/devices/device-detail/ha-device-actions-card.ts @@ -1,4 +1,4 @@ -import { customElement } from "lit-element"; +import { customElement } from "lit/decorators"; import "../../../../components/ha-card"; import { DeviceAction, diff --git a/src/panels/config/devices/device-detail/ha-device-automation-card.ts b/src/panels/config/devices/device-detail/ha-device-automation-card.ts index b267581048..741c426f3d 100644 --- a/src/panels/config/devices/device-detail/ha-device-automation-card.ts +++ b/src/panels/config/devices/device-detail/ha-device-automation-card.ts @@ -1,11 +1,5 @@ -import { - css, - CSSResult, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { property } from "lit/decorators"; import "../../../../components/ha-card"; import "../../../../components/ha-chip-set"; import { showAutomationEditor } from "../../../../data/automation"; @@ -78,15 +72,15 @@ export abstract class HaDeviceAutomationCard< return; } if (this.script) { - showScriptEditor(this, { sequence: [automation as DeviceAction] }); + showScriptEditor({ sequence: [automation as DeviceAction] }); return; } const data = {}; data[this.type] = [automation]; - showAutomationEditor(this, data); + showAutomationEditor(data); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` h3 { color: var(--primary-text-color); diff --git a/src/panels/config/devices/device-detail/ha-device-automation-dialog.ts b/src/panels/config/devices/device-detail/ha-device-automation-dialog.ts index d374b14860..eb18201a25 100644 --- a/src/panels/config/devices/device-detail/ha-device-automation-dialog.ts +++ b/src/panels/config/devices/device-detail/ha-device-automation-dialog.ts @@ -1,12 +1,6 @@ -import { - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import "@material/mwc-button/mwc-button"; +import { CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../../../common/dom/fire_event"; import "../../../../components/ha-dialog"; import { @@ -23,19 +17,18 @@ import "./ha-device-actions-card"; import "./ha-device-conditions-card"; import "./ha-device-triggers-card"; import { DeviceAutomationDialogParams } from "./show-dialog-device-automation"; -import "@material/mwc-button/mwc-button"; @customElement("dialog-device-automation") export class DialogDeviceAutomation extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _triggers: DeviceTrigger[] = []; + @state() private _triggers: DeviceTrigger[] = []; - @internalProperty() private _conditions: DeviceCondition[] = []; + @state() private _conditions: DeviceCondition[] = []; - @internalProperty() private _actions: DeviceAction[] = []; + @state() private _actions: DeviceAction[] = []; - @internalProperty() private _params?: DeviceAutomationDialogParams; + @state() private _params?: DeviceAutomationDialogParams; public async showDialog(params: DeviceAutomationDialogParams): Promise { this._params = params; @@ -140,7 +133,7 @@ export class DialogDeviceAutomation extends LitElement { `; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return haStyleDialog; } } diff --git a/src/panels/config/devices/device-detail/ha-device-conditions-card.ts b/src/panels/config/devices/device-detail/ha-device-conditions-card.ts index 54f126667a..ffa084bf6c 100644 --- a/src/panels/config/devices/device-detail/ha-device-conditions-card.ts +++ b/src/panels/config/devices/device-detail/ha-device-conditions-card.ts @@ -1,4 +1,4 @@ -import { customElement } from "lit-element"; +import { customElement } from "lit/decorators"; import "../../../../components/ha-card"; import { DeviceCondition, diff --git a/src/panels/config/devices/device-detail/ha-device-entities-card.ts b/src/panels/config/devices/device-detail/ha-device-entities-card.ts index 946c46e665..5bb169256b 100644 --- a/src/panels/config/devices/device-detail/ha-device-entities-card.ts +++ b/src/panels/config/devices/device-detail/ha-device-entities-card.ts @@ -3,14 +3,13 @@ import "@polymer/paper-item/paper-item"; import "@polymer/paper-item/paper-item-body"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property } from "lit/decorators"; import { computeDomain } from "../../../../common/entity/compute_domain"; import { domainIcon } from "../../../../common/entity/domain_icon"; import "../../../../components/entity/state-badge"; @@ -173,7 +172,7 @@ export class HaDeviceEntitiesCard extends LitElement { ); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { display: block; diff --git a/src/panels/config/devices/device-detail/ha-device-info-card.ts b/src/panels/config/devices/device-detail/ha-device-info-card.ts index af8110fe2c..f442246d0f 100644 --- a/src/panels/config/devices/device-detail/ha-device-info-card.ts +++ b/src/panels/config/devices/device-detail/ha-device-info-card.ts @@ -1,12 +1,5 @@ -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import { AreaRegistryEntry } from "../../../../data/area_registry"; import { computeDeviceName, @@ -94,7 +87,7 @@ export class HaDeviceCard extends LitElement { )})`; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` :host { display: block; diff --git a/src/panels/config/devices/device-detail/ha-device-triggers-card.ts b/src/panels/config/devices/device-detail/ha-device-triggers-card.ts index ec14f55d35..bdf15ee03b 100644 --- a/src/panels/config/devices/device-detail/ha-device-triggers-card.ts +++ b/src/panels/config/devices/device-detail/ha-device-triggers-card.ts @@ -1,4 +1,4 @@ -import { customElement } from "lit-element"; +import { customElement } from "lit/decorators"; import { DeviceTrigger, localizeDeviceAutomationTrigger, diff --git a/src/panels/config/devices/device-detail/integration-elements/mqtt/dialog-mqtt-device-debug-info.ts b/src/panels/config/devices/device-detail/integration-elements/mqtt/dialog-mqtt-device-debug-info.ts index d66d736779..0208bbbd7a 100644 --- a/src/panels/config/devices/device-detail/integration-elements/mqtt/dialog-mqtt-device-debug-info.ts +++ b/src/panels/config/devices/device-detail/integration-elements/mqtt/dialog-mqtt-device-debug-info.ts @@ -1,13 +1,6 @@ import "@material/mwc-button/mwc-button"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, state } from "lit/decorators"; import { computeStateName } from "../../../../../../common/entity/compute_state_name"; import { computeRTLDirection } from "../../../../../../common/util/compute_rtl"; import "../../../../../../components/ha-dialog"; @@ -29,13 +22,13 @@ import { MQTTDeviceDebugInfoDialogParams } from "./show-dialog-mqtt-device-debug class DialogMQTTDeviceDebugInfo extends LitElement { public hass!: HomeAssistant; - @internalProperty() private _params?: MQTTDeviceDebugInfoDialogParams; + @state() private _params?: MQTTDeviceDebugInfoDialogParams; - @internalProperty() private _debugInfo?: MQTTDeviceDebugInfo; + @state() private _debugInfo?: MQTTDeviceDebugInfo; - @internalProperty() private _showAsYaml = true; + @state() private _showAsYaml = true; - @internalProperty() private _showDeserialized = true; + @state() private _showDeserialized = true; public async showDialog( params: MQTTDeviceDebugInfoDialogParams @@ -56,7 +49,7 @@ class DialogMQTTDeviceDebugInfo extends LitElement { return html` ${safeDump(payload)} ` + ? html`
${dump(payload)}
` : html`
${JSON.stringify(payload, null, 2)}
`} `; } @@ -48,7 +40,7 @@ class MQTTDiscoveryPayload extends LitElement { this._open = !this._open; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` .expander { cursor: pointer; diff --git a/src/panels/config/devices/device-detail/integration-elements/mqtt/mqtt-messages.ts b/src/panels/config/devices/device-detail/integration-elements/mqtt/mqtt-messages.ts index 15a8ce0051..d07f83fb5f 100644 --- a/src/panels/config/devices/device-detail/integration-elements/mqtt/mqtt-messages.ts +++ b/src/panels/config/devices/device-detail/integration-elements/mqtt/mqtt-messages.ts @@ -1,15 +1,7 @@ -import { safeDump } from "js-yaml"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +import { dump } from "js-yaml"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import { formatTimeWithSeconds } from "../../../../../../common/datetime/format_time"; import { MQTTMessage } from "../../../../../../data/mqtt"; import { HomeAssistant } from "../../../../../../types"; @@ -28,11 +20,11 @@ class MQTTMessages extends LitElement { @property() public summary!: string; - @internalProperty() private _open = false; + @state() private _open = false; - @internalProperty() private _payloadsJson = new WeakMap(); + @state() private _payloadsJson = new WeakMap(); - @internalProperty() private _showTopic = false; + @state() private _showTopic = false; protected firstUpdated(): void { this.messages.forEach((message) => { @@ -100,7 +92,7 @@ class MQTTMessages extends LitElement { return json ? html` ${this.showAsYaml - ? html`
${safeDump(json)}
` + ? html`
${dump(json)}
` : html`
${JSON.stringify(json, null, 2)}
`} ` : html` ${message.payload} `; @@ -133,7 +125,7 @@ class MQTTMessages extends LitElement { this._open = !this._open; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` .expander { cursor: pointer; diff --git a/src/panels/config/devices/device-detail/integration-elements/ozw/ha-device-actions-ozw.ts b/src/panels/config/devices/device-detail/integration-elements/ozw/ha-device-actions-ozw.ts index 82f770c928..3608c6514d 100644 --- a/src/panels/config/devices/device-detail/integration-elements/ozw/ha-device-actions-ozw.ts +++ b/src/panels/config/devices/device-detail/integration-elements/ozw/ha-device-actions-ozw.ts @@ -1,14 +1,13 @@ import "@material/mwc-button/mwc-button"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property } from "lit/decorators"; import { navigate } from "../../../../../../common/navigate"; import { DeviceRegistryEntry } from "../../../../../../data/device_registry"; import { @@ -67,12 +66,11 @@ export class HaDeviceActionsOzw extends LitElement { private async _nodeDetailsClicked() { navigate( - this, `/config/ozw/network/${this.ozw_instance}/node/${this.node_id}/dashboard` ); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/devices/device-detail/integration-elements/ozw/ha-device-info-ozw.ts b/src/panels/config/devices/device-detail/integration-elements/ozw/ha-device-info-ozw.ts index f23ce1c636..bfb4d7bba8 100644 --- a/src/panels/config/devices/device-detail/integration-elements/ozw/ha-device-info-ozw.ts +++ b/src/panels/config/devices/device-detail/integration-elements/ozw/ha-device-info-ozw.ts @@ -1,14 +1,12 @@ import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; import { DeviceRegistryEntry } from "../../../../../../data/device_registry"; import { fetchOZWNodeStatus, @@ -31,7 +29,7 @@ export class HaDeviceInfoOzw extends LitElement { @property() private ozw_instance = 1; - @internalProperty() private _ozwDevice?: OZWDevice; + @state() private _ozwDevice?: OZWDevice; protected updated(changedProperties: PropertyValues) { if (changedProperties.has("device")) { @@ -85,7 +83,7 @@ export class HaDeviceInfoOzw extends LitElement { `; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/devices/device-detail/integration-elements/tasmota/ha-device-actions-tasmota.ts b/src/panels/config/devices/device-detail/integration-elements/tasmota/ha-device-actions-tasmota.ts index 96253e2bd9..33bc22a3a3 100644 --- a/src/panels/config/devices/device-detail/integration-elements/tasmota/ha-device-actions-tasmota.ts +++ b/src/panels/config/devices/device-detail/integration-elements/tasmota/ha-device-actions-tasmota.ts @@ -1,12 +1,5 @@ -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import { DeviceRegistryEntry } from "../../../../../../data/device_registry"; import { removeTasmotaDeviceEntry } from "../../../../../../data/tasmota"; import { showConfirmationDialog } from "../../../../../../dialogs/generic/show-dialog-box"; @@ -39,7 +32,7 @@ export class HaDeviceActionsTasmota extends LitElement { await removeTasmotaDeviceEntry(this.hass!, this.device.id); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/devices/device-detail/integration-elements/zha/ha-device-actions-zha.ts b/src/panels/config/devices/device-detail/integration-elements/zha/ha-device-actions-zha.ts index 4d0b380bb2..2a0337c043 100644 --- a/src/panels/config/devices/device-detail/integration-elements/zha/ha-device-actions-zha.ts +++ b/src/panels/config/devices/device-detail/integration-elements/zha/ha-device-actions-zha.ts @@ -1,14 +1,12 @@ import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; import { navigate } from "../../../../../../common/navigate"; import { DeviceRegistryEntry } from "../../../../../../data/device_registry"; import { fetchZHADevice, ZHADevice } from "../../../../../../data/zha"; @@ -16,9 +14,9 @@ import { showConfirmationDialog } from "../../../../../../dialogs/generic/show-d import { haStyle } from "../../../../../../resources/styles"; import { HomeAssistant } from "../../../../../../types"; import { showZHAClusterDialog } from "../../../../integrations/integration-panels/zha/show-dialog-zha-cluster"; +import { showZHADeviceChildrenDialog } from "../../../../integrations/integration-panels/zha/show-dialog-zha-device-children"; import { showZHADeviceZigbeeInfoDialog } from "../../../../integrations/integration-panels/zha/show-dialog-zha-device-zigbee-info"; import { showZHAReconfigureDeviceDialog } from "../../../../integrations/integration-panels/zha/show-dialog-zha-reconfigure-device"; -import { showZHADeviceChildrenDialog } from "../../../../integrations/integration-panels/zha/show-dialog-zha-device-children"; @customElement("ha-device-actions-zha") export class HaDeviceActionsZha extends LitElement { @@ -26,7 +24,7 @@ export class HaDeviceActionsZha extends LitElement { @property() public device!: DeviceRegistryEntry; - @internalProperty() private _zhaDevice?: ZHADevice; + @state() private _zhaDevice?: ZHADevice; protected updated(changedProperties: PropertyValues) { if (changedProperties.has("device")) { @@ -109,14 +107,11 @@ export class HaDeviceActionsZha extends LitElement { } private _onAddDevicesClick() { - navigate(this, "/config/zha/add/" + this._zhaDevice!.ieee); + navigate(`/config/zha/add/${this._zhaDevice!.ieee}`); } private _onViewInVisualizationClick() { - navigate( - this, - "/config/zha/visualization/" + this._zhaDevice!.device_reg_id - ); + navigate(`/config/zha/visualization/${this._zhaDevice!.device_reg_id}`); } private async _handleZigbeeInfoClicked() { @@ -145,7 +140,7 @@ export class HaDeviceActionsZha extends LitElement { history.back(); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/devices/device-detail/integration-elements/zha/ha-device-info-zha.ts b/src/panels/config/devices/device-detail/integration-elements/zha/ha-device-info-zha.ts index 5440940f16..28a3e3e0e6 100644 --- a/src/panels/config/devices/device-detail/integration-elements/zha/ha-device-info-zha.ts +++ b/src/panels/config/devices/device-detail/integration-elements/zha/ha-device-info-zha.ts @@ -1,14 +1,12 @@ import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; import { DeviceRegistryEntry } from "../../../../../../data/device_registry"; import { fetchZHADevice, ZHADevice } from "../../../../../../data/zha"; import { haStyle } from "../../../../../../resources/styles"; @@ -21,7 +19,7 @@ export class HaDeviceActionsZha extends LitElement { @property() public device!: DeviceRegistryEntry; - @internalProperty() private _zhaDevice?: ZHADevice; + @state() private _zhaDevice?: ZHADevice; protected updated(changedProperties: PropertyValues) { if (changedProperties.has("device")) { @@ -77,7 +75,7 @@ export class HaDeviceActionsZha extends LitElement { `; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/devices/device-detail/integration-elements/zwave_js/ha-device-actions-zwave_js.ts b/src/panels/config/devices/device-detail/integration-elements/zwave_js/ha-device-actions-zwave_js.ts index a43d8126f3..e258e66835 100644 --- a/src/panels/config/devices/device-detail/integration-elements/zwave_js/ha-device-actions-zwave_js.ts +++ b/src/panels/config/devices/device-detail/integration-elements/zwave_js/ha-device-actions-zwave_js.ts @@ -1,15 +1,13 @@ import "@material/mwc-button/mwc-button"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; import { DeviceRegistryEntry } from "../../../../../../data/device_registry"; import { getIdentifiersFromDevice, @@ -25,9 +23,9 @@ export class HaDeviceActionsZWaveJS extends LitElement { @property() public device!: DeviceRegistryEntry; - @internalProperty() private _entryId?: string; + @state() private _entryId?: string; - @internalProperty() private _nodeId?: number; + @state() private _nodeId?: number; protected updated(changedProperties: PropertyValues) { if (changedProperties.has("device")) { @@ -70,7 +68,7 @@ export class HaDeviceActionsZWaveJS extends LitElement { }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` 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 ed35383b16..f8558fc5fb 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 @@ -1,23 +1,20 @@ import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; import { DeviceRegistryEntry } from "../../../../../../data/device_registry"; import { - getIdentifiersFromDevice, fetchNodeStatus, + getIdentifiersFromDevice, + nodeStatus, ZWaveJSNode, ZWaveJSNodeIdentifiers, - nodeStatus, } from "../../../../../../data/zwave_js"; - import { haStyle } from "../../../../../../resources/styles"; import { HomeAssistant } from "../../../../../../types"; @@ -27,13 +24,13 @@ export class HaDeviceInfoZWaveJS extends LitElement { @property() public device!: DeviceRegistryEntry; - @internalProperty() private _entryId?: string; + @state() private _entryId?: string; - @internalProperty() private _nodeId?: number; + @state() private _nodeId?: number; - @internalProperty() private _homeId?: string; + @state() private _homeId?: string; - @internalProperty() private _node?: ZWaveJSNode; + @state() private _node?: ZWaveJSNode; protected updated(changedProperties: PropertyValues) { if (changedProperties.has("device")) { @@ -95,7 +92,7 @@ export class HaDeviceInfoZWaveJS extends LitElement { `; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` 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 99bd51dcb7..5a36906c77 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 @@ -3,16 +3,8 @@ import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; import "@polymer/paper-input/paper-input"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../../../common/dom/fire_event"; import "../../../../components/ha-area-picker"; import "../../../../components/ha-dialog"; @@ -27,17 +19,17 @@ import { DeviceRegistryDetailDialogParams } from "./show-dialog-device-registry- class DialogDeviceRegistryDetail extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _nameByUser!: string; + @state() private _nameByUser!: string; - @internalProperty() private _error?: string; + @state() private _error?: string; - @internalProperty() private _params?: DeviceRegistryDetailDialogParams; + @state() private _params?: DeviceRegistryDetailDialogParams; - @internalProperty() private _areaId?: string | null; + @state() private _areaId?: string | null; - @internalProperty() private _disabledBy!: string | null; + @state() private _disabledBy!: string | null; - @internalProperty() private _submitting?: boolean; + @state() private _submitting?: boolean; public async showDialog( params: DeviceRegistryDetailDialogParams @@ -159,7 +151,7 @@ class DialogDeviceRegistryDetail extends LitElement { } } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, haStyleDialog, diff --git a/src/panels/config/devices/ha-config-device-page.ts b/src/panels/config/devices/ha-config-device-page.ts index bf2575ee97..3e2cdcfd4e 100644 --- a/src/panels/config/devices/ha-config-device-page.ts +++ b/src/panels/config/devices/ha-config-device-page.ts @@ -1,15 +1,7 @@ import "@polymer/paper-tooltip/paper-tooltip"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import { ifDefined } from "lit-html/directives/if-defined"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { ifDefined } from "lit/directives/if-defined"; import memoizeOne from "memoize-one"; import { isComponentLoaded } from "../../../common/config/is_component_loaded"; import { computeStateDomain } from "../../../common/entity/compute_state_domain"; @@ -75,7 +67,7 @@ export class HaConfigDevicePage extends LitElement { @property() public route!: Route; - @internalProperty() private _related?: RelatedResult; + @state() private _related?: RelatedResult; private _device = memoizeOne( ( @@ -323,28 +315,28 @@ export class HaConfigDevicePage extends LitElement { ${this._related?.automation?.length ? this._related.automation.map((automation) => { - const state = this.hass.states[automation]; - return state + const entityState = this.hass.states[automation]; + return entityState ? html`
- ${computeStateName(state)} + ${computeStateName(entityState)} - ${!state.attributes.id + ${!entityState.attributes.id ? html` ${this.hass.localize( @@ -402,28 +394,29 @@ export class HaConfigDevicePage extends LitElement { ${ this._related?.scene?.length ? this._related.scene.map((scene) => { - const state = this.hass.states[scene]; - return state + const entityState = this.hass.states[scene]; + return entityState ? html`
- ${computeStateName(state)} + ${computeStateName(entityState)} - ${!state.attributes.id + ${!entityState.attributes.id ? html` ${this._related?.script?.length ? this._related.script.map((script) => { - const state = this.hass.states[script]; - return state + const entityState = this.hass.states[script]; + return entityState ? html` - ${computeStateName(state)} + ${computeStateName(entityState)} @@ -519,8 +512,8 @@ export class HaConfigDevicePage extends LitElement { if (entity.name) { return entity.name; } - const state = this.hass.states[entity.entity_id]; - return state ? computeStateName(state) : null; + const entityState = this.hass.states[entity.entity_id]; + return entityState ? computeStateName(entityState) : null; } private _onImageLoad(ev) { @@ -540,7 +533,7 @@ export class HaConfigDevicePage extends LitElement { this._entities(this.deviceId, this.entities).forEach((entity) => { entities[entity.entity_id] = ""; }); - showSceneEditor(this, { + showSceneEditor({ entities, }); } @@ -748,7 +741,7 @@ export class HaConfigDevicePage extends LitElement { }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/devices/ha-config-devices-dashboard.ts b/src/panels/config/devices/ha-config-devices-dashboard.ts index 67dd2fa2c2..b30b7a24d4 100644 --- a/src/panels/config/devices/ha-config-devices-dashboard.ts +++ b/src/panels/config/devices/ha-config-devices-dashboard.ts @@ -2,16 +2,8 @@ import "@material/mwc-list/mwc-list-item"; import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item"; import { mdiCancel, mdiFilterVariant, mdiPlus } from "@mdi/js"; import "@polymer/paper-tooltip/paper-tooltip"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import { HASSDomEvent } from "../../../common/dom/fire_event"; import { computeStateDomain } from "../../../common/entity/compute_state_domain"; @@ -68,15 +60,37 @@ export class HaConfigDeviceDashboard extends LitElement { @property() public route!: Route; - @internalProperty() private _searchParms = new URLSearchParams( - window.location.search - ); + @state() private _searchParms = new URLSearchParams(window.location.search); - @internalProperty() private _showDisabled = false; + @state() private _showDisabled = false; - @internalProperty() private _filter = ""; + @state() private _filter = ""; - @internalProperty() private _numHiddenDevices = 0; + @state() private _numHiddenDevices = 0; + + private _ignoreLocationChange = false; + + public constructor() { + super(); + window.addEventListener("location-changed", () => { + if (this._ignoreLocationChange) { + this._ignoreLocationChange = false; + return; + } + if ( + window.location.search.substring(1) !== this._searchParms.toString() + ) { + this._searchParms = new URLSearchParams(window.location.search); + } + }); + window.addEventListener("popstate", () => { + if ( + window.location.search.substring(1) !== this._searchParms.toString() + ) { + this._searchParms = new URLSearchParams(window.location.search); + } + }); + } private _activeFilters = memoizeOne( ( @@ -88,10 +102,6 @@ export class HaConfigDeviceDashboard extends LitElement { filters.forEach((value, key) => { switch (key) { case "config_entry": { - // If we are requested to show the devices for a given config entry, - // also show the disabled ones by default. - this._showDisabled = true; - const configEntry = entries.find( (entry) => entry.entry_id === value ); @@ -128,7 +138,6 @@ export class HaConfigDeviceDashboard extends LitElement { ) => { // Some older installations might have devices pointing at invalid entryIDs // So we guard for that. - let outputDevices: DeviceRowData[] = devices; const deviceLookup: { [deviceId: string]: DeviceRegistryEntry } = {}; @@ -325,14 +334,14 @@ export class HaConfigDeviceDashboard extends LitElement { } ); - public constructor() { - super(); - window.addEventListener("location-changed", () => { - this._searchParms = new URLSearchParams(window.location.search); - }); - window.addEventListener("popstate", () => { - this._searchParms = new URLSearchParams(window.location.search); - }); + public willUpdate(changedProps) { + if (changedProps.has("_searchParms")) { + if (this._searchParms.get("config_entry")) { + // If we are requested to show the devices for a given config entry, + // also show the disabled ones by default. + this._showDisabled = true; + } + } } protected render(): TemplateResult { @@ -445,7 +454,8 @@ export class HaConfigDeviceDashboard extends LitElement { private _handleRowClicked(ev: HASSDomEvent) { const deviceId = ev.detail.id; - navigate(this, `/config/devices/device/${deviceId}`); + this._ignoreLocationChange = true; + navigate(`/config/devices/device/${deviceId}`); } private _showDisabledChanged(ev: CustomEvent) { @@ -463,12 +473,12 @@ export class HaConfigDeviceDashboard extends LitElement { if ( this._activeFilters(this.entries, this._searchParms, this.hass.localize) ) { - navigate(this, window.location.pathname, true); + navigate(window.location.pathname, { replace: true }); } this._showDisabled = true; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ css` ha-button-menu { diff --git a/src/panels/config/devices/ha-config-devices.ts b/src/panels/config/devices/ha-config-devices.ts index 82dd2d7720..fe5625565c 100644 --- a/src/panels/config/devices/ha-config-devices.ts +++ b/src/panels/config/devices/ha-config-devices.ts @@ -1,10 +1,6 @@ import { UnsubscribeFunc } from "home-assistant-js-websocket"; -import { - customElement, - internalProperty, - property, - PropertyValues, -} from "lit-element"; +import { PropertyValues } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { AreaRegistryEntry, subscribeAreaRegistry, @@ -49,15 +45,15 @@ class HaConfigDevices extends HassRouterPage { }, }; - @internalProperty() private _configEntries: ConfigEntry[] = []; + @state() private _configEntries: ConfigEntry[] = []; - @internalProperty() + @state() private _entityRegistryEntries: EntityRegistryEntry[] = []; - @internalProperty() + @state() private _deviceRegistryEntries: DeviceRegistryEntry[] = []; - @internalProperty() private _areas: AreaRegistryEntry[] = []; + @state() private _areas: AreaRegistryEntry[] = []; private _unsubs?: UnsubscribeFunc[]; diff --git a/src/panels/config/entities/dialog-entity-editor.ts b/src/panels/config/entities/dialog-entity-editor.ts index c0f4f18ea7..a9f02c9137 100644 --- a/src/panels/config/entities/dialog-entity-editor.ts +++ b/src/panels/config/entities/dialog-entity-editor.ts @@ -3,17 +3,9 @@ import "@material/mwc-tab"; import "@material/mwc-tab-bar"; import { mdiClose, mdiTune } from "@mdi/js"; import { HassEntity } from "home-assistant-js-websocket"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import { cache } from "lit-html/directives/cache"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { cache } from "lit/directives/cache"; import { dynamicElement } from "../../../common/dom/dynamic-element-directive"; import { fireEvent } from "../../../common/dom/fire_event"; import { computeStateName } from "../../../common/entity/compute_state_name"; @@ -26,13 +18,13 @@ import { ExtEntityRegistryEntry, getExtendedEntityRegistryEntry, } from "../../../data/entity_registry"; +import { replaceDialog } from "../../../dialogs/make-dialog-manager"; import { haStyleDialog } from "../../../resources/styles"; import type { HomeAssistant } from "../../../types"; import { documentationUrl } from "../../../util/documentation-url"; import { PLATFORMS_WITH_SETTINGS_TAB } from "./const"; import "./entity-registry-settings"; import type { EntityRegistryDetailDialogParams } from "./show-dialog-entity-editor"; -import { replaceDialog } from "../../../dialogs/make-dialog-manager"; interface Tabs { [key: string]: Tab; @@ -47,30 +39,24 @@ interface Tab { export class DialogEntityEditor extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _params?: EntityRegistryDetailDialogParams; + @state() private _params?: EntityRegistryDetailDialogParams; - @internalProperty() private _entry?: - | EntityRegistryEntry - | ExtEntityRegistryEntry - | null; + @state() private _entry?: EntityRegistryEntry | ExtEntityRegistryEntry | null; - @internalProperty() private _curTab = "tab-settings"; + @state() private _curTab = "tab-settings"; - @internalProperty() private _extraTabs: Tabs = {}; + @state() private _extraTabs: Tabs = {}; - @internalProperty() private _settingsElementTag?: string; + @state() private _settingsElementTag?: string; private _curTabIndex = 0; - public async showDialog( - params: EntityRegistryDetailDialogParams - ): Promise { + public showDialog(params: EntityRegistryDetailDialogParams): void { this._params = params; this._entry = undefined; this._settingsElementTag = undefined; this._extraTabs = {}; this._getEntityReg(); - await this.updateComplete; } public closeDialog(): void { @@ -256,7 +242,7 @@ export class DialogEntityEditor extends LitElement { this.closeDialog(); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyleDialog, css` diff --git a/src/panels/config/entities/editor-tabs/settings/entity-settings-helper-tab.ts b/src/panels/config/entities/editor-tabs/settings/entity-settings-helper-tab.ts index dae2b5f42e..8d48ffd2e6 100644 --- a/src/panels/config/entities/editor-tabs/settings/entity-settings-helper-tab.ts +++ b/src/panels/config/entities/editor-tabs/settings/entity-settings-helper-tab.ts @@ -1,15 +1,12 @@ import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, - query, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state, query } from "lit/decorators"; import { isComponentLoaded } from "../../../../../common/config/is_component_loaded"; import { dynamicElement } from "../../../../../common/dom/dynamic-element-directive"; import { fireEvent } from "../../../../../common/dom/fire_event"; @@ -110,13 +107,13 @@ export class EntityRegistrySettingsHelper extends LitElement { @property() public entry!: ExtEntityRegistryEntry; - @internalProperty() private _error?: string; + @state() private _error?: string; - @internalProperty() private _item?: Helper | null; + @state() private _item?: Helper | null; - @internalProperty() private _submitting?: boolean; + @state() private _submitting?: boolean; - @internalProperty() private _componentLoaded?: boolean; + @state() private _componentLoaded?: boolean; @query("ha-registry-basic-editor") private _registryEditor?: HaEntityRegistryBasicEditor; @@ -242,7 +239,7 @@ export class EntityRegistrySettingsHelper extends LitElement { } } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/entities/entity-registry-basic-editor.ts b/src/panels/config/entities/entity-registry-basic-editor.ts index 1063639aa4..af79a115aa 100644 --- a/src/panels/config/entities/entity-registry-basic-editor.ts +++ b/src/panels/config/entities/entity-registry-basic-editor.ts @@ -1,15 +1,7 @@ import "@polymer/paper-input/paper-input"; import { UnsubscribeFunc } from "home-assistant-js-websocket"; -import { - css, - customElement, - html, - internalProperty, - LitElement, - property, - PropertyValues, - TemplateResult, -} from "lit-element"; +import { css, html, LitElement, PropertyValues, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { computeDomain } from "../../../common/entity/compute_domain"; import "../../../components/ha-area-picker"; import "../../../components/ha-switch"; @@ -34,19 +26,19 @@ export class HaEntityRegistryBasicEditor extends SubscribeMixin(LitElement) { @property() public entry!: ExtEntityRegistryEntry; - @internalProperty() private _origEntityId!: string; + @state() private _origEntityId!: string; - @internalProperty() private _entityId!: string; + @state() private _entityId!: string; - @internalProperty() private _areaId?: string | null; + @state() private _areaId?: string | null; - @internalProperty() private _disabledBy!: string | null; + @state() private _disabledBy!: string | null; private _deviceLookup?: Record; - @internalProperty() private _device?: DeviceRegistryEntry; + @state() private _device?: DeviceRegistryEntry; - @internalProperty() private _submitting?: boolean; + @state() private _submitting?: boolean; public async updateEntry(): Promise { this._submitting = true; diff --git a/src/panels/config/entities/entity-registry-settings.ts b/src/panels/config/entities/entity-registry-settings.ts index 6e60b08bfe..36bc24b843 100644 --- a/src/panels/config/entities/entity-registry-settings.ts +++ b/src/panels/config/entities/entity-registry-settings.ts @@ -3,15 +3,13 @@ import "@polymer/paper-input/paper-input"; import { HassEntity, UnsubscribeFunc } from "home-assistant-js-websocket"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../../common/dom/fire_event"; import { computeDomain } from "../../../common/entity/compute_domain"; import { domainIcon } from "../../../common/entity/domain_icon"; @@ -47,23 +45,23 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) { @property() public entry!: ExtEntityRegistryEntry; - @internalProperty() private _name!: string; + @state() private _name!: string; - @internalProperty() private _icon!: string; + @state() private _icon!: string; - @internalProperty() private _entityId!: string; + @state() private _entityId!: string; - @internalProperty() private _areaId?: string | null; + @state() private _areaId?: string | null; - @internalProperty() private _disabledBy!: string | null; + @state() private _disabledBy!: string | null; private _deviceLookup?: Record; - @internalProperty() private _device?: DeviceRegistryEntry; + @state() private _device?: DeviceRegistryEntry; - @internalProperty() private _error?: string; + @state() private _error?: string; - @internalProperty() private _submitting?: boolean; + @state() private _submitting?: boolean; private _origEntityId!: string; @@ -359,7 +357,7 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) { this._disabledBy = (ev.target as HaSwitch).checked ? null : "user"; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/entities/ha-config-entities.ts b/src/panels/config/entities/ha-config-entities.ts index d42ef240cf..40c32e4d3c 100644 --- a/src/panels/config/entities/ha-config-entities.ts +++ b/src/panels/config/entities/ha-config-entities.ts @@ -13,19 +13,10 @@ import "@polymer/paper-item/paper-icon-item"; import "@polymer/paper-listbox/paper-listbox"; import "@polymer/paper-tooltip/paper-tooltip"; import { UnsubscribeFunc } from "home-assistant-js-websocket"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - query, - TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; -import { styleMap } from "lit-html/directives/style-map"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state, query } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; +import { styleMap } from "lit/directives/style-map"; import memoize from "memoize-one"; import type { HASSDomEvent } from "../../../common/dom/fire_event"; import { computeDomain } from "../../../common/entity/compute_domain"; @@ -101,31 +92,29 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { @property() public route!: Route; - @internalProperty() private _entities?: EntityRegistryEntry[]; + @state() private _entities?: EntityRegistryEntry[]; - @internalProperty() private _devices?: DeviceRegistryEntry[]; + @state() private _devices?: DeviceRegistryEntry[]; - @internalProperty() private _areas: AreaRegistryEntry[] = []; + @state() private _areas: AreaRegistryEntry[] = []; - @internalProperty() private _stateEntities: StateEntity[] = []; + @state() private _stateEntities: StateEntity[] = []; @property() public _entries?: ConfigEntry[]; - @internalProperty() private _showDisabled = false; + @state() private _showDisabled = false; - @internalProperty() private _showUnavailable = true; + @state() private _showUnavailable = true; - @internalProperty() private _showReadOnly = true; + @state() private _showReadOnly = true; - @internalProperty() private _filter = ""; + @state() private _filter = ""; - @internalProperty() private _numHiddenEntities = 0; + @state() private _numHiddenEntities = 0; - @internalProperty() private _searchParms = new URLSearchParams( - window.location.search - ); + @state() private _searchParms = new URLSearchParams(window.location.search); - @internalProperty() private _selectedEntities: string[] = []; + @state() private _selectedEntities: string[] = []; @query("hass-tabs-subpage-data-table", true) private _dataTable!: HaTabsSubpageDataTable; @@ -402,10 +391,18 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { public constructor() { super(); window.addEventListener("location-changed", () => { - this._searchParms = new URLSearchParams(window.location.search); + if ( + window.location.search.substring(1) !== this._searchParms.toString() + ) { + this._searchParms = new URLSearchParams(window.location.search); + } }); window.addEventListener("popstate", () => { - this._searchParms = new URLSearchParams(window.location.search); + if ( + window.location.search.substring(1) !== this._searchParms.toString() + ) { + this._searchParms = new URLSearchParams(window.location.search); + } }); } @@ -634,8 +631,8 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { loadEntityEditorDialog(); } - protected updated(changedProps): void { - super.updated(changedProps); + public willUpdate(changedProps): void { + super.willUpdate(changedProps); const oldHass = changedProps.get("hass"); let changed = false; if (!this.hass || !this._entities) { @@ -840,14 +837,14 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { if ( this._activeFilters(this._searchParms, this.hass.localize, this._entries) ) { - navigate(this, window.location.pathname, true); + navigate(window.location.pathname, { replace: true }); } this._showDisabled = true; this._showReadOnly = true; this._showUnavailable = true; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/ha-config-section.ts b/src/panels/config/ha-config-section.ts index f98ef27012..01211a9b7a 100644 --- a/src/panels/config/ha-config-section.ts +++ b/src/panels/config/ha-config-section.ts @@ -1,5 +1,6 @@ -import { css, customElement, html, LitElement, property } from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +import { css, html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; @customElement("ha-config-section") export class HaConfigSection extends LitElement { diff --git a/src/panels/config/ha-entity-config.ts b/src/panels/config/ha-entity-config.ts index 9fb1d804dd..87a3fa0687 100644 --- a/src/panels/config/ha-entity-config.ts +++ b/src/panels/config/ha-entity-config.ts @@ -1,15 +1,13 @@ import "@material/mwc-button"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, LitElement, - property, PropertyValues, - query, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, query } from "lit/decorators"; import "../../components/buttons/ha-progress-button"; import "../../components/entity/ha-entity-picker"; import "../../components/ha-card"; @@ -103,7 +101,7 @@ export class HaEntityConfig extends LitElement { } } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/ha-panel-config.ts b/src/panels/config/ha-panel-config.ts index 831bb4682d..e31711cf99 100644 --- a/src/panels/config/ha-panel-config.ts +++ b/src/panels/config/ha-panel-config.ts @@ -22,12 +22,8 @@ import { import "@polymer/paper-item/paper-item"; import "@polymer/paper-item/paper-item-body"; import { PolymerElement } from "@polymer/polymer"; -import { - customElement, - internalProperty, - property, - PropertyValues, -} from "lit-element"; +import { PropertyValues } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { isComponentLoaded } from "../../common/config/is_component_loaded"; import { listenMediaQuery } from "../../common/dom/media_query"; import { CloudStatus, fetchCloudStatus } from "../../data/cloud"; @@ -316,11 +312,11 @@ class HaPanelConfig extends HassRouterPage { }, }; - @internalProperty() private _wideSidebar = false; + @state() private _wideSidebar = false; - @internalProperty() private _wide = false; + @state() private _wide = false; - @internalProperty() private _cloudStatus?: CloudStatus; + @state() private _cloudStatus?: CloudStatus; private _listeners: Array<() => void> = []; diff --git a/src/panels/config/helpers/dialog-helper-detail.ts b/src/panels/config/helpers/dialog-helper-detail.ts index b4eeed86be..3740b8bdaf 100644 --- a/src/panels/config/helpers/dialog-helper-detail.ts +++ b/src/panels/config/helpers/dialog-helper-detail.ts @@ -1,18 +1,9 @@ import "@material/mwc-button/mwc-button"; import "@polymer/paper-item/paper-icon-item"; import "@polymer/paper-tooltip/paper-tooltip"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - query, - TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state, query } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import { isComponentLoaded } from "../../../common/config/is_component_loaded"; import { dynamicElement } from "../../../common/dom/dynamic-element-directive"; import { domainIcon } from "../../../common/entity/domain_icon"; @@ -49,15 +40,15 @@ const HELPERS = { export class DialogHelperDetail extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _item?: Helper; + @state() private _item?: Helper; - @internalProperty() private _opened = false; + @state() private _opened = false; - @internalProperty() private _platform?: string; + @state() private _platform?: string; - @internalProperty() private _error?: string; + @state() private _error?: string; - @internalProperty() private _submitting = false; + @state() private _submitting = false; @query(".form") private _form?: HTMLDivElement; @@ -77,7 +68,7 @@ export class DialogHelperDetail extends LitElement { return html` ; - @internalProperty() private _name!: string; + @state() private _name!: string; - @internalProperty() private _icon!: string; + @state() private _icon!: string; - @internalProperty() private _maximum?: number; + @state() private _maximum?: number; - @internalProperty() private _minimum?: number; + @state() private _minimum?: number; - @internalProperty() private _restore?: boolean; + @state() private _restore?: boolean; - @internalProperty() private _initial?: number; + @state() private _initial?: number; - @internalProperty() private _step?: number; + @state() private _step?: number; set item(item: Counter) { this._item = item; @@ -183,7 +175,7 @@ class HaCounterForm extends LitElement { }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/helpers/forms/ha-input_boolean-form.ts b/src/panels/config/helpers/forms/ha-input_boolean-form.ts index 90656b861d..419819d4f2 100644 --- a/src/panels/config/helpers/forms/ha-input_boolean-form.ts +++ b/src/panels/config/helpers/forms/ha-input_boolean-form.ts @@ -1,14 +1,6 @@ import "@polymer/paper-input/paper-input"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../../../common/dom/fire_event"; import "../../../../components/ha-icon-input"; import { InputBoolean } from "../../../../data/input_boolean"; @@ -23,9 +15,9 @@ class HaInputBooleanForm extends LitElement { private _item?: InputBoolean; - @internalProperty() private _name!: string; + @state() private _name!: string; - @internalProperty() private _icon!: string; + @state() private _icon!: string; set item(item: InputBoolean) { this._item = item; @@ -100,7 +92,7 @@ class HaInputBooleanForm extends LitElement { }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/helpers/forms/ha-input_datetime-form.ts b/src/panels/config/helpers/forms/ha-input_datetime-form.ts index 09a1efc4e7..362fe30c90 100644 --- a/src/panels/config/helpers/forms/ha-input_datetime-form.ts +++ b/src/panels/config/helpers/forms/ha-input_datetime-form.ts @@ -1,16 +1,8 @@ import "@polymer/paper-input/paper-input"; import "@polymer/paper-radio-button/paper-radio-button"; import "@polymer/paper-radio-group/paper-radio-group"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../../../common/dom/fire_event"; import "../../../../components/ha-icon-input"; import { InputDateTime } from "../../../../data/input_datetime"; @@ -25,11 +17,11 @@ class HaInputDateTimeForm extends LitElement { private _item?: InputDateTime; - @internalProperty() private _name!: string; + @state() private _name!: string; - @internalProperty() private _icon!: string; + @state() private _icon!: string; - @internalProperty() private _mode!: "date" | "time" | "datetime"; + @state() private _mode!: "date" | "time" | "datetime"; set item(item: InputDateTime) { this._item = item; @@ -145,7 +137,7 @@ class HaInputDateTimeForm extends LitElement { }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/helpers/forms/ha-input_number-form.ts b/src/panels/config/helpers/forms/ha-input_number-form.ts index 0439227315..ec3288ebab 100644 --- a/src/panels/config/helpers/forms/ha-input_number-form.ts +++ b/src/panels/config/helpers/forms/ha-input_number-form.ts @@ -1,16 +1,8 @@ import "@polymer/paper-input/paper-input"; import "@polymer/paper-radio-button/paper-radio-button"; import "@polymer/paper-radio-group/paper-radio-group"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../../../common/dom/fire_event"; import "../../../../components/ha-icon-input"; import { InputNumber } from "../../../../data/input_number"; @@ -25,20 +17,20 @@ class HaInputNumberForm extends LitElement { private _item?: Partial; - @internalProperty() private _name!: string; + @state() private _name!: string; - @internalProperty() private _icon!: string; + @state() private _icon!: string; - @internalProperty() private _max?: number; + @state() private _max?: number; - @internalProperty() private _min?: number; + @state() private _min?: number; - @internalProperty() private _mode?: string; + @state() private _mode?: string; - @internalProperty() private _step?: number; + @state() private _step?: number; // eslint-disable-next-line: variable-name - @internalProperty() private _unit_of_measurement?: string; + @state() private _unit_of_measurement?: string; set item(item: InputNumber) { this._item = item; @@ -194,7 +186,7 @@ class HaInputNumberForm extends LitElement { }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/helpers/forms/ha-input_select-form.ts b/src/panels/config/helpers/forms/ha-input_select-form.ts index 2aec4aee3a..fbb15f7f6e 100644 --- a/src/panels/config/helpers/forms/ha-input_select-form.ts +++ b/src/panels/config/helpers/forms/ha-input_select-form.ts @@ -3,17 +3,8 @@ import "@polymer/paper-input/paper-input"; import type { PaperInputElement } from "@polymer/paper-input/paper-input"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-item/paper-item-body"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - query, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state, query } from "lit/decorators"; import { fireEvent } from "../../../../common/dom/fire_event"; import "../../../../components/ha-icon-button"; import "../../../../components/ha-icon-input"; @@ -30,11 +21,11 @@ class HaInputSelectForm extends LitElement { private _item?: InputSelect; - @internalProperty() private _name!: string; + @state() private _name!: string; - @internalProperty() private _icon!: string; + @state() private _icon!: string; - @internalProperty() private _options: string[] = []; + @state() private _options: string[] = []; @query("#option_input", true) private _optionInput?: PaperInputElement; @@ -190,7 +181,7 @@ class HaInputSelectForm extends LitElement { }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/helpers/forms/ha-input_text-form.ts b/src/panels/config/helpers/forms/ha-input_text-form.ts index 5c738b9dd8..4de30e62d2 100644 --- a/src/panels/config/helpers/forms/ha-input_text-form.ts +++ b/src/panels/config/helpers/forms/ha-input_text-form.ts @@ -1,16 +1,8 @@ import "@polymer/paper-input/paper-input"; import "@polymer/paper-radio-button/paper-radio-button"; import "@polymer/paper-radio-group/paper-radio-group"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../../../common/dom/fire_event"; import "../../../../components/ha-icon-input"; import { InputText } from "../../../../data/input_text"; @@ -25,17 +17,17 @@ class HaInputTextForm extends LitElement { private _item?: InputText; - @internalProperty() private _name!: string; + @state() private _name!: string; - @internalProperty() private _icon!: string; + @state() private _icon!: string; - @internalProperty() private _max?: number; + @state() private _max?: number; - @internalProperty() private _min?: number; + @state() private _min?: number; - @internalProperty() private _mode?: string; + @state() private _mode?: string; - @internalProperty() private _pattern?: string; + @state() private _pattern?: string; set item(item: InputText) { this._item = item; @@ -177,7 +169,7 @@ class HaInputTextForm extends LitElement { }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/helpers/forms/ha-timer-form.ts b/src/panels/config/helpers/forms/ha-timer-form.ts index 1b81f2d481..2842226ce5 100644 --- a/src/panels/config/helpers/forms/ha-timer-form.ts +++ b/src/panels/config/helpers/forms/ha-timer-form.ts @@ -1,13 +1,5 @@ -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../../../common/dom/fire_event"; import "../../../../components/ha-icon-input"; import { DurationDict, Timer } from "../../../../data/timer"; @@ -22,11 +14,11 @@ class HaTimerForm extends LitElement { private _item?: Timer; - @internalProperty() private _name!: string; + @state() private _name!: string; - @internalProperty() private _icon!: string; + @state() private _icon!: string; - @internalProperty() private _duration!: string | number | DurationDict; + @state() private _duration!: string | number | DurationDict; set item(item: Timer) { this._item = item; @@ -111,7 +103,7 @@ class HaTimerForm extends LitElement { }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/helpers/ha-config-helpers.ts b/src/panels/config/helpers/ha-config-helpers.ts index 71623d5289..40371e8607 100644 --- a/src/panels/config/helpers/ha-config-helpers.ts +++ b/src/panels/config/helpers/ha-config-helpers.ts @@ -5,15 +5,8 @@ import "@polymer/paper-item/paper-icon-item"; import "@polymer/paper-listbox/paper-listbox"; import "@polymer/paper-tooltip/paper-tooltip"; import { HassEntity } from "home-assistant-js-websocket"; -import { - customElement, - html, - internalProperty, - LitElement, - property, - PropertyValues, - TemplateResult, -} from "lit-element"; +import { html, LitElement, PropertyValues, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import memoize from "memoize-one"; import { computeStateDomain } from "../../../common/entity/compute_state_domain"; import { domainIcon } from "../../../common/entity/domain_icon"; @@ -43,7 +36,7 @@ export class HaConfigHelpers extends LitElement { @property() public route!: Route; - @internalProperty() private _stateItems: HassEntity[] = []; + @state() private _stateItems: HassEntity[] = []; private _columns = memoize( (narrow, _language): DataTableColumnContainer => { @@ -121,13 +114,13 @@ export class HaConfigHelpers extends LitElement { ); private _getItems = memoize((stateItems: HassEntity[]) => - stateItems.map((state) => ({ - id: state.entity_id, - icon: state.attributes.icon, - name: state.attributes.friendly_name || "", - entity_id: state.entity_id, - editable: state.attributes.editable, - type: computeStateDomain(state), + stateItems.map((entityState) => ({ + id: entityState.entity_id, + icon: entityState.attributes.icon, + name: entityState.attributes.friendly_name || "", + entity_id: entityState.entity_id, + editable: entityState.attributes.editable, + type: computeStateDomain(entityState), })) ); diff --git a/src/panels/config/info/ha-config-info.ts b/src/panels/config/info/ha-config-info.ts index b3ffe78557..d849eaeada 100644 --- a/src/panels/config/info/ha-config-info.ts +++ b/src/panels/config/info/ha-config-info.ts @@ -1,11 +1,5 @@ -import { - css, - CSSResult, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { property } from "lit/decorators"; import "../../../layouts/hass-tabs-subpage"; import { haStyle } from "../../../resources/styles"; import { HomeAssistant, Route } from "../../../types"; @@ -161,7 +155,7 @@ class HaConfigInfo extends LitElement { }, 1000); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/info/integrations-card.ts b/src/panels/config/info/integrations-card.ts index 42287dda06..2c31c9a354 100644 --- a/src/panels/config/info/integrations-card.ts +++ b/src/panels/config/info/integrations-card.ts @@ -1,13 +1,5 @@ -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import "../../../components/ha-card"; import { @@ -27,11 +19,11 @@ class IntegrationsCard extends LitElement { @property({ type: Boolean }) public narrow = false; - @internalProperty() private _manifests?: { + @state() private _manifests?: { [domain: string]: IntegrationManifest; }; - @internalProperty() private _setups?: { + @state() private _setups?: { [domain: string]: IntegrationSetup; }; @@ -152,7 +144,7 @@ class IntegrationsCard extends LitElement { this._setups = setups; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` table { width: 100%; diff --git a/src/panels/config/info/system-health-card.ts b/src/panels/config/info/system-health-card.ts index ebdcf8f4e4..28c139609a 100644 --- a/src/panels/config/info/system-health-card.ts +++ b/src/panels/config/info/system-health-card.ts @@ -4,18 +4,11 @@ import { ActionDetail } from "@material/mwc-list/mwc-list-foundation"; import "@material/mwc-list/mwc-list-item"; import { mdiContentCopy } from "@mdi/js"; import "@polymer/paper-tooltip/paper-tooltip"; -import { - css, - CSSResult, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { property, state } from "lit/decorators"; +import { isComponentLoaded } from "../../../common/config/is_component_loaded"; import { formatDateTime } from "../../../common/datetime/format_date_time"; import { copyToClipboard } from "../../../common/util/copy-clipboard"; -import { isComponentLoaded } from "../../../common/config/is_component_loaded"; import "../../../components/ha-button-menu"; import "../../../components/ha-card"; import "../../../components/ha-circular-progress"; @@ -48,7 +41,7 @@ const sortKeys = (a: string, b: string) => { class SystemHealthCard extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _info?: SystemHealthInfo; + @state() private _info?: SystemHealthInfo; protected render(): TemplateResult { if (!this.hass) { @@ -260,7 +253,7 @@ class SystemHealthCard extends LitElement { }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` table { width: 100%; diff --git a/src/panels/config/integrations/ha-config-flow-card.ts b/src/panels/config/integrations/ha-config-flow-card.ts index fd6769b22c..369b4dca7a 100644 --- a/src/panels/config/integrations/ha-config-flow-card.ts +++ b/src/panels/config/integrations/ha-config-flow-card.ts @@ -1,12 +1,6 @@ -import { - customElement, - LitElement, - property, - css, - html, - TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +import { css, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import { fireEvent } from "../../../common/dom/fire_event"; import { ATTENTION_SOURCES, diff --git a/src/panels/config/integrations/ha-config-integrations.ts b/src/panels/config/integrations/ha-config-integrations.ts index 3bfe8bb69b..20546603cb 100644 --- a/src/panels/config/integrations/ha-config-integrations.ts +++ b/src/panels/config/integrations/ha-config-integrations.ts @@ -6,21 +6,26 @@ import Fuse from "fuse.js"; import type { UnsubscribeFunc } from "home-assistant-js-websocket"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; -import { ifDefined } from "lit-html/directives/if-defined"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { ifDefined } from "lit/directives/if-defined"; import memoizeOne from "memoize-one"; +import type { HASSDomEvent } from "../../../common/dom/fire_event"; import { navigate } from "../../../common/navigate"; +import "../../../common/search/search-input"; import { caseInsensitiveCompare } from "../../../common/string/compare"; +import type { LocalizeFunc } from "../../../common/translations/localize"; import { extractSearchParam } from "../../../common/url/search-params"; import { nextRender } from "../../../common/util/render-status"; +import "../../../components/ha-button-menu"; +import "../../../components/ha-checkbox"; +import "../../../components/ha-fab"; +import "../../../components/ha-svg-icon"; import { ConfigEntry, getConfigEntries } from "../../../data/config_entries"; import { getConfigFlowInProgressCollection, @@ -44,25 +49,16 @@ import { } from "../../../data/integration"; import { showConfigFlowDialog } from "../../../dialogs/config-flow/show-dialog-config-flow"; import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box"; -import { SubscribeMixin } from "../../../mixins/subscribe-mixin"; -import { haStyle } from "../../../resources/styles"; -import { configSections } from "../ha-panel-config"; - -import type { HomeAssistant, Route } from "../../../types"; -import type { HASSDomEvent } from "../../../common/dom/fire_event"; -import type { LocalizeFunc } from "../../../common/translations/localize"; -import type { HaIntegrationCard } from "./ha-integration-card"; - -import "../../../common/search/search-input"; -import "../../../components/ha-button-menu"; -import "../../../components/ha-fab"; -import "../../../components/ha-checkbox"; -import "../../../components/ha-svg-icon"; import "../../../layouts/hass-loading-screen"; import "../../../layouts/hass-tabs-subpage"; -import "./ha-integration-card"; +import { SubscribeMixin } from "../../../mixins/subscribe-mixin"; +import { haStyle } from "../../../resources/styles"; +import type { HomeAssistant, Route } from "../../../types"; +import { configSections } from "../ha-panel-config"; import "./ha-config-flow-card"; import "./ha-ignored-config-entry-card"; +import "./ha-integration-card"; +import type { HaIntegrationCard } from "./ha-integration-card"; export interface ConfigEntryUpdatedEvent { entry: ConfigEntry; @@ -114,31 +110,31 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) { @property() public route!: Route; - @internalProperty() private _configEntries?: ConfigEntryExtended[]; + @state() private _configEntries?: ConfigEntryExtended[]; @property() private _configEntriesInProgress: DataEntryFlowProgressExtended[] = []; - @internalProperty() + @state() private _entityRegistryEntries: EntityRegistryEntry[] = []; - @internalProperty() + @state() private _deviceRegistryEntries: DeviceRegistryEntry[] = []; - @internalProperty() + @state() private _manifests: Record = {}; private _extraFetchedManifests?: Set; - @internalProperty() private _showIgnored = false; + @state() private _showIgnored = false; - @internalProperty() private _showDisabled = false; + @state() private _showDisabled = false; - @internalProperty() private _searchParms = new URLSearchParams( + @state() private _searchParms = new URLSearchParams( window.location.hash.substring(1) ); - @internalProperty() private _filter?: string; + @state() private _filter?: string; public hassSubscribe(): UnsubscribeFunc[] { return [ @@ -195,7 +191,10 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) { ): [ Map, ConfigEntryExtended[], - Map + Map, + // Counter for disabled integrations since the tuple element above will + // be grouped by the integration name and therefore not provide a valid count + number ] => { const filteredConfigEnties = this._filterConfigEntries( configEntries, @@ -214,6 +213,7 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) { groupByIntegration(filteredConfigEnties), ignored, groupByIntegration(disabled), + disabled.length, ]; } ); @@ -271,6 +271,7 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) { groupedConfigEntries, ignoredConfigEntries, disabledConfigEntries, + disabledCount, ] = this._filterGroupConfigEntries(this._configEntries, this._filter); const configEntriesInProgress = this._filterConfigEntriesInProgress( this._configEntriesInProgress, @@ -342,12 +343,11 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) { "ui.panel.config.integrations.search" )} > - ${!this._showDisabled && disabledConfigEntries.size + ${!this._showDisabled && disabledCount ? html`
${this.hass.localize( "ui.panel.config.integrations.disable.disabled_integrations", - "number", - disabledConfigEntries.size + { number: disabledCount } )} ) { const domain = extractSearchParam("domain"); - navigate(this, "/config/integrations", true); + navigate("/config/integrations", { replace: true }); if (!domain) { return; } const localize = await localizePromise; if ( !(await showConfirmationDialog(this, { - title: localize( - "ui.panel.config.integrations.confirm_new", - "integration", - domainToName(localize, domain) - ), + title: localize("ui.panel.config.integrations.confirm_new", { + integration: domainToName(localize, domain), + }), })) ) { return; @@ -624,7 +622,7 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) { }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/integrations/ha-ignored-config-entry-card.ts b/src/panels/config/integrations/ha-ignored-config-entry-card.ts index cbd6c476b7..34c7c32dc3 100644 --- a/src/panels/config/integrations/ha-ignored-config-entry-card.ts +++ b/src/panels/config/integrations/ha-ignored-config-entry-card.ts @@ -1,11 +1,5 @@ -import { - customElement, - LitElement, - property, - css, - html, - TemplateResult, -} from "lit-element"; +import { css, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import { fireEvent } from "../../../common/dom/fire_event"; import { deleteConfigEntry } from "../../../data/config_entries"; import type { IntegrationManifest } from "../../../data/integration"; diff --git a/src/panels/config/integrations/ha-integration-action-card.ts b/src/panels/config/integrations/ha-integration-action-card.ts index 2470067684..8f24451007 100644 --- a/src/panels/config/integrations/ha-integration-action-card.ts +++ b/src/panels/config/integrations/ha-integration-action-card.ts @@ -1,11 +1,5 @@ -import { - TemplateResult, - html, - customElement, - LitElement, - property, - css, -} from "lit-element"; +import { css, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import type { IntegrationManifest } from "../../../data/integration"; import type { HomeAssistant } from "../../../types"; import "./ha-integration-header"; diff --git a/src/panels/config/integrations/ha-integration-card.ts b/src/panels/config/integrations/ha-integration-card.ts index 44cd2866c7..cbd7de5aab 100644 --- a/src/panels/config/integrations/ha-integration-card.ts +++ b/src/panels/config/integrations/ha-integration-card.ts @@ -1,26 +1,19 @@ -import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item"; -import "@material/mwc-list/mwc-list-item"; -import "@polymer/paper-listbox"; import "@material/mwc-button"; -import "@polymer/paper-item"; -import "@polymer/paper-tooltip/paper-tooltip"; +import "@material/mwc-list/mwc-list-item"; +import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item"; import { mdiAlertCircle, mdiDotsVertical, mdiOpenInNew } from "@mdi/js"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +import "@polymer/paper-item"; +import "@polymer/paper-listbox"; +import "@polymer/paper-tooltip/paper-tooltip"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import { fireEvent } from "../../../common/dom/fire_event"; import { shouldHandleRequestSelectedEvent } from "../../../common/mwc/handle-request-selected-event"; -import "../../../components/ha-icon-next"; import "../../../components/ha-button-menu"; -import "../../../components/ha-svg-icon"; import "../../../components/ha-card"; +import "../../../components/ha-icon-next"; +import "../../../components/ha-svg-icon"; import { ConfigEntry, deleteConfigEntry, @@ -300,80 +293,73 @@ export class HaIntegrationCard extends LitElement { ` : ""}
- ${!this.manifest - ? "" - : html` - - - - - + + + + + + ${this.hass.localize( + "ui.panel.config.integrations.config_entry.rename" + )} + + + ${this.hass.localize( + "ui.panel.config.integrations.config_entry.system_options" + )} + + ${this.manifest + ? html`
+ ${this.hass.localize( - "ui.panel.config.integrations.config_entry.rename" - )} + "ui.panel.config.integrations.config_entry.documentation" + )} - - ${this.hass.localize( - "ui.panel.config.integrations.config_entry.system_options" - )} - - - - - ${this.hass.localize( - "ui.panel.config.integrations.config_entry.documentation" - )} - - - ${!item.disabled_by && - item.state === "loaded" && - item.supports_unload && - item.source !== "system" - ? html` - ${this.hass.localize( - "ui.panel.config.integrations.config_entry.reload" - )} - ` - : ""} - ${item.disabled_by === "user" - ? html` - ${this.hass.localize("ui.common.enable")} - ` - : item.source !== "system" - ? html` - ${this.hass.localize("ui.common.disable")} - ` - : ""} - ${item.source !== "system" - ? html` - ${this.hass.localize( - "ui.panel.config.integrations.config_entry.delete" - )} - ` - : ""} - - `} + ` + : ""} + ${!item.disabled_by && + item.state === "loaded" && + item.supports_unload && + item.source !== "system" + ? html` + ${this.hass.localize( + "ui.panel.config.integrations.config_entry.reload" + )} + ` + : ""} + ${item.disabled_by === "user" + ? html` + ${this.hass.localize("ui.common.enable")} + ` + : item.source !== "system" + ? html` + ${this.hass.localize("ui.common.disable")} + ` + : ""} + ${item.source !== "system" + ? html` + ${this.hass.localize( + "ui.panel.config.integrations.config_entry.delete" + )} + ` + : ""} +
`; } @@ -581,7 +567,7 @@ export class HaIntegrationCard extends LitElement { fireEvent(this, "entry-updated", { entry: newEntry }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, haStyleScrollbar, diff --git a/src/panels/config/integrations/ha-integration-header.ts b/src/panels/config/integrations/ha-integration-header.ts index 29cf8d3544..cd189da48b 100644 --- a/src/panels/config/integrations/ha-integration-header.ts +++ b/src/panels/config/integrations/ha-integration-header.ts @@ -1,14 +1,8 @@ -import "../../../components/ha-svg-icon"; -import { mdiPackageVariant, mdiCloud } from "@mdi/js"; +import { mdiCloud, mdiPackageVariant } from "@mdi/js"; import "@polymer/paper-tooltip/paper-tooltip"; -import { - css, - html, - customElement, - property, - LitElement, - TemplateResult, -} from "lit-element"; +import { css, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; +import "../../../components/ha-svg-icon"; import { domainToName, IntegrationManifest } from "../../../data/integration"; import { HomeAssistant } from "../../../types"; import { brandsUrl } from "../../../util/brands-url"; diff --git a/src/panels/config/integrations/integration-panels/mqtt/mqtt-config-panel.ts b/src/panels/config/integrations/integration-panels/mqtt/mqtt-config-panel.ts index a7e971bfca..2edd27c8db 100644 --- a/src/panels/config/integrations/integration-panels/mqtt/mqtt-config-panel.ts +++ b/src/panels/config/integrations/integration-panels/mqtt/mqtt-config-panel.ts @@ -1,15 +1,7 @@ import "@material/mwc-button"; import "@polymer/paper-input/paper-input"; -import { - css, - CSSResultArray, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import "../../../../../components/ha-card"; import "../../../../../components/ha-code-editor"; import { getConfigEntries } from "../../../../../data/config_entries"; @@ -25,9 +17,9 @@ class HaPanelDevMqtt extends LitElement { @property({ type: Boolean }) public narrow!: boolean; - @internalProperty() private topic = ""; + @state() private topic = ""; - @internalProperty() private payload = ""; + @state() private payload = ""; private inited = false; @@ -123,7 +115,7 @@ class HaPanelDevMqtt extends LitElement { showOptionsFlowDialog(this, configEntry!); } - static get styles(): CSSResultArray { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/integrations/integration-panels/mqtt/mqtt-subscribe-card.ts b/src/panels/config/integrations/integration-panels/mqtt/mqtt-subscribe-card.ts index 532b8f7873..c3fd96ce4f 100644 --- a/src/panels/config/integrations/integration-panels/mqtt/mqtt-subscribe-card.ts +++ b/src/panels/config/integrations/integration-panels/mqtt/mqtt-subscribe-card.ts @@ -1,15 +1,7 @@ import "@material/mwc-button"; import "@polymer/paper-input/paper-input"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { formatTime } from "../../../../../common/datetime/format_time"; import "../../../../../components/ha-card"; import { MQTTMessage, subscribeMQTTTopic } from "../../../../../data/mqtt"; @@ -19,11 +11,11 @@ import { HomeAssistant } from "../../../../../types"; class MqttSubscribeCard extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _topic = ""; + @state() private _topic = ""; - @internalProperty() private _subscribed?: () => void; + @state() private _subscribed?: () => void; - @internalProperty() private _messages: Array<{ + @state() private _messages: Array<{ id: number; message: MQTTMessage; payload: string; @@ -129,7 +121,7 @@ class MqttSubscribeCard extends LitElement { ]; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` form { display: block; diff --git a/src/panels/config/integrations/integration-panels/ozw/dialog-ozw-refresh-node.ts b/src/panels/config/integrations/integration-panels/ozw/dialog-ozw-refresh-node.ts index f041c1c370..4aaacd533f 100644 --- a/src/panels/config/integrations/integration-panels/ozw/dialog-ozw-refresh-node.ts +++ b/src/panels/config/integrations/integration-panels/ozw/dialog-ozw-refresh-node.ts @@ -1,14 +1,12 @@ import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; import "../../../../../components/ha-circular-progress"; import "../../../../../components/ha-code-editor"; import { createCloseHeading } from "../../../../../components/ha-dialog"; @@ -26,17 +24,17 @@ import { OZWRefreshNodeDialogParams } from "./show-dialog-ozw-refresh-node"; class DialogOZWRefreshNode extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _node_id?: number; + @state() private _node_id?: number; - @internalProperty() private _ozw_instance = 1; + @state() private _ozw_instance = 1; - @internalProperty() private _nodeMetaData?: OZWDeviceMetaData; + @state() private _nodeMetaData?: OZWDeviceMetaData; - @internalProperty() private _node?: OZWDevice; + @state() private _node?: OZWDevice; - @internalProperty() private _active = false; + @state() private _active = false; - @internalProperty() private _complete = false; + @state() private _complete = false; private _refreshDevicesTimeoutHandle?: number; @@ -81,7 +79,7 @@ class DialogOZWRefreshNode extends LitElement { return html` ({ @@ -95,7 +88,7 @@ class OZWNetworkNodes extends LitElement { protected firstUpdated() { if (!this.ozwInstance) { - navigate(this, "/config/ozw/dashboard", true); + navigate("/config/ozw/dashboard", { replace: true }); } else if (this.hass) { this._fetchData(); } @@ -124,10 +117,10 @@ class OZWNetworkNodes extends LitElement { private _handleRowClicked(ev: HASSDomEvent) { const nodeId = ev.detail.id; - navigate(this, `/config/ozw/network/${this.ozwInstance}/node/${nodeId}`); + navigate(`/config/ozw/network/${this.ozwInstance}/node/${nodeId}`); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return haStyle; } } diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-network-router.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-network-router.ts index e16133ba01..0294ff9b0f 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-network-router.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-network-router.ts @@ -1,5 +1,5 @@ import { mdiNetwork, mdiServerNetwork } from "@mdi/js"; -import { customElement, property } from "lit-element"; +import { customElement, property } from "lit/decorators"; import { HassRouterPage, RouterOptions, diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-node-config.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-node-config.ts index d495a45d76..db7e9ee6e0 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-node-config.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-node-config.ts @@ -1,14 +1,6 @@ import "@material/mwc-button/mwc-button"; -import { - css, - CSSResultArray, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { navigate } from "../../../../../common/navigate"; import "../../../../../components/buttons/ha-call-service-button"; import "../../../../../components/ha-card"; @@ -45,19 +37,21 @@ class OZWNodeConfig extends LitElement { @property() public nodeId?; - @internalProperty() private _node?: OZWDevice; + @state() private _node?: OZWDevice; - @internalProperty() private _metadata?: OZWDeviceMetaDataResponse; + @state() private _metadata?: OZWDeviceMetaDataResponse; - @internalProperty() private _config?: OZWDeviceConfig[]; + @state() private _config?: OZWDeviceConfig[]; - @internalProperty() private _error?: string; + @state() private _error?: string; protected firstUpdated() { if (!this.ozwInstance) { - navigate(this, "/config/ozw/dashboard", true); + navigate("/config/ozw/dashboard", { replace: true }); } else if (!this.nodeId) { - navigate(this, `/config/ozw/network/${this.ozwInstance}/nodes`, true); + navigate(`/config/ozw/network/${this.ozwInstance}/nodes`, { + replace: true, + }); } else { this._fetchData(); } @@ -221,7 +215,7 @@ class OZWNodeConfig extends LitElement { }); } - static get styles(): CSSResultArray { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts index ff13a68f2f..c34a5bf729 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-node-dashboard.ts @@ -1,14 +1,6 @@ import "@material/mwc-button/mwc-button"; -import { - css, - CSSResultArray, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { navigate } from "../../../../../common/navigate"; import "../../../../../components/buttons/ha-call-service-button"; import "../../../../../components/ha-card"; @@ -43,17 +35,19 @@ class OZWNodeDashboard extends LitElement { @property() public nodeId?; - @internalProperty() private _node?: OZWDevice; + @state() private _node?: OZWDevice; - @internalProperty() private _metadata?: OZWDeviceMetaDataResponse; + @state() private _metadata?: OZWDeviceMetaDataResponse; - @internalProperty() private _not_found = false; + @state() private _not_found = false; protected firstUpdated() { if (!this.ozwInstance) { - navigate(this, "/config/ozw/dashboard", true); + navigate("/config/ozw/dashboard", { replace: true }); } else if (!this.nodeId) { - navigate(this, `/config/ozw/network/${this.ozwInstance}/nodes`, true); + navigate(`/config/ozw/network/${this.ozwInstance}/nodes`, { + replace: true, + }); } else if (this.hass) { this._fetchData(); } @@ -189,7 +183,7 @@ class OZWNodeDashboard extends LitElement { }); } - static get styles(): CSSResultArray { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/integrations/integration-panels/ozw/ozw-node-router.ts b/src/panels/config/integrations/integration-panels/ozw/ozw-node-router.ts index 45a922f8b7..f5676bdcaa 100644 --- a/src/panels/config/integrations/integration-panels/ozw/ozw-node-router.ts +++ b/src/panels/config/integrations/integration-panels/ozw/ozw-node-router.ts @@ -1,5 +1,5 @@ import { mdiNetwork, mdiWrench } from "@mdi/js"; -import { customElement, property } from "lit-element"; +import { customElement, property } from "lit/decorators"; import { navigate } from "../../../../../common/navigate"; import { HassRouterPage, @@ -68,11 +68,10 @@ class OZWNodeRouter extends HassRouterPage { if (this._configEntry && !searchParams.has("config_entry")) { searchParams.append("config_entry", this._configEntry); navigate( - this, `${this.routeTail.prefix}${ this.routeTail.path }?${searchParams.toString()}`, - true + { replace: true } ); } } diff --git a/src/panels/config/integrations/integration-panels/zha/dialog-zha-cluster.ts b/src/panels/config/integrations/integration-panels/zha/dialog-zha-cluster.ts index 3632eb748f..f46570057d 100644 --- a/src/panels/config/integrations/integration-panels/zha/dialog-zha-cluster.ts +++ b/src/panels/config/integrations/integration-panels/zha/dialog-zha-cluster.ts @@ -1,13 +1,11 @@ import { - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; import { HASSDomEvent } from "../../../../../common/dom/fire_event"; import "../../../../../components/ha-code-editor"; import { createCloseHeading } from "../../../../../components/ha-dialog"; @@ -33,13 +31,13 @@ import "./zha-group-binding"; class DialogZHACluster extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _device?: ZHADevice; + @state() private _device?: ZHADevice; - @internalProperty() private _selectedCluster?: Cluster; + @state() private _selectedCluster?: Cluster; - @internalProperty() private _bindableDevices: ZHADevice[] = []; + @state() private _bindableDevices: ZHADevice[] = []; - @internalProperty() private _groups: ZHAGroup[] = []; + @state() private _groups: ZHAGroup[] = []; public async showDialog( params: ZHADeviceZigbeeInfoDialogParams @@ -63,7 +61,7 @@ class DialogZHACluster extends LitElement { | undefined; + @state() private _devices: Map | undefined; private _deviceChildren = memoizeOne( ( @@ -132,7 +125,7 @@ class DialogZHADeviceChildren extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return haStyleDialog; } } diff --git a/src/panels/config/integrations/integration-panels/zha/dialog-zha-device-zigbee-info.ts b/src/panels/config/integrations/integration-panels/zha/dialog-zha-device-zigbee-info.ts index d0fc98269f..5150ed473a 100644 --- a/src/panels/config/integrations/integration-panels/zha/dialog-zha-device-zigbee-info.ts +++ b/src/panels/config/integrations/integration-panels/zha/dialog-zha-device-zigbee-info.ts @@ -1,12 +1,5 @@ -import { - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import "../../../../../components/ha-code-editor"; import { createCloseHeading } from "../../../../../components/ha-dialog"; import { haStyleDialog } from "../../../../../resources/styles"; @@ -17,7 +10,7 @@ import { ZHADeviceZigbeeInfoDialogParams } from "./show-dialog-zha-device-zigbee class DialogZHADeviceZigbeeInfo extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _signature: any; + @state() private _signature: any; public async showDialog( params: ZHADeviceZigbeeInfoDialogParams @@ -43,7 +36,7 @@ class DialogZHADeviceZigbeeInfo extends LitElement { = new Map(); - @internalProperty() private _params: + @state() private _params: | ZHAReconfigureDeviceDialogParams | undefined = undefined; - @internalProperty() private _allSuccessful = true; + @state() private _allSuccessful = true; - @internalProperty() private _showDetails = false; + @state() private _showDetails = false; private _subscribed?: Promise; @@ -397,7 +389,7 @@ class DialogZHAReconfigureDevice extends LitElement { this._showDetails = !this._showDetails; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyleDialog, css` diff --git a/src/panels/config/integrations/integration-panels/zha/zha-add-devices-page.ts b/src/panels/config/integrations/integration-panels/zha/zha-add-devices-page.ts index eceb2fa034..654cd3b4be 100644 --- a/src/panels/config/integrations/integration-panels/zha/zha-add-devices-page.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-add-devices-page.ts @@ -3,15 +3,13 @@ import { IronAutogrowTextareaElement } from "@polymer/iron-autogrow-textarea"; import "@polymer/paper-input/paper-textarea"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; import "../../../../../components/ha-circular-progress"; import "../../../../../components/ha-icon-button"; import "../../../../../components/ha-service-description"; @@ -36,20 +34,17 @@ class ZHAAddDevicesPage extends LitElement { @property() public route?: Route; - @internalProperty() private _error?: string; + @state() private _error?: string; - @internalProperty() private _discoveredDevices: Record< - string, - ZHADevice - > = {}; + @state() private _discoveredDevices: Record = {}; - @internalProperty() private _formattedEvents = ""; + @state() private _formattedEvents = ""; - @internalProperty() private _active = false; + @state() private _active = false; - @internalProperty() private _showHelp = false; + @state() private _showHelp = false; - @internalProperty() private _showLogs = false; + @state() private _showLogs = false; private _ieeeAddress?: string; @@ -217,7 +212,7 @@ class ZHAAddDevicesPage extends LitElement { ); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/integrations/integration-panels/zha/zha-add-group-page.ts b/src/panels/config/integrations/integration-panels/zha/zha-add-group-page.ts index 81765c1810..34ed5174e2 100644 --- a/src/panels/config/integrations/integration-panels/zha/zha-add-group-page.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-add-group-page.ts @@ -1,17 +1,8 @@ import "@material/mwc-button"; import "@polymer/paper-input/paper-input"; import type { PaperInputElement } from "@polymer/paper-input/paper-input"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - PropertyValues, - query, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit"; +import { customElement, property, state, query } from "lit/decorators"; import type { HASSDomEvent } from "../../../../../common/dom/fire_event"; import { navigate } from "../../../../../common/navigate"; import type { SelectionChangedEvent } from "../../../../../components/data-table/ha-data-table"; @@ -38,9 +29,9 @@ export class ZHAAddGroupPage extends LitElement { @property({ type: Array }) public deviceEndpoints: ZHADeviceEndpoint[] = []; - @internalProperty() private _processingAdd = false; + @state() private _processingAdd = false; - @internalProperty() private _groupName = ""; + @state() private _groupName = ""; @query("zha-device-endpoint-data-table", true) private _zhaDevicesDataTable!: ZHADeviceEndpointDataTable; @@ -147,7 +138,7 @@ export class ZHAAddGroupPage extends LitElement { this._processingAdd = false; this._groupName = ""; this._zhaDevicesDataTable.clearSelection(); - navigate(this, `/config/zha/group/${group.group_id}`, true); + navigate(`/config/zha/group/${group.group_id}`, { replace: true }); } private _handleNameChange(ev: PolymerChangedEvent) { @@ -155,7 +146,7 @@ export class ZHAAddGroupPage extends LitElement { this._groupName = target.value || ""; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ css` .header { diff --git a/src/panels/config/integrations/integration-panels/zha/zha-cluster-attributes.ts b/src/panels/config/integrations/integration-panels/zha/zha-cluster-attributes.ts index 2ef7ed2784..0d7a815256 100644 --- a/src/panels/config/integrations/integration-panels/zha/zha-cluster-attributes.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-cluster-attributes.ts @@ -5,14 +5,13 @@ import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; import { css, - CSSResult, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { property, state } from "lit/decorators"; import "../../../../../components/buttons/ha-call-service-button"; import "../../../../../components/ha-card"; import "../../../../../components/ha-icon-button"; @@ -46,15 +45,15 @@ export class ZHAClusterAttributes extends LitElement { @property() public selectedCluster?: Cluster; - @internalProperty() private _attributes: Attribute[] = []; + @state() private _attributes: Attribute[] = []; - @internalProperty() private _selectedAttributeIndex = -1; + @state() private _selectedAttributeIndex = -1; - @internalProperty() private _attributeValue?: any = ""; + @state() private _attributeValue?: any = ""; - @internalProperty() private _manufacturerCodeOverride?: string | number; + @state() private _manufacturerCodeOverride?: string | number; - @internalProperty() + @state() private _setAttributeServiceData?: SetAttributeServiceData; protected updated(changedProperties: PropertyValues): void { @@ -273,7 +272,7 @@ export class ZHAClusterAttributes extends LitElement { this._attributeValue = ""; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/integrations/integration-panels/zha/zha-cluster-commands.ts b/src/panels/config/integrations/integration-panels/zha/zha-cluster-commands.ts index f66f398148..5ffcf61637 100644 --- a/src/panels/config/integrations/integration-panels/zha/zha-cluster-commands.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-cluster-commands.ts @@ -4,14 +4,13 @@ import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; import { css, - CSSResult, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { property, state } from "lit/decorators"; import "../../../../../components/buttons/ha-call-service-button"; import "../../../../../components/ha-card"; import "../../../../../components/ha-icon-button"; @@ -41,15 +40,15 @@ export class ZHAClusterCommands extends LitElement { @property() public selectedCluster?: Cluster; - @internalProperty() private _showHelp = false; + @state() private _showHelp = false; - @internalProperty() private _commands: Command[] = []; + @state() private _commands: Command[] = []; - @internalProperty() private _selectedCommandIndex = -1; + @state() private _selectedCommandIndex = -1; - @internalProperty() private _manufacturerCodeOverride?: number; + @state() private _manufacturerCodeOverride?: number; - @internalProperty() + @state() private _issueClusterCommandServiceData?: IssueCommandServiceData; protected updated(changedProperties: PropertyValues): void { @@ -205,7 +204,7 @@ export class ZHAClusterCommands extends LitElement { this._issueClusterCommandServiceData = this._computeIssueClusterCommandServiceData(); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/integrations/integration-panels/zha/zha-clusters-data-table.ts b/src/panels/config/integrations/integration-panels/zha/zha-clusters-data-table.ts index cfaa1a1717..e29bcbe10d 100644 --- a/src/panels/config/integrations/integration-panels/zha/zha-clusters-data-table.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-clusters-data-table.ts @@ -1,11 +1,5 @@ -import { - customElement, - html, - LitElement, - property, - query, - TemplateResult, -} from "lit-element"; +import { html, LitElement, TemplateResult } from "lit"; +import { customElement, property, query } from "lit/decorators"; import memoizeOne from "memoize-one"; import { computeRTLDirection } from "../../../../../common/util/compute_rtl"; import "../../../../../components/data-table/ha-data-table"; diff --git a/src/panels/config/integrations/integration-panels/zha/zha-clusters.ts b/src/panels/config/integrations/integration-panels/zha/zha-clusters.ts index 9761d1b0b6..4559fafe9e 100644 --- a/src/panels/config/integrations/integration-panels/zha/zha-clusters.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-clusters.ts @@ -3,14 +3,13 @@ import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; import { css, - CSSResult, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { property, state } from "lit/decorators"; import { fireEvent } from "../../../../../common/dom/fire_event"; import "../../../../../components/buttons/ha-call-service-button"; import "../../../../../components/ha-card"; @@ -45,9 +44,9 @@ export class ZHAClusters extends LitElement { @property() public showHelp = false; - @internalProperty() private _selectedClusterIndex = -1; + @state() private _selectedClusterIndex = -1; - @internalProperty() private _clusters: Cluster[] = []; + @state() private _clusters: Cluster[] = []; protected updated(changedProperties: PropertyValues): void { if (changedProperties.has("selectedDevice")) { @@ -132,7 +131,7 @@ export class ZHAClusters extends LitElement { this.showHelp = !this.showHelp; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/integrations/integration-panels/zha/zha-config-dashboard-router.ts b/src/panels/config/integrations/integration-panels/zha/zha-config-dashboard-router.ts index 4fcef9343c..8b0963b190 100644 --- a/src/panels/config/integrations/integration-panels/zha/zha-config-dashboard-router.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-config-dashboard-router.ts @@ -1,4 +1,4 @@ -import { customElement, property } from "lit-element"; +import { customElement, property } from "lit/decorators"; import { navigate } from "../../../../../common/navigate"; import { HassRouterPage, @@ -67,11 +67,10 @@ class ZHAConfigDashboardRouter extends HassRouterPage { if (this._configEntry && !searchParams.has("config_entry")) { searchParams.append("config_entry", this._configEntry); navigate( - this, `${this.routeTail.prefix}${ this.routeTail.path }?${searchParams.toString()}`, - true + { replace: true } ); } } diff --git a/src/panels/config/integrations/integration-panels/zha/zha-config-dashboard.ts b/src/panels/config/integrations/integration-panels/zha/zha-config-dashboard.ts index fd67ae4c04..0b1014d78c 100644 --- a/src/panels/config/integrations/integration-panels/zha/zha-config-dashboard.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-config-dashboard.ts @@ -4,14 +4,12 @@ import "@polymer/paper-item/paper-item"; import "@polymer/paper-item/paper-item-body"; import { css, - CSSResultArray, - customElement, + CSSResultGroup, html, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; import { computeRTL } from "../../../../../common/util/compute_rtl"; import "../../../../../components/ha-card"; import "../../../../../components/ha-fab"; @@ -27,6 +25,7 @@ import { updateZHAConfiguration, ZHAConfiguration, } from "../../../../../data/zha"; +import { customElement, property } from "lit/decorators"; export const zhaTabs: PageNavigation[] = [ { @@ -169,7 +168,7 @@ class ZHAConfigDashboard extends LitElement { schema.name; } - static get styles(): CSSResultArray { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/integrations/integration-panels/zha/zha-device-binding.ts b/src/panels/config/integrations/integration-panels/zha/zha-device-binding.ts index 41d269f69c..36c71f8536 100644 --- a/src/panels/config/integrations/integration-panels/zha/zha-device-binding.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-device-binding.ts @@ -4,15 +4,13 @@ import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; import "../../../../../components/buttons/ha-call-service-button"; import "../../../../../components/ha-card"; import "../../../../../components/ha-icon-button"; @@ -31,13 +29,13 @@ export class ZHADeviceBindingControl extends LitElement { @property() public selectedDevice?: ZHADevice; - @internalProperty() private _showHelp = false; + @state() private _showHelp = false; - @internalProperty() private _bindTargetIndex = -1; + @state() private _bindTargetIndex = -1; - @internalProperty() private bindableDevices: ZHADevice[] = []; + @state() private bindableDevices: ZHADevice[] = []; - @internalProperty() private _deviceToBind?: ZHADevice; + @state() private _deviceToBind?: ZHADevice; protected updated(changedProperties: PropertyValues): void { if (changedProperties.has("selectedDevice")) { @@ -142,7 +140,7 @@ export class ZHADeviceBindingControl extends LitElement { } } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/integrations/integration-panels/zha/zha-device-card.ts b/src/panels/config/integrations/integration-panels/zha/zha-device-card.ts index 763bb5d49a..f1dbb1a254 100644 --- a/src/panels/config/integrations/integration-panels/zha/zha-device-card.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-device-card.ts @@ -1,16 +1,7 @@ import "@polymer/paper-input/paper-input"; import "@polymer/paper-listbox/paper-listbox"; import { UnsubscribeFunc } from "home-assistant-js-websocket"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - internalProperty, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { fireEvent } from "../../../../../common/dom/fire_event"; import { computeStateName } from "../../../../../common/entity/compute_state_name"; import "../../../../../components/buttons/ha-call-service-button"; @@ -34,6 +25,7 @@ import { EntityRegistryStateEntry } from "../../../devices/ha-config-device-page import { compare } from "../../../../../common/string/compare"; import { getIeeeTail } from "./functions"; import { slugify } from "../../../../../common/string/slugify"; +import { customElement, property, state } from "lit/decorators"; @customElement("zha-device-card") class ZHADeviceCard extends SubscribeMixin(LitElement) { @@ -43,7 +35,7 @@ class ZHADeviceCard extends SubscribeMixin(LitElement) { @property({ type: Boolean }) public narrow?: boolean; - @internalProperty() private _entities: EntityRegistryEntry[] = []; + @state() private _entities: EntityRegistryEntry[] = []; private _deviceEntities = memoizeOne( ( @@ -206,7 +198,7 @@ class ZHADeviceCard extends SubscribeMixin(LitElement) { } } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/integrations/integration-panels/zha/zha-device-endpoint-data-table.ts b/src/panels/config/integrations/integration-panels/zha/zha-device-endpoint-data-table.ts index 2b09a8220a..3a3ce48f09 100644 --- a/src/panels/config/integrations/integration-panels/zha/zha-device-endpoint-data-table.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-device-endpoint-data-table.ts @@ -1,13 +1,5 @@ -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - query, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, query } from "lit/decorators"; import memoizeOne from "memoize-one"; import { computeRTLDirection } from "../../../../../common/util/compute_rtl"; import "../../../../../components/data-table/ha-data-table"; @@ -156,7 +148,7 @@ export class ZHADeviceEndpointDataTable extends LitElement { `; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ css` .table-cell-text { diff --git a/src/panels/config/integrations/integration-panels/zha/zha-device-pairing-status-card.ts b/src/panels/config/integrations/integration-panels/zha/zha-device-pairing-status-card.ts index d3422dd828..0fc745cf81 100644 --- a/src/panels/config/integrations/integration-panels/zha/zha-device-pairing-status-card.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-device-pairing-status-card.ts @@ -1,16 +1,8 @@ import "@polymer/paper-input/paper-input"; import "@polymer/paper-listbox/paper-listbox"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import "../../../../../components/buttons/ha-call-service-button"; import "../../../../../components/entity/state-badge"; import "../../../../../components/ha-area-picker"; @@ -36,7 +28,7 @@ class ZHADevicePairingStatusCard extends LitElement { @property({ type: Boolean }) public narrow?: boolean; - @internalProperty() private _showHelp = false; + @state() private _showHelp = false; protected render(): TemplateResult { if (!this.hass || !this.device) { @@ -102,7 +94,7 @@ class ZHADevicePairingStatusCard extends LitElement { `; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/integrations/integration-panels/zha/zha-group-binding.ts b/src/panels/config/integrations/integration-panels/zha/zha-group-binding.ts index 449db0795a..201c139c69 100644 --- a/src/panels/config/integrations/integration-panels/zha/zha-group-binding.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-group-binding.ts @@ -4,16 +4,13 @@ import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, - query, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state, query } from "lit/decorators"; import type { HASSDomEvent } from "../../../../../common/dom/fire_event"; import "../../../../../components/buttons/ha-call-service-button"; import { SelectionChangedEvent } from "../../../../../components/data-table/ha-data-table"; @@ -45,15 +42,15 @@ export class ZHAGroupBindingControl extends LitElement { @property() public selectedDevice?: ZHADevice; - @internalProperty() private _showHelp = false; + @state() private _showHelp = false; - @internalProperty() private _bindTargetIndex = -1; + @state() private _bindTargetIndex = -1; - @internalProperty() private groups: ZHAGroup[] = []; + @state() private groups: ZHAGroup[] = []; - @internalProperty() private _selectedClusters: string[] = []; + @state() private _selectedClusters: string[] = []; - @internalProperty() private _clusters: Cluster[] = []; + @state() private _clusters: Cluster[] = []; private _groupToBind?: ZHAGroup; @@ -250,7 +247,7 @@ export class ZHAGroupBindingControl extends LitElement { ); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/integrations/integration-panels/zha/zha-group-page.ts b/src/panels/config/integrations/integration-panels/zha/zha-group-page.ts index e56c145673..9d22b43bbb 100644 --- a/src/panels/config/integrations/integration-panels/zha/zha-group-page.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-group-page.ts @@ -1,15 +1,6 @@ import "@material/mwc-button"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - PropertyValues, - query, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit"; +import { customElement, property, state, query } from "lit/decorators"; import { HASSDomEvent } from "../../../../../common/dom/fire_event"; import { navigate } from "../../../../../common/navigate"; import { SelectionChangedEvent } from "../../../../../components/data-table/ha-data-table"; @@ -46,16 +37,16 @@ export class ZHAGroupPage extends LitElement { @property({ type: Array }) public deviceEndpoints: ZHADeviceEndpoint[] = []; - @internalProperty() private _processingAdd = false; + @state() private _processingAdd = false; - @internalProperty() private _processingRemove = false; + @state() private _processingRemove = false; - @internalProperty() + @state() private _filteredDeviceEndpoints: ZHADeviceEndpoint[] = []; - @internalProperty() private _selectedDevicesToAdd: string[] = []; + @state() private _selectedDevicesToAdd: string[] = []; - @internalProperty() private _selectedDevicesToRemove: string[] = []; + @state() private _selectedDevicesToRemove: string[] = []; @query("#addMembers", true) private _zhaAddMembersDataTable!: ZHADeviceEndpointDataTable; @@ -282,10 +273,10 @@ export class ZHAGroupPage extends LitElement { private async _deleteGroup(): Promise { await removeGroups(this.hass, [this.groupId]); - navigate(this, `/config/zha/groups`, true); + navigate(`/config/zha/groups`, { replace: true }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ css` hass-subpage { diff --git a/src/panels/config/integrations/integration-panels/zha/zha-groups-dashboard.ts b/src/panels/config/integrations/integration-panels/zha/zha-groups-dashboard.ts index ce1e02415a..39f77d934b 100644 --- a/src/panels/config/integrations/integration-panels/zha/zha-groups-dashboard.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-groups-dashboard.ts @@ -2,14 +2,13 @@ import "@material/mwc-button"; import { mdiPlus } from "@mdi/js"; import { css, - CSSResultArray, - customElement, + CSSResultGroup, html, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property } from "lit/decorators"; import memoizeOne from "memoize-one"; import { HASSDomEvent } from "../../../../../common/dom/fire_event"; import { navigate } from "../../../../../common/navigate"; @@ -141,10 +140,10 @@ export class ZHAGroupsDashboard extends LitElement { private _handleRowClicked(ev: HASSDomEvent) { const groupId = ev.detail.id; - navigate(this, `/config/zha/group/${groupId}`); + navigate(`/config/zha/group/${groupId}`); } - static get styles(): CSSResultArray { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/integrations/integration-panels/zha/zha-network-visualization-page.ts b/src/panels/config/integrations/integration-panels/zha/zha-network-visualization-page.ts index c1937537c1..b42c15fb6b 100644 --- a/src/panels/config/integrations/integration-panels/zha/zha-network-visualization-page.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-network-visualization-page.ts @@ -1,14 +1,4 @@ -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - PropertyValues, - query, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit"; import "@material/mwc-button"; import { navigate } from "../../../../../common/navigate"; @@ -19,7 +9,7 @@ import { } from "../../../../../data/zha"; import "../../../../../layouts/hass-tabs-subpage"; import type { HomeAssistant, Route } from "../../../../../types"; -import { Network, Edge, Node, EdgeOptions } from "vis-network"; +import { Network, Edge, Node, EdgeOptions } from "vis-network/peer"; import "../../../../../common/search/search-input"; import "../../../../../components/device/ha-device-picker"; import "../../../../../components/ha-button-menu"; @@ -30,6 +20,7 @@ import { DeviceRegistryEntry } from "../../../../../data/device_registry"; import "../../../../../components/ha-checkbox"; import type { HaCheckbox } from "../../../../../components/ha-checkbox"; import { zhaTabs } from "./zha-config-dashboard"; +import { customElement, property, query, state } from "lit/decorators"; @customElement("zha-network-visualization-page") export class ZHANetworkVisualizationPage extends LitElement { @@ -47,19 +38,19 @@ export class ZHANetworkVisualizationPage extends LitElement { @query("#visualization", true) private _visualization?: HTMLElement; - @internalProperty() + @state() private _devices: Map = new Map(); - @internalProperty() + @state() private _devicesByDeviceId: Map = new Map(); - @internalProperty() + @state() private _nodes: Node[] = []; - @internalProperty() + @state() private _network?: Network; - @internalProperty() + @state() private _filter?: string; private _autoZoom = true; @@ -109,11 +100,7 @@ export class ZHANetworkVisualizationPage extends LitElement { if (ieee) { const device = this._devices.get(ieee); if (device) { - navigate( - this, - `/config/devices/device/${device.device_reg_id}`, - false - ); + navigate(`/config/devices/device/${device.device_reg_id}`); } } }); @@ -361,7 +348,7 @@ export class ZHANetworkVisualizationPage extends LitElement { this._autoZoom = (ev.target as HaCheckbox).checked; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ css` .header { diff --git a/src/panels/config/integrations/integration-panels/zwave/zwave-config-router.ts b/src/panels/config/integrations/integration-panels/zwave/zwave-config-router.ts index 70d5a07b0b..4ebb4b9970 100644 --- a/src/panels/config/integrations/integration-panels/zwave/zwave-config-router.ts +++ b/src/panels/config/integrations/integration-panels/zwave/zwave-config-router.ts @@ -1,10 +1,10 @@ -import { customElement, property } from "lit-element"; +import { customElement, property } from "lit/decorators"; +import { navigate } from "../../../../../common/navigate"; import { HassRouterPage, RouterOptions, } from "../../../../../layouts/hass-router-page"; import { HomeAssistant } from "../../../../../types"; -import { navigate } from "../../../../../common/navigate"; @customElement("zwave-config-router") class ZWaveConfigRouter extends HassRouterPage { @@ -46,11 +46,10 @@ class ZWaveConfigRouter extends HassRouterPage { if (this._configEntry && !searchParams.has("config_entry")) { searchParams.append("config_entry", this._configEntry); navigate( - this, `${this.routeTail.prefix}${ this.routeTail.path }?${searchParams.toString()}`, - true + { replace: true } ); } } diff --git a/src/panels/config/integrations/integration-panels/zwave/zwave-migration.ts b/src/panels/config/integrations/integration-panels/zwave/zwave-migration.ts index 5ea9be159f..318744d30b 100644 --- a/src/panels/config/integrations/integration-panels/zwave/zwave-migration.ts +++ b/src/panels/config/integrations/integration-panels/zwave/zwave-migration.ts @@ -1,45 +1,37 @@ +import "@material/mwc-button/mwc-button"; import "@polymer/app-layout/app-header/app-header"; import "@polymer/app-layout/app-toolbar/app-toolbar"; -import "@material/mwc-button/mwc-button"; -import "../../../../../components/ha-icon-button"; -import "../../../../../components/ha-circular-progress"; import { UnsubscribeFunc } from "home-assistant-js-websocket"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - internalProperty, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { isComponentLoaded } from "../../../../../common/config/is_component_loaded"; +import { computeStateName } from "../../../../../common/entity/compute_state_name"; +import { navigate } from "../../../../../common/navigate"; import "../../../../../components/buttons/ha-call-api-button"; import "../../../../../components/buttons/ha-call-service-button"; import "../../../../../components/ha-card"; +import "../../../../../components/ha-circular-progress"; import "../../../../../components/ha-icon"; -import { - fetchNetworkStatus, - ZWaveNetworkStatus, - ZWAVE_NETWORK_STATE_STOPPED, - fetchMigrationConfig, - ZWaveMigrationConfig, - startOzwConfigFlow, -} from "../../../../../data/zwave"; -import { haStyle } from "../../../../../resources/styles"; -import type { HomeAssistant, Route } from "../../../../../types"; -import "../../../ha-config-section"; -import "../../../../../layouts/hass-subpage"; -import { showConfigFlowDialog } from "../../../../../dialogs/config-flow/show-dialog-config-flow"; -import { migrateZwave, OZWMigrationData } from "../../../../../data/ozw"; -import { navigate } from "../../../../../common/navigate"; -import { showAlertDialog } from "../../../../../dialogs/generic/show-dialog-box"; -import { computeStateName } from "../../../../../common/entity/compute_state_name"; +import "../../../../../components/ha-icon-button"; import { computeDeviceName, subscribeDeviceRegistry, } from "../../../../../data/device_registry"; -import { isComponentLoaded } from "../../../../../common/config/is_component_loaded"; +import { migrateZwave, OZWMigrationData } from "../../../../../data/ozw"; +import { + fetchMigrationConfig, + fetchNetworkStatus, + startOzwConfigFlow, + ZWaveMigrationConfig, + ZWaveNetworkStatus, + ZWAVE_NETWORK_STATE_STOPPED, +} from "../../../../../data/zwave"; +import { showConfigFlowDialog } from "../../../../../dialogs/config-flow/show-dialog-config-flow"; +import { showAlertDialog } from "../../../../../dialogs/generic/show-dialog-box"; +import "../../../../../layouts/hass-subpage"; +import { haStyle } from "../../../../../resources/styles"; +import type { HomeAssistant, Route } from "../../../../../types"; +import "../../../ha-config-section"; @customElement("zwave-migration") export class ZwaveMigration extends LitElement { @@ -51,19 +43,19 @@ export class ZwaveMigration extends LitElement { @property({ type: Boolean }) public isWide!: boolean; - @internalProperty() private _networkStatus?: ZWaveNetworkStatus; + @state() private _networkStatus?: ZWaveNetworkStatus; - @internalProperty() private _step = 0; + @state() private _step = 0; - @internalProperty() private _stoppingNetwork = false; + @state() private _stoppingNetwork = false; - @internalProperty() private _migrationConfig?: ZWaveMigrationConfig; + @state() private _migrationConfig?: ZWaveMigrationConfig; - @internalProperty() private _migrationData?: OZWMigrationData; + @state() private _migrationData?: OZWMigrationData; - @internalProperty() private _migratedZwaveEntities?: string[]; + @state() private _migratedZwaveEntities?: string[]; - @internalProperty() private _deviceNameLookup: { [id: string]: string } = {}; + @state() private _deviceNameLookup: { [id: string]: string } = {}; private _unsub?: Promise; @@ -447,7 +439,7 @@ export class ZwaveMigration extends LitElement { } private _navigateOzw() { - navigate(this, "/config/ozw"); + navigate("/config/ozw"); } private _networkStopped(): void { @@ -461,7 +453,7 @@ export class ZwaveMigration extends LitElement { this._networkStatus = await fetchNetworkStatus(this.hass!); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/integrations/integration-panels/zwave/zwave-network.ts b/src/panels/config/integrations/integration-panels/zwave/zwave-network.ts index b9860c0589..12d0284cc1 100644 --- a/src/panels/config/integrations/integration-panels/zwave/zwave-network.ts +++ b/src/panels/config/integrations/integration-panels/zwave/zwave-network.ts @@ -1,14 +1,6 @@ import { UnsubscribeFunc } from "home-assistant-js-websocket"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import "../../../../../components/buttons/ha-call-api-button"; import "../../../../../components/buttons/ha-call-service-button"; import "../../../../../components/ha-card"; @@ -35,11 +27,11 @@ export class ZwaveNetwork extends LitElement { @property() public isWide!: boolean; - @internalProperty() private _showHelp = false; + @state() private _showHelp = false; - @internalProperty() private _networkStatus?: ZWaveNetworkStatus; + @state() private _networkStatus?: ZWaveNetworkStatus; - @internalProperty() private _unsubs: Array> = []; + @state() private _unsubs: Array> = []; public disconnectedCallback(): void { this._unsubscribe(); @@ -239,7 +231,7 @@ export class ZwaveNetwork extends LitElement { `; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/integrations/integration-panels/zwave/zwave-node-config.ts b/src/panels/config/integrations/integration-panels/zwave/zwave-node-config.ts index 343cc3b479..3a846334b6 100644 --- a/src/panels/config/integrations/integration-panels/zwave/zwave-node-config.ts +++ b/src/panels/config/integrations/integration-panels/zwave/zwave-node-config.ts @@ -4,15 +4,13 @@ import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; import "../../../../../components/buttons/ha-call-service-button"; import "../../../../../components/ha-card"; import { @@ -34,13 +32,13 @@ export class ZwaveNodeConfig extends LitElement { @property() public selectedNode = -1; - @internalProperty() private _configItem?: ZWaveConfigItem; + @state() private _configItem?: ZWaveConfigItem; - @internalProperty() private _wakeupInput = -1; + @state() private _wakeupInput = -1; - @internalProperty() private _selectedConfigParameter = -1; + @state() private _selectedConfigParameter = -1; - @internalProperty() private _selectedConfigValue: number | string = -1; + @state() private _selectedConfigValue: number | string = -1; protected render(): TemplateResult { return html` @@ -107,9 +105,9 @@ export class ZwaveNodeConfig extends LitElement { @iron-select=${this._selectedConfigParameterChanged} > ${this.config.map( - (state) => html` + (entityState) => html` - ${state.key}: ${state.value.label} + ${entityState.key}: ${entityState.value.label} ` )} @@ -135,8 +133,8 @@ export class ZwaveNodeConfig extends LitElement { @iron-select=${this._configValueSelectChanged} > ${this._configItem.value.data_items.map( - (state) => html` - ${state} + (entityState) => html` + ${entityState} ` )} @@ -218,7 +216,7 @@ export class ZwaveNodeConfig extends LitElement { `; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/integrations/integration-panels/zwave/zwave-values.ts b/src/panels/config/integrations/integration-panels/zwave/zwave-values.ts index 9d2ee97f3e..1e6750c6af 100644 --- a/src/panels/config/integrations/integration-panels/zwave/zwave-values.ts +++ b/src/panels/config/integrations/integration-panels/zwave/zwave-values.ts @@ -1,16 +1,8 @@ import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import "../../../../../components/buttons/ha-call-service-button"; import "../../../../../components/ha-card"; import { ZWaveValue } from "../../../../../data/zwave"; @@ -23,7 +15,7 @@ export class ZwaveValues extends LitElement { @property() public values: ZWaveValue[] = []; - @internalProperty() private _selectedValue = -1; + @state() private _selectedValue = -1; protected render(): TemplateResult { return html` @@ -54,7 +46,7 @@ export class ZwaveValues extends LitElement { `; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/integrations/integration-panels/zwave_js/dialog-zwave_js-add-node.ts b/src/panels/config/integrations/integration-panels/zwave_js/dialog-zwave_js-add-node.ts index fa9f30869e..9e2f4e8874 100644 --- a/src/panels/config/integrations/integration-panels/zwave_js/dialog-zwave_js-add-node.ts +++ b/src/panels/config/integrations/integration-panels/zwave_js/dialog-zwave_js-add-node.ts @@ -2,22 +2,14 @@ import "@material/mwc-button/mwc-button"; import { mdiCheckCircle, mdiCloseCircle } from "@mdi/js"; import "../../../../../components/ha-switch"; import "../../../../../components/ha-formfield"; -import { - CSSResult, - customElement, - html, - LitElement, - property, - internalProperty, - TemplateResult, - css, -} from "lit-element"; +import { CSSResultGroup, html, LitElement, TemplateResult, css } from "lit"; import "../../../../../components/ha-circular-progress"; import { createCloseHeading } from "../../../../../components/ha-dialog"; import { haStyleDialog } from "../../../../../resources/styles"; import { HomeAssistant } from "../../../../../types"; import { ZWaveJSAddNodeDialogParams } from "./show-dialog-zwave_js-add-node"; import { fireEvent } from "../../../../../common/dom/fire_event"; +import { customElement, property, state } from "lit/decorators"; export interface ZWaveJSAddNodeDevice { id: string; @@ -28,13 +20,19 @@ export interface ZWaveJSAddNodeDevice { class DialogZWaveJSAddNode extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private entry_id?: string; + @state() private entry_id?: string; - @internalProperty() private _use_secure_inclusion = false; + @state() private _use_secure_inclusion = false; - @internalProperty() private _status = ""; + @state() private _status = ""; - @internalProperty() private _device?: ZWaveJSAddNodeDevice; + @state() private _nodeAdded = false; + + @state() private _device?: ZWaveJSAddNodeDevice; + + @state() private _stages?: string[]; + + private _stoppedTimeout?: any; private _addNodeTimeoutHandle?: number; @@ -128,6 +126,40 @@ class DialogZWaveJSAddNode extends LitElement { ` : ``} + ${this._status === "interviewing" + ? html` +
+ +
+

+ ${this.hass.localize( + "ui.panel.config.zwave_js.add_node.interview_started" + )} +

+ ${this._stages + ? html`
+ ${this._stages.map( + (stage) => html` + + + ${stage} + + ` + )} +
` + : ""} +
+
+ + ${this.hass.localize("ui.panel.config.zwave_js.common.close")} + + ` + : ``} ${this._status === "failed" ? html`
@@ -141,6 +173,21 @@ class DialogZWaveJSAddNode extends LitElement { "ui.panel.config.zwave_js.add_node.inclusion_failed" )}

+ ${this._stages + ? html`
+ ${this._stages.map( + (stage) => html` + + + ${stage} + + ` + )} +
` + : ""}
@@ -168,6 +215,21 @@ class DialogZWaveJSAddNode extends LitElement { )} + ${this._stages + ? html`
+ ${this._stages.map( + (stage) => html` + + + ${stage} + + ` + )} +
` + : ""}
@@ -211,16 +273,41 @@ class DialogZWaveJSAddNode extends LitElement { this._status = "failed"; } if (message.event === "inclusion stopped") { - if (this._status !== "finished") { - this._status = ""; - } - this._unsubscribe(); + // we get the inclusion stopped event before the node added event + // during a successful inclusion. so we set a timer to wait 3 seconds + // to give the node added event time to come in before assuming it + // timed out or was cancelled and unsubscribing. + this._stoppedTimeout = setTimeout(() => { + if (!this._nodeAdded) { + this._status = ""; + this._unsubscribe(); + this._stoppedTimeout = undefined; + } + }, 3000); } if (message.event === "device registered") { this._device = message.device; + } + if (message.event === "node added") { + this._nodeAdded = true; + if (this._stoppedTimeout) { + clearTimeout(this._stoppedTimeout); + } + this._status = "interviewing"; + } + + if (message.event === "interview completed") { this._status = "finished"; this._unsubscribe(); } + + if (message.event === "interview stage completed") { + if (this._stages === undefined) { + this._stages = [message.stage]; + } else { + this._stages = [...this._stages, message.stage]; + } + } } private _unsubscribe(): void { @@ -246,13 +333,19 @@ class DialogZWaveJSAddNode extends LitElement { this._unsubscribe(); this.entry_id = undefined; this._status = ""; + this._nodeAdded = false; this._device = undefined; + this._stages = undefined; + if (this._stoppedTimeout) { + clearTimeout(this._stoppedTimeout); + this._stoppedTimeout = undefined; + } this._use_secure_inclusion = false; fireEvent(this, "dialog-closed", { dialog: this.localName }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyleDialog, css` @@ -261,11 +354,24 @@ class DialogZWaveJSAddNode extends LitElement { } .success { - color: green; + color: var(--success-color); } .failed { - color: red; + color: var(--warning-color); + } + + .stages { + margin-top: 16px; + } + + .flex-container .stage ha-svg-icon { + width: 16px; + height: 16px; + margin-right: 0px; + } + .stage { + padding: 8px; } blockquote { diff --git a/src/panels/config/integrations/integration-panels/zwave_js/dialog-zwave_js-reinterview-node.ts b/src/panels/config/integrations/integration-panels/zwave_js/dialog-zwave_js-reinterview-node.ts index 7dfc9a999a..c3bfd90433 100644 --- a/src/panels/config/integrations/integration-panels/zwave_js/dialog-zwave_js-reinterview-node.ts +++ b/src/panels/config/integrations/integration-panels/zwave_js/dialog-zwave_js-reinterview-node.ts @@ -1,35 +1,27 @@ import "@material/mwc-button/mwc-button"; import { mdiCheckCircle, mdiCloseCircle } from "@mdi/js"; -import { - CSSResult, - customElement, - html, - LitElement, - property, - internalProperty, - TemplateResult, - css, -} from "lit-element"; +import { UnsubscribeFunc } from "home-assistant-js-websocket"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { fireEvent } from "../../../../../common/dom/fire_event"; import "../../../../../components/ha-circular-progress"; import { createCloseHeading } from "../../../../../components/ha-dialog"; +import { reinterviewNode } from "../../../../../data/zwave_js"; import { haStyleDialog } from "../../../../../resources/styles"; import { HomeAssistant } from "../../../../../types"; import { ZWaveJSReinterviewNodeDialogParams } from "./show-dialog-zwave_js-reinterview-node"; -import { fireEvent } from "../../../../../common/dom/fire_event"; -import { UnsubscribeFunc } from "home-assistant-js-websocket"; -import { reinterviewNode } from "../../../../../data/zwave_js"; @customElement("dialog-zwave_js-reinterview-node") class DialogZWaveJSReinterviewNode extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private entry_id?: string; + @state() private entry_id?: string; - @internalProperty() private node_id?: number; + @state() private node_id?: number; - @internalProperty() private _status?: string; + @state() private _status?: string; - @internalProperty() private _stages?: string[]; + @state() private _stages?: string[]; private _subscribed?: Promise; @@ -212,7 +204,7 @@ class DialogZWaveJSReinterviewNode extends LitElement { fireEvent(this, "dialog-closed", { dialog: this.localName }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyleDialog, css` diff --git a/src/panels/config/integrations/integration-panels/zwave_js/dialog-zwave_js-remove-node.ts b/src/panels/config/integrations/integration-panels/zwave_js/dialog-zwave_js-remove-node.ts index a319ad8ce9..a6f7018940 100644 --- a/src/panels/config/integrations/integration-panels/zwave_js/dialog-zwave_js-remove-node.ts +++ b/src/panels/config/integrations/integration-panels/zwave_js/dialog-zwave_js-remove-node.ts @@ -1,21 +1,13 @@ import "@material/mwc-button/mwc-button"; -import { - CSSResult, - customElement, - html, - LitElement, - property, - internalProperty, - TemplateResult, - css, -} from "lit-element"; +import { mdiCheckCircle, mdiCloseCircle } 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 "../../../../../components/ha-circular-progress"; import { createCloseHeading } from "../../../../../components/ha-dialog"; import { haStyleDialog } from "../../../../../resources/styles"; import { HomeAssistant } from "../../../../../types"; import { ZWaveJSRemoveNodeDialogParams } from "./show-dialog-zwave_js-remove-node"; -import { mdiCheckCircle, mdiCloseCircle } from "@mdi/js"; -import { fireEvent } from "../../../../../common/dom/fire_event"; export interface ZWaveJSRemovedNode { node_id: number; @@ -27,11 +19,11 @@ export interface ZWaveJSRemovedNode { class DialogZWaveJSRemoveNode extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private entry_id?: string; + @state() private entry_id?: string; - @internalProperty() private _status = ""; + @state() private _status = ""; - @internalProperty() private _node?: ZWaveJSRemovedNode; + @state() private _node?: ZWaveJSRemovedNode; private _removeNodeTimeoutHandle?: number; @@ -213,7 +205,7 @@ class DialogZWaveJSRemoveNode extends LitElement { fireEvent(this, "dialog-closed", { dialog: this.localName }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyleDialog, css` diff --git a/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-config-dashboard.ts b/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-config-dashboard.ts index eb53eeafba..6a9580cb7f 100644 --- a/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-config-dashboard.ts +++ b/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-config-dashboard.ts @@ -1,20 +1,12 @@ import "@material/mwc-button/mwc-button"; import "@material/mwc-icon-button/mwc-icon-button"; import { mdiCheckCircle, mdiCircle, mdiRefresh } from "@mdi/js"; -import { - css, - CSSResultArray, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import "../../../../../components/ha-card"; -import "../../../../../components/ha-svg-icon"; import "../../../../../components/ha-icon-next"; +import "../../../../../components/ha-svg-icon"; import { getSignedPath } from "../../../../../data/auth"; import { fetchDataCollectionStatus, @@ -49,15 +41,15 @@ class ZWaveJSConfigDashboard extends LitElement { @property() public configEntryId?: string; - @internalProperty() private _network?: ZWaveJSNetwork; + @state() private _network?: ZWaveJSNetwork; - @internalProperty() private _nodes?: ZWaveJSNode[]; + @state() private _nodes?: ZWaveJSNode[]; - @internalProperty() private _status = "unknown"; + @state() private _status = "unknown"; - @internalProperty() private _icon = mdiCircle; + @state() private _icon = mdiCircle; - @internalProperty() private _dataCollectionOptIn?: boolean; + @state() private _dataCollectionOptIn?: boolean; protected firstUpdated() { if (this.hass) { @@ -328,7 +320,7 @@ class ZWaveJSConfigDashboard extends LitElement { this.shadowRoot!.removeChild(a); } - static get styles(): CSSResultArray { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-config-router.ts b/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-config-router.ts index 2973f17c3b..c81eacadea 100644 --- a/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-config-router.ts +++ b/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-config-router.ts @@ -1,4 +1,3 @@ -import { customElement, property } from "lit-element"; import { HassRouterPage, RouterOptions, @@ -8,6 +7,7 @@ import { navigate } from "../../../../../common/navigate"; import { PageNavigation } from "../../../../../layouts/hass-tabs-subpage"; import { mdiServerNetwork, mdiMathLog } from "@mdi/js"; +import { customElement, property } from "lit/decorators"; export const configTabs: PageNavigation[] = [ { @@ -64,11 +64,10 @@ class ZWaveJSConfigRouter extends HassRouterPage { if (this._configEntry && !searchParams.has("config_entry")) { searchParams.append("config_entry", this._configEntry); navigate( - this, `${this.routeTail.prefix}${ this.routeTail.path }?${searchParams.toString()}`, - true + { replace: true } ); } } diff --git a/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-logs.ts b/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-logs.ts index b51a9d8163..37a984666e 100644 --- a/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-logs.ts +++ b/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-logs.ts @@ -1,27 +1,19 @@ -import { UnsubscribeFunc } from "home-assistant-js-websocket"; -import { - css, - html, - property, - customElement, - LitElement, - CSSResultArray, - internalProperty, - query, -} from "lit-element"; -import "@polymer/paper-listbox/paper-listbox"; import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; +import "@polymer/paper-listbox/paper-listbox"; +import { UnsubscribeFunc } from "home-assistant-js-websocket"; +import { css, CSSResultArray, html, LitElement } from "lit"; +import { customElement, property, state, query } from "lit/decorators"; import { fetchZWaveJSLogConfig, setZWaveJSLogLevel, subscribeZWaveJSLogs, ZWaveJSLogConfig, } from "../../../../../data/zwave_js"; +import "../../../../../layouts/hass-tabs-subpage"; import { SubscribeMixin } from "../../../../../mixins/subscribe-mixin"; +import { haStyle } from "../../../../../resources/styles"; import { HomeAssistant, Route } from "../../../../../types"; import { configTabs } from "./zwave_js-config-router"; -import "../../../../../layouts/hass-tabs-subpage"; -import { haStyle } from "../../../../../resources/styles"; @customElement("zwave_js-logs") class ZWaveJSLogs extends SubscribeMixin(LitElement) { @@ -33,7 +25,7 @@ class ZWaveJSLogs extends SubscribeMixin(LitElement) { @property() public configEntryId!: string; - @internalProperty() private _logConfig?: ZWaveJSLogConfig; + @state() private _logConfig?: ZWaveJSLogConfig; @query("textarea", true) private _textarea?: HTMLTextAreaElement; @@ -126,10 +118,16 @@ class ZWaveJSLogs extends SubscribeMixin(LitElement) { if (ev.target === undefined || this._logConfig === undefined) { return; } - if (this._logConfig.level === ev.target.selected) { + const selected = ev.target.selected; + if (this._logConfig.level === selected) { return; } - setZWaveJSLogLevel(this.hass!, this.configEntryId, ev.target.selected); + setZWaveJSLogLevel(this.hass!, this.configEntryId, selected); + this._logConfig.level = selected; + this._textarea!.value += `${this.hass.localize( + "ui.panel.config.zwave_js.logs.log_level_changed", + { level: selected.charAt(0).toUpperCase() + selected.slice(1) } + )}\n`; } static get styles(): CSSResultArray { diff --git a/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-node-config.ts b/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-node-config.ts index bc850d348f..b58c12ec53 100644 --- a/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-node-config.ts +++ b/src/panels/config/integrations/integration-panels/zwave_js/zwave_js-node-config.ts @@ -1,31 +1,37 @@ -import { - mdiCheckCircle, - mdiCircle, - mdiProgressClock, - mdiCloseCircle, -} from "@mdi/js"; -import "../../../../../components/ha-settings-row"; -import "@polymer/paper-item/paper-item"; -import "@polymer/paper-listbox/paper-listbox"; -import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; import "@material/mwc-button/mwc-button"; import "@material/mwc-icon-button/mwc-icon-button"; +import { + mdiCheckCircle, + mdiCircle, + mdiCloseCircle, + mdiProgressClock, +} from "@mdi/js"; +import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; +import "@polymer/paper-item/paper-item"; +import "@polymer/paper-listbox/paper-listbox"; +import { UnsubscribeFunc } from "home-assistant-js-websocket"; import { css, - CSSResultArray, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; +import memoizeOne from "memoize-one"; import { debounce } from "../../../../../common/util/debounce"; import "../../../../../components/ha-card"; -import "../../../../../components/ha-svg-icon"; import "../../../../../components/ha-icon-next"; +import "../../../../../components/ha-settings-row"; +import "../../../../../components/ha-svg-icon"; import "../../../../../components/ha-switch"; +import { + computeDeviceName, + DeviceRegistryEntry, + subscribeDeviceRegistry, +} from "../../../../../data/device_registry"; import { fetchNodeConfigParameters, setNodeConfigParameter, @@ -33,19 +39,11 @@ import { ZWaveJSSetConfigParamResult, } from "../../../../../data/zwave_js"; import "../../../../../layouts/hass-tabs-subpage"; +import { SubscribeMixin } from "../../../../../mixins/subscribe-mixin"; import { haStyle } from "../../../../../resources/styles"; import type { HomeAssistant, Route } from "../../../../../types"; import "../../../ha-config-section"; import { configTabs } from "./zwave_js-config-router"; -import { - DeviceRegistryEntry, - computeDeviceName, - subscribeDeviceRegistry, -} from "../../../../../data/device_registry"; -import { SubscribeMixin } from "../../../../../mixins/subscribe-mixin"; -import { UnsubscribeFunc } from "home-assistant-js-websocket"; -import memoizeOne from "memoize-one"; -import { classMap } from "lit-html/directives/class-map"; const icons = { accepted: mdiCheckCircle, @@ -91,14 +89,11 @@ class ZWaveJSNodeConfig extends SubscribeMixin(LitElement) { @property({ type: Array }) private _deviceRegistryEntries?: DeviceRegistryEntry[]; - @internalProperty() private _config?: ZWaveJSNodeConfigParams; + @state() private _config?: ZWaveJSNodeConfigParams; - @internalProperty() private _results: Record< - string, - ZWaveJSSetConfigParamResult - > = {}; + @state() private _results: Record = {}; - @internalProperty() private _error?: string; + @state() private _error?: string; public connectedCallback(): void { super.connectedCallback(); @@ -294,8 +289,8 @@ class ZWaveJSNodeConfig extends SubscribeMixin(LitElement) { @iron-select=${this._dropdownSelected} > ${Object.entries(item.metadata.states).map( - ([key, state]) => html` - ${state} + ([key, entityState]) => html` + ${entityState} ` )} @@ -428,7 +423,7 @@ class ZWaveJSNodeConfig extends SubscribeMixin(LitElement) { ); } - static get styles(): CSSResultArray { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/logs/dialog-system-log-detail.ts b/src/panels/config/logs/dialog-system-log-detail.ts index db8a33c244..51e2483d73 100644 --- a/src/panels/config/logs/dialog-system-log-detail.ts +++ b/src/panels/config/logs/dialog-system-log-detail.ts @@ -1,15 +1,8 @@ import "@material/mwc-icon-button/mwc-icon-button"; import { mdiClose, mdiContentCopy, mdiPackageVariant } from "@mdi/js"; import "@polymer/paper-tooltip/paper-tooltip"; -import { - css, - CSSResult, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { property, state } from "lit/decorators"; import { fireEvent } from "../../../common/dom/fire_event"; import { copyToClipboard } from "../../../common/util/copy-clipboard"; import "../../../components/ha-dialog"; @@ -34,9 +27,9 @@ import { formatSystemLogTime } from "./util"; class DialogSystemLogDetail extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _params?: SystemLogDetailDialogParams; + @state() private _params?: SystemLogDetailDialogParams; - @internalProperty() private _manifest?: IntegrationManifest; + @state() private _manifest?: IntegrationManifest; public async showDialog(params: SystemLogDetailDialogParams): Promise { this._params = params; @@ -197,7 +190,7 @@ class DialogSystemLogDetail extends LitElement { }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyleDialog, css` diff --git a/src/panels/config/logs/error-log-card.ts b/src/panels/config/logs/error-log-card.ts index 2dd3fc9ceb..b096fb93ad 100644 --- a/src/panels/config/logs/error-log-card.ts +++ b/src/panels/config/logs/error-log-card.ts @@ -1,13 +1,6 @@ import "@material/mwc-button"; -import { - css, - CSSResult, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { property, state } from "lit/decorators"; import "../../../components/ha-icon-button"; import { fetchErrorLog } from "../../../data/error_log"; import { HomeAssistant } from "../../../types"; @@ -15,7 +8,7 @@ import { HomeAssistant } from "../../../types"; class ErrorLogCard extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _errorHTML!: TemplateResult[] | string; + @state() private _errorHTML!: TemplateResult[] | string; protected render(): TemplateResult { return html` @@ -47,7 +40,7 @@ class ErrorLogCard extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` .error-log-intro { text-align: center; diff --git a/src/panels/config/logs/ha-config-logs.ts b/src/panels/config/logs/ha-config-logs.ts index a8c822ccd1..13ef1137dc 100644 --- a/src/panels/config/logs/ha-config-logs.ts +++ b/src/panels/config/logs/ha-config-logs.ts @@ -1,13 +1,5 @@ -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, - query, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, query } from "lit/decorators"; import "../../../layouts/hass-tabs-subpage"; import { haStyle } from "../../../resources/styles"; import { HomeAssistant, Route } from "../../../types"; @@ -54,7 +46,7 @@ export class HaConfigLogs extends LitElement { `; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/logs/system-log-card.ts b/src/panels/config/logs/system-log-card.ts index 3cc184b8be..bc59a07457 100644 --- a/src/panels/config/logs/system-log-card.ts +++ b/src/panels/config/logs/system-log-card.ts @@ -1,15 +1,7 @@ import "@polymer/paper-item/paper-item"; import "@polymer/paper-item/paper-item-body"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import "../../../components/buttons/ha-call-service-button"; import "../../../components/buttons/ha-progress-button"; import "../../../components/ha-card"; @@ -32,7 +24,7 @@ export class SystemLogCard extends LitElement { public loaded = false; - @internalProperty() private _items?: LoggedError[]; + @state() private _items?: LoggedError[]; public async fetchData(): Promise { this._items = undefined; @@ -154,7 +146,7 @@ export class SystemLogCard extends LitElement { showSystemLogDetailDialog(this, { item }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` ha-card { padding-top: 16px; diff --git a/src/panels/config/logs/util.ts b/src/panels/config/logs/util.ts index ebe74c2e06..3eb92fcd96 100644 --- a/src/panels/config/logs/util.ts +++ b/src/panels/config/logs/util.ts @@ -1,8 +1,8 @@ import { formatDateTimeWithSeconds } from "../../../common/datetime/format_date_time"; import { formatTimeWithSeconds } from "../../../common/datetime/format_time"; -import { FrontendTranslationData } from "../../../data/translation"; +import { FrontendLocaleData } from "../../../data/translation"; -export const formatSystemLogTime = (date, locale: FrontendTranslationData) => { +export const formatSystemLogTime = (date, locale: FrontendLocaleData) => { const today = new Date().setHours(0, 0, 0, 0); const dateTime = new Date(date * 1000); const dateTimeDay = new Date(date * 1000).setHours(0, 0, 0, 0); diff --git a/src/panels/config/lovelace/dashboards/dialog-lovelace-dashboard-detail.ts b/src/panels/config/lovelace/dashboards/dialog-lovelace-dashboard-detail.ts index 3ed55ea16d..d7dbaa4eca 100644 --- a/src/panels/config/lovelace/dashboards/dialog-lovelace-dashboard-detail.ts +++ b/src/panels/config/lovelace/dashboards/dialog-lovelace-dashboard-detail.ts @@ -1,14 +1,6 @@ import "@material/mwc-button/mwc-button"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { slugify } from "../../../../common/string/slugify"; import { computeRTLDirection } from "../../../../common/util/compute_rtl"; import { createCloseHeading } from "../../../../components/ha-dialog"; @@ -31,22 +23,22 @@ import { LovelaceDashboardDetailsDialogParams } from "./show-dialog-lovelace-das export class DialogLovelaceDashboardDetail extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _params?: LovelaceDashboardDetailsDialogParams; + @state() private _params?: LovelaceDashboardDetailsDialogParams; - @internalProperty() private _urlPath!: LovelaceDashboard["url_path"]; + @state() private _urlPath!: LovelaceDashboard["url_path"]; - @internalProperty() private _showInSidebar!: boolean; + @state() private _showInSidebar!: boolean; - @internalProperty() private _icon!: string; + @state() private _icon!: string; - @internalProperty() private _title!: string; + @state() private _title!: string; - @internalProperty() + @state() private _requireAdmin!: LovelaceDashboard["require_admin"]; - @internalProperty() private _error?: string; + @state() private _error?: string; - @internalProperty() private _submitting = false; + @state() private _submitting = false; public async showDialog( params: LovelaceDashboardDetailsDialogParams @@ -82,7 +74,7 @@ export class DialogLovelaceDashboardDetail extends LitElement { return html` { @@ -246,8 +239,7 @@ export class HaConfigLovelaceDashboards extends LitElement { private _navigate(ev: Event) { ev.stopPropagation(); - const url = `/${(ev.target as any).urlPath}`; - navigate(this, url); + navigate(`/${(ev.target as any).urlPath}`); } private _editDashboard(ev: CustomEvent) { diff --git a/src/panels/config/lovelace/ha-config-lovelace.ts b/src/panels/config/lovelace/ha-config-lovelace.ts index 1f12645d3b..2c09c81569 100644 --- a/src/panels/config/lovelace/ha-config-lovelace.ts +++ b/src/panels/config/lovelace/ha-config-lovelace.ts @@ -1,4 +1,4 @@ -import { customElement, property } from "lit-element"; +import { customElement, property } from "lit/decorators"; import { HassRouterPage, RouterOptions, diff --git a/src/panels/config/lovelace/resources/dialog-lovelace-resource-detail.ts b/src/panels/config/lovelace/resources/dialog-lovelace-resource-detail.ts index ff4df8eb82..b4145ca5c3 100644 --- a/src/panels/config/lovelace/resources/dialog-lovelace-resource-detail.ts +++ b/src/panels/config/lovelace/resources/dialog-lovelace-resource-detail.ts @@ -2,16 +2,8 @@ import "@material/mwc-button/mwc-button"; import "@polymer/paper-input/paper-input"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { createCloseHeading } from "../../../../components/ha-dialog"; import "../../../../components/ha-paper-dropdown-menu"; import { @@ -41,15 +33,15 @@ const detectResourceType = (url: string) => { export class DialogLovelaceResourceDetail extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _params?: LovelaceResourceDetailsDialogParams; + @state() private _params?: LovelaceResourceDetailsDialogParams; - @internalProperty() private _url!: LovelaceResource["url"]; + @state() private _url!: LovelaceResource["url"]; - @internalProperty() private _type?: LovelaceResource["type"]; + @state() private _type?: LovelaceResource["type"]; - @internalProperty() private _error?: string; + @state() private _error?: string; - @internalProperty() private _submitting = false; + @state() private _submitting = false; public async showDialog( params: LovelaceResourceDetailsDialogParams @@ -74,7 +66,7 @@ export class DialogLovelaceResourceDetail extends LitElement { return html` ({ diff --git a/src/panels/config/person/dialog-person-detail.ts b/src/panels/config/person/dialog-person-detail.ts index 9d83ae4d9a..88dce3ce2c 100644 --- a/src/panels/config/person/dialog-person-detail.ts +++ b/src/panels/config/person/dialog-person-detail.ts @@ -1,14 +1,7 @@ import "@material/mwc-button"; import "@polymer/paper-input/paper-input"; -import { - css, - CSSResult, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { property, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import { computeRTLDirection } from "../../../common/util/compute_rtl"; import "../../../components/entity/ha-entities-picker"; @@ -50,25 +43,25 @@ const cropOptions: CropOptions = { class DialogPersonDetail extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _name!: string; + @state() private _name!: string; - @internalProperty() private _userId?: string; + @state() private _userId?: string; - @internalProperty() private _user?: User; + @state() private _user?: User; - @internalProperty() private _isAdmin?: boolean; + @state() private _isAdmin?: boolean; - @internalProperty() private _deviceTrackers!: string[]; + @state() private _deviceTrackers!: string[]; - @internalProperty() private _picture!: string | null; + @state() private _picture!: string | null; - @internalProperty() private _error?: string; + @state() private _error?: string; - @internalProperty() private _params?: PersonDetailDialogParams; + @state() private _params?: PersonDetailDialogParams; - @internalProperty() private _submitting = false; + @state() private _submitting = false; - @internalProperty() private _personExists = false; + @state() private _personExists = false; private _deviceTrackersAvailable = memoizeOne((hass) => Object.keys(hass.states).some( @@ -438,7 +431,7 @@ class DialogPersonDetail extends LitElement { this._params = undefined; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyleDialog, css` diff --git a/src/panels/config/person/ha-config-person.ts b/src/panels/config/person/ha-config-person.ts index 697627e09f..e67bb715f6 100644 --- a/src/panels/config/person/ha-config-person.ts +++ b/src/panels/config/person/ha-config-person.ts @@ -1,15 +1,8 @@ import { mdiPlus } from "@mdi/js"; import "@polymer/paper-item/paper-icon-item"; import "@polymer/paper-item/paper-item-body"; -import { - css, - CSSResult, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { property, state } from "lit/decorators"; import { compare } from "../../../common/string/compare"; import "../../../components/ha-card"; import "../../../components/ha-fab"; @@ -47,9 +40,9 @@ class HaConfigPerson extends LitElement { @property() public route!: Route; - @internalProperty() private _storageItems?: Person[]; + @state() private _storageItems?: Person[]; - @internalProperty() private _configItems?: Person[]; + @state() private _configItems?: Person[]; private _usersLoad?: Promise; @@ -265,7 +258,7 @@ class HaConfigPerson extends LitElement { }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` a { color: var(--primary-color); diff --git a/src/panels/config/scene/ha-config-scene.ts b/src/panels/config/scene/ha-config-scene.ts index 275a00200f..ae0742e754 100644 --- a/src/panels/config/scene/ha-config-scene.ts +++ b/src/panels/config/scene/ha-config-scene.ts @@ -1,5 +1,6 @@ import { HassEntities } from "home-assistant-js-websocket"; -import { customElement, property, PropertyValues } from "lit-element"; +import { PropertyValues } from "lit"; +import { customElement, property } from "lit/decorators"; import memoizeOne from "memoize-one"; import { computeStateDomain } from "../../../common/entity/compute_state_domain"; import { debounce } from "../../../common/util/debounce"; diff --git a/src/panels/config/scene/ha-scene-dashboard.ts b/src/panels/config/scene/ha-scene-dashboard.ts index cdecf87ec2..d887231989 100644 --- a/src/panels/config/scene/ha-scene-dashboard.ts +++ b/src/panels/config/scene/ha-scene-dashboard.ts @@ -8,26 +8,18 @@ import { mdiPlus, } from "@mdi/js"; import "@polymer/paper-tooltip/paper-tooltip"; -import { - css, - CSSResultArray, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; -import { ifDefined } from "lit-html/directives/if-defined"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { ifDefined } from "lit/directives/if-defined"; import memoizeOne from "memoize-one"; import { fireEvent } from "../../../common/dom/fire_event"; import { computeStateName } from "../../../common/entity/compute_state_name"; import { stateIcon } from "../../../common/entity/state_icon"; import { DataTableColumnContainer } from "../../../components/data-table/ha-data-table"; +import "../../../components/ha-button-related-filter-menu"; import "../../../components/ha-fab"; import "../../../components/ha-icon"; import "../../../components/ha-svg-icon"; -import "../../../components/ha-button-related-filter-menu"; import { forwardHaptic } from "../../../data/haptics"; import { activateScene, SceneEntity } from "../../../data/scene"; import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box"; @@ -52,9 +44,9 @@ class HaSceneDashboard extends LitElement { @property() private _activeFilters?: string[]; - @internalProperty() private _filteredScenes?: string[] | null; + @state() private _filteredScenes?: string[] | null; - @internalProperty() private _filterValue?; + @state() private _filterValue?; private _scenes = memoizeOne( (scenes: SceneEntity[], filteredScenes?: string[] | null) => { @@ -252,7 +244,7 @@ class HaSceneDashboard extends LitElement { }); } - static get styles(): CSSResultArray { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/scene/ha-scene-editor.ts b/src/panels/config/scene/ha-scene-editor.ts index 0fd4d9dcd1..bf4b44e295 100644 --- a/src/panels/config/scene/ha-scene-editor.ts +++ b/src/panels/config/scene/ha-scene-editor.ts @@ -1,20 +1,25 @@ -import { mdiContentSave } from "@mdi/js"; +import { ActionDetail } from "@material/mwc-list/mwc-list-foundation"; +import "@material/mwc-list/mwc-list-item"; +import { + mdiContentDuplicate, + mdiContentSave, + mdiDelete, + mdiDotsVertical, +} from "@mdi/js"; import "@polymer/paper-item/paper-icon-item"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-item/paper-item-body"; import { HassEvent } from "home-assistant-js-websocket"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import memoizeOne from "memoize-one"; import { fireEvent } from "../../../common/dom/fire_event"; import { computeDomain } from "../../../common/entity/compute_domain"; @@ -48,6 +53,7 @@ import { SceneEntities, SceneEntity, SCENE_IGNORED_DOMAINS, + showSceneEditor, } from "../../../data/scene"; import { showAlertDialog, @@ -83,35 +89,35 @@ export class HaSceneEditor extends SubscribeMixin( @property() public route!: Route; - @property() public sceneId?: string; + @property() public sceneId: string | null = null; @property() public scenes!: SceneEntity[]; @property() public showAdvanced!: boolean; - @internalProperty() private _dirty = false; + @state() private _dirty = false; - @internalProperty() private _errors?: string; + @state() private _errors?: string; - @internalProperty() private _config?: SceneConfig; + @state() private _config?: SceneConfig; - @internalProperty() private _entities: string[] = []; + @state() private _entities: string[] = []; - @internalProperty() private _devices: string[] = []; + @state() private _devices: string[] = []; - @internalProperty() + @state() private _deviceRegistryEntries: DeviceRegistryEntry[] = []; - @internalProperty() + @state() private _entityRegistryEntries: EntityRegistryEntry[] = []; - @internalProperty() private _scene?: SceneEntity; + @state() private _scene?: SceneEntity; private _storedStates: SceneEntities = {}; private _unsubscribeEvents?: () => void; - @internalProperty() private _deviceEntityLookup: DeviceEntitiesLookup = {}; + @state() private _deviceEntityLookup: DeviceEntitiesLookup = {}; private _activateContextId?: string; @@ -198,19 +204,52 @@ export class HaSceneEditor extends SubscribeMixin( .backCallback=${() => this._backTapped()} .tabs=${configSections.automation} > - ${!this.sceneId - ? "" - : html` - - `} + + + + + + ${this.hass.localize( + "ui.panel.config.scene.picker.duplicate_scene" + )} + + + + + ${this.hass.localize("ui.panel.config.scene.picker.delete_scene")} + + + + ${this._errors ? html`
${this._errors}
` : ""} ${this.narrow ? html` ${name} ` : ""}
) { + switch (ev.detail.index) { + case 0: + this._duplicate(); + break; + case 1: + this._deleteTapped(); + break; + } + } + private async _setScene() { const scene = this.scenes.find( (entity: SceneEntity) => entity.attributes.id === this.sceneId @@ -683,12 +733,37 @@ export class HaSceneEditor extends SubscribeMixin( history.back(); } + private async _duplicate() { + if (this._dirty) { + if ( + !(await showConfirmationDialog(this, { + text: this.hass!.localize( + "ui.panel.config.scene.editor.unsaved_confirm" + ), + confirmText: this.hass!.localize("ui.common.leave"), + dismissText: this.hass!.localize("ui.common.stay"), + })) + ) { + return; + } + // Wait for dialog to complete closing + await new Promise((resolve) => setTimeout(resolve, 0)); + } + showSceneEditor({ + ...this._config, + id: undefined, + name: `${this._config?.name} (${this.hass.localize( + "ui.panel.config.scene.picker.duplicate" + )})`, + }); + } + private _calculateStates(): SceneEntities { const output: SceneEntities = {}; this._entities.forEach((entityId) => { - const state = this._getCurrentState(entityId); - if (state) { - output[entityId] = state; + const entityState = this._getCurrentState(entityId); + if (entityState) { + output[entityId] = entityState; } }); return output; @@ -698,11 +773,11 @@ export class HaSceneEditor extends SubscribeMixin( if (entityId in this._storedStates) { return; } - const state = this._getCurrentState(entityId); - if (!state) { + const entityState = this._getCurrentState(entityId); + if (!entityState) { return; } - this._storedStates[entityId] = state; + this._storedStates[entityId] = entityState; } private _getCurrentState(entityId: string) { @@ -721,7 +796,7 @@ export class HaSceneEditor extends SubscribeMixin( this._dirty = false; if (!this.sceneId) { - navigate(this, `/config/scene/edit/${id}`, true); + navigate(`/config/scene/edit/${id}`, { replace: true }); } } catch (err) { this._errors = err.body.message || err.message; @@ -736,7 +811,7 @@ export class HaSceneEditor extends SubscribeMixin( this._saveScene(); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/script/ha-config-script.ts b/src/panels/config/script/ha-config-script.ts index 6efe063b55..f1c11a2b84 100644 --- a/src/panels/config/script/ha-config-script.ts +++ b/src/panels/config/script/ha-config-script.ts @@ -1,5 +1,6 @@ import { HassEntities } from "home-assistant-js-websocket"; -import { customElement, property, PropertyValues } from "lit-element"; +import { PropertyValues } from "lit"; +import { customElement, property } from "lit/decorators"; import memoizeOne from "memoize-one"; import { computeStateDomain } from "../../../common/entity/compute_state_domain"; import { debounce } from "../../../common/util/debounce"; diff --git a/src/panels/config/script/ha-script-editor.ts b/src/panels/config/script/ha-script-editor.ts index e59a8b7429..dc7abce376 100644 --- a/src/panels/config/script/ha-script-editor.ts +++ b/src/panels/config/script/ha-script-editor.ts @@ -13,16 +13,14 @@ import "@polymer/paper-dropdown-menu/paper-dropdown-menu-light"; import { PaperListboxElement } from "@polymer/paper-listbox"; import { css, - CSSResult, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, - query, TemplateResult, -} from "lit-element"; -import { classMap } from "lit-html/directives/class-map"; +} from "lit"; +import { property, state, query } from "lit/decorators"; +import { classMap } from "lit/directives/class-map"; import { computeObjectId } from "../../../common/entity/compute_object_id"; import { navigate } from "../../../common/navigate"; import { slugify } from "../../../common/string/slugify"; @@ -61,7 +59,7 @@ import { configSections } from "../ha-panel-config"; export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) { @property({ attribute: false }) public hass!: HomeAssistant; - @property() public scriptEntityId!: string; + @property() public scriptEntityId: string | null = null; @property() public route!: Route; @@ -69,17 +67,17 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) { @property() public narrow!: boolean; - @internalProperty() private _config?: ScriptConfig; + @state() private _config?: ScriptConfig; - @internalProperty() private _entityId?: string; + @state() private _entityId?: string; - @internalProperty() private _idError = false; + @state() private _idError = false; - @internalProperty() private _dirty = false; + @state() private _dirty = false; - @internalProperty() private _errors?: string; + @state() private _errors?: string; - @internalProperty() private _mode: "gui" | "yaml" = "gui"; + @state() private _mode: "gui" | "yaml" = "gui"; @query("ha-yaml-editor", true) private _editor?: HaYamlEditor; @@ -161,12 +159,12 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) { aria-label=${this.hass.localize( "ui.panel.config.script.editor.delete_script" )} - class=${classMap({ warning: this.scriptEntityId })} + class=${classMap({ warning: Boolean(this.scriptEntityId) })} graphic="icon" > ${this.hass.localize("ui.panel.config.script.editor.delete_script")} @@ -470,7 +468,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) { private async _runScript(ev) { ev.stopPropagation(); - await triggerScript(this.hass, this.scriptEntityId); + await triggerScript(this.hass, this.scriptEntityId as string); showToast(this, { message: this.hass.localize( "ui.notification_toast.triggered", @@ -602,7 +600,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) { // Wait for dialog to complate closing await new Promise((resolve) => setTimeout(resolve, 0)); } - showScriptEditor(this, { + showScriptEditor({ ...this._config, alias: `${this._config?.alias} (${this.hass.localize( "ui.panel.config.script.picker.duplicate" @@ -620,7 +618,10 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) { } private async _delete() { - await deleteScript(this.hass, computeObjectId(this.scriptEntityId)); + await deleteScript( + this.hass, + computeObjectId(this.scriptEntityId as string) + ); history.back(); } @@ -664,7 +665,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) { this._dirty = false; if (!this.scriptEntityId) { - navigate(this, `/config/script/edit/${id}`, true); + navigate(`/config/script/edit/${id}`, { replace: true }); } }, (errors) => { @@ -681,7 +682,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) { this._saveScript(); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/script/ha-script-picker.ts b/src/panels/config/script/ha-script-picker.ts index bd38f62599..c52efb19df 100644 --- a/src/panels/config/script/ha-script-picker.ts +++ b/src/panels/config/script/ha-script-picker.ts @@ -7,16 +7,8 @@ import { mdiPlus, } from "@mdi/js"; import { HassEntity } from "home-assistant-js-websocket"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import { formatDateTime } from "../../../common/datetime/format_date_time"; import { fireEvent } from "../../../common/dom/fire_event"; @@ -50,9 +42,9 @@ class HaScriptPicker extends LitElement { @property() private _activeFilters?: string[]; - @internalProperty() private _filteredScripts?: string[] | null; + @state() private _filteredScripts?: string[] | null; - @internalProperty() private _filterValue?; + @state() private _filterValue?; private _scripts = memoizeOne( (scripts: HassEntity[], filteredScripts?: string[] | null) => { @@ -268,7 +260,7 @@ class HaScriptPicker extends LitElement { }); } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/server_control/ha-config-server-control.ts b/src/panels/config/server_control/ha-config-server-control.ts index f63cfab076..3a5c7ae56e 100644 --- a/src/panels/config/server_control/ha-config-server-control.ts +++ b/src/panels/config/server_control/ha-config-server-control.ts @@ -2,16 +2,8 @@ import "@material/mwc-button"; import "@polymer/app-layout/app-header/app-header"; import "@polymer/app-layout/app-toolbar/app-toolbar"; import "@polymer/paper-input/paper-input"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { componentsWithService } from "../../../common/config/components_with_service"; import "../../../components/buttons/ha-call-service-button"; import "../../../components/ha-card"; @@ -35,9 +27,9 @@ export class HaConfigServerControl extends LitElement { @property() public showAdvanced!: boolean; - @internalProperty() private _validating = false; + @state() private _validating = false; - @internalProperty() private _reloadableDomains: string[] = []; + @state() private _reloadableDomains: string[] = []; private _validateLog = ""; @@ -242,7 +234,7 @@ export class HaConfigServerControl extends LitElement { } } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/config/tags/dialog-tag-detail.ts b/src/panels/config/tags/dialog-tag-detail.ts index 68e9f39b0e..9d7f322336 100644 --- a/src/panels/config/tags/dialog-tag-detail.ts +++ b/src/panels/config/tags/dialog-tag-detail.ts @@ -1,20 +1,11 @@ import "@material/mwc-button"; import "@polymer/paper-input/paper-input"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../../../common/dom/fire_event"; import { createCloseHeading } from "../../../components/ha-dialog"; import "../../../components/ha-formfield"; import "../../../components/ha-switch"; -import "../../../components/map/ha-location-editor"; import { Tag, UpdateTagParams } from "../../../data/tag"; import { HassDialog } from "../../../dialogs/make-dialog-manager"; import { haStyleDialog } from "../../../resources/styles"; @@ -29,17 +20,17 @@ class DialogTagDetail implements HassDialog { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _id?: string; + @state() private _id?: string; - @internalProperty() private _name!: string; + @state() private _name!: string; - @internalProperty() private _error?: string; + @state() private _error?: string; - @internalProperty() private _params?: TagDetailDialogParams; + @state() private _params?: TagDetailDialogParams; - @internalProperty() private _submitting = false; + @state() private _submitting = false; - @internalProperty() private _qrCode?: TemplateResult; + @state() private _qrCode?: TemplateResult; public showDialog(params: TagDetailDialogParams): void { this._params = params; @@ -253,7 +244,7 @@ class DialogTagDetail this._qrCode = html``; } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyleDialog, css` diff --git a/src/panels/config/tags/ha-config-tags.ts b/src/panels/config/tags/ha-config-tags.ts index d543b5c6af..030bb53213 100644 --- a/src/panels/config/tags/ha-config-tags.ts +++ b/src/panels/config/tags/ha-config-tags.ts @@ -6,14 +6,8 @@ import { mdiPlus, mdiRobot, } from "@mdi/js"; -import { - customElement, - html, - internalProperty, - LitElement, - property, - PropertyValues, -} from "lit-element"; +import { html, LitElement, PropertyValues } from "lit"; +import { customElement, property, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import { DataTableColumnContainer } from "../../../components/data-table/ha-data-table"; import "../../../components/ha-card"; @@ -57,9 +51,9 @@ export class HaConfigTags extends SubscribeMixin(LitElement) { @property() public route!: Route; - @internalProperty() private _tags: Tag[] = []; + @state() private _tags: Tag[] = []; - @internalProperty() private _canWriteTags = false; + @state() private _canWriteTags = false; private _columns = memoizeOne( ( @@ -266,7 +260,7 @@ export class HaConfigTags extends SubscribeMixin(LitElement) { ), trigger: [{ platform: "tag", tag_id: tag.id } as TagTrigger], }; - showAutomationEditor(this, data); + showAutomationEditor(data); } private _addTag() { diff --git a/src/panels/config/tags/tag-image.ts b/src/panels/config/tags/tag-image.ts index 7392b935cb..ce5a5826c4 100644 --- a/src/panels/config/tags/tag-image.ts +++ b/src/panels/config/tags/tag-image.ts @@ -1,12 +1,6 @@ import { mdiNfcVariant } from "@mdi/js"; -import { - css, - CSSResult, - customElement, - html, - LitElement, - property, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; import "../../../components/ha-svg-icon"; import { TagRowData } from "./ha-config-tags"; @@ -52,7 +46,7 @@ export class HaTagImage extends LitElement {
`; } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` .image { height: 100%; diff --git a/src/panels/config/users/dialog-add-user.ts b/src/panels/config/users/dialog-add-user.ts index b18bfc7a7e..ed9f6520f0 100644 --- a/src/panels/config/users/dialog-add-user.ts +++ b/src/panels/config/users/dialog-add-user.ts @@ -2,15 +2,13 @@ import "@material/mwc-button"; import "@polymer/paper-input/paper-input"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, TemplateResult, -} from "lit-element"; +} from "lit"; +import { customElement, property, state } from "lit/decorators"; import { computeRTLDirection } from "../../../common/util/compute_rtl"; import "../../../components/ha-circular-progress"; import "../../../components/ha-dialog"; @@ -33,24 +31,24 @@ import { AddUserDialogParams } from "./show-dialog-add-user"; export class DialogAddUser extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; - @internalProperty() private _loading = false; + @state() private _loading = false; // Error message when can't talk to server etc - @internalProperty() private _error?: string; + @state() private _error?: string; - @internalProperty() private _params?: AddUserDialogParams; + @state() private _params?: AddUserDialogParams; - @internalProperty() private _name?: string; + @state() private _name?: string; - @internalProperty() private _username?: string; + @state() private _username?: string; - @internalProperty() private _password?: string; + @state() private _password?: string; - @internalProperty() private _passwordConfirm?: string; + @state() private _passwordConfirm?: string; - @internalProperty() private _isAdmin?: boolean; + @state() private _isAdmin?: boolean; - @internalProperty() private _allowChangeName = true; + @state() private _allowChangeName = true; public showDialog(params: AddUserDialogParams) { this._params = params; @@ -86,7 +84,7 @@ export class DialogAddUser extends LitElement { return html` { this._params = params; @@ -63,7 +55,7 @@ class DialogUserDetail extends LitElement { return html` [Number(lat), Number(lng)]); private _locationChanged(ev) { [this._latitude, this._longitude] = ev.currentTarget.location; @@ -283,7 +275,7 @@ class DialogZoneDetail extends LitElement { } } - static get styles(): CSSResult[] { + static get styles(): CSSResultGroup { return [ haStyleDialog, css` diff --git a/src/panels/config/zone/ha-config-zone.ts b/src/panels/config/zone/ha-config-zone.ts index 0e1972f69e..e5f6883d20 100644 --- a/src/panels/config/zone/ha-config-zone.ts +++ b/src/panels/config/zone/ha-config-zone.ts @@ -1,4 +1,3 @@ -import "../../../components/ha-fab"; import "@material/mwc-icon-button"; import { mdiPencil, mdiPencilOff, mdiPlus } from "@mdi/js"; import "@polymer/paper-item/paper-icon-item"; @@ -8,22 +7,20 @@ import "@polymer/paper-tooltip/paper-tooltip"; import { HassEntity, UnsubscribeFunc } from "home-assistant-js-websocket"; import { css, - CSSResult, - customElement, + CSSResultGroup, html, - internalProperty, LitElement, - property, PropertyValues, - query, TemplateResult, -} from "lit-element"; -import { ifDefined } from "lit-html/directives/if-defined"; +} from "lit"; +import { customElement, property, state, query } from "lit/decorators"; +import { ifDefined } from "lit/directives/if-defined"; import memoizeOne from "memoize-one"; import { computeStateDomain } from "../../../common/entity/compute_state_domain"; import { navigate } from "../../../common/navigate"; import { compare } from "../../../common/string/compare"; import "../../../components/ha-card"; +import "../../../components/ha-fab"; import "../../../components/ha-svg-icon"; import "../../../components/map/ha-locations-editor"; import type { @@ -62,13 +59,13 @@ export class HaConfigZone extends SubscribeMixin(LitElement) { @property() public route!: Route; - @internalProperty() private _storageItems?: Zone[]; + @state() private _storageItems?: Zone[]; - @internalProperty() private _stateItems?: HassEntity[]; + @state() private _stateItems?: HassEntity[]; - @internalProperty() private _activeEntry = ""; + @state() private _activeEntry = ""; - @internalProperty() private _canEditCore = false; + @state() private _canEditCore = false; @query("ha-locations-editor") private _map?: HaLocationsEditor; @@ -76,22 +73,25 @@ export class HaConfigZone extends SubscribeMixin(LitElement) { private _getZones = memoizeOne( (storageItems: Zone[], stateItems: HassEntity[]): MarkerLocation[] => { - const stateLocations: MarkerLocation[] = stateItems.map((state) => ({ - id: state.entity_id, - icon: state.attributes.icon, - name: state.attributes.friendly_name || state.entity_id, - latitude: state.attributes.latitude, - longitude: state.attributes.longitude, - radius: state.attributes.radius, - radius_color: - state.entity_id === "zone.home" - ? homeRadiusColor - : state.attributes.passive - ? passiveRadiusColor - : defaultRadiusColor, - location_editable: state.entity_id === "zone.home" && this._canEditCore, - radius_editable: false, - })); + const stateLocations: MarkerLocation[] = stateItems.map( + (entityState) => ({ + id: entityState.entity_id, + icon: entityState.attributes.icon, + name: entityState.attributes.friendly_name || entityState.entity_id, + latitude: entityState.attributes.latitude, + longitude: entityState.attributes.longitude, + radius: entityState.attributes.radius, + radius_color: + entityState.entity_id === "zone.home" + ? homeRadiusColor + : entityState.attributes.passive + ? passiveRadiusColor + : defaultRadiusColor, + location_editable: + entityState.entity_id === "zone.home" && this._canEditCore, + radius_editable: false, + }) + ); const storageLocations: MarkerLocation[] = storageItems.map((zone) => ({ ...zone, radius_color: zone.passive ? passiveRadiusColor : defaultRadiusColor, @@ -161,22 +161,26 @@ export class HaConfigZone extends SubscribeMixin(LitElement) { ` )} ${this._stateItems.map( - (state) => html` + (stateObject) => html` - + - ${state.attributes.friendly_name || state.entity_id} + ${stateObject.attributes.friendly_name || + stateObject.entity_id}
- ${state.entity_id === "zone.home" + ${stateObject.entity_id === "zone.home" ? this.hass.localize( `ui.panel.config.zone.${ this.narrow @@ -265,7 +269,7 @@ export class HaConfigZone extends SubscribeMixin(LitElement) { ["storage", "default"].includes(this.hass.config.config_source); this._fetchData(); if (this.route.path === "/new") { - navigate(this, "/config/zone", true); + navigate("/config/zone", { replace: true }); this._createZone(); } } @@ -395,7 +399,7 @@ export class HaConfigZone extends SubscribeMixin(LitElement) { ) { return; } - navigate(this, "/config/core"); + navigate("/config/core"); } private async _createEntry(values: ZoneMutableParams) { @@ -462,7 +466,7 @@ export class HaConfigZone extends SubscribeMixin(LitElement) { }); } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` hass-loading-screen { --app-header-background-color: var(--sidebar-background-color); diff --git a/src/panels/custom/ha-panel-custom.ts b/src/panels/custom/ha-panel-custom.ts index e000a4c7dd..907bc9c655 100644 --- a/src/panels/custom/ha-panel-custom.ts +++ b/src/panels/custom/ha-panel-custom.ts @@ -1,5 +1,6 @@ -import { property, PropertyValues, UpdatingElement } from "lit-element"; -import { navigate } from "../../common/navigate"; +import { PropertyValues, ReactiveElement } from "lit"; +import { property } from "lit/decorators"; +import { navigate, NavigateOptions } from "../../common/navigate"; import { CustomPanelInfo } from "../../data/panel_custom"; import { HomeAssistant, Route } from "../../types"; import { createCustomPanelElement } from "../../util/custom-panel/create-custom-panel-element"; @@ -15,7 +16,7 @@ declare global { } } -export class HaPanelCustom extends UpdatingElement { +export class HaPanelCustom extends ReactiveElement { @property({ attribute: false }) public hass!: HomeAssistant; @property() public narrow!: boolean; @@ -26,11 +27,15 @@ export class HaPanelCustom extends UpdatingElement { private _setProperties?: (props: Record) => void | undefined; + protected createRenderRoot() { + return this; + } + // Since navigate fires events on `window`, we need to expose this as a function // to allow custom panels to forward their location changes to the main window // instead of their iframe window. - public navigate = (path: string, replace?: boolean) => - navigate(this, path, replace); + public navigate = (path: string, options?: NavigateOptions) => + navigate(path, options); public registerIframe(initialize, setProperties) { initialize(this.panel, { diff --git a/src/panels/developer-tools/developer-tools-router.ts b/src/panels/developer-tools/developer-tools-router.ts index 903948a168..efc0c01ddc 100644 --- a/src/panels/developer-tools/developer-tools-router.ts +++ b/src/panels/developer-tools/developer-tools-router.ts @@ -1,5 +1,5 @@ import { PolymerElement } from "@polymer/polymer"; -import { customElement, property } from "lit-element"; +import { customElement, property } from "lit/decorators"; import { HassRouterPage, RouterOptions } from "../../layouts/hass-router-page"; import { HomeAssistant } from "../../types"; diff --git a/src/panels/developer-tools/event/developer-tools-event.js b/src/panels/developer-tools/event/developer-tools-event.js index 6c508799cc..962676645f 100644 --- a/src/panels/developer-tools/event/developer-tools-event.js +++ b/src/panels/developer-tools/event/developer-tools-event.js @@ -4,7 +4,7 @@ import "@polymer/paper-input/paper-input"; import { html } from "@polymer/polymer/lib/utils/html-tag"; /* eslint-plugin-disable lit */ import { PolymerElement } from "@polymer/polymer/polymer-element"; -import { safeLoad } from "js-yaml"; +import { load } from "js-yaml"; import "../../../components/ha-code-editor"; import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box"; import { EventsMixin } from "../../../mixins/events-mixin"; @@ -151,7 +151,7 @@ class HaPanelDevEvent extends EventsMixin(LocalizeMixin(PolymerElement)) { _computeParsedEventData(eventData) { try { - return eventData.trim() ? safeLoad(eventData) : {}; + return eventData.trim() ? load(eventData) : {}; } catch (err) { return ERROR_SENTINEL; } diff --git a/src/panels/developer-tools/event/event-subscribe-card.ts b/src/panels/developer-tools/event/event-subscribe-card.ts index 58a8fc27a7..cfa8a67be6 100644 --- a/src/panels/developer-tools/event/event-subscribe-card.ts +++ b/src/panels/developer-tools/event/event-subscribe-card.ts @@ -1,16 +1,8 @@ import "@material/mwc-button"; import "@polymer/paper-input/paper-input"; import { HassEvent } from "home-assistant-js-websocket"; -import { - css, - CSSResult, - customElement, - html, - internalProperty, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property, state } from "lit/decorators"; import { formatTime } from "../../../common/datetime/format_time"; import "../../../components/ha-card"; import { PolymerChangedEvent } from "../../../polymer-types"; @@ -20,11 +12,11 @@ import { HomeAssistant } from "../../../types"; class EventSubscribeCard extends LitElement { @property({ attribute: false }) public hass?: HomeAssistant; - @internalProperty() private _eventType = ""; + @state() private _eventType = ""; - @internalProperty() private _subscribed?: () => void; + @state() private _subscribed?: () => void; - @internalProperty() private _events: Array<{ + @state() private _events: Array<{ id: number; event: HassEvent; }> = []; @@ -118,7 +110,7 @@ class EventSubscribeCard extends LitElement { } } - static get styles(): CSSResult { + static get styles(): CSSResultGroup { return css` form { display: block; diff --git a/src/panels/developer-tools/ha-panel-developer-tools.ts b/src/panels/developer-tools/ha-panel-developer-tools.ts index 3ad8fe9887..3d05125563 100644 --- a/src/panels/developer-tools/ha-panel-developer-tools.ts +++ b/src/panels/developer-tools/ha-panel-developer-tools.ts @@ -1,15 +1,8 @@ import "@polymer/app-layout/app-header/app-header"; import "@polymer/app-layout/app-toolbar/app-toolbar"; import "@polymer/paper-tabs/paper-tab"; -import { - css, - CSSResultArray, - customElement, - html, - LitElement, - property, - TemplateResult, -} from "lit-element"; +import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; +import { customElement, property } from "lit/decorators"; import { navigate } from "../../common/navigate"; import "../../components/ha-icon-button"; import "../../components/ha-menu-button"; @@ -84,7 +77,7 @@ class PanelDeveloperTools extends LitElement { private handlePageSelected(ev) { const newPage = ev.detail.item.getAttribute("page-name"); if (newPage !== this._page) { - navigate(this, `/developer-tools/${newPage}`); + navigate(`/developer-tools/${newPage}`); } else { scrollTo(0, 0); } @@ -94,7 +87,7 @@ class PanelDeveloperTools extends LitElement { return this.route.path.substr(1); } - static get styles(): CSSResultArray { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/developer-tools/service/developer-tools-service.ts b/src/panels/developer-tools/service/developer-tools-service.ts index a7b3451a14..8e66d99a87 100644 --- a/src/panels/developer-tools/service/developer-tools-service.ts +++ b/src/panels/developer-tools/service/developer-tools-service.ts @@ -1,15 +1,8 @@ import { mdiHelpCircle } from "@mdi/js"; import { ERR_CONNECTION_LOST } from "home-assistant-js-websocket"; -import { safeLoad } from "js-yaml"; -import { - css, - CSSResultArray, - html, - internalProperty, - LitElement, - property, - query, -} from "lit-element"; +import { load } from "js-yaml"; +import { css, CSSResultGroup, html, LitElement } from "lit"; +import { property, query, state } from "lit/decorators"; import memoizeOne from "memoize-one"; import { LocalStorage } from "../../../common/decorators/local-storage"; import { computeDomain } from "../../../common/entity/compute_domain"; @@ -42,7 +35,7 @@ class HaPanelDevService extends LitElement { @property({ type: Boolean }) public narrow!: boolean; - @internalProperty() private _uiAvailable = true; + @state() private _uiAvailable = true; @LocalStorage("panel-dev-service-state-service-data", true) private _serviceData?: ServiceAction = { service: "", target: {}, data: {} }; @@ -368,9 +361,9 @@ class HaPanelDevService extends LitElement { const example = {}; fields.forEach((field) => { if (field.example) { - let value = ""; + let value: any = ""; try { - value = safeLoad(field.example); + value = load(field.example); } catch (err) { value = field.example; } @@ -381,7 +374,7 @@ class HaPanelDevService extends LitElement { this._yamlEditor?.setValue(this._serviceData); } - static get styles(): CSSResultArray { + static get styles(): CSSResultGroup { return [ haStyle, css` diff --git a/src/panels/developer-tools/state/developer-tools-state.js b/src/panels/developer-tools/state/developer-tools-state.js index 64f85edfae..3389d29ae6 100644 --- a/src/panels/developer-tools/state/developer-tools-state.js +++ b/src/panels/developer-tools/state/developer-tools-state.js @@ -1,16 +1,19 @@ import "@material/mwc-button"; import { - mdiInformationOutline, mdiClipboardTextMultipleOutline, + mdiInformationOutline, + mdiRefresh, } from "@mdi/js"; import "@polymer/paper-checkbox/paper-checkbox"; import "@polymer/paper-input/paper-input"; import { html } from "@polymer/polymer/lib/utils/html-tag"; /* eslint-plugin-disable lit */ import { PolymerElement } from "@polymer/polymer/polymer-element"; -import { safeDump, safeLoad } from "js-yaml"; +import { dump, load } from "js-yaml"; import { formatDateTimeWithSeconds } from "../../../common/datetime/format_date_time"; +import { isPatternInWord } from "../../../common/string/filter/filter"; import { computeRTL } from "../../../common/util/compute_rtl"; +import { copyToClipboard } from "../../../common/util/copy-clipboard"; import "../../../components/entity/ha-entity-picker"; import "../../../components/ha-code-editor"; import "../../../components/ha-svg-icon"; @@ -18,7 +21,6 @@ import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box"; import { EventsMixin } from "../../../mixins/events-mixin"; import LocalizeMixin from "../../../mixins/localize-mixin"; import "../../../styles/polymer-ha-style"; -import { copyToClipboard } from "../../../common/util/copy-clipboard"; const ERROR_SENTINEL = {}; /* @@ -46,8 +48,10 @@ class HaPanelDevState extends EventsMixin(LocalizeMixin(PolymerElement)) { padding: 0 16px; } - mwc-button { + .button-row { + display: flex; margin-top: 8px; + align-items: center; } .table-wrapper { @@ -88,6 +92,12 @@ class HaPanelDevState extends EventsMixin(LocalizeMixin(PolymerElement)) { --mdc-icon-size: 20px; padding: 4px; cursor: pointer; + flex-shrink: 0; + margin-right: 8px; + } + .entities td:nth-child(1) { + min-width: 300px; + width: 30%; } .entities td:nth-child(3) { white-space: pre-wrap; @@ -98,6 +108,15 @@ class HaPanelDevState extends EventsMixin(LocalizeMixin(PolymerElement)) { color: var(--primary-color); } + .entities .id-name-container { + display: flex; + flex-direction: column; + } + .entities .id-name-row { + display: flex; + align-items: center; + } + :host([narrow]) .state-wrapper { flex-direction: column; } @@ -139,9 +158,19 @@ class HaPanelDevState extends EventsMixin(LocalizeMixin(PolymerElement)) { error="[[!validJSON]]" on-value-changed="_yamlChanged" > - [[localize('ui.panel.developer-tools.tabs.states.set_state')]] +
+ [[localize('ui.panel.developer-tools.tabs.states.set_state')]] + +