mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-19 07:16:39 +00:00
GUI editor for conditional card (#5051)
* GUI editor for conditional card * Typing * Fix typos. Remove quotes * Add lovelace to card picker * Address review comments
This commit is contained in:
parent
5a2649a65b
commit
503dec7345
@ -2,12 +2,26 @@ import { customElement } from "lit-element";
|
|||||||
|
|
||||||
import { HuiConditionalBase } from "../components/hui-conditional-base";
|
import { HuiConditionalBase } from "../components/hui-conditional-base";
|
||||||
import { createCardElement } from "../create-element/create-card-element";
|
import { createCardElement } from "../create-element/create-card-element";
|
||||||
import { LovelaceCard } from "../types";
|
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||||
import { computeCardSize } from "../common/compute-card-size";
|
import { computeCardSize } from "../common/compute-card-size";
|
||||||
import { ConditionalCardConfig } from "./types";
|
import { ConditionalCardConfig } from "./types";
|
||||||
|
|
||||||
@customElement("hui-conditional-card")
|
@customElement("hui-conditional-card")
|
||||||
class HuiConditionalCard extends HuiConditionalBase implements LovelaceCard {
|
class HuiConditionalCard extends HuiConditionalBase implements LovelaceCard {
|
||||||
|
public static async getConfigElement(): Promise<LovelaceCardEditor> {
|
||||||
|
await import(
|
||||||
|
/* webpackChunkName: "hui-conditional-card-editor" */ "../editor/config-elements/hui-conditional-card-editor"
|
||||||
|
);
|
||||||
|
return document.createElement("hui-conditional-card-editor");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getStubConfig(): object {
|
||||||
|
return {
|
||||||
|
conditions: [],
|
||||||
|
card: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public setConfig(config: ConditionalCardConfig): void {
|
public setConfig(config: ConditionalCardConfig): void {
|
||||||
this.validateConfig(config);
|
this.validateConfig(config);
|
||||||
|
|
||||||
|
@ -0,0 +1,277 @@
|
|||||||
|
import {
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
TemplateResult,
|
||||||
|
customElement,
|
||||||
|
property,
|
||||||
|
CSSResult,
|
||||||
|
css,
|
||||||
|
} from "lit-element";
|
||||||
|
import "@polymer/paper-tabs";
|
||||||
|
|
||||||
|
import { struct } from "../../common/structs/struct";
|
||||||
|
import { HomeAssistant } from "../../../../types";
|
||||||
|
import { LovelaceCardEditor } from "../../types";
|
||||||
|
import { StackCardConfig } from "../../cards/types";
|
||||||
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
|
import { LovelaceConfig } from "../../../../data/lovelace";
|
||||||
|
|
||||||
|
import "../../../../components/entity/ha-entity-picker";
|
||||||
|
import "../../../../components/ha-switch";
|
||||||
|
|
||||||
|
const conditionStruct = struct({
|
||||||
|
entity: "string",
|
||||||
|
state: "string?",
|
||||||
|
state_not: "string?",
|
||||||
|
});
|
||||||
|
const cardConfigStruct = struct({
|
||||||
|
type: "string",
|
||||||
|
card: "any",
|
||||||
|
conditions: struct.optional([conditionStruct]),
|
||||||
|
});
|
||||||
|
|
||||||
|
@customElement("hui-conditional-card-editor")
|
||||||
|
export class HuiConditionalCardEditor extends LitElement
|
||||||
|
implements LovelaceCardEditor {
|
||||||
|
@property() public hass?: HomeAssistant;
|
||||||
|
@property() public lovelace?: LovelaceConfig;
|
||||||
|
@property() private _config?: StackCardConfig;
|
||||||
|
@property() private _cardTab: boolean = false;
|
||||||
|
|
||||||
|
public setConfig(config: StackCardConfig): void {
|
||||||
|
this._config = cardConfigStruct(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this.hass || !this._config) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<paper-tabs
|
||||||
|
.selected=${this._cardTab ? "1" : "0"}
|
||||||
|
@iron-select=${this._selectTab}
|
||||||
|
>
|
||||||
|
<paper-tab
|
||||||
|
>${this.hass!.localize(
|
||||||
|
"ui.panel.lovelace.editor.card.conditional.conditions"
|
||||||
|
)}</paper-tab
|
||||||
|
>
|
||||||
|
<paper-tab
|
||||||
|
>${this.hass!.localize(
|
||||||
|
"ui.panel.lovelace.editor.card.conditional.card"
|
||||||
|
)}</paper-tab
|
||||||
|
>
|
||||||
|
</paper-tabs>
|
||||||
|
${this._cardTab
|
||||||
|
? html`
|
||||||
|
<div class="card">
|
||||||
|
${this._config.card.type
|
||||||
|
? html`
|
||||||
|
<div class="card-options">
|
||||||
|
<mwc-button @click=${this._handleReplaceCard}
|
||||||
|
>${this.hass!.localize(
|
||||||
|
"ui.panel.lovelace.editor.card.conditional.change_type"
|
||||||
|
)}</mwc-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<hui-card-editor
|
||||||
|
.hass=${this.hass}
|
||||||
|
.value=${this._config.card}
|
||||||
|
@config-changed=${this._handleCardChanged}
|
||||||
|
></hui-card-editor>
|
||||||
|
`
|
||||||
|
: html`
|
||||||
|
<hui-card-picker
|
||||||
|
.hass=${this.hass}
|
||||||
|
.lovelace=${this.lovelace}
|
||||||
|
@config-changed=${this._handleCardChanged}
|
||||||
|
></hui-card-picker>
|
||||||
|
`}
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: html`
|
||||||
|
<div class="conditions">
|
||||||
|
${this.hass!.localize(
|
||||||
|
"ui.panel.lovelace.editor.card.conditional.condition_explanation"
|
||||||
|
)}
|
||||||
|
${this._config.conditions.map((cond, idx) => {
|
||||||
|
return html`
|
||||||
|
<div class="condition">
|
||||||
|
<div class="entity">
|
||||||
|
<ha-entity-picker
|
||||||
|
.hass=${this.hass}
|
||||||
|
.value=${cond.entity}
|
||||||
|
.index=${idx}
|
||||||
|
.configValue=${"entity"}
|
||||||
|
@change=${this._changeCondition}
|
||||||
|
allow-custom-entity
|
||||||
|
></ha-entity-picker>
|
||||||
|
</div>
|
||||||
|
<div class="state">
|
||||||
|
<paper-dropdown-menu>
|
||||||
|
<paper-listbox
|
||||||
|
.selected=${cond.state_not !== undefined ? 1 : 0}
|
||||||
|
slot="dropdown-content"
|
||||||
|
.index=${idx}
|
||||||
|
.configValue=${"invert"}
|
||||||
|
@selected-item-changed=${this._changeCondition}
|
||||||
|
>
|
||||||
|
<paper-item
|
||||||
|
>${this.hass!.localize(
|
||||||
|
"ui.panel.lovelace.editor.card.conditional.state_equal"
|
||||||
|
)}</paper-item
|
||||||
|
>
|
||||||
|
<paper-item
|
||||||
|
>${this.hass!.localize(
|
||||||
|
"ui.panel.lovelace.editor.card.conditional.state_not_equal"
|
||||||
|
)}</paper-item
|
||||||
|
>
|
||||||
|
</paper-listbox>
|
||||||
|
</paper-dropdown-menu>
|
||||||
|
<paper-input
|
||||||
|
.label="${this.hass!.localize(
|
||||||
|
"ui.panel.lovelace.editor.card.generic.state"
|
||||||
|
)} (${this.hass!.localize(
|
||||||
|
"ui.panel.lovelace.editor.card.conditional.current_state"
|
||||||
|
)}: '${this.hass?.states[cond.entity].state}')"
|
||||||
|
.value=${cond.state_not !== undefined
|
||||||
|
? cond.state_not
|
||||||
|
: cond.state}
|
||||||
|
.index=${idx}
|
||||||
|
.configValue=${"state"}
|
||||||
|
@value-changed=${this._changeCondition}
|
||||||
|
></paper-input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
})}
|
||||||
|
<div class="condition">
|
||||||
|
<ha-entity-picker
|
||||||
|
.hass=${this.hass}
|
||||||
|
@change=${this._addCondition}
|
||||||
|
></ha-entity-picker>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _selectTab(ev: Event): void {
|
||||||
|
this._cardTab = parseInt((ev.target! as any).selected!, 10) === 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleCardChanged(ev: CustomEvent): void {
|
||||||
|
ev.stopPropagation();
|
||||||
|
if (!this._config) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._config.card = ev.detail.config;
|
||||||
|
fireEvent(this, "config-changed", { config: this._config });
|
||||||
|
}
|
||||||
|
private _handleReplaceCard(): void {
|
||||||
|
if (!this._config) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._config.card = {};
|
||||||
|
fireEvent(this, "config-changed", { config: this._config });
|
||||||
|
}
|
||||||
|
|
||||||
|
private _addCondition(ev: Event): void {
|
||||||
|
const target = ev.target! as any;
|
||||||
|
if (target.value === "" || !this._config) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._config.conditions.push({
|
||||||
|
entity: target.value,
|
||||||
|
state: "",
|
||||||
|
});
|
||||||
|
target.value = "";
|
||||||
|
fireEvent(this, "config-changed", { config: this._config });
|
||||||
|
}
|
||||||
|
private _changeCondition(ev: Event): void {
|
||||||
|
const target = ev.target as any;
|
||||||
|
if (!this._config || !target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (target.configValue === "entity" && target.value === "") {
|
||||||
|
this._config.conditions.splice(target.index, 1);
|
||||||
|
} else {
|
||||||
|
const condition = this._config.conditions[target.index];
|
||||||
|
if (target.configValue === "entity") {
|
||||||
|
condition.entity = target.value;
|
||||||
|
} else if (target.configValue === "state") {
|
||||||
|
if (condition.state_not !== undefined) {
|
||||||
|
condition.state_not = target.value;
|
||||||
|
} else {
|
||||||
|
condition.state = target.value;
|
||||||
|
}
|
||||||
|
} else if (target.configValue === "invert") {
|
||||||
|
if (target.selected === 1) {
|
||||||
|
if (condition.state) {
|
||||||
|
condition.state_not = condition.state;
|
||||||
|
delete condition.state;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (condition.state_not) {
|
||||||
|
condition.state = condition.state_not;
|
||||||
|
delete condition.state_not;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._config.conditions[target.index] = condition;
|
||||||
|
}
|
||||||
|
fireEvent(this, "config-changed", { config: this._config });
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResult {
|
||||||
|
return css`
|
||||||
|
paper-tabs {
|
||||||
|
--paper-tabs-selection-bar-color: var(--primary-color);
|
||||||
|
--paper-tab-ink: var(--primary-color);
|
||||||
|
border-bottom: 1px solid var(--divider-color);
|
||||||
|
}
|
||||||
|
.conditions {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
.condition {
|
||||||
|
margin-top: 8px;
|
||||||
|
border: 1px solid var(--divider-color);
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
.condition .state {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
.condition .state paper-dropdown-menu {
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
.condition .state paper-input {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
margin-top: 8px;
|
||||||
|
border: 1px solid var(--divider-color);
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
@media (max-width: 450px) {
|
||||||
|
.card,
|
||||||
|
.condition {
|
||||||
|
margin: 8px -12px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.card .card-options {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"hui-conditional-card-editor": HuiConditionalCardEditor;
|
||||||
|
}
|
||||||
|
}
|
@ -1966,7 +1966,14 @@
|
|||||||
},
|
},
|
||||||
"conditional": {
|
"conditional": {
|
||||||
"name": "Conditional",
|
"name": "Conditional",
|
||||||
"description": "The Conditional card displays another card based on entity states."
|
"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"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"required": "Required",
|
"required": "Required",
|
||||||
@ -2041,7 +2048,8 @@
|
|||||||
"title": "Title",
|
"title": "Title",
|
||||||
"theme": "Theme",
|
"theme": "Theme",
|
||||||
"unit": "Unit",
|
"unit": "Unit",
|
||||||
"url": "Url"
|
"url": "Url",
|
||||||
|
"state": "State"
|
||||||
},
|
},
|
||||||
"map": {
|
"map": {
|
||||||
"name": "Map",
|
"name": "Map",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user