mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-18 23:06:40 +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 { createCardElement } from "../create-element/create-card-element";
|
||||
import { LovelaceCard } from "../types";
|
||||
import { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||
import { computeCardSize } from "../common/compute-card-size";
|
||||
import { ConditionalCardConfig } from "./types";
|
||||
|
||||
@customElement("hui-conditional-card")
|
||||
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 {
|
||||
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": {
|
||||
"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": {
|
||||
"required": "Required",
|
||||
@ -2041,7 +2048,8 @@
|
||||
"title": "Title",
|
||||
"theme": "Theme",
|
||||
"unit": "Unit",
|
||||
"url": "Url"
|
||||
"url": "Url",
|
||||
"state": "State"
|
||||
},
|
||||
"map": {
|
||||
"name": "Map",
|
||||
|
Loading…
x
Reference in New Issue
Block a user