diff --git a/gallery/src/demos/demo-hui-conditional-card.js b/gallery/src/demos/demo-hui-conditional-card.js new file mode 100644 index 0000000000..69288eee08 --- /dev/null +++ b/gallery/src/demos/demo-hui-conditional-card.js @@ -0,0 +1,84 @@ +import { html } from '@polymer/polymer/lib/utils/html-tag.js'; +import { PolymerElement } from '@polymer/polymer/polymer-element.js'; + +import getEntity from '../data/entity.js'; +import provideHass from '../data/provide_hass.js'; +import '../components/demo-cards.js'; + +const ENTITIES = [ + getEntity('light', 'controller_1', 'on', { + friendly_name: 'Controller 1' + }), + getEntity('light', 'controller_2', 'on', { + friendly_name: 'Controller 2' + }), + getEntity('light', 'floor', 'off', { + friendly_name: 'Floor light' + }), + getEntity('light', 'kitchen', 'on', { + friendly_name: 'Kitchen light' + }), +]; + +const CONFIGS = [ + { + heading: 'Controller', + config: ` +- type: entities + entities: + - light.controller_1 + - light.controller_2 + - type: divider + - light.floor + - light.kitchen + ` + }, + { + heading: 'Demo', + config: ` +- type: conditional + conditions: + - entity: light.controller_1 + state: "on" + - entity: light.controller_2 + state_not: "off" + card: + type: entities + entities: + - light.controller_1 + - light.controller_2 + - light.floor + - light.kitchen + ` + }, +]; + +class DemoConditional extends PolymerElement { + static get template() { + return html` + + `; + } + + static get properties() { + return { + _configs: { + type: Object, + value: CONFIGS + }, + hass: Object, + }; + } + + ready() { + super.ready(); + const hass = provideHass(this.$.demos); + hass.addEntities(ENTITIES); + } +} + +customElements.define('demo-hui-conditional-card', DemoConditional); diff --git a/src/panels/lovelace/cards/hui-conditional-card.js b/src/panels/lovelace/cards/hui-conditional-card.js new file mode 100644 index 0000000000..0408fb6fd7 --- /dev/null +++ b/src/panels/lovelace/cards/hui-conditional-card.js @@ -0,0 +1,78 @@ +import { html } from '@polymer/polymer/lib/utils/html-tag.js'; +import { PolymerElement } from '@polymer/polymer/polymer-element.js'; + +import computeCardSize from '../common/compute-card-size.js'; +import createCardElement from '../common/create-card-element.js'; + +class HuiConditionalCard extends PolymerElement { + static get template() { + return html` + +
+ `; + } + + static get properties() { + return { + hass: { + type: Object, + observer: '_hassChanged', + }, + _config: Object + }; + } + + ready() { + super.ready(); + if (this._config) this._buildConfig(); + } + + setConfig(config) { + if (!config || !config.card || !Array.isArray(config.conditions) || + !config.conditions.every(c => c.entity && (c.state || c.state_not))) { + throw new Error('Error in card configuration.'); + } + + this._config = config; + if (this.$) this._buildConfig(); + } + + _buildConfig() { + const config = this._config; + const root = this.$.card; + while (root.lastChild) { + root.removeChild(root.lastChild); + } + + const element = createCardElement(config.card); + element.hass = this.hass; + root.appendChild(element); + } + + getCardSize() { + const el = this.$.card && this.$.card.lastChild; + return el ? computeCardSize(el) : 1; + } + + _hassChanged(hass) { + const root = this.$.card; + if (!root || !root.lastChild) return; + + root.lastChild.hass = hass; + + const conditions = this._config.conditions; + const visible = conditions.every((c) => { + if (c.entity in hass.states) { + if (c.state) return hass.states[c.entity].state === c.state; + return hass.states[c.entity].state !== c.state_not; + } + return false; + }); + root.classList.toggle('hidden', !visible); + } +} +customElements.define('hui-conditional-card', HuiConditionalCard); diff --git a/src/panels/lovelace/common/create-card-element.js b/src/panels/lovelace/common/create-card-element.js index b2495daad8..3f47536b93 100644 --- a/src/panels/lovelace/common/create-card-element.js +++ b/src/panels/lovelace/common/create-card-element.js @@ -1,5 +1,6 @@ import fireEvent from '../../../common/dom/fire_event.js'; +import '../cards/hui-conditional-card.js'; import '../cards/hui-entities-card.js'; import '../cards/hui-entity-filter-card.js'; import '../cards/hui-error-card.js'; @@ -20,7 +21,8 @@ import '../cards/hui-weather-forecast-card'; import createErrorCardConfig from './create-error-card-config.js'; -const CARD_TYPES = [ +const CARD_TYPES = new Set([ + 'conditional', 'entities', 'entity-filter', 'error', @@ -38,7 +40,7 @@ const CARD_TYPES = [ 'plant-status', 'vertical-stack', 'weather-forecast' -]; +]); const CUSTOM_TYPE_PREFIX = 'custom:'; @@ -81,7 +83,7 @@ export default function createCardElement(config) { return element; } - if (!CARD_TYPES.includes(config.type)) { + if (!CARD_TYPES.has(config.type)) { return _createErrorElement(`Unknown card type encountered: ${config.type}.`, config); }