diff --git a/src/views/AbstractView.ts b/src/views/AbstractView.ts index 28e7d13..7cb72aa 100644 --- a/src/views/AbstractView.ts +++ b/src/views/AbstractView.ts @@ -1,171 +1,159 @@ -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; +import { HassServiceTarget } from 'home-assistant-js-websocket'; +import HeaderCard from '../cards/HeaderCard'; +import { Registry } from '../Registry'; +import { LovelaceCardConfig } from '../types/homeassistant/data/lovelace/config/card'; +import { LovelaceViewConfig } from '../types/homeassistant/data/lovelace/config/view'; +import { StackCardConfig } from '../types/homeassistant/panels/lovelace/cards/types'; +import { AbstractCardConfig, CustomHeaderCardConfig, StrategyHeaderCardConfig } from '../types/strategy/strategy-cards'; +import { SupportedDomains } from '../types/strategy/strategy-generics'; +import { ViewConfig, ViewConstructor } from '../types/strategy/strategy-views'; +import { sanitizeClassName } from '../utilities/auxiliaries'; +import { logMessage, lvlFatal } from '../utilities/debug'; +import RegistryFilter from '../utilities/RegistryFilter'; /** * Abstract View Class. * - * To create a new view, extend the new class with this one. + * To create a view configuration, this class should be extended by a child class. + * Child classes should override the default configuration so the view correctly reflects the entities of a domain. * - * @class - * @abstract + * @remarks + * Before this class can be used, the Registry module must be initialized by calling {@link Registry.initialize}. */ abstract class AbstractView { - /** - * Configuration of the view. - * - * @type {LovelaceViewConfig} - */ - config: LovelaceViewConfig = { - icon: "mdi:view-dashboard", + /** The base configuration of a view. */ + protected baseConfiguration: LovelaceViewConfig = { + icon: 'mdi:view-dashboard', subview: false, }; - /** - * A card to switch all entities in the view. - * - * @type {StackCardConfig} - */ - viewControllerCard: StackCardConfig = { + /** A card configuration to control all entities in the view. */ + private viewHeaderCardConfiguration: StackCardConfig = { cards: [], - type: "", + type: '', }; - /** - * The domain of which we operate the devices. - * - * @type {SupportedDomains | "home"} - * @private - * @readonly - */ - readonly #domain: SupportedDomains | "home"; + protected get domain(): SupportedDomains | 'home' { + return (this.constructor as unknown as ViewConstructor).domain; + } /** * 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. + * @remarks + * Before this class can be used, the Registry module must be initialized by calling {@link Registry.initialize}. */ - protected constructor(domain: SupportedDomains | "home") { - if (!Helper.isInitialized()) { - throw new Error("The Helper module must be initialized before using this one."); + protected constructor() { + if (!Registry.initialized) { + logMessage(lvlFatal, 'Registry not initialized!'); } - - this.#domain = domain; } /** - * Create the cards to include in the view. - * - * @returns {Promise<(StackCardConfig | TitleCardConfig)[]>} An array of card objects. + * Create the configuration of the cards to include in the view. */ - 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. + protected async createCardConfigurations(): Promise { + if (this.domain === 'home') { + // The home domain should override this method because it hasn't entities of its own. + // The method override creates its own configurations for cards to show at the home view. return []; } const viewCards: LovelaceCardConfig[] = []; + const domainEntities = new RegistryFilter(Registry.entities).whereDomain(this.domain).toList(); + const moduleName = sanitizeClassName(this.domain + 'Card'); + const DomainCard = (await import(`../cards/${moduleName}`)).default; - // 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}`); + // Create card configurations for each area. + for (const area of Registry.areas) { + const areaCards: AbstractCardConfig[] = []; - // Set the target for controller cards to the current area. + // Set the target of the Header card to the current area. let target: HassServiceTarget = { area_id: [area.area_id], }; + const areaEntities = new RegistryFilter(domainEntities).whereAreaId(area.area_id).toList(); - 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") { + // Set the target of the Header card to entities without an area. + if (area.area_id === 'undisclosed') { target = { - entity_id: entities.map(entity => entity.entity_id), - } + entity_id: areaEntities.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"]; + // Create a card configuration for each entity in the current area. + areaCards.push( + ...areaEntities.map((entity) => + new DomainCard(entity, Registry.strategyOptions.card_options?.[entity.entity_id]).getCard(), + ), + ); - if (cardOptions?.hidden || deviceOptions?.hidden) { - continue; - } - - areaCards.push(new cardModule[className](entity, cardOptions).getCard()); - } - - // Vertical stack the area cards if it has entities. + // Vertically stack the cards of the current area. if (areaCards.length) { - const titleCardOptions = ("controllerCardOptions" in this.config) ? this.config.controllerCardOptions : {}; + const areaHeaderCardOptions = ( + 'headerCardConfiguration' in this.baseConfiguration ? this.baseConfiguration.headerCardConfiguration : {} + ) as CustomHeaderCardConfig; - // Create and insert a Controller card. - areaCards.unshift(new ControllerCard(target, Object.assign({title: area.name}, titleCardOptions)).createCard()); + // Create and insert a Header card. + areaCards.unshift(new HeaderCard(target, { title: area.name, ...areaHeaderCardOptions }).createCard()); - viewCards.push({ - type: "vertical-stack", - cards: areaCards, - } as StackCardConfig); + viewCards.push({ type: 'vertical-stack', cards: areaCards }); } } - // Add a Controller Card for all the entities in the view. - if (this.viewControllerCard.cards.length && viewCards.length) { - viewCards.unshift(this.viewControllerCard); + // Add a Header Card to control all the entities in the view. + if (this.viewHeaderCardConfiguration.cards.length && viewCards.length) { + viewCards.unshift(this.viewHeaderCardConfiguration); } return viewCards; } /** - * Get a view object. + * Get a view configuration. * - * The view includes the cards which are created by method createViewCards(). - * - * @returns {Promise} The view object. + * The configuration includes the card configurations which are created by createCardConfigurations(). */ async getView(): Promise { return { - ...this.config, - cards: await this.createViewCards(), + ...this.baseConfiguration, + cards: await this.createCardConfigurations(), }; } /** - * Get a target of entity IDs for the given domain. - * - * @param {string} domain - The target domain to retrieve entity IDs from. - * @returns {HassServiceTarget} - A target for a service call. + * Get the domain's entity ids to target for a HASS service call. */ - targetDomain(domain: string): HassServiceTarget { + private getDomainTargets(): 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), + entity_id: Registry.entities + .filter((entity) => entity.entity_id.startsWith(this.domain + '.')) + .map((entity) => entity.entity_id), }; } + + /** + * Initialize the view configuration with defaults and custom settings. + * + * @param viewConfiguration The view's default configuration for the view. + * @param customConfiguration The view's custom configuration to apply. + * @param headerCardConfig The view's Header card configuration. + */ + protected initializeViewConfig( + viewConfiguration: ViewConfig, + customConfiguration: ViewConfig = {}, + headerCardConfig: CustomHeaderCardConfig, + ): void { + this.baseConfiguration = { ...this.baseConfiguration, ...viewConfiguration, ...customConfiguration }; + + this.viewHeaderCardConfiguration = new HeaderCard(this.getDomainTargets(), { + ...(('headerCardConfiguration' in this.baseConfiguration + ? this.baseConfiguration.headerCardConfiguration + : {}) as StrategyHeaderCardConfig), + ...headerCardConfig, + }).createCard(); + } } -export {AbstractView}; +export default AbstractView; diff --git a/src/views/CameraView.ts b/src/views/CameraView.ts index 1fd2005..0674cac 100644 --- a/src/views/CameraView.ts +++ b/src/views/CameraView.ts @@ -1,77 +1,54 @@ -import {ControllerCard} from "../cards/ControllerCard"; -import {AbstractView} from "./AbstractView"; -import {views} from "../types/strategy/views"; -import {cards} from "../types/strategy/cards"; -import {Helper} from "../Helper"; -import {generic} from "../types/strategy/generic"; -import SupportedDomains = generic.SupportedDomains; - // noinspection JSUnusedGlobalSymbols Class is dynamically imported. + +import { Registry } from '../Registry'; +import { CustomHeaderCardConfig } from '../types/strategy/strategy-cards'; +import { SupportedDomains } from '../types/strategy/strategy-generics'; +import { ViewConfig } from '../types/strategy/strategy-views'; +import { localize } from '../utilities/localize'; +import AbstractView from './AbstractView'; + /** * Camera View Class. * - * Used to create a view for entities of the camera domain. - * - * @class CameraView - * @extends AbstractView + * Used to create a view configuration for entities of the camera domain. */ class CameraView extends AbstractView { - /** - * Domain of the view's entities. - * - * @type {SupportedDomains} - * @static - * @private - */ - static #domain: SupportedDomains = "camera"; + /** The domain of the entities that the view is representing. */ + static readonly domain: SupportedDomains = 'camera' as const; - /** - * Default configuration of the view. - * - * @type {views.ViewConfig} - * @private - */ - #defaultConfig: views.ViewConfig = { - title: Helper.customLocalize("camera.cameras"), - path: "cameras", - icon: "mdi:cctv", - subview: false, - controllerCardOptions: { - showControls: false, - }, - }; + /** Returns the default configuration object for the view. */ + static getDefaultConfig(): ViewConfig { + return { + title: localize('camera.cameras'), + path: 'cameras', + icon: 'mdi:cctv', + subview: false, + headerCardConfiguration: { + showControls: false, + }, + }; + } - /** - * Default configuration of the view's Controller card. - * - * @type {cards.ControllerCardOptions} - * @private - */ - #viewControllerCardConfig: cards.ControllerCardOptions = { - title: Helper.customLocalize("camera.all_cameras"), - subtitle: - `${Helper.getCountTemplate(CameraView.#domain, "ne", "off")} ${Helper.customLocalize("camera.cameras")} ` - + Helper.customLocalize("generic.busy"), - }; + /** Returns the default configuration of the view's Header card. */ + static getViewHeaderCardConfig(): CustomHeaderCardConfig { + return { + title: localize('camera.all_cameras'), + subtitle: + `${Registry.getCountTemplate(CameraView.domain, 'ne', 'off')} ${localize('camera.cameras')} ` + + localize('generic.busy'), + }; + } /** * Class constructor. * - * @param {views.ViewConfig} [options={}] Options for the view. + * @param {ViewConfig} [customConfiguration] Custom view configuration. */ - constructor(options: views.ViewConfig = {}) { - super(CameraView.#domain); + constructor(customConfiguration?: ViewConfig) { + super(); - this.config = Object.assign(this.config, this.#defaultConfig, options); - - // Create a Controller card to switch all entities of the domain. - this.viewControllerCard = new ControllerCard( - {}, - { - ...this.#viewControllerCardConfig, - ...("controllerCardOptions" in this.config ? this.config.controllerCardOptions : {}) as cards.ControllerCardConfig, - }).createCard(); + this.initializeViewConfig(CameraView.getDefaultConfig(), customConfiguration, CameraView.getViewHeaderCardConfig()); } } -export {CameraView}; +export default CameraView; diff --git a/src/views/ClimateView.ts b/src/views/ClimateView.ts index dfd458a..7853567 100644 --- a/src/views/ClimateView.ts +++ b/src/views/ClimateView.ts @@ -1,77 +1,58 @@ -import {Helper} from "../Helper"; -import {ControllerCard} from "../cards/ControllerCard"; -import {AbstractView} from "./AbstractView"; -import {views} from "../types/strategy/views"; -import {cards} from "../types/strategy/cards"; -import {generic} from "../types/strategy/generic"; -import SupportedDomains = generic.SupportedDomains; - // noinspection JSUnusedGlobalSymbols Class is dynamically imported. + +import { Registry } from '../Registry'; +import { CustomHeaderCardConfig } from '../types/strategy/strategy-cards'; +import { SupportedDomains } from '../types/strategy/strategy-generics'; +import { ViewConfig } from '../types/strategy/strategy-views'; +import { localize } from '../utilities/localize'; +import AbstractView from './AbstractView'; + /** * Climate View Class. * - * Used to create a view for entities of the climate domain. - * - * @class ClimateView - * @extends AbstractView + * Used to create a view configuration for entities of the climate domain. */ class ClimateView extends AbstractView { - /** - * Domain of the view's entities. - * - * @type {SupportedDomains} - * @static - * @private - */ - static #domain: SupportedDomains = "climate"; + /**The domain of the entities that the view is representing. */ + static readonly domain: SupportedDomains = 'climate' as const; - /** - * Default configuration of the view. - * - * @type {views.ViewConfig} - * @private - */ - #defaultConfig: views.ViewConfig = { - title: Helper.customLocalize("climate.climates"), - path: "climates", - icon: "mdi:thermostat", - subview: false, - controllerCardOptions: { - showControls: false, - }, - }; + /** Returns the default configuration object for the view. */ + static getDefaultConfig(): ViewConfig { + return { + title: localize('climate.climates'), + path: 'climates', + icon: 'mdi:thermostat', + subview: false, + headerCardConfiguration: { + showControls: false, + }, + }; + } - /** - * Default configuration of the view's Controller card. - * - * @type {cards.ControllerCardOptions} - * @private - */ - #viewControllerCardConfig: cards.ControllerCardOptions = { - title: Helper.customLocalize("climate.all_climates"), - subtitle: - `${Helper.getCountTemplate(ClimateView.#domain, "ne", "off")} ${Helper.customLocalize("climate.climates")} ` - + Helper.customLocalize("generic.busy"), - }; + /** Returns the default configuration of the view's Header card. */ + static getViewHeaderCardConfig(): CustomHeaderCardConfig { + return { + title: localize('climate.all_climates'), + subtitle: + `${Registry.getCountTemplate(ClimateView.domain, 'ne', 'off')} ${localize('climate.climates')} ` + + localize('generic.busy'), + }; + } /** * Class constructor. * - * @param {views.ViewConfig} [options={}] Options for the view. + * @param {ViewConfig} [customConfiguration] Custom view configuration. */ - constructor(options: views.ViewConfig = {}) { - super(ClimateView.#domain); + constructor(customConfiguration?: ViewConfig) { + super(); - this.config = Object.assign(this.config, this.#defaultConfig, options); - - // Create a Controller card to switch all entities of the domain. - this.viewControllerCard = new ControllerCard( - this.targetDomain(ClimateView.#domain), - { - ...this.#viewControllerCardConfig, - ...("controllerCardOptions" in this.config ? this.config.controllerCardOptions : {}) as cards.ControllerCardConfig, - }).createCard(); + this.initializeViewConfig( + ClimateView.getDefaultConfig(), + customConfiguration, + ClimateView.getViewHeaderCardConfig(), + ); } } -export {ClimateView}; +export default ClimateView; diff --git a/src/views/CoverView.ts b/src/views/CoverView.ts index de576e4..78ec2f6 100644 --- a/src/views/CoverView.ts +++ b/src/views/CoverView.ts @@ -1,80 +1,58 @@ -import {Helper} from "../Helper"; -import {ControllerCard} from "../cards/ControllerCard"; -import {AbstractView} from "./AbstractView"; -import {views} from "../types/strategy/views"; -import {cards} from "../types/strategy/cards"; -import {generic} from "../types/strategy/generic"; -import SupportedDomains = generic.SupportedDomains; - // noinspection JSUnusedGlobalSymbols Class is dynamically imported. + +import { Registry } from '../Registry'; +import { CustomHeaderCardConfig } from '../types/strategy/strategy-cards'; +import { SupportedDomains } from '../types/strategy/strategy-generics'; +import { ViewConfig } from '../types/strategy/strategy-views'; +import { localize } from '../utilities/localize'; +import AbstractView from './AbstractView'; + /** * Cover View Class. * - * Used to create a view for entities of the cover domain. - * - * @class CoverView - * @extends AbstractView + * Used to create a view configuration for entities of the cover domain. */ class CoverView extends AbstractView { - /** - * Domain of the view's entities. - * - * @type {SupportedDomains} - * @static - * @private - */ - static #domain: SupportedDomains = "cover"; + /** The domain of the entities that the view is representing. */ + static readonly domain: SupportedDomains = 'cover' as const; - /** - * Default configuration of the view. - * - * @type {views.ViewConfig} - * @private - */ - #defaultConfig: views.ViewConfig = { - title: Helper.customLocalize("cover.covers"), - path: "covers", - icon: "mdi:window-open", - subview: false, - controllerCardOptions: { - iconOn: "mdi:arrow-up", - iconOff: "mdi:arrow-down", - onService: "cover.open_cover", - offService: "cover.close_cover", - }, - }; + /** Returns the default configuration object for the view. */ + static getDefaultConfig(): ViewConfig { + return { + title: localize('cover.covers'), + path: 'covers', + icon: 'mdi:window-open', + subview: false, + headerCardConfiguration: { + iconOn: 'mdi:arrow-up', + iconOff: 'mdi:arrow-down', + onService: 'cover.open_cover', + offService: 'cover.close_cover', + }, + }; + } - /** - * Default configuration of the view's Controller card. - * - * @type {cards.ControllerCardOptions} - * @private - */ - #viewControllerCardConfig: cards.ControllerCardOptions = { - title: Helper.customLocalize("cover.all_covers"), - subtitle: - `${Helper.getCountTemplate(CoverView.#domain, "search", "(open|opening|closing)")} ${Helper.customLocalize("cover.covers")} ` - + Helper.customLocalize("generic.unclosed"), - }; + /** Returns the default configuration of the view's Header card. */ + static getViewHeaderCardConfig(): CustomHeaderCardConfig { + return { + title: localize('cover.all_covers'), + subtitle: + `${Registry.getCountTemplate(CoverView.domain, 'search', '(open|opening|closing)')} ` + + `${localize('cover.covers')} ` + + `${localize('generic.unclosed')}`, + }; + } /** * Class constructor. * - * @param {views.ViewConfig} [options={}] Options for the view. + * @param {ViewConfig} [customConfiguration] Custom view configuration. */ - constructor(options: views.ViewConfig = {}) { - super(CoverView.#domain); + constructor(customConfiguration?: ViewConfig) { + super(); - this.config = Object.assign(this.config, this.#defaultConfig, options); - - // Create a Controller card to switch all entities of the domain. - this.viewControllerCard = new ControllerCard( - this.targetDomain(CoverView.#domain), - { - ...this.#viewControllerCardConfig, - ...("controllerCardOptions" in this.config ? this.config.controllerCardOptions : {}) as cards.ControllerCardConfig, - }).createCard(); + this.initializeViewConfig(CoverView.getDefaultConfig(), customConfiguration, CoverView.getViewHeaderCardConfig()); } } -export {CoverView}; +export default CoverView; diff --git a/src/views/FanView.ts b/src/views/FanView.ts index 3cdd259..17997bb 100644 --- a/src/views/FanView.ts +++ b/src/views/FanView.ts @@ -1,80 +1,56 @@ -import {Helper} from "../Helper"; -import {ControllerCard} from "../cards/ControllerCard"; -import {AbstractView} from "./AbstractView"; -import {views} from "../types/strategy/views"; -import {cards} from "../types/strategy/cards"; -import {generic} from "../types/strategy/generic"; -import SupportedDomains = generic.SupportedDomains; - // noinspection JSUnusedGlobalSymbols Class is dynamically imported. + +import { Registry } from '../Registry'; +import { CustomHeaderCardConfig } from '../types/strategy/strategy-cards'; +import { SupportedDomains } from '../types/strategy/strategy-generics'; +import { ViewConfig } from '../types/strategy/strategy-views'; +import { localize } from '../utilities/localize'; +import AbstractView from './AbstractView'; + /** * Fan View Class. * - * Used to create a view for entities of the fan domain. - * - * @class FanView - * @extends AbstractView + * Used to create a view configuration for entities of the fan domain. */ class FanView extends AbstractView { - /** - * Domain of the view's entities. - * - * @type {SupportedDomains} - * @static - * @private - */ - static #domain: SupportedDomains = "fan"; + /** The domain of the entities that the view is representing. */ + static readonly domain: SupportedDomains = 'fan' as const; - /** - * Default configuration of the view. - * - * @type {views.ViewConfig} - * @private - */ - #defaultConfig: views.ViewConfig = { - title: Helper.customLocalize("fan.fans"), - path: "fans", - icon: "mdi:fan", - subview: false, - controllerCardOptions: { - iconOn: "mdi:fan", - iconOff: "mdi:fan-off", - onService: "fan.turn_on", - offService: "fan.turn_off", - }, - }; + /** Returns the default configuration object for the view. */ + static getDefaultConfig(): ViewConfig { + return { + title: localize('fan.fans'), + path: 'fans', + icon: 'mdi:fan', + subview: false, + headerCardConfiguration: { + iconOn: 'mdi:fan', + iconOff: 'mdi:fan-off', + onService: 'fan.turn_on', + offService: 'fan.turn_off', + }, + }; + } - /** - * Default configuration of the view's Controller card. - * - * @type {cards.ControllerCardOptions} - * @private - */ - #viewControllerCardConfig: cards.ControllerCardOptions = { - title: Helper.customLocalize("fan.all_fans"), - subtitle: - `${Helper.getCountTemplate(FanView.#domain, "eq", "on")} ${Helper.customLocalize("fan.fans")} ` - + Helper.customLocalize("generic.on"), - }; + /** Returns the default configuration of the view's Header card. */ + static getViewHeaderCardConfig(): CustomHeaderCardConfig { + return { + title: localize('fan.all_fans'), + subtitle: + `${Registry.getCountTemplate(FanView.domain, 'eq', 'on')} ${localize('fan.fans')} ` + localize('generic.on'), + }; + } /** * Class constructor. * - * @param {views.ViewConfig} [options={}] Options for the view. + * @param {ViewConfig} [customConfiguration] Custom view configuration. */ - constructor(options: views.ViewConfig = {}) { - super(FanView.#domain); + constructor(customConfiguration?: ViewConfig) { + super(); - this.config = Object.assign(this.config, this.#defaultConfig, options); - - // Create a Controller card to switch all entities of the domain. - this.viewControllerCard = new ControllerCard( - this.targetDomain(FanView.#domain), - { - ...this.#viewControllerCardConfig, - ...("controllerCardOptions" in this.config ? this.config.controllerCardOptions : {}) as cards.ControllerCardConfig, - }).createCard(); + this.initializeViewConfig(FanView.getDefaultConfig(), customConfiguration, FanView.getViewHeaderCardConfig()); } } -export {FanView}; +export default FanView; diff --git a/src/views/HomeView.ts b/src/views/HomeView.ts index 38bf83c..c37ebe7 100644 --- a/src/views/HomeView.ts +++ b/src/views/HomeView.ts @@ -1,65 +1,71 @@ -import {Helper} from "../Helper"; -import {AbstractView} from "./AbstractView"; -import {views} from "../types/strategy/views"; -import {LovelaceChipConfig} from "../types/lovelace-mushroom/utils/lovelace/chip/types"; -import {ChipsCardConfig} from "../types/lovelace-mushroom/cards/chips-card"; -import {TemplateCardConfig} from "../types/lovelace-mushroom/cards/template-card-config"; -import {ActionConfig} from "../types/homeassistant/data/lovelace"; -import {TitleCardConfig} from "../types/lovelace-mushroom/cards/title-card-config"; -import {PersonCardConfig} from "../types/lovelace-mushroom/cards/person-card-config"; -import {AreaCardConfig, StackCardConfig} from "../types/homeassistant/panels/lovelace/cards/types"; -import {generic} from "../types/strategy/generic"; -import supportedChips = generic.SupportedChips; - - // noinspection JSUnusedGlobalSymbols Class is dynamically imported. + +import { Registry } from '../Registry'; +import { ActionConfig } from '../types/homeassistant/data/lovelace/config/action'; +import { LovelaceCardConfig } from '../types/homeassistant/data/lovelace/config/card'; +import { AreaCardConfig, StackCardConfig } from '../types/homeassistant/panels/lovelace/cards/types'; +import { ChipsCardConfig } from '../types/lovelace-mushroom/cards/chips-card'; +import { PersonCardConfig } from '../types/lovelace-mushroom/cards/person-card-config'; +import { TemplateCardConfig } from '../types/lovelace-mushroom/cards/template-card-config'; +import { LovelaceChipConfig } from '../types/lovelace-mushroom/utils/lovelace/chip/types'; +import { HomeViewSections, isSupportedChip } from '../types/strategy/strategy-generics'; +import { ViewConfig } from '../types/strategy/strategy-views'; +import { sanitizeClassName } from '../utilities/auxiliaries'; +import { logMessage, lvlError } from '../utilities/debug'; +import { localize } from '../utilities/localize'; +import AbstractView from './AbstractView'; + /** * Home View Class. * * Used to create a Home view. - * - * @class HomeView - * @extends AbstractView */ class HomeView extends AbstractView { - /** - * Default configuration of the view. - * - * @type {views.ViewConfig} - * @private - */ - #defaultConfig: views.ViewConfig = { - title: Helper.customLocalize("generic.home"), - icon: "mdi:home-assistant", - path: "home", - subview: false, - }; + /** The domain of the entities that the view is representing. */ + static readonly domain = 'home' as const; + + /** Returns the default configuration object for the view. */ + static getDefaultConfig(): ViewConfig { + return { + title: localize('generic.home'), + icon: 'mdi:home-assistant', + path: 'home', + subview: false, + }; + } /** * Class constructor. * - * @param {views.ViewConfig} [options={}] Options for the view. + * @param {ViewConfig} [customConfiguration] Custom view configuration. */ - constructor(options: views.ViewConfig = {}) { - super("home"); + constructor(customConfiguration?: ViewConfig) { + super(); - this.config = Object.assign(this.config, this.#defaultConfig, options); + this.baseConfiguration = { ...this.baseConfiguration, ...HomeView.getDefaultConfig(), ...customConfiguration }; } /** - * Create the cards to include in the view. + * Create the configuration of the cards to include in the view. * - * @returns {Promise<(StackCardConfig | TemplateCardConfig | ChipsCardConfig)[]>} Promise a View Card array. * @override */ - async createViewCards(): Promise<(StackCardConfig | TemplateCardConfig | ChipsCardConfig)[]> { - return await Promise.all([ - this.#createChips(), - this.#createPersonCards(), - this.#createAreaSection(), - ]).then(([chips, personCards, areaCards]) => { - const options = Helper.strategyOptions; - const homeViewCards = []; + async createCardConfigurations(): Promise { + const homeViewCards: LovelaceCardConfig[] = []; + + let chipsSection, personsSection, areasSection; + + try { + [chipsSection, personsSection, areasSection] = await Promise.all([ + this.createChipsSection(), + this.createPersonsSection(), + this.createAreasSection(), + ]); + } catch (e) { + logMessage(lvlError, 'Error importing created sections!', e); + + return homeViewCards; + } if (chips.length) { // TODO: Create the Chip card at this.#createChips() diff --git a/src/views/LightView.ts b/src/views/LightView.ts index 90f2cde..7aa0f24 100644 --- a/src/views/LightView.ts +++ b/src/views/LightView.ts @@ -1,12 +1,11 @@ -import {Helper} from "../Helper"; -import {ControllerCard} from "../cards/ControllerCard"; -import {AbstractView} from "./AbstractView"; -import {views} from "../types/strategy/views"; -import {cards} from "../types/strategy/cards"; -import {generic} from "../types/strategy/generic"; -import SupportedDomains = generic.SupportedDomains; - // noinspection JSUnusedGlobalSymbols Class is dynamically imported. + +import { Registry } from '../Registry'; +import { CustomHeaderCardConfig } from '../types/strategy/strategy-cards'; +import { ViewConfig } from '../types/strategy/strategy-views'; +import { localize } from '../utilities/localize'; +import AbstractView from './AbstractView'; + /** * Light View Class. * @@ -16,65 +15,40 @@ import SupportedDomains = generic.SupportedDomains; * @extends AbstractView */ class LightView extends AbstractView { - /** - * Domain of the view's entities. - * - * @type {SupportedDomains} - * @static - * @private - */ - static #domain: SupportedDomains = "light"; + /** The domain of the entities that the view is representing. */ + static readonly domain = 'light' as const; - /** - * Default configuration of the view. - * - * @type {views.ViewConfig} - * @private - */ - #defaultConfig: views.ViewConfig = { - title: Helper.customLocalize("light.lights"), - path: "lights", - icon: "mdi:lightbulb-group", - subview: false, - controllerCardOptions: { - iconOn: "mdi:lightbulb", - iconOff: "mdi:lightbulb-off", - onService: "light.turn_on", - offService: "light.turn_off", - }, - }; + /** Returns the default configuration object for the view. */ + static getDefaultConfig(): ViewConfig { + return { + title: localize('light.lights'), + path: 'lights', + icon: 'mdi:lightbulb-group', + subview: false, + headerCardConfiguration: { + iconOn: 'mdi:lightbulb', + iconOff: 'mdi:lightbulb-off', + onService: 'light.turn_on', + offService: 'light.turn_off', + }, + }; + } - /** - * Default configuration of the view's Controller card. - * - * @type {cards.ControllerCardOptions} - * @private - */ - #viewControllerCardConfig: cards.ControllerCardOptions = { - title: Helper.customLocalize("light.all_lights"), - subtitle: - `${Helper.getCountTemplate(LightView.#domain, "eq", "on")} ${Helper.customLocalize("light.lights")} ` - + Helper.customLocalize("generic.on"), - }; + /** Returns the default configuration of the view's Header card. */ + static getViewHeaderCardConfig(): CustomHeaderCardConfig { + return { + title: localize('light.all_lights'), + subtitle: + `${Registry.getCountTemplate(LightView.domain, 'eq', 'on')} ${localize('light.lights')} ` + + localize('generic.on'), + }; + } - /** - * Class constructor. - * - * @param {views.ViewConfig} [options={}] Options for the view. - */ - constructor(options: views.ViewConfig = {}) { - super(LightView.#domain); + constructor(customConfiguration?: ViewConfig) { + super(); - this.config = Object.assign(this.config, this.#defaultConfig, options); - - // Create a Controller card to switch all entities of the domain. - this.viewControllerCard = new ControllerCard( - this.targetDomain(LightView.#domain), - { - ...this.#viewControllerCardConfig, - ...("controllerCardOptions" in this.config ? this.config.controllerCardOptions : {}) as cards.ControllerCardConfig, - }).createCard(); + this.initializeViewConfig(LightView.getDefaultConfig(), customConfiguration, LightView.getViewHeaderCardConfig()); } } -export {LightView}; +export default LightView; diff --git a/src/views/SceneView.ts b/src/views/SceneView.ts index 613352e..f741415 100644 --- a/src/views/SceneView.ts +++ b/src/views/SceneView.ts @@ -1,54 +1,47 @@ -import {Helper} from "../Helper"; -import {AbstractView} from "./AbstractView"; -import {views} from "../types/strategy/views"; -import {generic} from "../types/strategy/generic"; -import SupportedDomains = generic.SupportedDomains; - // noinspection JSUnusedGlobalSymbols Class is dynamically imported. + +import { CustomHeaderCardConfig } from '../types/strategy/strategy-cards'; +import { ViewConfig } from '../types/strategy/strategy-views'; +import { localize } from '../utilities/localize'; +import AbstractView from './AbstractView'; + /** * Scene View Class. * - * Used to create a view for entities of the scene domain. - * - * @class SceneView - * @extends AbstractView + * sed to create a view configuration for entities of the scene domain. */ class SceneView extends AbstractView { - /** - * Domain of the view's entities. - * - * @type {SupportedDomains} - * @static - * @private - */ - static #domain: SupportedDomains = "scene"; + /** The domain of the entities that the view is representing. */ + static readonly domain = 'scene' as const; - /** - * Default configuration of the view. - * - * @type {views.ViewConfig} - * @private - */ - #defaultConfig: views.ViewConfig = { - title: Helper.customLocalize("scene.scenes"), - path: "scenes", - icon: "mdi:palette", - subview: false, - controllerCardOptions: { - showControls: false, - }, - }; + /** Returns the default configuration object for the view. */ + static getDefaultConfig(): ViewConfig { + return { + title: localize('scene.scenes'), + path: 'scenes', + icon: 'mdi:palette', + subview: false, + headerCardConfiguration: { + showControls: false, + }, + }; + } + + /** Returns the default configuration of the view's Header card. */ + static getViewHeaderCardConfig(): CustomHeaderCardConfig { + return {}; + } /** * Class constructor. * - * @param {views.ViewConfig} [options={}] Options for the view. + * @param {ViewConfig} [customConfiguration] Custom view configuration. */ - constructor(options: views.ViewConfig = {}) { - super(SceneView.#domain); + constructor(customConfiguration?: ViewConfig) { + super(); - this.config = Object.assign(this.config, this.#defaultConfig, options); + this.initializeViewConfig(SceneView.getDefaultConfig(), customConfiguration, SceneView.getViewHeaderCardConfig()); } } -export {SceneView}; +export default SceneView; diff --git a/src/views/SwitchView.ts b/src/views/SwitchView.ts index 9df4c07..bb10dc1 100644 --- a/src/views/SwitchView.ts +++ b/src/views/SwitchView.ts @@ -1,80 +1,56 @@ -import {Helper} from "../Helper"; -import {ControllerCard} from "../cards/ControllerCard"; -import {AbstractView} from "./AbstractView"; -import {views} from "../types/strategy/views"; -import {cards} from "../types/strategy/cards"; -import {generic} from "../types/strategy/generic"; -import SupportedDomains = generic.SupportedDomains; - // noinspection JSUnusedGlobalSymbols Class is dynamically imported. + +import { Registry } from '../Registry'; +import { CustomHeaderCardConfig } from '../types/strategy/strategy-cards'; +import { ViewConfig } from '../types/strategy/strategy-views'; +import { localize } from '../utilities/localize'; +import AbstractView from './AbstractView'; + /** * Switch View Class. * - * Used to create a view for entities of the switch domain. - * - * @class SwitchView - * @extends AbstractView + * Used to create a view configuration for entities of the switch domain. */ class SwitchView extends AbstractView { - /** - * Domain of the view's entities. - * - * @type {SupportedDomains} - * @static - * @private - */ - static #domain: SupportedDomains = "switch"; + /** The domain of the entities that the view is representing. */ + static readonly domain = 'switch' as const; - /** - * Default configuration of the view. - * - * @type {views.ViewConfig} - * @private - */ - #defaultConfig: views.ViewConfig = { - title: Helper.customLocalize("switch.switches"), - path: "switches", - icon: "mdi:dip-switch", - subview: false, - controllerCardOptions: { - iconOn: "mdi:power-plug", - iconOff: "mdi:power-plug-off", - onService: "switch.turn_on", - offService: "switch.turn_off", - }, - }; + /** Returns the default configuration object for the view. */ + static getDefaultConfig(): ViewConfig { + return { + title: localize('switch.switches'), + path: 'switches', + icon: 'mdi:dip-switch', + subview: false, + headerCardConfiguration: { + iconOn: 'mdi:power-plug', + iconOff: 'mdi:power-plug-off', + onService: 'switch.turn_on', + offService: 'switch.turn_off', + }, + }; + } - /** - * Default configuration of the view's Controller card. - * - * @type {cards.ControllerCardOptions} - * @private - */ - #viewControllerCardConfig: cards.ControllerCardOptions = { - title: Helper.customLocalize("switch.all_switches"), - subtitle: - `${Helper.getCountTemplate(SwitchView.#domain, "eq", "on")} ${Helper.customLocalize("switch.switches")} ` - + Helper.customLocalize("generic.on"), - }; + /** Returns the default configuration of the view's Header card. */ + static getViewHeaderCardConfig(): CustomHeaderCardConfig { + return { + title: localize('switch.all_switches'), + subtitle: + `${Registry.getCountTemplate(SwitchView.domain, 'eq', 'on')} ${localize('switch.switches')} ` + + localize('generic.on'), + }; + } /** * Class constructor. * - * @param {views.ViewConfig} [options={}] Options for the view. + * @param {ViewConfig} [customConfiguration] Custom view configuration. */ - constructor(options: views.ViewConfig = {}) { - super(SwitchView.#domain); + constructor(customConfiguration?: ViewConfig) { + super(); - this.config = Object.assign(this.config, this.#defaultConfig, options); - - // Create a Controller card to switch all entities of the domain. - this.viewControllerCard = new ControllerCard( - this.targetDomain(SwitchView.#domain), - { - ...this.#viewControllerCardConfig, - ...("controllerCardOptions" in this.config ? this.config.controllerCardOptions : {}) as cards.ControllerCardConfig, - }).createCard(); + this.initializeViewConfig(SwitchView.getDefaultConfig(), customConfiguration, SwitchView.getViewHeaderCardConfig()); } } -export {SwitchView}; +export default SwitchView; diff --git a/src/views/VacuumView.ts b/src/views/VacuumView.ts index 819e932..8e4d3f7 100644 --- a/src/views/VacuumView.ts +++ b/src/views/VacuumView.ts @@ -1,80 +1,56 @@ -import {Helper} from "../Helper"; -import {ControllerCard} from "../cards/ControllerCard"; -import {AbstractView} from "./AbstractView"; -import {views} from "../types/strategy/views"; -import {cards} from "../types/strategy/cards"; -import {generic} from "../types/strategy/generic"; -import SupportedDomains = generic.SupportedDomains; - // noinspection JSUnusedGlobalSymbols Class is dynamically imported. + +import { Registry } from '../Registry'; +import { CustomHeaderCardConfig } from '../types/strategy/strategy-cards'; +import { ViewConfig } from '../types/strategy/strategy-views'; +import { localize } from '../utilities/localize'; +import AbstractView from './AbstractView'; + /** * Vacuum View Class. * - * Used to create a view for entities of the vacuum domain. - * - * @class VacuumView - * @extends AbstractView + * Used to create a view configuration for entities of the vacuum domain. */ class VacuumView extends AbstractView { - /** - * Domain of the view's entities. - * - * @type {SupportedDomains} - * @static - * @private - */ - static #domain: SupportedDomains = "vacuum"; + /** The domain of the entities that the view is representing. */ + static readonly domain = 'vacuum' as const; - /** - * Default configuration of the view. - * - * @type {views.ViewConfig} - * @private - */ - #defaultConfig: views.ViewConfig = { - title: Helper.customLocalize("vacuum.vacuums"), - path: "vacuums", - icon: "mdi:robot-vacuum", - subview: false, - controllerCardOptions: { - iconOn: "mdi:robot-vacuum", - iconOff: "mdi:robot-vacuum-off", - onService: "vacuum.start", - offService: "vacuum.stop", - }, - }; + /** Returns the default configuration object for the view. */ + static getDefaultConfig(): ViewConfig { + return { + title: localize('vacuum.vacuums'), + path: 'vacuums', + icon: 'mdi:robot-vacuum', + subview: false, + headerCardConfiguration: { + iconOn: 'mdi:robot-vacuum', + iconOff: 'mdi:robot-vacuum-off', + onService: 'vacuum.start', + offService: 'vacuum.stop', + }, + }; + } - /** - * Default configuration of the view's Controller card. - * - * @type {cards.ControllerCardOptions} - * @private - */ - #viewControllerCardConfig: cards.ControllerCardOptions = { - title: Helper.customLocalize("vacuum.all_vacuums"), - subtitle: - `${Helper.getCountTemplate(VacuumView.#domain, "ne", "off")} ${Helper.customLocalize("vacuum.vacuums")} ` - + Helper.customLocalize("generic.busy"), - }; + /** Returns the default configuration of the view's Header card. */ + static getViewHeaderCardConfig(): CustomHeaderCardConfig { + return { + title: localize('vacuum.all_vacuums'), + subtitle: + `${Registry.getCountTemplate(VacuumView.domain, 'ne', 'off')} ${localize('vacuum.vacuums')} ` + + localize('generic.busy'), + }; + } /** * Class constructor. * - * @param {views.ViewConfig} [options={}] Options for the view. + * @param {ViewConfig} [customConfiguration] Custom view configuration. */ - constructor(options: views.ViewConfig = {}) { - super(VacuumView.#domain); + constructor(customConfiguration?: ViewConfig) { + super(); - this.config = Object.assign(this.config, this.#defaultConfig, options); - - // Create a Controller card to switch all entities of the domain. - this.viewControllerCard = new ControllerCard( - this.targetDomain(VacuumView.#domain), - { - ...this.#viewControllerCardConfig, - ...("controllerCardOptions" in this.config ? this.config.controllerCardOptions : {}) as cards.ControllerCardConfig, - }).createCard(); + this.initializeViewConfig(VacuumView.getDefaultConfig(), customConfiguration, VacuumView.getViewHeaderCardConfig()); } } -export {VacuumView}; +export default VacuumView;