mirror of
https://github.com/home-assistant/frontend.git
synced 2025-11-09 10:59:50 +00:00
Compare commits
2 Commits
copilot/ad
...
triggers-d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c87327e34 | ||
|
|
9b9078229a |
@@ -46,22 +46,9 @@ class HassioIngressView extends LitElement {
|
|||||||
|
|
||||||
private _fetchDataTimeout?: number;
|
private _fetchDataTimeout?: number;
|
||||||
|
|
||||||
private _messageListener = (ev: MessageEvent) => {
|
|
||||||
if (this._addon?.webui_ha_aware && ev.data?.type === "toggle-sidebar") {
|
|
||||||
this._toggleMenu();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public connectedCallback() {
|
|
||||||
super.connectedCallback();
|
|
||||||
window.addEventListener("message", this._messageListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
public disconnectedCallback() {
|
public disconnectedCallback() {
|
||||||
super.disconnectedCallback();
|
super.disconnectedCallback();
|
||||||
|
|
||||||
window.removeEventListener("message", this._messageListener);
|
|
||||||
|
|
||||||
if (this._sessionKeepAlive) {
|
if (this._sessionKeepAlive) {
|
||||||
clearInterval(this._sessionKeepAlive);
|
clearInterval(this._sessionKeepAlive);
|
||||||
this._sessionKeepAlive = undefined;
|
this._sessionKeepAlive = undefined;
|
||||||
@@ -96,17 +83,8 @@ class HassioIngressView extends LitElement {
|
|||||||
</hass-subpage>`;
|
</hass-subpage>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If webui_ha_aware is true, or if narrow or sidebar is always hidden,
|
return html`${this.narrow || this.hass.dockedSidebar === "always_hidden"
|
||||||
// don't render the header and just render the iframe
|
? html`<div class="header">
|
||||||
if (
|
|
||||||
this._addon.webui_ha_aware ||
|
|
||||||
this.narrow ||
|
|
||||||
this.hass.dockedSidebar === "always_hidden"
|
|
||||||
) {
|
|
||||||
return iframe;
|
|
||||||
}
|
|
||||||
|
|
||||||
return html`<div class="header">
|
|
||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
.label=${this.hass.localize("ui.sidebar.sidebar_toggle")}
|
.label=${this.hass.localize("ui.sidebar.sidebar_toggle")}
|
||||||
.path=${mdiMenu}
|
.path=${mdiMenu}
|
||||||
@@ -114,7 +92,8 @@ class HassioIngressView extends LitElement {
|
|||||||
></ha-icon-button>
|
></ha-icon-button>
|
||||||
<div class="main-title">${this._addon.name}</div>
|
<div class="main-title">${this._addon.name}</div>
|
||||||
</div>
|
</div>
|
||||||
${iframe}`;
|
${iframe}`
|
||||||
|
: iframe}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async firstUpdated(): Promise<void> {
|
protected async firstUpdated(): Promise<void> {
|
||||||
|
|||||||
@@ -94,9 +94,6 @@ export class HaServiceControl extends LitElement {
|
|||||||
@property({ attribute: "hide-picker", type: Boolean, reflect: true })
|
@property({ attribute: "hide-picker", type: Boolean, reflect: true })
|
||||||
public hidePicker = false;
|
public hidePicker = false;
|
||||||
|
|
||||||
@property({ attribute: "hide-description", type: Boolean })
|
|
||||||
public hideDescription = false;
|
|
||||||
|
|
||||||
@state() private _value!: this["value"];
|
@state() private _value!: this["value"];
|
||||||
|
|
||||||
@state() private _checkedKeys = new Set();
|
@state() private _checkedKeys = new Set();
|
||||||
@@ -480,9 +477,7 @@ export class HaServiceControl extends LitElement {
|
|||||||
@value-changed=${this._serviceChanged}
|
@value-changed=${this._serviceChanged}
|
||||||
.showServiceId=${this.showServiceId}
|
.showServiceId=${this.showServiceId}
|
||||||
></ha-service-picker>`}
|
></ha-service-picker>`}
|
||||||
${this.hideDescription
|
|
||||||
? nothing
|
|
||||||
: html`
|
|
||||||
<div class="description">
|
<div class="description">
|
||||||
${description ? html`<p>${description}</p>` : ""}
|
${description ? html`<p>${description}</p>` : ""}
|
||||||
${this._manifest
|
${this._manifest
|
||||||
@@ -506,14 +501,15 @@ export class HaServiceControl extends LitElement {
|
|||||||
</a>`
|
</a>`
|
||||||
: nothing}
|
: nothing}
|
||||||
</div>
|
</div>
|
||||||
`}
|
|
||||||
${serviceData && "target" in serviceData
|
${serviceData && "target" in serviceData
|
||||||
? html`<ha-settings-row .narrow=${this.narrow}>
|
? html`<ha-settings-row .narrow=${this.narrow}>
|
||||||
${hasOptional
|
${hasOptional
|
||||||
? html`<div slot="prefix" class="checkbox-spacer"></div>`
|
? html`<div slot="prefix" class="checkbox-spacer"></div>`
|
||||||
: ""}
|
: ""}
|
||||||
<span slot="heading"
|
<span slot="heading"
|
||||||
>${this.hass.localize("ui.components.service-control.target")}</span
|
>${this.hass.localize(
|
||||||
|
"ui.components.service-control.target"
|
||||||
|
)}</span
|
||||||
>
|
>
|
||||||
<span slot="description"
|
<span slot="description"
|
||||||
>${this.hass.localize(
|
>${this.hass.localize(
|
||||||
|
|||||||
97
src/components/ha-trigger-icon.ts
Normal file
97
src/components/ha-trigger-icon.ts
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
import {
|
||||||
|
mdiAvTimer,
|
||||||
|
mdiCalendar,
|
||||||
|
mdiClockOutline,
|
||||||
|
mdiCodeBraces,
|
||||||
|
mdiDevices,
|
||||||
|
mdiFormatListBulleted,
|
||||||
|
mdiGestureDoubleTap,
|
||||||
|
mdiHomeAssistant,
|
||||||
|
mdiMapMarker,
|
||||||
|
mdiMapMarkerRadius,
|
||||||
|
mdiMessageAlert,
|
||||||
|
mdiMicrophoneMessage,
|
||||||
|
mdiNfcVariant,
|
||||||
|
mdiNumeric,
|
||||||
|
mdiStateMachine,
|
||||||
|
mdiSwapHorizontal,
|
||||||
|
mdiWeatherSunny,
|
||||||
|
mdiWebhook,
|
||||||
|
} from "@mdi/js";
|
||||||
|
import { html, LitElement, nothing } from "lit";
|
||||||
|
import { customElement, property } from "lit/decorators";
|
||||||
|
import { until } from "lit/directives/until";
|
||||||
|
import { computeDomain } from "../common/entity/compute_domain";
|
||||||
|
import { FALLBACK_DOMAIN_ICONS, triggerIcon } from "../data/icons";
|
||||||
|
import type { HomeAssistant } from "../types";
|
||||||
|
import "./ha-icon";
|
||||||
|
import "./ha-svg-icon";
|
||||||
|
|
||||||
|
export const TRIGGER_ICONS = {
|
||||||
|
calendar: mdiCalendar,
|
||||||
|
device: mdiDevices,
|
||||||
|
event: mdiGestureDoubleTap,
|
||||||
|
state: mdiStateMachine,
|
||||||
|
geo_location: mdiMapMarker,
|
||||||
|
homeassistant: mdiHomeAssistant,
|
||||||
|
mqtt: mdiSwapHorizontal,
|
||||||
|
numeric_state: mdiNumeric,
|
||||||
|
sun: mdiWeatherSunny,
|
||||||
|
conversation: mdiMicrophoneMessage,
|
||||||
|
tag: mdiNfcVariant,
|
||||||
|
template: mdiCodeBraces,
|
||||||
|
time: mdiClockOutline,
|
||||||
|
time_pattern: mdiAvTimer,
|
||||||
|
webhook: mdiWebhook,
|
||||||
|
persistent_notification: mdiMessageAlert,
|
||||||
|
zone: mdiMapMarkerRadius,
|
||||||
|
list: mdiFormatListBulleted,
|
||||||
|
};
|
||||||
|
|
||||||
|
@customElement("ha-trigger-icon")
|
||||||
|
export class HaTriggerIcon extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property() public trigger?: string;
|
||||||
|
|
||||||
|
@property() public icon?: string;
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
if (this.icon) {
|
||||||
|
return html`<ha-icon .icon=${this.icon}></ha-icon>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.trigger) {
|
||||||
|
return nothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.hass) {
|
||||||
|
return this._renderFallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
const icon = triggerIcon(this.hass, this.trigger).then((icn) => {
|
||||||
|
if (icn) {
|
||||||
|
return html`<ha-icon .icon=${icn}></ha-icon>`;
|
||||||
|
}
|
||||||
|
return this._renderFallback();
|
||||||
|
});
|
||||||
|
|
||||||
|
return html`${until(icon)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _renderFallback() {
|
||||||
|
const domain = computeDomain(this.trigger!);
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<ha-svg-icon
|
||||||
|
.path=${TRIGGER_ICONS[this.trigger!] || FALLBACK_DOMAIN_ICONS[domain]}
|
||||||
|
></ha-svg-icon>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-trigger-icon": HaTriggerIcon;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import type {
|
import type {
|
||||||
HassEntityAttributeBase,
|
HassEntityAttributeBase,
|
||||||
HassEntityBase,
|
HassEntityBase,
|
||||||
|
HassServiceTarget,
|
||||||
} from "home-assistant-js-websocket";
|
} from "home-assistant-js-websocket";
|
||||||
import { ensureArray } from "../common/array/ensure-array";
|
import { ensureArray } from "../common/array/ensure-array";
|
||||||
import { navigate } from "../common/navigate";
|
import { navigate } from "../common/navigate";
|
||||||
@@ -11,6 +12,7 @@ import { CONDITION_BUILDING_BLOCKS } from "./condition";
|
|||||||
import type { DeviceCondition, DeviceTrigger } from "./device_automation";
|
import type { DeviceCondition, DeviceTrigger } from "./device_automation";
|
||||||
import type { Action, Field, MODES } from "./script";
|
import type { Action, Field, MODES } from "./script";
|
||||||
import { migrateAutomationAction } from "./script";
|
import { migrateAutomationAction } from "./script";
|
||||||
|
import type { TriggerDescription } from "./trigger";
|
||||||
|
|
||||||
export const AUTOMATION_DEFAULT_MODE: (typeof MODES)[number] = "single";
|
export const AUTOMATION_DEFAULT_MODE: (typeof MODES)[number] = "single";
|
||||||
export const AUTOMATION_DEFAULT_MAX = 10;
|
export const AUTOMATION_DEFAULT_MAX = 10;
|
||||||
@@ -84,6 +86,11 @@ export interface BaseTrigger {
|
|||||||
id?: string;
|
id?: string;
|
||||||
variables?: Record<string, unknown>;
|
variables?: Record<string, unknown>;
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
|
options?: Record<string, unknown>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PlatformTrigger extends BaseTrigger {
|
||||||
|
target?: HassServiceTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StateTrigger extends BaseTrigger {
|
export interface StateTrigger extends BaseTrigger {
|
||||||
@@ -570,6 +577,7 @@ export interface TriggerSidebarConfig extends BaseSidebarConfig {
|
|||||||
insertAfter: (value: Trigger | Trigger[]) => boolean;
|
insertAfter: (value: Trigger | Trigger[]) => boolean;
|
||||||
toggleYamlMode: () => void;
|
toggleYamlMode: () => void;
|
||||||
config: Trigger;
|
config: Trigger;
|
||||||
|
description?: TriggerDescription;
|
||||||
yamlMode: boolean;
|
yamlMode: boolean;
|
||||||
uiSupported: boolean;
|
uiSupported: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -803,9 +803,15 @@ const tryDescribeTrigger = (
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const triggerType = trigger.trigger;
|
||||||
|
const [domain, type] = triggerType.split(".", 2);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
hass.localize(
|
hass.localize(
|
||||||
`ui.panel.config.automation.editor.triggers.type.${trigger.trigger}.label`
|
`component.${domain}.triggers.${type || "_"}.description_configured`
|
||||||
|
) ||
|
||||||
|
hass.localize(
|
||||||
|
`ui.panel.config.automation.editor.triggers.type.${triggerType}.label`
|
||||||
) ||
|
) ||
|
||||||
hass.localize(`ui.panel.config.automation.editor.triggers.unknown_trigger`)
|
hass.localize(`ui.panel.config.automation.editor.triggers.unknown_trigger`)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -112,7 +112,6 @@ export interface HassioAddonDetails extends HassioAddonInfo {
|
|||||||
translations: Record<string, AddonTranslations>;
|
translations: Record<string, AddonTranslations>;
|
||||||
watchdog: null | boolean;
|
watchdog: null | boolean;
|
||||||
webui: null | string;
|
webui: null | string;
|
||||||
webui_ha_aware?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HassioAddonsInfo {
|
export interface HassioAddonsInfo {
|
||||||
|
|||||||
@@ -131,14 +131,19 @@ const resources: {
|
|||||||
all?: Promise<Record<string, ServiceIcons>>;
|
all?: Promise<Record<string, ServiceIcons>>;
|
||||||
domains: Record<string, ServiceIcons | Promise<ServiceIcons>>;
|
domains: Record<string, ServiceIcons | Promise<ServiceIcons>>;
|
||||||
};
|
};
|
||||||
|
triggers: {
|
||||||
|
all?: Promise<Record<string, TriggerIcons>>;
|
||||||
|
domains: Record<string, TriggerIcons | Promise<TriggerIcons>>;
|
||||||
|
};
|
||||||
} = {
|
} = {
|
||||||
entity: {},
|
entity: {},
|
||||||
entity_component: {},
|
entity_component: {},
|
||||||
services: { domains: {} },
|
services: { domains: {} },
|
||||||
|
triggers: { domains: {} },
|
||||||
};
|
};
|
||||||
|
|
||||||
interface IconResources<
|
interface IconResources<
|
||||||
T extends ComponentIcons | PlatformIcons | ServiceIcons,
|
T extends ComponentIcons | PlatformIcons | ServiceIcons | TriggerIcons,
|
||||||
> {
|
> {
|
||||||
resources: Record<string, T>;
|
resources: Record<string, T>;
|
||||||
}
|
}
|
||||||
@@ -182,12 +187,22 @@ type ServiceIcons = Record<
|
|||||||
{ service: string; sections?: Record<string, string> }
|
{ service: string; sections?: Record<string, string> }
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export type IconCategory = "entity" | "entity_component" | "services";
|
type TriggerIcons = Record<
|
||||||
|
string,
|
||||||
|
{ trigger: string; sections?: Record<string, string> }
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type IconCategory =
|
||||||
|
| "entity"
|
||||||
|
| "entity_component"
|
||||||
|
| "services"
|
||||||
|
| "triggers";
|
||||||
|
|
||||||
interface CategoryType {
|
interface CategoryType {
|
||||||
entity: PlatformIcons;
|
entity: PlatformIcons;
|
||||||
entity_component: ComponentIcons;
|
entity_component: ComponentIcons;
|
||||||
services: ServiceIcons;
|
services: ServiceIcons;
|
||||||
|
triggers: TriggerIcons;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getHassIcons = async <T extends IconCategory>(
|
export const getHassIcons = async <T extends IconCategory>(
|
||||||
@@ -265,12 +280,10 @@ export const getServiceIcons = async (
|
|||||||
if (!force && resources.services.all) {
|
if (!force && resources.services.all) {
|
||||||
return resources.services.all;
|
return resources.services.all;
|
||||||
}
|
}
|
||||||
resources.services.all = getHassIcons(hass, "services", domain).then(
|
resources.services.all = getHassIcons(hass, "services").then((res) => {
|
||||||
(res) => {
|
|
||||||
resources.services.domains = res.resources;
|
resources.services.domains = res.resources;
|
||||||
return res?.resources;
|
return res?.resources;
|
||||||
}
|
});
|
||||||
);
|
|
||||||
return resources.services.all;
|
return resources.services.all;
|
||||||
}
|
}
|
||||||
if (!force && domain in resources.services.domains) {
|
if (!force && domain in resources.services.domains) {
|
||||||
@@ -292,6 +305,40 @@ export const getServiceIcons = async (
|
|||||||
return resources.services.domains[domain];
|
return resources.services.domains[domain];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getTriggerIcons = async (
|
||||||
|
hass: HomeAssistant,
|
||||||
|
domain?: string,
|
||||||
|
force = false
|
||||||
|
): Promise<TriggerIcons | Record<string, TriggerIcons> | undefined> => {
|
||||||
|
if (!domain) {
|
||||||
|
if (!force && resources.triggers.all) {
|
||||||
|
return resources.triggers.all;
|
||||||
|
}
|
||||||
|
resources.triggers.all = getHassIcons(hass, "triggers").then((res) => {
|
||||||
|
resources.triggers.domains = res.resources;
|
||||||
|
return res?.resources;
|
||||||
|
});
|
||||||
|
return resources.triggers.all;
|
||||||
|
}
|
||||||
|
if (!force && domain in resources.triggers.domains) {
|
||||||
|
return resources.triggers.domains[domain];
|
||||||
|
}
|
||||||
|
if (resources.triggers.all && !force) {
|
||||||
|
await resources.triggers.all;
|
||||||
|
if (domain in resources.triggers.domains) {
|
||||||
|
return resources.triggers.domains[domain];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isComponentLoaded(hass, domain)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const result = getHassIcons(hass, "triggers", domain);
|
||||||
|
resources.triggers.domains[domain] = result.then(
|
||||||
|
(res) => res?.resources[domain]
|
||||||
|
);
|
||||||
|
return resources.triggers.domains[domain];
|
||||||
|
};
|
||||||
|
|
||||||
// Cache for sorted range keys
|
// Cache for sorted range keys
|
||||||
const sortedRangeCache = new WeakMap<Record<string, string>, number[]>();
|
const sortedRangeCache = new WeakMap<Record<string, string>, number[]>();
|
||||||
|
|
||||||
@@ -471,6 +518,26 @@ export const attributeIcon = async (
|
|||||||
return icon;
|
return icon;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const triggerIcon = async (
|
||||||
|
hass: HomeAssistant,
|
||||||
|
trigger: string
|
||||||
|
): Promise<string | undefined> => {
|
||||||
|
let icon: string | undefined;
|
||||||
|
|
||||||
|
const domain = trigger.includes(".") ? computeDomain(trigger) : trigger;
|
||||||
|
const triggerName = trigger.includes(".") ? computeObjectId(trigger) : "_";
|
||||||
|
|
||||||
|
const triggerIcons = await getTriggerIcons(hass, domain);
|
||||||
|
if (triggerIcons) {
|
||||||
|
const trgrIcon = triggerIcons[triggerName] as TriggerIcons[string];
|
||||||
|
icon = trgrIcon?.trigger;
|
||||||
|
}
|
||||||
|
if (!icon) {
|
||||||
|
icon = await domainIcon(hass, domain);
|
||||||
|
}
|
||||||
|
return icon;
|
||||||
|
};
|
||||||
|
|
||||||
export const serviceIcon = async (
|
export const serviceIcon = async (
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
service: string
|
service: string
|
||||||
|
|||||||
@@ -73,7 +73,8 @@ export type TranslationCategory =
|
|||||||
| "application_credentials"
|
| "application_credentials"
|
||||||
| "issues"
|
| "issues"
|
||||||
| "selector"
|
| "selector"
|
||||||
| "services";
|
| "services"
|
||||||
|
| "triggers";
|
||||||
|
|
||||||
export const subscribeTranslationPreferences = (
|
export const subscribeTranslationPreferences = (
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
|||||||
@@ -1,53 +1,12 @@
|
|||||||
import {
|
import { mdiDotsHorizontal, mdiMapClock, mdiShape } from "@mdi/js";
|
||||||
mdiAvTimer,
|
|
||||||
mdiCalendar,
|
|
||||||
mdiClockOutline,
|
|
||||||
mdiCodeBraces,
|
|
||||||
mdiDevices,
|
|
||||||
mdiDotsHorizontal,
|
|
||||||
mdiFormatListBulleted,
|
|
||||||
mdiGestureDoubleTap,
|
|
||||||
mdiMapClock,
|
|
||||||
mdiMapMarker,
|
|
||||||
mdiMapMarkerRadius,
|
|
||||||
mdiMessageAlert,
|
|
||||||
mdiMicrophoneMessage,
|
|
||||||
mdiNfcVariant,
|
|
||||||
mdiNumeric,
|
|
||||||
mdiShape,
|
|
||||||
mdiStateMachine,
|
|
||||||
mdiSwapHorizontal,
|
|
||||||
mdiWeatherSunny,
|
|
||||||
mdiWebhook,
|
|
||||||
} from "@mdi/js";
|
|
||||||
|
|
||||||
import { mdiHomeAssistant } from "../resources/home-assistant-logo-svg";
|
import type { HomeAssistant } from "../types";
|
||||||
import type {
|
import type {
|
||||||
AutomationElementGroup,
|
AutomationElementGroup,
|
||||||
Trigger,
|
Trigger,
|
||||||
TriggerList,
|
TriggerList,
|
||||||
} from "./automation";
|
} from "./automation";
|
||||||
|
import type { Selector, TargetSelector } from "./selector";
|
||||||
export const TRIGGER_ICONS = {
|
|
||||||
calendar: mdiCalendar,
|
|
||||||
device: mdiDevices,
|
|
||||||
event: mdiGestureDoubleTap,
|
|
||||||
state: mdiStateMachine,
|
|
||||||
geo_location: mdiMapMarker,
|
|
||||||
homeassistant: mdiHomeAssistant,
|
|
||||||
mqtt: mdiSwapHorizontal,
|
|
||||||
numeric_state: mdiNumeric,
|
|
||||||
sun: mdiWeatherSunny,
|
|
||||||
conversation: mdiMicrophoneMessage,
|
|
||||||
tag: mdiNfcVariant,
|
|
||||||
template: mdiCodeBraces,
|
|
||||||
time: mdiClockOutline,
|
|
||||||
time_pattern: mdiAvTimer,
|
|
||||||
webhook: mdiWebhook,
|
|
||||||
persistent_notification: mdiMessageAlert,
|
|
||||||
zone: mdiMapMarkerRadius,
|
|
||||||
list: mdiFormatListBulleted,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const TRIGGER_GROUPS: AutomationElementGroup = {
|
export const TRIGGER_GROUPS: AutomationElementGroup = {
|
||||||
device: {},
|
device: {},
|
||||||
@@ -74,3 +33,26 @@ export const TRIGGER_GROUPS: AutomationElementGroup = {
|
|||||||
|
|
||||||
export const isTriggerList = (trigger: Trigger): trigger is TriggerList =>
|
export const isTriggerList = (trigger: Trigger): trigger is TriggerList =>
|
||||||
"triggers" in trigger;
|
"triggers" in trigger;
|
||||||
|
|
||||||
|
export interface TriggerDescription {
|
||||||
|
target?: TargetSelector["target"];
|
||||||
|
fields: Record<
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
example?: string | boolean | number;
|
||||||
|
default?: unknown;
|
||||||
|
required?: boolean;
|
||||||
|
selector?: Selector;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TriggerDescriptions = Record<string, TriggerDescription>;
|
||||||
|
|
||||||
|
export const subscribeTriggers = (
|
||||||
|
hass: HomeAssistant,
|
||||||
|
callback: (triggers: TriggerDescriptions) => void
|
||||||
|
) =>
|
||||||
|
hass.connection.subscribeMessage<TriggerDescriptions>(callback, {
|
||||||
|
type: "trigger_platforms/subscribe",
|
||||||
|
});
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ import {
|
|||||||
domainToName,
|
domainToName,
|
||||||
fetchIntegrationManifests,
|
fetchIntegrationManifests,
|
||||||
} from "../../../data/integration";
|
} from "../../../data/integration";
|
||||||
import { TRIGGER_GROUPS, TRIGGER_ICONS } from "../../../data/trigger";
|
import { TRIGGER_GROUPS } from "../../../data/trigger";
|
||||||
import type { HassDialog } from "../../../dialogs/make-dialog-manager";
|
import type { HassDialog } from "../../../dialogs/make-dialog-manager";
|
||||||
import { KeyboardShortcutMixin } from "../../../mixins/keyboard-shortcut-mixin";
|
import { KeyboardShortcutMixin } from "../../../mixins/keyboard-shortcut-mixin";
|
||||||
import { HaFuse } from "../../../resources/fuse";
|
import { HaFuse } from "../../../resources/fuse";
|
||||||
@@ -54,6 +54,7 @@ import { isMac } from "../../../util/is_mac";
|
|||||||
import { showToast } from "../../../util/toast";
|
import { showToast } from "../../../util/toast";
|
||||||
import type { AddAutomationElementDialogParams } from "./show-add-automation-element-dialog";
|
import type { AddAutomationElementDialogParams } from "./show-add-automation-element-dialog";
|
||||||
import { PASTE_VALUE } from "./show-add-automation-element-dialog";
|
import { PASTE_VALUE } from "./show-add-automation-element-dialog";
|
||||||
|
import { TRIGGER_ICONS } from "../../../components/ha-trigger-icon";
|
||||||
|
|
||||||
const TYPES = {
|
const TYPES = {
|
||||||
trigger: { groups: TRIGGER_GROUPS, icons: TRIGGER_ICONS },
|
trigger: { groups: TRIGGER_GROUPS, icons: TRIGGER_ICONS },
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import type HaAutomationConditionEditor from "../action/ha-automation-action-edi
|
|||||||
import { getAutomationActionType } from "../action/ha-automation-action-row";
|
import { getAutomationActionType } from "../action/ha-automation-action-row";
|
||||||
import { getRepeatType } from "../action/types/ha-automation-action-repeat";
|
import { getRepeatType } from "../action/types/ha-automation-action-repeat";
|
||||||
import { overflowStyles, sidebarEditorStyles } from "../styles";
|
import { overflowStyles, sidebarEditorStyles } from "../styles";
|
||||||
import "../trigger/ha-automation-trigger-editor";
|
|
||||||
import "./ha-automation-sidebar-card";
|
import "./ha-automation-sidebar-card";
|
||||||
|
|
||||||
@customElement("ha-automation-sidebar-action")
|
@customElement("ha-automation-sidebar-action")
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import "../../../../components/ha-dialog-header";
|
|||||||
import "../../../../components/ha-icon-button";
|
import "../../../../components/ha-icon-button";
|
||||||
import "../../../../components/ha-md-button-menu";
|
import "../../../../components/ha-md-button-menu";
|
||||||
import "../../../../components/ha-md-divider";
|
import "../../../../components/ha-md-divider";
|
||||||
import "../../../../components/ha-md-menu-item";
|
|
||||||
import type { HomeAssistant } from "../../../../types";
|
import type { HomeAssistant } from "../../../../types";
|
||||||
import "../ha-automation-editor-warning";
|
import "../ha-automation-editor-warning";
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ import {
|
|||||||
} from "@mdi/js";
|
} from "@mdi/js";
|
||||||
import { html, LitElement, nothing } from "lit";
|
import { html, LitElement, nothing } from "lit";
|
||||||
import { customElement, property, query } from "lit/decorators";
|
import { customElement, property, query } from "lit/decorators";
|
||||||
|
import "../../../../components/ha-md-divider";
|
||||||
|
import "../../../../components/ha-md-menu-item";
|
||||||
|
import "../../../../components/ha-svg-icon";
|
||||||
import type { OptionSidebarConfig } from "../../../../data/automation";
|
import type { OptionSidebarConfig } from "../../../../data/automation";
|
||||||
import type { HomeAssistant } from "../../../../types";
|
import type { HomeAssistant } from "../../../../types";
|
||||||
import { isMac } from "../../../../util/is_mac";
|
import { isMac } from "../../../../util/is_mac";
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ import { overflowStyles, sidebarEditorStyles } from "../styles";
|
|||||||
import "../trigger/ha-automation-trigger-editor";
|
import "../trigger/ha-automation-trigger-editor";
|
||||||
import type HaAutomationTriggerEditor from "../trigger/ha-automation-trigger-editor";
|
import type HaAutomationTriggerEditor from "../trigger/ha-automation-trigger-editor";
|
||||||
import "./ha-automation-sidebar-card";
|
import "./ha-automation-sidebar-card";
|
||||||
|
import { computeDomain } from "../../../../common/entity/compute_domain";
|
||||||
|
import { computeObjectId } from "../../../../common/entity/compute_object_id";
|
||||||
|
|
||||||
@customElement("ha-automation-sidebar-trigger")
|
@customElement("ha-automation-sidebar-trigger")
|
||||||
export default class HaAutomationSidebarTrigger extends LitElement {
|
export default class HaAutomationSidebarTrigger extends LitElement {
|
||||||
@@ -68,9 +70,22 @@ export default class HaAutomationSidebarTrigger extends LitElement {
|
|||||||
"ui.panel.config.automation.editor.triggers.trigger"
|
"ui.panel.config.automation.editor.triggers.trigger"
|
||||||
);
|
);
|
||||||
|
|
||||||
const title = this.hass.localize(
|
const domain =
|
||||||
|
"trigger" in this.config.config &&
|
||||||
|
this.config.config.trigger.includes(".")
|
||||||
|
? computeDomain(this.config.config.trigger)
|
||||||
|
: "trigger" in this.config.config && this.config.config.trigger;
|
||||||
|
const triggerName =
|
||||||
|
"trigger" in this.config.config &&
|
||||||
|
this.config.config.trigger.includes(".")
|
||||||
|
? computeObjectId(this.config.config.trigger)
|
||||||
|
: "_";
|
||||||
|
|
||||||
|
const title =
|
||||||
|
this.hass.localize(
|
||||||
`ui.panel.config.automation.editor.triggers.type.${type}.label`
|
`ui.panel.config.automation.editor.triggers.type.${type}.label`
|
||||||
);
|
) ||
|
||||||
|
this.hass.localize(`component.${domain}.triggers.${triggerName}.name`);
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-automation-sidebar-card
|
<ha-automation-sidebar-card
|
||||||
@@ -246,6 +261,7 @@ export default class HaAutomationSidebarTrigger extends LitElement {
|
|||||||
class="sidebar-editor"
|
class="sidebar-editor"
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.trigger=${this.config.config}
|
.trigger=${this.config.config}
|
||||||
|
.description=${this.config.description}
|
||||||
@value-changed=${this._valueChangedSidebar}
|
@value-changed=${this._valueChangedSidebar}
|
||||||
@yaml-changed=${this._yamlChangedSidebar}
|
@yaml-changed=${this._yamlChangedSidebar}
|
||||||
.uiSupported=${this.config.uiSupported}
|
.uiSupported=${this.config.uiSupported}
|
||||||
|
|||||||
@@ -9,10 +9,12 @@ import "../../../../components/ha-yaml-editor";
|
|||||||
import type { HaYamlEditor } from "../../../../components/ha-yaml-editor";
|
import type { HaYamlEditor } from "../../../../components/ha-yaml-editor";
|
||||||
import type { Trigger } from "../../../../data/automation";
|
import type { Trigger } from "../../../../data/automation";
|
||||||
import { migrateAutomationTrigger } from "../../../../data/automation";
|
import { migrateAutomationTrigger } from "../../../../data/automation";
|
||||||
|
import type { TriggerDescription } from "../../../../data/trigger";
|
||||||
import { isTriggerList } from "../../../../data/trigger";
|
import { isTriggerList } from "../../../../data/trigger";
|
||||||
import { haStyle } from "../../../../resources/styles";
|
import { haStyle } from "../../../../resources/styles";
|
||||||
import type { HomeAssistant } from "../../../../types";
|
import type { HomeAssistant } from "../../../../types";
|
||||||
import "../ha-automation-editor-warning";
|
import "../ha-automation-editor-warning";
|
||||||
|
import "./types/ha-automation-trigger-platform";
|
||||||
|
|
||||||
@customElement("ha-automation-trigger-editor")
|
@customElement("ha-automation-trigger-editor")
|
||||||
export default class HaAutomationTriggerEditor extends LitElement {
|
export default class HaAutomationTriggerEditor extends LitElement {
|
||||||
@@ -29,6 +31,8 @@ export default class HaAutomationTriggerEditor extends LitElement {
|
|||||||
|
|
||||||
@property({ type: Boolean, attribute: "sidebar" }) public inSidebar = false;
|
@property({ type: Boolean, attribute: "sidebar" }) public inSidebar = false;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public description?: TriggerDescription;
|
||||||
|
|
||||||
@query("ha-yaml-editor") public yamlEditor?: HaYamlEditor;
|
@query("ha-yaml-editor") public yamlEditor?: HaYamlEditor;
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
@@ -88,7 +92,14 @@ export default class HaAutomationTriggerEditor extends LitElement {
|
|||||||
`
|
`
|
||||||
: nothing}
|
: nothing}
|
||||||
<div @value-changed=${this._onUiChanged}>
|
<div @value-changed=${this._onUiChanged}>
|
||||||
${dynamicElement(`ha-automation-trigger-${type}`, {
|
${this.description
|
||||||
|
? html`<ha-automation-trigger-platform
|
||||||
|
.hass=${this.hass}
|
||||||
|
.trigger=${this.trigger}
|
||||||
|
.description=${this.description}
|
||||||
|
.disabled=${this.disabled}
|
||||||
|
></ha-automation-trigger-platform>`
|
||||||
|
: dynamicElement(`ha-automation-trigger-${type}`, {
|
||||||
hass: this.hass,
|
hass: this.hass,
|
||||||
trigger: this.trigger,
|
trigger: this.trigger,
|
||||||
disabled: this.disabled,
|
disabled: this.disabled,
|
||||||
|
|||||||
@@ -40,9 +40,11 @@ import "../../../../components/ha-md-button-menu";
|
|||||||
import "../../../../components/ha-md-divider";
|
import "../../../../components/ha-md-divider";
|
||||||
import "../../../../components/ha-md-menu-item";
|
import "../../../../components/ha-md-menu-item";
|
||||||
import "../../../../components/ha-svg-icon";
|
import "../../../../components/ha-svg-icon";
|
||||||
|
import { TRIGGER_ICONS } from "../../../../components/ha-trigger-icon";
|
||||||
import type {
|
import type {
|
||||||
AutomationClipboard,
|
AutomationClipboard,
|
||||||
Trigger,
|
Trigger,
|
||||||
|
TriggerList,
|
||||||
TriggerSidebarConfig,
|
TriggerSidebarConfig,
|
||||||
} from "../../../../data/automation";
|
} from "../../../../data/automation";
|
||||||
import { isTrigger, subscribeTrigger } from "../../../../data/automation";
|
import { isTrigger, subscribeTrigger } from "../../../../data/automation";
|
||||||
@@ -50,7 +52,8 @@ import { describeTrigger } from "../../../../data/automation_i18n";
|
|||||||
import { validateConfig } from "../../../../data/config";
|
import { validateConfig } from "../../../../data/config";
|
||||||
import { fullEntitiesContext } from "../../../../data/context";
|
import { fullEntitiesContext } from "../../../../data/context";
|
||||||
import type { EntityRegistryEntry } from "../../../../data/entity_registry";
|
import type { EntityRegistryEntry } from "../../../../data/entity_registry";
|
||||||
import { TRIGGER_ICONS, isTriggerList } from "../../../../data/trigger";
|
import type { TriggerDescriptions } from "../../../../data/trigger";
|
||||||
|
import { isTriggerList } from "../../../../data/trigger";
|
||||||
import {
|
import {
|
||||||
showAlertDialog,
|
showAlertDialog,
|
||||||
showPromptDialog,
|
showPromptDialog,
|
||||||
@@ -72,6 +75,7 @@ import "./types/ha-automation-trigger-list";
|
|||||||
import "./types/ha-automation-trigger-mqtt";
|
import "./types/ha-automation-trigger-mqtt";
|
||||||
import "./types/ha-automation-trigger-numeric_state";
|
import "./types/ha-automation-trigger-numeric_state";
|
||||||
import "./types/ha-automation-trigger-persistent_notification";
|
import "./types/ha-automation-trigger-persistent_notification";
|
||||||
|
import "./types/ha-automation-trigger-platform";
|
||||||
import "./types/ha-automation-trigger-state";
|
import "./types/ha-automation-trigger-state";
|
||||||
import "./types/ha-automation-trigger-sun";
|
import "./types/ha-automation-trigger-sun";
|
||||||
import "./types/ha-automation-trigger-tag";
|
import "./types/ha-automation-trigger-tag";
|
||||||
@@ -137,6 +141,9 @@ export default class HaAutomationTriggerRow extends LitElement {
|
|||||||
|
|
||||||
@state() private _warnings?: string[];
|
@state() private _warnings?: string[];
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
public triggerDescriptions: TriggerDescriptions = {};
|
||||||
|
|
||||||
@property({ type: Boolean }) public narrow = false;
|
@property({ type: Boolean }) public narrow = false;
|
||||||
|
|
||||||
@query("ha-automation-trigger-editor")
|
@query("ha-automation-trigger-editor")
|
||||||
@@ -178,18 +185,24 @@ export default class HaAutomationTriggerRow extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _renderRow() {
|
private _renderRow() {
|
||||||
const type = this._getType(this.trigger);
|
const type = this._getType(this.trigger, this.triggerDescriptions);
|
||||||
|
|
||||||
const supported = this._uiSupported(type);
|
const supported = this._uiSupported(type);
|
||||||
|
|
||||||
const yamlMode = this._yamlMode || !supported;
|
const yamlMode = this._yamlMode || !supported;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-svg-icon
|
${type === "list"
|
||||||
|
? html`<ha-svg-icon
|
||||||
slot="leading-icon"
|
slot="leading-icon"
|
||||||
class="trigger-icon"
|
class="trigger-icon"
|
||||||
.path=${TRIGGER_ICONS[type]}
|
.path=${TRIGGER_ICONS[type]}
|
||||||
></ha-svg-icon>
|
></ha-svg-icon>`
|
||||||
|
: html`<ha-trigger-icon
|
||||||
|
slot="leading-icon"
|
||||||
|
.hass=${this.hass}
|
||||||
|
.trigger=${(this.trigger as Exclude<Trigger, TriggerList>).trigger}
|
||||||
|
></ha-trigger-icon>`}
|
||||||
<h3 slot="header">
|
<h3 slot="header">
|
||||||
${describeTrigger(this.trigger, this.hass, this._entityReg)}
|
${describeTrigger(this.trigger, this.hass, this._entityReg)}
|
||||||
</h3>
|
</h3>
|
||||||
@@ -393,6 +406,9 @@ export default class HaAutomationTriggerRow extends LitElement {
|
|||||||
<ha-automation-trigger-editor
|
<ha-automation-trigger-editor
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.trigger=${this.trigger}
|
.trigger=${this.trigger}
|
||||||
|
.description=${"trigger" in this.trigger
|
||||||
|
? this.triggerDescriptions[this.trigger.trigger]
|
||||||
|
: undefined}
|
||||||
.disabled=${this.disabled}
|
.disabled=${this.disabled}
|
||||||
.yamlMode=${this._yamlMode}
|
.yamlMode=${this._yamlMode}
|
||||||
.uiSupported=${supported}
|
.uiSupported=${supported}
|
||||||
@@ -552,6 +568,7 @@ export default class HaAutomationTriggerRow extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public openSidebar(trigger?: Trigger): void {
|
public openSidebar(trigger?: Trigger): void {
|
||||||
|
trigger = trigger || this.trigger;
|
||||||
fireEvent(this, "open-sidebar", {
|
fireEvent(this, "open-sidebar", {
|
||||||
save: (value) => {
|
save: (value) => {
|
||||||
fireEvent(this, "value-changed", { value });
|
fireEvent(this, "value-changed", { value });
|
||||||
@@ -576,8 +593,14 @@ export default class HaAutomationTriggerRow extends LitElement {
|
|||||||
duplicate: this._duplicateTrigger,
|
duplicate: this._duplicateTrigger,
|
||||||
cut: this._cutTrigger,
|
cut: this._cutTrigger,
|
||||||
insertAfter: this._insertAfter,
|
insertAfter: this._insertAfter,
|
||||||
config: trigger || this.trigger,
|
config: trigger,
|
||||||
uiSupported: this._uiSupported(this._getType(trigger || this.trigger)),
|
uiSupported: this._uiSupported(
|
||||||
|
this._getType(trigger, this.triggerDescriptions)
|
||||||
|
),
|
||||||
|
description:
|
||||||
|
"trigger" in trigger
|
||||||
|
? this.triggerDescriptions[trigger.trigger]
|
||||||
|
: undefined,
|
||||||
yamlMode: this._yamlMode,
|
yamlMode: this._yamlMode,
|
||||||
} satisfies TriggerSidebarConfig);
|
} satisfies TriggerSidebarConfig);
|
||||||
this._selected = true;
|
this._selected = true;
|
||||||
@@ -759,8 +782,18 @@ export default class HaAutomationTriggerRow extends LitElement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getType = memoizeOne((trigger: Trigger) =>
|
private _getType = memoizeOne(
|
||||||
isTriggerList(trigger) ? "list" : trigger.trigger
|
(trigger: Trigger, triggerDescriptions: TriggerDescriptions) => {
|
||||||
|
if (isTriggerList(trigger)) {
|
||||||
|
return "list";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trigger.trigger in triggerDescriptions) {
|
||||||
|
return "platform";
|
||||||
|
}
|
||||||
|
|
||||||
|
return trigger.trigger;
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
private _uiSupported = memoizeOne(
|
private _uiSupported = memoizeOne(
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import type { PropertyValues } from "lit";
|
|||||||
import { html, LitElement, nothing } from "lit";
|
import { html, LitElement, nothing } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { repeat } from "lit/directives/repeat";
|
import { repeat } from "lit/directives/repeat";
|
||||||
|
import { ensureArray } from "../../../../common/array/ensure-array";
|
||||||
import { storage } from "../../../../common/decorators/storage";
|
import { storage } from "../../../../common/decorators/storage";
|
||||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
import { stopPropagation } from "../../../../common/dom/stop_propagation";
|
import { stopPropagation } from "../../../../common/dom/stop_propagation";
|
||||||
@@ -17,7 +18,9 @@ import type {
|
|||||||
Trigger,
|
Trigger,
|
||||||
TriggerList,
|
TriggerList,
|
||||||
} from "../../../../data/automation";
|
} from "../../../../data/automation";
|
||||||
import { isTriggerList } from "../../../../data/trigger";
|
import type { TriggerDescriptions } from "../../../../data/trigger";
|
||||||
|
import { isTriggerList, subscribeTriggers } from "../../../../data/trigger";
|
||||||
|
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
||||||
import type { HomeAssistant } from "../../../../types";
|
import type { HomeAssistant } from "../../../../types";
|
||||||
import {
|
import {
|
||||||
PASTE_VALUE,
|
PASTE_VALUE,
|
||||||
@@ -26,10 +29,9 @@ import {
|
|||||||
import { automationRowsStyles } from "../styles";
|
import { automationRowsStyles } from "../styles";
|
||||||
import "./ha-automation-trigger-row";
|
import "./ha-automation-trigger-row";
|
||||||
import type HaAutomationTriggerRow from "./ha-automation-trigger-row";
|
import type HaAutomationTriggerRow from "./ha-automation-trigger-row";
|
||||||
import { ensureArray } from "../../../../common/array/ensure-array";
|
|
||||||
|
|
||||||
@customElement("ha-automation-trigger")
|
@customElement("ha-automation-trigger")
|
||||||
export default class HaAutomationTrigger extends LitElement {
|
export default class HaAutomationTrigger extends SubscribeMixin(LitElement) {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public triggers!: Trigger[];
|
@property({ attribute: false }) public triggers!: Trigger[];
|
||||||
@@ -62,6 +64,23 @@ export default class HaAutomationTrigger extends LitElement {
|
|||||||
|
|
||||||
private _triggerKeys = new WeakMap<Trigger, string>();
|
private _triggerKeys = new WeakMap<Trigger, string>();
|
||||||
|
|
||||||
|
@state() private _triggerDescriptions: TriggerDescriptions = {};
|
||||||
|
|
||||||
|
protected hassSubscribe() {
|
||||||
|
return [
|
||||||
|
subscribeTriggers(this.hass, (triggers) => this._addTriggers(triggers)),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private _addTriggers(triggers: TriggerDescriptions) {
|
||||||
|
this._triggerDescriptions = { ...this._triggerDescriptions, ...triggers };
|
||||||
|
}
|
||||||
|
|
||||||
|
protected firstUpdated(changedProps: PropertyValues) {
|
||||||
|
super.firstUpdated(changedProps);
|
||||||
|
this.hass.loadBackendTranslation("triggers");
|
||||||
|
}
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
return html`
|
return html`
|
||||||
<ha-sortable
|
<ha-sortable
|
||||||
@@ -85,6 +104,7 @@ export default class HaAutomationTrigger extends LitElement {
|
|||||||
.first=${idx === 0}
|
.first=${idx === 0}
|
||||||
.last=${idx === this.triggers.length - 1}
|
.last=${idx === this.triggers.length - 1}
|
||||||
.trigger=${trg}
|
.trigger=${trg}
|
||||||
|
.triggerDescriptions=${this._triggerDescriptions}
|
||||||
@duplicate=${this._duplicateTrigger}
|
@duplicate=${this._duplicateTrigger}
|
||||||
@insert-after=${this._insertAfter}
|
@insert-after=${this._insertAfter}
|
||||||
@move-down=${this._moveDown}
|
@move-down=${this._moveDown}
|
||||||
|
|||||||
@@ -0,0 +1,406 @@
|
|||||||
|
import { mdiHelpCircle } from "@mdi/js";
|
||||||
|
import type { PropertyValues } from "lit";
|
||||||
|
import { css, html, LitElement, nothing } from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
|
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||||
|
import { computeDomain } from "../../../../../common/entity/compute_domain";
|
||||||
|
import { computeObjectId } from "../../../../../common/entity/compute_object_id";
|
||||||
|
import "../../../../../components/ha-checkbox";
|
||||||
|
import "../../../../../components/ha-selector/ha-selector";
|
||||||
|
import "../../../../../components/ha-settings-row";
|
||||||
|
import "../../../../../components/ha-textfield";
|
||||||
|
import "../../../../../components/ha-yaml-editor";
|
||||||
|
import "../../../../../components/user/ha-users-picker";
|
||||||
|
import type { PlatformTrigger } from "../../../../../data/automation";
|
||||||
|
import type { IntegrationManifest } from "../../../../../data/integration";
|
||||||
|
import { fetchIntegrationManifest } from "../../../../../data/integration";
|
||||||
|
import type { TargetSelector } from "../../../../../data/selector";
|
||||||
|
import type { TriggerDescription } from "../../../../../data/trigger";
|
||||||
|
import type { HomeAssistant } from "../../../../../types";
|
||||||
|
import { documentationUrl } from "../../../../../util/documentation-url";
|
||||||
|
|
||||||
|
const showOptionalToggle = (field) =>
|
||||||
|
field.selector &&
|
||||||
|
!field.required &&
|
||||||
|
!("boolean" in field.selector && field.default);
|
||||||
|
|
||||||
|
@customElement("ha-automation-trigger-platform")
|
||||||
|
export class HaPlatformTrigger extends LitElement {
|
||||||
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public trigger!: PlatformTrigger;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public description?: TriggerDescription;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public disabled = false;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public narrow = true;
|
||||||
|
|
||||||
|
@state() private _checkedKeys = new Set();
|
||||||
|
|
||||||
|
@state() private _manifest?: IntegrationManifest;
|
||||||
|
|
||||||
|
public static get defaultConfig(): PlatformTrigger {
|
||||||
|
return { trigger: "" };
|
||||||
|
}
|
||||||
|
|
||||||
|
protected willUpdate(changedProperties: PropertyValues<this>) {
|
||||||
|
super.willUpdate(changedProperties);
|
||||||
|
if (!this.hasUpdated) {
|
||||||
|
this.hass.loadBackendTranslation("triggers");
|
||||||
|
this.hass.loadBackendTranslation("selector");
|
||||||
|
}
|
||||||
|
if (!changedProperties.has("trigger")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const oldValue = changedProperties.get("trigger") as
|
||||||
|
| undefined
|
||||||
|
| this["trigger"];
|
||||||
|
|
||||||
|
// Fetch the manifest if we have a trigger selected and the trigger domain changed.
|
||||||
|
// If no trigger is selected, clear the manifest.
|
||||||
|
if (this.trigger?.trigger) {
|
||||||
|
const domain = this.trigger.trigger.includes(".")
|
||||||
|
? computeDomain(this.trigger.trigger)
|
||||||
|
: this.trigger.trigger;
|
||||||
|
|
||||||
|
const oldDomain = oldValue?.trigger.includes(".")
|
||||||
|
? computeDomain(oldValue.trigger)
|
||||||
|
: oldValue?.trigger;
|
||||||
|
|
||||||
|
if (domain !== oldDomain) {
|
||||||
|
this._fetchManifest(domain);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this._manifest = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
const domain = this.trigger.trigger.includes(".")
|
||||||
|
? computeDomain(this.trigger.trigger)
|
||||||
|
: this.trigger.trigger;
|
||||||
|
const triggerName = this.trigger.trigger.includes(".")
|
||||||
|
? computeObjectId(this.trigger.trigger)
|
||||||
|
: "_";
|
||||||
|
|
||||||
|
const description = this.hass.localize(
|
||||||
|
`component.${domain}.triggers.${triggerName}.description`
|
||||||
|
);
|
||||||
|
|
||||||
|
const triggerDesc = this.description;
|
||||||
|
|
||||||
|
const shouldRenderDataYaml = !triggerDesc?.fields;
|
||||||
|
|
||||||
|
const hasOptional = Boolean(
|
||||||
|
triggerDesc?.fields &&
|
||||||
|
Object.values(triggerDesc.fields).some((field) =>
|
||||||
|
showOptionalToggle(field)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<div class="description">
|
||||||
|
${description ? html`<p>${description}</p>` : ""}
|
||||||
|
${this._manifest
|
||||||
|
? html` <a
|
||||||
|
href=${this._manifest.is_built_in
|
||||||
|
? documentationUrl(
|
||||||
|
this.hass,
|
||||||
|
`/integrations/${this._manifest.domain}`
|
||||||
|
)
|
||||||
|
: this._manifest.documentation}
|
||||||
|
title=${this.hass.localize(
|
||||||
|
"ui.components.service-control.integration_doc"
|
||||||
|
)}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
<ha-icon-button
|
||||||
|
.path=${mdiHelpCircle}
|
||||||
|
class="help-icon"
|
||||||
|
></ha-icon-button>
|
||||||
|
</a>`
|
||||||
|
: nothing}
|
||||||
|
</div>
|
||||||
|
${triggerDesc && "target" in triggerDesc
|
||||||
|
? html`<ha-settings-row .narrow=${this.narrow}>
|
||||||
|
${hasOptional
|
||||||
|
? html`<div slot="prefix" class="checkbox-spacer"></div>`
|
||||||
|
: ""}
|
||||||
|
<span slot="heading"
|
||||||
|
>${this.hass.localize(
|
||||||
|
"ui.components.service-control.target"
|
||||||
|
)}</span
|
||||||
|
>
|
||||||
|
<span slot="description"
|
||||||
|
>${this.hass.localize(
|
||||||
|
"ui.components.service-control.target_secondary"
|
||||||
|
)}</span
|
||||||
|
><ha-selector
|
||||||
|
.hass=${this.hass}
|
||||||
|
.selector=${this._targetSelector(triggerDesc.target)}
|
||||||
|
.disabled=${this.disabled}
|
||||||
|
@value-changed=${this._targetChanged}
|
||||||
|
.value=${this.trigger?.target}
|
||||||
|
></ha-selector
|
||||||
|
></ha-settings-row>`
|
||||||
|
: nothing}
|
||||||
|
${shouldRenderDataYaml
|
||||||
|
? html`<ha-yaml-editor
|
||||||
|
.hass=${this.hass}
|
||||||
|
.label=${this.hass.localize(
|
||||||
|
"ui.components.service-control.action_data"
|
||||||
|
)}
|
||||||
|
.name=${"data"}
|
||||||
|
.readOnly=${this.disabled}
|
||||||
|
.defaultValue=${this.trigger?.options}
|
||||||
|
@value-changed=${this._dataChanged}
|
||||||
|
></ha-yaml-editor>`
|
||||||
|
: Object.entries(triggerDesc.fields).map(([fieldName, dataField]) =>
|
||||||
|
this._renderField(
|
||||||
|
fieldName,
|
||||||
|
dataField,
|
||||||
|
hasOptional,
|
||||||
|
domain,
|
||||||
|
triggerName
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _targetSelector = memoizeOne(
|
||||||
|
(targetSelector: TargetSelector["target"] | null | undefined) =>
|
||||||
|
targetSelector ? { target: { ...targetSelector } } : { target: {} }
|
||||||
|
);
|
||||||
|
|
||||||
|
private _renderField = (
|
||||||
|
fieldName: string,
|
||||||
|
dataField: TriggerDescription["fields"][string],
|
||||||
|
hasOptional: boolean,
|
||||||
|
domain: string | undefined,
|
||||||
|
triggerName: string | undefined
|
||||||
|
) => {
|
||||||
|
const selector = dataField?.selector ?? { text: null };
|
||||||
|
|
||||||
|
const showOptional = showOptionalToggle(dataField);
|
||||||
|
|
||||||
|
return dataField.selector
|
||||||
|
? html`<ha-settings-row .narrow=${this.narrow}>
|
||||||
|
${!showOptional
|
||||||
|
? hasOptional
|
||||||
|
? html`<div slot="prefix" class="checkbox-spacer"></div>`
|
||||||
|
: ""
|
||||||
|
: html`<ha-checkbox
|
||||||
|
.key=${fieldName}
|
||||||
|
.checked=${this._checkedKeys.has(fieldName) ||
|
||||||
|
(this.trigger?.options &&
|
||||||
|
this.trigger.options[fieldName] !== undefined)}
|
||||||
|
.disabled=${this.disabled}
|
||||||
|
@change=${this._checkboxChanged}
|
||||||
|
slot="prefix"
|
||||||
|
></ha-checkbox>`}
|
||||||
|
<span slot="heading"
|
||||||
|
>${this.hass.localize(
|
||||||
|
`component.${domain}.triggers.${triggerName}.fields.${fieldName}.name`
|
||||||
|
) || triggerName}</span
|
||||||
|
>
|
||||||
|
<span slot="description"
|
||||||
|
>${this.hass.localize(
|
||||||
|
`component.${domain}.triggers.${triggerName}.fields.${fieldName}.description`
|
||||||
|
)}</span
|
||||||
|
>
|
||||||
|
<ha-selector
|
||||||
|
.disabled=${this.disabled ||
|
||||||
|
(showOptional &&
|
||||||
|
!this._checkedKeys.has(fieldName) &&
|
||||||
|
(!this.trigger?.options ||
|
||||||
|
this.trigger.options[fieldName] === undefined))}
|
||||||
|
.hass=${this.hass}
|
||||||
|
.selector=${selector}
|
||||||
|
.key=${fieldName}
|
||||||
|
@value-changed=${this._dataChanged}
|
||||||
|
.value=${this.trigger?.options
|
||||||
|
? this.trigger.options[fieldName]
|
||||||
|
: undefined}
|
||||||
|
.placeholder=${dataField.default}
|
||||||
|
.localizeValue=${this._localizeValueCallback}
|
||||||
|
></ha-selector>
|
||||||
|
</ha-settings-row>`
|
||||||
|
: "";
|
||||||
|
};
|
||||||
|
|
||||||
|
private _dataChanged(ev: CustomEvent) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
if (ev.detail.isValid === false) {
|
||||||
|
// Don't clear an object selector that returns invalid YAML
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const key = (ev.currentTarget as any).key;
|
||||||
|
const value = ev.detail.value;
|
||||||
|
if (
|
||||||
|
this.trigger?.options?.[key] === value ||
|
||||||
|
((!this.trigger?.options || !(key in this.trigger.options)) &&
|
||||||
|
(value === "" || value === undefined))
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const options = { ...this.trigger?.options, [key]: value };
|
||||||
|
|
||||||
|
if (
|
||||||
|
value === "" ||
|
||||||
|
value === undefined ||
|
||||||
|
(typeof value === "object" && !Object.keys(value).length)
|
||||||
|
) {
|
||||||
|
delete options[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
fireEvent(this, "value-changed", {
|
||||||
|
value: {
|
||||||
|
...this.trigger,
|
||||||
|
options,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _targetChanged(ev: CustomEvent): void {
|
||||||
|
ev.stopPropagation();
|
||||||
|
fireEvent(this, "value-changed", {
|
||||||
|
value: {
|
||||||
|
...this.trigger,
|
||||||
|
target: ev.detail.value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _checkboxChanged(ev) {
|
||||||
|
const checked = ev.currentTarget.checked;
|
||||||
|
const key = ev.currentTarget.key;
|
||||||
|
let options;
|
||||||
|
|
||||||
|
if (checked) {
|
||||||
|
this._checkedKeys.add(key);
|
||||||
|
const field =
|
||||||
|
this.description &&
|
||||||
|
Object.entries(this.description).find(([k, _value]) => k === key)?.[1];
|
||||||
|
let defaultValue = field?.default;
|
||||||
|
|
||||||
|
if (
|
||||||
|
defaultValue == null &&
|
||||||
|
field?.selector &&
|
||||||
|
"constant" in field.selector
|
||||||
|
) {
|
||||||
|
defaultValue = field.selector.constant?.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
defaultValue == null &&
|
||||||
|
field?.selector &&
|
||||||
|
"boolean" in field.selector
|
||||||
|
) {
|
||||||
|
defaultValue = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (defaultValue != null) {
|
||||||
|
options = {
|
||||||
|
...this.trigger?.options,
|
||||||
|
[key]: defaultValue,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this._checkedKeys.delete(key);
|
||||||
|
options = { ...this.trigger?.options };
|
||||||
|
delete options[key];
|
||||||
|
}
|
||||||
|
if (options) {
|
||||||
|
fireEvent(this, "value-changed", {
|
||||||
|
value: {
|
||||||
|
...this.trigger,
|
||||||
|
options,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.requestUpdate("_checkedKeys");
|
||||||
|
}
|
||||||
|
|
||||||
|
private _localizeValueCallback = (key: string) => {
|
||||||
|
if (!this.trigger?.trigger) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return this.hass.localize(
|
||||||
|
`component.${computeDomain(this.trigger.trigger)}.selector.${key}`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
private async _fetchManifest(integration: string) {
|
||||||
|
this._manifest = undefined;
|
||||||
|
try {
|
||||||
|
this._manifest = await fetchIntegrationManifest(this.hass, integration);
|
||||||
|
} catch (_err: any) {
|
||||||
|
// Ignore if loading manifest fails. Probably bad JSON in manifest
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static styles = css`
|
||||||
|
ha-settings-row {
|
||||||
|
padding: var(--service-control-padding, 0 16px);
|
||||||
|
}
|
||||||
|
ha-settings-row[narrow] {
|
||||||
|
padding-bottom: 8px;
|
||||||
|
}
|
||||||
|
ha-settings-row {
|
||||||
|
--settings-row-content-width: 100%;
|
||||||
|
--settings-row-prefix-display: contents;
|
||||||
|
border-top: var(
|
||||||
|
--service-control-items-border-top,
|
||||||
|
1px solid var(--divider-color)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ha-service-picker,
|
||||||
|
ha-entity-picker,
|
||||||
|
ha-yaml-editor {
|
||||||
|
display: block;
|
||||||
|
margin: var(--service-control-padding, 0 16px);
|
||||||
|
}
|
||||||
|
ha-yaml-editor {
|
||||||
|
padding: 16px 0;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
margin: var(--service-control-padding, 0 16px);
|
||||||
|
padding: 16px 0;
|
||||||
|
}
|
||||||
|
:host([hide-picker]) p {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
.checkbox-spacer {
|
||||||
|
width: 32px;
|
||||||
|
}
|
||||||
|
ha-checkbox {
|
||||||
|
margin-left: -16px;
|
||||||
|
margin-inline-start: -16px;
|
||||||
|
margin-inline-end: initial;
|
||||||
|
}
|
||||||
|
.help-icon {
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
}
|
||||||
|
.description {
|
||||||
|
justify-content: space-between;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding-right: 2px;
|
||||||
|
padding-inline-end: 2px;
|
||||||
|
padding-inline-start: initial;
|
||||||
|
}
|
||||||
|
.description p {
|
||||||
|
direction: ltr;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-automation-trigger-platform": HaPlatformTrigger;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,14 @@
|
|||||||
import { mdiCalendarSync, mdiGestureTap } from "@mdi/js";
|
import { mdiCalendarSync, mdiClose, mdiGestureTap } from "@mdi/js";
|
||||||
import type { CSSResultGroup } from "lit";
|
import type { CSSResultGroup } from "lit";
|
||||||
import { LitElement, css, html, nothing } from "lit";
|
import { LitElement, css, html, nothing } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, query, state } from "lit/decorators";
|
||||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
|
import "../../../../components/ha-dialog-header";
|
||||||
|
import "../../../../components/ha-icon-button";
|
||||||
import "../../../../components/ha-icon-next";
|
import "../../../../components/ha-icon-next";
|
||||||
|
import "../../../../components/ha-md-dialog";
|
||||||
|
import type { HaMdDialog } from "../../../../components/ha-md-dialog";
|
||||||
import "../../../../components/ha-md-list";
|
import "../../../../components/ha-md-list";
|
||||||
import "../../../../components/ha-wa-dialog";
|
|
||||||
import "../../../../components/ha-md-list-item";
|
import "../../../../components/ha-md-list-item";
|
||||||
import "../../../../components/ha-svg-icon";
|
import "../../../../components/ha-svg-icon";
|
||||||
import type { HassDialog } from "../../../../dialogs/make-dialog-manager";
|
import type { HassDialog } from "../../../../dialogs/make-dialog-manager";
|
||||||
@@ -21,38 +24,48 @@ class DialogNewBackup extends LitElement implements HassDialog {
|
|||||||
|
|
||||||
@state() private _params?: NewBackupDialogParams;
|
@state() private _params?: NewBackupDialogParams;
|
||||||
|
|
||||||
|
@query("ha-md-dialog") private _dialog?: HaMdDialog;
|
||||||
|
|
||||||
public showDialog(params: NewBackupDialogParams): void {
|
public showDialog(params: NewBackupDialogParams): void {
|
||||||
this._opened = true;
|
this._opened = true;
|
||||||
this._params = params;
|
this._params = params;
|
||||||
}
|
}
|
||||||
|
|
||||||
public closeDialog() {
|
public closeDialog() {
|
||||||
this._opened = false;
|
this._dialog?.close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _dialogClosed() {
|
private _dialogClosed() {
|
||||||
if (this._params?.cancel) {
|
if (this._params!.cancel) {
|
||||||
this._params.cancel();
|
this._params!.cancel();
|
||||||
}
|
}
|
||||||
this._params = undefined;
|
if (this._opened) {
|
||||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||||
}
|
}
|
||||||
|
this._opened = false;
|
||||||
|
this._params = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
if (!this._params) {
|
if (!this._opened || !this._params) {
|
||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-wa-dialog
|
<ha-md-dialog open @closed=${this._dialogClosed}>
|
||||||
.hass=${this.hass}
|
<ha-dialog-header slot="headline">
|
||||||
.open=${this._opened}
|
<ha-icon-button
|
||||||
header-title=${this.hass.localize(
|
slot="navigationIcon"
|
||||||
"ui.panel.config.backup.dialogs.new.title"
|
@click=${this.closeDialog}
|
||||||
)}
|
.label=${this.hass.localize("ui.common.close")}
|
||||||
@closed=${this._dialogClosed}
|
.path=${mdiClose}
|
||||||
>
|
></ha-icon-button>
|
||||||
|
<span slot="title">
|
||||||
|
${this.hass.localize("ui.panel.config.backup.dialogs.new.title")}
|
||||||
|
</span>
|
||||||
|
</ha-dialog-header>
|
||||||
|
<div slot="content">
|
||||||
<ha-md-list
|
<ha-md-list
|
||||||
innerRole="listbox"
|
innerRole="listbox"
|
||||||
itemRoles="option"
|
itemRoles="option"
|
||||||
@@ -60,6 +73,7 @@ class DialogNewBackup extends LitElement implements HassDialog {
|
|||||||
"ui.panel.config.backup.dialogs.new.options"
|
"ui.panel.config.backup.dialogs.new.options"
|
||||||
)}
|
)}
|
||||||
rootTabbable
|
rootTabbable
|
||||||
|
dialogInitialFocus
|
||||||
>
|
>
|
||||||
<ha-md-list-item
|
<ha-md-list-item
|
||||||
@click=${this._automatic}
|
@click=${this._automatic}
|
||||||
@@ -94,7 +108,8 @@ class DialogNewBackup extends LitElement implements HassDialog {
|
|||||||
<ha-icon-next slot="end"></ha-icon-next>
|
<ha-icon-next slot="end"></ha-icon-next>
|
||||||
</ha-md-list-item>
|
</ha-md-list-item>
|
||||||
</ha-md-list>
|
</ha-md-list>
|
||||||
</ha-wa-dialog>
|
</div>
|
||||||
|
</ha-md-dialog>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,13 +128,24 @@ class DialogNewBackup extends LitElement implements HassDialog {
|
|||||||
haStyle,
|
haStyle,
|
||||||
haStyleDialog,
|
haStyleDialog,
|
||||||
css`
|
css`
|
||||||
ha-wa-dialog {
|
ha-md-dialog {
|
||||||
--dialog-content-padding: 0;
|
--dialog-content-padding: 0;
|
||||||
|
max-width: 500px;
|
||||||
|
}
|
||||||
|
@media all and (max-width: 450px), all and (max-height: 500px) {
|
||||||
|
ha-md-dialog {
|
||||||
|
max-width: none;
|
||||||
|
}
|
||||||
|
div[slot="content"] {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ha-md-list {
|
ha-md-list {
|
||||||
background: none;
|
background: none;
|
||||||
}
|
}
|
||||||
|
ha-md-list-item {
|
||||||
|
}
|
||||||
ha-icon-next {
|
ha-icon-next {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,11 +20,6 @@ export class HuiDialogWebBrowserPlayMedia extends LitElement {
|
|||||||
|
|
||||||
public closeDialog() {
|
public closeDialog() {
|
||||||
this._params = undefined;
|
this._params = undefined;
|
||||||
const img = this.renderRoot.querySelector("img");
|
|
||||||
if (img) {
|
|
||||||
// Unload streaming images so the connection can be closed
|
|
||||||
img.src = "";
|
|
||||||
}
|
|
||||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user