Optimize Views

- Make use of the debug module.
- Make use of the auxiliaries module.
- Make use of the localization module.
- Make use of the Registry module.
- Align code across the chip modules.
- Make configurations immutable.
- Make use of the refactored types.
This commit is contained in:
DigiLive
2025-04-23 07:55:29 +02:00
parent 5b02f20084
commit c1754ce598
10 changed files with 448 additions and 623 deletions

View File

@@ -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<LovelaceCardConfig[]> {
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<LovelaceViewConfig>} The view object.
* The configuration includes the card configurations which are created by createCardConfigurations().
*/
async getView(): Promise<LovelaceViewConfig> {
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;

View File

@@ -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",
/** Returns the default configuration object for the view. */
static getDefaultConfig(): ViewConfig {
return {
title: localize('camera.cameras'),
path: 'cameras',
icon: 'mdi:cctv',
subview: false,
controllerCardOptions: {
headerCardConfiguration: {
showControls: false,
},
};
}
/**
* Default configuration of the view's Controller card.
*
* @type {cards.ControllerCardOptions}
* @private
*/
#viewControllerCardConfig: cards.ControllerCardOptions = {
title: Helper.customLocalize("camera.all_cameras"),
/** Returns the default configuration of the view's Header card. */
static getViewHeaderCardConfig(): CustomHeaderCardConfig {
return {
title: localize('camera.all_cameras'),
subtitle:
`${Helper.getCountTemplate(CameraView.#domain, "ne", "off")} ${Helper.customLocalize("camera.cameras")} `
+ Helper.customLocalize("generic.busy"),
`${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;

View File

@@ -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",
/** Returns the default configuration object for the view. */
static getDefaultConfig(): ViewConfig {
return {
title: localize('climate.climates'),
path: 'climates',
icon: 'mdi:thermostat',
subview: false,
controllerCardOptions: {
headerCardConfiguration: {
showControls: false,
},
};
}
/**
* Default configuration of the view's Controller card.
*
* @type {cards.ControllerCardOptions}
* @private
*/
#viewControllerCardConfig: cards.ControllerCardOptions = {
title: Helper.customLocalize("climate.all_climates"),
/** Returns the default configuration of the view's Header card. */
static getViewHeaderCardConfig(): CustomHeaderCardConfig {
return {
title: localize('climate.all_climates'),
subtitle:
`${Helper.getCountTemplate(ClimateView.#domain, "ne", "off")} ${Helper.customLocalize("climate.climates")} `
+ Helper.customLocalize("generic.busy"),
`${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;

View File

@@ -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",
/** Returns the default configuration object for the view. */
static getDefaultConfig(): ViewConfig {
return {
title: localize('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",
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"),
/** Returns the default configuration of the view's Header card. */
static getViewHeaderCardConfig(): CustomHeaderCardConfig {
return {
title: localize('cover.all_covers'),
subtitle:
`${Helper.getCountTemplate(CoverView.#domain, "search", "(open|opening|closing)")} ${Helper.customLocalize("cover.covers")} `
+ Helper.customLocalize("generic.unclosed"),
`${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;

View File

@@ -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",
/** Returns the default configuration object for the view. */
static getDefaultConfig(): ViewConfig {
return {
title: localize('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",
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"),
/** Returns the default configuration of the view's Header card. */
static getViewHeaderCardConfig(): CustomHeaderCardConfig {
return {
title: localize('fan.all_fans'),
subtitle:
`${Helper.getCountTemplate(FanView.#domain, "eq", "on")} ${Helper.customLocalize("fan.fans")} `
+ Helper.customLocalize("generic.on"),
`${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;

View File

@@ -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",
/** 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<LovelaceCardConfig[]> {
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()

View File

@@ -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",
/** Returns the default configuration object for the view. */
static getDefaultConfig(): ViewConfig {
return {
title: localize('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",
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"),
/** Returns the default configuration of the view's Header card. */
static getViewHeaderCardConfig(): CustomHeaderCardConfig {
return {
title: localize('light.all_lights'),
subtitle:
`${Helper.getCountTemplate(LightView.#domain, "eq", "on")} ${Helper.customLocalize("light.lights")} `
+ Helper.customLocalize("generic.on"),
`${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;

View File

@@ -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",
/** Returns the default configuration object for the view. */
static getDefaultConfig(): ViewConfig {
return {
title: localize('scene.scenes'),
path: 'scenes',
icon: 'mdi:palette',
subview: false,
controllerCardOptions: {
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;

View File

@@ -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",
/** Returns the default configuration object for the view. */
static getDefaultConfig(): ViewConfig {
return {
title: localize('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",
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"),
/** Returns the default configuration of the view's Header card. */
static getViewHeaderCardConfig(): CustomHeaderCardConfig {
return {
title: localize('switch.all_switches'),
subtitle:
`${Helper.getCountTemplate(SwitchView.#domain, "eq", "on")} ${Helper.customLocalize("switch.switches")} `
+ Helper.customLocalize("generic.on"),
`${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;

View File

@@ -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",
/** Returns the default configuration object for the view. */
static getDefaultConfig(): ViewConfig {
return {
title: localize('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",
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"),
/** Returns the default configuration of the view's Header card. */
static getViewHeaderCardConfig(): CustomHeaderCardConfig {
return {
title: localize('vacuum.all_vacuums'),
subtitle:
`${Helper.getCountTemplate(VacuumView.#domain, "ne", "off")} ${Helper.customLocalize("vacuum.vacuums")} `
+ Helper.customLocalize("generic.busy"),
`${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;