Only allow state filter for filter card (#1387)

* Only allow state filter for filter card

* Lint

* Address comments
This commit is contained in:
Paulus Schoutsen 2018-07-02 14:03:59 -04:00 committed by GitHub
parent 25fddad446
commit c868df2718
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 57 additions and 117 deletions

View File

@ -5,8 +5,7 @@ import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import stateCardType from '../../../common/entity/state_card_type.js';
import computeDomain from '../../../common/entity/compute_domain.js';
import { DOMAINS_HIDE_MORE_INFO } from '../../../common/const.js';
import computeConfigEntities from '../common/compute-config-entities';
import validateEntitiesConfig from '../common/validate-entities-config';
import processConfigEntities from '../common/process-config-entities.js';
import '../../../components/ha-card.js';
import '../components/hui-entities-toggle.js';
@ -100,18 +99,14 @@ class HuiEntitiesCard extends EventsMixin(PolymerElement) {
}
setConfig(config) {
if (!validateEntitiesConfig(config)) {
throw Error('Error in card config.');
}
this._config = config;
this._configEntities = processConfigEntities(config.entities);
if (this.$) this._buildConfig();
}
_buildConfig() {
const config = this._config;
const root = this.$.states;
const entities = computeConfigEntities(config);
const entities = this._configEntities;
while (root.lastChild) {
root.removeChild(root.lastChild);

View File

@ -1,7 +1,14 @@
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import computeStateDomain from '../../../common/entity/compute_state_domain.js';
import createCardElement from '../common/create-card-element.js';
import processConfigEntities from '../common/process-config-entities.js';
function getEntities(hass, filterState, entities) {
return entities.filter((entityConf) => {
const stateObj = hass.states[entityConf.entity];
return stateObj && filterState.includes(stateObj.state);
});
}
class HuiEntitiesCard extends PolymerElement {
static get properties() {
@ -17,44 +24,13 @@ class HuiEntitiesCard extends PolymerElement {
return this.lastChild ? this.lastChild.getCardSize() : 1;
}
// Return a list of entities based on filters.
_getEntities(hass, filterList) {
const entities = new Set();
filterList.forEach((filter) => {
const filters = [];
if (filter.domain) {
filters.push(stateObj => computeStateDomain(stateObj) === filter.domain);
}
if (filter.entity_id) {
filters.push(stateObj => this._filterEntityId(stateObj, filter.entity_id));
}
if (filter.state) {
filters.push(stateObj => stateObj.state === filter.state);
}
Object.values(hass.states).forEach((stateObj) => {
if (filters.every(filterFunc => filterFunc(stateObj))) {
entities.add(stateObj.entity_id);
}
});
});
return Array.from(entities);
}
_filterEntityId(stateObj, pattern) {
if (pattern.indexOf('*') === -1) {
return stateObj.entity_id === pattern;
}
const regEx = new RegExp(`^${pattern.replace(/\*/g, '.*')}$`);
return stateObj.entity_id.search(regEx) === 0;
}
setConfig(config) {
if (!config.filter || !Array.isArray(config.filter)) {
if (!config.state_filter || !Array.isArray(config.state_filter)) {
throw new Error('Incorrect filter config.');
}
this._config = config;
this._configEntities = processConfigEntities(config.entities);
if (this.lastChild) {
this.removeChild(this.lastChild);
@ -79,12 +55,14 @@ class HuiEntitiesCard extends PolymerElement {
_updateCardConfig(element) {
if (!element || element.tagName === 'HUI-ERROR-CARD' || !this.hass) return;
const entitiesList = this._getEntities(this.hass, this._config.filter);
if (entitiesList.length === 0) {
this.style.display = (this._config.show_empty === false) ? 'none' : 'block';
} else {
this.style.display = 'block';
const entitiesList = getEntities(this.hass, this._config.state_filter, this._configEntities);
if (entitiesList.length === 0 && this._config.show_empty === false) {
this.style.display = 'none';
return;
}
this.style.display = 'block';
element.setConfig(Object.assign(
{},
element._filterRawConfig,

View File

@ -3,7 +3,7 @@ import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import computeStateDisplay from '../../../common/entity/compute_state_display.js';
import computeStateName from '../../../common/entity/compute_state_name.js';
import computeConfigEntities from '../common/compute-config-entities';
import processConfigEntities from '../common/process-config-entities';
import '../../../components/entity/state-badge.js';
import '../../../components/ha-card.js';
@ -52,7 +52,7 @@ class HuiGlanceCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
<ha-card header$="[[_config.title]]">
<div class="entities">
<template is="dom-repeat" items="[[_computeEntities(_config)]]">
<template is="dom-repeat" items="[[_configEntities]]">
<template is="dom-if" if="[[_showEntity(item, hass.states)]]">
<div class="entity" on-click="_openDialog">
<div>[[_computeName(item, hass.states)]]</div>
@ -70,6 +70,7 @@ class HuiGlanceCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
return {
hass: Object,
_config: Object,
_configEntities: Array,
};
}
@ -77,16 +78,9 @@ class HuiGlanceCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
return 3;
}
_computeEntities(config) {
return computeConfigEntities(config);
}
setConfig(config) {
if (!config || !config.entities || !Array.isArray(config.entities)) {
throw new Error('Error in card configuration.');
}
this._config = config;
this._configEntities = processConfigEntities(config.entities);
}
_showEntity(item, states) {

View File

@ -1,5 +1,5 @@
import createErrorCardConfig from '../common/create-error-card-config.js';
import validateEntityConfig from '../common/validate-entity-config.js';
import computeDomain from '../../../common/entity/compute_domain.js';
export default class LegacyWrapperCard extends HTMLElement {
@ -15,8 +15,12 @@ export default class LegacyWrapperCard extends HTMLElement {
}
setConfig(config) {
if (!validateEntityConfig(config, this._domain)) {
throw new Error('Error in card configuration.');
if (!config.entity) {
throw new Error('No entity specified');
}
if (computeDomain(config.entity) !== this._domain) {
throw new Error(`Specified entity needs to be of domain ${this._domain}.`);
}
this._config = config;

View File

@ -1,17 +0,0 @@
// Parse array of entity objects from config
export default function computeConfigEntities(config) {
const entities = config && config.entities;
if (!entities || !Array.isArray(entities)) {
return null;
}
return entities.map((entity) => {
if (typeof entity === 'string') {
return { entity };
} else if (typeof entity === 'object' && !Array.isArray(entity)) {
return entity;
}
return null;
});
}

View File

@ -0,0 +1,26 @@
// Parse array of entity objects from config
import isValidEntityId from '../../../common/entity/valid_entity_id.js';
export default function processConfigEntities(entities) {
if (!entities || !Array.isArray(entities)) {
throw new Error('Entities need to be an array');
}
return entities.map((entityConf, index) => {
if (typeof entityConf === 'string') {
entityConf = { entity: entityConf };
} else if (typeof entityConf === 'object' && !Array.isArray(entityConf)) {
if (!entityConf.entity) {
throw new Error(`Entity object at position ${index} is missing entity field.`);
}
} else {
throw new Error(`Invalid entity specified at position ${index}.`);
}
if (!isValidEntityId(entityConf.entity)) {
throw new Error(`Invalid entity ID at position ${index}: ${entityConf.entity}`);
}
return entityConf;
});
}

View File

@ -1,23 +0,0 @@
/**
* Check that all items in array are objects with an entity property containing a valid entity_id.
*
* Optionally provide an array of additional keys that must be present in every object
*/
import validEntityId from '../../../common/entity/valid_entity_id';
export default function validateEntitiesConfig(config, additionalKeys = []) {
const entities = config && config.entities;
if (!entities || !Array.isArray(entities)) {
return false;
}
return entities.every((entity) => {
if (typeof entity === 'string') {
return validEntityId(entity) && !additionalKeys.length;
}
return entity && typeof entity === 'object' && !Array.isArray(entity) &&
'entity' in entity && validEntityId(entity.entity) && additionalKeys.every(key => key in entity);
});
}

View File

@ -1,17 +0,0 @@
// check for valid value of config.entity with optinal entity dommain check
import computeDomain from '../../../common/entity/compute_domain.js';
import validEntityId from '../../../common/entity/valid_entity_id';
export default function validateEntityConfig(config, domain = null) {
const entityId = config && config.entity;
if (!entityId || typeof entityId !== 'string' || !validEntityId(entityId)) {
return false;
}
if (domain) {
return computeDomain(entityId) === domain;
}
return true;
}