mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-24 09:46:36 +00:00
20230703.0 (#17150)
This commit is contained in:
commit
b309c64d7b
@ -23,6 +23,7 @@ import {
|
||||
SupervisorObject,
|
||||
supervisorCollection,
|
||||
SupervisorKeys,
|
||||
cleanupSupervisorCollection,
|
||||
} from "../../src/data/supervisor/supervisor";
|
||||
import { ProvideHassLitMixin } from "../../src/mixins/provide-hass-lit-mixin";
|
||||
import { urlSyncMixin } from "../../src/state/url-sync-mixin";
|
||||
@ -67,6 +68,10 @@ export class SupervisorBaseElement extends urlSyncMixin(
|
||||
this._unsubs[unsub]();
|
||||
delete this._unsubs[unsub];
|
||||
});
|
||||
Object.keys(this._collections).forEach((collection) => {
|
||||
cleanupSupervisorCollection(this.hass.connection, collection);
|
||||
});
|
||||
this._collections = {};
|
||||
this.removeEventListener(
|
||||
"supervisor-collection-refresh",
|
||||
this._handleSupervisorStoreRefreshEvent
|
||||
@ -114,7 +119,9 @@ export class SupervisorBaseElement extends urlSyncMixin(
|
||||
private async _handleSupervisorStoreRefreshEvent(ev) {
|
||||
const collection = ev.detail.collection;
|
||||
if (atLeastVersion(this.hass.config.version, 2021, 2, 4)) {
|
||||
this._collections[collection].refresh();
|
||||
if (collection in this._collections) {
|
||||
this._collections[collection].refresh();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -129,11 +136,17 @@ export class SupervisorBaseElement extends urlSyncMixin(
|
||||
if (this._unsubs[collection]) {
|
||||
this._unsubs[collection]();
|
||||
}
|
||||
this._unsubs[collection] = this._collections[collection].subscribe((data) =>
|
||||
this._updateSupervisor({
|
||||
[collection]: data,
|
||||
})
|
||||
);
|
||||
try {
|
||||
this._unsubs[collection] = this._collections[collection].subscribe(
|
||||
(data) =>
|
||||
this._updateSupervisor({
|
||||
[collection]: data,
|
||||
})
|
||||
);
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private async _initSupervisor(): Promise<void> {
|
||||
|
14
package.json
14
package.json
@ -52,7 +52,7 @@
|
||||
"@lit-labs/context": "0.3.3",
|
||||
"@lit-labs/motion": "1.0.3",
|
||||
"@lit-labs/virtualizer": "2.0.3",
|
||||
"@lrnwebcomponents/simple-tooltip": "7.0.10",
|
||||
"@lrnwebcomponents/simple-tooltip": "7.0.11",
|
||||
"@material/chips": "=14.0.0-canary.53b3cad2f.0",
|
||||
"@material/data-table": "=14.0.0-canary.53b3cad2f.0",
|
||||
"@material/mwc-button": "0.27.0",
|
||||
@ -78,7 +78,7 @@
|
||||
"@material/mwc-top-app-bar": "0.27.0",
|
||||
"@material/mwc-top-app-bar-fixed": "0.27.0",
|
||||
"@material/top-app-bar": "=14.0.0-canary.53b3cad2f.0",
|
||||
"@material/web": "=1.0.0-pre.11",
|
||||
"@material/web": "=1.0.0-pre.12",
|
||||
"@mdi/js": "7.2.96",
|
||||
"@mdi/svg": "7.2.96",
|
||||
"@polymer/app-layout": "3.1.0",
|
||||
@ -112,7 +112,7 @@
|
||||
"deep-freeze": "0.0.1",
|
||||
"fuse.js": "6.6.2",
|
||||
"google-timezones-json": "1.1.0",
|
||||
"hls.js": "1.4.6",
|
||||
"hls.js": "1.4.7",
|
||||
"home-assistant-js-websocket": "8.1.0",
|
||||
"idb-keyval": "6.2.1",
|
||||
"intl-messageformat": "10.5.0",
|
||||
@ -203,7 +203,7 @@
|
||||
"esprima": "4.0.1",
|
||||
"fancy-log": "2.0.0",
|
||||
"fs-extra": "11.1.1",
|
||||
"glob": "10.3.0",
|
||||
"glob": "10.3.1",
|
||||
"gulp": "4.0.2",
|
||||
"gulp-flatmap": "1.0.2",
|
||||
"gulp-json-transform": "0.4.8",
|
||||
@ -214,7 +214,7 @@
|
||||
"husky": "8.0.3",
|
||||
"instant-mocha": "1.5.1",
|
||||
"jszip": "3.10.1",
|
||||
"lint-staged": "13.2.2",
|
||||
"lint-staged": "13.2.3",
|
||||
"lit-analyzer": "2.0.0-pre.3",
|
||||
"lodash.template": "4.5.0",
|
||||
"magic-string": "0.30.0",
|
||||
@ -236,10 +236,10 @@
|
||||
"tar": "6.1.15",
|
||||
"terser-webpack-plugin": "5.3.9",
|
||||
"ts-lit-plugin": "2.0.0-pre.1",
|
||||
"typescript": "5.1.3",
|
||||
"typescript": "5.1.6",
|
||||
"vinyl-buffer": "1.0.1",
|
||||
"vinyl-source-stream": "2.0.0",
|
||||
"webpack": "5.88.0",
|
||||
"webpack": "5.88.1",
|
||||
"webpack-cli": "5.1.4",
|
||||
"webpack-dev-server": "4.15.1",
|
||||
"webpack-manifest-plugin": "5.0.0",
|
||||
|
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "home-assistant-frontend"
|
||||
version = "20230630.0"
|
||||
version = "20230703.0"
|
||||
license = {text = "Apache-2.0"}
|
||||
description = "The Home Assistant frontend"
|
||||
readme = "README.md"
|
||||
|
27
src/common/string/format-list.ts
Normal file
27
src/common/string/format-list.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import memoizeOne from "memoize-one";
|
||||
import "../../resources/intl-polyfill";
|
||||
import { FrontendLocaleData } from "../../data/translation";
|
||||
|
||||
export const formatListWithAnds = (
|
||||
locale: FrontendLocaleData,
|
||||
list: string[]
|
||||
) => formatConjunctionList(locale).format(list);
|
||||
|
||||
export const formatListWithOrs = (locale: FrontendLocaleData, list: string[]) =>
|
||||
formatDisjunctionList(locale).format(list);
|
||||
|
||||
const formatConjunctionList = memoizeOne(
|
||||
(locale: FrontendLocaleData) =>
|
||||
new Intl.ListFormat(locale.language, {
|
||||
style: "long",
|
||||
type: "conjunction",
|
||||
})
|
||||
);
|
||||
|
||||
const formatDisjunctionList = memoizeOne(
|
||||
(locale: FrontendLocaleData) =>
|
||||
new Intl.ListFormat(locale.language, {
|
||||
style: "long",
|
||||
type: "disjunction",
|
||||
})
|
||||
);
|
@ -12,6 +12,7 @@ import {
|
||||
} from "../common/entity/compute_attribute_display";
|
||||
import { computeStateDisplay } from "../common/entity/compute_state_display";
|
||||
import { computeStateName } from "../common/entity/compute_state_name";
|
||||
import "../resources/intl-polyfill";
|
||||
import type { HomeAssistant } from "../types";
|
||||
import { Condition, ForDict, Trigger } from "./automation";
|
||||
import {
|
||||
@ -21,7 +22,6 @@ import {
|
||||
localizeDeviceAutomationTrigger,
|
||||
} from "./device_automation";
|
||||
import { EntityRegistryEntry } from "./entity_registry";
|
||||
import "../resources/intl-polyfill";
|
||||
import { FrontendLocaleData } from "./translation";
|
||||
|
||||
const triggerTranslationBaseKey =
|
||||
|
@ -31,6 +31,10 @@ import {
|
||||
VariablesAction,
|
||||
WaitForTriggerAction,
|
||||
} from "./script";
|
||||
import { formatListWithAnds } from "../common/string/format-list";
|
||||
|
||||
const actionTranslationBaseKey =
|
||||
"ui.panel.config.automation.editor.actions.type";
|
||||
|
||||
export const describeAction = <T extends ActionType>(
|
||||
hass: HomeAssistant,
|
||||
@ -75,25 +79,8 @@ const tryDescribeAction = <T extends ActionType>(
|
||||
if (actionType === "service") {
|
||||
const config = action as ActionTypes["service"];
|
||||
|
||||
let base: string | undefined;
|
||||
|
||||
if (
|
||||
config.service_template ||
|
||||
(config.service && isTemplate(config.service))
|
||||
) {
|
||||
base = "Call a service based on a template";
|
||||
} else if (config.service) {
|
||||
const [domain, serviceName] = config.service.split(".", 2);
|
||||
const service = hass.services[domain][serviceName];
|
||||
base = service
|
||||
? `${domainToName(hass.localize, domain)}: ${service.name}`
|
||||
: `Call service: ${config.service}`;
|
||||
} else {
|
||||
return "Call a service";
|
||||
}
|
||||
const targets: string[] = [];
|
||||
if (config.target) {
|
||||
const targets: string[] = [];
|
||||
|
||||
for (const [key, label] of Object.entries({
|
||||
area_id: "areas",
|
||||
device_id: "devices",
|
||||
@ -108,7 +95,12 @@ const tryDescribeAction = <T extends ActionType>(
|
||||
|
||||
for (const targetThing of keyConf) {
|
||||
if (isTemplate(targetThing)) {
|
||||
targets.push(`templated ${label}`);
|
||||
targets.push(
|
||||
hass.localize(
|
||||
`${actionTranslationBaseKey}.service.description.target_template`,
|
||||
{ name: label }
|
||||
)
|
||||
);
|
||||
break;
|
||||
} else if (key === "entity_id") {
|
||||
if (targetThing.includes(".")) {
|
||||
@ -125,7 +117,11 @@ const tryDescribeAction = <T extends ActionType>(
|
||||
computeEntityRegistryName(hass, entityReg) || targetThing
|
||||
);
|
||||
} else {
|
||||
targets.push("unknown entity");
|
||||
targets.push(
|
||||
hass.localize(
|
||||
`${actionTranslationBaseKey}.service.description.target_unknown_entity`
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if (key === "device_id") {
|
||||
@ -133,46 +129,105 @@ const tryDescribeAction = <T extends ActionType>(
|
||||
if (device) {
|
||||
targets.push(computeDeviceName(device, hass));
|
||||
} else {
|
||||
targets.push("unknown device");
|
||||
targets.push(
|
||||
hass.localize(
|
||||
`${actionTranslationBaseKey}.service.description.target_unknown_device`
|
||||
)
|
||||
);
|
||||
}
|
||||
} else if (key === "area_id") {
|
||||
const area = hass.areas[targetThing];
|
||||
if (area?.name) {
|
||||
targets.push(area.name);
|
||||
} else {
|
||||
targets.push("unknown area");
|
||||
targets.push(
|
||||
hass.localize(
|
||||
`${actionTranslationBaseKey}.service.description.target_unknown_area`
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
targets.push(targetThing);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (targets.length > 0) {
|
||||
base += ` ${targets.join(", ")}`;
|
||||
}
|
||||
}
|
||||
|
||||
return base;
|
||||
if (
|
||||
config.service_template ||
|
||||
(config.service && isTemplate(config.service))
|
||||
) {
|
||||
return hass.localize(
|
||||
`${actionTranslationBaseKey}.service.description.service_based_on_template`,
|
||||
{ targets: formatListWithAnds(hass.locale, targets) }
|
||||
);
|
||||
}
|
||||
|
||||
if (config.service) {
|
||||
const [domain, serviceName] = config.service.split(".", 2);
|
||||
const service = hass.services[domain][serviceName];
|
||||
return hass.localize(
|
||||
`${actionTranslationBaseKey}.service.description.service_based_on_name`,
|
||||
{
|
||||
name: service
|
||||
? `${domainToName(hass.localize, domain)}: ${service.name}`
|
||||
: config.service,
|
||||
targets: formatListWithAnds(hass.locale, targets),
|
||||
}
|
||||
);
|
||||
}
|
||||
return hass.localize(
|
||||
`${actionTranslationBaseKey}.service.description.service`
|
||||
);
|
||||
}
|
||||
|
||||
if (actionType === "delay") {
|
||||
const config = action as DelayAction;
|
||||
|
||||
let duration: string;
|
||||
|
||||
if (typeof config.delay === "number") {
|
||||
duration = `for ${secondsToDuration(config.delay)!}`;
|
||||
duration = hass.localize(
|
||||
`${actionTranslationBaseKey}.delay.description.duration_string`,
|
||||
{
|
||||
duration: secondsToDuration(config.delay)!,
|
||||
}
|
||||
);
|
||||
} else if (typeof config.delay === "string") {
|
||||
duration = isTemplate(config.delay)
|
||||
? "based on a template"
|
||||
: `for ${config.delay || "a duration"}`;
|
||||
? hass.localize(
|
||||
`${actionTranslationBaseKey}.delay.description.duration_template`
|
||||
)
|
||||
: hass.localize(
|
||||
`${actionTranslationBaseKey}.delay.description.duration_string`,
|
||||
{
|
||||
duration:
|
||||
config.delay ||
|
||||
hass.localize(
|
||||
`${actionTranslationBaseKey}.delay.description.duration_unknown`
|
||||
),
|
||||
}
|
||||
);
|
||||
} else if (config.delay) {
|
||||
duration = `for ${formatDuration(config.delay)}`;
|
||||
duration = hass.localize(
|
||||
`${actionTranslationBaseKey}.delay.description.duration_string`,
|
||||
{
|
||||
duration: formatDuration(config.delay),
|
||||
}
|
||||
);
|
||||
} else {
|
||||
duration = "for a duration";
|
||||
duration = hass.localize(
|
||||
`${actionTranslationBaseKey}.delay.description.duration_string`,
|
||||
{
|
||||
duration: hass.localize(
|
||||
`${actionTranslationBaseKey}.delay.description.duration_unknown`
|
||||
),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return `Delay ${duration}`;
|
||||
return hass.localize(`${actionTranslationBaseKey}.delay.description.full`, {
|
||||
duration: duration,
|
||||
});
|
||||
}
|
||||
|
||||
if (actionType === "activate_scene") {
|
||||
@ -184,77 +239,139 @@ const tryDescribeAction = <T extends ActionType>(
|
||||
entityId = config.target?.entity_id || config.entity_id;
|
||||
}
|
||||
if (!entityId) {
|
||||
return "Activate a scene";
|
||||
return hass.localize(
|
||||
`${actionTranslationBaseKey}.activate_scene.description.activate_scene`
|
||||
);
|
||||
}
|
||||
const sceneStateObj = entityId ? hass.states[entityId] : undefined;
|
||||
return `Activate scene ${
|
||||
sceneStateObj ? computeStateName(sceneStateObj) : entityId
|
||||
}`;
|
||||
return hass.localize(
|
||||
`${actionTranslationBaseKey}.activate_scene.description.activate_scene_with_name`,
|
||||
{ name: sceneStateObj ? computeStateName(sceneStateObj) : entityId }
|
||||
);
|
||||
}
|
||||
|
||||
if (actionType === "play_media") {
|
||||
const config = action as PlayMediaAction;
|
||||
const entityId = config.target?.entity_id || config.entity_id;
|
||||
const mediaStateObj = entityId ? hass.states[entityId] : undefined;
|
||||
return `Play ${
|
||||
config.metadata.title || config.data.media_content_id || "media"
|
||||
} on ${
|
||||
mediaStateObj
|
||||
? computeStateName(mediaStateObj)
|
||||
: entityId || "a media player"
|
||||
}`;
|
||||
return hass.localize(
|
||||
`${actionTranslationBaseKey}.play_media.description.full`,
|
||||
{
|
||||
hasMedia: config.metadata.title || config.data.media_content_id,
|
||||
media: config.metadata.title || config.data.media_content_id,
|
||||
hasMediaPlayer: mediaStateObj ? true : entityId !== undefined,
|
||||
mediaPlayer: mediaStateObj ? computeStateName(mediaStateObj) : entityId,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (actionType === "wait_for_trigger") {
|
||||
const config = action as WaitForTriggerAction;
|
||||
const triggers = ensureArray(config.wait_for_trigger);
|
||||
if (!triggers || triggers.length === 0) {
|
||||
return "Wait for a trigger";
|
||||
return hass.localize(
|
||||
`${actionTranslationBaseKey}.wait_for_trigger.description.wait_for_a_trigger`
|
||||
);
|
||||
}
|
||||
return `Wait for ${triggers
|
||||
.map((trigger) => describeTrigger(trigger, hass, entityRegistry))
|
||||
.join(", ")}`;
|
||||
const triggerNames = triggers.map((trigger) =>
|
||||
describeTrigger(trigger, hass, entityRegistry)
|
||||
);
|
||||
return hass.localize(
|
||||
`${actionTranslationBaseKey}.wait_for_trigger.description.wait_for_triggers_with_name`,
|
||||
{ triggers: formatListWithAnds(hass.locale, triggerNames) }
|
||||
);
|
||||
}
|
||||
|
||||
if (actionType === "variables") {
|
||||
const config = action as VariablesAction;
|
||||
return `Define variables ${Object.keys(config.variables).join(", ")}`;
|
||||
return hass.localize(
|
||||
`${actionTranslationBaseKey}.variables.description.full`,
|
||||
{
|
||||
names: formatListWithAnds(hass.locale, Object.keys(config.variables)),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (actionType === "fire_event") {
|
||||
const config = action as EventAction;
|
||||
if (isTemplate(config.event)) {
|
||||
return "Fire event based on a template";
|
||||
return hass.localize(
|
||||
`${actionTranslationBaseKey}.event.description.full`,
|
||||
{
|
||||
name: hass.localize(
|
||||
`${actionTranslationBaseKey}.event.description.template`
|
||||
),
|
||||
}
|
||||
);
|
||||
}
|
||||
return `Fire event ${config.event}`;
|
||||
return hass.localize(`${actionTranslationBaseKey}.event.description.full`, {
|
||||
name: config.event,
|
||||
});
|
||||
}
|
||||
|
||||
if (actionType === "wait_template") {
|
||||
return "Wait for a template to render true";
|
||||
}
|
||||
|
||||
if (actionType === "check_condition") {
|
||||
return describeCondition(action as Condition, hass, entityRegistry);
|
||||
return hass.localize(
|
||||
`${actionTranslationBaseKey}.wait_template.description.full`
|
||||
);
|
||||
}
|
||||
|
||||
if (actionType === "stop") {
|
||||
const config = action as StopAction;
|
||||
return `Stop${config.stop ? ` because: ${config.stop}` : ""}`;
|
||||
return hass.localize(`${actionTranslationBaseKey}.stop.description.full`, {
|
||||
hasReason: config.stop !== undefined,
|
||||
reason: config.stop,
|
||||
});
|
||||
}
|
||||
|
||||
if (actionType === "if") {
|
||||
const config = action as IfAction;
|
||||
return `Perform an action if: ${
|
||||
!config.if
|
||||
? ""
|
||||
: typeof config.if === "string"
|
||||
? config.if
|
||||
: ensureArray(config.if).length > 1
|
||||
? `${ensureArray(config.if).length} conditions`
|
||||
: ensureArray(config.if).length
|
||||
? describeCondition(ensureArray(config.if)[0], hass, entityRegistry)
|
||||
: ""
|
||||
}${config.else ? " (or else!)" : ""}`;
|
||||
|
||||
let ifConditions: string[] = [];
|
||||
if (Array.isArray(config.if)) {
|
||||
const conditions = ensureArray(config.if);
|
||||
conditions.forEach((condition) => {
|
||||
ifConditions.push(describeCondition(condition, hass, entityRegistry));
|
||||
});
|
||||
} else {
|
||||
ifConditions = [config.if];
|
||||
}
|
||||
|
||||
let elseActions: string[] = [];
|
||||
if (config.else) {
|
||||
if (Array.isArray(config.else)) {
|
||||
const actions = ensureArray(config.else);
|
||||
actions.forEach((currentAction) => {
|
||||
elseActions.push(
|
||||
describeAction(hass, entityRegistry, currentAction, undefined)
|
||||
);
|
||||
});
|
||||
} else {
|
||||
elseActions = [
|
||||
describeAction(hass, entityRegistry, config.else, undefined),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
let thenActions: string[] = [];
|
||||
if (Array.isArray(config.then)) {
|
||||
const actions = ensureArray(config.then);
|
||||
actions.forEach((currentAction) => {
|
||||
thenActions.push(
|
||||
describeAction(hass, entityRegistry, currentAction, undefined)
|
||||
);
|
||||
});
|
||||
} else {
|
||||
thenActions = [
|
||||
describeAction(hass, entityRegistry, config.then, undefined),
|
||||
];
|
||||
}
|
||||
|
||||
return hass.localize(`${actionTranslationBaseKey}.if.description.full`, {
|
||||
hasElse: config.else !== undefined,
|
||||
action: formatListWithAnds(hass.locale, thenActions),
|
||||
conditions: formatListWithAnds(hass.locale, ifConditions),
|
||||
elseAction: formatListWithAnds(hass.locale, elseActions),
|
||||
});
|
||||
}
|
||||
|
||||
if (actionType === "choose") {
|
||||
@ -262,42 +379,64 @@ const tryDescribeAction = <T extends ActionType>(
|
||||
if (config.choose) {
|
||||
const numActions =
|
||||
ensureArray(config.choose).length + (config.default ? 1 : 0);
|
||||
return `Choose between ${numActions} action${
|
||||
numActions === 1 ? "" : "s"
|
||||
}`;
|
||||
return hass.localize(
|
||||
`${actionTranslationBaseKey}.choose.description.full`,
|
||||
{ number: numActions }
|
||||
);
|
||||
}
|
||||
return "Choose an action";
|
||||
return hass.localize(
|
||||
`${actionTranslationBaseKey}.choose.description.no_action`
|
||||
);
|
||||
}
|
||||
|
||||
if (actionType === "repeat") {
|
||||
const config = action as RepeatAction;
|
||||
|
||||
let base = "Repeat an action";
|
||||
let chosenAction = "";
|
||||
if ("count" in config.repeat) {
|
||||
const count = config.repeat.count;
|
||||
base += ` ${count} time${Number(count) === 1 ? "" : "s"}`;
|
||||
chosenAction = hass.localize(
|
||||
`${actionTranslationBaseKey}.repeat.description.count`,
|
||||
{ count: count }
|
||||
);
|
||||
} else if ("while" in config.repeat) {
|
||||
base += ` while ${ensureArray(config.repeat.while)
|
||||
.map((condition) => describeCondition(condition, hass, entityRegistry))
|
||||
.join(", ")} is true`;
|
||||
const conditions = ensureArray(config.repeat.while).map((condition) =>
|
||||
describeCondition(condition, hass, entityRegistry)
|
||||
);
|
||||
chosenAction = hass.localize(
|
||||
`${actionTranslationBaseKey}.repeat.description.while`,
|
||||
{ conditions: formatListWithAnds(hass.locale, conditions) }
|
||||
);
|
||||
} else if ("until" in config.repeat) {
|
||||
base += ` until ${ensureArray(config.repeat.until)
|
||||
.map((condition) => describeCondition(condition, hass, entityRegistry))
|
||||
.join(", ")} is true`;
|
||||
const conditions = ensureArray(config.repeat.until).map((condition) =>
|
||||
describeCondition(condition, hass, entityRegistry)
|
||||
);
|
||||
chosenAction = hass.localize(
|
||||
`${actionTranslationBaseKey}.repeat.description.until`,
|
||||
{ conditions: formatListWithAnds(hass.locale, conditions) }
|
||||
);
|
||||
} else if ("for_each" in config.repeat) {
|
||||
base += ` for every item: ${ensureArray(config.repeat.for_each)
|
||||
.map((item) => JSON.stringify(item))
|
||||
.join(", ")}`;
|
||||
const items = ensureArray(config.repeat.for_each).map((item) =>
|
||||
JSON.stringify(item)
|
||||
);
|
||||
chosenAction = hass.localize(
|
||||
`${actionTranslationBaseKey}.repeat.description.for_each`,
|
||||
{ items: formatListWithAnds(hass.locale, items) }
|
||||
);
|
||||
}
|
||||
return base;
|
||||
return hass.localize(
|
||||
`${actionTranslationBaseKey}.repeat.description.full`,
|
||||
{ chosenAction: chosenAction }
|
||||
);
|
||||
}
|
||||
|
||||
if (actionType === "check_condition") {
|
||||
return `Test ${describeCondition(
|
||||
action as Condition,
|
||||
hass,
|
||||
entityRegistry
|
||||
)}`;
|
||||
return hass.localize(
|
||||
`${actionTranslationBaseKey}.check_condition.description.full`,
|
||||
{
|
||||
condition: describeCondition(action as Condition, hass, entityRegistry),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (actionType === "device_action") {
|
||||
@ -313,7 +452,7 @@ const tryDescribeAction = <T extends ActionType>(
|
||||
if (localized) {
|
||||
return localized;
|
||||
}
|
||||
const stateObj = hass.states[config.entity_id as string];
|
||||
const stateObj = hass.states[config.entity_id];
|
||||
return `${config.type || "Perform action with"} ${
|
||||
stateObj ? computeStateName(stateObj) : config.entity_id
|
||||
}`;
|
||||
@ -322,7 +461,10 @@ const tryDescribeAction = <T extends ActionType>(
|
||||
if (actionType === "parallel") {
|
||||
const config = action as ParallelAction;
|
||||
const numActions = ensureArray(config.parallel).length;
|
||||
return `Run ${numActions} action${numActions === 1 ? "" : "s"} in parallel`;
|
||||
return hass.localize(
|
||||
`${actionTranslationBaseKey}.parallel.description.full`,
|
||||
{ number: numActions }
|
||||
);
|
||||
}
|
||||
|
||||
return actionType;
|
||||
|
@ -132,3 +132,6 @@ export const getSupervisorEventCollection = (
|
||||
subscribeSupervisorEventUpdates(connection, store, key),
|
||||
{ unsubGrace: false }
|
||||
);
|
||||
|
||||
export const cleanupSupervisorCollection = (conn: Connection, key: string) =>
|
||||
delete conn[`_supervisor${key}Event`];
|
||||
|
@ -15,7 +15,6 @@ import {
|
||||
mdiStopCircleOutline,
|
||||
} from "@mdi/js";
|
||||
import deepClone from "deep-clone-simple";
|
||||
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import {
|
||||
CSSResultGroup,
|
||||
LitElement,
|
||||
@ -26,6 +25,7 @@ import {
|
||||
} from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { consume } from "@lit-labs/context";
|
||||
import { storage } from "../../../../common/decorators/storage";
|
||||
import { dynamicElement } from "../../../../common/dom/dynamic-element-directive";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
@ -40,10 +40,7 @@ import type { HaYamlEditor } from "../../../../components/ha-yaml-editor";
|
||||
import { ACTION_TYPES, YAML_ONLY_ACTION_TYPES } from "../../../../data/action";
|
||||
import { AutomationClipboard } from "../../../../data/automation";
|
||||
import { validateConfig } from "../../../../data/config";
|
||||
import {
|
||||
EntityRegistryEntry,
|
||||
subscribeEntityRegistry,
|
||||
} from "../../../../data/entity_registry";
|
||||
import { EntityRegistryEntry } from "../../../../data/entity_registry";
|
||||
import {
|
||||
Action,
|
||||
NonConditionAction,
|
||||
@ -73,6 +70,7 @@ import "./types/ha-automation-action-service";
|
||||
import "./types/ha-automation-action-stop";
|
||||
import "./types/ha-automation-action-wait_for_trigger";
|
||||
import "./types/ha-automation-action-wait_template";
|
||||
import { fullEntitiesContext } from "../../../../data/context";
|
||||
|
||||
export const getType = (action: Action | undefined) => {
|
||||
if (!action) {
|
||||
@ -137,7 +135,9 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
})
|
||||
public _clipboard?: AutomationClipboard;
|
||||
|
||||
@state() private _entityReg: EntityRegistryEntry[] = [];
|
||||
@state()
|
||||
@consume({ context: fullEntitiesContext, subscribe: true })
|
||||
_entityReg!: EntityRegistryEntry[];
|
||||
|
||||
@state() private _warnings?: string[];
|
||||
|
||||
@ -147,14 +147,6 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
|
||||
@query("ha-yaml-editor") private _yamlEditor?: HaYamlEditor;
|
||||
|
||||
public hassSubscribe(): UnsubscribeFunc[] {
|
||||
return [
|
||||
subscribeEntityRegistry(this.hass.connection!, (entities) => {
|
||||
this._entityReg = entities;
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
protected willUpdate(changedProperties: PropertyValues) {
|
||||
if (!changedProperties.has("action")) {
|
||||
return;
|
||||
|
@ -1,11 +1,9 @@
|
||||
import { consume } from "@lit-labs/context";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/ha-chip";
|
||||
import "../../../../components/ha-chip-set";
|
||||
import { showAutomationEditor } from "../../../../data/automation";
|
||||
import { fullEntitiesContext } from "../../../../data/context";
|
||||
import {
|
||||
DeviceAction,
|
||||
DeviceAutomation,
|
||||
@ -32,11 +30,9 @@ export abstract class HaDeviceAutomationCard<
|
||||
|
||||
@property({ attribute: false }) public automations: T[] = [];
|
||||
|
||||
@state() public _showSecondary = false;
|
||||
@property({ attribute: false }) entityReg?: EntityRegistryEntry[];
|
||||
|
||||
@state()
|
||||
@consume({ context: fullEntitiesContext, subscribe: true })
|
||||
_entityReg!: EntityRegistryEntry[];
|
||||
@state() public _showSecondary = false;
|
||||
|
||||
abstract headerKey: Parameters<typeof this.hass.localize>[0];
|
||||
|
||||
@ -67,7 +63,7 @@ export abstract class HaDeviceAutomationCard<
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (this.automations.length === 0) {
|
||||
if (this.automations.length === 0 || !this.entityReg) {
|
||||
return nothing;
|
||||
}
|
||||
const automations = this._showSecondary
|
||||
@ -89,7 +85,7 @@ export abstract class HaDeviceAutomationCard<
|
||||
>
|
||||
${this._localizeDeviceAutomation(
|
||||
this.hass,
|
||||
this._entityReg,
|
||||
this.entityReg!,
|
||||
automation
|
||||
)}
|
||||
</ha-chip>
|
||||
|
@ -109,6 +109,7 @@ export class DialogDeviceAutomation extends LitElement {
|
||||
<ha-device-triggers-card
|
||||
.hass=${this.hass}
|
||||
.automations=${this._triggers}
|
||||
.entityReg=${this._params.entityReg}
|
||||
></ha-device-triggers-card>
|
||||
`
|
||||
: ""}
|
||||
@ -117,6 +118,7 @@ export class DialogDeviceAutomation extends LitElement {
|
||||
<ha-device-conditions-card
|
||||
.hass=${this.hass}
|
||||
.automations=${this._conditions}
|
||||
.entityReg=${this._params.entityReg}
|
||||
></ha-device-conditions-card>
|
||||
`
|
||||
: ""}
|
||||
@ -126,6 +128,7 @@ export class DialogDeviceAutomation extends LitElement {
|
||||
.hass=${this.hass}
|
||||
.automations=${this._actions}
|
||||
.script=${this._params.script}
|
||||
.entityReg=${this._params.entityReg}
|
||||
></ha-device-actions-card>
|
||||
`
|
||||
: ""}
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { DeviceRegistryEntry } from "../../../../data/device_registry";
|
||||
import { EntityRegistryEntry } from "../../../../data/entity_registry";
|
||||
|
||||
export interface DeviceAutomationDialogParams {
|
||||
device: DeviceRegistryEntry;
|
||||
entityReg: EntityRegistryEntry[];
|
||||
script?: boolean;
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ import {
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { ifDefined } from "lit/directives/if-defined";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { consume } from "@lit-labs/context";
|
||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import { SENSOR_ENTITIES } from "../../../common/const";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
@ -84,6 +85,7 @@ import {
|
||||
loadDeviceRegistryDetailDialog,
|
||||
showDeviceRegistryDetailDialog,
|
||||
} from "./device-registry-detail/show-dialog-device-registry-detail";
|
||||
import { fullEntitiesContext } from "../../../data/context";
|
||||
|
||||
export interface EntityRegistryStateEntry extends EntityRegistryEntry {
|
||||
stateName?: string | null;
|
||||
@ -137,6 +139,10 @@ export class HaConfigDevicePage extends LitElement {
|
||||
|
||||
@state() private _deviceAlerts?: DeviceAlert[];
|
||||
|
||||
@state()
|
||||
@consume({ context: fullEntitiesContext, subscribe: true })
|
||||
_entityReg!: EntityRegistryEntry[];
|
||||
|
||||
private _logbookTime = { recent: 86400 };
|
||||
|
||||
private _device = memoizeOne(
|
||||
@ -422,12 +428,13 @@ export class HaConfigDevicePage extends LitElement {
|
||||
)
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.devices.automation.create",
|
||||
"type",
|
||||
this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
)
|
||||
{
|
||||
type: this.hass.localize(
|
||||
`ui.panel.config.devices.type.${
|
||||
device.entry_type || "device"
|
||||
}`
|
||||
),
|
||||
}
|
||||
)}
|
||||
.path=${mdiPlusCircle}
|
||||
></ha-icon-button>
|
||||
@ -1180,6 +1187,7 @@ export class HaConfigDevicePage extends LitElement {
|
||||
private _showScriptDialog() {
|
||||
showDeviceAutomationDialog(this, {
|
||||
device: this._device(this.deviceId, this.devices)!,
|
||||
entityReg: this._entityReg,
|
||||
script: true,
|
||||
});
|
||||
}
|
||||
@ -1187,6 +1195,7 @@ export class HaConfigDevicePage extends LitElement {
|
||||
private _showAutomationDialog() {
|
||||
showDeviceAutomationDialog(this, {
|
||||
device: this._device(this.deviceId, this.devices)!,
|
||||
entityReg: this._entityReg,
|
||||
script: false,
|
||||
});
|
||||
}
|
||||
|
@ -77,10 +77,13 @@ export class HaIntegrationActionCard extends LitElement {
|
||||
font-weight: 400;
|
||||
margin-top: 8px;
|
||||
margin-bottom: 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
h3 {
|
||||
font-size: 14px;
|
||||
margin: 0;
|
||||
max-width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
.header-button {
|
||||
position: absolute;
|
||||
|
@ -24,8 +24,6 @@ import { classMap } from "lit/directives/class-map";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { computeRTL } from "../../../common/util/compute_rtl";
|
||||
import "../../../components/ha-card";
|
||||
import "../../../components/ha-icon-next";
|
||||
import "../../../components/ha-list-item";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import { ConfigEntry, ERROR_STATES } from "../../../data/config_entries";
|
||||
import type { DeviceRegistryEntry } from "../../../data/device_registry";
|
||||
@ -114,12 +112,6 @@ export class HaIntegrationCard extends LitElement {
|
||||
: undefined}
|
||||
.manifest=${this.manifest}
|
||||
>
|
||||
<ha-icon-next
|
||||
slot="header-button"
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.integrations.config_entry.configure"
|
||||
)}
|
||||
></ha-icon-next>
|
||||
</ha-integration-header>
|
||||
</a>
|
||||
|
||||
@ -345,9 +337,6 @@ export class HaIntegrationCard extends LitElement {
|
||||
text-decoration: none;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
a ha-icon-next {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.icons {
|
||||
display: flex;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { mdiAlertCircleOutline, mdiAlertOutline } from "@mdi/js";
|
||||
import { LitElement, TemplateResult, css, html, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import "../../../components/ha-icon-next";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import { IntegrationManifest, domainToName } from "../../../data/integration";
|
||||
import { HomeAssistant } from "../../../types";
|
||||
@ -40,27 +41,34 @@ export class HaIntegrationHeader extends LitElement {
|
||||
/>
|
||||
<div class="info">
|
||||
<div
|
||||
class="primary ${this.warning || this.error ? "hasError" : ""}"
|
||||
class="primary ${this.warning || this.error ? "has-secondary" : ""}"
|
||||
role="heading"
|
||||
aria-level="1"
|
||||
>
|
||||
${domainName}
|
||||
</div>
|
||||
${this.error
|
||||
? html`<div class="error">
|
||||
<ha-svg-icon .path=${mdiAlertCircleOutline}></ha-svg-icon>${this
|
||||
.error}
|
||||
</div>`
|
||||
? html`
|
||||
<div class="secondary error">
|
||||
<ha-svg-icon .path=${mdiAlertCircleOutline}></ha-svg-icon>
|
||||
<span>${this.error}</span>
|
||||
</div>
|
||||
`
|
||||
: this.warning
|
||||
? html`<div class="warning">
|
||||
<ha-svg-icon .path=${mdiAlertOutline}></ha-svg-icon>${this
|
||||
.warning}
|
||||
</div>`
|
||||
? html`
|
||||
<div class="secondary warning">
|
||||
<ha-svg-icon .path=${mdiAlertOutline}></ha-svg-icon>
|
||||
<span>${this.warning}</span>
|
||||
</div>
|
||||
`
|
||||
: nothing}
|
||||
</div>
|
||||
<div class="header-button">
|
||||
<slot name="header-button"></slot>
|
||||
</div>
|
||||
<ha-icon-next
|
||||
class="header-button"
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.integrations.config_entry.configure"
|
||||
)}
|
||||
></ha-icon-next>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@ -76,12 +84,15 @@ export class HaIntegrationHeader extends LitElement {
|
||||
static styles = css`
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
padding-top: 16px;
|
||||
padding-bottom: 16px;
|
||||
padding-inline-start: 16px;
|
||||
padding-inline-end: 8px;
|
||||
direction: var(--direction);
|
||||
box-sizing: border-box;
|
||||
min-width: 0;
|
||||
}
|
||||
.header img {
|
||||
margin-inline-start: initial;
|
||||
@ -91,50 +102,55 @@ export class HaIntegrationHeader extends LitElement {
|
||||
direction: var(--direction);
|
||||
}
|
||||
.header .info {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
align-self: center;
|
||||
min-width: 0;
|
||||
}
|
||||
.primary,
|
||||
.warning,
|
||||
.error {
|
||||
word-wrap: break-word;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
ha-icon-next {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.primary {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
word-break: break-word;
|
||||
color: var(--primary-text-color);
|
||||
-webkit-line-clamp: 2;
|
||||
}
|
||||
.hasError {
|
||||
.has-secondary {
|
||||
-webkit-line-clamp: 1;
|
||||
font-size: 14px;
|
||||
}
|
||||
.warning,
|
||||
.error {
|
||||
line-height: 20px;
|
||||
.secondary {
|
||||
min-width: 0;
|
||||
--mdc-icon-size: 20px;
|
||||
-webkit-line-clamp: 1;
|
||||
font-size: 0.9em;
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
.secondary > span {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.secondary > ha-svg-icon {
|
||||
margin-right: 4px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.error ha-svg-icon {
|
||||
margin-right: 4px;
|
||||
color: var(--error-color);
|
||||
}
|
||||
.warning ha-svg-icon {
|
||||
margin-right: 4px;
|
||||
color: var(--warning-color);
|
||||
}
|
||||
.header-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 36px;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
|
@ -336,11 +336,15 @@ class ViewMountDialog extends LitElement {
|
||||
private async _connectMount() {
|
||||
this._error = undefined;
|
||||
this._waiting = true;
|
||||
const mountData = { ...this._data! };
|
||||
if (mountData.type === "cifs" && mountData.version === "auto") {
|
||||
mountData.version = undefined;
|
||||
}
|
||||
try {
|
||||
if (this._existing) {
|
||||
await updateSupervisorMount(this.hass, this._data!);
|
||||
await updateSupervisorMount(this.hass, mountData);
|
||||
} else {
|
||||
await createSupervisorMount(this.hass, this._data!);
|
||||
await createSupervisorMount(this.hass, mountData);
|
||||
}
|
||||
} catch (err: any) {
|
||||
this._error = extractApiErrorMessage(err);
|
||||
|
@ -21,6 +21,10 @@ import type { LovelaceCard } from "../../types";
|
||||
import { severityMap } from "../hui-gauge-card";
|
||||
import type { EnergyCarbonGaugeCardConfig } from "../types";
|
||||
|
||||
const FORMAT_OPTIONS = {
|
||||
maximumFractionDigits: 0,
|
||||
};
|
||||
|
||||
@customElement("hui-energy-carbon-consumed-gauge-card")
|
||||
class HuiEnergyCarbonGaugeCard
|
||||
extends SubscribeMixin(LitElement)
|
||||
@ -129,6 +133,7 @@ class HuiEnergyCarbonGaugeCard
|
||||
min="0"
|
||||
max="100"
|
||||
.value=${value}
|
||||
.formatOptions=${FORMAT_OPTIONS}
|
||||
.locale=${this.hass.locale}
|
||||
label="%"
|
||||
style=${styleMap({
|
||||
|
@ -19,6 +19,10 @@ import type { LovelaceCard } from "../../types";
|
||||
import { severityMap } from "../hui-gauge-card";
|
||||
import type { EnergySelfSufficiencyGaugeCardConfig } from "../types";
|
||||
|
||||
const FORMAT_OPTIONS = {
|
||||
maximumFractionDigits: 0,
|
||||
};
|
||||
|
||||
@customElement("hui-energy-self-sufficiency-gauge-card")
|
||||
class HuiEnergySelfSufficiencyGaugeCard
|
||||
extends SubscribeMixin(LitElement)
|
||||
@ -174,8 +178,9 @@ class HuiEnergySelfSufficiencyGaugeCard
|
||||
min="0"
|
||||
max="100"
|
||||
.value=${value}
|
||||
.locale=${this.hass.locale}
|
||||
label="%"
|
||||
.formatOptions=${FORMAT_OPTIONS}
|
||||
.locale=${this.hass.locale}
|
||||
style=${styleMap({
|
||||
"--gauge-color": this._computeSeverity(value),
|
||||
})}
|
||||
|
@ -19,6 +19,10 @@ import type { LovelaceCard } from "../../types";
|
||||
import { severityMap } from "../hui-gauge-card";
|
||||
import type { EnergySolarGaugeCardConfig } from "../types";
|
||||
|
||||
const FORMAT_OPTIONS = {
|
||||
maximumFractionDigits: 0,
|
||||
};
|
||||
|
||||
@customElement("hui-energy-solar-consumed-gauge-card")
|
||||
class HuiEnergySolarGaugeCard
|
||||
extends SubscribeMixin(LitElement)
|
||||
@ -109,8 +113,9 @@ class HuiEnergySolarGaugeCard
|
||||
min="0"
|
||||
max="100"
|
||||
.value=${value}
|
||||
.locale=${this.hass.locale}
|
||||
label="%"
|
||||
.formatOptions=${FORMAT_OPTIONS}
|
||||
.locale=${this.hass.locale}
|
||||
style=${styleMap({
|
||||
"--gauge-color": this._computeSeverity(value),
|
||||
})}
|
||||
|
@ -82,12 +82,12 @@ export class HuiGaugeCardEditor
|
||||
{
|
||||
name: "min",
|
||||
default: DEFAULT_MIN,
|
||||
selector: { number: { mode: "box" } },
|
||||
selector: { number: { mode: "box", step: "any" } },
|
||||
},
|
||||
{
|
||||
name: "max",
|
||||
default: DEFAULT_MAX,
|
||||
selector: { number: { mode: "box" } },
|
||||
selector: { number: { mode: "box", step: "any" } },
|
||||
},
|
||||
],
|
||||
},
|
||||
@ -107,15 +107,15 @@ export class HuiGaugeCardEditor
|
||||
schema: [
|
||||
{
|
||||
name: "green",
|
||||
selector: { number: { mode: "box" } },
|
||||
selector: { number: { mode: "box", step: "any" } },
|
||||
},
|
||||
{
|
||||
name: "yellow",
|
||||
selector: { number: { mode: "box" } },
|
||||
selector: { number: { mode: "box", step: "any" } },
|
||||
},
|
||||
{
|
||||
name: "red",
|
||||
selector: { number: { mode: "box" } },
|
||||
selector: { number: { mode: "box", step: "any" } },
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -2573,25 +2573,50 @@
|
||||
"label": "Call service",
|
||||
"response_variable": "Response variable",
|
||||
"has_optional_response": "This service can return a response, if you want to use the response, enter the name of a variable the response will be saved in",
|
||||
"has_response": "This service returns a response, enter the name of a variable the response will be saved in"
|
||||
"has_response": "This service returns a response, enter the name of a variable the response will be saved in",
|
||||
"description": {
|
||||
"service_based_on_template": "Call a service based on a template on {targets}",
|
||||
"service_based_on_name": "Call a service ''{name}'' on {targets}",
|
||||
"service": "Call a service",
|
||||
"target_template": "templated {name}",
|
||||
"target_unknown_entity": "unknown entity",
|
||||
"target_unknown_device": "unknown device",
|
||||
"target_unknown_area": "unknown area"
|
||||
}
|
||||
},
|
||||
"play_media": {
|
||||
"label": "Play media"
|
||||
"label": "Play media",
|
||||
"description": {
|
||||
"full": "Play {hasMedia, select, \n true {{media}} \n other {media}\n } on {hasMediaPlayer, select, \n true {{mediaPlayer}} \n other {a media player}\n }"
|
||||
}
|
||||
},
|
||||
"delay": {
|
||||
"label": "Wait for time to pass (delay)",
|
||||
"delay": "Duration"
|
||||
"delay": "Duration",
|
||||
"description": {
|
||||
"full": "Delay {duration}",
|
||||
"duration_string": "for {string}",
|
||||
"duration_template": "based on a template",
|
||||
"duration_unknown": "a duration"
|
||||
}
|
||||
},
|
||||
"wait_template": {
|
||||
"label": "Wait for a template",
|
||||
"wait_template": "Wait Template",
|
||||
"timeout": "Timeout (optional)",
|
||||
"continue_timeout": "Continue on timeout"
|
||||
"continue_timeout": "Continue on timeout",
|
||||
"description": {
|
||||
"full": "Wait for a template to evaluate to true"
|
||||
}
|
||||
},
|
||||
"wait_for_trigger": {
|
||||
"label": "Wait for a trigger",
|
||||
"timeout": "[%key:ui::panel::config::automation::editor::actions::type::wait_template::timeout%]",
|
||||
"continue_timeout": "[%key:ui::panel::config::automation::editor::actions::type::wait_template::continue_timeout%]"
|
||||
"continue_timeout": "[%key:ui::panel::config::automation::editor::actions::type::wait_template::continue_timeout%]",
|
||||
"description": {
|
||||
"wait_for_a_trigger": "Wait for a trigger",
|
||||
"wait_for_triggers_with_name": "Wait for ''{triggers}''"
|
||||
}
|
||||
},
|
||||
"condition": {
|
||||
"label": "Condition"
|
||||
@ -2599,7 +2624,11 @@
|
||||
"event": {
|
||||
"label": "Event",
|
||||
"event": "[%key:ui::panel::config::automation::editor::triggers::type::event::label%]",
|
||||
"event_data": "[%key:ui::panel::config::automation::editor::triggers::type::event::event_data%]"
|
||||
"event_data": "[%key:ui::panel::config::automation::editor::triggers::type::event::event_data%]",
|
||||
"description": {
|
||||
"full": "Fire event {name}",
|
||||
"template": "based on a template"
|
||||
}
|
||||
},
|
||||
"device_id": {
|
||||
"label": "Device",
|
||||
@ -2618,7 +2647,11 @@
|
||||
},
|
||||
"activate_scene": {
|
||||
"label": "Scene",
|
||||
"scene": "Scene"
|
||||
"scene": "Scene",
|
||||
"description": {
|
||||
"activate_scene": "Activate a scene",
|
||||
"activate_scene_with_name": "Activate scene {name}"
|
||||
}
|
||||
},
|
||||
"repeat": {
|
||||
"label": "Repeat",
|
||||
@ -2636,7 +2669,14 @@
|
||||
"conditions": "Until conditions"
|
||||
}
|
||||
},
|
||||
"sequence": "Actions"
|
||||
"sequence": "Actions",
|
||||
"description": {
|
||||
"full": "Repeat an action {chosenAction}",
|
||||
"count": "{count} {count, plural,\n one {time}\n other {times}\n}",
|
||||
"while": "while ''{conditions}'' is true",
|
||||
"until": "until ''{conditions}'' is true",
|
||||
"for_each": "for every item: {items}"
|
||||
}
|
||||
},
|
||||
"choose": {
|
||||
"label": "Choose",
|
||||
@ -2646,26 +2686,47 @@
|
||||
"add_option": "Add option",
|
||||
"remove_option": "Remove option",
|
||||
"conditions": "Conditions",
|
||||
"sequence": "Actions"
|
||||
"sequence": "Actions",
|
||||
"description": {
|
||||
"full": "Choose between {number} {number, plural,\n one {action}\n other{actions}\n}",
|
||||
"no_action": "Choose an action"
|
||||
}
|
||||
},
|
||||
"if": {
|
||||
"label": "If-then",
|
||||
"if": "If",
|
||||
"then": "Then",
|
||||
"else": "Else",
|
||||
"add_else": "Add else"
|
||||
"add_else": "Add else",
|
||||
"description": {
|
||||
"full": "Perform ''{action}'' if ''{conditions}''{hasElse, select, \n true { otherwise ''{elseAction}''} \n other {}\n } "
|
||||
}
|
||||
},
|
||||
"stop": {
|
||||
"label": "Stop",
|
||||
"stop": "Reason for stopping",
|
||||
"response_variable": "The name of the variable to use as response",
|
||||
"error": "Stop because of an unexpected error"
|
||||
"error": "Stop because of an unexpected error",
|
||||
"description": {
|
||||
"full": "Stop {hasReason, select, \n true { because: {reason}} \n other {}\n }"
|
||||
}
|
||||
},
|
||||
"parallel": {
|
||||
"label": "Run in parallel"
|
||||
"label": "Run in parallel",
|
||||
"description": {
|
||||
"full": "Run {number} {number, plural,\n one {action}\n other {actions}\n} in parallel"
|
||||
}
|
||||
},
|
||||
"variables": {
|
||||
"label": "Define variables"
|
||||
"label": "Define variables",
|
||||
"description": {
|
||||
"full": "Define variables {names}"
|
||||
}
|
||||
},
|
||||
"check_condition": {
|
||||
"description": {
|
||||
"full": "Test {condition}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2782,7 +2843,6 @@
|
||||
},
|
||||
"discover_blueprint_tip": "[%key:ui::panel::config::automation::dialog_new::discover_blueprint_tip%]"
|
||||
},
|
||||
|
||||
"editor": {
|
||||
"alias": "Name",
|
||||
"icon": "Icon",
|
||||
|
98
yarn.lock
98
yarn.lock
@ -2107,12 +2107,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@lrnwebcomponents/simple-tooltip@npm:7.0.10":
|
||||
version: 7.0.10
|
||||
resolution: "@lrnwebcomponents/simple-tooltip@npm:7.0.10"
|
||||
"@lrnwebcomponents/simple-tooltip@npm:7.0.11":
|
||||
version: 7.0.11
|
||||
resolution: "@lrnwebcomponents/simple-tooltip@npm:7.0.11"
|
||||
dependencies:
|
||||
lit: ^2.7.5
|
||||
checksum: 4e355b580b21b246fed49d3625e6999777b12d8154b786ab27eeafba6d49d2efa4a49a8aa4e7b5e75874e68a1795f911f295f80eedeaf1ad5fbd633d6efeb7c4
|
||||
checksum: 95c89d1f6ace6229b8661d953c792cef4d0842cbf4de830505a75f5fef9a312f730a7b0085aa11bb4e8e6c8a94d4c1d3512127d208695274f130e9f360f770b9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -3141,14 +3141,14 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@material/web@npm:=1.0.0-pre.11":
|
||||
version: 1.0.0-pre.11
|
||||
resolution: "@material/web@npm:1.0.0-pre.11"
|
||||
"@material/web@npm:=1.0.0-pre.12":
|
||||
version: 1.0.0-pre.12
|
||||
resolution: "@material/web@npm:1.0.0-pre.12"
|
||||
dependencies:
|
||||
lit: ^2.7.4
|
||||
safevalues: ^0.4.3
|
||||
tslib: ^2.4.0
|
||||
checksum: 6c08d5d1b159472032d8a274eb29c22229dbcd29a80c478bbf680906903a9542dab9916d547e40c3b607a0ecfe51484bc8681b8c2f1fcd521b2b20fe23d84a66
|
||||
checksum: 21132f90e004c84745bd9ba15aacc0ec74ee5c67e8dd610da14220cf0fa129882a82c409094b39226a82f9eaae0c1fbea9a6df07a6a056fc2ef5b771a14b078a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -9156,18 +9156,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"glob@npm:10.3.0, glob@npm:^10.2.2":
|
||||
version: 10.3.0
|
||||
resolution: "glob@npm:10.3.0"
|
||||
"glob@npm:10.3.1, glob@npm:^10.2.2":
|
||||
version: 10.3.1
|
||||
resolution: "glob@npm:10.3.1"
|
||||
dependencies:
|
||||
foreground-child: ^3.1.0
|
||||
jackspeak: ^2.0.3
|
||||
minimatch: ^9.0.1
|
||||
minipass: ^5.0.0 || ^6.0.2
|
||||
path-scurry: ^1.7.0
|
||||
path-scurry: ^1.10.0
|
||||
bin:
|
||||
glob: dist/cjs/src/bin.js
|
||||
checksum: 6fa4ac0a86ffec1c5715a2e6fbdd63e1e7f1c2c8f5db08cc3256cdfcb81093678e7c80a3d100b502a1b9d141369ecf87bc24fe2bcb72acec7b14626d358a4eb0
|
||||
checksum: 19c8c2805658b1002fecf0722cd609a33153d756a0d5260676bd0e9c5e6ef889ec9cce6d3dac0411aa90bce8de3d14f25b6f5589a3292582cccbfeddd0e98cc4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -9578,10 +9578,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"hls.js@npm:1.4.6":
|
||||
version: 1.4.6
|
||||
resolution: "hls.js@npm:1.4.6"
|
||||
checksum: 7a44107c92e52859bfd5a37b6ea647cfea20848466286c1280b2cf956cfaccf8131fa54867cd8edfb60042a238025fb8788263fd9dfb9d1798ddbdc08f5aab50
|
||||
"hls.js@npm:1.4.7":
|
||||
version: 1.4.7
|
||||
resolution: "hls.js@npm:1.4.7"
|
||||
checksum: ca58d97d49048fa6f437b834b807d26f5b47750aae57a573f179155e63e39159aa304f3ef13504b42c19969984918b17557e9311a779b0b04641bd6b668b45db
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -9622,7 +9622,7 @@ __metadata:
|
||||
"@lit-labs/context": 0.3.3
|
||||
"@lit-labs/motion": 1.0.3
|
||||
"@lit-labs/virtualizer": 2.0.3
|
||||
"@lrnwebcomponents/simple-tooltip": 7.0.10
|
||||
"@lrnwebcomponents/simple-tooltip": 7.0.11
|
||||
"@material/chips": =14.0.0-canary.53b3cad2f.0
|
||||
"@material/data-table": =14.0.0-canary.53b3cad2f.0
|
||||
"@material/mwc-button": 0.27.0
|
||||
@ -9648,7 +9648,7 @@ __metadata:
|
||||
"@material/mwc-top-app-bar": 0.27.0
|
||||
"@material/mwc-top-app-bar-fixed": 0.27.0
|
||||
"@material/top-app-bar": =14.0.0-canary.53b3cad2f.0
|
||||
"@material/web": =1.0.0-pre.11
|
||||
"@material/web": =1.0.0-pre.12
|
||||
"@mdi/js": 7.2.96
|
||||
"@mdi/svg": 7.2.96
|
||||
"@octokit/auth-oauth-device": 5.0.2
|
||||
@ -9728,7 +9728,7 @@ __metadata:
|
||||
fancy-log: 2.0.0
|
||||
fs-extra: 11.1.1
|
||||
fuse.js: 6.6.2
|
||||
glob: 10.3.0
|
||||
glob: 10.3.1
|
||||
google-timezones-json: 1.1.0
|
||||
gulp: 4.0.2
|
||||
gulp-flatmap: 1.0.2
|
||||
@ -9736,7 +9736,7 @@ __metadata:
|
||||
gulp-merge-json: 2.1.2
|
||||
gulp-rename: 2.0.0
|
||||
gulp-zopfli-green: 6.0.1
|
||||
hls.js: 1.4.6
|
||||
hls.js: 1.4.7
|
||||
home-assistant-js-websocket: 8.1.0
|
||||
html-minifier-terser: 7.2.0
|
||||
husky: 8.0.3
|
||||
@ -9747,7 +9747,7 @@ __metadata:
|
||||
jszip: 3.10.1
|
||||
leaflet: 1.9.4
|
||||
leaflet-draw: 1.0.4
|
||||
lint-staged: 13.2.2
|
||||
lint-staged: 13.2.3
|
||||
lit: 2.7.5
|
||||
lit-analyzer: 2.0.0-pre.3
|
||||
lodash.template: 4.5.0
|
||||
@ -9785,7 +9785,7 @@ __metadata:
|
||||
ts-lit-plugin: 2.0.0-pre.1
|
||||
tsparticles-engine: 2.10.1
|
||||
tsparticles-preset-links: 2.10.1
|
||||
typescript: 5.1.3
|
||||
typescript: 5.1.6
|
||||
unfetch: 5.0.0
|
||||
vinyl-buffer: 1.0.1
|
||||
vinyl-source-stream: 2.0.0
|
||||
@ -9793,7 +9793,7 @@ __metadata:
|
||||
vis-network: 9.1.6
|
||||
vue: 2.7.14
|
||||
vue2-daterange-picker: 0.6.8
|
||||
webpack: 5.88.0
|
||||
webpack: 5.88.1
|
||||
webpack-cli: 5.1.4
|
||||
webpack-dev-server: 4.15.1
|
||||
webpack-manifest-plugin: 5.0.0
|
||||
@ -11309,9 +11309,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lint-staged@npm:13.2.2":
|
||||
version: 13.2.2
|
||||
resolution: "lint-staged@npm:13.2.2"
|
||||
"lint-staged@npm:13.2.3":
|
||||
version: 13.2.3
|
||||
resolution: "lint-staged@npm:13.2.3"
|
||||
dependencies:
|
||||
chalk: 5.2.0
|
||||
cli-truncate: ^3.1.0
|
||||
@ -11328,7 +11328,7 @@ __metadata:
|
||||
yaml: ^2.2.2
|
||||
bin:
|
||||
lint-staged: bin/lint-staged.js
|
||||
checksum: f34f6e2e85e827364658ab8717bf8b35239473c2d4959d746b053a4cf158ac657348444c755820a8ef3eac2d4753a37c52e9db3e201ee20b085f26d2f2fbc9ed
|
||||
checksum: ff51a1e33072f488b28b938ed47323816a1ff278ef6d0e5cbe1704b292773a6c8ce945b504eae3a9b5702917a979523a741f17023e16077bd5fa35be687cc067
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -11622,10 +11622,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lru-cache@npm:^9.1.1":
|
||||
version: 9.1.2
|
||||
resolution: "lru-cache@npm:9.1.2"
|
||||
checksum: d3415634be3908909081fc4c56371a8d562d9081eba70543d86871b978702fffd0e9e362b83921b27a29ae2b37b90f55675aad770a54ac83bb3e4de5049d4b15
|
||||
"lru-cache@npm:^9.1.1 || ^10.0.0":
|
||||
version: 10.0.0
|
||||
resolution: "lru-cache@npm:10.0.0"
|
||||
checksum: 18f101675fe283bc09cda0ef1e3cc83781aeb8373b439f086f758d1d91b28730950db785999cd060d3c825a8571c03073e8c14512b6655af2188d623031baf50
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -12954,13 +12954,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"path-scurry@npm:^1.7.0":
|
||||
version: 1.9.2
|
||||
resolution: "path-scurry@npm:1.9.2"
|
||||
"path-scurry@npm:^1.10.0":
|
||||
version: 1.10.0
|
||||
resolution: "path-scurry@npm:1.10.0"
|
||||
dependencies:
|
||||
lru-cache: ^9.1.1
|
||||
lru-cache: ^9.1.1 || ^10.0.0
|
||||
minipass: ^5.0.0 || ^6.0.2
|
||||
checksum: 92888dfb68e285043c6d3291c8e971d5d2bc2f5082f4d7b5392896f34be47024c9d0a8b688dd7ae6d125acc424699195474927cb4f00049a9b1ec7c4256fa8e0
|
||||
checksum: 3b66a4a6ab66e45755b577c966ecf0da92d3e068b3c992d8f69aa2cc908ef4eda9358253e9b4f86cad43d3ad810ec445be164105975f5cb3fdab68459c59dc6e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -15428,13 +15428,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"typescript@npm:5.1.3":
|
||||
version: 5.1.3
|
||||
resolution: "typescript@npm:5.1.3"
|
||||
"typescript@npm:5.1.6":
|
||||
version: 5.1.6
|
||||
resolution: "typescript@npm:5.1.6"
|
||||
bin:
|
||||
tsc: bin/tsc
|
||||
tsserver: bin/tsserver
|
||||
checksum: d9d51862d98efa46534f2800a1071a613751b1585dc78884807d0c179bcd93d6e9d4012a508e276742f5f33c480adefc52ffcafaf9e0e00ab641a14cde9a31c7
|
||||
checksum: b2f2c35096035fe1f5facd1e38922ccb8558996331405eb00a5111cc948b2e733163cc22fab5db46992aba7dd520fff637f2c1df4996ff0e134e77d3249a7350
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -15448,13 +15448,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"typescript@patch:typescript@5.1.3#~builtin<compat/typescript>":
|
||||
version: 5.1.3
|
||||
resolution: "typescript@patch:typescript@npm%3A5.1.3#~builtin<compat/typescript>::version=5.1.3&hash=5da071"
|
||||
"typescript@patch:typescript@5.1.6#~builtin<compat/typescript>":
|
||||
version: 5.1.6
|
||||
resolution: "typescript@patch:typescript@npm%3A5.1.6#~builtin<compat/typescript>::version=5.1.6&hash=5da071"
|
||||
bin:
|
||||
tsc: bin/tsc
|
||||
tsserver: bin/tsserver
|
||||
checksum: 6f0a9dca6bf4ce9dcaf4e282aade55ef4c56ecb5fb98d0a4a5c0113398815aea66d871b5611e83353e5953a19ed9ef103cf5a76ac0f276d550d1e7cd5344f61e
|
||||
checksum: f53bfe97f7c8b2b6d23cf572750d4e7d1e0c5fff1c36d859d0ec84556a827b8785077bc27676bf7e71fae538e517c3ecc0f37e7f593be913d884805d931bc8be
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -16135,9 +16135,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"webpack@npm:5.88.0":
|
||||
version: 5.88.0
|
||||
resolution: "webpack@npm:5.88.0"
|
||||
"webpack@npm:5.88.1":
|
||||
version: 5.88.1
|
||||
resolution: "webpack@npm:5.88.1"
|
||||
dependencies:
|
||||
"@types/eslint-scope": ^3.7.3
|
||||
"@types/estree": ^1.0.0
|
||||
@ -16168,7 +16168,7 @@ __metadata:
|
||||
optional: true
|
||||
bin:
|
||||
webpack: bin/webpack.js
|
||||
checksum: 9fd1568b34ec2e99ba97c8509a15ab2576ec80c396e7015551ec814b24cfc11de173acba3e114dafe95f1a6d460781b09d6201e6a1fb15110e1d01a09f61a283
|
||||
checksum: 726e7e05ab2e7c142609a673dd6aa1a711ed97f349418a2a393d650c5ddad172d191257f60e1e37f6b2a77261571c202aabd5ce9240791a686774f0801cf5ec2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user