Add entity filter section strategy
parent
91e9836423
commit
99cd67c857
|
@ -5,6 +5,7 @@ import type { LovelaceStrategyConfig } from "./strategy";
|
|||
export interface LovelaceBaseSectionConfig {
|
||||
visibility?: Condition[];
|
||||
column_span?: number;
|
||||
hidden?: boolean;
|
||||
row_span?: number;
|
||||
/**
|
||||
* @deprecated Use heading card instead.
|
||||
|
|
|
@ -80,7 +80,7 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
|
|||
|
||||
const cardsConfig = this._config?.cards ?? [];
|
||||
|
||||
const editMode = Boolean(this.lovelace?.editMode && !this.isStrategy);
|
||||
const editMode = Boolean(this.lovelace?.editMode);
|
||||
|
||||
const sortableOptions = this.importOnly
|
||||
? IMPORT_MODE_CARD_SORTABLE_OPTIONS
|
||||
|
@ -88,7 +88,7 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
|
|||
|
||||
return html`
|
||||
<ha-sortable
|
||||
.disabled=${!editMode}
|
||||
.disabled=${!(editMode && !this.isStrategy)}
|
||||
@drag-start=${this._dragStart}
|
||||
@drag-end=${this._dragEnd}
|
||||
draggable-selector=".card"
|
||||
|
@ -103,6 +103,7 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
|
|||
class="container ${classMap({
|
||||
"edit-mode": editMode,
|
||||
"import-only": this.importOnly,
|
||||
"is-strategy": this.isStrategy,
|
||||
})}"
|
||||
>
|
||||
${repeat(
|
||||
|
@ -133,7 +134,7 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
|
|||
})}"
|
||||
.sortableData=${cardPath}
|
||||
>
|
||||
${editMode
|
||||
${editMode && !this.isStrategy
|
||||
? html`
|
||||
<hui-card-edit-mode
|
||||
.hass=${this.hass}
|
||||
|
@ -151,7 +152,7 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
|
|||
`;
|
||||
}
|
||||
)}
|
||||
${editMode && !this.importOnly
|
||||
${editMode && !this.importOnly && !this.isStrategy
|
||||
? html`
|
||||
<button
|
||||
class="add"
|
||||
|
@ -246,6 +247,10 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
|
|||
min-height: var(--row-height);
|
||||
}
|
||||
|
||||
.container.edit-mode.is-strategy {
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
.container.import-only {
|
||||
border: none;
|
||||
padding: 0 !important;
|
||||
|
|
|
@ -55,6 +55,8 @@ export class HuiSection extends ReactiveElement {
|
|||
|
||||
@state() private _cards: HuiCard[] = [];
|
||||
|
||||
@state() private _config?: LovelaceSectionConfig;
|
||||
|
||||
private _layoutElementType?: string;
|
||||
|
||||
private _layoutElement?: LovelaceSectionElement;
|
||||
|
@ -195,6 +197,8 @@ export class HuiSection extends ReactiveElement {
|
|||
type: sectionConfig.type || DEFAULT_SECTION_LAYOUT,
|
||||
};
|
||||
|
||||
this._config = sectionConfig;
|
||||
|
||||
// Create a new layout element if necessary.
|
||||
let addLayoutElement = false;
|
||||
|
||||
|
@ -223,14 +227,16 @@ export class HuiSection extends ReactiveElement {
|
|||
}
|
||||
|
||||
private _updateElement(forceVisible?: boolean) {
|
||||
if (!this._layoutElement) {
|
||||
if (!this._layoutElement || !this._config) {
|
||||
return;
|
||||
}
|
||||
|
||||
const visible =
|
||||
forceVisible ||
|
||||
this.preview ||
|
||||
!this.config.visibility ||
|
||||
checkConditionsMet(this.config.visibility, this.hass);
|
||||
(!this._config.hidden &&
|
||||
(!this.config.visibility ||
|
||||
checkConditionsMet(this.config.visibility, this.hass)));
|
||||
|
||||
if (this.hidden !== !visible) {
|
||||
this.style.setProperty("display", visible ? "" : "none");
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
import { ReactiveElement } from "lit";
|
||||
import { customElement } from "lit/decorators";
|
||||
import {
|
||||
generateEntityFilter,
|
||||
type EntityFilter,
|
||||
} from "../../../../common/entity/entity_filter";
|
||||
import type { TileCardConfig, HeadingCardConfig } from "../../cards/types";
|
||||
import type { HomeAssistant } from "../../../../types";
|
||||
import type { LovelaceSectionConfig } from "../../../../data/lovelace/config/section";
|
||||
import type { LovelaceCardConfig } from "../../../../data/lovelace/config/card";
|
||||
import { ensureArray } from "../../../../common/array/ensure-array";
|
||||
|
||||
interface EntityFilterConfig {
|
||||
title?: string;
|
||||
icon?: string;
|
||||
filter?: EntityFilter | EntityFilter[];
|
||||
include_entities?: string[];
|
||||
exclude_entities?: string[];
|
||||
order?: string[];
|
||||
}
|
||||
|
||||
export type EntitiesFilterSectionStrategyConfig = EntityFilterConfig & {
|
||||
type: "entities-filter";
|
||||
groups?: EntityFilterConfig[];
|
||||
};
|
||||
|
||||
const getEntities = (hass: HomeAssistant, config: EntityFilterConfig) => {
|
||||
let entitiesIds =
|
||||
config.filter || config.exclude_entities ? Object.keys(hass.states) : [];
|
||||
|
||||
if (config.exclude_entities) {
|
||||
entitiesIds = entitiesIds.filter(
|
||||
(entityId) => !config.exclude_entities!.includes(entityId)
|
||||
);
|
||||
}
|
||||
|
||||
if (config.filter) {
|
||||
const filters = ensureArray(config.filter);
|
||||
const entityFilters = filters.map((filter) =>
|
||||
generateEntityFilter(hass, filter)
|
||||
);
|
||||
|
||||
entitiesIds = entitiesIds.filter((entityId) =>
|
||||
entityFilters.some((filter) => filter(entityId))
|
||||
);
|
||||
}
|
||||
|
||||
if (config.include_entities) {
|
||||
entitiesIds.push(...config.include_entities);
|
||||
}
|
||||
|
||||
if (config.order) {
|
||||
entitiesIds.sort((a, b) => {
|
||||
const aIndex = config.order!.indexOf(a);
|
||||
const bIndex = config.order!.indexOf(b);
|
||||
if (aIndex === -1 && bIndex === -1) return 0;
|
||||
if (aIndex === -1) return 1;
|
||||
if (bIndex === -1) return -1;
|
||||
return aIndex - bIndex;
|
||||
});
|
||||
}
|
||||
|
||||
return entitiesIds;
|
||||
};
|
||||
|
||||
@customElement("entities-filter-section-strategy")
|
||||
export class EntitiesFilterSectionStrategy extends ReactiveElement {
|
||||
static async generate(
|
||||
config: EntitiesFilterSectionStrategyConfig,
|
||||
hass: HomeAssistant
|
||||
): Promise<LovelaceSectionConfig> {
|
||||
const cards: LovelaceCardConfig[] = [];
|
||||
let isEmpty = true;
|
||||
|
||||
if (config.title) {
|
||||
const headingCard: HeadingCardConfig = {
|
||||
type: "heading",
|
||||
heading: config.title,
|
||||
heading_style: "title",
|
||||
icon: config.icon,
|
||||
};
|
||||
cards.push(headingCard);
|
||||
}
|
||||
|
||||
const entities = getEntities(hass, config);
|
||||
|
||||
if (entities.length > 0) {
|
||||
isEmpty = false;
|
||||
for (const entityId of entities) {
|
||||
const tileCard: TileCardConfig = {
|
||||
type: "tile",
|
||||
entity: entityId,
|
||||
};
|
||||
cards.push(tileCard);
|
||||
}
|
||||
}
|
||||
|
||||
if (config.groups) {
|
||||
for (const group of config.groups) {
|
||||
const groupEntities = getEntities(hass, group);
|
||||
|
||||
if (groupEntities.length > 0) {
|
||||
isEmpty = false;
|
||||
if (group.title) {
|
||||
cards.push({
|
||||
type: "heading",
|
||||
heading: group.title,
|
||||
heading_style: "subtitle",
|
||||
icon: group.icon,
|
||||
});
|
||||
}
|
||||
|
||||
for (const entityId of groupEntities) {
|
||||
const tileCard: TileCardConfig = {
|
||||
type: "tile",
|
||||
entity: entityId,
|
||||
};
|
||||
cards.push(tileCard);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isEmpty) {
|
||||
cards.push({
|
||||
type: "markdown",
|
||||
content: "No entities found.",
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
type: "grid",
|
||||
cards: cards,
|
||||
hidden: isEmpty,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"entities-filter-section-strategy": EntitiesFilterSectionStrategy;
|
||||
}
|
||||
}
|
|
@ -35,7 +35,10 @@ const STRATEGIES: Record<LovelaceStrategyConfigType, Record<string, any>> = {
|
|||
area: () => import("./area/area-view-strategy"),
|
||||
areas: () => import("./areas/areas-view-strategy"),
|
||||
},
|
||||
section: {},
|
||||
section: {
|
||||
"entities-filter": () =>
|
||||
import("./entities-filter/entities-filter-section-strategy"),
|
||||
},
|
||||
};
|
||||
|
||||
export type LovelaceStrategyConfigType = "dashboard" | "view" | "section";
|
||||
|
|
Loading…
Reference in New Issue