Add options for all areas (#52)

Area identifier `_` sets the options for all areas.
Options for a specific area can still be overridden like before.

Also the HA area-card is added to use as a strategy area-card.

---------

Co-authored-by: DigiLive <info@digilive.nl>
This commit is contained in:
Johan Frick
2023-10-13 08:12:11 +02:00
committed by GitHub
parent 8311fa240c
commit 98ef9fed05
8 changed files with 152 additions and 42 deletions

View File

@@ -75,7 +75,7 @@ All the rounded cards can be configured using the Dashboard UI editor.
```yaml ```yaml
strategy: strategy:
type: custom:mushroom-strategy type: custom:mushroom-strategy
views: [ ] views: []
``` ```
### Hidding specific entities ### Hidding specific entities
@@ -133,7 +133,7 @@ strategy:
name: Family Room name: Family Room
icon: mdi:sofa icon: mdi:sofa
icon_color: green icon_color: green
views: [ ] views: []
``` ```
### Area Object ### Area Object
@@ -161,6 +161,7 @@ at the top of the area subview.
| `hidden` | boolean | false | Set to `true` to exclude the area from the dashboard and views. | | `hidden` | boolean | false | Set to `true` to exclude the area from the dashboard and views. |
| `order` | number | Infinity | Ordering position of the area in the list of available areas. | | `order` | number | Infinity | Ordering position of the area in the list of available areas. |
| `extra_cards` | array of cards | unset or empty | A list of cards to show on the top of the area subview. | | `extra_cards` | array of cards | unset or empty | A list of cards to show on the top of the area subview. |
| `type` | string | `default` | Set to a type of area card. (Currently supported: `default` & `HaAreaCard` |
*) `more-info` `toggle` `call-service` `navigate` `url` `none` *) `more-info` `toggle` `call-service` `navigate` `url` `none`
@@ -191,7 +192,9 @@ strategy:
order: 2 order: 2
garage_id: garage_id:
hidden: true hidden: true
views: [ ] hallway_id:
type: HaAreaCard
views: []
``` ```
#### Undisclosed Area #### Undisclosed Area
@@ -202,6 +205,22 @@ This area is enabled by default and includes the entities that aren't linked to
The area can be configured like any other area as described above. The area can be configured like any other area as described above.
To exclude this area from the dashboard and views, set its property `hidden` to `true`. To exclude this area from the dashboard and views, set its property `hidden` to `true`.
#### Setting options for all areas
Use `_` as an identifier to set the options for all areas.
The following example sets the type of all area-cards to Home Assistant's area card:
```yaml
strategy:
type: custom:mushroom-strategy
options:
areas:
_:
type: HaAreaCard
views: []
```
### Card Options ### Card Options
The `card_options` entry enables you to specify a card type for an entity or to hide the card from the dashboard. The `card_options` entry enables you to specify a card type for an entity or to hide the card from the dashboard.
@@ -222,7 +241,7 @@ strategy:
077ba0492c9bb3b31ffac34f1f3a626a: 077ba0492c9bb3b31ffac34f1f3a626a:
hidden: true hidden: true
views: [ ] views: []
``` ```
### Pre-built views ### Pre-built views
@@ -270,7 +289,7 @@ strategy:
order: 1 order: 1
hidden: true hidden: true
icon: mdi:toggle-switch icon: mdi:toggle-switch
views: [ ] views: []
``` ```
### Supported domains ### Supported domains
@@ -312,7 +331,7 @@ strategy:
showControls: false showControls: false
default: default:
hidden: true hidden: true
views: [ ] views: []
``` ```
### Chips ### Chips
@@ -475,7 +494,7 @@ strategy:
title: cool view title: cool view
path: cool-view path: cool-view
icon: mdi:emoticon-cool icon: mdi:emoticon-cool
badges: [ ] badges: []
cards: cards:
- type: markdown - type: markdown
content: I am cool content: I am cool

File diff suppressed because one or more lines are too long

View File

