mirror of
https://github.com/home-assistant/frontend.git
synced 2026-05-19 15:47:05 +00:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 18d765ba8e | |||
| d28c388eba | |||
| b32a76fb10 | |||
| 950de204aa | |||
| 91b6a4c4b6 | |||
| 643cc4ca7d | |||
| 9ef71e6cf4 | |||
| bface72af7 | |||
| 90028b2e22 | |||
| 914c48abd5 | |||
| 79c082acde | |||
| 0456b40210 |
+3
-4
@@ -62,7 +62,6 @@
|
||||
"@lit-labs/virtualizer": "2.1.1",
|
||||
"@lit/context": "1.1.6",
|
||||
"@lit/reactive-element": "2.1.2",
|
||||
"@material/data-table": "=14.0.0-canary.53b3cad2f.0",
|
||||
"@material/mwc-base": "0.27.0",
|
||||
"@material/mwc-formfield": "patch:@material/mwc-formfield@npm%3A0.27.0#~/.yarn/patches/@material-mwc-formfield-npm-0.27.0-9528cb60f6.patch",
|
||||
"@material/mwc-list": "patch:@material/mwc-list@npm%3A0.27.0#~/.yarn/patches/@material-mwc-list-npm-0.27.0-5344fc9de4.patch",
|
||||
@@ -75,8 +74,8 @@
|
||||
"@replit/codemirror-indentation-markers": "6.5.3",
|
||||
"@swc/helpers": "0.5.21",
|
||||
"@thomasloven/round-slider": "0.6.0",
|
||||
"@tsparticles/engine": "4.0.0",
|
||||
"@tsparticles/preset-links": "4.0.0",
|
||||
"@tsparticles/engine": "4.0.1",
|
||||
"@tsparticles/preset-links": "4.0.1",
|
||||
"@vibrant/color": "4.0.4",
|
||||
"@webcomponents/scoped-custom-element-registry": "0.0.10",
|
||||
"@webcomponents/webcomponentsjs": "2.8.0",
|
||||
@@ -166,7 +165,7 @@
|
||||
"babel-plugin-template-html-minifier": "4.1.0",
|
||||
"browserslist-useragent-regexp": "4.1.4",
|
||||
"del": "8.0.1",
|
||||
"eslint": "10.3.0",
|
||||
"eslint": "10.4.0",
|
||||
"eslint-config-prettier": "10.1.8",
|
||||
"eslint-import-resolver-webpack": "0.13.11",
|
||||
"eslint-plugin-import-x": "4.16.2",
|
||||
|
||||
@@ -187,7 +187,6 @@ export class HaAutomationRow extends LitElement {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow-wrap: anywhere;
|
||||
margin: 0 var(--ha-space-3);
|
||||
}
|
||||
::slotted([slot="header"]) {
|
||||
overflow-wrap: anywhere;
|
||||
|
||||
@@ -116,7 +116,7 @@ export class HaProgressButton extends LitElement {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
ha-svg-icon {
|
||||
:host([appearance="brand"]) ha-svg-icon {
|
||||
color: var(--white-color);
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -30,6 +30,7 @@ export class HaSettingsRow extends LitElement {
|
||||
<slot name="prefix"></slot>
|
||||
<div
|
||||
class="body"
|
||||
part="heading"
|
||||
?two-line=${!this.threeLine && hasDescription}
|
||||
?three-line=${this.threeLine}
|
||||
>
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import "@home-assistant/webawesome/dist/components/textarea/textarea";
|
||||
import type WaTextarea from "@home-assistant/webawesome/dist/components/textarea/textarea";
|
||||
import { HasSlotController } from "@home-assistant/webawesome/dist/internal/slot";
|
||||
import type { PropertyValues } from "lit";
|
||||
import { LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, query } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { ifDefined } from "lit/directives/if-defined";
|
||||
import { WaInputMixin, waInputStyles } from "./input/wa-input-mixin";
|
||||
import { stopPropagation } from "../common/dom/stop_propagation";
|
||||
import { WaInputMixin, waInputStyles } from "./input/wa-input-mixin";
|
||||
|
||||
/**
|
||||
* Home Assistant textarea component
|
||||
@@ -84,6 +85,20 @@ export class HaTextArea extends WaInputMixin(LitElement) {
|
||||
this.removeEventListener("keydown", stopPropagation);
|
||||
}
|
||||
|
||||
protected override async firstUpdated(
|
||||
changedProperties: PropertyValues<this>
|
||||
): Promise<void> {
|
||||
super.firstUpdated(changedProperties);
|
||||
if (this.autofocus) {
|
||||
await this._textarea?.updateComplete;
|
||||
this._textarea?.focus();
|
||||
}
|
||||
}
|
||||
|
||||
public override focus(options?: FocusOptions): void {
|
||||
this._textarea?.focus(options);
|
||||
}
|
||||
|
||||
protected render() {
|
||||
const hasLabelSlot = this.label
|
||||
? false
|
||||
|
||||
@@ -95,6 +95,7 @@ export interface TriggerList {
|
||||
|
||||
export interface BaseTrigger {
|
||||
alias?: string;
|
||||
comment?: string;
|
||||
/** @deprecated Use `trigger` instead */
|
||||
platform?: string;
|
||||
trigger: string;
|
||||
@@ -240,6 +241,7 @@ export type Trigger = LegacyTrigger | TriggerList | PlatformTrigger;
|
||||
interface BaseCondition {
|
||||
condition: string;
|
||||
alias?: string;
|
||||
comment?: string;
|
||||
enabled?: boolean;
|
||||
options?: Record<string, unknown>;
|
||||
}
|
||||
@@ -607,6 +609,7 @@ export interface AutomationClipboard {
|
||||
export interface BaseSidebarConfig {
|
||||
delete: () => void;
|
||||
close: (focus?: boolean) => void;
|
||||
editComment: () => void;
|
||||
}
|
||||
|
||||
export interface TriggerSidebarConfig extends BaseSidebarConfig {
|
||||
@@ -668,6 +671,7 @@ export interface OptionSidebarConfig extends BaseSidebarConfig {
|
||||
rename: () => void;
|
||||
duplicate: () => void;
|
||||
defaultOption?: boolean;
|
||||
comment?: string;
|
||||
}
|
||||
|
||||
export interface ScriptFieldSidebarConfig extends BaseSidebarConfig {
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
|
||||
export interface DeviceAutomation {
|
||||
alias?: string;
|
||||
comment?: string;
|
||||
device_id: string;
|
||||
domain: string;
|
||||
entity_id?: string;
|
||||
|
||||
@@ -148,6 +148,7 @@ export interface GridSourceTypeEnergyPreference {
|
||||
power_config?: PowerConfig;
|
||||
|
||||
cost_adjustment_day: number;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
export interface SolarSourceTypeEnergyPreference {
|
||||
@@ -156,6 +157,7 @@ export interface SolarSourceTypeEnergyPreference {
|
||||
stat_energy_from: string;
|
||||
stat_rate?: string;
|
||||
config_entry_solar_forecast: string[] | null;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
export interface BatterySourceTypeEnergyPreference {
|
||||
@@ -165,6 +167,7 @@ export interface BatterySourceTypeEnergyPreference {
|
||||
stat_rate?: string; // always available if power_config is set
|
||||
power_config?: PowerConfig;
|
||||
stat_soc?: string;
|
||||
name?: string;
|
||||
}
|
||||
export interface GasSourceTypeEnergyPreference {
|
||||
type: "gas";
|
||||
|
||||
+97
-199
@@ -1,11 +1,15 @@
|
||||
import { atLeastVersion } from "../../common/config/version";
|
||||
import type { HaFormSchema } from "../../components/ha-form/types";
|
||||
import type { HomeAssistant, TranslationDict } from "../../types";
|
||||
import type {
|
||||
CallWS,
|
||||
HomeAssistant,
|
||||
HomeAssistantApi,
|
||||
TranslationDict,
|
||||
} from "../../types";
|
||||
import { supervisorApiCall } from "../supervisor/common";
|
||||
import type { StoreAddonDetails } from "../supervisor/store";
|
||||
import type { Supervisor, SupervisorArch } from "../supervisor/supervisor";
|
||||
import type { HassioResponse } from "./common";
|
||||
import { extractApiErrorMessage, hassioApiResultExtractor } from "./common";
|
||||
import { extractApiErrorMessage } from "./common";
|
||||
|
||||
export type AddonCapability = Exclude<
|
||||
keyof TranslationDict["ui"]["panel"]["config"]["apps"]["dashboard"]["capability"],
|
||||
@@ -143,57 +147,38 @@ export interface HassioAddonSetOptionParams {
|
||||
}
|
||||
|
||||
export const reloadHassioAddons = async (hass: HomeAssistant) => {
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
await hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: "/addons/reload",
|
||||
method: "post",
|
||||
});
|
||||
return;
|
||||
}
|
||||
await hass.callApi<HassioResponse<void>>("POST", `hassio/addons/reload`);
|
||||
await hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: "/addons/reload",
|
||||
method: "post",
|
||||
});
|
||||
};
|
||||
|
||||
export const fetchHassioAddonsInfo = async (
|
||||
hass: HomeAssistant
|
||||
): Promise<HassioAddonsInfo> => {
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
return hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: "/addons",
|
||||
method: "get",
|
||||
});
|
||||
}
|
||||
|
||||
return hassioApiResultExtractor(
|
||||
await hass.callApi<HassioResponse<HassioAddonsInfo>>("GET", `hassio/addons`)
|
||||
);
|
||||
return hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: "/addons",
|
||||
method: "get",
|
||||
});
|
||||
};
|
||||
|
||||
export const fetchHassioAddonInfo = async (
|
||||
hass: HomeAssistant,
|
||||
callWS: CallWS,
|
||||
slug: string
|
||||
): Promise<HassioAddonDetails> => {
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
return hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/info`,
|
||||
method: "get",
|
||||
});
|
||||
}
|
||||
|
||||
return hassioApiResultExtractor(
|
||||
await hass.callApi<HassioResponse<HassioAddonDetails>>(
|
||||
"GET",
|
||||
`hassio/addons/${slug}/info`
|
||||
)
|
||||
);
|
||||
return callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/info`,
|
||||
method: "get",
|
||||
});
|
||||
};
|
||||
|
||||
export const fetchHassioAddonChangelog = async (
|
||||
hass: HomeAssistant,
|
||||
api: HomeAssistantApi,
|
||||
slug: string
|
||||
) => hass.callApi<string>("GET", `hassio/addons/${slug}/changelog`);
|
||||
) => api.callApi<string>("GET", `hassio/addons/${slug}/changelog`);
|
||||
|
||||
export const fetchHassioAddonLogs = async (hass: HomeAssistant, slug: string) =>
|
||||
hass.callApi<string>("GET", `hassio/addons/${slug}/logs`);
|
||||
@@ -204,119 +189,77 @@ export const fetchHassioAddonDocumentation = async (
|
||||
) => hass.callApi<string>("GET", `hassio/addons/${slug}/documentation`);
|
||||
|
||||
export const setHassioAddonOption = async (
|
||||
hass: HomeAssistant,
|
||||
callWS: CallWS,
|
||||
slug: string,
|
||||
data: HassioAddonSetOptionParams
|
||||
) => {
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
const response = await hass.callWS<HassioResponse<any>>({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/options`,
|
||||
method: "post",
|
||||
data,
|
||||
});
|
||||
const response = await callWS<HassioResponse<any>>({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/options`,
|
||||
method: "post",
|
||||
data,
|
||||
});
|
||||
|
||||
if (response.result === "error") {
|
||||
throw Error(extractApiErrorMessage(response));
|
||||
}
|
||||
return response;
|
||||
if (response.result === "error") {
|
||||
throw Error(extractApiErrorMessage(response));
|
||||
}
|
||||
|
||||
return hass.callApi<HassioResponse<any>>(
|
||||
"POST",
|
||||
`hassio/addons/${slug}/options`,
|
||||
data
|
||||
);
|
||||
return response;
|
||||
};
|
||||
|
||||
export const validateHassioAddonOption = async (
|
||||
hass: HomeAssistant,
|
||||
callWS: CallWS,
|
||||
slug: string,
|
||||
data?: any
|
||||
): Promise<{ message: string; valid: boolean }> => {
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
return hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/options/validate`,
|
||||
method: "post",
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
await hass.callApi<HassioResponse<{ message: string; valid: boolean }>>(
|
||||
"POST",
|
||||
`hassio/addons/${slug}/options/validate`
|
||||
)
|
||||
).data;
|
||||
return callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/options/validate`,
|
||||
method: "post",
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
export const startHassioAddon = async (hass: HomeAssistant, slug: string) => {
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
return hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/start`,
|
||||
method: "post",
|
||||
timeout: null,
|
||||
});
|
||||
}
|
||||
|
||||
return hass.callApi<string>("POST", `hassio/addons/${slug}/start`);
|
||||
export const startHassioAddon = async (callWS: CallWS, slug: string) => {
|
||||
return callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/start`,
|
||||
method: "post",
|
||||
timeout: null,
|
||||
});
|
||||
};
|
||||
|
||||
export const stopHassioAddon = async (hass: HomeAssistant, slug: string) => {
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
return hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/stop`,
|
||||
method: "post",
|
||||
timeout: null,
|
||||
});
|
||||
}
|
||||
|
||||
return hass.callApi<string>("POST", `hassio/addons/${slug}/stop`);
|
||||
export const stopHassioAddon = async (callWS: CallWS, slug: string) => {
|
||||
return callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/stop`,
|
||||
method: "post",
|
||||
timeout: null,
|
||||
});
|
||||
};
|
||||
|
||||
export const setHassioAddonSecurity = async (
|
||||
hass: HomeAssistant,
|
||||
callWS: CallWS,
|
||||
slug: string,
|
||||
data: HassioAddonSetSecurityParams
|
||||
) => {
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
await hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/security`,
|
||||
method: "post",
|
||||
data,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await hass.callApi<HassioResponse<void>>(
|
||||
"POST",
|
||||
`hassio/addons/${slug}/security`,
|
||||
data
|
||||
);
|
||||
await callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/security`,
|
||||
method: "post",
|
||||
data,
|
||||
});
|
||||
};
|
||||
|
||||
export const installHassioAddon = async (
|
||||
hass: HomeAssistant,
|
||||
callWS: CallWS,
|
||||
slug: string
|
||||
): Promise<void> => {
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
await hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/install`,
|
||||
method: "post",
|
||||
timeout: null,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await hass.callApi<HassioResponse<void>>(
|
||||
"POST",
|
||||
`hassio/addons/${slug}/install`
|
||||
);
|
||||
await callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/install`,
|
||||
method: "post",
|
||||
timeout: null,
|
||||
});
|
||||
};
|
||||
|
||||
export const updateHassioAddon = async (
|
||||
@@ -324,74 +267,37 @@ export const updateHassioAddon = async (
|
||||
slug: string,
|
||||
backup: boolean
|
||||
): Promise<void> => {
|
||||
if (atLeastVersion(hass.config.version, 2025, 2, 0)) {
|
||||
await hass.callWS({
|
||||
type: "hassio/update/addon",
|
||||
addon: slug,
|
||||
backup: backup,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
await hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/store/addons/${slug}/update`,
|
||||
method: "post",
|
||||
timeout: null,
|
||||
data: { backup },
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await hass.callApi<HassioResponse<void>>(
|
||||
"POST",
|
||||
`hassio/addons/${slug}/update`,
|
||||
{ backup }
|
||||
);
|
||||
await hass.callWS({
|
||||
type: "hassio/update/addon",
|
||||
addon: slug,
|
||||
backup: backup,
|
||||
});
|
||||
};
|
||||
|
||||
export const restartHassioAddon = async (
|
||||
hass: HomeAssistant,
|
||||
callWS: CallWS,
|
||||
slug: string
|
||||
): Promise<void> => {
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
await hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/restart`,
|
||||
method: "post",
|
||||
timeout: null,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await hass.callApi<HassioResponse<void>>(
|
||||
"POST",
|
||||
`hassio/addons/${slug}/restart`
|
||||
);
|
||||
await callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/restart`,
|
||||
method: "post",
|
||||
timeout: null,
|
||||
});
|
||||
};
|
||||
|
||||
export const uninstallHassioAddon = async (
|
||||
hass: HomeAssistant,
|
||||
callWS: CallWS,
|
||||
slug: string,
|
||||
removeData: boolean
|
||||
): Promise<void> => {
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
await hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/uninstall`,
|
||||
method: "post",
|
||||
timeout: null,
|
||||
data: { remove_config: removeData },
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await hass.callApi<HassioResponse<void>>(
|
||||
"POST",
|
||||
`hassio/addons/${slug}/uninstall`,
|
||||
{ remove_config: removeData }
|
||||
);
|
||||
await callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/uninstall`,
|
||||
method: "post",
|
||||
timeout: null,
|
||||
data: { remove_config: removeData },
|
||||
});
|
||||
};
|
||||
|
||||
export const fetchAddonInfo = (
|
||||
@@ -407,21 +313,13 @@ export const fetchAddonInfo = (
|
||||
);
|
||||
|
||||
export const rebuildLocalAddon = async (
|
||||
hass: HomeAssistant,
|
||||
callWS: CallWS,
|
||||
slug: string
|
||||
): Promise<void> => {
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
return hass.callWS<undefined>({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/rebuild`,
|
||||
method: "post",
|
||||
timeout: null,
|
||||
});
|
||||
}
|
||||
return (
|
||||
await hass.callApi<HassioResponse<void>>(
|
||||
"POST",
|
||||
`hassio/addons/${slug}rebuild`
|
||||
)
|
||||
).data;
|
||||
return callWS<undefined>({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/addons/${slug}/rebuild`,
|
||||
method: "post",
|
||||
timeout: null,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { atLeastVersion } from "../../common/config/version";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
import type { CallWS } from "../../types";
|
||||
|
||||
export interface HassioResponse<T> {
|
||||
data: T;
|
||||
@@ -46,21 +45,12 @@ export const ignoreSupervisorError = (error): boolean => {
|
||||
};
|
||||
|
||||
export const fetchHassioStats = async (
|
||||
hass: HomeAssistant,
|
||||
callWS: CallWS,
|
||||
container: string
|
||||
): Promise<HassioStats> => {
|
||||
if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
|
||||
return hass.callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/${container}/stats`,
|
||||
method: "get",
|
||||
});
|
||||
}
|
||||
|
||||
return hassioApiResultExtractor(
|
||||
await hass.callApi<HassioResponse<HassioStats>>(
|
||||
"GET",
|
||||
`hassio/${container}/stats`
|
||||
)
|
||||
);
|
||||
return callWS({
|
||||
type: "supervisor/api",
|
||||
endpoint: `/${container}/stats`,
|
||||
method: "get",
|
||||
});
|
||||
};
|
||||
|
||||
@@ -36,6 +36,7 @@ export const isMaxMode = arrayLiteralIncludes(MODES_MAX);
|
||||
|
||||
export const baseActionStruct = object({
|
||||
alias: optional(string()),
|
||||
comment: optional(string()),
|
||||
continue_on_error: optional(boolean()),
|
||||
enabled: optional(boolean()),
|
||||
});
|
||||
@@ -105,6 +106,7 @@ export interface Field {
|
||||
|
||||
interface BaseAction {
|
||||
alias?: string;
|
||||
comment?: string;
|
||||
continue_on_error?: boolean;
|
||||
enabled?: boolean;
|
||||
}
|
||||
@@ -195,6 +197,7 @@ export interface ForEachRepeat extends BaseRepeat {
|
||||
|
||||
export interface Option {
|
||||
alias?: string;
|
||||
comment?: string;
|
||||
conditions: string | Condition[];
|
||||
sequence: Action | Action[];
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import "../../components/ha-dialog";
|
||||
import "../../components/ha-dialog-footer";
|
||||
import "../../components/ha-dialog-header";
|
||||
import "../../components/ha-svg-icon";
|
||||
import "../../components/ha-textarea";
|
||||
import "../../components/input/ha-input";
|
||||
import type { HaInput } from "../../components/input/ha-input";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
@@ -28,7 +29,7 @@ class DialogBox extends LitElement {
|
||||
|
||||
@state() private _validInput = true;
|
||||
|
||||
@query("ha-input") private _textField?: HaInput;
|
||||
@query("ha-input, ha-textarea") private _textField?: HaInput;
|
||||
|
||||
private _closePromise?: Promise<void>;
|
||||
|
||||
@@ -109,7 +110,7 @@ class DialogBox extends LitElement {
|
||||
</ha-dialog-header>
|
||||
<div id="dialog-box-description">
|
||||
${this._params.text ? html` <p>${this._params.text}</p> ` : ""}
|
||||
${this._params.prompt
|
||||
${this._params.prompt && !this._params.multiline
|
||||
? html`
|
||||
<ha-input
|
||||
autofocus
|
||||
@@ -131,7 +132,19 @@ class DialogBox extends LitElement {
|
||||
: nothing}
|
||||
</ha-input>
|
||||
`
|
||||
: nothing}
|
||||
: this._params.prompt && this._params.multiline
|
||||
? html`
|
||||
<ha-textarea
|
||||
resize="auto"
|
||||
autofocus
|
||||
.value=${this._params.defaultValue}
|
||||
.placeholder=${this._params.placeholder}
|
||||
.label=${this._params.inputLabel}
|
||||
.disabled=${this._loading}
|
||||
@input=${this._validateInput}
|
||||
></ha-textarea>
|
||||
`
|
||||
: nothing}
|
||||
</div>
|
||||
<ha-dialog-footer slot="footer">
|
||||
${confirmPrompt
|
||||
|
||||
@@ -33,6 +33,7 @@ export interface PromptDialogParams extends BaseDialogBoxParams {
|
||||
inputMin?: number | string;
|
||||
inputMax?: number | string;
|
||||
action?: (value?: string) => Promise<void>;
|
||||
multiline?: boolean;
|
||||
}
|
||||
|
||||
export interface DialogBoxParams
|
||||
|
||||
@@ -200,12 +200,13 @@ class MoreInfoMediaPlayer extends LitElement {
|
||||
protected _renderSourceControl() {
|
||||
if (
|
||||
!this.stateObj ||
|
||||
!supportsFeature(this.stateObj, MediaPlayerEntityFeature.SELECT_SOURCE) ||
|
||||
!this.stateObj.attributes.source_list?.length
|
||||
!supportsFeature(this.stateObj, MediaPlayerEntityFeature.SELECT_SOURCE)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const sourceList = this.stateObj.attributes.source_list || [];
|
||||
|
||||
return html`<ha-tooltip for="source-button">
|
||||
${this.hass.localize(`ui.card.media_player.source`)}
|
||||
</ha-tooltip>
|
||||
@@ -217,7 +218,7 @@ class MoreInfoMediaPlayer extends LitElement {
|
||||
.path=${mdiLoginVariant}
|
||||
>
|
||||
</ha-icon-button>
|
||||
${this.stateObj.attributes.source_list!.map(
|
||||
${sourceList.map(
|
||||
(source) =>
|
||||
html`<ha-dropdown-item
|
||||
.value=${source}
|
||||
|
||||
@@ -199,13 +199,13 @@ export class HaVoiceAssistantSetupStepLocal extends LitElement {
|
||||
this._detailState = this.hass.localize(
|
||||
`ui.panel.config.voice_assistants.satellite_wizard.local.state.installing_${this._ttsProviderName}`
|
||||
);
|
||||
await installHassioAddon(this.hass, this._ttsAddonName);
|
||||
await installHassioAddon(this.hass.callWS, this._ttsAddonName);
|
||||
}
|
||||
if (!ttsAddon || ttsAddon.state !== "started") {
|
||||
this._detailState = this.hass.localize(
|
||||
`ui.panel.config.voice_assistants.satellite_wizard.local.state.starting_${this._ttsProviderName}`
|
||||
);
|
||||
await startHassioAddon(this.hass, this._ttsAddonName);
|
||||
await startHassioAddon(this.hass.callWS, this._ttsAddonName);
|
||||
}
|
||||
this._detailState = this.hass.localize(
|
||||
`ui.panel.config.voice_assistants.satellite_wizard.local.state.setup_${this._ttsProviderName}`
|
||||
@@ -217,13 +217,13 @@ export class HaVoiceAssistantSetupStepLocal extends LitElement {
|
||||
this._detailState = this.hass.localize(
|
||||
`ui.panel.config.voice_assistants.satellite_wizard.local.state.installing_${this._sttProviderName}`
|
||||
);
|
||||
await installHassioAddon(this.hass, this._sttAddonName);
|
||||
await installHassioAddon(this.hass.callWS, this._sttAddonName);
|
||||
}
|
||||
if (!sttAddon || sttAddon.state !== "started") {
|
||||
this._detailState = this.hass.localize(
|
||||
`ui.panel.config.voice_assistants.satellite_wizard.local.state.starting_${this._sttProviderName}`
|
||||
);
|
||||
await startHassioAddon(this.hass, this._sttAddonName);
|
||||
await startHassioAddon(this.hass.callWS, this._sttAddonName);
|
||||
}
|
||||
this._detailState = this.hass.localize(
|
||||
`ui.panel.config.voice_assistants.satellite_wizard.local.state.setup_${this._sttProviderName}`
|
||||
|
||||
@@ -213,7 +213,7 @@ class HaPanelApp extends LitElement {
|
||||
let addon: HassioAddonDetails;
|
||||
|
||||
try {
|
||||
addon = await fetchHassioAddonInfo(this.hass, addonSlug);
|
||||
addon = await fetchHassioAddonInfo(this.hass.callWS, addonSlug);
|
||||
} catch (err: any) {
|
||||
await this._showErrorAndNavigateHome(
|
||||
addonSlug,
|
||||
@@ -253,7 +253,7 @@ class HaPanelApp extends LitElement {
|
||||
);
|
||||
// Set auto-retry window for after starting the app
|
||||
this._autoRetryUntil = Date.now() + START_WAIT_TIME;
|
||||
await startHassioAddon(this.hass, addonSlug);
|
||||
await startHassioAddon(this.hass.callWS, addonSlug);
|
||||
this._fetchData(addonSlug);
|
||||
return;
|
||||
} catch (_err) {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { css, html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import "../../../../../components/ha-bar";
|
||||
import "../../../../../components/ha-settings-row";
|
||||
import "../../../../../components/item/ha-row-item";
|
||||
import { roundWithOneDecimal } from "../../../../../util/calculate";
|
||||
|
||||
@customElement("supervisor-app-metric")
|
||||
@@ -16,9 +16,9 @@ class SupervisorAppMetric extends LitElement {
|
||||
|
||||
protected render(): TemplateResult {
|
||||
const roundedValue = roundWithOneDecimal(this.value);
|
||||
return html`<ha-settings-row empty>
|
||||
<span slot="heading"> ${this.description} </span>
|
||||
<div slot="description" .title=${this.tooltip ?? ""}>
|
||||
return html`<ha-row-item empty>
|
||||
<span slot="headline"> ${this.description} </span>
|
||||
<div slot="supporting-text" .title=${this.tooltip ?? ""}>
|
||||
<span class="value"> ${roundedValue} % </span>
|
||||
<ha-bar
|
||||
class=${classMap({
|
||||
@@ -28,16 +28,14 @@ class SupervisorAppMetric extends LitElement {
|
||||
.value=${this.value}
|
||||
></ha-bar>
|
||||
</div>
|
||||
</ha-settings-row>`;
|
||||
</ha-row-item>`;
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
ha-settings-row {
|
||||
padding: 0;
|
||||
height: 54px;
|
||||
ha-row-item {
|
||||
width: 100%;
|
||||
}
|
||||
ha-settings-row > div[slot="description"] {
|
||||
ha-row-item > div[slot="supporting-text"] {
|
||||
white-space: normal;
|
||||
color: var(--secondary-text-color);
|
||||
display: flex;
|
||||
|
||||
@@ -1,283 +0,0 @@
|
||||
import {
|
||||
css,
|
||||
type CSSResultGroup,
|
||||
html,
|
||||
LitElement,
|
||||
nothing,
|
||||
type PropertyValues,
|
||||
} from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { atLeastVersion } from "../../../../../common/config/version";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import "../../../../../components/buttons/ha-progress-button";
|
||||
import "../../../../../components/ha-alert";
|
||||
import "../../../../../components/ha-button";
|
||||
import "../../../../../components/ha-card";
|
||||
import "../../../../../components/ha-faded";
|
||||
import "../../../../../components/ha-markdown";
|
||||
import "../../../../../components/ha-spinner";
|
||||
import "../../../../../components/ha-switch";
|
||||
import type { HaSwitch } from "../../../../../components/ha-switch";
|
||||
import "../../../../../components/item/ha-row-item";
|
||||
import type { HassioAddonDetails } from "../../../../../data/hassio/addon";
|
||||
import {
|
||||
fetchHassioAddonChangelog,
|
||||
updateHassioAddon,
|
||||
} from "../../../../../data/hassio/addon";
|
||||
import {
|
||||
extractApiErrorMessage,
|
||||
ignoreSupervisorError,
|
||||
} from "../../../../../data/hassio/common";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
import { extractChangelog } from "../util/supervisor-app";
|
||||
|
||||
declare global {
|
||||
interface HASSDomEvents {
|
||||
"update-complete": undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@customElement("supervisor-app-update-available-card")
|
||||
class SupervisorAppUpdateAvailableCard extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ type: Boolean }) public narrow = false;
|
||||
|
||||
@property({ attribute: false }) public addon!: HassioAddonDetails;
|
||||
|
||||
@state() private _changelogContent?: string;
|
||||
|
||||
@state() private _updating = false;
|
||||
|
||||
@state() private _error?: string;
|
||||
|
||||
protected render() {
|
||||
if (!this.addon) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const createBackupTexts = this._computeCreateBackupTexts();
|
||||
|
||||
return html`
|
||||
<ha-card
|
||||
outlined
|
||||
.header=${this.hass.localize(
|
||||
"ui.panel.config.apps.dashboard.update_available.update_name",
|
||||
{
|
||||
name: this.addon.name,
|
||||
}
|
||||
)}
|
||||
>
|
||||
<div class="card-content">
|
||||
${this._error
|
||||
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||
: ""}
|
||||
${this.addon.version === this.addon.version_latest
|
||||
? html`<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.apps.dashboard.update_available.no_update",
|
||||
{
|
||||
name: this.addon.name,
|
||||
}
|
||||
)}
|
||||
</p>`
|
||||
: !this._updating
|
||||
? html`
|
||||
${this._changelogContent
|
||||
? html`
|
||||
<ha-faded>
|
||||
<ha-markdown .content=${this._changelogContent}>
|
||||
</ha-markdown>
|
||||
</ha-faded>
|
||||
`
|
||||
: nothing}
|
||||
<div class="versions">
|
||||
<p>
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.apps.dashboard.update_available.description",
|
||||
{
|
||||
name: this.addon.name,
|
||||
version: this.addon.version,
|
||||
newest_version: this.addon.version_latest,
|
||||
}
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
${createBackupTexts
|
||||
? html`
|
||||
<hr />
|
||||
<ha-row-item>
|
||||
<span slot="headline">
|
||||
${createBackupTexts.title}
|
||||
</span>
|
||||
|
||||
${createBackupTexts.description
|
||||
? html`
|
||||
<span slot="supporting-text">
|
||||
${createBackupTexts.description}
|
||||
</span>
|
||||
`
|
||||
: nothing}
|
||||
<ha-switch slot="end" id="create-backup"></ha-switch>
|
||||
</ha-row-item>
|
||||
`
|
||||
: nothing}
|
||||
`
|
||||
: html`<ha-spinner
|
||||
aria-label="Updating"
|
||||
size="large"
|
||||
></ha-spinner>
|
||||
<p class="progress-text">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.apps.dashboard.update_available.updating",
|
||||
{
|
||||
name: this.addon.name,
|
||||
version: this.addon.version_latest,
|
||||
}
|
||||
)}
|
||||
</p>`}
|
||||
</div>
|
||||
${this.addon.version !== this.addon.version_latest && !this._updating
|
||||
? html`
|
||||
<div class="card-actions">
|
||||
<span></span>
|
||||
<ha-progress-button @click=${this._update}>
|
||||
${this.hass.localize("ui.common.update")}
|
||||
</ha-progress-button>
|
||||
</div>
|
||||
`
|
||||
: nothing}
|
||||
</ha-card>
|
||||
`;
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProps: PropertyValues<this>) {
|
||||
super.firstUpdated(changedProps);
|
||||
this._loadAddonData();
|
||||
}
|
||||
|
||||
private _computeCreateBackupTexts():
|
||||
| { title: string; description?: string }
|
||||
| undefined {
|
||||
if (atLeastVersion(this.hass.config.version, 2025, 2, 0)) {
|
||||
const version = this.addon.version;
|
||||
return {
|
||||
title: this.hass.localize(
|
||||
"ui.panel.config.apps.dashboard.update_available.create_backup.app"
|
||||
),
|
||||
description: this.hass.localize(
|
||||
"ui.panel.config.apps.dashboard.update_available.create_backup.app_description",
|
||||
{ version: version }
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
title: this.hass.localize(
|
||||
"ui.panel.config.apps.dashboard.update_available.create_backup.generic"
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
get _shouldCreateBackup(): boolean {
|
||||
const createBackupSwitch = this.shadowRoot?.getElementById(
|
||||
"create-backup"
|
||||
) as HaSwitch;
|
||||
if (createBackupSwitch) {
|
||||
return createBackupSwitch.checked;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private async _loadAddonData() {
|
||||
if (this.addon.changelog) {
|
||||
try {
|
||||
const content = await fetchHassioAddonChangelog(
|
||||
this.hass,
|
||||
this.addon.slug
|
||||
);
|
||||
this._changelogContent = extractChangelog(
|
||||
this.addon as HassioAddonDetails,
|
||||
content
|
||||
);
|
||||
} catch (err) {
|
||||
this._error = extractApiErrorMessage(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async _update() {
|
||||
this._error = undefined;
|
||||
this._updating = true;
|
||||
|
||||
try {
|
||||
await updateHassioAddon(
|
||||
this.hass,
|
||||
this.addon.slug,
|
||||
this._shouldCreateBackup
|
||||
);
|
||||
} catch (err: any) {
|
||||
if (this.hass.connection.connected && !ignoreSupervisorError(err)) {
|
||||
this._error = extractApiErrorMessage(err);
|
||||
this._updating = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
fireEvent(this, "update-complete");
|
||||
this._updating = false;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
ha-card {
|
||||
margin: auto;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
.card-actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
ha-spinner {
|
||||
display: block;
|
||||
margin: 32px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
ha-markdown {
|
||||
padding-bottom: var(--ha-space-2);
|
||||
}
|
||||
|
||||
hr {
|
||||
border-color: var(--divider-color);
|
||||
border-bottom: none;
|
||||
margin: var(--ha-space-4) 0 0 0;
|
||||
}
|
||||
|
||||
ha-row-item {
|
||||
--ha-row-item-padding-inline: 0;
|
||||
margin-bottom: calc(-1 * var(--ha-space-4));
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"supervisor-app-update-available-card": SupervisorAppUpdateAvailableCard;
|
||||
}
|
||||
}
|
||||
@@ -183,7 +183,7 @@ class SupervisorAppAudio extends LitElement {
|
||||
this._selectedOutput === "default" ? null : this._selectedOutput,
|
||||
};
|
||||
try {
|
||||
await setHassioAddonOption(this.hass, this.addon.slug, data);
|
||||
await setHassioAddonOption(this.hass.callWS, this.addon.slug, data);
|
||||
if (this.addon?.state === "started") {
|
||||
await suggestSupervisorAppRestart(this, this.hass, this.addon);
|
||||
}
|
||||
|
||||
@@ -449,7 +449,7 @@ class SupervisorAppConfig extends LitElement {
|
||||
options: null,
|
||||
};
|
||||
try {
|
||||
await setHassioAddonOption(this.hass, this.addon.slug, data);
|
||||
await setHassioAddonOption(this.hass.callWS, this.addon.slug, data);
|
||||
this._configHasChanged = false;
|
||||
const eventdata = {
|
||||
success: true,
|
||||
@@ -488,14 +488,14 @@ class SupervisorAppConfig extends LitElement {
|
||||
|
||||
try {
|
||||
const validation = await validateHassioAddonOption(
|
||||
this.hass,
|
||||
this.hass.callWS,
|
||||
this.addon.slug,
|
||||
options
|
||||
);
|
||||
if (!validation.valid) {
|
||||
throw Error(validation.message);
|
||||
}
|
||||
await setHassioAddonOption(this.hass, this.addon.slug, {
|
||||
await setHassioAddonOption(this.hass.callWS, this.addon.slug, {
|
||||
options,
|
||||
});
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@ import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import "../../../../../components/buttons/ha-progress-button";
|
||||
import "../../../../../components/ha-alert";
|
||||
import "../../../../../components/ha-card";
|
||||
import "../../../../../components/ha-formfield";
|
||||
import "../../../../../components/ha-form/ha-form";
|
||||
import type { HaFormSchema } from "../../../../../components/ha-form/types";
|
||||
import "../../../../../components/ha-formfield";
|
||||
import type {
|
||||
HassioAddonDetails,
|
||||
HassioAddonSetOptionParams,
|
||||
@@ -17,8 +17,8 @@ import { setHassioAddonOption } from "../../../../../data/hassio/addon";
|
||||
import { extractApiErrorMessage } from "../../../../../data/hassio/common";
|
||||
import { haStyle } from "../../../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
import { suggestSupervisorAppRestart } from "../dialogs/suggestSupervisorAppRestart";
|
||||
import { supervisorAppsStyle } from "../../resources/supervisor-apps-style";
|
||||
import { suggestSupervisorAppRestart } from "../dialogs/suggestSupervisorAppRestart";
|
||||
|
||||
@customElement("supervisor-app-network")
|
||||
class SupervisorAppNetwork extends LitElement {
|
||||
@@ -160,7 +160,7 @@ class SupervisorAppNetwork extends LitElement {
|
||||
};
|
||||
|
||||
try {
|
||||
await setHassioAddonOption(this.hass, this.addon.slug, data);
|
||||
await setHassioAddonOption(this.hass.callWS, this.addon.slug, data);
|
||||
this._configHasChanged = false;
|
||||
const eventdata = {
|
||||
success: true,
|
||||
@@ -205,7 +205,7 @@ class SupervisorAppNetwork extends LitElement {
|
||||
};
|
||||
|
||||
try {
|
||||
await setHassioAddonOption(this.hass, this.addon.slug, data);
|
||||
await setHassioAddonOption(this.hass.callWS, this.addon.slug, data);
|
||||
this._configHasChanged = false;
|
||||
const eventdata = {
|
||||
success: true,
|
||||
|
||||
@@ -28,7 +28,7 @@ export const suggestSupervisorAppRestart = async (
|
||||
});
|
||||
if (confirmed) {
|
||||
try {
|
||||
await restartHassioAddon(hass, addon.slug);
|
||||
await restartHassioAddon(hass.callWS, addon.slug);
|
||||
} catch (err: any) {
|
||||
showAlertDialog(element, {
|
||||
title: hass.localize(
|
||||
|
||||
@@ -46,8 +46,8 @@ class SupervisorAppInfoDashboard extends LitElement {
|
||||
css`
|
||||
.content {
|
||||
margin: auto;
|
||||
padding: var(--ha-space-2);
|
||||
max-width: 1024px;
|
||||
padding: var(--ha-space-4);
|
||||
max-width: 1200px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,16 +1,19 @@
|
||||
import { consume, type ContextType } from "@lit/context";
|
||||
import type { TemplateResult } from "lit";
|
||||
import { LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import "../../../../../components/ha-alert";
|
||||
import "../../../../../components/ha-button";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
import { internationalizationContext } from "../../../../../data/context";
|
||||
|
||||
@customElement("supervisor-app-system-managed")
|
||||
class SupervisorAppSystemManaged extends LitElement {
|
||||
@property({ type: Boolean }) public narrow = false;
|
||||
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
@state()
|
||||
@consume({ context: internationalizationContext, subscribe: true })
|
||||
private i18n!: ContextType<typeof internationalizationContext>;
|
||||
|
||||
@property({ type: Boolean, attribute: "hide-button" }) public hideButton =
|
||||
false;
|
||||
@@ -19,18 +22,18 @@ class SupervisorAppSystemManaged extends LitElement {
|
||||
return html`
|
||||
<ha-alert
|
||||
alert-type="warning"
|
||||
.title=${this.hass.localize(
|
||||
.title=${this.i18n.localize(
|
||||
"ui.panel.config.apps.dashboard.system_managed.title"
|
||||
)}
|
||||
.narrow=${this.narrow}
|
||||
>
|
||||
${this.hass.localize(
|
||||
${this.i18n.localize(
|
||||
"ui.panel.config.apps.dashboard.system_managed.description"
|
||||
)}
|
||||
${!this.hideButton
|
||||
? html`
|
||||
<ha-button slot="action" @click=${this._takeControl}>
|
||||
${this.hass.localize(
|
||||
${this.i18n.localize(
|
||||
"ui.panel.config.apps.dashboard.system_managed.take_control"
|
||||
)}
|
||||
</ha-button>
|
||||
|
||||
@@ -161,7 +161,7 @@ class HaConfigAppDashboard extends LitElement {
|
||||
}
|
||||
|
||||
try {
|
||||
this._addon = await fetchHassioAddonInfo(this.hass, slug);
|
||||
this._addon = await fetchHassioAddonInfo(this.hass.callWS, slug);
|
||||
} catch (err: any) {
|
||||
if (repositoryUrl) {
|
||||
try {
|
||||
@@ -210,7 +210,7 @@ class HaConfigAppDashboard extends LitElement {
|
||||
}
|
||||
|
||||
await addStoreRepository(this.hass, repositoryUrl);
|
||||
this._addon = await fetchHassioAddonInfo(this.hass, slug);
|
||||
this._addon = await fetchHassioAddonInfo(this.hass.callWS, slug);
|
||||
}
|
||||
|
||||
private async _apiCalled(ev): Promise<void> {
|
||||
|
||||
@@ -107,6 +107,7 @@ export default class HaAutomationActionEditor extends LitElement {
|
||||
ev.stopPropagation();
|
||||
const value = {
|
||||
...(this.action.alias ? { alias: this.action.alias } : {}),
|
||||
...(this.action.comment ? { comment: this.action.comment } : {}),
|
||||
...ev.detail.value,
|
||||
};
|
||||
fireEvent(this, "value-changed", { value });
|
||||
|
||||
@@ -7,6 +7,8 @@ import {
|
||||
mdiArrowUp,
|
||||
mdiCheckboxBlankOutline,
|
||||
mdiCheckboxOutline,
|
||||
mdiCommentEditOutline,
|
||||
mdiCommentTextOutline,
|
||||
mdiContentCopy,
|
||||
mdiContentCut,
|
||||
mdiContentPaste,
|
||||
@@ -294,6 +296,13 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
?.target
|
||||
: undefined;
|
||||
|
||||
const trimmedComment = this.action.comment?.trim() || "";
|
||||
const commentTooltipText = !trimmedComment
|
||||
? ""
|
||||
: trimmedComment.length > 250
|
||||
? `${trimmedComment.substring(0, 250)}...`
|
||||
: trimmedComment;
|
||||
|
||||
return html`
|
||||
${type === "service" && "action" in this.action && this.action.action
|
||||
? html`
|
||||
@@ -329,6 +338,21 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
serviceTargetSpec
|
||||
)
|
||||
: nothing}
|
||||
${commentTooltipText
|
||||
? html`
|
||||
<ha-svg-icon
|
||||
id="comment-icon"
|
||||
.path=${mdiCommentTextOutline}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.comment.label"
|
||||
)}
|
||||
class="comment-indicator"
|
||||
></ha-svg-icon
|
||||
><ha-tooltip for="comment-icon"
|
||||
><p>${commentTooltipText}</p></ha-tooltip
|
||||
>
|
||||
`
|
||||
: nothing}
|
||||
${type !== "condition" &&
|
||||
(this.action as NonConditionAction).continue_on_error === true
|
||||
? html`<ha-svg-icon
|
||||
@@ -384,6 +408,14 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
)
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<ha-dropdown-item value="edit_comment">
|
||||
<ha-svg-icon slot="icon" .path=${mdiCommentEditOutline}></ha-svg-icon>
|
||||
${this._renderOverflowLabel(
|
||||
this.hass.localize(
|
||||
`ui.panel.config.automation.editor.comment.${this.action.comment ? "edit" : "add"}`
|
||||
)
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<wa-divider></wa-divider>
|
||||
<ha-dropdown-item value="duplicate" .disabled=${this.disabled}>
|
||||
<ha-svg-icon
|
||||
@@ -910,6 +942,38 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
}
|
||||
};
|
||||
|
||||
private _editCommentAction = async (): Promise<void> => {
|
||||
const comment = await showPromptDialog(this, {
|
||||
title: this.hass.localize(
|
||||
`ui.panel.config.automation.editor.comment.${this.action.comment ? "edit" : "add"}`
|
||||
),
|
||||
inputLabel: this.hass.localize(
|
||||
"ui.panel.config.automation.editor.comment.label"
|
||||
),
|
||||
inputType: "string",
|
||||
defaultValue: this.action.comment,
|
||||
confirmText: this.hass.localize("ui.common.submit"),
|
||||
multiline: true,
|
||||
});
|
||||
if (comment !== null) {
|
||||
const value = { ...this.action };
|
||||
if (comment === "") {
|
||||
delete value.comment;
|
||||
} else {
|
||||
value.comment = comment;
|
||||
}
|
||||
fireEvent(this, "value-changed", {
|
||||
value,
|
||||
});
|
||||
|
||||
if (this._selected && this.optionsInSidebar) {
|
||||
this.openSidebar(value); // refresh sidebar
|
||||
} else if (this._yamlMode) {
|
||||
this._actionEditor?.yamlEditor?.setValue(value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private _duplicateAction = () => {
|
||||
fireEvent(this, "duplicate");
|
||||
};
|
||||
@@ -1026,6 +1090,7 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
rename: () => {
|
||||
this._renameAction();
|
||||
},
|
||||
editComment: this._editCommentAction,
|
||||
toggleYamlMode: () => {
|
||||
this._toggleYamlMode();
|
||||
this.openSidebar();
|
||||
@@ -1121,6 +1186,9 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
case "rename":
|
||||
this._renameAction();
|
||||
break;
|
||||
case "edit_comment":
|
||||
this._editCommentAction();
|
||||
break;
|
||||
case "duplicate":
|
||||
this._duplicateAction();
|
||||
break;
|
||||
|
||||
@@ -186,6 +186,10 @@ export class HaDeviceAction extends LitElement {
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
margin-bottom: var(--ha-space-3);
|
||||
}
|
||||
ha-device-picker {
|
||||
display: block;
|
||||
margin-bottom: 24px;
|
||||
|
||||
@@ -123,6 +123,7 @@ export default class HaAutomationConditionEditor extends LitElement {
|
||||
ev.stopPropagation();
|
||||
const value = {
|
||||
...(this.condition.alias ? { alias: this.condition.alias } : {}),
|
||||
...(this.condition.comment ? { comment: this.condition.comment } : {}),
|
||||
...ev.detail.value,
|
||||
};
|
||||
fireEvent(this, "value-changed", { value });
|
||||
|
||||
@@ -4,6 +4,8 @@ import {
|
||||
mdiAppleKeyboardCommand,
|
||||
mdiArrowDown,
|
||||
mdiArrowUp,
|
||||
mdiCommentEditOutline,
|
||||
mdiCommentTextOutline,
|
||||
mdiContentCopy,
|
||||
mdiContentCut,
|
||||
mdiContentPaste,
|
||||
@@ -200,6 +202,13 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
const conditionTargetSpec =
|
||||
this.conditionDescriptions[this.condition.condition]?.target;
|
||||
|
||||
const trimmedComment = this.condition.comment?.trim() || "";
|
||||
const commentTooltipText = !trimmedComment
|
||||
? ""
|
||||
: trimmedComment.length > 250
|
||||
? `${trimmedComment.substring(0, 250)}...`
|
||||
: trimmedComment;
|
||||
|
||||
return html`
|
||||
<ha-condition-icon
|
||||
slot="leading-icon"
|
||||
@@ -217,6 +226,21 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
conditionTargetSpec
|
||||
)
|
||||
: nothing}
|
||||
${this.condition.comment?.trim()
|
||||
? html`
|
||||
<ha-svg-icon
|
||||
id="comment-icon"
|
||||
.path=${mdiCommentTextOutline}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.comment.label"
|
||||
)}
|
||||
class="comment-indicator"
|
||||
></ha-svg-icon>
|
||||
<ha-tooltip for="comment-icon"
|
||||
><p>${commentTooltipText}</p></ha-tooltip
|
||||
>
|
||||
`
|
||||
: nothing}
|
||||
</h3>
|
||||
<ha-automation-row-event-chip
|
||||
.show=${this._testing}
|
||||
@@ -264,6 +288,14 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
)
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<ha-dropdown-item value="edit_comment">
|
||||
<ha-svg-icon slot="icon" .path=${mdiCommentEditOutline}></ha-svg-icon>
|
||||
${this._renderOverflowLabel(
|
||||
this.hass.localize(
|
||||
`ui.panel.config.automation.editor.comment.${this.condition.comment ? "edit" : "add"}`
|
||||
)
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
|
||||
<wa-divider></wa-divider>
|
||||
|
||||
@@ -813,6 +845,38 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
}
|
||||
};
|
||||
|
||||
private _editCommentCondition = async (): Promise<void> => {
|
||||
const comment = await showPromptDialog(this, {
|
||||
title: this.hass.localize(
|
||||
`ui.panel.config.automation.editor.comment.${this.condition.comment ? "edit" : "add"}`
|
||||
),
|
||||
inputLabel: this.hass.localize(
|
||||
"ui.panel.config.automation.editor.comment.label"
|
||||
),
|
||||
inputType: "string",
|
||||
defaultValue: this.condition.comment,
|
||||
confirmText: this.hass.localize("ui.common.submit"),
|
||||
multiline: true,
|
||||
});
|
||||
if (comment !== null) {
|
||||
const value = { ...this.condition };
|
||||
if (comment === "") {
|
||||
delete value.comment;
|
||||
} else {
|
||||
value.comment = comment;
|
||||
}
|
||||
fireEvent(this, "value-changed", {
|
||||
value,
|
||||
});
|
||||
|
||||
if (this._selected && this.optionsInSidebar) {
|
||||
this.openSidebar(value); // refresh sidebar
|
||||
} else if (this._yamlMode) {
|
||||
this.conditionEditor?.yamlEditor?.setValue(value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private _duplicateCondition = () => {
|
||||
fireEvent(this, "duplicate");
|
||||
};
|
||||
@@ -954,6 +1018,7 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
rename: () => {
|
||||
this._renameCondition();
|
||||
},
|
||||
editComment: this._editCommentCondition,
|
||||
toggleYamlMode: () => {
|
||||
this._toggleYamlMode();
|
||||
this.openSidebar();
|
||||
@@ -1025,6 +1090,9 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
case "rename":
|
||||
this._renameCondition();
|
||||
break;
|
||||
case "edit_comment":
|
||||
this._editCommentCondition();
|
||||
break;
|
||||
case "duplicate":
|
||||
this._duplicateCondition();
|
||||
break;
|
||||
|
||||
@@ -188,6 +188,10 @@ export class HaDeviceCondition extends LitElement {
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
margin-bottom: var(--ha-space-3);
|
||||
}
|
||||
ha-device-picker {
|
||||
display: block;
|
||||
margin-bottom: 24px;
|
||||
|
||||
+9
-1
@@ -1,5 +1,5 @@
|
||||
import type { PropertyValues } from "lit";
|
||||
import { html, LitElement } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import {
|
||||
@@ -22,6 +22,7 @@ import type { HomeAssistant } from "../../../../../types";
|
||||
|
||||
const numericStateConditionStruct = object({
|
||||
alias: optional(string()),
|
||||
comment: optional(string()),
|
||||
condition: literal("numeric_state"),
|
||||
entity_id: optional(string()),
|
||||
attribute: optional(string()),
|
||||
@@ -255,6 +256,13 @@ export default class HaNumericStateCondition extends LitElement {
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
margin-bottom: var(--ha-space-3);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import type { PropertyValues } from "lit";
|
||||
import { html, LitElement } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import {
|
||||
array,
|
||||
assert,
|
||||
boolean,
|
||||
literal,
|
||||
@@ -10,10 +11,9 @@ import {
|
||||
optional,
|
||||
string,
|
||||
union,
|
||||
array,
|
||||
} from "superstruct";
|
||||
import { createDurationData } from "../../../../../common/datetime/create_duration_data";
|
||||
import { ensureArray } from "../../../../../common/array/ensure-array";
|
||||
import { createDurationData } from "../../../../../common/datetime/create_duration_data";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import "../../../../../components/ha-form/ha-form";
|
||||
import type { SchemaUnion } from "../../../../../components/ha-form/types";
|
||||
@@ -25,6 +25,7 @@ import type { ConditionElement } from "../ha-automation-condition-row";
|
||||
|
||||
const stateConditionStruct = object({
|
||||
alias: optional(string()),
|
||||
comment: optional(string()),
|
||||
condition: literal("state"),
|
||||
entity_id: optional(string()),
|
||||
attribute: optional(string()),
|
||||
@@ -142,6 +143,13 @@ export class HaStateCondition extends LitElement implements ConditionElement {
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
margin-bottom: var(--ha-space-3);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
import "@home-assistant/webawesome/dist/components/divider/divider";
|
||||
import { consume, type ContextType } from "@lit/context";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import "../../../components/ha-button";
|
||||
import "../../../components/ha-settings-row";
|
||||
import { internationalizationContext } from "../../../data/context";
|
||||
|
||||
@customElement("ha-automation-comment")
|
||||
export class HaAutomationComment extends LitElement {
|
||||
@property() public comment!: string;
|
||||
|
||||
@state()
|
||||
@consume({ context: internationalizationContext, subscribe: true })
|
||||
private _i18n!: ContextType<typeof internationalizationContext>;
|
||||
|
||||
protected render() {
|
||||
return html`
|
||||
<ha-settings-row narrow>
|
||||
<div class="heading" slot="heading">
|
||||
<span class="title" id="comment-label">
|
||||
${this._i18n.localize(
|
||||
"ui.panel.config.automation.editor.comment.label"
|
||||
)}
|
||||
</span>
|
||||
<ha-button
|
||||
@click=${this._handleClick}
|
||||
size="small"
|
||||
appearance="plain"
|
||||
>
|
||||
${this._i18n.localize("ui.common.edit")}
|
||||
</ha-button>
|
||||
</div>
|
||||
<p aria-labelledby="comment-label">${this.comment}</p>
|
||||
</ha-settings-row>
|
||||
`;
|
||||
}
|
||||
|
||||
private _handleClick() {
|
||||
fireEvent(this, "edit-comment");
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
ha-settings-row {
|
||||
margin-inline: calc(-1 * var(--ha-space-4));
|
||||
}
|
||||
ha-settings-row::part(heading) {
|
||||
padding-inline-end: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
.heading {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
p {
|
||||
margin: var(--ha-space-2) 0 0;
|
||||
border: var(--ha-border-width-sm) solid
|
||||
var(--ha-color-border-neutral-quiet);
|
||||
padding: var(--ha-space-1) var(--ha-space-3);
|
||||
border-radius: var(--ha-border-radius-lg);
|
||||
background-color: var(--ha-color-fill-neutral-quiet-resting);
|
||||
white-space: pre;
|
||||
}
|
||||
ha-button {
|
||||
margin-inline-end: calc(-1 * var(--ha-space-3));
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-automation-comment": HaAutomationComment;
|
||||
}
|
||||
|
||||
interface HASSDomEvents {
|
||||
"edit-comment": undefined;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ import {
|
||||
mdiAppleKeyboardCommand,
|
||||
mdiArrowDown,
|
||||
mdiArrowUp,
|
||||
mdiCommentEditOutline,
|
||||
mdiCommentTextOutline,
|
||||
mdiDelete,
|
||||
mdiDotsVertical,
|
||||
mdiPlusCircleMultipleOutline,
|
||||
@@ -37,11 +39,11 @@ import type { Action, Option } from "../../../../data/script";
|
||||
import { showPromptDialog } from "../../../../dialogs/generic/show-dialog-box";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import { isMac } from "../../../../util/is_mac";
|
||||
import { showEditorToast } from "../editor-toast";
|
||||
import "../action/ha-automation-action";
|
||||
import type HaAutomationAction from "../action/ha-automation-action";
|
||||
import "../condition/ha-automation-condition";
|
||||
import type HaAutomationCondition from "../condition/ha-automation-condition";
|
||||
import { showEditorToast } from "../editor-toast";
|
||||
import {
|
||||
editorStyles,
|
||||
indentStyle,
|
||||
@@ -138,8 +140,14 @@ export default class HaAutomationOptionRow extends LitElement {
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private _renderRow() {
|
||||
const trimmedComment = this.option?.comment?.trim() || "";
|
||||
const commentTooltipText = !trimmedComment
|
||||
? ""
|
||||
: trimmedComment.length > 250
|
||||
? `${trimmedComment.substring(0, 250)}...`
|
||||
: trimmedComment;
|
||||
|
||||
return html`
|
||||
<h3 slot="header">
|
||||
${this.option
|
||||
@@ -150,6 +158,21 @@ export default class HaAutomationOptionRow extends LitElement {
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.type.choose.default"
|
||||
)}
|
||||
${this.option?.comment?.trim()
|
||||
? html`
|
||||
<ha-svg-icon
|
||||
id="comment-icon"
|
||||
.path=${mdiCommentTextOutline}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.comment.label"
|
||||
)}
|
||||
class="comment-indicator"
|
||||
></ha-svg-icon>
|
||||
<ha-tooltip for="comment-icon"
|
||||
><p>${commentTooltipText}</p></ha-tooltip
|
||||
>
|
||||
`
|
||||
: nothing}
|
||||
</h3>
|
||||
|
||||
<slot name="icons" slot="icons"></slot>
|
||||
@@ -177,6 +200,17 @@ export default class HaAutomationOptionRow extends LitElement {
|
||||
)
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<ha-dropdown-item value="edit_comment">
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${mdiCommentEditOutline}
|
||||
></ha-svg-icon>
|
||||
${this._renderOverflowLabel(
|
||||
this.hass.localize(
|
||||
`ui.panel.config.automation.editor.comment.${this.option?.comment ? "edit" : "add"}`
|
||||
)
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
|
||||
<ha-dropdown-item value="duplicate" .disabled=${this.disabled}>
|
||||
<ha-svg-icon
|
||||
@@ -361,6 +395,9 @@ export default class HaAutomationOptionRow extends LitElement {
|
||||
case "rename":
|
||||
this._renameOption();
|
||||
break;
|
||||
case "edit_comment":
|
||||
this._editCommentOption();
|
||||
break;
|
||||
case "delete":
|
||||
this._removeOption();
|
||||
break;
|
||||
@@ -424,6 +461,39 @@ export default class HaAutomationOptionRow extends LitElement {
|
||||
}
|
||||
};
|
||||
|
||||
private _editCommentOption = async (): Promise<void> => {
|
||||
if (!this.option) {
|
||||
return;
|
||||
}
|
||||
const comment = await showPromptDialog(this, {
|
||||
title: this.hass.localize(
|
||||
`ui.panel.config.automation.editor.comment.${this.option.comment ? "edit" : "add"}`
|
||||
),
|
||||
inputLabel: this.hass.localize(
|
||||
"ui.panel.config.automation.editor.comment.label"
|
||||
),
|
||||
inputType: "string",
|
||||
defaultValue: this.option.comment,
|
||||
confirmText: this.hass.localize("ui.common.submit"),
|
||||
multiline: true,
|
||||
});
|
||||
if (comment !== null) {
|
||||
const value: Option = { ...this.option };
|
||||
if (comment === "") {
|
||||
delete value.comment;
|
||||
} else {
|
||||
value.comment = comment;
|
||||
}
|
||||
fireEvent(this, "value-changed", {
|
||||
value,
|
||||
});
|
||||
|
||||
if (this._selected) {
|
||||
this.openSidebar(value); // refresh sidebar
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private _conditionChanged(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
const conditions = ev.detail.value as Condition[];
|
||||
@@ -455,7 +525,8 @@ export default class HaAutomationOptionRow extends LitElement {
|
||||
this.openSidebar();
|
||||
}
|
||||
|
||||
public openSidebar(): void {
|
||||
public openSidebar(option?: Option): void {
|
||||
const sidebarOption = option ?? this.option;
|
||||
fireEvent(this, "open-sidebar", {
|
||||
close: (focus?: boolean) => {
|
||||
this._selected = false;
|
||||
@@ -467,9 +538,11 @@ export default class HaAutomationOptionRow extends LitElement {
|
||||
rename: () => {
|
||||
this._renameOption();
|
||||
},
|
||||
editComment: this._editCommentOption,
|
||||
delete: this._removeOption,
|
||||
duplicate: this._duplicateOption,
|
||||
defaultOption: !!this.defaultActions,
|
||||
comment: sidebarOption?.comment,
|
||||
} satisfies OptionSidebarConfig);
|
||||
this._selected = true;
|
||||
this._collapsed = false;
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
mdiAppleKeyboardCommand,
|
||||
mdiCheckboxBlankOutline,
|
||||
mdiCheckboxOutline,
|
||||
mdiCommentEditOutline,
|
||||
mdiContentCopy,
|
||||
mdiContentCut,
|
||||
mdiContentPaste,
|
||||
@@ -26,8 +27,8 @@ import type { HaDropdownSelectEvent } from "../../../../components/ha-dropdown";
|
||||
import "../../../../components/ha-dropdown-item";
|
||||
import { ACTION_BUILDING_BLOCKS } from "../../../../data/action";
|
||||
import type { ActionSidebarConfig } from "../../../../data/automation";
|
||||
import { domainToName } from "../../../../data/integration";
|
||||
import type { DomainManifestLookup } from "../../../../data/integration";
|
||||
import { domainToName } from "../../../../data/integration";
|
||||
import type {
|
||||
NonConditionAction,
|
||||
RepeatAction,
|
||||
@@ -38,6 +39,7 @@ import { isMac } from "../../../../util/is_mac";
|
||||
import type HaAutomationConditionEditor from "../action/ha-automation-action-editor";
|
||||
import { getAutomationActionType } from "../action/ha-automation-action-row";
|
||||
import { getRepeatType } from "../action/types/ha-automation-action-repeat";
|
||||
import "../ha-automation-comment";
|
||||
import { overflowStyles, sidebarEditorStyles } from "../styles";
|
||||
import "./ha-automation-sidebar-card";
|
||||
|
||||
@@ -175,6 +177,15 @@ export default class HaAutomationSidebarAction extends LitElement {
|
||||
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
|
||||
</div>
|
||||
</ha-dropdown-item>
|
||||
<ha-dropdown-item slot="menu-items" value="edit_comment">
|
||||
<ha-svg-icon slot="icon" .path=${mdiCommentEditOutline}></ha-svg-icon>
|
||||
<div class="overflow-label">
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.automation.editor.comment.${this.config.config.action.comment ? "edit" : "add"}`
|
||||
)}
|
||||
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
|
||||
</div>
|
||||
</ha-dropdown-item>
|
||||
|
||||
<wa-divider slot="menu-items"></wa-divider>
|
||||
<ha-dropdown-item
|
||||
@@ -377,6 +388,12 @@ export default class HaAutomationSidebarAction extends LitElement {
|
||||
@ui-mode-not-available=${this._handleUiModeNotAvailable}
|
||||
></ha-automation-action-editor>`
|
||||
)}
|
||||
${this.config.config.action.comment?.trim() && !this.yamlMode
|
||||
? html`<ha-automation-comment
|
||||
@edit-comment=${this.config.editComment}
|
||||
.comment=${this.config.config.action.comment}
|
||||
></ha-automation-comment>`
|
||||
: nothing}
|
||||
</ha-automation-sidebar-card>`;
|
||||
}
|
||||
|
||||
@@ -425,6 +442,9 @@ export default class HaAutomationSidebarAction extends LitElement {
|
||||
case "rename":
|
||||
this.config.rename();
|
||||
break;
|
||||
case "edit_comment":
|
||||
this.config.editComment();
|
||||
break;
|
||||
case "run":
|
||||
this.config.run();
|
||||
break;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import "@home-assistant/webawesome/dist/components/divider/divider";
|
||||
import {
|
||||
mdiAppleKeyboardCommand,
|
||||
mdiCommentEditOutline,
|
||||
mdiContentCopy,
|
||||
mdiContentCut,
|
||||
mdiContentPaste,
|
||||
@@ -34,6 +35,7 @@ import type { HomeAssistant } from "../../../../types";
|
||||
import { isMac } from "../../../../util/is_mac";
|
||||
import "../condition/ha-automation-condition-editor";
|
||||
import type HaAutomationConditionEditor from "../condition/ha-automation-condition-editor";
|
||||
import "../ha-automation-comment";
|
||||
import { overflowStyles, sidebarEditorStyles } from "../styles";
|
||||
import "./ha-automation-sidebar-card";
|
||||
|
||||
@@ -149,6 +151,19 @@ export default class HaAutomationSidebarCondition extends LitElement {
|
||||
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
|
||||
</div>
|
||||
</ha-dropdown-item>
|
||||
<ha-dropdown-item
|
||||
slot="menu-items"
|
||||
value="edit_comment"
|
||||
.disabled=${this.disabled}
|
||||
>
|
||||
<ha-svg-icon slot="icon" .path=${mdiCommentEditOutline}></ha-svg-icon>
|
||||
<div class="overflow-label">
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.automation.editor.comment.${this.config.config.comment ? "edit" : "add"}`
|
||||
)}
|
||||
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
|
||||
</div>
|
||||
</ha-dropdown-item>
|
||||
|
||||
<wa-divider slot="menu-items"></wa-divider>
|
||||
|
||||
@@ -332,6 +347,12 @@ export default class HaAutomationSidebarCondition extends LitElement {
|
||||
sidebar
|
||||
></ha-automation-condition-editor>`
|
||||
)}
|
||||
${this.config.config.comment?.trim() && !this.yamlMode
|
||||
? html`<ha-automation-comment
|
||||
@edit-comment=${this.config.editComment}
|
||||
.comment=${this.config.config.comment}
|
||||
></ha-automation-comment>`
|
||||
: nothing}
|
||||
<div class="testing-wrapper">
|
||||
<div
|
||||
class="testing ${classMap({
|
||||
@@ -396,6 +417,9 @@ export default class HaAutomationSidebarCondition extends LitElement {
|
||||
case "rename":
|
||||
this.config.rename();
|
||||
break;
|
||||
case "edit_comment":
|
||||
this.config.editComment();
|
||||
break;
|
||||
case "test":
|
||||
this.config.test();
|
||||
break;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import "@home-assistant/webawesome/dist/components/divider/divider";
|
||||
import {
|
||||
mdiAppleKeyboardCommand,
|
||||
mdiCommentEditOutline,
|
||||
mdiDelete,
|
||||
mdiPlusCircleMultipleOutline,
|
||||
mdiRenameBox,
|
||||
@@ -14,6 +15,7 @@ import type { OptionSidebarConfig } from "../../../../data/automation";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import { isMac } from "../../../../util/is_mac";
|
||||
import type HaAutomationConditionEditor from "../action/ha-automation-action-editor";
|
||||
import "../ha-automation-comment";
|
||||
import { overflowStyles, sidebarEditorStyles } from "../styles";
|
||||
import "./ha-automation-sidebar-card";
|
||||
import type { HaDropdownSelectEvent } from "../../../../components/ha-dropdown";
|
||||
@@ -72,6 +74,22 @@ export default class HaAutomationSidebarOption extends LitElement {
|
||||
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
|
||||
</div>
|
||||
</ha-dropdown-item>
|
||||
<ha-dropdown-item
|
||||
slot="menu-items"
|
||||
value="edit_comment"
|
||||
.disabled=${!!disabled}
|
||||
>
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${mdiCommentEditOutline}
|
||||
></ha-svg-icon>
|
||||
<div class="overflow-label">
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.automation.editor.comment.${this.config.comment ? "edit" : "add"}`
|
||||
)}
|
||||
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
|
||||
</div>
|
||||
</ha-dropdown-item>
|
||||
|
||||
<ha-dropdown-item
|
||||
slot="menu-items"
|
||||
@@ -126,6 +144,12 @@ export default class HaAutomationSidebarOption extends LitElement {
|
||||
`}
|
||||
|
||||
<div class="description">${description}</div>
|
||||
${!this.config.defaultOption && this.config.comment?.trim()
|
||||
? html`<ha-automation-comment
|
||||
@edit-comment=${this.config.editComment}
|
||||
.comment=${this.config.comment}
|
||||
></ha-automation-comment>`
|
||||
: nothing}
|
||||
</ha-automation-sidebar-card>`;
|
||||
}
|
||||
|
||||
@@ -140,6 +164,9 @@ export default class HaAutomationSidebarOption extends LitElement {
|
||||
case "rename":
|
||||
this.config.rename();
|
||||
break;
|
||||
case "edit_comment":
|
||||
this.config.editComment();
|
||||
break;
|
||||
case "duplicate":
|
||||
this.config.duplicate();
|
||||
break;
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
import { mdiAppleKeyboardCommand, mdiDelete, mdiPlaylistEdit } from "@mdi/js";
|
||||
import {
|
||||
mdiAppleKeyboardCommand,
|
||||
mdiCommentEditOutline,
|
||||
mdiDelete,
|
||||
mdiPlaylistEdit,
|
||||
} from "@mdi/js";
|
||||
import type { PropertyValues } from "lit";
|
||||
import { html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { keyed } from "lit/directives/keyed";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import type { HaDropdownSelectEvent } from "../../../../components/ha-dropdown";
|
||||
import "../../../../components/ha-dropdown-item";
|
||||
import type { ScriptFieldSidebarConfig } from "../../../../data/automation";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import { isMac } from "../../../../util/is_mac";
|
||||
import "../../script/ha-script-field-editor";
|
||||
import type HaAutomationConditionEditor from "../action/ha-automation-action-editor";
|
||||
import "../ha-automation-comment";
|
||||
import { overflowStyles, sidebarEditorStyles } from "../styles";
|
||||
import "./ha-automation-sidebar-card";
|
||||
import type { HaDropdownSelectEvent } from "../../../../components/ha-dropdown";
|
||||
|
||||
@customElement("ha-automation-sidebar-script-field")
|
||||
export default class HaAutomationSidebarScriptField extends LitElement {
|
||||
@@ -62,6 +68,15 @@ export default class HaAutomationSidebarScriptField extends LitElement {
|
||||
@wa-select=${this._handleDropdownSelect}
|
||||
>
|
||||
<span slot="title">${title}</span>
|
||||
<ha-dropdown-item slot="menu-items" value="edit_comment">
|
||||
<ha-svg-icon slot="icon" .path=${mdiCommentEditOutline}></ha-svg-icon>
|
||||
<div class="overflow-label">
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.automation.editor.comment.${this.config.config.field.description ? "edit" : "add"}`
|
||||
)}
|
||||
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
|
||||
</div>
|
||||
</ha-dropdown-item>
|
||||
<ha-dropdown-item
|
||||
slot="menu-items"
|
||||
value="toggle_yaml_mode"
|
||||
@@ -121,6 +136,12 @@ export default class HaAutomationSidebarScriptField extends LitElement {
|
||||
@yaml-changed=${this._yamlChangedSidebar}
|
||||
></ha-script-field-editor>`
|
||||
)}
|
||||
${this.config.config.field.description?.trim() && !this.yamlMode
|
||||
? html`<ha-automation-comment
|
||||
@edit-comment=${this.config.editComment}
|
||||
.comment=${this.config.config.field.description}
|
||||
></ha-automation-comment>`
|
||||
: nothing}
|
||||
</ha-automation-sidebar-card>`;
|
||||
}
|
||||
|
||||
@@ -168,6 +189,9 @@ export default class HaAutomationSidebarScriptField extends LitElement {
|
||||
case "toggle_yaml_mode":
|
||||
this._toggleYamlMode();
|
||||
break;
|
||||
case "edit_comment":
|
||||
this.config.editComment();
|
||||
break;
|
||||
case "delete":
|
||||
this.config.delete();
|
||||
break;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import "@home-assistant/webawesome/dist/components/divider/divider";
|
||||
import {
|
||||
mdiAppleKeyboardCommand,
|
||||
mdiCommentEditOutline,
|
||||
mdiContentCopy,
|
||||
mdiContentCut,
|
||||
mdiContentPaste,
|
||||
@@ -18,9 +19,12 @@ import { customElement, property, query, state } from "lit/decorators";
|
||||
import { keyed } from "lit/directives/keyed";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { handleStructError } from "../../../../common/structs/handle-errors";
|
||||
import type { HaDropdownSelectEvent } from "../../../../components/ha-dropdown";
|
||||
import "../../../../components/ha-dropdown-item";
|
||||
import type {
|
||||
LegacyTrigger,
|
||||
Trigger,
|
||||
TriggerList,
|
||||
TriggerSidebarConfig,
|
||||
} from "../../../../data/automation";
|
||||
import {
|
||||
@@ -30,11 +34,11 @@ import {
|
||||
} from "../../../../data/trigger";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import { isMac } from "../../../../util/is_mac";
|
||||
import "../ha-automation-comment";
|
||||
import { overflowStyles, sidebarEditorStyles } from "../styles";
|
||||
import "../trigger/ha-automation-trigger-editor";
|
||||
import type HaAutomationTriggerEditor from "../trigger/ha-automation-trigger-editor";
|
||||
import "./ha-automation-sidebar-card";
|
||||
import type { HaDropdownSelectEvent } from "../../../../components/ha-dropdown";
|
||||
|
||||
@customElement("ha-automation-sidebar-trigger")
|
||||
export default class HaAutomationSidebarTrigger extends LitElement {
|
||||
@@ -125,7 +129,24 @@ export default class HaAutomationSidebarTrigger extends LitElement {
|
||||
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
|
||||
</div>
|
||||
</ha-dropdown-item>
|
||||
|
||||
${type !== "list"
|
||||
? html`<ha-dropdown-item
|
||||
slot="menu-items"
|
||||
value="edit_comment"
|
||||
.disabled=${this.disabled}
|
||||
>
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${mdiCommentEditOutline}
|
||||
></ha-svg-icon>
|
||||
<div class="overflow-label">
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.automation.editor.comment.${(this.config.config as Exclude<Trigger, TriggerList>).comment ? "edit" : "add"}`
|
||||
)}
|
||||
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
|
||||
</div>
|
||||
</ha-dropdown-item>`
|
||||
: nothing}
|
||||
${!this.yamlMode &&
|
||||
!("id" in this.config.config) &&
|
||||
!this._requestShowId
|
||||
@@ -321,6 +342,14 @@ export default class HaAutomationSidebarTrigger extends LitElement {
|
||||
sidebar
|
||||
></ha-automation-trigger-editor>`
|
||||
)}
|
||||
${!isTriggerList(this.config.config) &&
|
||||
this.config.config.comment?.trim() &&
|
||||
!this.yamlMode
|
||||
? html`<ha-automation-comment
|
||||
@edit-comment=${this.config.editComment}
|
||||
.comment=${this.config.config.comment}
|
||||
></ha-automation-comment>`
|
||||
: nothing}
|
||||
</ha-automation-sidebar-card>
|
||||
`;
|
||||
}
|
||||
@@ -372,6 +401,9 @@ export default class HaAutomationSidebarTrigger extends LitElement {
|
||||
case "rename":
|
||||
this.config.rename();
|
||||
break;
|
||||
case "edit_comment":
|
||||
this.config.editComment();
|
||||
break;
|
||||
case "show_id":
|
||||
this._showTriggerId();
|
||||
break;
|
||||
|
||||
@@ -4,6 +4,7 @@ export const baseTriggerStruct = object({
|
||||
trigger: string(),
|
||||
id: optional(string()),
|
||||
enabled: optional(boolean()),
|
||||
comment: optional(string()),
|
||||
});
|
||||
|
||||
export const forDictStruct = object({
|
||||
|
||||
@@ -52,6 +52,18 @@ export const rowStyles = css`
|
||||
ha-automation-row-event-chip.event-chip {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.comment-indicator {
|
||||
color: var(--ha-color-on-neutral-normal);
|
||||
}
|
||||
.comment-indicator + ha-tooltip::part(body) {
|
||||
cursor: default;
|
||||
max-width: 300px;
|
||||
}
|
||||
.comment-indicator + ha-tooltip p {
|
||||
white-space: pre;
|
||||
margin: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
export const editorStyles = css`
|
||||
|
||||
@@ -141,6 +141,7 @@ export default class HaAutomationTriggerEditor extends LitElement {
|
||||
ev.stopPropagation();
|
||||
const value = {
|
||||
...(this.trigger.alias ? { alias: this.trigger.alias } : {}),
|
||||
...(this.trigger.comment ? { comment: this.trigger.comment } : {}),
|
||||
...ev.detail.value,
|
||||
};
|
||||
fireEvent(this, "value-changed", { value });
|
||||
|
||||
@@ -4,6 +4,8 @@ import {
|
||||
mdiAppleKeyboardCommand,
|
||||
mdiArrowDown,
|
||||
mdiArrowUp,
|
||||
mdiCommentEditOutline,
|
||||
mdiCommentTextOutline,
|
||||
mdiContentCopy,
|
||||
mdiContentCut,
|
||||
mdiContentPaste,
|
||||
@@ -221,6 +223,16 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
?.target
|
||||
: undefined;
|
||||
|
||||
const trimmedComment =
|
||||
(type !== "list" &&
|
||||
(this.trigger as Exclude<Trigger, TriggerList>).comment?.trim()) ||
|
||||
"";
|
||||
const commentTooltipText = !trimmedComment
|
||||
? ""
|
||||
: trimmedComment.length > 250
|
||||
? `${trimmedComment.substring(0, 250)}...`
|
||||
: trimmedComment;
|
||||
|
||||
return html`
|
||||
${type === "list"
|
||||
? html`<ha-svg-icon
|
||||
@@ -242,6 +254,22 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
triggerTargetSpec
|
||||
)
|
||||
: nothing}
|
||||
${type !== "list" &&
|
||||
(this.trigger as Exclude<Trigger, TriggerList>).comment?.trim()
|
||||
? html`
|
||||
<ha-svg-icon
|
||||
id="comment-icon"
|
||||
.path=${mdiCommentTextOutline}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.comment.label"
|
||||
)}
|
||||
class="comment-indicator"
|
||||
></ha-svg-icon>
|
||||
<ha-tooltip for="comment-icon"
|
||||
><p>${commentTooltipText}</p></ha-tooltip
|
||||
>
|
||||
`
|
||||
: nothing}
|
||||
</h3>
|
||||
<ha-automation-row-event-chip
|
||||
.show=${this._triggered}
|
||||
@@ -282,7 +310,19 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
)
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
|
||||
${type !== "list"
|
||||
? html`<ha-dropdown-item value="edit_comment">
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${mdiCommentEditOutline}
|
||||
></ha-svg-icon>
|
||||
${this._renderOverflowLabel(
|
||||
this.hass.localize(
|
||||
`ui.panel.config.automation.editor.comment.${(this.trigger as Exclude<Trigger, TriggerList>).comment ? "edit" : "add"}`
|
||||
)
|
||||
)}
|
||||
</ha-dropdown-item>`
|
||||
: nothing}
|
||||
<wa-divider></wa-divider>
|
||||
|
||||
<ha-dropdown-item value="duplicate" .disabled=${this.disabled}>
|
||||
@@ -659,6 +699,7 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
rename: () => {
|
||||
this._renameTrigger();
|
||||
},
|
||||
editComment: this._editCommentTrigger,
|
||||
toggleYamlMode: () => {
|
||||
this._toggleYamlMode();
|
||||
this.openSidebar();
|
||||
@@ -802,6 +843,40 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
}
|
||||
};
|
||||
|
||||
private _editCommentTrigger = async (): Promise<void> => {
|
||||
if (isTriggerList(this.trigger)) return;
|
||||
const trigger = this.trigger;
|
||||
const comment = await showPromptDialog(this, {
|
||||
title: this.hass.localize(
|
||||
`ui.panel.config.automation.editor.comment.${trigger.comment ? "edit" : "add"}`
|
||||
),
|
||||
inputLabel: this.hass.localize(
|
||||
"ui.panel.config.automation.editor.comment.label"
|
||||
),
|
||||
inputType: "string",
|
||||
defaultValue: trigger.comment,
|
||||
confirmText: this.hass.localize("ui.common.submit"),
|
||||
multiline: true,
|
||||
});
|
||||
if (comment !== null) {
|
||||
const value = { ...trigger };
|
||||
if (comment === "") {
|
||||
delete value.comment;
|
||||
} else {
|
||||
value.comment = comment;
|
||||
}
|
||||
fireEvent(this, "value-changed", {
|
||||
value,
|
||||
});
|
||||
|
||||
if (this._selected && this.optionsInSidebar) {
|
||||
this.openSidebar(value); // refresh sidebar
|
||||
} else if (this._yamlMode) {
|
||||
this.triggerEditor?.yamlEditor?.setValue(value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private _duplicateTrigger = () => {
|
||||
fireEvent(this, "duplicate");
|
||||
};
|
||||
@@ -913,6 +988,9 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
case "rename":
|
||||
this._renameTrigger();
|
||||
break;
|
||||
case "edit_comment":
|
||||
this._editCommentTrigger();
|
||||
break;
|
||||
case "duplicate":
|
||||
this._duplicateTrigger();
|
||||
break;
|
||||
|
||||
@@ -212,6 +212,10 @@ export class HaDeviceTrigger extends LitElement {
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
margin-bottom: var(--ha-space-3);
|
||||
}
|
||||
ha-device-picker {
|
||||
display: block;
|
||||
margin-bottom: 24px;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import type { PropertyValues } from "lit";
|
||||
import { html, LitElement } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { ensureArray } from "../../../../../common/array/ensure-array";
|
||||
import { createDurationData } from "../../../../../common/datetime/create_duration_data";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import { hasTemplate } from "../../../../../common/string/has-template";
|
||||
@@ -10,7 +11,6 @@ import "../../../../../components/ha-form/ha-form";
|
||||
import type { SchemaUnion } from "../../../../../components/ha-form/types";
|
||||
import type { NumericStateTrigger } from "../../../../../data/automation";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
import { ensureArray } from "../../../../../common/array/ensure-array";
|
||||
|
||||
@customElement("ha-automation-trigger-numeric_state")
|
||||
export class HaNumericStateTrigger extends LitElement {
|
||||
@@ -333,6 +333,13 @@ export class HaNumericStateTrigger extends LitElement {
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
margin-bottom: var(--ha-space-3);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
||||
@@ -29,6 +29,7 @@ const DEFAULT_KEYS: (keyof PlatformTrigger)[] = [
|
||||
"trigger",
|
||||
"target",
|
||||
"alias",
|
||||
"comment",
|
||||
"id",
|
||||
"variables",
|
||||
"enabled",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { PropertyValues } from "lit";
|
||||
import { html, LitElement } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import {
|
||||
array,
|
||||
assert,
|
||||
@@ -13,22 +14,21 @@ import {
|
||||
string,
|
||||
union,
|
||||
} from "superstruct";
|
||||
import memoizeOne from "memoize-one";
|
||||
import type { LocalizeFunc } from "../../../../../common/translations/localize";
|
||||
import { ensureArray } from "../../../../../common/array/ensure-array";
|
||||
import { createDurationData } from "../../../../../common/datetime/create_duration_data";
|
||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||
import { hasTemplate } from "../../../../../common/string/has-template";
|
||||
import type { StateTrigger } from "../../../../../data/automation";
|
||||
import type { LocalizeFunc } from "../../../../../common/translations/localize";
|
||||
import { ANY_STATE_VALUE } from "../../../../../components/entity/const";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
import { baseTriggerStruct, forDictStruct } from "../../structs";
|
||||
import type { TriggerElement } from "../ha-automation-trigger-row";
|
||||
import "../../../../../components/ha-form/ha-form";
|
||||
import { createDurationData } from "../../../../../common/datetime/create_duration_data";
|
||||
import type {
|
||||
HaFormSchema,
|
||||
SchemaUnion,
|
||||
} from "../../../../../components/ha-form/types";
|
||||
import type { StateTrigger } from "../../../../../data/automation";
|
||||
import type { HomeAssistant } from "../../../../../types";
|
||||
import { baseTriggerStruct, forDictStruct } from "../../structs";
|
||||
import type { TriggerElement } from "../ha-automation-trigger-row";
|
||||
|
||||
const stateTriggerStruct = assign(
|
||||
baseTriggerStruct,
|
||||
@@ -303,6 +303,13 @@ export class HaStateTrigger extends LitElement implements TriggerElement {
|
||||
? "ui.components.entity.entity-picker.entity"
|
||||
: `ui.panel.config.automation.editor.triggers.type.state.${schema.name}`
|
||||
);
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
margin-bottom: var(--ha-space-3);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { mdiBatteryHigh, mdiDelete, mdiPencil, mdiPlus } from "@mdi/js";
|
||||
import type { CSSResultGroup, TemplateResult } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import "../../../../components/ha-card";
|
||||
@@ -100,19 +100,24 @@ export class EnergyBatterySettings extends LitElement {
|
||||
></ha-svg-icon>`}
|
||||
<div class="content">
|
||||
<span class="label"
|
||||
>${getStatisticLabel(
|
||||
>${source.name ||
|
||||
getStatisticLabel(
|
||||
this.hass,
|
||||
source.stat_energy_from,
|
||||
this.statsMetadata?.[source.stat_energy_from]
|
||||
)}</span
|
||||
>
|
||||
<span class="label"
|
||||
>${getStatisticLabel(
|
||||
this.hass,
|
||||
source.stat_energy_to,
|
||||
this.statsMetadata?.[source.stat_energy_to]
|
||||
)}</span
|
||||
>
|
||||
${source.name
|
||||
? nothing
|
||||
: html`
|
||||
<span class="label"
|
||||
>${getStatisticLabel(
|
||||
this.hass,
|
||||
source.stat_energy_to,
|
||||
this.statsMetadata?.[source.stat_energy_to]
|
||||
)}</span
|
||||
>
|
||||
`}
|
||||
</div>
|
||||
<ha-icon-button
|
||||
.label=${this.hass.localize(
|
||||
@@ -153,6 +158,7 @@ export class EnergyBatterySettings extends LitElement {
|
||||
|
||||
private _addSource() {
|
||||
showEnergySettingsBatteryDialog(this, {
|
||||
statsMetadata: this.statsMetadata,
|
||||
battery_sources: this.preferences.energy_sources.filter(
|
||||
(src) => src.type === "battery"
|
||||
) as BatterySourceTypeEnergyPreference[],
|
||||
@@ -169,6 +175,7 @@ export class EnergyBatterySettings extends LitElement {
|
||||
const origSource: BatterySourceTypeEnergyPreference =
|
||||
ev.currentTarget.closest(".row").source;
|
||||
showEnergySettingsBatteryDialog(this, {
|
||||
statsMetadata: this.statsMetadata,
|
||||
source: { ...origSource },
|
||||
battery_sources: this.preferences.energy_sources.filter(
|
||||
(src) => src.type === "battery"
|
||||
|
||||
@@ -124,13 +124,16 @@ export class EnergyGridSettings extends LitElement {
|
||||
></ha-svg-icon>`}
|
||||
<div class="content">
|
||||
<span class="label"
|
||||
>${getStatisticLabel(
|
||||
>${source.name ||
|
||||
getStatisticLabel(
|
||||
this.hass,
|
||||
primaryStat,
|
||||
this.statsMetadata?.[primaryStat]
|
||||
)}</span
|
||||
>
|
||||
${source.stat_energy_from && source.stat_energy_to
|
||||
${source.stat_energy_from &&
|
||||
source.stat_energy_to &&
|
||||
!source.name
|
||||
? html`<span class="label secondary"
|
||||
>${getStatisticLabel(
|
||||
this.hass,
|
||||
@@ -266,6 +269,7 @@ export class EnergyGridSettings extends LitElement {
|
||||
|
||||
private _addSource() {
|
||||
showEnergySettingsGridDialog(this, {
|
||||
statsMetadata: this.statsMetadata,
|
||||
grid_sources: this._getGridSources(),
|
||||
saveCallback: async (source) => {
|
||||
const preferences: EnergyPreferences = {
|
||||
@@ -283,6 +287,7 @@ export class EnergyGridSettings extends LitElement {
|
||||
const sourceIndex: number = row.sourceIndex;
|
||||
|
||||
showEnergySettingsGridDialog(this, {
|
||||
statsMetadata: this.statsMetadata,
|
||||
source: { ...origSource },
|
||||
grid_sources: this._getGridSources(),
|
||||
saveCallback: async (newSource) => {
|
||||
|
||||
@@ -101,7 +101,8 @@ export class EnergySolarSettings extends LitElement {
|
||||
.path=${mdiSolarPower}
|
||||
></ha-svg-icon>`}
|
||||
<span class="content"
|
||||
>${getStatisticLabel(
|
||||
>${source.name ||
|
||||
getStatisticLabel(
|
||||
this.hass,
|
||||
source.stat_energy_from,
|
||||
this.statsMetadata?.[source.stat_energy_from]
|
||||
@@ -154,6 +155,7 @@ export class EnergySolarSettings extends LitElement {
|
||||
|
||||
private _addSource() {
|
||||
showEnergySettingsSolarDialog(this, {
|
||||
statsMetadata: this.statsMetadata,
|
||||
info: this.info!,
|
||||
solar_sources: this.preferences.energy_sources.filter(
|
||||
(src) => src.type === "solar"
|
||||
@@ -171,6 +173,7 @@ export class EnergySolarSettings extends LitElement {
|
||||
const origSource: SolarSourceTypeEnergyPreference =
|
||||
ev.currentTarget.closest(".row").source;
|
||||
showEnergySettingsSolarDialog(this, {
|
||||
statsMetadata: this.statsMetadata,
|
||||
info: this.info!,
|
||||
source: { ...origSource },
|
||||
solar_sources: this.preferences.energy_sources.filter(
|
||||
|
||||
@@ -6,6 +6,7 @@ import "../../../../components/entity/ha-statistic-picker";
|
||||
import "../../../../components/ha-button";
|
||||
import "../../../../components/ha-dialog";
|
||||
import "../../../../components/ha-dialog-footer";
|
||||
import "../../../../components/input/ha-input";
|
||||
import type {
|
||||
BatterySourceTypeEnergyPreference,
|
||||
PowerConfig,
|
||||
@@ -14,6 +15,11 @@ import {
|
||||
emptyBatteryEnergyPreference,
|
||||
energyStatisticHelpUrl,
|
||||
} from "../../../../data/energy";
|
||||
import {
|
||||
getStatisticLabel,
|
||||
getStatisticMetadata,
|
||||
isExternalStatistic,
|
||||
} from "../../../../data/recorder";
|
||||
import { getSensorDeviceClassConvertibleUnits } from "../../../../data/sensor";
|
||||
import type { HassDialog } from "../../../../dialogs/make-dialog-manager";
|
||||
import { haStyle, haStyleDialog } from "../../../../resources/styles";
|
||||
@@ -27,6 +33,7 @@ import {
|
||||
type PowerType,
|
||||
} from "./ha-energy-power-config";
|
||||
import type { EnergySettingsBatteryDialogParams } from "./show-dialogs-energy";
|
||||
import type { HaInput } from "../../../../components/input/ha-input";
|
||||
|
||||
const energyUnitClasses = ["energy"];
|
||||
const socStatisticsUnits = ["%"];
|
||||
@@ -174,6 +181,32 @@ export class DialogEnergyBatterySettings
|
||||
)}
|
||||
></ha-statistic-picker>
|
||||
|
||||
<ha-input
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.battery.dialog.display_name"
|
||||
)}
|
||||
type="text"
|
||||
.disabled=${!(
|
||||
this._source?.stat_energy_from || this._source?.stat_energy_to
|
||||
)}
|
||||
.value=${this._source?.name || ""}
|
||||
.placeholder=${this._source?.stat_energy_from
|
||||
? getStatisticLabel(
|
||||
this.hass,
|
||||
this._source.stat_energy_from,
|
||||
this._params?.statsMetadata?.[this._source.stat_energy_from]
|
||||
)
|
||||
: this._source?.stat_energy_to
|
||||
? getStatisticLabel(
|
||||
this.hass,
|
||||
this._source.stat_energy_to,
|
||||
this._params?.statsMetadata?.[this._source.stat_energy_to]
|
||||
)
|
||||
: ""}
|
||||
@input=${this._nameChanged}
|
||||
>
|
||||
</ha-input>
|
||||
|
||||
<ha-energy-power-config
|
||||
.hass=${this.hass}
|
||||
.powerType=${this._powerType}
|
||||
@@ -232,12 +265,39 @@ export class DialogEnergyBatterySettings
|
||||
return true;
|
||||
}
|
||||
|
||||
private async _updateMetadata(statId: string) {
|
||||
if (
|
||||
statId &&
|
||||
isExternalStatistic(statId) &&
|
||||
this._params?.statsMetadata &&
|
||||
!(statId in this._params.statsMetadata)
|
||||
) {
|
||||
const [metadata] = await getStatisticMetadata(this.hass, [statId]);
|
||||
if (metadata) {
|
||||
this._params.statsMetadata[statId] = metadata;
|
||||
this.requestUpdate("_params");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _statisticToChanged(ev: ValueChangedEvent<string>) {
|
||||
this._source = { ...this._source!, stat_energy_to: ev.detail.value };
|
||||
this._updateMetadata(ev.detail.value);
|
||||
}
|
||||
|
||||
private _statisticFromChanged(ev: ValueChangedEvent<string>) {
|
||||
this._source = { ...this._source!, stat_energy_from: ev.detail.value };
|
||||
this._updateMetadata(ev.detail.value);
|
||||
}
|
||||
|
||||
private _nameChanged(ev: InputEvent) {
|
||||
this._source = {
|
||||
...this._source!,
|
||||
name: (ev.target as HaInput).value,
|
||||
};
|
||||
if (!this._source.name) {
|
||||
delete this._source.name;
|
||||
}
|
||||
}
|
||||
|
||||
private _handlePowerConfigChanged(
|
||||
@@ -261,6 +321,9 @@ export class DialogEnergyBatterySettings
|
||||
stat_energy_from: this._source!.stat_energy_from,
|
||||
stat_energy_to: this._source!.stat_energy_to,
|
||||
};
|
||||
if (this._source?.name) {
|
||||
source.name = this._source.name;
|
||||
}
|
||||
|
||||
// Only include power_config if a power type is selected
|
||||
if (this._powerType !== "none") {
|
||||
|
||||
@@ -19,7 +19,11 @@ import {
|
||||
emptyGridSourceEnergyPreference,
|
||||
energyStatisticHelpUrl,
|
||||
} from "../../../../data/energy";
|
||||
import { isExternalStatistic } from "../../../../data/recorder";
|
||||
import {
|
||||
getStatisticLabel,
|
||||
getStatisticMetadata,
|
||||
isExternalStatistic,
|
||||
} from "../../../../data/recorder";
|
||||
import { getSensorDeviceClassConvertibleUnits } from "../../../../data/sensor";
|
||||
import type { HassDialog } from "../../../../dialogs/make-dialog-manager";
|
||||
import { haStyle, haStyleDialog } from "../../../../resources/styles";
|
||||
@@ -33,6 +37,7 @@ import {
|
||||
type PowerType,
|
||||
} from "./ha-energy-power-config";
|
||||
import type { EnergySettingsGridDialogParams } from "./show-dialogs-energy";
|
||||
import type { HaInput } from "../../../../components/input/ha-input";
|
||||
|
||||
const energyUnitClasses = ["energy"];
|
||||
|
||||
@@ -224,6 +229,33 @@ export class DialogEnergyGridSettings
|
||||
)}
|
||||
></ha-statistic-picker>
|
||||
|
||||
<ha-input
|
||||
class="name"
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.grid.dialog.display_name"
|
||||
)}
|
||||
type="text"
|
||||
.disabled=${!(
|
||||
this._source?.stat_energy_from || this._source?.stat_energy_to
|
||||
)}
|
||||
.value=${this._source?.name || ""}
|
||||
.placeholder=${this._source?.stat_energy_from
|
||||
? getStatisticLabel(
|
||||
this.hass,
|
||||
this._source.stat_energy_from,
|
||||
this._params?.statsMetadata?.[this._source.stat_energy_from]
|
||||
)
|
||||
: this._source?.stat_energy_to
|
||||
? getStatisticLabel(
|
||||
this.hass,
|
||||
this._source.stat_energy_to,
|
||||
this._params?.statsMetadata?.[this._source.stat_energy_to]
|
||||
)
|
||||
: ""}
|
||||
@input=${this._nameChanged}
|
||||
>
|
||||
</ha-input>
|
||||
|
||||
<p class="section-label">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.energy.grid.dialog.import_cost"
|
||||
@@ -444,6 +476,21 @@ export class DialogEnergyGridSettings
|
||||
return true;
|
||||
}
|
||||
|
||||
private async _updateMetadata(statId: string) {
|
||||
if (
|
||||
statId &&
|
||||
isExternalStatistic(statId) &&
|
||||
this._params?.statsMetadata &&
|
||||
!(statId in this._params.statsMetadata)
|
||||
) {
|
||||
const [metadata] = await getStatisticMetadata(this.hass, [statId]);
|
||||
if (metadata) {
|
||||
this._params.statsMetadata[statId] = metadata;
|
||||
this.requestUpdate("_params");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _statisticFromChanged(ev: ValueChangedEvent<string>) {
|
||||
this._source = { ...this._source!, stat_energy_from: ev.detail.value };
|
||||
// Reset cost type if switching to external statistic with incompatible cost type
|
||||
@@ -459,6 +506,7 @@ export class DialogEnergyGridSettings
|
||||
number_energy_price: null,
|
||||
};
|
||||
}
|
||||
this._updateMetadata(ev.detail.value);
|
||||
}
|
||||
|
||||
private _statisticToChanged(ev: ValueChangedEvent<string>) {
|
||||
@@ -487,6 +535,17 @@ export class DialogEnergyGridSettings
|
||||
number_energy_price_export: null,
|
||||
};
|
||||
}
|
||||
this._updateMetadata(ev.detail.value);
|
||||
}
|
||||
|
||||
private _nameChanged(ev: InputEvent) {
|
||||
this._source = {
|
||||
...this._source!,
|
||||
name: (ev.target as HaInput).value,
|
||||
};
|
||||
if (!this._source.name) {
|
||||
delete this._source.name;
|
||||
}
|
||||
}
|
||||
|
||||
private _handleImportCostTypeChanged(ev: Event) {
|
||||
@@ -569,6 +628,9 @@ export class DialogEnergyGridSettings
|
||||
number_energy_price_export: this._source!.number_energy_price_export,
|
||||
cost_adjustment_day: this._source!.cost_adjustment_day,
|
||||
};
|
||||
if (this._source?.name) {
|
||||
source.name = this._source.name;
|
||||
}
|
||||
|
||||
// Only include power_config if a power type is selected
|
||||
if (this._powerType !== "none") {
|
||||
@@ -601,6 +663,9 @@ export class DialogEnergyGridSettings
|
||||
ha-input:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
ha-input.name {
|
||||
margin-top: var(--ha-space-4);
|
||||
}
|
||||
ha-radio-group {
|
||||
margin-bottom: var(--ha-space-4);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import "../../../../components/ha-dialog";
|
||||
import "../../../../components/ha-dialog-footer";
|
||||
import "../../../../components/ha-svg-icon";
|
||||
import "../../../../components/radio/ha-radio-group";
|
||||
import "../../../../components/input/ha-input";
|
||||
import type { HaRadioGroup } from "../../../../components/radio/ha-radio-group";
|
||||
import "../../../../components/radio/ha-radio-option";
|
||||
import type { ConfigEntry } from "../../../../data/config_entries";
|
||||
@@ -27,6 +28,12 @@ import { haStyle, haStyleDialog } from "../../../../resources/styles";
|
||||
import type { HomeAssistant, ValueChangedEvent } from "../../../../types";
|
||||
import { brandsUrl } from "../../../../util/brands-url";
|
||||
import type { EnergySettingsSolarDialogParams } from "./show-dialogs-energy";
|
||||
import {
|
||||
getStatisticLabel,
|
||||
getStatisticMetadata,
|
||||
isExternalStatistic,
|
||||
} from "../../../../data/recorder";
|
||||
import type { HaInput } from "../../../../components/input/ha-input";
|
||||
|
||||
const energyUnitClasses = ["energy"];
|
||||
const powerUnitClasses = ["power"];
|
||||
@@ -129,6 +136,24 @@ export class DialogEnergySolarSettings
|
||||
autofocus
|
||||
></ha-statistic-picker>
|
||||
|
||||
<ha-input
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.energy.solar.dialog.display_name"
|
||||
)}
|
||||
type="text"
|
||||
.disabled=${!this._source?.stat_energy_from}
|
||||
.value=${this._source?.name || ""}
|
||||
.placeholder=${this._source?.stat_energy_from
|
||||
? getStatisticLabel(
|
||||
this.hass,
|
||||
this._source.stat_energy_from,
|
||||
this._params?.statsMetadata?.[this._source.stat_energy_from]
|
||||
)
|
||||
: ""}
|
||||
@input=${this._nameChanged}
|
||||
>
|
||||
</ha-input>
|
||||
|
||||
<ha-statistic-picker
|
||||
.hass=${this.hass}
|
||||
.includeUnitClass=${powerUnitClasses}
|
||||
@@ -284,14 +309,38 @@ export class DialogEnergySolarSettings
|
||||
});
|
||||
}
|
||||
|
||||
private _statisticChanged(ev: ValueChangedEvent<string>) {
|
||||
private async _statisticChanged(ev: ValueChangedEvent<string>) {
|
||||
this._source = { ...this._source!, stat_energy_from: ev.detail.value };
|
||||
if (
|
||||
ev.detail.value &&
|
||||
isExternalStatistic(ev.detail.value) &&
|
||||
this._params?.statsMetadata &&
|
||||
!(ev.detail.value in this._params.statsMetadata)
|
||||
) {
|
||||
const [metadata] = await getStatisticMetadata(this.hass, [
|
||||
ev.detail.value,
|
||||
]);
|
||||
if (metadata) {
|
||||
this._params.statsMetadata[ev.detail.value] = metadata;
|
||||
this.requestUpdate("_params");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _powerStatisticChanged(ev: ValueChangedEvent<string>) {
|
||||
this._source = { ...this._source!, stat_rate: ev.detail.value };
|
||||
}
|
||||
|
||||
private _nameChanged(ev: InputEvent) {
|
||||
this._source = {
|
||||
...this._source!,
|
||||
name: (ev.target as HaInput).value,
|
||||
};
|
||||
if (!this._source.name) {
|
||||
delete this._source.name;
|
||||
}
|
||||
}
|
||||
|
||||
private async _save() {
|
||||
try {
|
||||
if (!this._forecast) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import type { StatisticsMetaData } from "../../../../data/recorder";
|
||||
export interface EnergySettingsGridDialogParams {
|
||||
source?: GridSourceTypeEnergyPreference;
|
||||
grid_sources: GridSourceTypeEnergyPreference[];
|
||||
statsMetadata?: Record<string, StatisticsMetaData>;
|
||||
saveCallback: (source: GridSourceTypeEnergyPreference) => Promise<void>;
|
||||
}
|
||||
|
||||
@@ -21,12 +22,14 @@ export interface EnergySettingsSolarDialogParams {
|
||||
info: EnergyInfo;
|
||||
source?: SolarSourceTypeEnergyPreference;
|
||||
solar_sources: SolarSourceTypeEnergyPreference[];
|
||||
statsMetadata?: Record<string, StatisticsMetaData>;
|
||||
saveCallback: (source: SolarSourceTypeEnergyPreference) => Promise<void>;
|
||||
}
|
||||
|
||||
export interface EnergySettingsBatteryDialogParams {
|
||||
source?: BatterySourceTypeEnergyPreference;
|
||||
battery_sources: BatterySourceTypeEnergyPreference[];
|
||||
statsMetadata?: Record<string, StatisticsMetaData>;
|
||||
saveCallback: (source: BatterySourceTypeEnergyPreference) => Promise<void>;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ import { copyToClipboard } from "../../../common/util/copy-clipboard";
|
||||
import { subscribePollingCollection } from "../../../common/util/subscribe-polling";
|
||||
import "../../../components/ha-alert";
|
||||
import "../../../components/ha-button";
|
||||
import "../../../components/ha-dialog-footer";
|
||||
import "../../../components/ha-dialog";
|
||||
import "../../../components/ha-dialog-footer";
|
||||
import "../../../components/ha-metric";
|
||||
import "../../../components/ha-spinner";
|
||||
import type { HassioStats } from "../../../data/hassio/common";
|
||||
@@ -103,10 +103,10 @@ class DialogSystemInformation extends LitElement {
|
||||
this.hass,
|
||||
async () => {
|
||||
this._supervisorStats = await fetchHassioStats(
|
||||
this.hass,
|
||||
this.hass.callWS,
|
||||
"supervisor"
|
||||
);
|
||||
this._coreStats = await fetchHassioStats(this.hass, "core");
|
||||
this._coreStats = await fetchHassioStats(this.hass.callWS, "core");
|
||||
},
|
||||
10000
|
||||
);
|
||||
|
||||
@@ -42,10 +42,6 @@ export default class HaScriptFieldEditor extends LitElement {
|
||||
name: "key",
|
||||
selector: { text: {} },
|
||||
},
|
||||
{
|
||||
name: "description",
|
||||
selector: { text: {} },
|
||||
},
|
||||
{
|
||||
name: "required",
|
||||
selector: { boolean: {} },
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import {
|
||||
mdiAppleKeyboardCommand,
|
||||
mdiCommentEditOutline,
|
||||
mdiCommentTextOutline,
|
||||
mdiDelete,
|
||||
mdiDotsVertical,
|
||||
mdiPlaylistEdit,
|
||||
@@ -21,6 +23,7 @@ import "../../../components/ha-dropdown-item";
|
||||
import type { ScriptFieldSidebarConfig } from "../../../data/automation";
|
||||
import type { Field } from "../../../data/script";
|
||||
import { SELECTOR_SELECTOR_BUILDING_BLOCKS } from "../../../data/selector/selector_selector";
|
||||
import { showPromptDialog } from "../../../dialogs/generic/show-dialog-box";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { isMac } from "../../../util/is_mac";
|
||||
import { showEditorToast } from "../automation/editor-toast";
|
||||
@@ -66,6 +69,14 @@ export default class HaScriptFieldRow extends LitElement {
|
||||
protected render() {
|
||||
const hasSelector =
|
||||
this.field.selector && typeof this.field.selector === "object";
|
||||
|
||||
const trimmedComment = this.field.description?.trim() || "";
|
||||
const commentTooltipText = !trimmedComment
|
||||
? ""
|
||||
: trimmedComment.length > 250
|
||||
? `${trimmedComment.substring(0, 250)}...`
|
||||
: trimmedComment;
|
||||
|
||||
return html`
|
||||
<ha-card outlined>
|
||||
<ha-automation-row
|
||||
@@ -90,6 +101,16 @@ export default class HaScriptFieldRow extends LitElement {
|
||||
.label=${this.hass.localize("ui.common.menu")}
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
|
||||
<ha-dropdown-item value="edit_comment">
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${mdiCommentEditOutline}
|
||||
></ha-svg-icon>
|
||||
${this.hass.localize(
|
||||
`ui.panel.config.automation.editor.comment.${this.field.description ? "edit" : "add"}`
|
||||
)}
|
||||
</ha-dropdown-item>
|
||||
<ha-dropdown-item value="toggle_yaml_mode">
|
||||
<ha-svg-icon slot="icon" .path=${mdiPlaylistEdit}></ha-svg-icon>
|
||||
<div class="overflow-label">
|
||||
@@ -132,7 +153,24 @@ export default class HaScriptFieldRow extends LitElement {
|
||||
</ha-dropdown-item>
|
||||
</ha-dropdown>
|
||||
|
||||
<h3 slot="header">${this.field.name ?? this.key}</h3>
|
||||
<h3 slot="header">
|
||||
${this.field.name ?? this.key}
|
||||
${this.field.description?.trim()
|
||||
? html`
|
||||
<ha-svg-icon
|
||||
id="comment-icon"
|
||||
.path=${mdiCommentTextOutline}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.comment.label"
|
||||
)}
|
||||
class="comment-indicator"
|
||||
></ha-svg-icon>
|
||||
<ha-tooltip for="comment-icon"
|
||||
><p>${commentTooltipText}</p></ha-tooltip
|
||||
>
|
||||
`
|
||||
: nothing}
|
||||
</h3>
|
||||
|
||||
<slot name="icons" slot="icons"></slot>
|
||||
</ha-automation-row>
|
||||
@@ -324,11 +362,46 @@ export default class HaScriptFieldRow extends LitElement {
|
||||
});
|
||||
}
|
||||
|
||||
public openSidebar(selectorEditor = false): void {
|
||||
private _editComment = async (): Promise<void> => {
|
||||
const comment = await showPromptDialog(this, {
|
||||
title: this.hass.localize(
|
||||
`ui.panel.config.automation.editor.comment.${this.field.description ? "edit" : "add"}`
|
||||
),
|
||||
inputLabel: this.hass.localize(
|
||||
"ui.panel.config.automation.editor.comment.label"
|
||||
),
|
||||
inputType: "string",
|
||||
defaultValue: this.field.description,
|
||||
confirmText: this.hass.localize("ui.common.submit"),
|
||||
multiline: true,
|
||||
});
|
||||
if (comment !== null) {
|
||||
const value = { ...this.field };
|
||||
if (comment === "") {
|
||||
delete value.description;
|
||||
} else {
|
||||
value.description = comment;
|
||||
}
|
||||
fireEvent(this, "value-changed", {
|
||||
value,
|
||||
});
|
||||
|
||||
if (this._selected) {
|
||||
this.openSidebar(false, value); // refresh sidebar
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public openSidebar(
|
||||
selectorEditor = false,
|
||||
fieldValue?: HaScriptFieldRow["field"]
|
||||
): void {
|
||||
if (!selectorEditor) {
|
||||
this._selected = true;
|
||||
}
|
||||
|
||||
const field = fieldValue ?? this.field;
|
||||
|
||||
fireEvent(this, "open-sidebar", {
|
||||
save: (value) => {
|
||||
fireEvent(this, "value-changed", { value });
|
||||
@@ -353,12 +426,13 @@ export default class HaScriptFieldRow extends LitElement {
|
||||
},
|
||||
delete: this._onDelete,
|
||||
config: {
|
||||
field: this.field,
|
||||
field,
|
||||
selector: selectorEditor,
|
||||
key: this.key,
|
||||
excludeKeys: this.excludeKeys,
|
||||
},
|
||||
yamlMode: this._yamlMode,
|
||||
editComment: this._editComment,
|
||||
} satisfies ScriptFieldSidebarConfig);
|
||||
|
||||
if (this.narrow) {
|
||||
@@ -419,6 +493,9 @@ export default class HaScriptFieldRow extends LitElement {
|
||||
case "delete":
|
||||
this._onDelete();
|
||||
break;
|
||||
case "edit_comment":
|
||||
this._editComment();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,8 +26,7 @@ export const supportsMediaPlayerSourceCardFeature = (
|
||||
const domain = computeDomain(stateObj.entity_id);
|
||||
return (
|
||||
domain === "media_player" &&
|
||||
supportsFeature(stateObj, MediaPlayerEntityFeature.SELECT_SOURCE) &&
|
||||
!!stateObj.attributes.source_list?.length
|
||||
supportsFeature(stateObj, MediaPlayerEntityFeature.SELECT_SOURCE)
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -355,11 +355,13 @@ export class HuiEnergySolarGraphCard
|
||||
name: this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.energy_solar_graph.production",
|
||||
{
|
||||
name: getStatisticLabel(
|
||||
this.hass,
|
||||
source.stat_energy_from,
|
||||
statisticsMetaData[source.stat_energy_from]
|
||||
),
|
||||
name:
|
||||
source.name ||
|
||||
getStatisticLabel(
|
||||
this.hass,
|
||||
source.stat_energy_from,
|
||||
statisticsMetaData[source.stat_energy_from]
|
||||
),
|
||||
}
|
||||
),
|
||||
barMaxWidth: 50,
|
||||
@@ -463,11 +465,13 @@ export class HuiEnergySolarGraphCard
|
||||
name: this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.energy_solar_graph.forecast",
|
||||
{
|
||||
name: getStatisticLabel(
|
||||
this.hass,
|
||||
source.stat_energy_from,
|
||||
statisticsMetaData[source.stat_energy_from]
|
||||
),
|
||||
name:
|
||||
source.name ||
|
||||
getStatisticLabel(
|
||||
this.hass,
|
||||
source.stat_energy_from,
|
||||
statisticsMetaData[source.stat_energy_from]
|
||||
),
|
||||
}
|
||||
),
|
||||
step: false,
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
// @ts-ignore
|
||||
import dataTableStyles from "@material/data-table/dist/mdc.data-table.min.css";
|
||||
import type { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||
import type { CSSResultGroup, PropertyValues } from "lit";
|
||||
import { css, html, LitElement, unsafeCSS, nothing } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
@@ -551,7 +549,13 @@ export class HuiEnergySourcesTableCard
|
||||
null,
|
||||
null,
|
||||
showCosts,
|
||||
compare
|
||||
compare,
|
||||
source.name
|
||||
? this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.energy_sources_table.named_battery_discharged",
|
||||
{ name: source.name }
|
||||
)
|
||||
: ""
|
||||
)}${this._renderRow(
|
||||
computedStyles,
|
||||
"battery_in",
|
||||
@@ -563,7 +567,13 @@ export class HuiEnergySourcesTableCard
|
||||
null,
|
||||
null,
|
||||
showCosts,
|
||||
compare
|
||||
compare,
|
||||
source.name
|
||||
? this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.energy_sources_table.named_battery_charged",
|
||||
{ name: source.name }
|
||||
)
|
||||
: ""
|
||||
)}`;
|
||||
})}
|
||||
${types.battery
|
||||
@@ -630,6 +640,15 @@ export class HuiEnergySourcesTableCard
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const name = !source.name
|
||||
? ""
|
||||
: source.stat_energy_to
|
||||
? this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.energy_sources_table.named_grid_imported",
|
||||
{ name: source.name }
|
||||
)
|
||||
: source.name;
|
||||
|
||||
return this._renderRow(
|
||||
computedStyles,
|
||||
"grid_consumption",
|
||||
@@ -641,7 +660,8 @@ export class HuiEnergySourcesTableCard
|
||||
cost,
|
||||
costCompare,
|
||||
showCosts,
|
||||
compare
|
||||
compare,
|
||||
name
|
||||
);
|
||||
})();
|
||||
|
||||
@@ -670,6 +690,15 @@ export class HuiEnergySourcesTableCard
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const name = !source.name
|
||||
? ""
|
||||
: source.stat_energy_from
|
||||
? this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.energy_sources_table.named_grid_exported",
|
||||
{ name: source.name }
|
||||
)
|
||||
: source.name;
|
||||
|
||||
return this._renderRow(
|
||||
computedStyles,
|
||||
"grid_return",
|
||||
@@ -681,7 +710,8 @@ export class HuiEnergySourcesTableCard
|
||||
-cost,
|
||||
-costCompare,
|
||||
showCosts,
|
||||
compare
|
||||
compare,
|
||||
name
|
||||
);
|
||||
})();
|
||||
|
||||
@@ -756,63 +786,120 @@ export class HuiEnergySourcesTableCard
|
||||
}
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return css`
|
||||
${unsafeCSS(dataTableStyles)}
|
||||
.mdc-data-table {
|
||||
width: 100%;
|
||||
border: 0;
|
||||
}
|
||||
.mdc-data-table__header-cell,
|
||||
.mdc-data-table__cell {
|
||||
color: var(--primary-text-color);
|
||||
border-bottom-color: var(--divider-color);
|
||||
text-align: var(--float-start);
|
||||
}
|
||||
.mdc-data-table__row:not(.mdc-data-table__row--selected):hover {
|
||||
background-color: rgba(var(--rgb-primary-text-color), 0.04);
|
||||
}
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
.total {
|
||||
--mdc-typography-body2-font-weight: var(--ha-font-weight-medium);
|
||||
}
|
||||
.total .mdc-data-table__cell {
|
||||
border-top: 1px solid var(--divider-color);
|
||||
}
|
||||
ha-card {
|
||||
max-height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
.card-header {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.content {
|
||||
padding: 16px;
|
||||
}
|
||||
.has-header {
|
||||
padding-top: 0;
|
||||
}
|
||||
.cell-bullet {
|
||||
width: 32px;
|
||||
padding-right: 0;
|
||||
padding-inline-end: 0;
|
||||
padding-inline-start: 16px;
|
||||
direction: var(--direction);
|
||||
}
|
||||
.bullet {
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-radius: var(--ha-border-radius-sm);
|
||||
height: 16px;
|
||||
width: 32px;
|
||||
}
|
||||
.mdc-data-table__cell--numeric {
|
||||
direction: ltr;
|
||||
}
|
||||
`;
|
||||
}
|
||||
static styles: CSSResultGroup = css`
|
||||
.mdc-data-table__content,
|
||||
.mdc-data-table__cell {
|
||||
font-family: var(--ha-font-family-body);
|
||||
-moz-osx-font-smoothing: var(--ha-moz-osx-font-smoothing);
|
||||
-webkit-font-smoothing: var(--ha-font-smoothing);
|
||||
font-size: var(--ha-font-size-m);
|
||||
line-height: var(--ha-line-height-normal);
|
||||
font-weight: var(--ha-font-weight-normal);
|
||||
letter-spacing: 0.0178571429em;
|
||||
text-decoration: inherit;
|
||||
text-transform: inherit;
|
||||
}
|
||||
.mdc-data-table {
|
||||
background-color: var(--card-background-color);
|
||||
border-radius: var(--ha-border-radius-sm);
|
||||
border: 0;
|
||||
box-sizing: border-box;
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
.mdc-data-table__table-container {
|
||||
-webkit-overflow-scrolling: touch;
|
||||
overflow-x: auto;
|
||||
width: 100%;
|
||||
}
|
||||
.mdc-data-table__table {
|
||||
min-width: 100%;
|
||||
border: 0;
|
||||
border-spacing: 0;
|
||||
table-layout: fixed;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.mdc-data-table__header-row {
|
||||
height: 56px;
|
||||
}
|
||||
.mdc-data-table__row {
|
||||
background-color: inherit;
|
||||
height: 52px;
|
||||
}
|
||||
.mdc-data-table__header-cell,
|
||||
.mdc-data-table__cell {
|
||||
border-bottom-width: 1px;
|
||||
border-bottom-style: solid;
|
||||
box-sizing: border-box;
|
||||
color: var(--primary-text-color);
|
||||
border-bottom-color: var(--divider-color);
|
||||
overflow: hidden;
|
||||
padding: 0 16px;
|
||||
text-align: var(--float-start);
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.mdc-data-table__header-cell {
|
||||
background-color: var(--card-background-color);
|
||||
font-family: var(--ha-font-family-body);
|
||||
-moz-osx-font-smoothing: var(--ha-moz-osx-font-smoothing);
|
||||
-webkit-font-smoothing: var(--ha-font-smoothing);
|
||||
font-size: var(--ha-font-size-m);
|
||||
line-height: var(--ha-line-height-normal);
|
||||
font-weight: var(--ha-font-weight-medium);
|
||||
letter-spacing: 0.0071428571em;
|
||||
text-decoration: inherit;
|
||||
text-transform: inherit;
|
||||
}
|
||||
.mdc-data-table__row:last-child .mdc-data-table__cell {
|
||||
border-bottom: none;
|
||||
}
|
||||
.mdc-data-table__row:not(.mdc-data-table__row--selected):hover {
|
||||
background-color: rgba(var(--rgb-primary-text-color), 0.04);
|
||||
}
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
.total .mdc-data-table__cell {
|
||||
border-top: 1px solid var(--divider-color);
|
||||
font-weight: var(--ha-font-weight-medium);
|
||||
}
|
||||
ha-card {
|
||||
max-height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
.card-header {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.content {
|
||||
padding: 16px;
|
||||
}
|
||||
.has-header {
|
||||
padding-top: 0;
|
||||
}
|
||||
.cell-bullet {
|
||||
width: 32px;
|
||||
padding-right: 0;
|
||||
padding-inline-end: 0;
|
||||
padding-inline-start: 16px;
|
||||
direction: var(--direction);
|
||||
}
|
||||
.bullet {
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-radius: var(--ha-border-radius-sm);
|
||||
height: 16px;
|
||||
width: 32px;
|
||||
}
|
||||
.mdc-data-table__cell--numeric {
|
||||
text-align: var(--float-end);
|
||||
direction: ltr;
|
||||
}
|
||||
.mdc-data-table__header-cell--numeric {
|
||||
text-align: var(--float-end);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
||||
@@ -259,6 +259,16 @@ export class HuiEnergyUsageGraphCard
|
||||
from_battery?: string[];
|
||||
} = {};
|
||||
|
||||
const statLabels: {
|
||||
to_grid: Record<string, string>;
|
||||
from_grid: Record<string, string>;
|
||||
to_battery: Record<string, string>;
|
||||
} = {
|
||||
to_grid: {},
|
||||
from_grid: {},
|
||||
to_battery: {},
|
||||
};
|
||||
|
||||
for (const source of energyData.prefs.energy_sources) {
|
||||
if (source.type === "solar") {
|
||||
if (statIds.solar) {
|
||||
@@ -277,6 +287,12 @@ export class HuiEnergyUsageGraphCard
|
||||
statIds.to_battery = [source.stat_energy_to];
|
||||
statIds.from_battery = [source.stat_energy_from];
|
||||
}
|
||||
if (source.name) {
|
||||
statLabels.to_battery[source.stat_energy_to] = this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.energy_sources_table.named_battery_charged",
|
||||
{ name: source.name }
|
||||
);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -291,6 +307,15 @@ export class HuiEnergyUsageGraphCard
|
||||
} else {
|
||||
statIds.from_grid = [gridSource.stat_energy_from];
|
||||
}
|
||||
if (gridSource.name) {
|
||||
statLabels.from_grid[gridSource.stat_energy_from] =
|
||||
gridSource.stat_energy_to
|
||||
? this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.energy_usage_graph.named_grid_consumed",
|
||||
{ name: gridSource.name }
|
||||
)
|
||||
: gridSource.name;
|
||||
}
|
||||
}
|
||||
if (gridSource.stat_energy_to) {
|
||||
if (statIds.to_grid) {
|
||||
@@ -298,6 +323,15 @@ export class HuiEnergyUsageGraphCard
|
||||
} else {
|
||||
statIds.to_grid = [gridSource.stat_energy_to];
|
||||
}
|
||||
if (gridSource.name) {
|
||||
statLabels.to_grid[gridSource.stat_energy_to] =
|
||||
gridSource.stat_energy_from
|
||||
? this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.energy_usage_graph.named_grid_exported",
|
||||
{ name: gridSource.name }
|
||||
)
|
||||
: gridSource.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,7 +354,7 @@ export class HuiEnergyUsageGraphCard
|
||||
}
|
||||
});
|
||||
|
||||
const labels = {
|
||||
const typeLabels = {
|
||||
used_grid: this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.energy_usage_graph.combined_from_grid"
|
||||
),
|
||||
@@ -354,7 +388,8 @@ export class HuiEnergyUsageGraphCard
|
||||
statIds,
|
||||
colorIndices,
|
||||
computedStyles,
|
||||
labels,
|
||||
typeLabels,
|
||||
statLabels,
|
||||
trackY,
|
||||
true
|
||||
)
|
||||
@@ -381,7 +416,8 @@ export class HuiEnergyUsageGraphCard
|
||||
statIds,
|
||||
colorIndices,
|
||||
computedStyles,
|
||||
labels,
|
||||
typeLabels,
|
||||
statLabels,
|
||||
trackY,
|
||||
false
|
||||
)
|
||||
@@ -415,11 +451,16 @@ export class HuiEnergyUsageGraphCard
|
||||
},
|
||||
colorIndices: Record<string, Record<string, number>>,
|
||||
computedStyles: CSSStyleDeclaration,
|
||||
labels: {
|
||||
typeLabels: {
|
||||
used_grid: string;
|
||||
used_solar: string;
|
||||
used_battery: string;
|
||||
},
|
||||
statLabels: {
|
||||
to_grid: Record<string, string>;
|
||||
from_grid: Record<string, string>;
|
||||
to_battery: Record<string, string>;
|
||||
},
|
||||
trackY: (v: number) => void,
|
||||
compare = false
|
||||
) {
|
||||
@@ -540,9 +581,10 @@ export class HuiEnergyUsageGraphCard
|
||||
type: "bar",
|
||||
cursor: "default",
|
||||
name:
|
||||
type in labels
|
||||
? labels[type]
|
||||
: getStatisticLabel(
|
||||
type in typeLabels
|
||||
? typeLabels[type]
|
||||
: statLabels[type]?.[statId] ||
|
||||
getStatisticLabel(
|
||||
this.hass,
|
||||
statId,
|
||||
statisticsMetaData[statId]
|
||||
|
||||
@@ -332,7 +332,7 @@ export default <T extends Constructor<HassElement>>(superClass: T) =>
|
||||
import("../data/supervisor/store"),
|
||||
]);
|
||||
const [info, repos] = await Promise.all([
|
||||
fetchHassioAddonInfo(this.hass!, myParams.get("app")!),
|
||||
fetchHassioAddonInfo(this.hass!.callWS, myParams.get("app")!),
|
||||
fetchStoreRepositories(this.hass!),
|
||||
]);
|
||||
const repo = repos.find((r) => r.slug === info.repository);
|
||||
|
||||
@@ -1751,7 +1751,7 @@
|
||||
"no_areas_text_non_admin": "Ask an administrator to map your vacuum's segments to areas.",
|
||||
"configure_area_mapping": "Configure area mapping",
|
||||
"configure": "Configure",
|
||||
"clean_areas_order_hint": "Cleaning order may not be supported by your vacuum.",
|
||||
"clean_areas_order_hint": "The order in which areas are cleaned may not be supported by your vacuum.",
|
||||
"other_areas": "Other areas"
|
||||
},
|
||||
"person": {
|
||||
@@ -2818,6 +2818,7 @@
|
||||
},
|
||||
"state": {
|
||||
"update_available": "Update available",
|
||||
"updating": "Updating...",
|
||||
"installed": "Installed",
|
||||
"not_installed": "Not installed",
|
||||
"not_available": "Not available"
|
||||
@@ -2873,6 +2874,7 @@
|
||||
"dashboard": {
|
||||
"cpu_usage": "CPU usage",
|
||||
"ram_usage": "RAM usage",
|
||||
"controls": "Controls",
|
||||
"app_running": "App is running",
|
||||
"app_stopped": "App is stopped",
|
||||
"current_version": "Current version: {version}",
|
||||
@@ -2889,6 +2891,7 @@
|
||||
"failed_to_save": "Failed to save: {error}",
|
||||
"failed_to_reset": "Failed to reset: {error}",
|
||||
"failed_to_restart": "Failed to restart {name}",
|
||||
"uninstalling": "Uninstalling...",
|
||||
"protection_mode": {
|
||||
"title": "Protection mode disabled!",
|
||||
"content": "Protection mode on this app is disabled! This gives the app full access to the entire system, which is more risky for your system if the app is compromised. Only disable protection mode if you know what you are doing.",
|
||||
@@ -4115,6 +4118,7 @@
|
||||
"energy_from_helper": "Pick a sensor which measures grid import in either of {unit}.",
|
||||
"energy_to_grid": "Energy exported to grid",
|
||||
"energy_to_helper": "Pick a sensor which measures grid export in either of {unit}.",
|
||||
"display_name": "[%key:ui::panel::config::energy::device_consumption::dialog::display_name%]",
|
||||
"import_cost": "Cost tracking",
|
||||
"import_cost_para": "Select how Home Assistant should keep track of the costs of the imported energy.",
|
||||
"no_cost_tracking": "Do not track costs",
|
||||
@@ -4172,6 +4176,7 @@
|
||||
"dialog": {
|
||||
"header": "Configure solar panels",
|
||||
"entity_para": "Pick a sensor which measures solar production in either of {unit}.",
|
||||
"display_name": "[%key:ui::panel::config::energy::device_consumption::dialog::display_name%]",
|
||||
"solar_production_energy": "Solar production energy",
|
||||
"solar_production_power": "Solar production power",
|
||||
"solar_production_forecast": "Solar production forecast",
|
||||
@@ -4195,6 +4200,7 @@
|
||||
"energy_helper_out": "Pick a sensor that measures the electricity flowing out of the battery in either of {unit}.",
|
||||
"energy_into_battery": "Energy charged into the battery",
|
||||
"energy_out_of_battery": "Energy discharged from the battery",
|
||||
"display_name": "[%key:ui::panel::config::energy::device_consumption::dialog::display_name%]",
|
||||
"state_of_charge": "Battery state of charge sensor",
|
||||
"state_of_charge_helper": "Sensor reporting battery state of charge as %.",
|
||||
"power": "Battery power",
|
||||
@@ -5043,6 +5049,11 @@
|
||||
"placeholder": "Optional description",
|
||||
"add": "Add description"
|
||||
},
|
||||
"comment": {
|
||||
"label": "Comment",
|
||||
"edit": "Edit comment",
|
||||
"add": "Add comment"
|
||||
},
|
||||
"leave": {
|
||||
"unsaved_new_title": "Save new automation?",
|
||||
"unsaved_new_text": "You can save your changes, or delete this automation. You can't undo this action.",
|
||||
@@ -8570,7 +8581,10 @@
|
||||
"total_usage": "+{num} kWh",
|
||||
"combined_from_grid": "Combined from grid",
|
||||
"consumed_solar": "Consumed solar",
|
||||
"consumed_battery": "Consumed battery"
|
||||
"consumed_battery": "Consumed battery",
|
||||
"named_battery_charged": "[%key:ui::panel::lovelace::cards::energy::energy_sources_table::named_battery_charged%]",
|
||||
"named_grid_consumed": "Consumed {name}",
|
||||
"named_grid_exported": "[%key:ui::panel::lovelace::cards::energy::energy_sources_table::named_grid_exported%]"
|
||||
},
|
||||
"energy_sources_table": {
|
||||
"grid_total": "Grid total",
|
||||
@@ -8583,7 +8597,11 @@
|
||||
"previous_energy": "Previous usage",
|
||||
"previous_cost": "Previous cost",
|
||||
"battery_total": "Battery total",
|
||||
"total_costs": "Total costs"
|
||||
"total_costs": "Total costs",
|
||||
"named_battery_charged": "{name} charged",
|
||||
"named_battery_discharged": "{name} discharged",
|
||||
"named_grid_imported": "{name} imported",
|
||||
"named_grid_exported": "{name} exported"
|
||||
},
|
||||
"energy_solar_graph": {
|
||||
"production": "Production {name}",
|
||||
|
||||
+3
-1
@@ -253,6 +253,8 @@ export interface HomeAssistantInternationalization {
|
||||
loadFragmentTranslation(fragment: string): Promise<LocalizeFunc | undefined>;
|
||||
}
|
||||
|
||||
export type CallWS = <T>(msg: MessageBase) => Promise<T>;
|
||||
|
||||
export interface HomeAssistantApi {
|
||||
callService<T = any>(
|
||||
domain: ServiceCallRequest["domain"],
|
||||
@@ -277,7 +279,7 @@ export interface HomeAssistantApi {
|
||||
): Promise<Response>;
|
||||
fetchWithAuth(path: string, init?: Record<string, any>): Promise<Response>;
|
||||
sendWS(msg: MessageBase): void;
|
||||
callWS<T>(msg: MessageBase): Promise<T>;
|
||||
callWS: CallWS;
|
||||
}
|
||||
|
||||
export interface HomeAssistantFormatters {
|
||||
|
||||
Reference in New Issue
Block a user