mirror of
https://github.com/home-assistant/frontend.git
synced 2025-08-02 05:57:54 +00:00
Merge branch 'streaming_history_hui-graph-header-footer_maps' into remove_legacy_history_calls
This commit is contained in:
commit
a77589922c
4
.gitignore
vendored
4
.gitignore
vendored
@ -8,7 +8,7 @@ dist/
|
|||||||
/translations/
|
/translations/
|
||||||
|
|
||||||
# yarn
|
# yarn
|
||||||
.yarn/**
|
.yarn/*
|
||||||
!.yarn/patches
|
!.yarn/patches
|
||||||
!.yarn/releases
|
!.yarn/releases
|
||||||
!.yarn/plugins
|
!.yarn/plugins
|
||||||
@ -31,7 +31,7 @@ pip-selfcheck.json
|
|||||||
.venv
|
.venv
|
||||||
|
|
||||||
# vscode
|
# vscode
|
||||||
.vscode/**
|
.vscode/*
|
||||||
!.vscode/extensions.json
|
!.vscode/extensions.json
|
||||||
!.vscode/launch.json
|
!.vscode/launch.json
|
||||||
!.vscode/tasks.json
|
!.vscode/tasks.json
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
diff --git a/mwc-icon-button-base.js b/mwc-icon-button-base.js
|
|
||||||
index 45cdaab93ccc0a6daaaaabc01266dcdc32e46bfd..b3ea5b541597308d85f86ce6c23fd00785fda835 100644
|
|
||||||
--- a/mwc-icon-button-base.js
|
|
||||||
+++ b/mwc-icon-button-base.js
|
|
||||||
@@ -63,7 +63,6 @@ export class IconButtonBase extends LitElement {
|
|
||||||
@touchend="${this.handleRippleDeactivate}"
|
|
||||||
@touchcancel="${this.handleRippleDeactivate}"
|
|
||||||
>${this.renderRipple()}
|
|
||||||
- <i class="material-icons">${this.icon}</i>
|
|
||||||
<span
|
|
||||||
><slot></slot
|
|
||||||
></span>
|
|
@ -1,36 +1,40 @@
|
|||||||
const del = require("del");
|
const del = import("del");
|
||||||
const gulp = require("gulp");
|
const gulp = require("gulp");
|
||||||
const paths = require("../paths");
|
const paths = require("../paths");
|
||||||
require("./translations");
|
require("./translations");
|
||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"clean",
|
"clean",
|
||||||
gulp.parallel("clean-translations", () =>
|
gulp.parallel("clean-translations", async () =>
|
||||||
del([paths.app_output_root, paths.build_dir])
|
(await del).deleteSync([paths.app_output_root, paths.build_dir])
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"clean-demo",
|
"clean-demo",
|
||||||
gulp.parallel("clean-translations", () =>
|
gulp.parallel("clean-translations", async () =>
|
||||||
del([paths.demo_output_root, paths.build_dir])
|
(await del).deleteSync([paths.demo_output_root, paths.build_dir])
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"clean-cast",
|
"clean-cast",
|
||||||
gulp.parallel("clean-translations", () =>
|
gulp.parallel("clean-translations", async () =>
|
||||||
del([paths.cast_output_root, paths.build_dir])
|
(await del).deleteSync([paths.cast_output_root, paths.build_dir])
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
gulp.task("clean-hassio", () =>
|
gulp.task("clean-hassio", async () =>
|
||||||
del([paths.hassio_output_root, paths.build_dir])
|
(await del).deleteSync([paths.hassio_output_root, paths.build_dir])
|
||||||
);
|
);
|
||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"clean-gallery",
|
"clean-gallery",
|
||||||
gulp.parallel("clean-translations", () =>
|
gulp.parallel("clean-translations", async () =>
|
||||||
del([paths.gallery_output_root, paths.gallery_build, paths.build_dir])
|
(await del).deleteSync([
|
||||||
|
paths.gallery_output_root,
|
||||||
|
paths.gallery_build,
|
||||||
|
paths.build_dir,
|
||||||
|
])
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
// Task to download the latest Lokalise translations from the nightly workflow artifacts
|
// Task to download the latest Lokalise translations from the nightly workflow artifacts
|
||||||
|
|
||||||
|
const del = import("del");
|
||||||
const fs = require("fs/promises");
|
const fs = require("fs/promises");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const process = require("process");
|
const process = require("process");
|
||||||
const del = require("del");
|
|
||||||
const gulp = require("gulp");
|
const gulp = require("gulp");
|
||||||
const jszip = require("jszip");
|
const jszip = require("jszip");
|
||||||
const tar = require("tar");
|
const tar = require("tar");
|
||||||
@ -17,8 +17,8 @@ const WORKFLOW_NAME = "nightly.yaml";
|
|||||||
const ARTIFACT_NAME = "translations";
|
const ARTIFACT_NAME = "translations";
|
||||||
const CLIENT_ID = "Iv1.3914e28cb27834d1";
|
const CLIENT_ID = "Iv1.3914e28cb27834d1";
|
||||||
const EXTRACT_DIR = "translations";
|
const EXTRACT_DIR = "translations";
|
||||||
const TOKEN_FILE = path.join(EXTRACT_DIR, "token.json");
|
const TOKEN_FILE = path.posix.join(EXTRACT_DIR, "token.json");
|
||||||
const ARTIFACT_FILE = path.join(EXTRACT_DIR, "artifact.json");
|
const ARTIFACT_FILE = path.posix.join(EXTRACT_DIR, "artifact.json");
|
||||||
|
|
||||||
let allowTokenSetup = false;
|
let allowTokenSetup = false;
|
||||||
gulp.task("allow-setup-fetch-nightly-translations", (done) => {
|
gulp.task("allow-setup-fetch-nightly-translations", (done) => {
|
||||||
@ -137,7 +137,11 @@ gulp.task("fetch-nightly-translations", async function () {
|
|||||||
|
|
||||||
// Remove the current translations
|
// Remove the current translations
|
||||||
const deleteCurrent = Promise.all(writings).then(
|
const deleteCurrent = Promise.all(writings).then(
|
||||||
del([`${EXTRACT_DIR}/*`, `!${ARTIFACT_FILE}`, `!${TOKEN_FILE}`])
|
(await del).deleteAsync([
|
||||||
|
`${EXTRACT_DIR}/*`,
|
||||||
|
`!${ARTIFACT_FILE}`,
|
||||||
|
`!${TOKEN_FILE}`,
|
||||||
|
])
|
||||||
);
|
);
|
||||||
|
|
||||||
// Get the download URL and follow the redirect to download (stored as ArrayBuffer)
|
// Get the download URL and follow the redirect to download (stored as ArrayBuffer)
|
@ -1,4 +1,4 @@
|
|||||||
const del = require("del");
|
const del = import("del");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const gulp = require("gulp");
|
const gulp = require("gulp");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
@ -6,7 +6,7 @@ const paths = require("../paths");
|
|||||||
|
|
||||||
const outDir = "build/locale-data";
|
const outDir = "build/locale-data";
|
||||||
|
|
||||||
gulp.task("clean-locale-data", () => del([outDir]));
|
gulp.task("clean-locale-data", async () => (await del).deleteSync([outDir]));
|
||||||
|
|
||||||
gulp.task("ensure-locale-data-build-dir", (done) => {
|
gulp.task("ensure-locale-data-build-dir", (done) => {
|
||||||
if (!fs.existsSync(outDir)) {
|
if (!fs.existsSync(outDir)) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
const del = import("del");
|
||||||
const crypto = require("crypto");
|
const crypto = require("crypto");
|
||||||
const del = require("del");
|
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const source = require("vinyl-source-stream");
|
const source = require("vinyl-source-stream");
|
||||||
const vinylBuffer = require("vinyl-buffer");
|
const vinylBuffer = require("vinyl-buffer");
|
||||||
@ -13,7 +13,7 @@ const { mapFiles } = require("../util");
|
|||||||
const env = require("../env");
|
const env = require("../env");
|
||||||
const paths = require("../paths");
|
const paths = require("../paths");
|
||||||
|
|
||||||
require("./fetch-nightly_translations");
|
require("./fetch-nightly-translations");
|
||||||
|
|
||||||
const inFrontendDir = "translations/frontend";
|
const inFrontendDir = "translations/frontend";
|
||||||
const inBackendDir = "translations/backend";
|
const inBackendDir = "translations/backend";
|
||||||
@ -120,7 +120,7 @@ function lokaliseTransform(data, original, file) {
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
gulp.task("clean-translations", () => del([workDir]));
|
gulp.task("clean-translations", async () => (await del).deleteSync([workDir]));
|
||||||
|
|
||||||
gulp.task("ensure-translations-build-dir", (done) => {
|
gulp.task("ensure-translations-build-dir", (done) => {
|
||||||
if (!fs.existsSync(workDir)) {
|
if (!fs.existsSync(workDir)) {
|
||||||
|
72
package.json
72
package.json
@ -47,30 +47,30 @@
|
|||||||
"@lezer/highlight": "^1.1.3",
|
"@lezer/highlight": "^1.1.3",
|
||||||
"@lit-labs/motion": "^1.0.2",
|
"@lit-labs/motion": "^1.0.2",
|
||||||
"@lit-labs/virtualizer": "patch:@lit-labs/virtualizer@0.7.0-pre.2#./.yarn/patches/@lit-labs/virtualizer/event-target-shim.patch",
|
"@lit-labs/virtualizer": "patch:@lit-labs/virtualizer@0.7.0-pre.2#./.yarn/patches/@lit-labs/virtualizer/event-target-shim.patch",
|
||||||
"@material/chips": "14.0.0-canary.261f2db59.0",
|
"@material/chips": "=14.0.0-canary.53b3cad2f.0",
|
||||||
"@material/data-table": "14.0.0-canary.261f2db59.0",
|
"@material/data-table": "=14.0.0-canary.53b3cad2f.0",
|
||||||
"@material/mwc-button": "0.25.3",
|
"@material/mwc-button": "^0.27.0",
|
||||||
"@material/mwc-checkbox": "0.25.3",
|
"@material/mwc-checkbox": "^0.27.0",
|
||||||
"@material/mwc-circular-progress": "0.25.3",
|
"@material/mwc-circular-progress": "^0.27.0",
|
||||||
"@material/mwc-dialog": "0.25.3",
|
"@material/mwc-dialog": "^0.27.0",
|
||||||
"@material/mwc-drawer": "^0.25.3",
|
"@material/mwc-drawer": "^0.27.0",
|
||||||
"@material/mwc-fab": "0.25.3",
|
"@material/mwc-fab": "^0.27.0",
|
||||||
"@material/mwc-formfield": "0.25.3",
|
"@material/mwc-formfield": "^0.27.0",
|
||||||
"@material/mwc-icon-button": "patch:@material/mwc-icon-button@0.25.3#./.yarn/patches/@material/mwc-icon-button/remove-icon.patch",
|
"@material/mwc-icon-button": "^0.27.0",
|
||||||
"@material/mwc-linear-progress": "0.25.3",
|
"@material/mwc-linear-progress": "^0.27.0",
|
||||||
"@material/mwc-list": "^0.25.3",
|
"@material/mwc-list": "^0.27.0",
|
||||||
"@material/mwc-menu": "0.25.3",
|
"@material/mwc-menu": "^0.27.0",
|
||||||
"@material/mwc-radio": "0.25.3",
|
"@material/mwc-radio": "^0.27.0",
|
||||||
"@material/mwc-ripple": "0.25.3",
|
"@material/mwc-ripple": "^0.27.0",
|
||||||
"@material/mwc-select": "0.25.3",
|
"@material/mwc-select": "^0.27.0",
|
||||||
"@material/mwc-slider": "0.25.3",
|
"@material/mwc-slider": "^0.27.0",
|
||||||
"@material/mwc-switch": "0.25.3",
|
"@material/mwc-switch": "^0.27.0",
|
||||||
"@material/mwc-tab": "0.25.3",
|
"@material/mwc-tab": "^0.27.0",
|
||||||
"@material/mwc-tab-bar": "0.25.3",
|
"@material/mwc-tab-bar": "^0.27.0",
|
||||||
"@material/mwc-textarea": "^0.25.3",
|
"@material/mwc-textarea": "^0.27.0",
|
||||||
"@material/mwc-textfield": "0.25.3",
|
"@material/mwc-textfield": "^0.27.0",
|
||||||
"@material/mwc-top-app-bar-fixed": "^0.25.3",
|
"@material/mwc-top-app-bar-fixed": "^0.27.0",
|
||||||
"@material/top-app-bar": "14.0.0-canary.261f2db59.0",
|
"@material/top-app-bar": "=14.0.0-canary.53b3cad2f.0",
|
||||||
"@mdi/js": "7.1.96",
|
"@mdi/js": "7.1.96",
|
||||||
"@mdi/svg": "7.1.96",
|
"@mdi/svg": "7.1.96",
|
||||||
"@polymer/app-layout": "^3.1.0",
|
"@polymer/app-layout": "^3.1.0",
|
||||||
@ -108,7 +108,7 @@
|
|||||||
"fuse.js": "^6.0.0",
|
"fuse.js": "^6.0.0",
|
||||||
"google-timezones-json": "^1.0.2",
|
"google-timezones-json": "^1.0.2",
|
||||||
"hammerjs": "^2.0.8",
|
"hammerjs": "^2.0.8",
|
||||||
"hls.js": "^1.2.5",
|
"hls.js": "^1.3.1",
|
||||||
"home-assistant-js-websocket": "^8.0.1",
|
"home-assistant-js-websocket": "^8.0.1",
|
||||||
"idb-keyval": "^5.1.3",
|
"idb-keyval": "^5.1.3",
|
||||||
"intl-messageformat": "^9.9.1",
|
"intl-messageformat": "^9.9.1",
|
||||||
@ -117,7 +117,7 @@
|
|||||||
"leaflet-draw": "^1.0.4",
|
"leaflet-draw": "^1.0.4",
|
||||||
"lit": "^2.1.2",
|
"lit": "^2.1.2",
|
||||||
"marked": "^4.0.12",
|
"marked": "^4.0.12",
|
||||||
"memoize-one": "^5.2.1",
|
"memoize-one": "^6.0.0",
|
||||||
"node-vibrant": "3.2.1-alpha.1",
|
"node-vibrant": "3.2.1-alpha.1",
|
||||||
"proxy-polyfill": "^0.3.2",
|
"proxy-polyfill": "^0.3.2",
|
||||||
"punycode": "^2.1.1",
|
"punycode": "^2.1.1",
|
||||||
@ -143,13 +143,13 @@
|
|||||||
"workbox-precaching": "^6.5.4",
|
"workbox-precaching": "^6.5.4",
|
||||||
"workbox-routing": "^6.5.4",
|
"workbox-routing": "^6.5.4",
|
||||||
"workbox-strategies": "^6.5.4",
|
"workbox-strategies": "^6.5.4",
|
||||||
"xss": "^1.0.9"
|
"xss": "^1.0.14"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.20.2",
|
"@babel/core": "^7.20.2",
|
||||||
"@babel/plugin-external-helpers": "^7.18.6",
|
"@babel/plugin-external-helpers": "^7.18.6",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
||||||
"@babel/plugin-proposal-decorators": "^7.20.2",
|
"@babel/plugin-proposal-decorators": "^7.20.7",
|
||||||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6",
|
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6",
|
||||||
"@babel/plugin-proposal-object-rest-spread": "^7.20.2",
|
"@babel/plugin-proposal-object-rest-spread": "^7.20.2",
|
||||||
"@babel/plugin-proposal-optional-chaining": "^7.18.9",
|
"@babel/plugin-proposal-optional-chaining": "^7.18.9",
|
||||||
@ -169,7 +169,7 @@
|
|||||||
"@rollup/plugin-replace": "^2.3.2",
|
"@rollup/plugin-replace": "^2.3.2",
|
||||||
"@types/chromecast-caf-receiver": "5.0.12",
|
"@types/chromecast-caf-receiver": "5.0.12",
|
||||||
"@types/chromecast-caf-sender": "^1.0.3",
|
"@types/chromecast-caf-sender": "^1.0.3",
|
||||||
"@types/glob": "^7",
|
"@types/glob": "^8",
|
||||||
"@types/hammerjs": "^2.0.41",
|
"@types/hammerjs": "^2.0.41",
|
||||||
"@types/js-yaml": "^4",
|
"@types/js-yaml": "^4",
|
||||||
"@types/leaflet": "^1",
|
"@types/leaflet": "^1",
|
||||||
@ -186,7 +186,7 @@
|
|||||||
"@web/dev-server-rollup": "^0.2.11",
|
"@web/dev-server-rollup": "^0.2.11",
|
||||||
"babel-loader": "^9.1.0",
|
"babel-loader": "^9.1.0",
|
||||||
"chai": "^4.3.4",
|
"chai": "^4.3.4",
|
||||||
"del": "^4.0.0",
|
"del": "^7.0.0",
|
||||||
"eslint": "^7.32.0",
|
"eslint": "^7.32.0",
|
||||||
"eslint-config-airbnb-base": "^14.2.1",
|
"eslint-config-airbnb-base": "^14.2.1",
|
||||||
"eslint-config-airbnb-typescript": "^14.0.0",
|
"eslint-config-airbnb-typescript": "^14.0.0",
|
||||||
@ -196,10 +196,10 @@
|
|||||||
"eslint-plugin-import": "^2.24.2",
|
"eslint-plugin-import": "^2.24.2",
|
||||||
"eslint-plugin-lit": "^1.6.1",
|
"eslint-plugin-lit": "^1.6.1",
|
||||||
"eslint-plugin-unused-imports": "^1.1.5",
|
"eslint-plugin-unused-imports": "^1.1.5",
|
||||||
"eslint-plugin-wc": "^1.3.2",
|
"eslint-plugin-wc": "^1.4.0",
|
||||||
"fancy-log": "^2.0.0",
|
"fancy-log": "^2.0.0",
|
||||||
"fs-extra": "^11.1.0",
|
"fs-extra": "^11.1.0",
|
||||||
"glob": "^7.2.0",
|
"glob": "^8.1.0",
|
||||||
"gulp": "^4.0.2",
|
"gulp": "^4.0.2",
|
||||||
"gulp-flatmap": "^1.0.2",
|
"gulp-flatmap": "^1.0.2",
|
||||||
"gulp-json-transform": "^0.4.6",
|
"gulp-json-transform": "^0.4.6",
|
||||||
@ -217,17 +217,17 @@
|
|||||||
"map-stream": "^0.0.7",
|
"map-stream": "^0.0.7",
|
||||||
"merge-stream": "^1.0.1",
|
"merge-stream": "^1.0.1",
|
||||||
"mocha": "^8.4.0",
|
"mocha": "^8.4.0",
|
||||||
"object-hash": "^2.0.3",
|
"object-hash": "^3.0.0",
|
||||||
"open": "^8.4.0",
|
"open": "^8.4.0",
|
||||||
"pinst": "^3.0.0",
|
"pinst": "^3.0.0",
|
||||||
"prettier": "^2.8.1",
|
"prettier": "^2.8.3",
|
||||||
"require-dir": "^1.2.0",
|
"require-dir": "^1.2.0",
|
||||||
"rollup": "^2.8.2",
|
"rollup": "^2.8.2",
|
||||||
"rollup-plugin-string": "^3.0.0",
|
"rollup-plugin-string": "^3.0.0",
|
||||||
"rollup-plugin-terser": "^5.3.0",
|
"rollup-plugin-terser": "^5.3.0",
|
||||||
"rollup-plugin-visualizer": "^5.9.0",
|
"rollup-plugin-visualizer": "^5.9.0",
|
||||||
"serve": "^11.3.2",
|
"serve": "^11.3.2",
|
||||||
"sinon": "^11.0.0",
|
"sinon": "^15.0.1",
|
||||||
"source-map-url": "^0.4.0",
|
"source-map-url": "^0.4.0",
|
||||||
"systemjs": "^6.3.2",
|
"systemjs": "^6.3.2",
|
||||||
"tar": "^6.1.11",
|
"tar": "^6.1.11",
|
||||||
@ -238,7 +238,7 @@
|
|||||||
"vinyl-source-stream": "^2.0.0",
|
"vinyl-source-stream": "^2.0.0",
|
||||||
"webpack": "^5.55.1",
|
"webpack": "^5.55.1",
|
||||||
"webpack-cli": "^4.8.0",
|
"webpack-cli": "^4.8.0",
|
||||||
"webpack-dev-server": "^4.3.0",
|
"webpack-dev-server": "^4.11.1",
|
||||||
"webpack-manifest-plugin": "^4.0.2",
|
"webpack-manifest-plugin": "^4.0.2",
|
||||||
"webpackbar": "^5.0.0-3",
|
"webpackbar": "^5.0.0-3",
|
||||||
"workbox-build": "^6.5.4"
|
"workbox-build": "^6.5.4"
|
||||||
|
@ -39,5 +39,5 @@ export default function scrollToTarget(element, target) {
|
|||||||
);
|
);
|
||||||
requestAnimationFrame(updateFrame.bind(element));
|
requestAnimationFrame(updateFrame.bind(element));
|
||||||
}
|
}
|
||||||
}.call(element));
|
}).call(element);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import type { HassEntity } from "home-assistant-js-websocket";
|
import type { HassEntity } from "home-assistant-js-websocket";
|
||||||
import { css, html, LitElement, TemplateResult } from "lit";
|
import { css, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
import { isValidEntityId } from "../../common/entity/valid_entity_id";
|
import { isValidEntityId } from "../../common/entity/valid_entity_id";
|
||||||
import type { PolymerChangedEvent } from "../../polymer-types";
|
import type { PolymerChangedEvent } from "../../polymer-types";
|
||||||
@ -95,7 +96,10 @@ class HaEntitiesPickerLight extends LitElement {
|
|||||||
.excludeEntities=${this.excludeEntities}
|
.excludeEntities=${this.excludeEntities}
|
||||||
.includeDeviceClasses=${this.includeDeviceClasses}
|
.includeDeviceClasses=${this.includeDeviceClasses}
|
||||||
.includeUnitOfMeasurement=${this.includeUnitOfMeasurement}
|
.includeUnitOfMeasurement=${this.includeUnitOfMeasurement}
|
||||||
.entityFilter=${this._entityFilter}
|
.entityFilter=${this._getEntityFilter(
|
||||||
|
this.value,
|
||||||
|
this.entityFilter
|
||||||
|
)}
|
||||||
.value=${entityId}
|
.value=${entityId}
|
||||||
.label=${this.pickedEntityLabel}
|
.label=${this.pickedEntityLabel}
|
||||||
.disabled=${this.disabled}
|
.disabled=${this.disabled}
|
||||||
@ -114,7 +118,7 @@ class HaEntitiesPickerLight extends LitElement {
|
|||||||
.excludeEntities=${this.excludeEntities}
|
.excludeEntities=${this.excludeEntities}
|
||||||
.includeDeviceClasses=${this.includeDeviceClasses}
|
.includeDeviceClasses=${this.includeDeviceClasses}
|
||||||
.includeUnitOfMeasurement=${this.includeUnitOfMeasurement}
|
.includeUnitOfMeasurement=${this.includeUnitOfMeasurement}
|
||||||
.entityFilter=${this._entityFilter}
|
.entityFilter=${this._getEntityFilter(this.value, this.entityFilter)}
|
||||||
.label=${this.pickEntityLabel}
|
.label=${this.pickEntityLabel}
|
||||||
.helper=${this.helper}
|
.helper=${this.helper}
|
||||||
.disabled=${this.disabled}
|
.disabled=${this.disabled}
|
||||||
@ -125,11 +129,15 @@ class HaEntitiesPickerLight extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _entityFilter: HaEntityPickerEntityFilterFunc = (
|
private _getEntityFilter = memoizeOne(
|
||||||
stateObj: HassEntity
|
(
|
||||||
) =>
|
value: string[] | undefined,
|
||||||
(!this.value || !this.value.includes(stateObj.entity_id)) &&
|
entityFilter: HaEntityPickerEntityFilterFunc | undefined
|
||||||
(!this.entityFilter || this.entityFilter(stateObj));
|
): HaEntityPickerEntityFilterFunc =>
|
||||||
|
(stateObj: HassEntity) =>
|
||||||
|
(!value || !value.includes(stateObj.entity_id)) &&
|
||||||
|
(!entityFilter || entityFilter(stateObj))
|
||||||
|
);
|
||||||
|
|
||||||
private get _currentEntities() {
|
private get _currentEntities() {
|
||||||
return this.value || [];
|
return this.value || [];
|
||||||
|
@ -35,9 +35,9 @@ const TRUNCATED_DOMAINS = [
|
|||||||
"person",
|
"person",
|
||||||
] as const satisfies ReadonlyArray<keyof typeof FIXED_DOMAIN_STATES>;
|
] as const satisfies ReadonlyArray<keyof typeof FIXED_DOMAIN_STATES>;
|
||||||
|
|
||||||
type TruncatedDomain = typeof TRUNCATED_DOMAINS[number];
|
type TruncatedDomain = (typeof TRUNCATED_DOMAINS)[number];
|
||||||
type TruncatedKey = {
|
type TruncatedKey = {
|
||||||
[T in TruncatedDomain]: `${T}.${typeof FIXED_DOMAIN_STATES[T][number]}`;
|
[T in TruncatedDomain]: `${T}.${(typeof FIXED_DOMAIN_STATES)[T][number]}`;
|
||||||
}[TruncatedDomain];
|
}[TruncatedDomain];
|
||||||
|
|
||||||
const getTruncatedKey = (domainKey: string, stateKey: string) => {
|
const getTruncatedKey = (domainKey: string, stateKey: string) => {
|
||||||
|
@ -278,6 +278,11 @@ export class HaBarSlider extends LitElement {
|
|||||||
--slider-bar-border-radius: 10px;
|
--slider-bar-border-radius: 10px;
|
||||||
height: var(--slider-bar-thickness);
|
height: var(--slider-bar-thickness);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
border-radius: var(--slider-bar-border-radius);
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
:host(:focus-visible) {
|
||||||
|
box-shadow: 0 0 0 2px var(--slider-bar-color);
|
||||||
}
|
}
|
||||||
:host([vertical]) {
|
:host([vertical]) {
|
||||||
width: var(--slider-bar-thickness);
|
width: var(--slider-bar-thickness);
|
||||||
|
@ -104,6 +104,14 @@ export class HaBarSwitch extends LitElement {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
border-radius: var(--switch-bar-border-radius);
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
:host(:focus-visible) {
|
||||||
|
box-shadow: 0 0 0 2px var(--switch-bar-off-color);
|
||||||
|
}
|
||||||
|
:host([checked]:focus-visible) {
|
||||||
|
box-shadow: 0 0 0 2px var(--switch-bar-on-color);
|
||||||
}
|
}
|
||||||
.switch {
|
.switch {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
@ -164,10 +164,11 @@ export class HaSelectSelector extends LitElement {
|
|||||||
<ha-select
|
<ha-select
|
||||||
fixedMenuPosition
|
fixedMenuPosition
|
||||||
naturalMenuWidth
|
naturalMenuWidth
|
||||||
.label=${this.label}
|
.label=${this.label ?? ""}
|
||||||
.value=${this.value}
|
.value=${this.value ?? ""}
|
||||||
.helper=${this.helper}
|
.helper=${this.helper ?? ""}
|
||||||
.disabled=${this.disabled}
|
.disabled=${this.disabled}
|
||||||
|
.required=${this.required}
|
||||||
@closed=${stopPropagation}
|
@closed=${stopPropagation}
|
||||||
@selected=${this._valueChanged}
|
@selected=${this._valueChanged}
|
||||||
>
|
>
|
||||||
|
@ -8,7 +8,7 @@ import { BlueprintInput } from "./blueprint";
|
|||||||
import { DeviceCondition, DeviceTrigger } from "./device_automation";
|
import { DeviceCondition, DeviceTrigger } from "./device_automation";
|
||||||
import { Action, MODES } from "./script";
|
import { Action, MODES } from "./script";
|
||||||
|
|
||||||
export const AUTOMATION_DEFAULT_MODE: typeof MODES[number] = "single";
|
export const AUTOMATION_DEFAULT_MODE: (typeof MODES)[number] = "single";
|
||||||
export const AUTOMATION_DEFAULT_MAX = 10;
|
export const AUTOMATION_DEFAULT_MAX = 10;
|
||||||
|
|
||||||
export interface AutomationEntity extends HassEntityBase {
|
export interface AutomationEntity extends HassEntityBase {
|
||||||
@ -29,7 +29,7 @@ export interface ManualAutomationConfig {
|
|||||||
trigger: Trigger | Trigger[];
|
trigger: Trigger | Trigger[];
|
||||||
condition?: Condition | Condition[];
|
condition?: Condition | Condition[];
|
||||||
action: Action | Action[];
|
action: Action | Action[];
|
||||||
mode?: typeof MODES[number];
|
mode?: (typeof MODES)[number];
|
||||||
max?: number;
|
max?: number;
|
||||||
max_exceeded?:
|
max_exceeded?:
|
||||||
| "silent"
|
| "silent"
|
||||||
|
@ -84,3 +84,12 @@ export const setConversationOnboarding = (
|
|||||||
type: "conversation/onboarding/set",
|
type: "conversation/onboarding/set",
|
||||||
shown: value,
|
shown: value,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const prepareConversation = (
|
||||||
|
hass: HomeAssistant,
|
||||||
|
language?: string
|
||||||
|
): Promise<void> =>
|
||||||
|
hass.callWS({
|
||||||
|
type: "conversation/prepare",
|
||||||
|
language,
|
||||||
|
});
|
||||||
|
@ -671,7 +671,7 @@ export const getEnergySolarForecasts = (hass: HomeAssistant) =>
|
|||||||
});
|
});
|
||||||
|
|
||||||
const energyGasUnitClass = ["volume", "energy"] as const;
|
const energyGasUnitClass = ["volume", "energy"] as const;
|
||||||
export type EnergyGasUnitClass = typeof energyGasUnitClass[number];
|
export type EnergyGasUnitClass = (typeof energyGasUnitClass)[number];
|
||||||
|
|
||||||
export const getEnergyGasUnitClass = (
|
export const getEnergyGasUnitClass = (
|
||||||
prefs: EnergyPreferences,
|
prefs: EnergyPreferences,
|
||||||
|
@ -7,8 +7,8 @@ import { TranslationDict } from "../types";
|
|||||||
import { UNAVAILABLE_STATES } from "./entity";
|
import { UNAVAILABLE_STATES } from "./entity";
|
||||||
|
|
||||||
type HumidifierState =
|
type HumidifierState =
|
||||||
| typeof FIXED_DOMAIN_STATES.humidifier[number]
|
| (typeof FIXED_DOMAIN_STATES.humidifier)[number]
|
||||||
| typeof UNAVAILABLE_STATES[number];
|
| (typeof UNAVAILABLE_STATES)[number];
|
||||||
type HumidifierMode =
|
type HumidifierMode =
|
||||||
keyof TranslationDict["state_attributes"]["humidifier"]["mode"];
|
keyof TranslationDict["state_attributes"]["humidifier"]["mode"];
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ const statisticTypes = [
|
|||||||
"state",
|
"state",
|
||||||
"sum",
|
"sum",
|
||||||
] as const;
|
] as const;
|
||||||
export type StatisticsTypes = typeof statisticTypes[number][];
|
export type StatisticsTypes = (typeof statisticTypes)[number][];
|
||||||
|
|
||||||
export interface StatisticsValidationResults {
|
export interface StatisticsValidationResults {
|
||||||
[statisticId: string]: StatisticsValidationResult[];
|
[statisticId: string]: StatisticsValidationResult[];
|
||||||
|
@ -15,7 +15,7 @@ export interface ScheduleDay {
|
|||||||
to: string;
|
to: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type ScheduleDays = { [K in typeof weekdays[number]]?: ScheduleDay[] };
|
type ScheduleDays = { [K in (typeof weekdays)[number]]?: ScheduleDay[] };
|
||||||
|
|
||||||
export interface Schedule extends ScheduleDays {
|
export interface Schedule extends ScheduleDays {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -77,7 +77,7 @@ const activateSceneActionStruct: Describe<ServiceSceneAction> = assign(
|
|||||||
export interface ScriptEntity extends HassEntityBase {
|
export interface ScriptEntity extends HassEntityBase {
|
||||||
attributes: HassEntityAttributeBase & {
|
attributes: HassEntityAttributeBase & {
|
||||||
last_triggered: string;
|
last_triggered: string;
|
||||||
mode: typeof MODES[number];
|
mode: (typeof MODES)[number];
|
||||||
current?: number;
|
current?: number;
|
||||||
max?: number;
|
max?: number;
|
||||||
};
|
};
|
||||||
@ -89,7 +89,7 @@ export interface ManualScriptConfig {
|
|||||||
alias: string;
|
alias: string;
|
||||||
sequence: Action | Action[];
|
sequence: Action | Action[];
|
||||||
icon?: string;
|
icon?: string;
|
||||||
mode?: typeof MODES[number];
|
mode?: (typeof MODES)[number];
|
||||||
max?: number;
|
max?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
11
src/data/thread.ts
Normal file
11
src/data/thread.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { HomeAssistant } from "../types";
|
||||||
|
|
||||||
|
export interface ThreadInfo {
|
||||||
|
url: string;
|
||||||
|
active_dataset_tlvs: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const threadGetInfo = (hass: HomeAssistant): Promise<ThreadInfo> =>
|
||||||
|
hass.callWS({
|
||||||
|
type: "otbr/info",
|
||||||
|
});
|
@ -22,6 +22,7 @@ import type { HaTextField } from "../../components/ha-textfield";
|
|||||||
import {
|
import {
|
||||||
AgentInfo,
|
AgentInfo,
|
||||||
getAgentInfo,
|
getAgentInfo,
|
||||||
|
prepareConversation,
|
||||||
processConversationInput,
|
processConversationInput,
|
||||||
setConversationOnboarding,
|
setConversationOnboarding,
|
||||||
} from "../../data/conversation";
|
} from "../../data/conversation";
|
||||||
@ -220,6 +221,7 @@ export class HaVoiceCommandDialog extends LitElement {
|
|||||||
text: this.hass.localize("ui.dialogs.voice_command.how_can_i_help"),
|
text: this.hass.localize("ui.dialogs.voice_command.how_can_i_help"),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
prepareConversation(this.hass, this.hass.language);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected updated(changedProps: PropertyValues) {
|
protected updated(changedProps: PropertyValues) {
|
||||||
|
@ -26,7 +26,7 @@ class DialogAutomationMode extends LitElement implements HassDialog {
|
|||||||
|
|
||||||
private _params!: AutomationModeDialog;
|
private _params!: AutomationModeDialog;
|
||||||
|
|
||||||
@state() private _newMode: typeof MODES[number] = AUTOMATION_DEFAULT_MODE;
|
@state() private _newMode: (typeof MODES)[number] = AUTOMATION_DEFAULT_MODE;
|
||||||
|
|
||||||
@state() private _newMax?: number;
|
@state() private _newMax?: number;
|
||||||
|
|
||||||
|
@ -485,6 +485,13 @@ class HaPanelConfig extends HassRouterPage {
|
|||||||
"./integrations/integration-panels/matter/matter-config-panel"
|
"./integrations/integration-panels/matter/matter-config-panel"
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
thread: {
|
||||||
|
tag: "thread-config-panel",
|
||||||
|
load: () =>
|
||||||
|
import(
|
||||||
|
"./integrations/integration-panels/thread/thread-config-panel"
|
||||||
|
),
|
||||||
|
},
|
||||||
application_credentials: {
|
application_credentials: {
|
||||||
tag: "ha-config-application-credentials",
|
tag: "ha-config-application-credentials",
|
||||||
load: () =>
|
load: () =>
|
||||||
|
@ -39,6 +39,7 @@ import {
|
|||||||
rebootHost,
|
rebootHost,
|
||||||
shutdownHost,
|
shutdownHost,
|
||||||
} from "../../../data/hassio/host";
|
} from "../../../data/hassio/host";
|
||||||
|
import { scanUSBDevices } from "../../../data/usb";
|
||||||
import { showOptionsFlowDialog } from "../../../dialogs/config-flow/show-dialog-options-flow";
|
import { showOptionsFlowDialog } from "../../../dialogs/config-flow/show-dialog-options-flow";
|
||||||
import {
|
import {
|
||||||
showAlertDialog,
|
showAlertDialog,
|
||||||
@ -219,6 +220,10 @@ class HaConfigHardware extends SubscribeMixin(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
|
if (!this._configEntries) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
let boardId: string | undefined;
|
let boardId: string | undefined;
|
||||||
let boardName: string | undefined;
|
let boardName: string | undefined;
|
||||||
let imageURL: string | undefined;
|
let imageURL: string | undefined;
|
||||||
@ -230,13 +235,22 @@ class HaConfigHardware extends SubscribeMixin(LitElement) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const dongles = this._hardwareInfo?.hardware.filter(
|
const dongles = this._hardwareInfo?.hardware.filter(
|
||||||
(hw) => hw.dongle !== null
|
(hw) =>
|
||||||
|
hw.dongle !== null &&
|
||||||
|
(!hw.config_entries.length ||
|
||||||
|
hw.config_entries.some(
|
||||||
|
(entryId) =>
|
||||||
|
this._configEntries![entryId] &&
|
||||||
|
!this._configEntries![entryId].disabled_by
|
||||||
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
if (boardData) {
|
if (boardData) {
|
||||||
boardConfigEntries = boardData.config_entries
|
boardConfigEntries = boardData.config_entries
|
||||||
.map((id) => this._configEntries?.[id])
|
.map((id) => this._configEntries![id])
|
||||||
.filter((entry) => entry?.supports_options) as ConfigEntry[];
|
.filter(
|
||||||
|
(entry) => entry?.supports_options && !entry.disabled_by
|
||||||
|
) as ConfigEntry[];
|
||||||
boardId = boardData.board!.hassio_board_id;
|
boardId = boardData.board!.hassio_board_id;
|
||||||
boardName = boardData.name;
|
boardName = boardData.name;
|
||||||
documentationURL = boardData.url;
|
documentationURL = boardData.url;
|
||||||
@ -362,8 +376,10 @@ class HaConfigHardware extends SubscribeMixin(LitElement) {
|
|||||||
? html`<ha-card>
|
? html`<ha-card>
|
||||||
${dongles.map((dongle) => {
|
${dongles.map((dongle) => {
|
||||||
const configEntry = dongle.config_entries
|
const configEntry = dongle.config_entries
|
||||||
.map((id) => this._configEntries?.[id])
|
.map((id) => this._configEntries![id])
|
||||||
.filter((entry) => entry?.supports_options)[0];
|
.filter(
|
||||||
|
(entry) => entry?.supports_options && !entry.disabled_by
|
||||||
|
)[0];
|
||||||
return html`<div class="row">
|
return html`<div class="row">
|
||||||
${dongle.name}${configEntry
|
${dongle.name}${configEntry
|
||||||
? html`<mwc-button
|
? html`<mwc-button
|
||||||
@ -444,6 +460,10 @@ class HaConfigHardware extends SubscribeMixin(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _load() {
|
private async _load() {
|
||||||
|
if (isComponentLoaded(this.hass, "usb")) {
|
||||||
|
await scanUSBDevices(this.hass);
|
||||||
|
}
|
||||||
|
|
||||||
const isHassioLoaded = isComponentLoaded(this.hass, "hassio");
|
const isHassioLoaded = isComponentLoaded(this.hass, "hassio");
|
||||||
try {
|
try {
|
||||||
if (isComponentLoaded(this.hass, "hardware")) {
|
if (isComponentLoaded(this.hass, "hardware")) {
|
||||||
|
@ -21,7 +21,7 @@ export const HELPER_DOMAINS = [
|
|||||||
"schedule",
|
"schedule",
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export type HelperDomain = typeof HELPER_DOMAINS[number];
|
export type HelperDomain = (typeof HELPER_DOMAINS)[number];
|
||||||
export const isHelperDomain = arrayLiteralIncludes(HELPER_DOMAINS);
|
export const isHelperDomain = arrayLiteralIncludes(HELPER_DOMAINS);
|
||||||
|
|
||||||
export type Helper =
|
export type Helper =
|
||||||
|
@ -79,6 +79,7 @@ const integrationsWithPanel = {
|
|||||||
zha: "/config/zha/dashboard",
|
zha: "/config/zha/dashboard",
|
||||||
zwave_js: "/config/zwave_js/dashboard",
|
zwave_js: "/config/zwave_js/dashboard",
|
||||||
matter: "/config/matter",
|
matter: "/config/matter",
|
||||||
|
otbr: "/config/thread",
|
||||||
};
|
};
|
||||||
|
|
||||||
@customElement("ha-integration-card")
|
@customElement("ha-integration-card")
|
||||||
|
@ -14,6 +14,7 @@ import { HomeAssistant } from "../../../../../types";
|
|||||||
import "../../../../../components/ha-alert";
|
import "../../../../../components/ha-alert";
|
||||||
import { showPromptDialog } from "../../../../../dialogs/generic/show-dialog-box";
|
import { showPromptDialog } from "../../../../../dialogs/generic/show-dialog-box";
|
||||||
import { navigate } from "../../../../../common/navigate";
|
import { navigate } from "../../../../../common/navigate";
|
||||||
|
import { isComponentLoaded } from "../../../../../common/config/is_component_loaded";
|
||||||
|
|
||||||
@customElement("matter-config-panel")
|
@customElement("matter-config-panel")
|
||||||
export class MatterConfigPanel extends LitElement {
|
export class MatterConfigPanel extends LitElement {
|
||||||
@ -32,18 +33,24 @@ export class MatterConfigPanel extends LitElement {
|
|||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<hass-subpage .narrow=${this.narrow} .hass=${this.hass} header="Matter">
|
<hass-subpage .narrow=${this.narrow} .hass=${this.hass} header="Matter">
|
||||||
|
${isComponentLoaded(this.hass, "otbr")
|
||||||
|
? html`
|
||||||
|
<a href="/config/thread" slot="toolbar-icon">
|
||||||
|
<mwc-button>Visit Thread Panel</mwc-button>
|
||||||
|
</a>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<ha-card header="Matter">
|
<ha-card header="Matter">
|
||||||
|
<ha-alert alert-type="warning"
|
||||||
|
>Matter is still in the early phase of development, it is not
|
||||||
|
meant to be used in production. This panel is for development
|
||||||
|
only.</ha-alert
|
||||||
|
>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
${this._error
|
${this._error
|
||||||
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||||
: ""}
|
: ""}
|
||||||
<ha-alert alert-type="warning"
|
|
||||||
>Matter is still in the early phase of development, it is not
|
|
||||||
meant to be used in production. This panel is for development
|
|
||||||
only.</ha-alert
|
|
||||||
>
|
|
||||||
|
|
||||||
You can add Matter devices by commissing them if they are not
|
You can add Matter devices by commissing them if they are not
|
||||||
setup yet, or share them from another controller and enter the
|
setup yet, or share them from another controller and enter the
|
||||||
share code.
|
share code.
|
||||||
@ -199,6 +206,10 @@ export class MatterConfigPanel extends LitElement {
|
|||||||
static styles = [
|
static styles = [
|
||||||
haStyle,
|
haStyle,
|
||||||
css`
|
css`
|
||||||
|
ha-alert[alert-type="warning"] {
|
||||||
|
position: relative;
|
||||||
|
top: -16px;
|
||||||
|
}
|
||||||
.content {
|
.content {
|
||||||
padding: 24px 0 32px;
|
padding: 24px 0 32px;
|
||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
@ -208,6 +219,9 @@ export class MatterConfigPanel extends LitElement {
|
|||||||
ha-card:first-child {
|
ha-card:first-child {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
a[slot="toolbar-icon"] {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
import "@material/mwc-button";
|
||||||
|
import { css, html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import "../../../../../components/ha-card";
|
||||||
|
import "../../../../../layouts/hass-subpage";
|
||||||
|
import { haStyle } from "../../../../../resources/styles";
|
||||||
|
import { HomeAssistant } from "../../../../../types";
|
||||||
|
import { threadGetInfo, ThreadInfo } from "../../../../../data/thread";
|
||||||
|
|
||||||
|
@customElement("thread-config-panel")
|
||||||
|
export class ThreadConfigPanel extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public narrow!: boolean;
|
||||||
|
|
||||||
|
@state() private _info?: ThreadInfo;
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<hass-subpage .narrow=${this.narrow} .hass=${this.hass} header="Thread">
|
||||||
|
<div class="content">
|
||||||
|
<ha-card header="Thread Border Router">
|
||||||
|
<div class="card-content">
|
||||||
|
${!this._info
|
||||||
|
? html`<ha-circular-progress active></ha-circular-progress>`
|
||||||
|
: html`
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>URL</td>
|
||||||
|
<td>${this._info.url}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Active Dataset TLVs</td>
|
||||||
|
<td>${this._info.active_dataset_tlvs || "-"}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
`}
|
||||||
|
</div>
|
||||||
|
</ha-card>
|
||||||
|
</div>
|
||||||
|
</hass-subpage>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override firstUpdated(changedProps: PropertyValues) {
|
||||||
|
super.firstUpdated(changedProps);
|
||||||
|
|
||||||
|
threadGetInfo(this.hass).then((info) => {
|
||||||
|
this._info = info;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static styles = [
|
||||||
|
haStyle,
|
||||||
|
css`
|
||||||
|
.content {
|
||||||
|
padding: 24px 0 32px;
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
direction: ltr;
|
||||||
|
}
|
||||||
|
ha-card:first-child {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"thread-config-panel": ThreadConfigPanel;
|
||||||
|
}
|
||||||
|
}
|
@ -50,7 +50,7 @@ export class ZHAManageClusters extends LitElement {
|
|||||||
|
|
||||||
@state() private _selectedCluster?: Cluster;
|
@state() private _selectedCluster?: Cluster;
|
||||||
|
|
||||||
@state() private _currTab: typeof tabs[number] = "attributes";
|
@state() private _currTab: (typeof tabs)[number] = "attributes";
|
||||||
|
|
||||||
@state() private _clustersLoaded = false;
|
@state() private _clustersLoaded = false;
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
(
|
(
|
||||||
hasID: boolean,
|
hasID: boolean,
|
||||||
useBluePrint?: boolean,
|
useBluePrint?: boolean,
|
||||||
currentMode?: typeof MODES[number]
|
currentMode?: (typeof MODES)[number]
|
||||||
) =>
|
) =>
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
@ -528,7 +528,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
// Mode must be one of max modes per schema definition above
|
// Mode must be one of max modes per schema definition above
|
||||||
return this.hass.localize(
|
return this.hass.localize(
|
||||||
`ui.panel.config.script.editor.max.${
|
`ui.panel.config.script.editor.max.${
|
||||||
data.mode as typeof MODES_MAX[number]
|
data.mode as (typeof MODES_MAX)[number]
|
||||||
}`
|
}`
|
||||||
);
|
);
|
||||||
default:
|
default:
|
||||||
|
@ -1,8 +1,16 @@
|
|||||||
import { memoize } from "@fullcalendar/common";
|
import { memoize } from "@fullcalendar/common";
|
||||||
|
import { Ripple } from "@material/mwc-ripple";
|
||||||
|
import { RippleHandlers } from "@material/mwc-ripple/ripple-handlers";
|
||||||
import { mdiExclamationThick, mdiHelp } from "@mdi/js";
|
import { mdiExclamationThick, mdiHelp } from "@mdi/js";
|
||||||
import { HassEntity } from "home-assistant-js-websocket";
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import {
|
||||||
|
customElement,
|
||||||
|
eventOptions,
|
||||||
|
property,
|
||||||
|
queryAsync,
|
||||||
|
state,
|
||||||
|
} from "lit/decorators";
|
||||||
import { styleMap } from "lit/directives/style-map";
|
import { styleMap } from "lit/directives/style-map";
|
||||||
import { computeCssColor } from "../../../common/color/compute-color";
|
import { computeCssColor } from "../../../common/color/compute-color";
|
||||||
import { hsv2rgb, rgb2hsv } from "../../../common/color/convert-color";
|
import { hsv2rgb, rgb2hsv } from "../../../common/color/convert-color";
|
||||||
@ -105,7 +113,8 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
|||||||
handleAction(this, this.hass!, this._config!, ev.detail.action!);
|
handleAction(this, this.hass!, this._config!, ev.detail.action!);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleIconAction() {
|
private _handleIconAction(ev: CustomEvent) {
|
||||||
|
ev.stopPropagation();
|
||||||
const config = {
|
const config = {
|
||||||
entity: this._config!.entity,
|
entity: this._config!.entity,
|
||||||
tap_action: this._config!.icon_tap_action,
|
tap_action: this._config!.icon_tap_action,
|
||||||
@ -219,6 +228,32 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
|||||||
return stateDisplay;
|
return stateDisplay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@queryAsync("mwc-ripple") private _ripple!: Promise<Ripple | null>;
|
||||||
|
|
||||||
|
@state() private _shouldRenderRipple = false;
|
||||||
|
|
||||||
|
private _rippleHandlers: RippleHandlers = new RippleHandlers(() => {
|
||||||
|
this._shouldRenderRipple = true;
|
||||||
|
return this._ripple;
|
||||||
|
});
|
||||||
|
|
||||||
|
@eventOptions({ passive: true })
|
||||||
|
private handleRippleActivate(evt?: Event) {
|
||||||
|
this._rippleHandlers.startPress(evt);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleRippleDeactivate() {
|
||||||
|
this._rippleHandlers.endPress();
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleRippleMouseEnter() {
|
||||||
|
this._rippleHandlers.startHover();
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleRippleMouseLeave() {
|
||||||
|
this._rippleHandlers.endHover();
|
||||||
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (!this._config || !this.hass) {
|
if (!this._config || !this.hass) {
|
||||||
return html``;
|
return html``;
|
||||||
@ -274,6 +309,7 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
|||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-card style=${styleMap(style)}>
|
<ha-card style=${styleMap(style)}>
|
||||||
|
${this._shouldRenderRipple ? html`<mwc-ripple></mwc-ripple>` : null}
|
||||||
<div class="tile">
|
<div class="tile">
|
||||||
<div
|
<div
|
||||||
class="icon-container"
|
class="icon-container"
|
||||||
@ -313,10 +349,17 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
|||||||
class="info"
|
class="info"
|
||||||
.primary=${name}
|
.primary=${name}
|
||||||
.secondary=${stateDisplay}
|
.secondary=${stateDisplay}
|
||||||
role="button"
|
|
||||||
tabindex="0"
|
|
||||||
@action=${this._handleAction}
|
@action=${this._handleAction}
|
||||||
.actionHandler=${actionHandler()}
|
.actionHandler=${actionHandler()}
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
@mousedown=${this.handleRippleActivate}
|
||||||
|
@mouseup=${this.handleRippleDeactivate}
|
||||||
|
@mouseenter=${this.handleRippleMouseEnter}
|
||||||
|
@mouseleave=${this.handleRippleMouseLeave}
|
||||||
|
@touchstart=${this.handleRippleActivate}
|
||||||
|
@touchend=${this.handleRippleDeactivate}
|
||||||
|
@touchcancel=${this.handleRippleDeactivate}
|
||||||
></ha-tile-info>
|
></ha-tile-info>
|
||||||
</div>
|
</div>
|
||||||
${supportedFeatures?.length
|
${supportedFeatures?.length
|
||||||
@ -365,11 +408,18 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
|||||||
return css`
|
return css`
|
||||||
:host {
|
:host {
|
||||||
--tile-color: rgb(var(--rgb-state-inactive-color));
|
--tile-color: rgb(var(--rgb-state-inactive-color));
|
||||||
--tile-tap-padding: 6px;
|
|
||||||
-webkit-tap-highlight-color: transparent;
|
-webkit-tap-highlight-color: transparent;
|
||||||
}
|
}
|
||||||
|
ha-card:has(ha-tile-info:focus-visible) {
|
||||||
|
border-color: var(--tile-color);
|
||||||
|
box-shadow: 0 0 0 1px var(--tile-color);
|
||||||
|
}
|
||||||
ha-card {
|
ha-card {
|
||||||
|
--mdc-ripple-color: var(--tile-color);
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
// For safari overflow hidden
|
||||||
|
z-index: 0;
|
||||||
}
|
}
|
||||||
ha-card.disabled {
|
ha-card.disabled {
|
||||||
--tile-color: rgb(var(--rgb-disabled-color));
|
--tile-color: rgb(var(--rgb-disabled-color));
|
||||||
@ -381,18 +431,16 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
|||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
.tile {
|
.tile {
|
||||||
padding: calc(12px - var(--tile-tap-padding));
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
.icon-container {
|
.icon-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: var(--tile-tap-padding);
|
|
||||||
flex: none;
|
flex: none;
|
||||||
margin-right: calc(12px - 2 * var(--tile-tap-padding));
|
margin-right: 12px;
|
||||||
margin-inline-end: calc(12px - 2 * var(--tile-tap-padding));
|
margin-inline-start: 12px;
|
||||||
margin-inline-start: initial;
|
margin-inline-end: initial;
|
||||||
direction: var(--direction);
|
direction: var(--direction);
|
||||||
transition: transform 180ms ease-in-out;
|
transition: transform 180ms ease-in-out;
|
||||||
}
|
}
|
||||||
@ -401,8 +449,8 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
|||||||
}
|
}
|
||||||
.icon-container .badge {
|
.icon-container .badge {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: calc(-3px + var(--tile-tap-padding));
|
top: -3px;
|
||||||
right: calc(-3px + var(--tile-tap-padding));
|
right: -3px;
|
||||||
}
|
}
|
||||||
.icon-container[role="button"]:focus-visible,
|
.icon-container[role="button"]:focus-visible,
|
||||||
.icon-container[role="button"]:active {
|
.icon-container[role="button"]:active {
|
||||||
@ -410,27 +458,12 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
|||||||
}
|
}
|
||||||
.info {
|
.info {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: var(--tile-tap-padding);
|
padding: 12px;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
min-height: 40px;
|
min-height: 40px;
|
||||||
transition: background-color 180ms ease-in-out;
|
transition: background-color 180ms ease-in-out;
|
||||||
}
|
}
|
||||||
.info::before {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
border-radius: calc(var(--ha-card-border-radius, 10px) - 2px);
|
|
||||||
background-color: transparent;
|
|
||||||
opacity: 0.1;
|
|
||||||
transition: background-color ease-in-out 180ms;
|
|
||||||
}
|
|
||||||
.info:focus-visible::before {
|
|
||||||
background-color: var(--tile-color);
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,7 +161,7 @@ export const computeCards = (
|
|||||||
renderFooterEntities &&
|
renderFooterEntities &&
|
||||||
(domain === "scene" || domain === "script")
|
(domain === "scene" || domain === "script")
|
||||||
) {
|
) {
|
||||||
const conf: typeof footerEntities[0] = {
|
const conf: (typeof footerEntities)[0] = {
|
||||||
entity: entityId,
|
entity: entityId,
|
||||||
show_icon: true,
|
show_icon: true,
|
||||||
show_name: true,
|
show_name: true,
|
||||||
|
@ -16,4 +16,4 @@ export const TIMESTAMP_RENDERING_FORMATS = [
|
|||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export type TimestampRenderingFormat =
|
export type TimestampRenderingFormat =
|
||||||
typeof TIMESTAMP_RENDERING_FORMATS[number];
|
(typeof TIMESTAMP_RENDERING_FORMATS)[number];
|
||||||
|
@ -38,7 +38,7 @@ const cardConfigStruct = assign(
|
|||||||
|
|
||||||
const stat_types = ["mean", "min", "max", "change"] as const;
|
const stat_types = ["mean", "min", "max", "change"] as const;
|
||||||
|
|
||||||
const statTypeMap: Record<typeof stat_types[number], StatisticType> = {
|
const statTypeMap: Record<(typeof stat_types)[number], StatisticType> = {
|
||||||
mean: "mean",
|
mean: "mean",
|
||||||
min: "min",
|
min: "min",
|
||||||
max: "max",
|
max: "max",
|
||||||
|
@ -102,6 +102,7 @@ class HuiSelectEntityRow extends LitElement implements LovelaceRow {
|
|||||||
}
|
}
|
||||||
ha-select {
|
ha-select {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
--ha-select-min-width: 0;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@ -186,10 +186,10 @@ export class HuiGraphHeaderFooter
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _unsubscribeHistoryTimeWindow() {
|
private _unsubscribeHistoryTimeWindow() {
|
||||||
|
clearInterval(this._interval);
|
||||||
if (!this._subscribed) {
|
if (!this._subscribed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
clearInterval(this._interval);
|
|
||||||
this._subscribed.then((unsubscribe) => {
|
this._subscribed.then((unsubscribe) => {
|
||||||
if (unsubscribe) {
|
if (unsubscribe) {
|
||||||
unsubscribe();
|
unsubscribe();
|
||||||
|
@ -18,7 +18,7 @@ export const VACUUM_COMMANDS = [
|
|||||||
"return_home",
|
"return_home",
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export type VacuumCommand = typeof VACUUM_COMMANDS[number];
|
export type VacuumCommand = (typeof VACUUM_COMMANDS)[number];
|
||||||
|
|
||||||
export interface VacuumCommandsTileFeatureConfig {
|
export interface VacuumCommandsTileFeatureConfig {
|
||||||
type: "vacuum-commands";
|
type: "vacuum-commands";
|
||||||
|
@ -2,14 +2,10 @@
|
|||||||
import { expose } from "comlink";
|
import { expose } from "comlink";
|
||||||
import { marked } from "marked";
|
import { marked } from "marked";
|
||||||
import "proxy-polyfill";
|
import "proxy-polyfill";
|
||||||
import { filterXSS, getDefaultWhiteList } from "xss";
|
import { filterXSS, getDefaultWhiteList, IWhiteList } from "xss";
|
||||||
|
|
||||||
interface WhiteList {
|
let whiteListNormal: IWhiteList | undefined;
|
||||||
[tag: string]: string[];
|
let whiteListSvg: IWhiteList | undefined;
|
||||||
}
|
|
||||||
|
|
||||||
let whiteListNormal: WhiteList | undefined;
|
|
||||||
let whiteListSvg: WhiteList | undefined;
|
|
||||||
|
|
||||||
// Override the default `onTagAttr` behavior to only render
|
// Override the default `onTagAttr` behavior to only render
|
||||||
// our markdown checkboxes.
|
// our markdown checkboxes.
|
||||||
@ -43,7 +39,7 @@ const renderMarkdown = (
|
|||||||
): string => {
|
): string => {
|
||||||
if (!whiteListNormal) {
|
if (!whiteListNormal) {
|
||||||
whiteListNormal = {
|
whiteListNormal = {
|
||||||
...(getDefaultWhiteList() as WhiteList),
|
...getDefaultWhiteList(),
|
||||||
input: ["type", "disabled", "checked"],
|
input: ["type", "disabled", "checked"],
|
||||||
"ha-icon": ["icon"],
|
"ha-icon": ["icon"],
|
||||||
"ha-svg-icon": ["path"],
|
"ha-svg-icon": ["path"],
|
||||||
@ -51,7 +47,7 @@ const renderMarkdown = (
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let whiteList: WhiteList | undefined;
|
let whiteList: IWhiteList | undefined;
|
||||||
|
|
||||||
if (hassOptions.allowSvg) {
|
if (hassOptions.allowSvg) {
|
||||||
if (!whiteListSvg) {
|
if (!whiteListSvg) {
|
||||||
|
@ -2,6 +2,7 @@ import type { PropertyValues } from "lit";
|
|||||||
import tinykeys from "tinykeys";
|
import tinykeys from "tinykeys";
|
||||||
import { isComponentLoaded } from "../common/config/is_component_loaded";
|
import { isComponentLoaded } from "../common/config/is_component_loaded";
|
||||||
import { mainWindow } from "../common/dom/get_main_window";
|
import { mainWindow } from "../common/dom/get_main_window";
|
||||||
|
import { HaSelect } from "../components/ha-select";
|
||||||
import {
|
import {
|
||||||
QuickBarParams,
|
QuickBarParams,
|
||||||
showQuickBar,
|
showQuickBar,
|
||||||
@ -133,17 +134,17 @@ export default <T extends Constructor<HassElement>>(superClass: T) =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _canOverrideAlphanumericInput(e: KeyboardEvent) {
|
private _canOverrideAlphanumericInput(e: KeyboardEvent) {
|
||||||
const el = e.composedPath()[0] as any;
|
const el = e.composedPath()[0];
|
||||||
|
|
||||||
if (el.tagName === "TEXTAREA") {
|
if (el instanceof HTMLTextAreaElement) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (el.parentElement.tagName === "HA-SELECT") {
|
if (el instanceof Element && el.parentElement instanceof HaSelect) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (el.tagName !== "INPUT") {
|
if (!(el instanceof HTMLInputElement)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -808,7 +808,7 @@
|
|||||||
"did_not_understand": "Didn't quite get that",
|
"did_not_understand": "Didn't quite get that",
|
||||||
"found": "I found the following for you:",
|
"found": "I found the following for you:",
|
||||||
"error": "Oops, an error has occurred",
|
"error": "Oops, an error has occurred",
|
||||||
"how_can_i_help": "How can I help?",
|
"how_can_i_help": "How can I assist?",
|
||||||
"input_label": "Enter a request",
|
"input_label": "Enter a request",
|
||||||
"send_text": "Send text",
|
"send_text": "Send text",
|
||||||
"start_listening": "Start listening"
|
"start_listening": "Start listening"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user