Files
mushroom-strategy/src/views/AbstractView.ts
T
DigiLive a9d3ccd9b0 Optimize types
The type definitions and interfaces of Home Assistant and Mushroom where
outdated. Also, the type definitions and interfaces of the strategy
could use some refinement.
2025-04-26 09:50:38 +02:00

172 lines
5.2 KiB
TypeScript

import {Helper} from "../Helper";
import {ControllerCard} from "../cards/ControllerCard";
import {LovelaceCardConfig} from "../types/homeassistant/data/lovelace";
import {cards} from "../types/strategy/cards";
import {TitleCardConfig} from "../types/lovelace-mushroom/cards/title-card-config";
import {HassServiceTarget} from "home-assistant-js-websocket";
import {applyEntityCategoryFilters} from "../utillties/filters";
import {LovelaceViewConfig} from "../types/homeassistant/data/lovelace/config/view";
import {StackCardConfig} from "../types/homeassistant/panels/lovelace/cards/types";
import {generic} from "../types/strategy/generic";
import abstractCardConfig = cards.AbstractCardConfig;
import SupportedDomains = generic.SupportedDomains;
/**
* Abstract View Class.
*
* To create a new view, extend the new class with this one.
*
* @class
* @abstract
*/
abstract class AbstractView {
/**
* Configuration of the view.
*
* @type {LovelaceViewConfig}
*/
config: LovelaceViewConfig = {
icon: "mdi:view-dashboard",
subview: false,
};
/**
* A card to switch all entities in the view.
*
* @type {StackCardConfig}
*/
viewControllerCard: StackCardConfig = {
cards: [],
type: "",
};
/**
* The domain of which we operate the devices.
*
* @type {SupportedDomains | "home"}
* @private
* @readonly
*/
readonly #domain: SupportedDomains | "home";
/**
* Class constructor.
*
* @param {SupportedDomains} domain The domain which the view is representing.
*
* @throws {Error} If trying to instantiate this class.
* @throws {Error} If the Helper module isn't initialized.
*/
protected constructor(domain: SupportedDomains | "home") {
if (!Helper.isInitialized()) {
throw new Error("The Helper module must be initialized before using this one.");
}
this.#domain = domain;
}
/**
* Create the cards to include in the view.
*
* @return {Promise<(StackCardConfig | TitleCardConfig)[]>} An array of card objects.
*/
async createViewCards(): Promise<(StackCardConfig | TitleCardConfig)[]> {
if (this.#domain === "home") {
// The home domain should override this method because it hasn't entities on its own.
// The method override creates its own cards to show at the home view.
return [];
}
const viewCards: LovelaceCardConfig[] = [];
// Create cards for each area.
for (const area of Helper.areas) {
const areaCards: abstractCardConfig[] = [];
const className = Helper.sanitizeClassName(this.#domain + "Card");
const cardModule = await import(`../cards/${className}`);
// Set the target for controller cards to the current area.
let target: HassServiceTarget = {
area_id: [area.area_id],
};
let entities = Helper.getDeviceEntities(area, this.#domain);
// Exclude hidden Config and Diagnostic entities.
entities = applyEntityCategoryFilters(entities, this.#domain);
// Set the target for controller cards to entities without an area.
if (area.area_id === "undisclosed") {
target = {
entity_id: entities.map(entity => entity.entity_id),
}
}
// Create a card for each domain-entity of the current area.
for (const entity of entities) {
let cardOptions = Helper.strategyOptions.card_options?.[entity.entity_id];
let deviceOptions = Helper.strategyOptions.card_options?.[entity.device_id ?? "null"];
if (cardOptions?.hidden || deviceOptions?.hidden) {
continue;
}
areaCards.push(new cardModule[className](entity, cardOptions).getCard());
}
// Vertical stack the area cards if it has entities.
if (areaCards.length) {
const titleCardOptions = ("controllerCardOptions" in this.config) ? this.config.controllerCardOptions : {};
// Create and insert a Controller card.
areaCards.unshift(new ControllerCard(target, Object.assign({title: area.name}, titleCardOptions)).createCard());
viewCards.push({
type: "vertical-stack",
cards: areaCards,
} as StackCardConfig);
}
}
// Add a Controller Card for all the entities in the view.
if (this.viewControllerCard.cards.length && viewCards.length) {
viewCards.unshift(this.viewControllerCard);
}
return viewCards;
}
/**
* Get a view object.
*
* The view includes the cards which are created by method createViewCards().
*
* @returns {Promise<LovelaceViewConfig>} The view object.
*/
async getView(): Promise<LovelaceViewConfig> {
return {
...this.config,
cards: await this.createViewCards(),
};
}
/**
* Get a target of entity IDs for the given domain.
*
* @param {string} domain - The target domain to retrieve entity IDs from.
* @return {HassServiceTarget} - A target for a service call.
*/
targetDomain(domain: string): HassServiceTarget {
return {
entity_id: Helper.entities.filter(
entity =>
entity.entity_id.startsWith(domain + ".")
&& !entity.hidden_by
&& !Helper.strategyOptions.card_options?.[entity.entity_id]?.hidden
).map(entity => entity.entity_id),
};
}
}
export {AbstractView};