mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-24 09:46:36 +00:00
Move condition editor into its own file (#18340)
This commit is contained in:
parent
aeaf091b50
commit
4354ad3807
@ -6,6 +6,7 @@ import { customElement, property, state } from "lit/decorators";
|
||||
import { dynamicElement } from "../../../../common/dom/dynamic-element-directive";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { stopPropagation } from "../../../../common/dom/stop_propagation";
|
||||
import { handleStructError } from "../../../../common/structs/handle-errors";
|
||||
import "../../../../components/ha-button-menu";
|
||||
import "../../../../components/ha-icon-button";
|
||||
import "../../../../components/ha-list-item";
|
||||
@ -14,15 +15,14 @@ import "../../../../components/ha-yaml-editor";
|
||||
import { haStyle } from "../../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import { ICON_CONDITION } from "../../common/icon-condition";
|
||||
import { Condition } from "../../common/validate-condition";
|
||||
import { Condition, LegacyCondition } from "../../common/validate-condition";
|
||||
import type { LovelaceConditionEditorConstructor } from "./types";
|
||||
import { handleStructError } from "../../../../common/structs/handle-errors";
|
||||
|
||||
@customElement("ha-card-condition-editor")
|
||||
export default class HaCardConditionEditor extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) condition!: Condition;
|
||||
@property({ attribute: false }) condition!: Condition | LegacyCondition;
|
||||
|
||||
@state() public _yamlMode = false;
|
||||
|
||||
@ -30,20 +30,25 @@ export default class HaCardConditionEditor extends LitElement {
|
||||
|
||||
@state() public _uiWarnings: string[] = [];
|
||||
|
||||
private get _editor() {
|
||||
const element = customElements.get(
|
||||
`ha-card-condition-${this.condition.condition}`
|
||||
) as LovelaceConditionEditorConstructor | undefined;
|
||||
@state() _condition?: Condition;
|
||||
|
||||
return element;
|
||||
private get _editor() {
|
||||
if (!this._condition) return undefined;
|
||||
return customElements.get(
|
||||
`ha-card-condition-${this._condition.condition}`
|
||||
) as LovelaceConditionEditorConstructor | undefined;
|
||||
}
|
||||
|
||||
protected willUpdate(changedProperties: PropertyValues): void {
|
||||
if (changedProperties.has("condition")) {
|
||||
this._condition = {
|
||||
condition: "state",
|
||||
...this.condition,
|
||||
};
|
||||
const validator = this._editor?.validateUIConfig;
|
||||
if (validator) {
|
||||
try {
|
||||
validator(this.condition, this.hass);
|
||||
validator(this._condition, this.hass);
|
||||
this._uiAvailable = true;
|
||||
this._uiWarnings = [];
|
||||
} catch (err) {
|
||||
@ -65,7 +70,9 @@ export default class HaCardConditionEditor extends LitElement {
|
||||
}
|
||||
|
||||
protected render() {
|
||||
const condition = this.condition;
|
||||
const condition = this._condition;
|
||||
|
||||
if (!condition) return nothing;
|
||||
|
||||
return html`
|
||||
<div class="header">
|
||||
@ -75,7 +82,7 @@ export default class HaCardConditionEditor extends LitElement {
|
||||
></ha-svg-icon>
|
||||
<span class="title">
|
||||
${this.hass.localize(
|
||||
`ui.panel.lovelace.editor.card.conditional.condition.${condition.condition}.label`
|
||||
`ui.panel.lovelace.editor.condition-editor.condition.${condition.condition}.label`
|
||||
) || condition.condition}
|
||||
</span>
|
||||
<ha-button-menu
|
||||
|
@ -0,0 +1,144 @@
|
||||
import { mdiPlus } from "@mdi/js";
|
||||
import { CSSResultGroup, LitElement, css, html } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { stopPropagation } from "../../../../common/dom/stop_propagation";
|
||||
import "../../../../components/ha-button";
|
||||
import "../../../../components/ha-list-item";
|
||||
import type { HaSelect } from "../../../../components/ha-select";
|
||||
import "../../../../components/ha-svg-icon";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import { ICON_CONDITION } from "../../common/icon-condition";
|
||||
import { Condition, LegacyCondition } from "../../common/validate-condition";
|
||||
import "./ha-card-condition-editor";
|
||||
import { LovelaceConditionEditorConstructor } from "./types";
|
||||
import "./types/ha-card-condition-screen";
|
||||
import "./types/ha-card-condition-state";
|
||||
|
||||
const UI_CONDITION = [
|
||||
"state",
|
||||
"screen",
|
||||
] as const satisfies readonly Condition["condition"][];
|
||||
|
||||
@customElement("ha-card-conditions-editor")
|
||||
export class HaCardConditionsEditor extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public conditions!: (
|
||||
| Condition
|
||||
| LegacyCondition
|
||||
)[];
|
||||
|
||||
protected render() {
|
||||
return html`
|
||||
<div class="conditions">
|
||||
${this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.condition-editor.explanation"
|
||||
)}
|
||||
${this.conditions.map(
|
||||
(cond, idx) => html`
|
||||
<div class="condition">
|
||||
<ha-card-condition-editor
|
||||
.index=${idx}
|
||||
@value-changed=${this._conditionChanged}
|
||||
.hass=${this.hass}
|
||||
.condition=${cond}
|
||||
></ha-card-condition-editor>
|
||||
</div>
|
||||
`
|
||||
)}
|
||||
<div>
|
||||
<ha-button-menu
|
||||
@action=${this._addCondition}
|
||||
fixed
|
||||
@closed=${stopPropagation}
|
||||
>
|
||||
<ha-button
|
||||
slot="trigger"
|
||||
outlined
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.lovelace.editor.condition-editor.add"
|
||||
)}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiPlus} slot="icon"></ha-svg-icon>
|
||||
</ha-button>
|
||||
${UI_CONDITION.map(
|
||||
(condition) => html`
|
||||
<ha-list-item .value=${condition} graphic="icon">
|
||||
${this.hass!.localize(
|
||||
`ui.panel.lovelace.editor.condition-editor.condition.${condition}.label`
|
||||
) || condition}
|
||||
<ha-svg-icon
|
||||
slot="graphic"
|
||||
.path=${ICON_CONDITION[condition]}
|
||||
></ha-svg-icon>
|
||||
</ha-list-item>
|
||||
`
|
||||
)}
|
||||
</ha-button-menu>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private _addCondition(ev: CustomEvent): void {
|
||||
const condition = (ev.currentTarget as HaSelect).items[ev.detail.index]
|
||||
.value as Condition["condition"];
|
||||
const conditions = [...this.conditions];
|
||||
|
||||
const elClass = customElements.get(`ha-card-condition-${condition}`) as
|
||||
| LovelaceConditionEditorConstructor
|
||||
| undefined;
|
||||
|
||||
conditions.push(
|
||||
elClass?.defaultConfig
|
||||
? { ...elClass.defaultConfig }
|
||||
: { condition: condition }
|
||||
);
|
||||
fireEvent(this, "value-changed", { value: conditions });
|
||||
}
|
||||
|
||||
private _conditionChanged(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
const conditions = [...this.conditions];
|
||||
const newValue = ev.detail.value;
|
||||
const index = (ev.target as any).index;
|
||||
|
||||
if (newValue === null) {
|
||||
conditions.splice(index, 1);
|
||||
} else {
|
||||
conditions[index] = newValue;
|
||||
}
|
||||
|
||||
fireEvent(this, "value-changed", { value: conditions });
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
css`
|
||||
mwc-tab-bar {
|
||||
border-bottom: 1px solid var(--divider-color);
|
||||
}
|
||||
.conditions {
|
||||
margin-top: 8px;
|
||||
}
|
||||
.condition {
|
||||
margin-top: 8px;
|
||||
border: 1px solid var(--divider-color);
|
||||
}
|
||||
.condition .content {
|
||||
padding: 12px;
|
||||
}
|
||||
ha-button-menu {
|
||||
margin-top: 12px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-card-conditions-editor": HaCardConditionsEditor;
|
||||
}
|
||||
}
|
@ -129,11 +129,11 @@ export class HaCardConditionScreen extends LitElement {
|
||||
return {
|
||||
value: b,
|
||||
label: `${localize(
|
||||
`ui.panel.lovelace.editor.card.conditional.condition.screen.breakpoints_list.${b}`
|
||||
`ui.panel.lovelace.editor.condition-editor.condition.screen.breakpoints_list.${b}`
|
||||
)}${
|
||||
value
|
||||
? ` (${localize(
|
||||
`ui.panel.lovelace.editor.card.conditional.condition.screen.min`,
|
||||
`ui.panel.lovelace.editor.condition-editor.condition.screen.min`,
|
||||
{ size: value }
|
||||
)})`
|
||||
: ""
|
||||
@ -188,7 +188,7 @@ export class HaCardConditionScreen extends LitElement {
|
||||
switch (schema.name) {
|
||||
case "breakpoints":
|
||||
return this.hass.localize(
|
||||
`ui.panel.lovelace.editor.card.conditional.condition.screen.${schema.name}`
|
||||
`ui.panel.lovelace.editor.condition-editor.condition.screen.${schema.name}`
|
||||
);
|
||||
default:
|
||||
return "";
|
||||
|
@ -61,19 +61,20 @@ export class HaCardConditionState extends LitElement {
|
||||
schema: [
|
||||
{
|
||||
name: "invert",
|
||||
required: true,
|
||||
selector: {
|
||||
select: {
|
||||
mode: "dropdown",
|
||||
options: [
|
||||
{
|
||||
label: localize(
|
||||
"ui.panel.lovelace.editor.card.conditional.state_equal"
|
||||
"ui.panel.lovelace.editor.condition-editor.condition.state.state_equal"
|
||||
),
|
||||
value: "false",
|
||||
},
|
||||
{
|
||||
label: localize(
|
||||
"ui.panel.lovelace.editor.card.conditional.state_not_equal"
|
||||
"ui.panel.lovelace.editor.condition-editor.condition.state.state_not_equal"
|
||||
),
|
||||
value: "true",
|
||||
},
|
||||
@ -148,7 +149,7 @@ export class HaCardConditionState extends LitElement {
|
||||
return `${this.hass.localize(
|
||||
"ui.components.entity.entity-state-picker.state"
|
||||
)} (${this.hass.localize(
|
||||
"ui.panel.lovelace.editor.card.conditional.current_state"
|
||||
"ui.panel.lovelace.editor.condition-editor.condition.state.current_state"
|
||||
)}: ${this.hass.formatEntityState(entity)})`;
|
||||
}
|
||||
return `${this.hass.localize(
|
||||
|
@ -1,23 +1,15 @@
|
||||
import "@material/mwc-tab-bar/mwc-tab-bar";
|
||||
import "@material/mwc-tab/mwc-tab";
|
||||
import type { MDCTabBarActivatedEvent } from "@material/tab-bar";
|
||||
import {
|
||||
mdiCodeBraces,
|
||||
mdiContentCopy,
|
||||
mdiListBoxOutline,
|
||||
mdiPlus,
|
||||
} from "@mdi/js";
|
||||
import { mdiCodeBraces, mdiContentCopy, mdiListBoxOutline } from "@mdi/js";
|
||||
import deepClone from "deep-clone-simple";
|
||||
import { CSSResultGroup, LitElement, css, html, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { any, array, assert, assign, object, optional } from "superstruct";
|
||||
import { storage } from "../../../../common/decorators/storage";
|
||||
import { HASSDomEvent, fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { stopPropagation } from "../../../../common/dom/stop_propagation";
|
||||
import "../../../../components/ha-button";
|
||||
import "../../../../components/ha-list-item";
|
||||
import "../../../../components/ha-menu-button";
|
||||
import type { HaSelect } from "../../../../components/ha-select";
|
||||
import "../../../../components/ha-svg-icon";
|
||||
import type {
|
||||
LovelaceCardConfig,
|
||||
@ -25,27 +17,17 @@ import type {
|
||||
} from "../../../../data/lovelace";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import type { ConditionalCardConfig } from "../../cards/types";
|
||||
import { ICON_CONDITION } from "../../common/icon-condition";
|
||||
import { Condition } from "../../common/validate-condition";
|
||||
import type { LovelaceCardEditor } from "../../types";
|
||||
import "../card-editor/hui-card-element-editor";
|
||||
import type { HuiCardElementEditor } from "../card-editor/hui-card-element-editor";
|
||||
import "../card-editor/hui-card-picker";
|
||||
import "../conditions/ha-card-condition-editor";
|
||||
import { LovelaceConditionEditorConstructor } from "../conditions/types";
|
||||
import "../conditions/types/ha-card-condition-screen";
|
||||
import "../conditions/types/ha-card-condition-state";
|
||||
import "../conditions/ha-card-conditions-editor";
|
||||
import "../hui-element-editor";
|
||||
import type { ConfigChangedEvent } from "../hui-element-editor";
|
||||
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
|
||||
import type { GUIModeChangedEvent } from "../types";
|
||||
import { configElementStyle } from "./config-elements-style";
|
||||
|
||||
const UI_CONDITION = [
|
||||
"state",
|
||||
"screen",
|
||||
] as const satisfies readonly Condition["condition"][];
|
||||
|
||||
const cardConfigStruct = assign(
|
||||
baseLovelaceCardConfig,
|
||||
object({
|
||||
@ -162,59 +144,12 @@ export class HuiConditionalCardEditor
|
||||
</div>
|
||||
`
|
||||
: html`
|
||||
<div class="conditions">
|
||||
<ha-alert alert-type="info">
|
||||
${this.hass!.localize(
|
||||
"ui.panel.lovelace.editor.card.conditional.condition_explanation"
|
||||
)}
|
||||
</ha-alert>
|
||||
${this._config.conditions.map((cond, idx) => {
|
||||
const condition: Condition = {
|
||||
condition: "state",
|
||||
...cond,
|
||||
};
|
||||
return html`
|
||||
<div class="condition">
|
||||
<ha-card-condition-editor
|
||||
.index=${idx}
|
||||
@value-changed=${this._conditionChanged}
|
||||
.hass=${this.hass}
|
||||
.condition=${condition}
|
||||
></ha-card-condition-editor>
|
||||
</div>
|
||||
`;
|
||||
})}
|
||||
<div>
|
||||
<ha-button-menu
|
||||
@action=${this._addCondition}
|
||||
fixed
|
||||
@closed=${stopPropagation}
|
||||
>
|
||||
<ha-button
|
||||
slot="trigger"
|
||||
outlined
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.lovelace.editor.card.conditional.add_condition"
|
||||
)}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiPlus} slot="icon"></ha-svg-icon>
|
||||
</ha-button>
|
||||
${UI_CONDITION.map(
|
||||
(condition) => html`
|
||||
<ha-list-item .value=${condition} graphic="icon">
|
||||
${this.hass!.localize(
|
||||
`ui.panel.lovelace.editor.card.conditional.condition.${condition}.label`
|
||||
) || condition}
|
||||
<ha-svg-icon
|
||||
slot="graphic"
|
||||
.path=${ICON_CONDITION[condition]}
|
||||
></ha-svg-icon>
|
||||
</ha-list-item>
|
||||
`
|
||||
)}
|
||||
</ha-button-menu>
|
||||
</div>
|
||||
</div>
|
||||
<ha-card-conditions-editor
|
||||
.hass=${this.hass}
|
||||
.conditions=${this._config.conditions}
|
||||
@value-changed=${this._conditionChanged}
|
||||
>
|
||||
</ha-card-conditions-editor>
|
||||
`}
|
||||
`;
|
||||
}
|
||||
@ -281,43 +216,16 @@ export class HuiConditionalCardEditor
|
||||
fireEvent(this, "config-changed", { config: this._config });
|
||||
}
|
||||
|
||||
private _addCondition(ev: CustomEvent): void {
|
||||
const condition = (ev.currentTarget as HaSelect).items[ev.detail.index]
|
||||
.value as Condition["condition"];
|
||||
private _conditionChanged(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
if (!this._config) {
|
||||
return;
|
||||
}
|
||||
const conditions = [...this._config.conditions];
|
||||
|
||||
const elClass = customElements.get(`ha-card-condition-${condition}`) as
|
||||
| LovelaceConditionEditorConstructor
|
||||
| undefined;
|
||||
|
||||
conditions.push(
|
||||
elClass?.defaultConfig
|
||||
? { ...elClass.defaultConfig }
|
||||
: { condition: condition }
|
||||
);
|
||||
const conditions = ev.detail.value;
|
||||
this._config = { ...this._config, conditions };
|
||||
fireEvent(this, "config-changed", { config: this._config });
|
||||
}
|
||||
|
||||
private _conditionChanged(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
const conditions = [...this._config!.conditions];
|
||||
const newValue = ev.detail.value;
|
||||
const index = (ev.target as any).index;
|
||||
|
||||
if (newValue === null) {
|
||||
conditions.splice(index, 1);
|
||||
} else {
|
||||
conditions[index] = newValue;
|
||||
}
|
||||
|
||||
this._config = { ...this._config!, conditions };
|
||||
fireEvent(this, "config-changed", { config: this._config });
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
configElementStyle,
|
||||
@ -325,19 +233,6 @@ export class HuiConditionalCardEditor
|
||||
mwc-tab-bar {
|
||||
border-bottom: 1px solid var(--divider-color);
|
||||
}
|
||||
.conditions {
|
||||
margin-top: 8px;
|
||||
}
|
||||
.condition {
|
||||
margin-top: 8px;
|
||||
border: 1px solid var(--divider-color);
|
||||
}
|
||||
.condition .content {
|
||||
padding: 12px;
|
||||
}
|
||||
ha-button-menu {
|
||||
margin-top: 12px;
|
||||
}
|
||||
.card {
|
||||
margin-top: 8px;
|
||||
border: 1px solid var(--divider-color);
|
||||
|
@ -4754,6 +4754,29 @@
|
||||
"none": "No action"
|
||||
}
|
||||
},
|
||||
"condition-editor": {
|
||||
"explanation": "The card will be shown when ALL conditions below are fulfilled.",
|
||||
"add": "Add condition",
|
||||
"condition": {
|
||||
"screen": {
|
||||
"label": "Screen",
|
||||
"breakpoints": "Screen sizes",
|
||||
"breakpoints_list": {
|
||||
"mobile": "Mobile",
|
||||
"tablet": "Tablet",
|
||||
"desktop": "Desktop",
|
||||
"wide": "Wide"
|
||||
},
|
||||
"min": "min: {size}px"
|
||||
},
|
||||
"state": {
|
||||
"label": "Entity state",
|
||||
"state_equal": "State is equal to",
|
||||
"state_not_equal": "State is not equal to",
|
||||
"current_state": "current"
|
||||
}
|
||||
}
|
||||
},
|
||||
"card": {
|
||||
"alarm-panel": {
|
||||
"name": "Alarm panel",
|
||||
@ -4782,28 +4805,7 @@
|
||||
"description": "The Conditional card displays another card based on entity states.",
|
||||
"conditions": "Conditions",
|
||||
"card": "Card",
|
||||
"state_equal": "State is equal to",
|
||||
"state_not_equal": "State is not equal to",
|
||||
"current_state": "current",
|
||||
"condition_explanation": "The card will be shown when ALL conditions below are fulfilled.",
|
||||
"change_type": "Change type",
|
||||
"add_condition": "Add condition",
|
||||
"condition": {
|
||||
"screen": {
|
||||
"label": "Screen",
|
||||
"breakpoints": "Screen sizes",
|
||||
"breakpoints_list": {
|
||||
"mobile": "Mobile",
|
||||
"tablet": "Tablet",
|
||||
"desktop": "Desktop",
|
||||
"wide": "Wide"
|
||||
},
|
||||
"min": "min: {size}px"
|
||||
},
|
||||
"state": {
|
||||
"label": "Entity state"
|
||||
}
|
||||
}
|
||||
"change_type": "Change type"
|
||||
},
|
||||
"config": {
|
||||
"required": "required",
|
||||
|
Loading…
x
Reference in New Issue
Block a user