mirror of
https://github.com/home-assistant/frontend.git
synced 2025-08-01 13:37:47 +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/
|
||||
|
||||
# yarn
|
||||
.yarn/**
|
||||
.yarn/*
|
||||
!.yarn/patches
|
||||
!.yarn/releases
|
||||
!.yarn/plugins
|
||||
@ -31,7 +31,7 @@ pip-selfcheck.json
|
||||
.venv
|
||||
|
||||
# vscode
|
||||
.vscode/**
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
!.vscode/launch.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 paths = require("../paths");
|
||||
require("./translations");
|
||||
|
||||
gulp.task(
|
||||
"clean",
|
||||
gulp.parallel("clean-translations", () =>
|
||||
del([paths.app_output_root, paths.build_dir])
|
||||
gulp.parallel("clean-translations", async () =>
|
||||
(await del).deleteSync([paths.app_output_root, paths.build_dir])
|
||||
)
|
||||
);
|
||||
|
||||
gulp.task(
|
||||
"clean-demo",
|
||||
gulp.parallel("clean-translations", () =>
|
||||
del([paths.demo_output_root, paths.build_dir])
|
||||
gulp.parallel("clean-translations", async () =>
|
||||
(await del).deleteSync([paths.demo_output_root, paths.build_dir])
|
||||
)
|
||||
);
|
||||
|
||||
gulp.task(
|
||||
"clean-cast",
|
||||
gulp.parallel("clean-translations", () =>
|
||||
del([paths.cast_output_root, paths.build_dir])
|
||||
gulp.parallel("clean-translations", async () =>
|
||||
(await del).deleteSync([paths.cast_output_root, paths.build_dir])
|
||||
)
|
||||
);
|
||||
|
||||
gulp.task("clean-hassio", () =>
|
||||
del([paths.hassio_output_root, paths.build_dir])
|
||||
gulp.task("clean-hassio", async () =>
|
||||
(await del).deleteSync([paths.hassio_output_root, paths.build_dir])
|
||||
);
|
||||
|
||||
gulp.task(
|
||||
"clean-gallery",
|
||||
gulp.parallel("clean-translations", () =>
|
||||
del([paths.gallery_output_root, paths.gallery_build, paths.build_dir])
|
||||
gulp.parallel("clean-translations", async () =>
|
||||
(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
|
||||
|
||||
const del = import("del");
|
||||
const fs = require("fs/promises");
|
||||
const path = require("path");
|
||||
const process = require("process");
|
||||
const del = require("del");
|
||||
const gulp = require("gulp");
|
||||
const jszip = require("jszip");
|
||||
const tar = require("tar");
|
||||
@ -17,8 +17,8 @@ const WORKFLOW_NAME = "nightly.yaml";
|
||||
const ARTIFACT_NAME = "translations";
|
||||
const CLIENT_ID = "Iv1.3914e28cb27834d1";
|
||||
const EXTRACT_DIR = "translations";
|
||||
const TOKEN_FILE = path.join(EXTRACT_DIR, "token.json");
|
||||
const ARTIFACT_FILE = path.join(EXTRACT_DIR, "artifact.json");
|
||||
const TOKEN_FILE = path.posix.join(EXTRACT_DIR, "token.json");
|
||||
const ARTIFACT_FILE = path.posix.join(EXTRACT_DIR, "artifact.json");
|
||||
|
||||
let allowTokenSetup = false;
|
||||
gulp.task("allow-setup-fetch-nightly-translations", (done) => {
|
||||
@ -137,7 +137,11 @@ gulp.task("fetch-nightly-translations", async function () {
|
||||
|
||||
// Remove the current translations
|
||||
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)
|
@ -1,4 +1,4 @@
|
||||
const del = require("del");
|
||||
const del = import("del");
|
||||
const path = require("path");
|
||||
const gulp = require("gulp");
|
||||
const fs = require("fs");
|
||||
@ -6,7 +6,7 @@ const paths = require("../paths");
|
||||
|
||||
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) => {
|
||||
if (!fs.existsSync(outDir)) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
const del = import("del");
|
||||
const crypto = require("crypto");
|
||||
const del = require("del");
|
||||
const path = require("path");
|
||||
const source = require("vinyl-source-stream");
|
||||
const vinylBuffer = require("vinyl-buffer");
|
||||
@ -13,7 +13,7 @@ const { mapFiles } = require("../util");
|
||||
const env = require("../env");
|
||||
const paths = require("../paths");
|
||||
|
||||
require("./fetch-nightly_translations");
|
||||
require("./fetch-nightly-translations");
|
||||
|
||||
const inFrontendDir = "translations/frontend";
|
||||
const inBackendDir = "translations/backend";
|
||||
@ -120,7 +120,7 @@ function lokaliseTransform(data, original, file) {
|
||||
return output;
|
||||
}
|
||||
|
||||
gulp.task("clean-translations", () => del([workDir]));
|
||||
gulp.task("clean-translations", async () => (await del).deleteSync([workDir]));
|
||||
|
||||
gulp.task("ensure-translations-build-dir", (done) => {
|
||||
if (!fs.existsSync(workDir)) {
|
||||
|
72
package.json
72
package.json
@ -47,30 +47,30 @@
|
||||
"@lezer/highlight": "^1.1.3",
|
||||
"@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",
|
||||
"@material/chips": "14.0.0-canary.261f2db59.0",
|
||||
"@material/data-table": "14.0.0-canary.261f2db59.0",
|
||||
"@material/mwc-button": "0.25.3",
|
||||
"@material/mwc-checkbox": "0.25.3",
|
||||
"@material/mwc-circular-progress": "0.25.3",
|
||||
"@material/mwc-dialog": "0.25.3",
|
||||
"@material/mwc-drawer": "^0.25.3",
|
||||
"@material/mwc-fab": "0.25.3",
|
||||
"@material/mwc-formfield": "0.25.3",
|
||||
"@material/mwc-icon-button": "patch:@material/mwc-icon-button@0.25.3#./.yarn/patches/@material/mwc-icon-button/remove-icon.patch",
|
||||
"@material/mwc-linear-progress": "0.25.3",
|
||||
"@material/mwc-list": "^0.25.3",
|
||||
"@material/mwc-menu": "0.25.3",
|
||||
"@material/mwc-radio": "0.25.3",
|
||||
"@material/mwc-ripple": "0.25.3",
|
||||
"@material/mwc-select": "0.25.3",
|
||||
"@material/mwc-slider": "0.25.3",
|
||||
"@material/mwc-switch": "0.25.3",
|
||||
"@material/mwc-tab": "0.25.3",
|
||||
"@material/mwc-tab-bar": "0.25.3",
|
||||
"@material/mwc-textarea": "^0.25.3",
|
||||
"@material/mwc-textfield": "0.25.3",
|
||||
"@material/mwc-top-app-bar-fixed": "^0.25.3",
|
||||
"@material/top-app-bar": "14.0.0-canary.261f2db59.0",
|
||||
"@material/chips": "=14.0.0-canary.53b3cad2f.0",
|
||||
"@material/data-table": "=14.0.0-canary.53b3cad2f.0",
|
||||
"@material/mwc-button": "^0.27.0",
|
||||
"@material/mwc-checkbox": "^0.27.0",
|
||||
"@material/mwc-circular-progress": "^0.27.0",
|
||||
"@material/mwc-dialog": "^0.27.0",
|
||||
"@material/mwc-drawer": "^0.27.0",
|
||||
"@material/mwc-fab": "^0.27.0",
|
||||
"@material/mwc-formfield": "^0.27.0",
|
||||
"@material/mwc-icon-button": "^0.27.0",
|
||||
"@material/mwc-linear-progress": "^0.27.0",
|
||||
"@material/mwc-list": "^0.27.0",
|
||||
"@material/mwc-menu": "^0.27.0",
|
||||
"@material/mwc-radio": "^0.27.0",
|
||||
"@material/mwc-ripple": "^0.27.0",
|
||||
"@material/mwc-select": "^0.27.0",
|
||||
"@material/mwc-slider": "^0.27.0",
|
||||
"@material/mwc-switch": "^0.27.0",
|
||||
"@material/mwc-tab": "^0.27.0",
|
||||
"@material/mwc-tab-bar": "^0.27.0",
|
||||
"@material/mwc-textarea": "^0.27.0",
|
||||
"@material/mwc-textfield": "^0.27.0",
|
||||
"@material/mwc-top-app-bar-fixed": "^0.27.0",
|
||||
"@material/top-app-bar": "=14.0.0-canary.53b3cad2f.0",
|
||||
"@mdi/js": "7.1.96",
|
||||
"@mdi/svg": "7.1.96",
|
||||
"@polymer/app-layout": "^3.1.0",
|
||||
@ -108,7 +108,7 @@
|
||||
"fuse.js": "^6.0.0",
|
||||
"google-timezones-json": "^1.0.2",
|
||||
"hammerjs": "^2.0.8",
|
||||
"hls.js": "^1.2.5",
|
||||
"hls.js": "^1.3.1",
|
||||
"home-assistant-js-websocket": "^8.0.1",
|
||||
"idb-keyval": "^5.1.3",
|
||||
"intl-messageformat": "^9.9.1",
|
||||
@ -117,7 +117,7 @@
|
||||
"leaflet-draw": "^1.0.4",
|
||||
"lit": "^2.1.2",
|
||||
"marked": "^4.0.12",
|
||||
"memoize-one": "^5.2.1",
|
||||
"memoize-one": "^6.0.0",
|
||||
"node-vibrant": "3.2.1-alpha.1",
|
||||
"proxy-polyfill": "^0.3.2",
|
||||
"punycode": "^2.1.1",
|
||||
@ -143,13 +143,13 @@
|
||||
"workbox-precaching": "^6.5.4",
|
||||
"workbox-routing": "^6.5.4",
|
||||
"workbox-strategies": "^6.5.4",
|
||||
"xss": "^1.0.9"
|
||||
"xss": "^1.0.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.20.2",
|
||||
"@babel/plugin-external-helpers": "^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-object-rest-spread": "^7.20.2",
|
||||
"@babel/plugin-proposal-optional-chaining": "^7.18.9",
|
||||
@ -169,7 +169,7 @@
|
||||
"@rollup/plugin-replace": "^2.3.2",
|
||||
"@types/chromecast-caf-receiver": "5.0.12",
|
||||
"@types/chromecast-caf-sender": "^1.0.3",
|
||||
"@types/glob": "^7",
|
||||
"@types/glob": "^8",
|
||||
"@types/hammerjs": "^2.0.41",
|
||||
"@types/js-yaml": "^4",
|
||||
"@types/leaflet": "^1",
|
||||
@ -186,7 +186,7 @@
|
||||
"@web/dev-server-rollup": "^0.2.11",
|
||||
"babel-loader": "^9.1.0",
|
||||
"chai": "^4.3.4",
|
||||
"del": "^4.0.0",
|
||||
"del": "^7.0.0",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-airbnb-base": "^14.2.1",
|
||||
"eslint-config-airbnb-typescript": "^14.0.0",
|
||||
@ -196,10 +196,10 @@
|
||||
"eslint-plugin-import": "^2.24.2",
|
||||
"eslint-plugin-lit": "^1.6.1",
|
||||
"eslint-plugin-unused-imports": "^1.1.5",
|
||||
"eslint-plugin-wc": "^1.3.2",
|
||||
"eslint-plugin-wc": "^1.4.0",
|
||||
"fancy-log": "^2.0.0",
|
||||
"fs-extra": "^11.1.0",
|
||||
"glob": "^7.2.0",
|
||||
"glob": "^8.1.0",
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-flatmap": "^1.0.2",
|
||||
"gulp-json-transform": "^0.4.6",
|
||||
@ -217,17 +217,17 @@
|
||||
"map-stream": "^0.0.7",
|
||||
"merge-stream": "^1.0.1",
|
||||
"mocha": "^8.4.0",
|
||||
"object-hash": "^2.0.3",
|
||||
"object-hash": "^3.0.0",
|
||||
"open": "^8.4.0",
|
||||
"pinst": "^3.0.0",
|
||||
"prettier": "^2.8.1",
|
||||
"prettier": "^2.8.3",
|
||||
"require-dir": "^1.2.0",
|
||||
"rollup": "^2.8.2",
|
||||
"rollup-plugin-string": "^3.0.0",
|
||||
"rollup-plugin-terser": "^5.3.0",
|
||||
"rollup-plugin-visualizer": "^5.9.0",
|
||||
"serve": "^11.3.2",
|
||||
"sinon": "^11.0.0",
|
||||
"sinon": "^15.0.1",
|
||||
"source-map-url": "^0.4.0",
|
||||
"systemjs": "^6.3.2",
|
||||
"tar": "^6.1.11",
|
||||
@ -238,7 +238,7 @@
|
||||
"vinyl-source-stream": "^2.0.0",
|
||||
"webpack": "^5.55.1",
|
||||
"webpack-cli": "^4.8.0",
|
||||
"webpack-dev-server": "^4.3.0",
|
||||
"webpack-dev-server": "^4.11.1",
|
||||
"webpack-manifest-plugin": "^4.0.2",
|
||||
"webpackbar": "^5.0.0-3",
|
||||
"workbox-build": "^6.5.4"
|
||||
|
@ -39,5 +39,5 @@ export default function scrollToTarget(element, target) {
|
||||
);
|
||||
requestAnimationFrame(updateFrame.bind(element));
|
||||
}
|
||||
}.call(element));
|
||||
}).call(element);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import type { HassEntity } from "home-assistant-js-websocket";
|
||||
import { css, html, LitElement, TemplateResult } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { isValidEntityId } from "../../common/entity/valid_entity_id";
|
||||
import type { PolymerChangedEvent } from "../../polymer-types";
|
||||
@ -95,7 +96,10 @@ class HaEntitiesPickerLight extends LitElement {
|
||||
.excludeEntities=${this.excludeEntities}
|
||||
.includeDeviceClasses=${this.includeDeviceClasses}
|
||||
.includeUnitOfMeasurement=${this.includeUnitOfMeasurement}
|
||||
.entityFilter=${this._entityFilter}
|
||||
.entityFilter=${this._getEntityFilter(
|
||||
this.value,
|
||||
this.entityFilter
|
||||
)}
|
||||
.value=${entityId}
|
||||
.label=${this.pickedEntityLabel}
|
||||
.disabled=${this.disabled}
|
||||
@ -114,7 +118,7 @@ class HaEntitiesPickerLight extends LitElement {
|
||||
.excludeEntities=${this.excludeEntities}
|
||||
.includeDeviceClasses=${this.includeDeviceClasses}
|
||||
.includeUnitOfMeasurement=${this.includeUnitOfMeasurement}
|
||||
.entityFilter=${this._entityFilter}
|
||||
.entityFilter=${this._getEntityFilter(this.value, this.entityFilter)}
|
||||
.label=${this.pickEntityLabel}
|
||||
.helper=${this.helper}
|
||||
.disabled=${this.disabled}
|
||||
@ -125,11 +129,15 @@ class HaEntitiesPickerLight extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private _entityFilter: HaEntityPickerEntityFilterFunc = (
|
||||
stateObj: HassEntity
|
||||
) =>
|
||||
(!this.value || !this.value.includes(stateObj.entity_id)) &&
|
||||
(!this.entityFilter || this.entityFilter(stateObj));
|
||||
private _getEntityFilter = memoizeOne(
|
||||
(
|
||||
value: string[] | undefined,
|
||||
entityFilter: HaEntityPickerEntityFilterFunc | undefined
|
||||
): HaEntityPickerEntityFilterFunc =>
|
||||
(stateObj: HassEntity) =>
|
||||
(!value || !value.includes(stateObj.entity_id)) &&
|
||||
(!entityFilter || entityFilter(stateObj))
|
||||
);
|
||||
|
||||
private get _currentEntities() {
|
||||
return this.value || [];
|
||||
|
@ -35,9 +35,9 @@ const TRUNCATED_DOMAINS = [
|
||||
"person",
|
||||
] as const satisfies ReadonlyArray<keyof typeof FIXED_DOMAIN_STATES>;
|
||||
|
||||
type TruncatedDomain = typeof TRUNCATED_DOMAINS[number];
|
||||
type TruncatedDomain = (typeof TRUNCATED_DOMAINS)[number];
|
||||
type TruncatedKey = {
|
||||
[T in TruncatedDomain]: `${T}.${typeof FIXED_DOMAIN_STATES[T][number]}`;
|
||||
[T in TruncatedDomain]: `${T}.${(typeof FIXED_DOMAIN_STATES)[T][number]}`;
|
||||
}[TruncatedDomain];
|
||||
|
||||
const getTruncatedKey = (domainKey: string, stateKey: string) => {
|
||||
|
@ -278,6 +278,11 @@ export class HaBarSlider extends LitElement {
|
||||
--slider-bar-border-radius: 10px;
|
||||
height: var(--slider-bar-thickness);
|
||||
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]) {
|
||||
width: var(--slider-bar-thickness);
|
||||
|
@ -104,6 +104,14 @@ export class HaBarSwitch extends LitElement {
|
||||
box-sizing: border-box;
|
||||
user-select: none;
|
||||
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 {
|
||||
box-sizing: border-box;
|
||||
|
@ -164,10 +164,11 @@ export class HaSelectSelector extends LitElement {
|
||||
<ha-select
|
||||
fixedMenuPosition
|
||||
naturalMenuWidth
|
||||
.label=${this.label}
|
||||
.value=${this.value}
|
||||
.helper=${this.helper}
|
||||
.label=${this.label ?? ""}
|
||||
.value=${this.value ?? ""}
|
||||
.helper=${this.helper ?? ""}
|
||||
.disabled=${this.disabled}
|
||||
.required=${this.required}
|
||||
@closed=${stopPropagation}
|
||||
@selected=${this._valueChanged}
|
||||
>
|
||||
|
@ -8,7 +8,7 @@ import { BlueprintInput } from "./blueprint";
|
||||
import { DeviceCondition, DeviceTrigger } from "./device_automation";
|
||||
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 interface AutomationEntity extends HassEntityBase {
|
||||
@ -29,7 +29,7 @@ export interface ManualAutomationConfig {
|
||||
trigger: Trigger | Trigger[];
|
||||
condition?: Condition | Condition[];
|
||||
action: Action | Action[];
|
||||
mode?: typeof MODES[number];
|
||||
mode?: (typeof MODES)[number];
|
||||
max?: number;
|
||||
max_exceeded?:
|
||||
| "silent"
|
||||
|
@ -84,3 +84,12 @@ export const setConversationOnboarding = (
|
||||
type: "conversation/onboarding/set",
|
||||
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;
|
||||
export type EnergyGasUnitClass = typeof energyGasUnitClass[number];
|
||||
export type EnergyGasUnitClass = (typeof energyGasUnitClass)[number];
|
||||
|
||||
export const getEnergyGasUnitClass = (
|
||||
prefs: EnergyPreferences,
|
||||
|
@ -7,8 +7,8 @@ import { TranslationDict } from "../types";
|
||||
import { UNAVAILABLE_STATES } from "./entity";
|
||||
|
||||
type HumidifierState =
|
||||
| typeof FIXED_DOMAIN_STATES.humidifier[number]
|
||||
| typeof UNAVAILABLE_STATES[number];
|
||||
| (typeof FIXED_DOMAIN_STATES.humidifier)[number]
|
||||
| (typeof UNAVAILABLE_STATES)[number];
|
||||
type HumidifierMode =
|
||||
keyof TranslationDict["state_attributes"]["humidifier"]["mode"];
|
||||
|
||||
|
@ -98,7 +98,7 @@ const statisticTypes = [
|
||||
"state",
|
||||
"sum",
|
||||
] as const;
|
||||
export type StatisticsTypes = typeof statisticTypes[number][];
|
||||
export type StatisticsTypes = (typeof statisticTypes)[number][];
|
||||
|
||||
export interface StatisticsValidationResults {
|
||||
[statisticId: string]: StatisticsValidationResult[];
|
||||
|
@ -15,7 +15,7 @@ export interface ScheduleDay {
|
||||
to: string;
|
||||
}
|
||||
|
||||
type ScheduleDays = { [K in typeof weekdays[number]]?: ScheduleDay[] };
|
||||
type ScheduleDays = { [K in (typeof weekdays)[number]]?: ScheduleDay[] };
|
||||
|
||||
export interface Schedule extends ScheduleDays {
|
||||
id: string;
|
||||
|
@ -77,7 +77,7 @@ const activateSceneActionStruct: Describe<ServiceSceneAction> = assign(
|
||||
export interface ScriptEntity extends HassEntityBase {
|
||||
attributes: HassEntityAttributeBase & {
|
||||
last_triggered: string;
|
||||
mode: typeof MODES[number];
|
||||
mode: (typeof MODES)[number];
|
||||
current?: number;
|
||||
max?: number;
|
||||
};
|
||||
@ -89,7 +89,7 @@ export interface ManualScriptConfig {
|
||||
alias: string;
|
||||
sequence: Action | Action[];
|
||||
icon?: string;
|
||||
mode?: typeof MODES[number];
|
||||
mode?: (typeof MODES)[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 {
|
||||
AgentInfo,
|
||||
getAgentInfo,
|
||||
prepareConversation,
|
||||
processConversationInput,
|
||||
setConversationOnboarding,
|
||||
} from "../../data/conversation";
|
||||
@ -220,6 +221,7 @@ export class HaVoiceCommandDialog extends LitElement {
|
||||
text: this.hass.localize("ui.dialogs.voice_command.how_can_i_help"),
|
||||
},
|
||||
];
|
||||
prepareConversation(this.hass, this.hass.language);
|
||||
}
|
||||
|
||||
protected updated(changedProps: PropertyValues) {
|
||||
|
@ -26,7 +26,7 @@ class DialogAutomationMode extends LitElement implements HassDialog {
|
||||
|
||||
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;
|
||||
|
||||
|
@ -485,6 +485,13 @@ class HaPanelConfig extends HassRouterPage {
|
||||
"./integrations/integration-panels/matter/matter-config-panel"
|
||||
),
|
||||
},
|
||||
thread: {
|
||||
tag: "thread-config-panel",
|
||||
load: () =>
|
||||
import(
|
||||
"./integrations/integration-panels/thread/thread-config-panel"
|
||||
),
|
||||
},
|
||||
application_credentials: {
|
||||
tag: "ha-config-application-credentials",
|
||||
load: () =>
|
||||
|
@ -39,6 +39,7 @@ import {
|
||||
rebootHost,
|
||||
shutdownHost,
|
||||
} from "../../../data/hassio/host";
|
||||
import { scanUSBDevices } from "../../../data/usb";
|
||||
import { showOptionsFlowDialog } from "../../../dialogs/config-flow/show-dialog-options-flow";
|
||||
import {
|
||||
showAlertDialog,
|
||||
@ -219,6 +220,10 @@ class HaConfigHardware extends SubscribeMixin(LitElement) {
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this._configEntries) {
|
||||
return html``;
|
||||
}
|
||||
|
||||
let boardId: string | undefined;
|
||||
let boardName: string | undefined;
|
||||
let imageURL: string | undefined;
|
||||
@ -230,13 +235,22 @@ class HaConfigHardware extends SubscribeMixin(LitElement) {
|
||||
);
|
||||
|
||||
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) {
|
||||
boardConfigEntries = boardData.config_entries
|
||||
.map((id) => this._configEntries?.[id])
|
||||
.filter((entry) => entry?.supports_options) as ConfigEntry[];
|
||||
.map((id) => this._configEntries![id])
|
||||
.filter(
|
||||
(entry) => entry?.supports_options && !entry.disabled_by
|
||||
) as ConfigEntry[];
|
||||
boardId = boardData.board!.hassio_board_id;
|
||||
boardName = boardData.name;
|
||||
documentationURL = boardData.url;
|
||||
@ -362,8 +376,10 @@ class HaConfigHardware extends SubscribeMixin(LitElement) {
|
||||
? html`<ha-card>
|
||||
${dongles.map((dongle) => {
|
||||
const configEntry = dongle.config_entries
|
||||
.map((id) => this._configEntries?.[id])
|
||||
.filter((entry) => entry?.supports_options)[0];
|
||||
.map((id) => this._configEntries![id])
|
||||
.filter(
|
||||
(entry) => entry?.supports_options && !entry.disabled_by
|
||||
)[0];
|
||||
return html`<div class="row">
|
||||
${dongle.name}${configEntry
|
||||
? html`<mwc-button
|
||||
@ -444,6 +460,10 @@ class HaConfigHardware extends SubscribeMixin(LitElement) {
|
||||
}
|
||||
|
||||
private async _load() {
|
||||
if (isComponentLoaded(this.hass, "usb")) {
|
||||
await scanUSBDevices(this.hass);
|
||||
}
|
||||
|
||||
const isHassioLoaded = isComponentLoaded(this.hass, "hassio");
|
||||
try {
|
||||
if (isComponentLoaded(this.hass, "hardware")) {
|
||||
|
@ -21,7 +21,7 @@ export const HELPER_DOMAINS = [
|
||||
"schedule",
|
||||
] as const;
|
||||
|
||||
export type HelperDomain = typeof HELPER_DOMAINS[number];
|
||||
export type HelperDomain = (typeof HELPER_DOMAINS)[number];
|
||||
export const isHelperDomain = arrayLiteralIncludes(HELPER_DOMAINS);
|
||||
|
||||
export type Helper =
|
||||
|
@ -79,6 +79,7 @@ const integrationsWithPanel = {
|
||||
zha: "/config/zha/dashboard",
|
||||
zwave_js: "/config/zwave_js/dashboard",
|
||||
matter: "/config/matter",
|
||||
otbr: "/config/thread",
|
||||
};
|
||||
|
||||
@customElement("ha-integration-card")
|
||||
|
@ -14,6 +14,7 @@ import { HomeAssistant } from "../../../../../types";
|
||||
import "../../../../../components/ha-alert";
|
||||
import { showPromptDialog } from "../../../../../dialogs/generic/show-dialog-box";
|
||||
import { navigate } from "../../../../../common/navigate";
|
||||
import { isComponentLoaded } from "../../../../../common/config/is_component_loaded";
|
||||
|
||||
@customElement("matter-config-panel")
|
||||
export class MatterConfigPanel extends LitElement {
|
||||
@ -32,18 +33,24 @@ export class MatterConfigPanel extends LitElement {
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<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">
|
||||
<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">
|
||||
${this._error
|
||||
? 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
|
||||
setup yet, or share them from another controller and enter the
|
||||
share code.
|
||||
@ -199,6 +206,10 @@ export class MatterConfigPanel extends LitElement {
|
||||
static styles = [
|
||||
haStyle,
|
||||
css`
|
||||
ha-alert[alert-type="warning"] {
|
||||
position: relative;
|
||||
top: -16px;
|
||||
}
|
||||
.content {
|
||||
padding: 24px 0 32px;
|
||||
max-width: 600px;
|
||||
@ -208,6 +219,9 @@ export class MatterConfigPanel extends LitElement {
|
||||
ha-card:first-child {
|
||||
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 _currTab: typeof tabs[number] = "attributes";
|
||||
@state() private _currTab: (typeof tabs)[number] = "attributes";
|
||||
|
||||
@state() private _clustersLoaded = false;
|
||||
|
||||
|
@ -95,7 +95,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
||||
(
|
||||
hasID: 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
|
||||
return this.hass.localize(
|
||||
`ui.panel.config.script.editor.max.${
|
||||
data.mode as typeof MODES_MAX[number]
|
||||
data.mode as (typeof MODES_MAX)[number]
|
||||
}`
|
||||
);
|
||||
default:
|
||||
|
@ -1,8 +1,16 @@
|
||||
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 { HassEntity } from "home-assistant-js-websocket";
|
||||
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 { computeCssColor } from "../../../common/color/compute-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!);
|
||||
}
|
||||
|
||||
private _handleIconAction() {
|
||||
private _handleIconAction(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
const config = {
|
||||
entity: this._config!.entity,
|
||||
tap_action: this._config!.icon_tap_action,
|
||||
@ -219,6 +228,32 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
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 {
|
||||
if (!this._config || !this.hass) {
|
||||
return html``;
|
||||
@ -274,6 +309,7 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
|
||||
return html`
|
||||
<ha-card style=${styleMap(style)}>
|
||||
${this._shouldRenderRipple ? html`<mwc-ripple></mwc-ripple>` : null}
|
||||
<div class="tile">
|
||||
<div
|
||||
class="icon-container"
|
||||
@ -313,10 +349,17 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
class="info"
|
||||
.primary=${name}
|
||||
.secondary=${stateDisplay}
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@action=${this._handleAction}
|
||||
.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>
|
||||
</div>
|
||||
${supportedFeatures?.length
|
||||
@ -365,11 +408,18 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
return css`
|
||||
:host {
|
||||
--tile-color: rgb(var(--rgb-state-inactive-color));
|
||||
--tile-tap-padding: 6px;
|
||||
-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 {
|
||||
--mdc-ripple-color: var(--tile-color);
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
// For safari overflow hidden
|
||||
z-index: 0;
|
||||
}
|
||||
ha-card.disabled {
|
||||
--tile-color: rgb(var(--rgb-disabled-color));
|
||||
@ -381,18 +431,16 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
outline: none;
|
||||
}
|
||||
.tile {
|
||||
padding: calc(12px - var(--tile-tap-padding));
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
.icon-container {
|
||||
position: relative;
|
||||
padding: var(--tile-tap-padding);
|
||||
flex: none;
|
||||
margin-right: calc(12px - 2 * var(--tile-tap-padding));
|
||||
margin-inline-end: calc(12px - 2 * var(--tile-tap-padding));
|
||||
margin-inline-start: initial;
|
||||
margin-right: 12px;
|
||||
margin-inline-start: 12px;
|
||||
margin-inline-end: initial;
|
||||
direction: var(--direction);
|
||||
transition: transform 180ms ease-in-out;
|
||||
}
|
||||
@ -401,8 +449,8 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
}
|
||||
.icon-container .badge {
|
||||
position: absolute;
|
||||
top: calc(-3px + var(--tile-tap-padding));
|
||||
right: calc(-3px + var(--tile-tap-padding));
|
||||
top: -3px;
|
||||
right: -3px;
|
||||
}
|
||||
.icon-container[role="button"]:focus-visible,
|
||||
.icon-container[role="button"]:active {
|
||||
@ -410,27 +458,12 @@ export class HuiTileCard extends LitElement implements LovelaceCard {
|
||||
}
|
||||
.info {
|
||||
position: relative;
|
||||
padding: var(--tile-tap-padding);
|
||||
padding: 12px;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
min-height: 40px;
|
||||
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 &&
|
||||
(domain === "scene" || domain === "script")
|
||||
) {
|
||||
const conf: typeof footerEntities[0] = {
|
||||
const conf: (typeof footerEntities)[0] = {
|
||||
entity: entityId,
|
||||
show_icon: true,
|
||||
show_name: true,
|
||||
|
@ -16,4 +16,4 @@ export const TIMESTAMP_RENDERING_FORMATS = [
|
||||
] as const;
|
||||
|
||||
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 statTypeMap: Record<typeof stat_types[number], StatisticType> = {
|
||||
const statTypeMap: Record<(typeof stat_types)[number], StatisticType> = {
|
||||
mean: "mean",
|
||||
min: "min",
|
||||
max: "max",
|
||||
|
@ -102,6 +102,7 @@ class HuiSelectEntityRow extends LitElement implements LovelaceRow {
|
||||
}
|
||||
ha-select {
|
||||
width: 100%;
|
||||
--ha-select-min-width: 0;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
@ -186,10 +186,10 @@ export class HuiGraphHeaderFooter
|
||||
}
|
||||
|
||||
private _unsubscribeHistoryTimeWindow() {
|
||||
clearInterval(this._interval);
|
||||
if (!this._subscribed) {
|
||||
return;
|
||||
}
|
||||
clearInterval(this._interval);
|
||||
this._subscribed.then((unsubscribe) => {
|
||||
if (unsubscribe) {
|
||||
unsubscribe();
|
||||
|
@ -18,7 +18,7 @@ export const VACUUM_COMMANDS = [
|
||||
"return_home",
|
||||
] as const;
|
||||
|
||||
export type VacuumCommand = typeof VACUUM_COMMANDS[number];
|
||||
export type VacuumCommand = (typeof VACUUM_COMMANDS)[number];
|
||||
|
||||
export interface VacuumCommandsTileFeatureConfig {
|
||||
type: "vacuum-commands";
|
||||
|
@ -2,14 +2,10 @@
|
||||
import { expose } from "comlink";
|
||||
import { marked } from "marked";
|
||||
import "proxy-polyfill";
|
||||
import { filterXSS, getDefaultWhiteList } from "xss";
|
||||
import { filterXSS, getDefaultWhiteList, IWhiteList } from "xss";
|
||||
|
||||
interface WhiteList {
|
||||
[tag: string]: string[];
|
||||
}
|
||||
|
||||
let whiteListNormal: WhiteList | undefined;
|
||||
let whiteListSvg: WhiteList | undefined;
|
||||
let whiteListNormal: IWhiteList | undefined;
|
||||
let whiteListSvg: IWhiteList | undefined;
|
||||
|
||||
// Override the default `onTagAttr` behavior to only render
|
||||
// our markdown checkboxes.
|
||||
@ -43,7 +39,7 @@ const renderMarkdown = (
|
||||
): string => {
|
||||
if (!whiteListNormal) {
|
||||
whiteListNormal = {
|
||||
...(getDefaultWhiteList() as WhiteList),
|
||||
...getDefaultWhiteList(),
|
||||
input: ["type", "disabled", "checked"],
|
||||
"ha-icon": ["icon"],
|
||||
"ha-svg-icon": ["path"],
|
||||
@ -51,7 +47,7 @@ const renderMarkdown = (
|
||||
};
|
||||
}
|
||||
|
||||
let whiteList: WhiteList | undefined;
|
||||
let whiteList: IWhiteList | undefined;
|
||||
|
||||
if (hassOptions.allowSvg) {
|
||||
if (!whiteListSvg) {
|
||||
|
@ -2,6 +2,7 @@ import type { PropertyValues } from "lit";
|
||||
import tinykeys from "tinykeys";
|
||||
import { isComponentLoaded } from "../common/config/is_component_loaded";
|
||||
import { mainWindow } from "../common/dom/get_main_window";
|
||||
import { HaSelect } from "../components/ha-select";
|
||||
import {
|
||||
QuickBarParams,
|
||||
showQuickBar,
|
||||
@ -133,17 +134,17 @@ export default <T extends Constructor<HassElement>>(superClass: T) =>
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (el.parentElement.tagName === "HA-SELECT") {
|
||||
if (el instanceof Element && el.parentElement instanceof HaSelect) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (el.tagName !== "INPUT") {
|
||||
if (!(el instanceof HTMLInputElement)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -808,7 +808,7 @@
|
||||
"did_not_understand": "Didn't quite get that",
|
||||
"found": "I found the following for you:",
|
||||
"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",
|
||||
"send_text": "Send text",
|
||||
"start_listening": "Start listening"
|
||||
|
Loading…
x
Reference in New Issue
Block a user