@@ -38,9 +38,15 @@ class AreaCard extends AbstractCard {
*/ */
constructor(area, options = {}) { constructor(area, options = {}) {
super(area); super(area);
this.#defaultOptions.primary = area.name; this.#defaultOptions.primary = area.name;
this.#defaultOptions.tap_action.navigation_path = area.area_id ?? area.name; this.#defaultOptions.tap_action.navigation_path = area.area_id ?? area.name;
// Set card type to default if a type "default" is given in strategy options.
if (options.type === "default") {
options.type = this.#defaultOptions.type;
}
this.mergeOptions( this.mergeOptions(
this.#defaultOptions, this.#defaultOptions,
options, options,

47
src/cards/HaAreaCard.js Normal file
View File

@@ -0,0 +1,47 @@
import {AbstractCard} from "./AbstractCard";
/**
* HA Area Card Class
*
* Used to create a card for an entity of the area domain using the built in type 'area'.
*
* @class
* @extends AbstractCard
*/
class AreaCard extends AbstractCard {
/**
* Default options of the card.
*
* @type {HaAreaCardOptions}
* @private
*/
#defaultOptions = {
type: "area",
area: undefined,
navigation_path: undefined,
};
/**
* Class constructor.
*
* @param {areaEntity} area The area entity to create a card for.
* @param {HaAreaCardOptions} [options={}] Options for the card.
* @throws {Error} If the Helper module isn't initialized.
*/
constructor(area, options = {}) {
super(area);
this.#defaultOptions.area = area.area_id ?? area.name;
this.#defaultOptions.navigation_path = area.area_id ?? area.name;
// Enforce the card type.
options.type = this.#defaultOptions.type;
this.mergeOptions(
this.#defaultOptions,
options,
);
}
}
export {AreaCard};

View File

@@ -112,6 +112,13 @@
* @memberOf typedefs.cards * @memberOf typedefs.cards
*/ */
/**
* @typedef {abstractOptions & Object} HaAreaCardOptions HA Area Card options.
* @property {string} area The id of the area.
* @property {string} navigation_path The id of the area to navigate to.
* @memberOf typedefs.cards
*/
/** /**
* @typedef {abstractOptions & Object} mediaPlayerCardOptions Media Player Card options. * @typedef {abstractOptions & Object} mediaPlayerCardOptions Media Player Card options.
* @property {boolean} [use_media_info=true] Use media info instead of name, state, and icon when a media is playing * @property {boolean} [use_media_info=true] Use media info instead of name, state, and icon when a media is playing

View File

@@ -191,7 +191,6 @@ class MushroomStrategy {
} }
if (!Helper.strategyOptions.domains.default.hidden) { if (!Helper.strategyOptions.domains.default.hidden) {
// TODO: Check if default is hidden
// Create cards for any other domain. // Create cards for any other domain.
// Collect device entities of the current area. // Collect device entities of the current area.
const areaDevices = Helper.devices.filter(device => device.area_id === area.area_id) const areaDevices = Helper.devices.filter(device => device.area_id === area.area_id)

View File

@@ -35,6 +35,7 @@
* @property {Object[]} [extra_cards] An array of card configurations. * @property {Object[]} [extra_cards] An array of card configurations.
* The configured cards are added to the dashboard. * The configured cards are added to the dashboard.
* This property is added by the custom strategy. * This property is added by the custom strategy.
* @property {boolean} [use_ha_area_card] Set to true to use ha area card instead of mushroom.
* @memberOf typedefs.generic * @memberOf typedefs.generic
*/ */

View File

@@ -82,9 +82,9 @@ class HomeView extends AbstractView {
// Add area cards. // Add area cards.
homeViewCards.push({ homeViewCards.push({
type: "vertical-stack", type: "vertical-stack",
cards: areaCards, cards: areaCards,
}); });
// Add custom cards. // Add custom cards.
if (options.extra_cards) { if (options.extra_cards) {
@@ -158,10 +158,10 @@ class HomeView extends AbstractView {
import("../cards/PersonCard").then(personModule => { import("../cards/PersonCard").then(personModule => {
for (const person of Helper.entities.filter(entity => { for (const person of Helper.entities.filter(entity => {
return entity.entity_id.startsWith("person.") return entity.entity_id.startsWith("person.")
&& entity.hidden_by == null && entity.hidden_by == null
&& entity.disabled_by == null && entity.disabled_by == null;
})) { })) {
cards.push(new personModule.PersonCard(person).getCard()); cards.push(new personModule.PersonCard(person).getCard());
} }
}); });
@@ -176,30 +176,61 @@ class HomeView extends AbstractView {
* *
* @return {Object[]} A card object array. * @return {Object[]} A card object array.
*/ */
#createAreaCards() { async #createAreaCards() {
const groupedCards = [{ /**
type: "custom:mushroom-title-card", * Cards to be stacked vertically.
title: "Areas", *
}]; * Contains a Title card and horizontal stacks of Area cards.
*
* @type {[{}]}
*/
const groupedCards = [
{
type: "custom:mushroom-title-card",
title: "Areas",
},
];
let areaCards = [];
import("../cards/AreaCard").then(areaModule => { for (const [i, area] of Helper.areas.entries()) {
const areaCards = []; let module;
let moduleName =
Helper.strategyOptions.areas[area.area_id ?? "undisclosed"]?.type ??
Helper.strategyOptions.areas["_"]?.type ??
"default";
for (const area of Helper.areas) { // Load module by type in strategy options.
if (!Helper.strategyOptions.areas[area.area_id]?.hidden) { try {
areaCards.push( module = await import((`../cards/${moduleName}`));
new areaModule.AreaCard(area, Helper.strategyOptions.areas[area.area_id ?? "undisclosed"]).getCard()); } catch (e) {
// Fallback to the default strategy card.
module = await import("../cards/AreaCard");
if (Helper.strategyOptions.debug && moduleName !== "default") {
console.error(e);
} }
} }
// Horizontally group every two area cards. // Get a card for the area.
for (let i = 0; i < areaCards.length; i += 2) { if (!Helper.strategyOptions.areas[area.area_id]?.hidden) {
groupedCards.push({ let options = {
type: "horizontal-stack", ...Helper.strategyOptions.areas["_"],
cards: areaCards.slice(i, i + 2), ...Helper.strategyOptions.areas[area.area_id ?? "undisclosed"],
}); };
areaCards.push(new module.AreaCard(area, options).getCard());
} }
});
// Horizontally group every two area cards if all cards are created.
if (i === Helper.areas.length - 1) {
for (let i = 0; i < areaCards.length; i += 2) {
groupedCards.push({
type: "horizontal-stack",
cards: areaCards.slice(i, i + 2),
});
}
}
}
return groupedCards; return groupedCards;
} }