mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-25 18:26:35 +00:00
20230223.0 (#15575)
This commit is contained in:
commit
dd6437376d
@ -60,7 +60,6 @@
|
|||||||
"no-restricted-globals": [2, "event"],
|
"no-restricted-globals": [2, "event"],
|
||||||
"prefer-promise-reject-errors": "off",
|
"prefer-promise-reject-errors": "off",
|
||||||
"no-unsafe-optional-chaining": "warn",
|
"no-unsafe-optional-chaining": "warn",
|
||||||
"prefer-regex-literals": ["warn"],
|
|
||||||
"import/prefer-default-export": "off",
|
"import/prefer-default-export": "off",
|
||||||
"import/no-default-export": "off",
|
"import/no-default-export": "off",
|
||||||
"import/no-unresolved": "off",
|
"import/no-unresolved": "off",
|
||||||
|
@ -252,6 +252,22 @@ export class HcMain extends HassElement {
|
|||||||
msg.urlPath = null;
|
msg.urlPath = null;
|
||||||
}
|
}
|
||||||
this._lovelacePath = msg.viewPath;
|
this._lovelacePath = msg.viewPath;
|
||||||
|
if (msg.urlPath === "energy") {
|
||||||
|
this._lovelaceConfig = {
|
||||||
|
views: [
|
||||||
|
{
|
||||||
|
strategy: {
|
||||||
|
type: "energy",
|
||||||
|
options: { show_date_selection: true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
this._urlPath = "energy";
|
||||||
|
this._lovelacePath = 0;
|
||||||
|
this._sendStatus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!this._unsubLovelace || this._urlPath !== msg.urlPath) {
|
if (!this._unsubLovelace || this._urlPath !== msg.urlPath) {
|
||||||
this._urlPath = msg.urlPath;
|
this._urlPath = msg.urlPath;
|
||||||
this._lovelaceConfig = undefined;
|
this._lovelaceConfig = undefined;
|
||||||
|
@ -66,7 +66,7 @@ const incrementalUnits = ["clients", "queries", "ads"];
|
|||||||
|
|
||||||
export const mockHistory = (mockHass: MockHomeAssistant) => {
|
export const mockHistory = (mockHass: MockHomeAssistant) => {
|
||||||
mockHass.mockAPI(
|
mockHass.mockAPI(
|
||||||
new RegExp("history/period/.+"),
|
/history\/period\/.+/,
|
||||||
(hass, _method, path, _parameters) => {
|
(hass, _method, path, _parameters) => {
|
||||||
const params = parseQuery<HistoryQueryParams>(path.split("?")[1]);
|
const params = parseQuery<HistoryQueryParams>(path.split("?")[1]);
|
||||||
const entities = params.filter_entity_id.split(",");
|
const entities = params.filter_entity_id.split(",");
|
||||||
|
@ -136,7 +136,7 @@ export class DemoAutomationDescribeAction extends LitElement {
|
|||||||
<div class="action">
|
<div class="action">
|
||||||
<span>
|
<span>
|
||||||
${this._action
|
${this._action
|
||||||
? describeAction(this.hass, this._action)
|
? describeAction(this.hass, [], this._action)
|
||||||
: "<invalid YAML>"}
|
: "<invalid YAML>"}
|
||||||
</span>
|
</span>
|
||||||
<ha-yaml-editor
|
<ha-yaml-editor
|
||||||
@ -149,7 +149,7 @@ export class DemoAutomationDescribeAction extends LitElement {
|
|||||||
${ACTIONS.map(
|
${ACTIONS.map(
|
||||||
(conf) => html`
|
(conf) => html`
|
||||||
<div class="action">
|
<div class="action">
|
||||||
<span>${describeAction(this.hass, conf as any)}</span>
|
<span>${describeAction(this.hass, [], conf as any)}</span>
|
||||||
<pre>${dump(conf)}</pre>
|
<pre>${dump(conf)}</pre>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
|
@ -71,7 +71,7 @@
|
|||||||
"@material/mwc-textfield": "^0.27.0",
|
"@material/mwc-textfield": "^0.27.0",
|
||||||
"@material/mwc-top-app-bar-fixed": "^0.27.0",
|
"@material/mwc-top-app-bar-fixed": "^0.27.0",
|
||||||
"@material/top-app-bar": "=14.0.0-canary.53b3cad2f.0",
|
"@material/top-app-bar": "=14.0.0-canary.53b3cad2f.0",
|
||||||
"@material/web": "=1.0.0-pre.2",
|
"@material/web": "=1.0.0-pre.3",
|
||||||
"@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",
|
||||||
@ -216,7 +216,7 @@
|
|||||||
"lint-staged": "^13.1.2",
|
"lint-staged": "^13.1.2",
|
||||||
"lit-analyzer": "^1.2.1",
|
"lit-analyzer": "^1.2.1",
|
||||||
"lodash.template": "^4.5.0",
|
"lodash.template": "^4.5.0",
|
||||||
"magic-string": "^0.29.0",
|
"magic-string": "^0.30.0",
|
||||||
"map-stream": "^0.0.7",
|
"map-stream": "^0.0.7",
|
||||||
"merge-stream": "^2.0.0",
|
"merge-stream": "^2.0.0",
|
||||||
"mocha": "^10.2.0",
|
"mocha": "^10.2.0",
|
||||||
|
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "home-assistant-frontend"
|
name = "home-assistant-frontend"
|
||||||
version = "20230222.0"
|
version = "20230223.0"
|
||||||
license = {text = "Apache-2.0"}
|
license = {text = "Apache-2.0"}
|
||||||
description = "The Home Assistant frontend"
|
description = "The Home Assistant frontend"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { HassEntity } from "home-assistant-js-websocket";
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
import { EntityRegistryEntry } from "../../data/entity_registry";
|
import { EntityRegistryDisplayEntry } from "../../data/entity_registry";
|
||||||
import { HomeAssistant } from "../../types";
|
import { HomeAssistant } from "../../types";
|
||||||
import { LocalizeFunc } from "../translations/localize";
|
import { LocalizeFunc } from "../translations/localize";
|
||||||
import { computeDomain } from "./compute_domain";
|
import { computeDomain } from "./compute_domain";
|
||||||
@ -15,7 +15,7 @@ export const computeAttributeValueDisplay = (
|
|||||||
const attributeValue =
|
const attributeValue =
|
||||||
value !== undefined ? value : stateObj.attributes[attribute];
|
value !== undefined ? value : stateObj.attributes[attribute];
|
||||||
const domain = computeDomain(entityId);
|
const domain = computeDomain(entityId);
|
||||||
const entity = entities[entityId] as EntityRegistryEntry | undefined;
|
const entity = entities[entityId] as EntityRegistryDisplayEntry | undefined;
|
||||||
const translationKey = entity?.translation_key;
|
const translationKey = entity?.translation_key;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -38,7 +38,7 @@ export const computeAttributeNameDisplay = (
|
|||||||
): string => {
|
): string => {
|
||||||
const entityId = stateObj.entity_id;
|
const entityId = stateObj.entity_id;
|
||||||
const domain = computeDomain(entityId);
|
const domain = computeDomain(entityId);
|
||||||
const entity = entities[entityId] as EntityRegistryEntry | undefined;
|
const entity = entities[entityId] as EntityRegistryDisplayEntry | undefined;
|
||||||
const translationKey = entity?.translation_key;
|
const translationKey = entity?.translation_key;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { HassEntity } from "home-assistant-js-websocket";
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
import { UNAVAILABLE, UNKNOWN } from "../../data/entity";
|
import { UNAVAILABLE, UNKNOWN } from "../../data/entity";
|
||||||
import { EntityRegistryEntry } from "../../data/entity_registry";
|
import { EntityRegistryDisplayEntry } from "../../data/entity_registry";
|
||||||
import { FrontendLocaleData } from "../../data/translation";
|
import { FrontendLocaleData } from "../../data/translation";
|
||||||
import {
|
import {
|
||||||
updateIsInstallingFromAttributes,
|
updateIsInstallingFromAttributes,
|
||||||
@ -49,7 +49,7 @@ export const computeStateDisplayFromEntityAttributes = (
|
|||||||
return localize(`state.default.${state}`);
|
return localize(`state.default.${state}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const entity = entities[entityId] as EntityRegistryEntry | undefined;
|
const entity = entities[entityId] as EntityRegistryDisplayEntry | undefined;
|
||||||
|
|
||||||
// Entities with a `unit_of_measurement` or `state_class` are numeric values and should use `formatNumber`
|
// Entities with a `unit_of_measurement` or `state_class` are numeric values and should use `formatNumber`
|
||||||
if (isNumericFromAttributes(attributes)) {
|
if (isNumericFromAttributes(attributes)) {
|
||||||
|
@ -2,7 +2,7 @@ import {
|
|||||||
HassEntity,
|
HassEntity,
|
||||||
HassEntityAttributeBase,
|
HassEntityAttributeBase,
|
||||||
} from "home-assistant-js-websocket";
|
} from "home-assistant-js-websocket";
|
||||||
import { EntityRegistryEntry } from "../../data/entity_registry";
|
import { EntityRegistryDisplayEntry } from "../../data/entity_registry";
|
||||||
import { FrontendLocaleData, NumberFormat } from "../../data/translation";
|
import { FrontendLocaleData, NumberFormat } from "../../data/translation";
|
||||||
import { round } from "./round";
|
import { round } from "./round";
|
||||||
|
|
||||||
@ -92,11 +92,9 @@ export const formatNumber = (
|
|||||||
*/
|
*/
|
||||||
export const getNumberFormatOptions = (
|
export const getNumberFormatOptions = (
|
||||||
entityState: HassEntity,
|
entityState: HassEntity,
|
||||||
entity?: EntityRegistryEntry
|
entity?: EntityRegistryDisplayEntry
|
||||||
): Intl.NumberFormatOptions | undefined => {
|
): Intl.NumberFormatOptions | undefined => {
|
||||||
const precision =
|
const precision = entity?.display_precision;
|
||||||
entity?.options?.sensor?.display_precision ??
|
|
||||||
entity?.options?.sensor?.suggested_display_precision;
|
|
||||||
if (precision != null) {
|
if (precision != null) {
|
||||||
return {
|
return {
|
||||||
maximumFractionDigits: precision,
|
maximumFractionDigits: precision,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const isTemplateRegex = new RegExp("{%|{{");
|
const isTemplateRegex = /{%|{{/;
|
||||||
|
|
||||||
export const isTemplate = (value: string): boolean =>
|
export const isTemplate = (value: string): boolean =>
|
||||||
isTemplateRegex.test(value);
|
isTemplateRegex.test(value);
|
||||||
|
@ -22,7 +22,7 @@ import {
|
|||||||
isNumericState,
|
isNumericState,
|
||||||
} from "../../common/number/format_number";
|
} from "../../common/number/format_number";
|
||||||
import { isUnavailableState, UNAVAILABLE, UNKNOWN } from "../../data/entity";
|
import { isUnavailableState, UNAVAILABLE, UNKNOWN } from "../../data/entity";
|
||||||
import { EntityRegistryEntry } from "../../data/entity_registry";
|
import { EntityRegistryDisplayEntry } from "../../data/entity_registry";
|
||||||
import { timerTimeRemaining } from "../../data/timer";
|
import { timerTimeRemaining } from "../../data/timer";
|
||||||
import { HomeAssistant } from "../../types";
|
import { HomeAssistant } from "../../types";
|
||||||
import "../ha-label-badge";
|
import "../ha-label-badge";
|
||||||
@ -160,7 +160,7 @@ export class HaStateLabelBadge extends LitElement {
|
|||||||
private _computeValue(
|
private _computeValue(
|
||||||
domain: string,
|
domain: string,
|
||||||
entityState: HassEntity,
|
entityState: HassEntity,
|
||||||
entry?: EntityRegistryEntry
|
entry?: EntityRegistryDisplayEntry
|
||||||
) {
|
) {
|
||||||
switch (domain) {
|
switch (domain) {
|
||||||
case "alarm_control_panel":
|
case "alarm_control_panel":
|
||||||
@ -200,7 +200,7 @@ export class HaStateLabelBadge extends LitElement {
|
|||||||
private _computeShowIcon(
|
private _computeShowIcon(
|
||||||
domain: string,
|
domain: string,
|
||||||
entityState: HassEntity,
|
entityState: HassEntity,
|
||||||
entry?: EntityRegistryEntry
|
entry?: EntityRegistryDisplayEntry
|
||||||
): boolean {
|
): boolean {
|
||||||
if (entityState.state === UNAVAILABLE) {
|
if (entityState.state === UNAVAILABLE) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -12,10 +12,11 @@ import {
|
|||||||
createAreaRegistryEntry,
|
createAreaRegistryEntry,
|
||||||
} from "../data/area_registry";
|
} from "../data/area_registry";
|
||||||
import {
|
import {
|
||||||
DeviceEntityLookup,
|
DeviceEntityDisplayLookup,
|
||||||
DeviceRegistryEntry,
|
DeviceRegistryEntry,
|
||||||
|
getDeviceEntityDisplayLookup,
|
||||||
} from "../data/device_registry";
|
} from "../data/device_registry";
|
||||||
import { EntityRegistryEntry } from "../data/entity_registry";
|
import { EntityRegistryDisplayEntry } from "../data/entity_registry";
|
||||||
import {
|
import {
|
||||||
showAlertDialog,
|
showAlertDialog,
|
||||||
showPromptDialog,
|
showPromptDialog,
|
||||||
@ -113,7 +114,7 @@ export class HaAreaPicker extends LitElement {
|
|||||||
(
|
(
|
||||||
areas: AreaRegistryEntry[],
|
areas: AreaRegistryEntry[],
|
||||||
devices: DeviceRegistryEntry[],
|
devices: DeviceRegistryEntry[],
|
||||||
entities: EntityRegistryEntry[],
|
entities: EntityRegistryDisplayEntry[],
|
||||||
includeDomains: this["includeDomains"],
|
includeDomains: this["includeDomains"],
|
||||||
excludeDomains: this["excludeDomains"],
|
excludeDomains: this["excludeDomains"],
|
||||||
includeDeviceClasses: this["includeDeviceClasses"],
|
includeDeviceClasses: this["includeDeviceClasses"],
|
||||||
@ -133,111 +134,107 @@ export class HaAreaPicker extends LitElement {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
const deviceEntityLookup: DeviceEntityLookup = {};
|
let deviceEntityLookup: DeviceEntityDisplayLookup = {};
|
||||||
let inputDevices: DeviceRegistryEntry[] | undefined;
|
let inputDevices: DeviceRegistryEntry[] | undefined;
|
||||||
let inputEntities: EntityRegistryEntry[] | undefined;
|
let inputEntities: EntityRegistryDisplayEntry[] | undefined;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
includeDomains ||
|
includeDomains ||
|
||||||
excludeDomains ||
|
excludeDomains ||
|
||||||
includeDeviceClasses ||
|
includeDeviceClasses ||
|
||||||
|
deviceFilter ||
|
||||||
entityFilter
|
entityFilter
|
||||||
) {
|
) {
|
||||||
for (const entity of entities) {
|
deviceEntityLookup = getDeviceEntityDisplayLookup(entities);
|
||||||
if (!entity.device_id) {
|
inputDevices = devices;
|
||||||
continue;
|
inputEntities = entities.filter((entity) => entity.area_id);
|
||||||
}
|
|
||||||
if (!(entity.device_id in deviceEntityLookup)) {
|
|
||||||
deviceEntityLookup[entity.device_id] = [];
|
|
||||||
}
|
|
||||||
deviceEntityLookup[entity.device_id].push(entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
inputDevices = devices;
|
|
||||||
inputEntities = entities.filter((entity) => entity.area_id);
|
|
||||||
|
|
||||||
if (includeDomains) {
|
if (includeDomains) {
|
||||||
inputDevices = inputDevices!.filter((device) => {
|
inputDevices = inputDevices!.filter((device) => {
|
||||||
const devEntities = deviceEntityLookup[device.id];
|
const devEntities = deviceEntityLookup[device.id];
|
||||||
if (!devEntities || !devEntities.length) {
|
if (!devEntities || !devEntities.length) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return deviceEntityLookup[device.id].some((entity) =>
|
return deviceEntityLookup[device.id].some((entity) =>
|
||||||
|
includeDomains.includes(computeDomain(entity.entity_id))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
inputEntities = inputEntities!.filter((entity) =>
|
||||||
includeDomains.includes(computeDomain(entity.entity_id))
|
includeDomains.includes(computeDomain(entity.entity_id))
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
inputEntities = inputEntities!.filter((entity) =>
|
|
||||||
includeDomains.includes(computeDomain(entity.entity_id))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (excludeDomains) {
|
if (excludeDomains) {
|
||||||
inputDevices = inputDevices!.filter((device) => {
|
inputDevices = inputDevices!.filter((device) => {
|
||||||
const devEntities = deviceEntityLookup[device.id];
|
const devEntities = deviceEntityLookup[device.id];
|
||||||
if (!devEntities || !devEntities.length) {
|
if (!devEntities || !devEntities.length) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return entities.every(
|
return entities.every(
|
||||||
|
(entity) =>
|
||||||
|
!excludeDomains.includes(computeDomain(entity.entity_id))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
inputEntities = inputEntities!.filter(
|
||||||
(entity) =>
|
(entity) =>
|
||||||
!excludeDomains.includes(computeDomain(entity.entity_id))
|
!excludeDomains.includes(computeDomain(entity.entity_id))
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
inputEntities = inputEntities!.filter(
|
|
||||||
(entity) => !excludeDomains.includes(computeDomain(entity.entity_id))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (includeDeviceClasses) {
|
if (includeDeviceClasses) {
|
||||||
inputDevices = inputDevices!.filter((device) => {
|
inputDevices = inputDevices!.filter((device) => {
|
||||||
const devEntities = deviceEntityLookup[device.id];
|
const devEntities = deviceEntityLookup[device.id];
|
||||||
if (!devEntities || !devEntities.length) {
|
if (!devEntities || !devEntities.length) {
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return deviceEntityLookup[device.id].some((entity) => {
|
|
||||||
const stateObj = this.hass.states[entity.entity_id];
|
|
||||||
if (!stateObj) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return deviceEntityLookup[device.id].some((entity) => {
|
||||||
|
const stateObj = this.hass.states[entity.entity_id];
|
||||||
|
if (!stateObj) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
stateObj.attributes.device_class &&
|
||||||
|
includeDeviceClasses.includes(stateObj.attributes.device_class)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
inputEntities = inputEntities!.filter((entity) => {
|
||||||
|
const stateObj = this.hass.states[entity.entity_id];
|
||||||
return (
|
return (
|
||||||
stateObj.attributes.device_class &&
|
stateObj.attributes.device_class &&
|
||||||
includeDeviceClasses.includes(stateObj.attributes.device_class)
|
includeDeviceClasses.includes(stateObj.attributes.device_class)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
inputEntities = inputEntities!.filter((entity) => {
|
|
||||||
const stateObj = this.hass.states[entity.entity_id];
|
if (deviceFilter) {
|
||||||
return (
|
inputDevices = inputDevices!.filter((device) =>
|
||||||
stateObj.attributes.device_class &&
|
deviceFilter!(device)
|
||||||
includeDeviceClasses.includes(stateObj.attributes.device_class)
|
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (deviceFilter) {
|
if (entityFilter) {
|
||||||
inputDevices = inputDevices!.filter((device) => deviceFilter!(device));
|
inputDevices = inputDevices!.filter((device) => {
|
||||||
}
|
const devEntities = deviceEntityLookup[device.id];
|
||||||
|
if (!devEntities || !devEntities.length) {
|
||||||
if (entityFilter) {
|
return false;
|
||||||
inputDevices = inputDevices!.filter((device) => {
|
}
|
||||||
const devEntities = deviceEntityLookup[device.id];
|
return deviceEntityLookup[device.id].some((entity) => {
|
||||||
if (!devEntities || !devEntities.length) {
|
const stateObj = this.hass.states[entity.entity_id];
|
||||||
return false;
|
if (!stateObj) {
|
||||||
}
|
return false;
|
||||||
return deviceEntityLookup[device.id].some((entity) => {
|
}
|
||||||
|
return entityFilter(stateObj);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
inputEntities = inputEntities!.filter((entity) => {
|
||||||
const stateObj = this.hass.states[entity.entity_id];
|
const stateObj = this.hass.states[entity.entity_id];
|
||||||
if (!stateObj) {
|
if (!stateObj) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return entityFilter(stateObj);
|
return entityFilter!(stateObj);
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
inputEntities = inputEntities!.filter((entity) => {
|
|
||||||
const stateObj = this.hass.states[entity.entity_id];
|
|
||||||
if (!stateObj) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return entityFilter!(stateObj);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let outputAreas = areas;
|
let outputAreas = areas;
|
||||||
|
@ -1,3 +1,10 @@
|
|||||||
|
import {
|
||||||
|
DIRECTION_HORIZONTAL,
|
||||||
|
DIRECTION_VERTICAL,
|
||||||
|
Manager,
|
||||||
|
Swipe,
|
||||||
|
Tap,
|
||||||
|
} from "@egjs/hammerjs";
|
||||||
import {
|
import {
|
||||||
css,
|
css,
|
||||||
CSSResultGroup,
|
CSSResultGroup,
|
||||||
@ -6,7 +13,7 @@ import {
|
|||||||
PropertyValues,
|
PropertyValues,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit";
|
} from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property, query } from "lit/decorators";
|
||||||
import { fireEvent } from "../common/dom/fire_event";
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
import "./ha-svg-icon";
|
import "./ha-svg-icon";
|
||||||
|
|
||||||
@ -30,8 +37,11 @@ export class HaControlSwitch extends LitElement {
|
|||||||
// SVG icon path (if you need a non SVG icon instead, use the provided off icon slot to pass an <ha-icon slot="icon-off"> in)
|
// SVG icon path (if you need a non SVG icon instead, use the provided off icon slot to pass an <ha-icon slot="icon-off"> in)
|
||||||
@property({ type: String }) pathOff?: string;
|
@property({ type: String }) pathOff?: string;
|
||||||
|
|
||||||
|
private _mc?: HammerManager;
|
||||||
|
|
||||||
protected firstUpdated(changedProperties: PropertyValues): void {
|
protected firstUpdated(changedProperties: PropertyValues): void {
|
||||||
super.firstUpdated(changedProperties);
|
super.firstUpdated(changedProperties);
|
||||||
|
this.setupListeners();
|
||||||
this.setAttribute("role", "switch");
|
this.setAttribute("role", "switch");
|
||||||
if (!this.hasAttribute("tabindex")) {
|
if (!this.hasAttribute("tabindex")) {
|
||||||
this.setAttribute("tabindex", "0");
|
this.setAttribute("tabindex", "0");
|
||||||
@ -53,14 +63,70 @@ export class HaControlSwitch extends LitElement {
|
|||||||
|
|
||||||
connectedCallback(): void {
|
connectedCallback(): void {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
this.addEventListener("keydown", this._keydown);
|
this.setupListeners();
|
||||||
this.addEventListener("click", this._toggle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnectedCallback(): void {
|
disconnectedCallback(): void {
|
||||||
super.disconnectedCallback();
|
super.disconnectedCallback();
|
||||||
|
this.destroyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
@query("#switch")
|
||||||
|
private switch!: HTMLDivElement;
|
||||||
|
|
||||||
|
setupListeners() {
|
||||||
|
if (this.switch && !this._mc) {
|
||||||
|
this._mc = new Manager(this.switch, {
|
||||||
|
touchAction: this.vertical ? "pan-x" : "pan-y",
|
||||||
|
});
|
||||||
|
this._mc.add(
|
||||||
|
new Swipe({
|
||||||
|
direction: this.vertical ? DIRECTION_VERTICAL : DIRECTION_HORIZONTAL,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
this._mc.add(new Tap({ event: "singletap" }));
|
||||||
|
|
||||||
|
if (this.vertical) {
|
||||||
|
this._mc.on("swipeup", () => {
|
||||||
|
if (this.disabled) return;
|
||||||
|
this.checked = !!this.reversed;
|
||||||
|
fireEvent(this, "change");
|
||||||
|
});
|
||||||
|
|
||||||
|
this._mc.on("swipedown", () => {
|
||||||
|
if (this.disabled) return;
|
||||||
|
this.checked = !this.reversed;
|
||||||
|
fireEvent(this, "change");
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this._mc.on("swiperight", () => {
|
||||||
|
if (this.disabled) return;
|
||||||
|
this.checked = !this.reversed;
|
||||||
|
fireEvent(this, "change");
|
||||||
|
});
|
||||||
|
|
||||||
|
this._mc.on("swipeleft", () => {
|
||||||
|
if (this.disabled) return;
|
||||||
|
this.checked = !!this.reversed;
|
||||||
|
fireEvent(this, "change");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this._mc.on("singletap", () => {
|
||||||
|
if (this.disabled) return;
|
||||||
|
this._toggle();
|
||||||
|
});
|
||||||
|
this.addEventListener("keydown", this._keydown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
destroyListeners() {
|
||||||
|
if (this._mc) {
|
||||||
|
this._mc.destroy();
|
||||||
|
this._mc = undefined;
|
||||||
|
}
|
||||||
this.removeEventListener("keydown", this._keydown);
|
this.removeEventListener("keydown", this._keydown);
|
||||||
this.removeEventListener("click", this._toggle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _keydown(ev: any) {
|
private _keydown(ev: any) {
|
||||||
@ -73,7 +139,7 @@ export class HaControlSwitch extends LitElement {
|
|||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<div class="switch">
|
<div id="switch" class="switch">
|
||||||
<div class="background"></div>
|
<div class="background"></div>
|
||||||
<div class="button" aria-hidden="true">
|
<div class="button" aria-hidden="true">
|
||||||
${this.checked
|
${this.checked
|
||||||
|
@ -45,6 +45,7 @@ export class HaDialog extends DialogBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
disconnectedCallback(): void {
|
disconnectedCallback(): void {
|
||||||
|
super.disconnectedCallback();
|
||||||
this.contentElement.removeEventListener("scroll", this._onScroll);
|
this.contentElement.removeEventListener("scroll", this._onScroll);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,9 @@ export class Gauge extends LitElement {
|
|||||||
|
|
||||||
@property({ type: Number }) public value = 0;
|
@property({ type: Number }) public value = 0;
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
public formatOptions?: Intl.NumberFormatOptions;
|
||||||
|
|
||||||
@property({ type: String }) public valueText?: string;
|
@property({ type: String }) public valueText?: string;
|
||||||
|
|
||||||
@property() public locale!: FrontendLocaleData;
|
@property() public locale!: FrontendLocaleData;
|
||||||
@ -132,7 +135,8 @@ export class Gauge extends LitElement {
|
|||||||
${
|
${
|
||||||
this._segment_label
|
this._segment_label
|
||||||
? this._segment_label
|
? this._segment_label
|
||||||
: this.valueText || formatNumber(this.value, this.locale)
|
: this.valueText ||
|
||||||
|
formatNumber(this.value, this.locale, this.formatOptions)
|
||||||
}${
|
}${
|
||||||
this._segment_label
|
this._segment_label
|
||||||
? ""
|
? ""
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
import { HassEntity, UnsubscribeFunc } from "home-assistant-js-websocket";
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { ensureArray } from "../../common/array/ensure-array";
|
import { ensureArray } from "../../common/array/ensure-array";
|
||||||
import type { DeviceRegistryEntry } from "../../data/device_registry";
|
import type { DeviceRegistryEntry } from "../../data/device_registry";
|
||||||
import { getDeviceIntegrationLookup } from "../../data/device_registry";
|
import { getDeviceIntegrationLookup } from "../../data/device_registry";
|
||||||
import {
|
|
||||||
EntityRegistryEntry,
|
|
||||||
subscribeEntityRegistry,
|
|
||||||
} from "../../data/entity_registry";
|
|
||||||
import {
|
import {
|
||||||
EntitySources,
|
EntitySources,
|
||||||
fetchEntitySourcesWithCache,
|
fetchEntitySourcesWithCache,
|
||||||
@ -18,13 +14,12 @@ import {
|
|||||||
filterSelectorDevices,
|
filterSelectorDevices,
|
||||||
filterSelectorEntities,
|
filterSelectorEntities,
|
||||||
} from "../../data/selector";
|
} from "../../data/selector";
|
||||||
import { SubscribeMixin } from "../../mixins/subscribe-mixin";
|
|
||||||
import { HomeAssistant } from "../../types";
|
import { HomeAssistant } from "../../types";
|
||||||
import "../ha-area-picker";
|
import "../ha-area-picker";
|
||||||
import "../ha-areas-picker";
|
import "../ha-areas-picker";
|
||||||
|
|
||||||
@customElement("ha-selector-area")
|
@customElement("ha-selector-area")
|
||||||
export class HaAreaSelector extends SubscribeMixin(LitElement) {
|
export class HaAreaSelector extends LitElement {
|
||||||
@property() public hass!: HomeAssistant;
|
@property() public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property() public selector!: AreaSelector;
|
@property() public selector!: AreaSelector;
|
||||||
@ -41,18 +36,8 @@ export class HaAreaSelector extends SubscribeMixin(LitElement) {
|
|||||||
|
|
||||||
@state() private _entitySources?: EntitySources;
|
@state() private _entitySources?: EntitySources;
|
||||||
|
|
||||||
@state() private _entities?: EntityRegistryEntry[];
|
|
||||||
|
|
||||||
private _deviceIntegrationLookup = memoizeOne(getDeviceIntegrationLookup);
|
private _deviceIntegrationLookup = memoizeOne(getDeviceIntegrationLookup);
|
||||||
|
|
||||||
public hassSubscribe(): UnsubscribeFunc[] {
|
|
||||||
return [
|
|
||||||
subscribeEntityRegistry(this.hass.connection!, (entities) => {
|
|
||||||
this._entities = entities.filter((entity) => entity.device_id !== null);
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
private _hasIntegration(selector: AreaSelector) {
|
private _hasIntegration(selector: AreaSelector) {
|
||||||
return (
|
return (
|
||||||
(selector.area?.entity &&
|
(selector.area?.entity &&
|
||||||
@ -127,10 +112,12 @@ export class HaAreaSelector extends SubscribeMixin(LitElement) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const deviceIntegrations =
|
const deviceIntegrations = this._entitySources
|
||||||
this._entitySources && this._entities
|
? this._deviceIntegrationLookup(
|
||||||
? this._deviceIntegrationLookup(this._entitySources, this._entities)
|
this._entitySources,
|
||||||
: undefined;
|
Object.values(this.hass.entities)
|
||||||
|
)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
return ensureArray(this.selector.area.device).some((filter) =>
|
return ensureArray(this.selector.area.device).some((filter) =>
|
||||||
filterSelectorDevices(filter, device, deviceIntegrations)
|
filterSelectorDevices(filter, device, deviceIntegrations)
|
||||||
|
@ -2,12 +2,11 @@ import { html, LitElement, PropertyValues } from "lit";
|
|||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
import { AttributeSelector } from "../../data/selector";
|
import { AttributeSelector } from "../../data/selector";
|
||||||
import { SubscribeMixin } from "../../mixins/subscribe-mixin";
|
|
||||||
import { HomeAssistant } from "../../types";
|
import { HomeAssistant } from "../../types";
|
||||||
import "../entity/ha-entity-attribute-picker";
|
import "../entity/ha-entity-attribute-picker";
|
||||||
|
|
||||||
@customElement("ha-selector-attribute")
|
@customElement("ha-selector-attribute")
|
||||||
export class HaSelectorAttribute extends SubscribeMixin(LitElement) {
|
export class HaSelectorAttribute extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public selector!: AttributeSelector;
|
@property({ attribute: false }) public selector!: AttributeSelector;
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
import { HassEntity, UnsubscribeFunc } from "home-assistant-js-websocket";
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
import { html, LitElement } from "lit";
|
import { html, LitElement } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { ensureArray } from "../../common/array/ensure-array";
|
import { ensureArray } from "../../common/array/ensure-array";
|
||||||
import type { DeviceRegistryEntry } from "../../data/device_registry";
|
import type { DeviceRegistryEntry } from "../../data/device_registry";
|
||||||
import { getDeviceIntegrationLookup } from "../../data/device_registry";
|
import { getDeviceIntegrationLookup } from "../../data/device_registry";
|
||||||
import {
|
|
||||||
EntityRegistryEntry,
|
|
||||||
subscribeEntityRegistry,
|
|
||||||
} from "../../data/entity_registry";
|
|
||||||
import {
|
import {
|
||||||
EntitySources,
|
EntitySources,
|
||||||
fetchEntitySourcesWithCache,
|
fetchEntitySourcesWithCache,
|
||||||
@ -18,21 +14,18 @@ import {
|
|||||||
filterSelectorDevices,
|
filterSelectorDevices,
|
||||||
filterSelectorEntities,
|
filterSelectorEntities,
|
||||||
} from "../../data/selector";
|
} from "../../data/selector";
|
||||||
import { SubscribeMixin } from "../../mixins/subscribe-mixin";
|
|
||||||
import type { HomeAssistant } from "../../types";
|
import type { HomeAssistant } from "../../types";
|
||||||
import "../device/ha-device-picker";
|
import "../device/ha-device-picker";
|
||||||
import "../device/ha-devices-picker";
|
import "../device/ha-devices-picker";
|
||||||
|
|
||||||
@customElement("ha-selector-device")
|
@customElement("ha-selector-device")
|
||||||
export class HaDeviceSelector extends SubscribeMixin(LitElement) {
|
export class HaDeviceSelector extends LitElement {
|
||||||
@property() public hass!: HomeAssistant;
|
@property() public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property() public selector!: DeviceSelector;
|
@property() public selector!: DeviceSelector;
|
||||||
|
|
||||||
@state() private _entitySources?: EntitySources;
|
@state() private _entitySources?: EntitySources;
|
||||||
|
|
||||||
@state() private _entities?: EntityRegistryEntry[];
|
|
||||||
|
|
||||||
@property() public value?: any;
|
@property() public value?: any;
|
||||||
|
|
||||||
@property() public label?: string;
|
@property() public label?: string;
|
||||||
@ -45,14 +38,6 @@ export class HaDeviceSelector extends SubscribeMixin(LitElement) {
|
|||||||
|
|
||||||
private _deviceIntegrationLookup = memoizeOne(getDeviceIntegrationLookup);
|
private _deviceIntegrationLookup = memoizeOne(getDeviceIntegrationLookup);
|
||||||
|
|
||||||
public hassSubscribe(): UnsubscribeFunc[] {
|
|
||||||
return [
|
|
||||||
subscribeEntityRegistry(this.hass.connection!, (entities) => {
|
|
||||||
this._entities = entities.filter((entity) => entity.device_id !== null);
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
private _hasIntegration(selector: DeviceSelector) {
|
private _hasIntegration(selector: DeviceSelector) {
|
||||||
return (
|
return (
|
||||||
(selector.device?.filter &&
|
(selector.device?.filter &&
|
||||||
@ -118,10 +103,12 @@ export class HaDeviceSelector extends SubscribeMixin(LitElement) {
|
|||||||
if (!this.selector.device?.filter) {
|
if (!this.selector.device?.filter) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const deviceIntegrations =
|
const deviceIntegrations = this._entitySources
|
||||||
this._entitySources && this._entities
|
? this._deviceIntegrationLookup(
|
||||||
? this._deviceIntegrationLookup(this._entitySources, this._entities)
|
this._entitySources,
|
||||||
: undefined;
|
Object.values(this.hass.entities)
|
||||||
|
)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
return ensureArray(this.selector.device.filter).some((filter) =>
|
return ensureArray(this.selector.device.filter).some((filter) =>
|
||||||
filterSelectorDevices(filter, device, deviceIntegrations)
|
filterSelectorDevices(filter, device, deviceIntegrations)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import chipStyles from "@material/chips/dist/mdc.chips.min.css";
|
import chipStyles from "@material/chips/dist/mdc.chips.min.css";
|
||||||
import "@material/mwc-button/mwc-button";
|
import "@material/mwc-button/mwc-button";
|
||||||
|
import "@material/mwc-menu/mwc-menu-surface";
|
||||||
import {
|
import {
|
||||||
mdiClose,
|
mdiClose,
|
||||||
mdiDevices,
|
mdiDevices,
|
||||||
@ -9,13 +10,14 @@ import {
|
|||||||
mdiUnfoldMoreVertical,
|
mdiUnfoldMoreVertical,
|
||||||
} from "@mdi/js";
|
} from "@mdi/js";
|
||||||
import "@polymer/paper-tooltip/paper-tooltip";
|
import "@polymer/paper-tooltip/paper-tooltip";
|
||||||
|
import { ComboBoxLightOpenedChangedEvent } from "@vaadin/combo-box/vaadin-combo-box-light";
|
||||||
import { HassEntity, HassServiceTarget } from "home-assistant-js-websocket";
|
import { HassEntity, HassServiceTarget } from "home-assistant-js-websocket";
|
||||||
import { css, CSSResultGroup, html, LitElement, unsafeCSS } from "lit";
|
import { css, CSSResultGroup, html, LitElement, unsafeCSS } from "lit";
|
||||||
import { customElement, property, query, state } from "lit/decorators";
|
import { customElement, property, query, state } from "lit/decorators";
|
||||||
import { classMap } from "lit/directives/class-map";
|
import { classMap } from "lit/directives/class-map";
|
||||||
import { ComboBoxLightOpenedChangedEvent } from "@vaadin/combo-box/vaadin-combo-box-light";
|
|
||||||
import { ensureArray } from "../common/array/ensure-array";
|
import { ensureArray } from "../common/array/ensure-array";
|
||||||
import { fireEvent } from "../common/dom/fire_event";
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
|
import { stopPropagation } from "../common/dom/stop_propagation";
|
||||||
import { computeDomain } from "../common/entity/compute_domain";
|
import { computeDomain } from "../common/entity/compute_domain";
|
||||||
import { computeStateName } from "../common/entity/compute_state_name";
|
import { computeStateName } from "../common/entity/compute_state_name";
|
||||||
import { isValidEntityId } from "../common/entity/valid_entity_id";
|
import { isValidEntityId } from "../common/entity/valid_entity_id";
|
||||||
@ -23,7 +25,7 @@ import {
|
|||||||
computeDeviceName,
|
computeDeviceName,
|
||||||
DeviceRegistryEntry,
|
DeviceRegistryEntry,
|
||||||
} from "../data/device_registry";
|
} from "../data/device_registry";
|
||||||
import { EntityRegistryEntry } from "../data/entity_registry";
|
import { EntityRegistryDisplayEntry } from "../data/entity_registry";
|
||||||
import { HomeAssistant } from "../types";
|
import { HomeAssistant } from "../types";
|
||||||
import "./device/ha-device-picker";
|
import "./device/ha-device-picker";
|
||||||
import type { HaDevicePickerDeviceFilterFunc } from "./device/ha-device-picker";
|
import type { HaDevicePickerDeviceFilterFunc } from "./device/ha-device-picker";
|
||||||
@ -33,8 +35,6 @@ import "./ha-area-picker";
|
|||||||
import "./ha-icon-button";
|
import "./ha-icon-button";
|
||||||
import "./ha-input-helper-text";
|
import "./ha-input-helper-text";
|
||||||
import "./ha-svg-icon";
|
import "./ha-svg-icon";
|
||||||
import { stopPropagation } from "../common/dom/stop_propagation";
|
|
||||||
import "@material/mwc-menu/mwc-menu-surface";
|
|
||||||
|
|
||||||
@customElement("ha-target-picker")
|
@customElement("ha-target-picker")
|
||||||
export class HaTargetPicker extends LitElement {
|
export class HaTargetPicker extends LitElement {
|
||||||
@ -551,7 +551,7 @@ export class HaTargetPicker extends LitElement {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _entityRegMeetsFilter(entity: EntityRegistryEntry): boolean {
|
private _entityRegMeetsFilter(entity: EntityRegistryDisplayEntry): boolean {
|
||||||
if (entity.entity_category) {
|
if (entity.entity_category) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import {
|
|||||||
mdiProgressWrench,
|
mdiProgressWrench,
|
||||||
mdiRecordCircleOutline,
|
mdiRecordCircleOutline,
|
||||||
} from "@mdi/js";
|
} from "@mdi/js";
|
||||||
|
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||||
import {
|
import {
|
||||||
css,
|
css,
|
||||||
CSSResultGroup,
|
CSSResultGroup,
|
||||||
@ -14,12 +15,16 @@ import {
|
|||||||
PropertyValues,
|
PropertyValues,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit";
|
} from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { ifDefined } from "lit/directives/if-defined";
|
import { ifDefined } from "lit/directives/if-defined";
|
||||||
import { formatDateTimeWithSeconds } from "../../common/datetime/format_date_time";
|
import { formatDateTimeWithSeconds } from "../../common/datetime/format_date_time";
|
||||||
import { relativeTime } from "../../common/datetime/relative_time";
|
import { relativeTime } from "../../common/datetime/relative_time";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
import { toggleAttribute } from "../../common/dom/toggle_attribute";
|
import { toggleAttribute } from "../../common/dom/toggle_attribute";
|
||||||
|
import {
|
||||||
|
EntityRegistryEntry,
|
||||||
|
subscribeEntityRegistry,
|
||||||
|
} from "../../data/entity_registry";
|
||||||
import { LogbookEntry } from "../../data/logbook";
|
import { LogbookEntry } from "../../data/logbook";
|
||||||
import {
|
import {
|
||||||
ChooseAction,
|
ChooseAction,
|
||||||
@ -193,6 +198,7 @@ class ActionRenderer {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private hass: HomeAssistant,
|
private hass: HomeAssistant,
|
||||||
|
private entityReg: EntityRegistryEntry[],
|
||||||
private entries: TemplateResult[],
|
private entries: TemplateResult[],
|
||||||
private trace: AutomationTraceExtended,
|
private trace: AutomationTraceExtended,
|
||||||
private logbookRenderer: LogbookRenderer,
|
private logbookRenderer: LogbookRenderer,
|
||||||
@ -298,7 +304,7 @@ class ActionRenderer {
|
|||||||
|
|
||||||
this._renderEntry(
|
this._renderEntry(
|
||||||
path,
|
path,
|
||||||
describeAction(this.hass, data, actionType),
|
describeAction(this.hass, this.entityReg, data, actionType),
|
||||||
undefined,
|
undefined,
|
||||||
data.enabled === false
|
data.enabled === false
|
||||||
);
|
);
|
||||||
@ -441,7 +447,9 @@ class ActionRenderer {
|
|||||||
) as RepeatAction;
|
) as RepeatAction;
|
||||||
const disabled = repeatConfig.enabled === false;
|
const disabled = repeatConfig.enabled === false;
|
||||||
|
|
||||||
const name = repeatConfig.alias || describeAction(this.hass, repeatConfig);
|
const name =
|
||||||
|
repeatConfig.alias ||
|
||||||
|
describeAction(this.hass, this.entityReg, repeatConfig);
|
||||||
|
|
||||||
this._renderEntry(repeatPath, name, undefined, disabled);
|
this._renderEntry(repeatPath, name, undefined, disabled);
|
||||||
|
|
||||||
@ -577,6 +585,16 @@ export class HaAutomationTracer extends LitElement {
|
|||||||
|
|
||||||
@property({ type: Boolean }) public allowPick = false;
|
@property({ type: Boolean }) public allowPick = false;
|
||||||
|
|
||||||
|
@state() private _entityReg: EntityRegistryEntry[] = [];
|
||||||
|
|
||||||
|
public hassSubscribe(): UnsubscribeFunc[] {
|
||||||
|
return [
|
||||||
|
subscribeEntityRegistry(this.hass.connection!, (entities) => {
|
||||||
|
this._entityReg = entities;
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (!this.trace) {
|
if (!this.trace) {
|
||||||
return html``;
|
return html``;
|
||||||
@ -592,6 +610,7 @@ export class HaAutomationTracer extends LitElement {
|
|||||||
);
|
);
|
||||||
const actionRenderer = new ActionRenderer(
|
const actionRenderer = new ActionRenderer(
|
||||||
this.hass,
|
this.hass,
|
||||||
|
this._entityReg,
|
||||||
entries,
|
entries,
|
||||||
this.trace,
|
this.trace,
|
||||||
logbookRenderer,
|
logbookRenderer,
|
||||||
|
@ -4,7 +4,10 @@ import { computeStateName } from "../common/entity/compute_state_name";
|
|||||||
import { caseInsensitiveStringCompare } from "../common/string/compare";
|
import { caseInsensitiveStringCompare } from "../common/string/compare";
|
||||||
import { debounce } from "../common/util/debounce";
|
import { debounce } from "../common/util/debounce";
|
||||||
import type { HomeAssistant } from "../types";
|
import type { HomeAssistant } from "../types";
|
||||||
import type { EntityRegistryEntry } from "./entity_registry";
|
import type {
|
||||||
|
EntityRegistryDisplayEntry,
|
||||||
|
EntityRegistryEntry,
|
||||||
|
} from "./entity_registry";
|
||||||
import type { EntitySources } from "./entity_sources";
|
import type { EntitySources } from "./entity_sources";
|
||||||
|
|
||||||
export interface DeviceRegistryEntry {
|
export interface DeviceRegistryEntry {
|
||||||
@ -25,6 +28,10 @@ export interface DeviceRegistryEntry {
|
|||||||
configuration_url: string | null;
|
configuration_url: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface DeviceEntityDisplayLookup {
|
||||||
|
[deviceId: string]: EntityRegistryDisplayEntry[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface DeviceEntityLookup {
|
export interface DeviceEntityLookup {
|
||||||
[deviceId: string]: EntityRegistryEntry[];
|
[deviceId: string]: EntityRegistryEntry[];
|
||||||
}
|
}
|
||||||
@ -147,9 +154,25 @@ export const getDeviceEntityLookup = (
|
|||||||
return deviceEntityLookup;
|
return deviceEntityLookup;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getDeviceEntityDisplayLookup = (
|
||||||
|
entities: EntityRegistryDisplayEntry[]
|
||||||
|
): DeviceEntityDisplayLookup => {
|
||||||
|
const deviceEntityLookup: DeviceEntityDisplayLookup = {};
|
||||||
|
for (const entity of entities) {
|
||||||
|
if (!entity.device_id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!(entity.device_id in deviceEntityLookup)) {
|
||||||
|
deviceEntityLookup[entity.device_id] = [];
|
||||||
|
}
|
||||||
|
deviceEntityLookup[entity.device_id].push(entity);
|
||||||
|
}
|
||||||
|
return deviceEntityLookup;
|
||||||
|
};
|
||||||
|
|
||||||
export const getDeviceIntegrationLookup = (
|
export const getDeviceIntegrationLookup = (
|
||||||
entitySources: EntitySources,
|
entitySources: EntitySources,
|
||||||
entities: EntityRegistryEntry[]
|
entities: EntityRegistryDisplayEntry[]
|
||||||
): Record<string, string[]> => {
|
): Record<string, string[]> => {
|
||||||
const deviceIntegrations: Record<string, string[]> = {};
|
const deviceIntegrations: Record<string, string[]> = {};
|
||||||
|
|
||||||
|
@ -6,6 +6,35 @@ import { caseInsensitiveStringCompare } from "../common/string/compare";
|
|||||||
import { debounce } from "../common/util/debounce";
|
import { debounce } from "../common/util/debounce";
|
||||||
import { HomeAssistant } from "../types";
|
import { HomeAssistant } from "../types";
|
||||||
|
|
||||||
|
type entityCategory = "config" | "diagnostic";
|
||||||
|
|
||||||
|
export interface EntityRegistryDisplayEntry {
|
||||||
|
entity_id: string;
|
||||||
|
name?: string;
|
||||||
|
device_id?: string;
|
||||||
|
area_id?: string;
|
||||||
|
hidden?: boolean;
|
||||||
|
entity_category?: entityCategory;
|
||||||
|
translation_key?: string;
|
||||||
|
platform?: string;
|
||||||
|
display_precision?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EntityRegistryDisplayEntryResponse {
|
||||||
|
entities: {
|
||||||
|
ei: string;
|
||||||
|
di?: string;
|
||||||
|
ai?: string;
|
||||||
|
ec?: number;
|
||||||
|
en?: string;
|
||||||
|
pl?: string;
|
||||||
|
tk?: string;
|
||||||
|
hb?: boolean;
|
||||||
|
dp?: number;
|
||||||
|
}[];
|
||||||
|
entity_categories: Record<number, entityCategory>;
|
||||||
|
}
|
||||||
|
|
||||||
export interface EntityRegistryEntry {
|
export interface EntityRegistryEntry {
|
||||||
id: string;
|
id: string;
|
||||||
entity_id: string;
|
entity_id: string;
|
||||||
@ -17,7 +46,7 @@ export interface EntityRegistryEntry {
|
|||||||
area_id: string | null;
|
area_id: string | null;
|
||||||
disabled_by: "user" | "device" | "integration" | "config_entry" | null;
|
disabled_by: "user" | "device" | "integration" | "config_entry" | null;
|
||||||
hidden_by: Exclude<EntityRegistryEntry["disabled_by"], "config_entry">;
|
hidden_by: Exclude<EntityRegistryEntry["disabled_by"], "config_entry">;
|
||||||
entity_category: "config" | "diagnostic" | null;
|
entity_category: entityCategory | null;
|
||||||
has_entity_name: boolean;
|
has_entity_name: boolean;
|
||||||
original_name?: string;
|
original_name?: string;
|
||||||
unique_id: string;
|
unique_id: string;
|
||||||
@ -154,6 +183,11 @@ export const fetchEntityRegistry = (conn: Connection) =>
|
|||||||
type: "config/entity_registry/list",
|
type: "config/entity_registry/list",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const fetchEntityRegistryDisplay = (conn: Connection) =>
|
||||||
|
conn.sendMessagePromise<EntityRegistryDisplayEntryResponse>({
|
||||||
|
type: "config/entity_registry/list_for_display",
|
||||||
|
});
|
||||||
|
|
||||||
const subscribeEntityRegistryUpdates = (
|
const subscribeEntityRegistryUpdates = (
|
||||||
conn: Connection,
|
conn: Connection,
|
||||||
store: Store<EntityRegistryEntry[]>
|
store: Store<EntityRegistryEntry[]>
|
||||||
@ -182,6 +216,34 @@ export const subscribeEntityRegistry = (
|
|||||||
onChange
|
onChange
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const subscribeEntityRegistryDisplayUpdates = (
|
||||||
|
conn: Connection,
|
||||||
|
store: Store<EntityRegistryDisplayEntryResponse>
|
||||||
|
) =>
|
||||||
|
conn.subscribeEvents(
|
||||||
|
debounce(
|
||||||
|
() =>
|
||||||
|
fetchEntityRegistryDisplay(conn).then((entities) =>
|
||||||
|
store.setState(entities, true)
|
||||||
|
),
|
||||||
|
500,
|
||||||
|
true
|
||||||
|
),
|
||||||
|
"entity_registry_updated"
|
||||||
|
);
|
||||||
|
|
||||||
|
export const subscribeEntityRegistryDisplay = (
|
||||||
|
conn: Connection,
|
||||||
|
onChange: (entities: EntityRegistryDisplayEntryResponse) => void
|
||||||
|
) =>
|
||||||
|
createCollection<EntityRegistryDisplayEntryResponse>(
|
||||||
|
"_entityRegistryDisplay",
|
||||||
|
fetchEntityRegistryDisplay,
|
||||||
|
subscribeEntityRegistryDisplayUpdates,
|
||||||
|
conn,
|
||||||
|
onChange
|
||||||
|
);
|
||||||
|
|
||||||
export const sortEntityRegistryByName = (
|
export const sortEntityRegistryByName = (
|
||||||
entries: EntityRegistryEntry[],
|
entries: EntityRegistryEntry[],
|
||||||
language: string
|
language: string
|
||||||
@ -190,10 +252,20 @@ export const sortEntityRegistryByName = (
|
|||||||
caseInsensitiveStringCompare(entry1.name || "", entry2.name || "", language)
|
caseInsensitiveStringCompare(entry1.name || "", entry2.name || "", language)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const entityRegistryByEntityId = memoizeOne(
|
||||||
|
(entries: EntityRegistryEntry[]) => {
|
||||||
|
const entities: Record<string, EntityRegistryEntry> = {};
|
||||||
|
for (const entity of entries) {
|
||||||
|
entities[entity.entity_id] = entity;
|
||||||
|
}
|
||||||
|
return entities;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
export const entityRegistryById = memoizeOne(
|
export const entityRegistryById = memoizeOne(
|
||||||
(entries: HomeAssistant["entities"]) => {
|
(entries: EntityRegistryEntry[]) => {
|
||||||
const entities: HomeAssistant["entities"] = {};
|
const entities: Record<string, EntityRegistryEntry> = {};
|
||||||
for (const entity of Object.values(entries)) {
|
for (const entity of entries) {
|
||||||
entities[entity.id] = entity;
|
entities[entity.id] = entity;
|
||||||
}
|
}
|
||||||
return entities;
|
return entities;
|
||||||
|
@ -11,6 +11,7 @@ import { computeDeviceName } from "./device_registry";
|
|||||||
import {
|
import {
|
||||||
computeEntityRegistryName,
|
computeEntityRegistryName,
|
||||||
entityRegistryById,
|
entityRegistryById,
|
||||||
|
EntityRegistryEntry,
|
||||||
} from "./entity_registry";
|
} from "./entity_registry";
|
||||||
import { domainToName } from "./integration";
|
import { domainToName } from "./integration";
|
||||||
import {
|
import {
|
||||||
@ -33,6 +34,7 @@ import {
|
|||||||
|
|
||||||
export const describeAction = <T extends ActionType>(
|
export const describeAction = <T extends ActionType>(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
entityRegistry: EntityRegistryEntry[],
|
||||||
action: ActionTypes[T],
|
action: ActionTypes[T],
|
||||||
actionType?: T,
|
actionType?: T,
|
||||||
ignoreAlias = false
|
ignoreAlias = false
|
||||||
@ -91,7 +93,7 @@ export const describeAction = <T extends ActionType>(
|
|||||||
targets.push(targetThing);
|
targets.push(targetThing);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const entityReg = entityRegistryById(hass.entities)[targetThing];
|
const entityReg = entityRegistryById(entityRegistry)[targetThing];
|
||||||
if (entityReg) {
|
if (entityReg) {
|
||||||
targets.push(
|
targets.push(
|
||||||
computeEntityRegistryName(hass, entityReg) || targetThing
|
computeEntityRegistryName(hass, entityReg) || targetThing
|
||||||
|
@ -26,12 +26,9 @@ export interface ThreadRouterDiscoveryEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class DiscoveryStream {
|
class DiscoveryStream {
|
||||||
hass: HomeAssistant;
|
|
||||||
|
|
||||||
routers: { [key: string]: ThreadRouter };
|
routers: { [key: string]: ThreadRouter };
|
||||||
|
|
||||||
constructor(hass: HomeAssistant) {
|
constructor() {
|
||||||
this.hass = hass;
|
|
||||||
this.routers = {};
|
this.routers = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +46,7 @@ export const subscribeDiscoverThreadRouters = (
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
callbackFunction: (routers: ThreadRouter[]) => void
|
callbackFunction: (routers: ThreadRouter[]) => void
|
||||||
) => {
|
) => {
|
||||||
const stream = new DiscoveryStream(hass);
|
const stream = new DiscoveryStream();
|
||||||
return hass.connection.subscribeMessage<ThreadRouterDiscoveryEvent>(
|
return hass.connection.subscribeMessage<ThreadRouterDiscoveryEvent>(
|
||||||
(message) => callbackFunction(stream.processEvent(message)),
|
(message) => callbackFunction(stream.processEvent(message)),
|
||||||
{
|
{
|
||||||
|
@ -757,10 +757,14 @@ export const fetchZwaveNodeFirmwareUpdateCapabilities = (
|
|||||||
export const uploadFirmwareAndBeginUpdate = async (
|
export const uploadFirmwareAndBeginUpdate = async (
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
device_id: string,
|
device_id: string,
|
||||||
file: File
|
file: File,
|
||||||
|
target?: number
|
||||||
) => {
|
) => {
|
||||||
const fd = new FormData();
|
const fd = new FormData();
|
||||||
fd.append("file", file);
|
fd.append("file", file);
|
||||||
|
if (target !== undefined) {
|
||||||
|
fd.append("target", target.toString());
|
||||||
|
}
|
||||||
const resp = await hass.fetchWithAuth(
|
const resp = await hass.fetchWithAuth(
|
||||||
`/api/zwave_js/firmware/upload/${device_id}`,
|
`/api/zwave_js/firmware/upload/${device_id}`,
|
||||||
{
|
{
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
import { css } from "lit";
|
||||||
|
|
||||||
|
export const moreInfoControlStyle = css`
|
||||||
|
:host {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls > *:not(:last-child) {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ha-attributes {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
`;
|
@ -23,7 +23,6 @@ import {
|
|||||||
lightSupportsColor,
|
lightSupportsColor,
|
||||||
lightSupportsColorMode,
|
lightSupportsColorMode,
|
||||||
} from "../../../../data/light";
|
} from "../../../../data/light";
|
||||||
import { haStyleDialog } from "../../../../resources/styles";
|
|
||||||
import { HomeAssistant } from "../../../../types";
|
import { HomeAssistant } from "../../../../types";
|
||||||
import { LightColorPickerViewParams } from "./show-view-light-color-picker";
|
import { LightColorPickerViewParams } from "./show-view-light-color-picker";
|
||||||
|
|
||||||
@ -78,117 +77,115 @@ class MoreInfoViewLightColorPicker extends LitElement {
|
|||||||
lightSupportsColorMode(this.stateObj, LightColorMode.RGBW);
|
lightSupportsColorMode(this.stateObj, LightColorMode.RGBW);
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div>
|
${this._modes.length > 1
|
||||||
${this._modes.length > 1
|
? html`
|
||||||
|
<mwc-tab-bar
|
||||||
|
.activeIndex=${this._mode ? this._modes.indexOf(this._mode) : 0}
|
||||||
|
@MDCTabBar:activated=${this._handleTabChanged}
|
||||||
|
>
|
||||||
|
${this._modes.map(
|
||||||
|
(value) =>
|
||||||
|
html`<mwc-tab
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
`ui.dialogs.more_info_control.light.color_picker.mode.${value}`
|
||||||
|
)}
|
||||||
|
></mwc-tab>`
|
||||||
|
)}
|
||||||
|
</mwc-tab-bar>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
<div class="content">
|
||||||
|
${this._mode === LightColorMode.COLOR_TEMP
|
||||||
? html`
|
? html`
|
||||||
<mwc-tab-bar
|
<ha-control-slider
|
||||||
.activeIndex=${this._mode ? this._modes.indexOf(this._mode) : 0}
|
vertical
|
||||||
@MDCTabBar:activated=${this._handleTabChanged}
|
class="color_temp"
|
||||||
|
label=${this.hass.localize("ui.card.light.color_temperature")}
|
||||||
|
min="1"
|
||||||
|
max="100"
|
||||||
|
mode="cursor"
|
||||||
|
.value=${this._ctSliderValue}
|
||||||
|
@value-changed=${this._ctSliderChanged}
|
||||||
|
.min=${this.stateObj.attributes.min_color_temp_kelvin!}
|
||||||
|
.max=${this.stateObj.attributes.max_color_temp_kelvin!}
|
||||||
>
|
>
|
||||||
${this._modes.map(
|
</ha-control-slider>
|
||||||
(value) =>
|
|
||||||
html`<mwc-tab
|
|
||||||
.label=${this.hass.localize(
|
|
||||||
`ui.dialogs.more_info_control.light.color_picker.mode.${value}`
|
|
||||||
)}
|
|
||||||
></mwc-tab>`
|
|
||||||
)}
|
|
||||||
</mwc-tab-bar>
|
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
<div class="content">
|
${this._mode === "color"
|
||||||
${this._mode === LightColorMode.COLOR_TEMP
|
? html`
|
||||||
? html`
|
<div class="segmentationContainer">
|
||||||
<ha-control-slider
|
<ha-color-picker
|
||||||
vertical
|
class="color"
|
||||||
class="color_temp"
|
@colorselected=${this._colorPicked}
|
||||||
label=${this.hass.localize("ui.card.light.color_temperature")}
|
.desiredRgbColor=${this._colorPickerColor}
|
||||||
min="1"
|
throttle="500"
|
||||||
max="100"
|
.hueSegments=${this._hueSegments}
|
||||||
mode="cursor"
|
.saturationSegments=${this._saturationSegments}
|
||||||
.value=${this._ctSliderValue}
|
|
||||||
@value-changed=${this._ctSliderChanged}
|
|
||||||
.min=${this.stateObj.attributes.min_color_temp_kelvin!}
|
|
||||||
.max=${this.stateObj.attributes.max_color_temp_kelvin!}
|
|
||||||
>
|
>
|
||||||
</ha-control-slider>
|
</ha-color-picker>
|
||||||
`
|
<ha-icon-button
|
||||||
: ""}
|
.path=${mdiPalette}
|
||||||
${this._mode === "color"
|
@click=${this._segmentClick}
|
||||||
? html`
|
class="segmentationButton"
|
||||||
<div class="segmentationContainer">
|
></ha-icon-button>
|
||||||
<ha-color-picker
|
</div>
|
||||||
class="color"
|
|
||||||
@colorselected=${this._colorPicked}
|
|
||||||
.desiredRgbColor=${this._colorPickerColor}
|
|
||||||
throttle="500"
|
|
||||||
.hueSegments=${this._hueSegments}
|
|
||||||
.saturationSegments=${this._saturationSegments}
|
|
||||||
>
|
|
||||||
</ha-color-picker>
|
|
||||||
<ha-icon-button
|
|
||||||
.path=${mdiPalette}
|
|
||||||
@click=${this._segmentClick}
|
|
||||||
class="segmentationButton"
|
|
||||||
></ha-icon-button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
${supportsRgbw || supportsRgbww
|
${supportsRgbw || supportsRgbww
|
||||||
? html`<ha-labeled-slider
|
? html`<ha-labeled-slider
|
||||||
|
.caption=${this.hass.localize(
|
||||||
|
"ui.card.light.color_brightness"
|
||||||
|
)}
|
||||||
|
icon="hass:brightness-7"
|
||||||
|
max="100"
|
||||||
|
.value=${this._colorBrightnessSliderValue}
|
||||||
|
@change=${this._colorBrightnessSliderChanged}
|
||||||
|
pin
|
||||||
|
></ha-labeled-slider>`
|
||||||
|
: ""}
|
||||||
|
${supportsRgbw
|
||||||
|
? html`
|
||||||
|
<ha-labeled-slider
|
||||||
.caption=${this.hass.localize(
|
.caption=${this.hass.localize(
|
||||||
"ui.card.light.color_brightness"
|
"ui.card.light.white_value"
|
||||||
)}
|
)}
|
||||||
icon="hass:brightness-7"
|
icon="hass:file-word-box"
|
||||||
max="100"
|
max="100"
|
||||||
.value=${this._colorBrightnessSliderValue}
|
.name=${"wv"}
|
||||||
@change=${this._colorBrightnessSliderChanged}
|
.value=${this._wvSliderValue}
|
||||||
|
@change=${this._wvSliderChanged}
|
||||||
pin
|
pin
|
||||||
></ha-labeled-slider>`
|
></ha-labeled-slider>
|
||||||
: ""}
|
`
|
||||||
${supportsRgbw
|
: ""}
|
||||||
? html`
|
${supportsRgbww
|
||||||
<ha-labeled-slider
|
? html`
|
||||||
.caption=${this.hass.localize(
|
<ha-labeled-slider
|
||||||
"ui.card.light.white_value"
|
.caption=${this.hass.localize(
|
||||||
)}
|
"ui.card.light.cold_white_value"
|
||||||
icon="hass:file-word-box"
|
)}
|
||||||
max="100"
|
icon="hass:file-word-box-outline"
|
||||||
.name=${"wv"}
|
max="100"
|
||||||
.value=${this._wvSliderValue}
|
.name=${"cw"}
|
||||||
@change=${this._wvSliderChanged}
|
.value=${this._cwSliderValue}
|
||||||
pin
|
@change=${this._wvSliderChanged}
|
||||||
></ha-labeled-slider>
|
pin
|
||||||
`
|
></ha-labeled-slider>
|
||||||
: ""}
|
<ha-labeled-slider
|
||||||
${supportsRgbww
|
.caption=${this.hass.localize(
|
||||||
? html`
|
"ui.card.light.warm_white_value"
|
||||||
<ha-labeled-slider
|
)}
|
||||||
.caption=${this.hass.localize(
|
icon="hass:file-word-box"
|
||||||
"ui.card.light.cold_white_value"
|
max="100"
|
||||||
)}
|
.name=${"ww"}
|
||||||
icon="hass:file-word-box-outline"
|
.value=${this._wwSliderValue}
|
||||||
max="100"
|
@change=${this._wvSliderChanged}
|
||||||
.name=${"cw"}
|
pin
|
||||||
.value=${this._cwSliderValue}
|
></ha-labeled-slider>
|
||||||
@change=${this._wvSliderChanged}
|
`
|
||||||
pin
|
: ""}
|
||||||
></ha-labeled-slider>
|
`
|
||||||
<ha-labeled-slider
|
: ""}
|
||||||
.caption=${this.hass.localize(
|
|
||||||
"ui.card.light.warm_white_value"
|
|
||||||
)}
|
|
||||||
icon="hass:file-word-box"
|
|
||||||
max="100"
|
|
||||||
.name=${"ww"}
|
|
||||||
.value=${this._wwSliderValue}
|
|
||||||
@change=${this._wvSliderChanged}
|
|
||||||
pin
|
|
||||||
></ha-labeled-slider>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@ -482,13 +479,18 @@ class MoreInfoViewLightColorPicker extends LitElement {
|
|||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return [
|
return [
|
||||||
haStyleDialog,
|
|
||||||
css`
|
css`
|
||||||
|
:host {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
.content {
|
.content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 16px;
|
justify-content: center;
|
||||||
|
padding: 24px;
|
||||||
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.segmentationContainer {
|
.segmentationContainer {
|
||||||
|
@ -94,12 +94,12 @@ export const computeShowLogBookComponent = (
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const computeShowNewMoreInfo = (stateObj: HassEntity) => {
|
export const computeShowNewMoreInfo = (stateObj: HassEntity): boolean => {
|
||||||
const domain = computeDomain(stateObj.entity_id);
|
const domain = computeDomain(stateObj.entity_id);
|
||||||
if (domain === "group") {
|
if (domain === "group") {
|
||||||
const groupDomain = computeGroupDomain(stateObj as GroupEntity);
|
const groupDomain = computeGroupDomain(stateObj as GroupEntity);
|
||||||
return (
|
return (
|
||||||
groupDomain &&
|
groupDomain != null &&
|
||||||
groupDomain !== "group" &&
|
groupDomain !== "group" &&
|
||||||
DOMAINS_WITH_NEW_MORE_INFO.includes(groupDomain)
|
DOMAINS_WITH_NEW_MORE_INFO.includes(groupDomain)
|
||||||
);
|
);
|
||||||
|
@ -12,6 +12,7 @@ import { dynamicElement } from "../../../common/dom/dynamic-element-directive";
|
|||||||
import { computeGroupDomain, GroupEntity } from "../../../data/group";
|
import { computeGroupDomain, GroupEntity } from "../../../data/group";
|
||||||
import "../../../state-summary/state-card-content";
|
import "../../../state-summary/state-card-content";
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
|
import { moreInfoControlStyle } from "../components/ha-more-info-control-style";
|
||||||
import {
|
import {
|
||||||
domainMoreInfoType,
|
domainMoreInfoType,
|
||||||
importMoreInfoControl,
|
importMoreInfoControl,
|
||||||
@ -94,12 +95,15 @@ class MoreInfoGroup extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return css`
|
return [
|
||||||
state-card-content {
|
moreInfoControlStyle,
|
||||||
display: block;
|
css`
|
||||||
margin-top: 8px;
|
state-card-content {
|
||||||
}
|
display: block;
|
||||||
`;
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ import "../../../components/ha-attributes";
|
|||||||
import "../../../components/ha-button-menu";
|
import "../../../components/ha-button-menu";
|
||||||
import "../../../components/ha-select";
|
import "../../../components/ha-select";
|
||||||
import { UNAVAILABLE } from "../../../data/entity";
|
import { UNAVAILABLE } from "../../../data/entity";
|
||||||
|
import { forwardHaptic } from "../../../data/haptics";
|
||||||
import {
|
import {
|
||||||
LightColorMode,
|
LightColorMode,
|
||||||
LightEntity,
|
LightEntity,
|
||||||
@ -32,6 +33,7 @@ import {
|
|||||||
lightSupportsColorMode,
|
lightSupportsColorMode,
|
||||||
} from "../../../data/light";
|
} from "../../../data/light";
|
||||||
import type { HomeAssistant } from "../../../types";
|
import type { HomeAssistant } from "../../../types";
|
||||||
|
import { moreInfoControlStyle } from "../components/ha-more-info-control-style";
|
||||||
import "../components/ha-more-info-state-header";
|
import "../components/ha-more-info-state-header";
|
||||||
import "../components/ha-more-info-toggle";
|
import "../components/ha-more-info-toggle";
|
||||||
import "../components/lights/ha-more-info-light-brightness";
|
import "../components/lights/ha-more-info-light-brightness";
|
||||||
@ -85,12 +87,12 @@ class MoreInfoLight extends LitElement {
|
|||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div class="content">
|
<ha-more-info-state-header
|
||||||
<ha-more-info-state-header
|
.hass=${this.hass}
|
||||||
.hass=${this.hass}
|
.stateObj=${this.stateObj}
|
||||||
.stateObj=${this.stateObj}
|
.stateOverride=${stateOverride}
|
||||||
.stateOverride=${stateOverride}
|
></ha-more-info-state-header>
|
||||||
></ha-more-info-state-header>
|
<div class="controls">
|
||||||
${supportsBrightness
|
${supportsBrightness
|
||||||
? html`
|
? html`
|
||||||
<ha-more-info-light-brightness
|
<ha-more-info-light-brightness
|
||||||
@ -184,17 +186,19 @@ class MoreInfoLight extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: null}
|
: null}
|
||||||
<ha-attributes
|
|
||||||
.hass=${this.hass}
|
|
||||||
.stateObj=${this.stateObj}
|
|
||||||
extra-filters="brightness,color_temp,color_temp_kelvin,white_value,effect_list,effect,hs_color,rgb_color,rgbw_color,rgbww_color,xy_color,min_mireds,max_mireds,min_color_temp_kelvin,max_color_temp_kelvin,entity_id,supported_color_modes,color_mode"
|
|
||||||
></ha-attributes>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<ha-attributes
|
||||||
|
.hass=${this.hass}
|
||||||
|
.stateObj=${this.stateObj}
|
||||||
|
extra-filters="brightness,color_temp,color_temp_kelvin,white_value,effect_list,effect,hs_color,rgb_color,rgbw_color,rgbww_color,xy_color,min_mireds,max_mireds,min_color_temp_kelvin,max_color_temp_kelvin,entity_id,supported_color_modes,color_mode"
|
||||||
|
></ha-attributes>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _toggle = () => {
|
private _toggle = () => {
|
||||||
const service = this.stateObj?.state === "on" ? "turn_off" : "turn_on";
|
const service = this.stateObj?.state === "on" ? "turn_off" : "turn_on";
|
||||||
|
forwardHaptic("light");
|
||||||
this.hass.callService("light", service, {
|
this.hass.callService("light", service, {
|
||||||
entity_id: this.stateObj!.entity_id,
|
entity_id: this.stateObj!.entity_id,
|
||||||
});
|
});
|
||||||
@ -230,41 +234,29 @@ class MoreInfoLight extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return css`
|
return [
|
||||||
.content {
|
moreInfoControlStyle,
|
||||||
display: flex;
|
css`
|
||||||
flex-direction: column;
|
.buttons {
|
||||||
align-items: center;
|
display: flex;
|
||||||
}
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.buttons > * {
|
||||||
|
margin: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.buttons {
|
md-outlined-icon-button-toggle,
|
||||||
display: flex;
|
md-outlined-icon-button {
|
||||||
align-items: center;
|
--ha-icon-display: block;
|
||||||
justify-content: center;
|
--md-sys-color-on-surface: var(--secondary-text-color);
|
||||||
margin-bottom: 12px;
|
--md-sys-color-on-surface-variant: var(--secondary-text-color);
|
||||||
}
|
--md-sys-color-on-surface-rgb: var(--rgb-secondary-text-color);
|
||||||
.buttons > * {
|
--md-sys-color-outline: var(--secondary-text-color);
|
||||||
margin: 4px;
|
}
|
||||||
}
|
`,
|
||||||
|
];
|
||||||
ha-more-info-light-brightness,
|
|
||||||
ha-more-info-toggle {
|
|
||||||
margin-bottom: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-attributes {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
md-outlined-icon-button-toggle,
|
|
||||||
md-outlined-icon-button {
|
|
||||||
--ha-icon-display: block;
|
|
||||||
--md-sys-color-on-surface: var(--secondary-text-color);
|
|
||||||
--md-sys-color-on-surface-variant: var(--secondary-text-color);
|
|
||||||
--md-sys-color-on-surface-rgb: var(--rgb-secondary-text-color);
|
|
||||||
--md-sys-color-outline: var(--secondary-text-color);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { mdiVolumeHigh, mdiVolumeOff } from "@mdi/js";
|
import { mdiVolumeHigh, mdiVolumeOff } from "@mdi/js";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import "../../../components/ha-attributes";
|
import "../../../components/ha-attributes";
|
||||||
import { LightEntity } from "../../../data/light";
|
import { LightEntity } from "../../../data/light";
|
||||||
import type { HomeAssistant } from "../../../types";
|
import type { HomeAssistant } from "../../../types";
|
||||||
|
import { moreInfoControlStyle } from "../components/ha-more-info-control-style";
|
||||||
import "../components/ha-more-info-state-header";
|
import "../components/ha-more-info-state-header";
|
||||||
import "../components/ha-more-info-toggle";
|
import "../components/ha-more-info-toggle";
|
||||||
|
|
||||||
@ -19,41 +20,27 @@ class MoreInfoSiren extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div class="content">
|
<ha-more-info-state-header
|
||||||
<ha-more-info-state-header
|
.hass=${this.hass}
|
||||||
.hass=${this.hass}
|
.stateObj=${this.stateObj}
|
||||||
.stateObj=${this.stateObj}
|
></ha-more-info-state-header>
|
||||||
></ha-more-info-state-header>
|
<div class="controls">
|
||||||
<ha-more-info-toggle
|
<ha-more-info-toggle
|
||||||
.stateObj=${this.stateObj}
|
.stateObj=${this.stateObj}
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.iconPathOn=${mdiVolumeHigh}
|
.iconPathOn=${mdiVolumeHigh}
|
||||||
.iconPathOff=${mdiVolumeOff}
|
.iconPathOff=${mdiVolumeOff}
|
||||||
></ha-more-info-toggle>
|
></ha-more-info-toggle>
|
||||||
<ha-attributes
|
|
||||||
.hass=${this.hass}
|
|
||||||
.stateObj=${this.stateObj}
|
|
||||||
></ha-attributes>
|
|
||||||
</div>
|
</div>
|
||||||
|
<ha-attributes
|
||||||
|
.hass=${this.hass}
|
||||||
|
.stateObj=${this.stateObj}
|
||||||
|
></ha-attributes>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return css`
|
return moreInfoControlStyle;
|
||||||
.content {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-more-info-toggle {
|
|
||||||
margin-bottom: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-attributes {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { mdiPower, mdiPowerOff } from "@mdi/js";
|
import { mdiPower, mdiPowerOff } from "@mdi/js";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import "../../../components/ha-attributes";
|
import "../../../components/ha-attributes";
|
||||||
import { LightEntity } from "../../../data/light";
|
import { LightEntity } from "../../../data/light";
|
||||||
import type { HomeAssistant } from "../../../types";
|
import type { HomeAssistant } from "../../../types";
|
||||||
|
import { moreInfoControlStyle } from "../components/ha-more-info-control-style";
|
||||||
import "../components/ha-more-info-state-header";
|
import "../components/ha-more-info-state-header";
|
||||||
import "../components/ha-more-info-toggle";
|
import "../components/ha-more-info-toggle";
|
||||||
|
|
||||||
@ -19,41 +20,27 @@ class MoreInfoSwitch extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div class="content">
|
<ha-more-info-state-header
|
||||||
<ha-more-info-state-header
|
.hass=${this.hass}
|
||||||
.hass=${this.hass}
|
.stateObj=${this.stateObj}
|
||||||
.stateObj=${this.stateObj}
|
></ha-more-info-state-header>
|
||||||
></ha-more-info-state-header>
|
<div class="controls">
|
||||||
<ha-more-info-toggle
|
<ha-more-info-toggle
|
||||||
.stateObj=${this.stateObj}
|
.stateObj=${this.stateObj}
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.iconPathOn=${mdiPower}
|
.iconPathOn=${mdiPower}
|
||||||
.iconPathOff=${mdiPowerOff}
|
.iconPathOff=${mdiPowerOff}
|
||||||
></ha-more-info-toggle>
|
></ha-more-info-toggle>
|
||||||
<ha-attributes
|
|
||||||
.hass=${this.hass}
|
|
||||||
.stateObj=${this.stateObj}
|
|
||||||
></ha-attributes>
|
|
||||||
</div>
|
</div>
|
||||||
|
<ha-attributes
|
||||||
|
.hass=${this.hass}
|
||||||
|
.stateObj=${this.stateObj}
|
||||||
|
></ha-attributes>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return css`
|
return moreInfoControlStyle;
|
||||||
.content {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-more-info-toggle {
|
|
||||||
margin-bottom: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-attributes {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,11 @@ import "../../components/ha-icon-button";
|
|||||||
import "../../components/ha-icon-button-prev";
|
import "../../components/ha-icon-button-prev";
|
||||||
import "../../components/ha-list-item";
|
import "../../components/ha-list-item";
|
||||||
import "../../components/ha-related-items";
|
import "../../components/ha-related-items";
|
||||||
import { EntityRegistryEntry } from "../../data/entity_registry";
|
import {
|
||||||
|
EntityRegistryEntry,
|
||||||
|
ExtEntityRegistryEntry,
|
||||||
|
getExtendedEntityRegistryEntry,
|
||||||
|
} from "../../data/entity_registry";
|
||||||
import { haStyleDialog } from "../../resources/styles";
|
import { haStyleDialog } from "../../resources/styles";
|
||||||
import "../../state-summary/state-card-content";
|
import "../../state-summary/state-card-content";
|
||||||
import { HomeAssistant } from "../../types";
|
import { HomeAssistant } from "../../types";
|
||||||
@ -77,6 +81,8 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
|
|
||||||
@state() private _childView?: ChildView;
|
@state() private _childView?: ChildView;
|
||||||
|
|
||||||
|
@state() private _entry?: ExtEntityRegistryEntry;
|
||||||
|
|
||||||
public showDialog(params: MoreInfoDialogParams) {
|
public showDialog(params: MoreInfoDialogParams) {
|
||||||
this._entityId = params.entityId;
|
this._entityId = params.entityId;
|
||||||
if (!this._entityId) {
|
if (!this._entityId) {
|
||||||
@ -86,10 +92,22 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
this._currView = params.view || "info";
|
this._currView = params.view || "info";
|
||||||
this._childView = undefined;
|
this._childView = undefined;
|
||||||
this.large = false;
|
this.large = false;
|
||||||
|
this._loadEntityRegistryEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _loadEntityRegistryEntry() {
|
||||||
|
if (!this._entityId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._entry = await getExtendedEntityRegistryEntry(
|
||||||
|
this.hass,
|
||||||
|
this._entityId
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public closeDialog() {
|
public closeDialog() {
|
||||||
this._entityId = undefined;
|
this._entityId = undefined;
|
||||||
|
this._entry = undefined;
|
||||||
this._childView = undefined;
|
this._childView = undefined;
|
||||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||||
}
|
}
|
||||||
@ -172,7 +190,10 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
idToPassThroughUrl = stateObj.attributes.id;
|
idToPassThroughUrl = stateObj.attributes.id;
|
||||||
}
|
}
|
||||||
if (EDITABLE_DOMAINS_WITH_UNIQUE_ID.includes(domain)) {
|
if (EDITABLE_DOMAINS_WITH_UNIQUE_ID.includes(domain)) {
|
||||||
idToPassThroughUrl = this.hass.entities[this._entityId!].unique_id;
|
if (!this._entry) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
idToPassThroughUrl = this._entry.unique_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
navigate(`/config/${domain}/edit/${idToPassThroughUrl}`);
|
navigate(`/config/${domain}/edit/${idToPassThroughUrl}`);
|
||||||
@ -203,13 +224,7 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
const isInfoView = this._currView === "info" && !this._childView;
|
const isInfoView = this._currView === "info" && !this._childView;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-dialog
|
<ha-dialog open @closed=${this.closeDialog} .heading=${title} hideActions>
|
||||||
open
|
|
||||||
@closed=${this.closeDialog}
|
|
||||||
.heading=${title}
|
|
||||||
hideActions
|
|
||||||
data-domain=${domain}
|
|
||||||
>
|
|
||||||
<div slot="heading" class="heading">
|
<div slot="heading" class="heading">
|
||||||
<ha-header-bar>
|
<ha-header-bar>
|
||||||
${isInfoView
|
${isInfoView
|
||||||
@ -335,10 +350,14 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
@show-child-view=${this._showChildView}
|
@show-child-view=${this._showChildView}
|
||||||
>
|
>
|
||||||
${this._childView
|
${this._childView
|
||||||
? dynamicElement(this._childView.viewTag, {
|
? html`
|
||||||
hass: this.hass,
|
<div class="child-view">
|
||||||
params: this._childView.viewParams,
|
${dynamicElement(this._childView.viewTag, {
|
||||||
})
|
hass: this.hass,
|
||||||
|
params: this._childView.viewParams,
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
`
|
||||||
: cache(
|
: cache(
|
||||||
this._currView === "info"
|
this._currView === "info"
|
||||||
? html`
|
? html`
|
||||||
@ -360,6 +379,8 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
<ha-more-info-settings
|
<ha-more-info-settings
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.entityId=${this._entityId}
|
.entityId=${this._entityId}
|
||||||
|
.entry=${this._entry}
|
||||||
|
@entity-entry-updated=${this._entryUpdated}
|
||||||
></ha-more-info-settings>
|
></ha-more-info-settings>
|
||||||
`
|
`
|
||||||
: this._currView === "related"
|
: this._currView === "related"
|
||||||
@ -385,12 +406,12 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
protected updated(changedProps: PropertyValues) {
|
protected updated(changedProps: PropertyValues) {
|
||||||
super.updated(changedProps);
|
super.updated(changedProps);
|
||||||
if (changedProps.has("_currView")) {
|
if (changedProps.has("_currView")) {
|
||||||
this.setAttribute("view", this._currView);
|
|
||||||
this._childView = undefined;
|
this._childView = undefined;
|
||||||
}
|
}
|
||||||
if (changedProps.has("_childView")) {
|
}
|
||||||
this.toggleAttribute("has-child-view", !!this._childView);
|
|
||||||
}
|
private _entryUpdated(ev: CustomEvent<ExtEntityRegistryEntry>) {
|
||||||
|
this._entry = ev.detail;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _enlarge() {
|
private _enlarge() {
|
||||||
@ -407,7 +428,6 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
--dialog-content-position: static;
|
--dialog-content-position: static;
|
||||||
--vertical-align-dialog: flex-start;
|
--vertical-align-dialog: flex-start;
|
||||||
--dialog-content-padding: 0;
|
--dialog-content-padding: 0;
|
||||||
--content-padding: 24px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ha-header-bar {
|
ha-header-bar {
|
||||||
@ -417,6 +437,7 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
display: block;
|
display: block;
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
@ -426,22 +447,16 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
var(--mdc-dialog-scroll-divider-color, rgba(0, 0, 0, 0.12));
|
var(--mdc-dialog-scroll-divider-color, rgba(0, 0, 0, 0.12));
|
||||||
}
|
}
|
||||||
|
|
||||||
:host([view="settings"]) ha-dialog {
|
ha-related-items,
|
||||||
--content-padding: 0;
|
ha-more-info-history-and-logbook {
|
||||||
|
padding: 24px;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
:host([view="info"]) ha-dialog[data-domain="camera"] {
|
@media all and (max-width: 450px) {
|
||||||
--content-padding: 0;
|
.child-view > * {
|
||||||
/* max height of the video is full screen, minus the height of the header of the dialog and the padding of the dialog (mdc-dialog-max-height: calc(100% - 72px)) */
|
min-height: calc(100vh - 56px);
|
||||||
--video-max-height: calc(100vh - 65px - 72px);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
:host([has-child-view]) ha-dialog {
|
|
||||||
--content-padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
padding: var(--content-padding);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-title {
|
.main-title {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { LitElement, html } from "lit";
|
import { css, CSSResultGroup, html, LitElement } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import { HomeAssistant } from "../../types";
|
import { HomeAssistant } from "../../types";
|
||||||
import {
|
import {
|
||||||
@ -34,6 +34,18 @@ export class MoreInfoHistoryAndLogbook extends LitElement {
|
|||||||
: ""}
|
: ""}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResultGroup {
|
||||||
|
return css`
|
||||||
|
ha-more-info-history,
|
||||||
|
ha-more-info-logbook {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
ha-more-info-history + ha-more-info-logbook {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
@ -16,6 +16,7 @@ import {
|
|||||||
} from "./const";
|
} from "./const";
|
||||||
import "./ha-more-info-history";
|
import "./ha-more-info-history";
|
||||||
import "./ha-more-info-logbook";
|
import "./ha-more-info-logbook";
|
||||||
|
import "./more-info-content";
|
||||||
|
|
||||||
@customElement("ha-more-info-info")
|
@customElement("ha-more-info-info")
|
||||||
export class MoreInfoInfo extends LitElement {
|
export class MoreInfoInfo extends LitElement {
|
||||||
@ -29,52 +30,59 @@ export class MoreInfoInfo extends LitElement {
|
|||||||
const entityId = this.entityId;
|
const entityId = this.entityId;
|
||||||
const stateObj = this.hass.states[entityId];
|
const stateObj = this.hass.states[entityId];
|
||||||
const domain = computeDomain(entityId);
|
const domain = computeDomain(entityId);
|
||||||
|
const newMoreInfo = computeShowNewMoreInfo(stateObj);
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
${!stateObj
|
<div class="container" data-domain=${domain}>
|
||||||
? html`<ha-alert alert-type="warning">
|
${!stateObj
|
||||||
${this.hass.localize(
|
? html`<ha-alert alert-type="warning">
|
||||||
"ui.dialogs.entity_registry.editor.unavailable"
|
${this.hass.localize(
|
||||||
)}
|
"ui.dialogs.entity_registry.editor.unavailable"
|
||||||
</ha-alert>`
|
)}
|
||||||
: ""}
|
</ha-alert>`
|
||||||
${stateObj?.attributes.restored && this._entityEntry
|
: ""}
|
||||||
? html`<ha-alert alert-type="warning">
|
${stateObj?.attributes.restored && this._entityEntry
|
||||||
${this.hass.localize(
|
? html`<ha-alert alert-type="warning">
|
||||||
"ui.dialogs.more_info_control.restored.no_longer_provided",
|
${this.hass.localize(
|
||||||
{
|
"ui.dialogs.more_info_control.restored.no_longer_provided",
|
||||||
integration: this._entityEntry.platform,
|
{
|
||||||
}
|
integration: this._entityEntry.platform,
|
||||||
)}
|
}
|
||||||
</ha-alert>`
|
)}
|
||||||
: ""}
|
</ha-alert>`
|
||||||
${DOMAINS_NO_INFO.includes(domain) || computeShowNewMoreInfo(stateObj)
|
: ""}
|
||||||
? ""
|
<div class="content">
|
||||||
: html`
|
${DOMAINS_NO_INFO.includes(domain) || computeShowNewMoreInfo(stateObj)
|
||||||
<state-card-content
|
? ""
|
||||||
in-dialog
|
: html`
|
||||||
.stateObj=${stateObj}
|
<state-card-content
|
||||||
.hass=${this.hass}
|
in-dialog
|
||||||
></state-card-content>
|
.stateObj=${stateObj}
|
||||||
`}
|
.hass=${this.hass}
|
||||||
${DOMAINS_WITH_MORE_INFO.includes(domain) ||
|
></state-card-content>
|
||||||
!computeShowHistoryComponent(this.hass, entityId)
|
`}
|
||||||
? ""
|
${DOMAINS_WITH_MORE_INFO.includes(domain) ||
|
||||||
: html`<ha-more-info-history
|
!computeShowHistoryComponent(this.hass, entityId)
|
||||||
|
? ""
|
||||||
|
: html`<ha-more-info-history
|
||||||
|
.hass=${this.hass}
|
||||||
|
.entityId=${this.entityId}
|
||||||
|
></ha-more-info-history>`}
|
||||||
|
${DOMAINS_WITH_MORE_INFO.includes(domain) ||
|
||||||
|
!computeShowLogBookComponent(this.hass, entityId)
|
||||||
|
? ""
|
||||||
|
: html`<ha-more-info-logbook
|
||||||
|
.hass=${this.hass}
|
||||||
|
.entityId=${this.entityId}
|
||||||
|
></ha-more-info-logbook>`}
|
||||||
|
<more-info-content
|
||||||
|
?full-height=${newMoreInfo}
|
||||||
|
.stateObj=${stateObj}
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.entityId=${this.entityId}
|
></more-info-content>
|
||||||
></ha-more-info-history>`}
|
<div class="toto"></div>
|
||||||
${DOMAINS_WITH_MORE_INFO.includes(domain) ||
|
</div>
|
||||||
!computeShowLogBookComponent(this.hass, entityId)
|
</div>
|
||||||
? ""
|
|
||||||
: html`<ha-more-info-logbook
|
|
||||||
.hass=${this.hass}
|
|
||||||
.entityId=${this.entityId}
|
|
||||||
></ha-more-info-logbook>`}
|
|
||||||
<more-info-content
|
|
||||||
.stateObj=${stateObj}
|
|
||||||
.hass=${this.hass}
|
|
||||||
></more-info-content>
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,6 +99,40 @@ export class MoreInfoInfo extends LitElement {
|
|||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return css`
|
return css`
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media all and (max-width: 450px) {
|
||||||
|
.container {
|
||||||
|
min-height: calc(100vh - 56px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1;
|
||||||
|
padding: 24px;
|
||||||
|
padding-bottom: max(env(safe-area-inset-bottom), 24px);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-domain="camera"] .content {
|
||||||
|
padding: 0;
|
||||||
|
/* max height of the video is full screen, minus the height of the header of the dialog and the padding of the dialog (mdc-dialog-max-height: calc(100% - 72px)) */
|
||||||
|
--video-max-height: calc(100vh - 65px - 72px);
|
||||||
|
}
|
||||||
|
|
||||||
|
more-info-content {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
more-info-content[full-height] {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
state-card-content,
|
state-card-content,
|
||||||
ha-more-info-history,
|
ha-more-info-history,
|
||||||
ha-more-info-logbook:not(:last-child) {
|
ha-more-info-logbook:not(:last-child) {
|
||||||
@ -100,9 +142,6 @@ export class MoreInfoInfo extends LitElement {
|
|||||||
|
|
||||||
ha-alert {
|
ha-alert {
|
||||||
display: block;
|
display: block;
|
||||||
margin: calc(-1 * var(--content-padding, 24px))
|
|
||||||
calc(-1 * var(--content-padding, 24px)) 16px
|
|
||||||
calc(-1 * var(--content-padding, 24px));
|
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,11 @@ import { dynamicElement } from "../../common/dom/dynamic-element-directive";
|
|||||||
import {
|
import {
|
||||||
EntityRegistryEntry,
|
EntityRegistryEntry,
|
||||||
ExtEntityRegistryEntry,
|
ExtEntityRegistryEntry,
|
||||||
getExtendedEntityRegistryEntry,
|
|
||||||
} from "../../data/entity_registry";
|
} from "../../data/entity_registry";
|
||||||
import { PLATFORMS_WITH_SETTINGS_TAB } from "../../panels/config/entities/const";
|
import { PLATFORMS_WITH_SETTINGS_TAB } from "../../panels/config/entities/const";
|
||||||
|
import "../../panels/config/entities/entity-registry-settings";
|
||||||
import type { HomeAssistant } from "../../types";
|
import type { HomeAssistant } from "../../types";
|
||||||
import { documentationUrl } from "../../util/documentation-url";
|
import { documentationUrl } from "../../util/documentation-url";
|
||||||
import "../../panels/config/entities/entity-registry-settings";
|
|
||||||
|
|
||||||
@customElement("ha-more-info-settings")
|
@customElement("ha-more-info-settings")
|
||||||
export class HaMoreInfoSettings extends LitElement {
|
export class HaMoreInfoSettings extends LitElement {
|
||||||
@ -19,18 +18,18 @@ export class HaMoreInfoSettings extends LitElement {
|
|||||||
|
|
||||||
@property({ attribute: false }) public entityId!: string;
|
@property({ attribute: false }) public entityId!: string;
|
||||||
|
|
||||||
@state() private _entry?: EntityRegistryEntry | ExtEntityRegistryEntry | null;
|
@state() private entry?: EntityRegistryEntry | ExtEntityRegistryEntry | null;
|
||||||
|
|
||||||
@state() private _settingsElementTag?: string;
|
@state() private _settingsElementTag?: string;
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
// loading.
|
// loading.
|
||||||
if (this._entry === undefined) {
|
if (this.entry === undefined) {
|
||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No unique ID
|
// No unique ID
|
||||||
if (this._entry === null) {
|
if (this.entry === null) {
|
||||||
return html`
|
return html`
|
||||||
<div class="content">
|
<div class="content">
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
@ -54,53 +53,31 @@ export class HaMoreInfoSettings extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div @entity-entry-updated=${this._entryUpdated}>
|
${dynamicElement(this._settingsElementTag, {
|
||||||
${dynamicElement(this._settingsElementTag, {
|
hass: this.hass,
|
||||||
hass: this.hass,
|
entry: this.entry,
|
||||||
entry: this._entry,
|
entityId: this.entityId,
|
||||||
entityId: this.entityId,
|
})}
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected willUpdate(changedProps: PropertyValues) {
|
public willUpdate(changedProps: PropertyValues) {
|
||||||
super.willUpdate(changedProps);
|
if (changedProps.has("entry")) {
|
||||||
if (changedProps.has("entityId")) {
|
|
||||||
this._entry = undefined;
|
|
||||||
if (this.entityId) {
|
|
||||||
this._getEntityReg();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _getEntityReg() {
|
|
||||||
try {
|
|
||||||
this._entry = await getExtendedEntityRegistryEntry(
|
|
||||||
this.hass,
|
|
||||||
this.entityId
|
|
||||||
);
|
|
||||||
this._loadPlatformSettingTabs();
|
this._loadPlatformSettingTabs();
|
||||||
} catch {
|
|
||||||
this._entry = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _entryUpdated(ev: CustomEvent<ExtEntityRegistryEntry>) {
|
|
||||||
this._entry = ev.detail;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _loadPlatformSettingTabs(): Promise<void> {
|
private async _loadPlatformSettingTabs(): Promise<void> {
|
||||||
if (!this._entry) {
|
if (!this.entry) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
!Object.keys(PLATFORMS_WITH_SETTINGS_TAB).includes(this._entry.platform)
|
!Object.keys(PLATFORMS_WITH_SETTINGS_TAB).includes(this.entry.platform)
|
||||||
) {
|
) {
|
||||||
this._settingsElementTag = "entity-registry-settings";
|
this._settingsElementTag = "entity-registry-settings";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const tag = PLATFORMS_WITH_SETTINGS_TAB[this._entry.platform];
|
const tag = PLATFORMS_WITH_SETTINGS_TAB[this.entry.platform];
|
||||||
await import(`../../panels/config/entities/editor-tabs/settings/${tag}`);
|
await import(`../../panels/config/entities/editor-tabs/settings/${tag}`);
|
||||||
this._settingsElementTag = tag;
|
this._settingsElementTag = tag;
|
||||||
}
|
}
|
||||||
|
@ -13,10 +13,8 @@ import {
|
|||||||
StaleWhileRevalidate,
|
StaleWhileRevalidate,
|
||||||
} from "workbox-strategies";
|
} from "workbox-strategies";
|
||||||
|
|
||||||
const noFallBackRegEx = new RegExp(
|
const noFallBackRegEx =
|
||||||
"/(api|static|auth|frontend_latest|frontend_es5|local)/.*"
|
/\/(api|static|auth|frontend_latest|frontend_es5|local)\/.*/;
|
||||||
);
|
|
||||||
|
|
||||||
// Clean up caches from older workboxes and old service workers.
|
// Clean up caches from older workboxes and old service workers.
|
||||||
// Will help with cleaning up Workbox v4 stuff
|
// Will help with cleaning up Workbox v4 stuff
|
||||||
cleanupOutdatedCaches();
|
cleanupOutdatedCaches();
|
||||||
@ -33,22 +31,22 @@ function initRouting() {
|
|||||||
|
|
||||||
// Cache static content (including translations) on first access.
|
// Cache static content (including translations) on first access.
|
||||||
registerRoute(
|
registerRoute(
|
||||||
new RegExp("/(static|frontend_latest|frontend_es5)/.+"),
|
/\/(static|frontend_latest|frontend_es5)\/.+/,
|
||||||
new CacheFirst({ matchOptions: { ignoreSearch: true } })
|
new CacheFirst({ matchOptions: { ignoreSearch: true } })
|
||||||
);
|
);
|
||||||
|
|
||||||
// Get api from network.
|
// Get api from network.
|
||||||
registerRoute(new RegExp("/(api|auth)/.*"), new NetworkOnly());
|
registerRoute(/\/(api|auth)\/.*/, new NetworkOnly());
|
||||||
|
|
||||||
// Get manifest, service worker, onboarding from network.
|
// Get manifest, service worker, onboarding from network.
|
||||||
registerRoute(
|
registerRoute(
|
||||||
new RegExp("/(service_worker.js|manifest.json|onboarding.html)"),
|
/\/(service_worker.js|manifest.json|onboarding.html)/,
|
||||||
new NetworkOnly()
|
new NetworkOnly()
|
||||||
);
|
);
|
||||||
|
|
||||||
// For the root "/" we ignore search
|
// For the root "/" we ignore search
|
||||||
registerRoute(
|
registerRoute(
|
||||||
new RegExp(/\/(\?.*)?$/),
|
/\/(\?.*)?$/,
|
||||||
new StaleWhileRevalidate({ matchOptions: { ignoreSearch: true } })
|
new StaleWhileRevalidate({ matchOptions: { ignoreSearch: true } })
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -57,7 +55,7 @@ function initRouting() {
|
|||||||
// First access might bring stale data from cache, but a single refresh will bring updated
|
// First access might bring stale data from cache, but a single refresh will bring updated
|
||||||
// file.
|
// file.
|
||||||
registerRoute(
|
registerRoute(
|
||||||
new RegExp(/\/.*/),
|
/\/.*/,
|
||||||
new StaleWhileRevalidate({
|
new StaleWhileRevalidate({
|
||||||
cacheName: "file-cache",
|
cacheName: "file-cache",
|
||||||
plugins: [
|
plugins: [
|
||||||
|
@ -116,7 +116,7 @@ export const provideHass = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
mockAPI(
|
mockAPI(
|
||||||
new RegExp("states/.+"),
|
/states\/.+/,
|
||||||
(
|
(
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
method,
|
method,
|
||||||
|
@ -11,6 +11,7 @@ import {
|
|||||||
mdiStopCircleOutline,
|
mdiStopCircleOutline,
|
||||||
mdiSort,
|
mdiSort,
|
||||||
} from "@mdi/js";
|
} from "@mdi/js";
|
||||||
|
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||||
import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit";
|
import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit";
|
||||||
import { customElement, property, query, state } from "lit/decorators";
|
import { customElement, property, query, state } from "lit/decorators";
|
||||||
import { classMap } from "lit/directives/class-map";
|
import { classMap } from "lit/directives/class-map";
|
||||||
@ -26,6 +27,10 @@ import "../../../../components/ha-icon-button";
|
|||||||
import type { HaYamlEditor } from "../../../../components/ha-yaml-editor";
|
import type { HaYamlEditor } from "../../../../components/ha-yaml-editor";
|
||||||
import { ACTION_TYPES } from "../../../../data/action";
|
import { ACTION_TYPES } from "../../../../data/action";
|
||||||
import { validateConfig } from "../../../../data/config";
|
import { validateConfig } from "../../../../data/config";
|
||||||
|
import {
|
||||||
|
EntityRegistryEntry,
|
||||||
|
subscribeEntityRegistry,
|
||||||
|
} from "../../../../data/entity_registry";
|
||||||
import { Action, getActionType } from "../../../../data/script";
|
import { Action, getActionType } from "../../../../data/script";
|
||||||
import { describeAction } from "../../../../data/script_i18n";
|
import { describeAction } from "../../../../data/script_i18n";
|
||||||
import { callExecuteScript } from "../../../../data/service";
|
import { callExecuteScript } from "../../../../data/service";
|
||||||
@ -107,6 +112,8 @@ export default class HaAutomationActionRow extends LitElement {
|
|||||||
|
|
||||||
@property({ type: Boolean }) public reOrderMode = false;
|
@property({ type: Boolean }) public reOrderMode = false;
|
||||||
|
|
||||||
|
@state() private _entityReg: EntityRegistryEntry[] = [];
|
||||||
|
|
||||||
@state() private _warnings?: string[];
|
@state() private _warnings?: string[];
|
||||||
|
|
||||||
@state() private _uiModeAvailable = true;
|
@state() private _uiModeAvailable = true;
|
||||||
@ -115,6 +122,14 @@ export default class HaAutomationActionRow extends LitElement {
|
|||||||
|
|
||||||
@query("ha-yaml-editor") private _yamlEditor?: HaYamlEditor;
|
@query("ha-yaml-editor") private _yamlEditor?: HaYamlEditor;
|
||||||
|
|
||||||
|
public hassSubscribe(): UnsubscribeFunc[] {
|
||||||
|
return [
|
||||||
|
subscribeEntityRegistry(this.hass.connection!, (entities) => {
|
||||||
|
this._entityReg = entities;
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
protected willUpdate(changedProperties: PropertyValues) {
|
protected willUpdate(changedProperties: PropertyValues) {
|
||||||
if (!changedProperties.has("action")) {
|
if (!changedProperties.has("action")) {
|
||||||
return;
|
return;
|
||||||
@ -156,7 +171,9 @@ export default class HaAutomationActionRow extends LitElement {
|
|||||||
class="action-icon"
|
class="action-icon"
|
||||||
.path=${ACTION_TYPES[type!]}
|
.path=${ACTION_TYPES[type!]}
|
||||||
></ha-svg-icon>
|
></ha-svg-icon>
|
||||||
${capitalizeFirstLetter(describeAction(this.hass, this.action))}
|
${capitalizeFirstLetter(
|
||||||
|
describeAction(this.hass, this._entityReg, this.action)
|
||||||
|
)}
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<slot name="icons" slot="icons"></slot>
|
<slot name="icons" slot="icons"></slot>
|
||||||
@ -465,7 +482,7 @@ export default class HaAutomationActionRow extends LitElement {
|
|||||||
),
|
),
|
||||||
inputType: "string",
|
inputType: "string",
|
||||||
placeholder: capitalizeFirstLetter(
|
placeholder: capitalizeFirstLetter(
|
||||||
describeAction(this.hass, this.action, undefined, true)
|
describeAction(this.hass, this._entityReg, this.action, undefined, true)
|
||||||
),
|
),
|
||||||
defaultValue: this.action.alias,
|
defaultValue: this.action.alias,
|
||||||
confirmText: this.hass.localize("ui.common.submit"),
|
confirmText: this.hass.localize("ui.common.submit"),
|
||||||
|
@ -49,6 +49,7 @@ import {
|
|||||||
showAutomationEditor,
|
showAutomationEditor,
|
||||||
triggerAutomationActions,
|
triggerAutomationActions,
|
||||||
} from "../../../data/automation";
|
} from "../../../data/automation";
|
||||||
|
import { fetchEntityRegistry } from "../../../data/entity_registry";
|
||||||
import {
|
import {
|
||||||
showAlertDialog,
|
showAlertDialog,
|
||||||
showConfirmationDialog,
|
showConfirmationDialog,
|
||||||
@ -479,7 +480,8 @@ export class HaAutomationEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
this._readOnly = false;
|
this._readOnly = false;
|
||||||
this._config = this._normalizeConfig(config);
|
this._config = this._normalizeConfig(config);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
const entity = Object.values(this.hass.entities).find(
|
const entityRegistry = await fetchEntityRegistry(this.hass.connection);
|
||||||
|
const entity = entityRegistry.find(
|
||||||
(ent) =>
|
(ent) =>
|
||||||
ent.platform === "automation" && ent.unique_id === this.automationId
|
ent.platform === "automation" && ent.unique_id === this.automationId
|
||||||
);
|
);
|
||||||
|
@ -36,6 +36,15 @@ import {
|
|||||||
showAlertDialog,
|
showAlertDialog,
|
||||||
showConfirmationDialog,
|
showConfirmationDialog,
|
||||||
} from "../../../../../dialogs/generic/show-dialog-box";
|
} from "../../../../../dialogs/generic/show-dialog-box";
|
||||||
|
import { HaFormSchema } from "../../../../../components/ha-form/types";
|
||||||
|
|
||||||
|
const firmwareTargetSchema: HaFormSchema[] = [
|
||||||
|
{
|
||||||
|
name: "firmware_target",
|
||||||
|
type: "integer",
|
||||||
|
valueMin: 0,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
@customElement("dialog-zwave_js-update-firmware-node")
|
@customElement("dialog-zwave_js-update-firmware-node")
|
||||||
class DialogZWaveJSUpdateFirmwareNode extends LitElement {
|
class DialogZWaveJSUpdateFirmwareNode extends LitElement {
|
||||||
@ -59,6 +68,8 @@ class DialogZWaveJSUpdateFirmwareNode extends LitElement {
|
|||||||
|
|
||||||
@state() private _nodeStatus?: ZWaveJSNodeStatus;
|
@state() private _nodeStatus?: ZWaveJSNodeStatus;
|
||||||
|
|
||||||
|
@state() private _firmwareTarget?: number;
|
||||||
|
|
||||||
private _subscribedNodeStatus?: Promise<UnsubscribeFunc>;
|
private _subscribedNodeStatus?: Promise<UnsubscribeFunc>;
|
||||||
|
|
||||||
private _subscribedNodeFirmwareUpdate?: Promise<UnsubscribeFunc>;
|
private _subscribedNodeFirmwareUpdate?: Promise<UnsubscribeFunc>;
|
||||||
@ -80,6 +91,7 @@ class DialogZWaveJSUpdateFirmwareNode extends LitElement {
|
|||||||
this._updateFinishedMessage = undefined;
|
this._updateFinishedMessage = undefined;
|
||||||
this._firmwareFile = undefined;
|
this._firmwareFile = undefined;
|
||||||
this._nodeStatus = undefined;
|
this._nodeStatus = undefined;
|
||||||
|
this._firmwareTarget = undefined;
|
||||||
this._uploading = this._updateInProgress = false;
|
this._uploading = this._updateInProgress = false;
|
||||||
|
|
||||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||||
@ -104,6 +116,19 @@ class DialogZWaveJSUpdateFirmwareNode extends LitElement {
|
|||||||
)}
|
)}
|
||||||
@file-picked=${this._uploadFile}
|
@file-picked=${this._uploadFile}
|
||||||
></ha-file-upload>
|
></ha-file-upload>
|
||||||
|
${this._nodeStatus.is_controller_node
|
||||||
|
? html``
|
||||||
|
: html`<p>
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.zwave_js.update_firmware.firmware_target_intro"
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
<ha-form
|
||||||
|
.hass=${this.hass}
|
||||||
|
.data=${{ firmware_target: this._firmwareTarget }}
|
||||||
|
.schema=${firmwareTargetSchema}
|
||||||
|
@value-changed=${this._firmwareTargetChanged}
|
||||||
|
></ha-form>`}
|
||||||
<mwc-button
|
<mwc-button
|
||||||
slot="primaryAction"
|
slot="primaryAction"
|
||||||
@click=${this._beginFirmwareUpdate}
|
@click=${this._beginFirmwareUpdate}
|
||||||
@ -283,7 +308,8 @@ class DialogZWaveJSUpdateFirmwareNode extends LitElement {
|
|||||||
await uploadFirmwareAndBeginUpdate(
|
await uploadFirmwareAndBeginUpdate(
|
||||||
this.hass,
|
this.hass,
|
||||||
this.device!.id,
|
this.device!.id,
|
||||||
this._firmwareFile!
|
this._firmwareFile!,
|
||||||
|
this._firmwareTarget
|
||||||
);
|
);
|
||||||
this._updateInProgress = true;
|
this._updateInProgress = true;
|
||||||
this._uploading = false;
|
this._uploading = false;
|
||||||
@ -388,6 +414,10 @@ class DialogZWaveJSUpdateFirmwareNode extends LitElement {
|
|||||||
this._subscribedNodeFirmwareUpdate = undefined;
|
this._subscribedNodeFirmwareUpdate = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async _firmwareTargetChanged(ev) {
|
||||||
|
this._firmwareTarget = ev.detail.value.firmware_target;
|
||||||
|
}
|
||||||
|
|
||||||
private async _uploadFile(ev) {
|
private async _uploadFile(ev) {
|
||||||
this._firmwareFile = ev.detail.files[0];
|
this._firmwareFile = ev.detail.files[0];
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,19 @@
|
|||||||
import { HassEntities } from "home-assistant-js-websocket";
|
import { HassEntities, UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||||
import { PropertyValues } from "lit";
|
import { PropertyValues } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
||||||
import { debounce } from "../../../common/util/debounce";
|
import { debounce } from "../../../common/util/debounce";
|
||||||
|
import {
|
||||||
|
EntityRegistryEntry,
|
||||||
|
subscribeEntityRegistry,
|
||||||
|
} from "../../../data/entity_registry";
|
||||||
import { ScriptEntity } from "../../../data/script";
|
import { ScriptEntity } from "../../../data/script";
|
||||||
import {
|
import {
|
||||||
HassRouterPage,
|
HassRouterPage,
|
||||||
RouterOptions,
|
RouterOptions,
|
||||||
} from "../../../layouts/hass-router-page";
|
} from "../../../layouts/hass-router-page";
|
||||||
|
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
|
||||||
import { HomeAssistant } from "../../../types";
|
import { HomeAssistant } from "../../../types";
|
||||||
import "./ha-script-editor";
|
import "./ha-script-editor";
|
||||||
import "./ha-script-picker";
|
import "./ha-script-picker";
|
||||||
@ -21,7 +26,7 @@ const equal = (a: ScriptEntity[], b: ScriptEntity[]): boolean => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
@customElement("ha-config-script")
|
@customElement("ha-config-script")
|
||||||
class HaConfigScript extends HassRouterPage {
|
class HaConfigScript extends SubscribeMixin(HassRouterPage) {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property() public narrow!: boolean;
|
@property() public narrow!: boolean;
|
||||||
@ -32,6 +37,16 @@ class HaConfigScript extends HassRouterPage {
|
|||||||
|
|
||||||
@property() public scripts: ScriptEntity[] = [];
|
@property() public scripts: ScriptEntity[] = [];
|
||||||
|
|
||||||
|
@state() private _entityReg: EntityRegistryEntry[] = [];
|
||||||
|
|
||||||
|
public hassSubscribe(): UnsubscribeFunc[] {
|
||||||
|
return [
|
||||||
|
subscribeEntityRegistry(this.hass.connection!, (entities) => {
|
||||||
|
this._entityReg = entities;
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
protected routerOptions: RouterOptions = {
|
protected routerOptions: RouterOptions = {
|
||||||
defaultPage: "dashboard",
|
defaultPage: "dashboard",
|
||||||
routes: {
|
routes: {
|
||||||
@ -78,6 +93,7 @@ class HaConfigScript extends HassRouterPage {
|
|||||||
pageEl.isWide = this.isWide;
|
pageEl.isWide = this.isWide;
|
||||||
pageEl.route = this.routeTail;
|
pageEl.route = this.routeTail;
|
||||||
pageEl.showAdvanced = this.showAdvanced;
|
pageEl.showAdvanced = this.showAdvanced;
|
||||||
|
pageEl.entityRegistry = this._entityReg;
|
||||||
|
|
||||||
if (this.hass) {
|
if (this.hass) {
|
||||||
if (!pageEl.scripts || !changedProps) {
|
if (!pageEl.scripts || !changedProps) {
|
||||||
|
@ -39,6 +39,7 @@ import "../../../components/ha-icon-button";
|
|||||||
import "../../../components/ha-svg-icon";
|
import "../../../components/ha-svg-icon";
|
||||||
import "../../../components/ha-yaml-editor";
|
import "../../../components/ha-yaml-editor";
|
||||||
import type { HaYamlEditor } from "../../../components/ha-yaml-editor";
|
import type { HaYamlEditor } from "../../../components/ha-yaml-editor";
|
||||||
|
import { EntityRegistryEntry } from "../../../data/entity_registry";
|
||||||
import {
|
import {
|
||||||
deleteScript,
|
deleteScript,
|
||||||
getScriptStateConfig,
|
getScriptStateConfig,
|
||||||
@ -75,6 +76,8 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
|
|
||||||
@property({ type: Boolean }) public narrow!: boolean;
|
@property({ type: Boolean }) public narrow!: boolean;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public entityRegistry!: EntityRegistryEntry[];
|
||||||
|
|
||||||
@state() private _config?: ScriptConfig;
|
@state() private _config?: ScriptConfig;
|
||||||
|
|
||||||
@state() private _entityId?: string;
|
@state() private _entityId?: string;
|
||||||
@ -431,7 +434,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
this._config = this._normalizeConfig(config);
|
this._config = this._normalizeConfig(config);
|
||||||
},
|
},
|
||||||
(resp) => {
|
(resp) => {
|
||||||
const entity = Object.values(this.hass.entities).find(
|
const entity = this.entityRegistry.find(
|
||||||
(ent) =>
|
(ent) =>
|
||||||
ent.platform === "script" && ent.unique_id === this.scriptId
|
ent.platform === "script" && ent.unique_id === this.scriptId
|
||||||
);
|
);
|
||||||
@ -477,7 +480,9 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
getScriptStateConfig(this.hass, this.entityId).then((c) => {
|
getScriptStateConfig(this.hass, this.entityId).then((c) => {
|
||||||
this._config = this._normalizeConfig(c.config);
|
this._config = this._normalizeConfig(c.config);
|
||||||
});
|
});
|
||||||
const regEntry = this.hass.entities[this.entityId];
|
const regEntry = this.entityRegistry.find(
|
||||||
|
(ent) => ent.entity_id === this.entityId
|
||||||
|
);
|
||||||
if (regEntry?.unique_id) {
|
if (regEntry?.unique_id) {
|
||||||
this.scriptId = regEntry.unique_id;
|
this.scriptId = regEntry.unique_id;
|
||||||
}
|
}
|
||||||
@ -544,7 +549,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
|
|||||||
if (!this.scriptId) {
|
if (!this.scriptId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const entity = Object.values(this.hass.entities).find(
|
const entity = this.entityRegistry.find(
|
||||||
(entry) => entry.unique_id === this.scriptId
|
(entry) => entry.unique_id === this.scriptId
|
||||||
);
|
);
|
||||||
if (!entity) {
|
if (!entity) {
|
||||||
|
@ -44,6 +44,7 @@ import { HomeAssistant, Route } from "../../../types";
|
|||||||
import { documentationUrl } from "../../../util/documentation-url";
|
import { documentationUrl } from "../../../util/documentation-url";
|
||||||
import { showToast } from "../../../util/toast";
|
import { showToast } from "../../../util/toast";
|
||||||
import { configSections } from "../ha-panel-config";
|
import { configSections } from "../ha-panel-config";
|
||||||
|
import { EntityRegistryEntry } from "../../../data/entity_registry";
|
||||||
|
|
||||||
@customElement("ha-script-picker")
|
@customElement("ha-script-picker")
|
||||||
class HaScriptPicker extends LitElement {
|
class HaScriptPicker extends LitElement {
|
||||||
@ -57,7 +58,9 @@ class HaScriptPicker extends LitElement {
|
|||||||
|
|
||||||
@property() public route!: Route;
|
@property() public route!: Route;
|
||||||
|
|
||||||
@property() private _activeFilters?: string[];
|
@property({ attribute: false }) public entityRegistry!: EntityRegistryEntry[];
|
||||||
|
|
||||||
|
@state() private _activeFilters?: string[];
|
||||||
|
|
||||||
@state() private _filteredScripts?: string[] | null;
|
@state() private _filteredScripts?: string[] | null;
|
||||||
|
|
||||||
@ -266,7 +269,7 @@ class HaScriptPicker extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _handleRowClicked(ev: HASSDomEvent<RowClickedEvent>) {
|
private _handleRowClicked(ev: HASSDomEvent<RowClickedEvent>) {
|
||||||
const entry = this.hass.entities[ev.detail.id];
|
const entry = this.entityRegistry.find((e) => e.entity_id === ev.detail.id);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
navigate(`/config/script/edit/${entry.unique_id}`);
|
navigate(`/config/script/edit/${entry.unique_id}`);
|
||||||
} else {
|
} else {
|
||||||
@ -275,7 +278,12 @@ class HaScriptPicker extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _runScript = async (script: any) => {
|
private _runScript = async (script: any) => {
|
||||||
const entry = this.hass.entities[script.entity_id];
|
const entry = this.entityRegistry.find(
|
||||||
|
(e) => e.entity_id === script.entity_id
|
||||||
|
);
|
||||||
|
if (!entry) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
await triggerScript(this.hass, entry.unique_id);
|
await triggerScript(this.hass, entry.unique_id);
|
||||||
showToast(this, {
|
showToast(this, {
|
||||||
message: this.hass.localize(
|
message: this.hass.localize(
|
||||||
@ -291,7 +299,9 @@ class HaScriptPicker extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _showTrace(script: any) {
|
private _showTrace(script: any) {
|
||||||
const entry = this.hass.entities[script.entity_id];
|
const entry = this.entityRegistry.find(
|
||||||
|
(e) => e.entity_id === script.entity_id
|
||||||
|
);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
navigate(`/config/script/trace/${entry.unique_id}`);
|
navigate(`/config/script/trace/${entry.unique_id}`);
|
||||||
}
|
}
|
||||||
@ -317,7 +327,12 @@ class HaScriptPicker extends LitElement {
|
|||||||
|
|
||||||
private async _duplicate(script: any) {
|
private async _duplicate(script: any) {
|
||||||
try {
|
try {
|
||||||
const entry = this.hass.entities[script.entity_id];
|
const entry = this.entityRegistry.find(
|
||||||
|
(e) => e.entity_id === script.entity_id
|
||||||
|
);
|
||||||
|
if (!entry) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const config = await fetchScriptFileConfig(this.hass, entry.unique_id);
|
const config = await fetchScriptFileConfig(this.hass, entry.unique_id);
|
||||||
showScriptEditor({
|
showScriptEditor({
|
||||||
...config,
|
...config,
|
||||||
@ -362,8 +377,12 @@ class HaScriptPicker extends LitElement {
|
|||||||
|
|
||||||
private async _delete(script: any) {
|
private async _delete(script: any) {
|
||||||
try {
|
try {
|
||||||
const entry = this.hass.entities[script.entity_id];
|
const entry = this.entityRegistry.find(
|
||||||
await deleteScript(this.hass, entry.unique_id);
|
(e) => e.entity_id === script.entity_id
|
||||||
|
);
|
||||||
|
if (entry) {
|
||||||
|
await deleteScript(this.hass, entry.unique_id);
|
||||||
|
}
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
await showAlertDialog(this, {
|
await showAlertDialog(this, {
|
||||||
text:
|
text:
|
||||||
|
@ -39,6 +39,7 @@ import { HomeAssistant, Route } from "../../../types";
|
|||||||
import "../../../layouts/hass-subpage";
|
import "../../../layouts/hass-subpage";
|
||||||
import "../../../components/ha-button-menu";
|
import "../../../components/ha-button-menu";
|
||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
|
import { EntityRegistryEntry } from "../../../data/entity_registry";
|
||||||
|
|
||||||
@customElement("ha-script-trace")
|
@customElement("ha-script-trace")
|
||||||
export class HaScriptTrace extends LitElement {
|
export class HaScriptTrace extends LitElement {
|
||||||
@ -54,6 +55,8 @@ export class HaScriptTrace extends LitElement {
|
|||||||
|
|
||||||
@property({ attribute: false }) public route!: Route;
|
@property({ attribute: false }) public route!: Route;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public entityRegistry!: EntityRegistryEntry[];
|
||||||
|
|
||||||
@state() private _entityId?: string;
|
@state() private _entityId?: string;
|
||||||
|
|
||||||
@state() private _traces?: ScriptTrace[];
|
@state() private _traces?: ScriptTrace[];
|
||||||
@ -318,7 +321,7 @@ export class HaScriptTrace extends LitElement {
|
|||||||
const params = new URLSearchParams(location.search);
|
const params = new URLSearchParams(location.search);
|
||||||
this._loadTraces(params.get("run_id") || undefined);
|
this._loadTraces(params.get("run_id") || undefined);
|
||||||
|
|
||||||
this._entityId = Object.values(this.hass.entities).find(
|
this._entityId = this.entityRegistry.find(
|
||||||
(entry) => entry.unique_id === this.scriptId
|
(entry) => entry.unique_id === this.scriptId
|
||||||
)?.entity_id;
|
)?.entity_id;
|
||||||
}
|
}
|
||||||
@ -335,7 +338,7 @@ export class HaScriptTrace extends LitElement {
|
|||||||
if (this.scriptId) {
|
if (this.scriptId) {
|
||||||
this._loadTraces();
|
this._loadTraces();
|
||||||
|
|
||||||
this._entityId = Object.values(this.hass.entities).find(
|
this._entityId = this.entityRegistry.find(
|
||||||
(entry) => entry.unique_id === this.scriptId
|
(entry) => entry.unique_id === this.scriptId
|
||||||
)?.entity_id;
|
)?.entity_id;
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ import "../lovelace/components/hui-energy-period-selector";
|
|||||||
import { Lovelace } from "../lovelace/types";
|
import { Lovelace } from "../lovelace/types";
|
||||||
import "../lovelace/views/hui-view";
|
import "../lovelace/views/hui-view";
|
||||||
|
|
||||||
const LOVELACE_CONFIG: LovelaceConfig = {
|
const ENERGY_LOVELACE_CONFIG: LovelaceConfig = {
|
||||||
views: [
|
views: [
|
||||||
{
|
{
|
||||||
strategy: {
|
strategy: {
|
||||||
@ -93,8 +93,8 @@ class PanelEnergy extends LitElement {
|
|||||||
|
|
||||||
private _setLovelace() {
|
private _setLovelace() {
|
||||||
this._lovelace = {
|
this._lovelace = {
|
||||||
config: LOVELACE_CONFIG,
|
config: ENERGY_LOVELACE_CONFIG,
|
||||||
rawConfig: LOVELACE_CONFIG,
|
rawConfig: ENERGY_LOVELACE_CONFIG,
|
||||||
editMode: false,
|
editMode: false,
|
||||||
urlPath: "energy",
|
urlPath: "energy",
|
||||||
mode: "generated",
|
mode: "generated",
|
||||||
|
@ -56,7 +56,7 @@ export class EnergyStrategy {
|
|||||||
(source) => source.type === "water"
|
(source) => source.type === "water"
|
||||||
);
|
);
|
||||||
|
|
||||||
if (info.narrow) {
|
if (info.narrow || info.view.strategy?.options?.show_date_selection) {
|
||||||
view.cards!.push({
|
view.cards!.push({
|
||||||
type: "energy-date-selection",
|
type: "energy-date-selection",
|
||||||
collection_key: "energy_dashboard",
|
collection_key: "energy_dashboard",
|
||||||
|
@ -884,6 +884,11 @@ class HuiEnergyDistrubutionCard
|
|||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
height: 20px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
max-width: 80px;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
line,
|
line,
|
||||||
path {
|
path {
|
||||||
|
@ -13,6 +13,7 @@ import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_elemen
|
|||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||||
import { isValidEntityId } from "../../../common/entity/valid_entity_id";
|
import { isValidEntityId } from "../../../common/entity/valid_entity_id";
|
||||||
|
import { getNumberFormatOptions } from "../../../common/number/format_number";
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
import "../../../components/ha-gauge";
|
import "../../../components/ha-gauge";
|
||||||
import { UNAVAILABLE } from "../../../data/entity";
|
import { UNAVAILABLE } from "../../../data/entity";
|
||||||
@ -129,6 +130,10 @@ class HuiGaugeCard extends LitElement implements LovelaceCard {
|
|||||||
.min=${this._config.min!}
|
.min=${this._config.min!}
|
||||||
.max=${this._config.max!}
|
.max=${this._config.max!}
|
||||||
.value=${stateObj.state}
|
.value=${stateObj.state}
|
||||||
|
.formatOptions=${getNumberFormatOptions(
|
||||||
|
stateObj,
|
||||||
|
this.hass.entities[stateObj.entity_id]
|
||||||
|
)}
|
||||||
.locale=${this.hass!.locale}
|
.locale=${this.hass!.locale}
|
||||||
.label=${this._config!.unit ||
|
.label=${this._config!.unit ||
|
||||||
this.hass?.states[this._config!.entity].attributes
|
this.hass?.states[this._config!.entity].attributes
|
||||||
|
@ -278,8 +278,8 @@ const computeDefaultViewStates = (
|
|||||||
.filter(
|
.filter(
|
||||||
(entry) =>
|
(entry) =>
|
||||||
entry.entity_category ||
|
entry.entity_category ||
|
||||||
HIDE_PLATFORM.has(entry.platform) ||
|
(entry.platform && HIDE_PLATFORM.has(entry.platform)) ||
|
||||||
entry.hidden_by
|
entry.hidden
|
||||||
)
|
)
|
||||||
.map((entry) => entry.entity_id)
|
.map((entry) => entry.entity_id)
|
||||||
);
|
);
|
||||||
|
@ -62,7 +62,7 @@ const buttonEntitiesRowConfigStruct = object({
|
|||||||
|
|
||||||
const castEntitiesRowConfigStruct = object({
|
const castEntitiesRowConfigStruct = object({
|
||||||
type: literal("cast"),
|
type: literal("cast"),
|
||||||
view: union([string(), number()]),
|
view: optional(union([string(), number()])),
|
||||||
dashboard: optional(string()),
|
dashboard: optional(string()),
|
||||||
name: optional(string()),
|
name: optional(string()),
|
||||||
icon: optional(string()),
|
icon: optional(string()),
|
||||||
|
@ -55,7 +55,7 @@ export interface CastConfig {
|
|||||||
type: "cast";
|
type: "cast";
|
||||||
icon?: string;
|
icon?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
view: string | number;
|
view?: string | number;
|
||||||
dashboard?: string;
|
dashboard?: string;
|
||||||
// Hide the row if either unsupported browser or no API available.
|
// Hide the row if either unsupported browser or no API available.
|
||||||
hide_if_unavailable?: boolean;
|
hide_if_unavailable?: boolean;
|
||||||
|
@ -29,13 +29,10 @@ class HuiCastRow extends LitElement implements LovelaceRow {
|
|||||||
@state() private _noHTTPS = false;
|
@state() private _noHTTPS = false;
|
||||||
|
|
||||||
public setConfig(config: CastConfig): void {
|
public setConfig(config: CastConfig): void {
|
||||||
if (!config || config.view === undefined || config.view === null) {
|
|
||||||
throw new Error("View required");
|
|
||||||
}
|
|
||||||
|
|
||||||
this._config = {
|
this._config = {
|
||||||
icon: "hass:television",
|
icon: "mdi:television",
|
||||||
name: "Home Assistant Cast",
|
name: "Home Assistant Cast",
|
||||||
|
view: 0,
|
||||||
...config,
|
...config,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -123,7 +120,7 @@ class HuiCastRow extends LitElement implements LovelaceRow {
|
|||||||
castSendShowLovelaceView(
|
castSendShowLovelaceView(
|
||||||
this._castManager!,
|
this._castManager!,
|
||||||
this.hass.auth.data.hassUrl,
|
this.hass.auth.data.hassUrl,
|
||||||
this._config!.view,
|
this._config!.view!,
|
||||||
this._config!.dashboard
|
this._config!.dashboard
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ import { polyfillsLoaded } from "../common/translations/localize";
|
|||||||
import { subscribeAreaRegistry } from "../data/area_registry";
|
import { subscribeAreaRegistry } from "../data/area_registry";
|
||||||
import { broadcastConnectionStatus } from "../data/connection-status";
|
import { broadcastConnectionStatus } from "../data/connection-status";
|
||||||
import { subscribeDeviceRegistry } from "../data/device_registry";
|
import { subscribeDeviceRegistry } from "../data/device_registry";
|
||||||
import { subscribeEntityRegistry } from "../data/entity_registry";
|
import { subscribeEntityRegistryDisplay } from "../data/entity_registry";
|
||||||
import { subscribeFrontendUserData } from "../data/frontend";
|
import { subscribeFrontendUserData } from "../data/frontend";
|
||||||
import { forwardHaptic } from "../data/haptics";
|
import { forwardHaptic } from "../data/haptics";
|
||||||
import { DEFAULT_PANEL } from "../data/panel";
|
import { DEFAULT_PANEL } from "../data/panel";
|
||||||
@ -188,10 +188,22 @@ export const connectionMixin = <T extends Constructor<HassBaseEl>>(
|
|||||||
});
|
});
|
||||||
|
|
||||||
subscribeEntities(conn, (states) => this._updateHass({ states }));
|
subscribeEntities(conn, (states) => this._updateHass({ states }));
|
||||||
subscribeEntityRegistry(conn, (entityReg) => {
|
subscribeEntityRegistryDisplay(conn, (entityReg) => {
|
||||||
const entities: HomeAssistant["entities"] = {};
|
const entities: HomeAssistant["entities"] = {};
|
||||||
for (const entity of entityReg) {
|
for (const entity of entityReg.entities) {
|
||||||
entities[entity.entity_id] = entity;
|
entities[entity.ei] = {
|
||||||
|
entity_id: entity.ei,
|
||||||
|
device_id: entity.di,
|
||||||
|
area_id: entity.ai,
|
||||||
|
translation_key: entity.tk,
|
||||||
|
platform: entity.pl,
|
||||||
|
entity_category: entity.ec
|
||||||
|
? entityReg.entity_categories[entity.ec]
|
||||||
|
: undefined,
|
||||||
|
name: entity.en,
|
||||||
|
hidden: entity.hb,
|
||||||
|
display_precision: entity.dp,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
this._updateHass({ entities });
|
this._updateHass({ entities });
|
||||||
});
|
});
|
||||||
|
@ -3691,6 +3691,8 @@
|
|||||||
"warning_controller": "WARNING: Firmware updates can brick your controller if you do not use the right firmware files, or if you attempt to stop the firmware update before it completes. The Home Assistant and Z-Wave JS teams do not take any responsibility for any damages to your controller as a result of the firmware update and will not be able to help you if you brick your controller. Would you still like to continue?",
|
"warning_controller": "WARNING: Firmware updates can brick your controller if you do not use the right firmware files, or if you attempt to stop the firmware update before it completes. The Home Assistant and Z-Wave JS teams do not take any responsibility for any damages to your controller as a result of the firmware update and will not be able to help you if you brick your controller. Would you still like to continue?",
|
||||||
"introduction": "Select the firmware file you would like to use to update {device}.",
|
"introduction": "Select the firmware file you would like to use to update {device}.",
|
||||||
"introduction_controller": "Select the firmware file you would like to use to update {device}. Note that once you start a firmware update, you MUST wait for the update to complete.",
|
"introduction_controller": "Select the firmware file you would like to use to update {device}. Note that once you start a firmware update, you MUST wait for the update to complete.",
|
||||||
|
"firmware_target_intro": "Select the firmware target (0 for the Z-Wave chip, ≥1 for other chips if they exist) for this update.",
|
||||||
|
"firmware_target": "Firmware Target (chip)",
|
||||||
"upload_firmware": "Upload Firmware",
|
"upload_firmware": "Upload Firmware",
|
||||||
"upload_failed": "Upload Failed",
|
"upload_failed": "Upload Failed",
|
||||||
"begin_update": "Begin Firmware Update",
|
"begin_update": "Begin Firmware Update",
|
||||||
|
@ -10,7 +10,7 @@ import {
|
|||||||
import { LocalizeFunc } from "./common/translations/localize";
|
import { LocalizeFunc } from "./common/translations/localize";
|
||||||
import { AreaRegistryEntry } from "./data/area_registry";
|
import { AreaRegistryEntry } from "./data/area_registry";
|
||||||
import { DeviceRegistryEntry } from "./data/device_registry";
|
import { DeviceRegistryEntry } from "./data/device_registry";
|
||||||
import { EntityRegistryEntry } from "./data/entity_registry";
|
import { EntityRegistryDisplayEntry } from "./data/entity_registry";
|
||||||
import { CoreFrontendUserData } from "./data/frontend";
|
import { CoreFrontendUserData } from "./data/frontend";
|
||||||
import { FrontendLocaleData, getHassTranslations } from "./data/translation";
|
import { FrontendLocaleData, getHassTranslations } from "./data/translation";
|
||||||
import { Themes } from "./data/ws-themes";
|
import { Themes } from "./data/ws-themes";
|
||||||
@ -189,7 +189,7 @@ export interface HomeAssistant {
|
|||||||
connection: Connection;
|
connection: Connection;
|
||||||
connected: boolean;
|
connected: boolean;
|
||||||
states: HassEntities;
|
states: HassEntities;
|
||||||
entities: { [id: string]: EntityRegistryEntry };
|
entities: { [id: string]: EntityRegistryDisplayEntry };
|
||||||
devices: { [id: string]: DeviceRegistryEntry };
|
devices: { [id: string]: DeviceRegistryEntry };
|
||||||
areas: { [id: string]: AreaRegistryEntry };
|
areas: { [id: string]: AreaRegistryEntry };
|
||||||
services: HassServices;
|
services: HassServices;
|
||||||
|
20
yarn.lock
20
yarn.lock
@ -3095,13 +3095,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@material/web@npm:=1.0.0-pre.2":
|
"@material/web@npm:=1.0.0-pre.3":
|
||||||
version: 1.0.0-pre.2
|
version: 1.0.0-pre.3
|
||||||
resolution: "@material/web@npm:1.0.0-pre.2"
|
resolution: "@material/web@npm:1.0.0-pre.3"
|
||||||
dependencies:
|
dependencies:
|
||||||
lit: ^2.3.0
|
lit: ^2.3.0
|
||||||
tslib: ^2.4.0
|
tslib: ^2.4.0
|
||||||
checksum: 7c6733fae5fb67c43d7c49fab70f7893defd95e4fcbe996d06057882e47c0121760546cc5d1c407a9dbd11c5f02f3f278016c52922e6a9e97db0c0b52d7133f2
|
checksum: d6286992cb0d63b094e638a3db484398195608b422bb2cb209102eaf87d220ed24bbe85d29933730054fd3cf99d318dbb3645ae9a2e271fe1a3c2833d829bf4c
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@ -9562,7 +9562,7 @@ fsevents@~2.3.2:
|
|||||||
"@material/mwc-textfield": ^0.27.0
|
"@material/mwc-textfield": ^0.27.0
|
||||||
"@material/mwc-top-app-bar-fixed": ^0.27.0
|
"@material/mwc-top-app-bar-fixed": ^0.27.0
|
||||||
"@material/top-app-bar": =14.0.0-canary.53b3cad2f.0
|
"@material/top-app-bar": =14.0.0-canary.53b3cad2f.0
|
||||||
"@material/web": =1.0.0-pre.2
|
"@material/web": =1.0.0-pre.3
|
||||||
"@mdi/js": 7.1.96
|
"@mdi/js": 7.1.96
|
||||||
"@mdi/svg": 7.1.96
|
"@mdi/svg": 7.1.96
|
||||||
"@octokit/auth-oauth-device": ^4.0.4
|
"@octokit/auth-oauth-device": ^4.0.4
|
||||||
@ -9663,7 +9663,7 @@ fsevents@~2.3.2:
|
|||||||
lit: ^2.6.1
|
lit: ^2.6.1
|
||||||
lit-analyzer: ^1.2.1
|
lit-analyzer: ^1.2.1
|
||||||
lodash.template: ^4.5.0
|
lodash.template: ^4.5.0
|
||||||
magic-string: ^0.29.0
|
magic-string: ^0.30.0
|
||||||
map-stream: ^0.0.7
|
map-stream: ^0.0.7
|
||||||
marked: ^4.2.12
|
marked: ^4.2.12
|
||||||
memoize-one: ^6.0.0
|
memoize-one: ^6.0.0
|
||||||
@ -11590,12 +11590,12 @@ fsevents@~2.3.2:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"magic-string@npm:^0.29.0":
|
"magic-string@npm:^0.30.0":
|
||||||
version: 0.29.0
|
version: 0.30.0
|
||||||
resolution: "magic-string@npm:0.29.0"
|
resolution: "magic-string@npm:0.30.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@jridgewell/sourcemap-codec": ^1.4.13
|
"@jridgewell/sourcemap-codec": ^1.4.13
|
||||||
checksum: 19e5398fcfc44804917127c72ad622c68a19a0a10cbdb8d4f9f9417584a087fe9e117140bfb2463d86743cf1ed9cf4182ae0b0ad1a7536f7fdda257ee4449ffb
|
checksum: 7bdf22e27334d8a393858a16f5f840af63a7c05848c000fd714da5aa5eefa09a1bc01d8469362f25cc5c4a14ec01b46557b7fff8751365522acddf21e57c488d
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user