forked from DigiLive/mushroom-strategy
Merge branch 'add-cards-per-row' into add-device-view
# Conflicts: # README.md # dist/mushroom-strategy.js # package-lock.json # package.json # src/Registry.ts # src/cards/HeaderCard.ts # src/configurationDefaults.ts # src/mushroom-strategy.ts # src/types/strategy/strategy-cards.ts # src/types/strategy/strategy-generics.ts # src/utilities/RegistryFilter.ts # src/views/AbstractView.ts # src/views/CameraView.ts # src/views/HomeView.ts # src/views/VacuumView.ts
This commit is contained in:
14
.github/PULL_REQUEST_TEMPLATE/bugfix.md
vendored
14
.github/PULL_REQUEST_TEMPLATE/bugfix.md
vendored
@ -5,7 +5,7 @@ Please fill out the following information to help us review your pull request.
|
||||
|
||||
---
|
||||
|
||||
### Bug Summary
|
||||
## Bug Summary
|
||||
|
||||
Explain why this fix is needed and what problem it solves.
|
||||
If it relates to an existing issue, please link it.
|
||||
@ -15,7 +15,7 @@ See [Linking a pull request to an issue](https://docs.github.com/en/issues/track
|
||||
|
||||
---
|
||||
|
||||
### Motivation and Context
|
||||
## Motivation and Context
|
||||
|
||||
Explain why this bug needs to be fixed and the impact it has on the project or users.
|
||||
|
||||
@ -23,20 +23,20 @@ Explain why this bug needs to be fixed and the impact it has on the project or u
|
||||
|
||||
---
|
||||
|
||||
### List of Changes
|
||||
## List of Changes
|
||||
|
||||
[Provide a concise list of the main changes introduced by this pull request to fix the bug.]
|
||||
|
||||
- ...
|
||||
|
||||
### Steps to Reproduce (if not covered in the linked issue)
|
||||
## Steps to Reproduce (if not covered in the linked issue)
|
||||
|
||||
If the steps to reproduce the bug are not clearly outlined in the linked issue, please provide them here:
|
||||
|
||||
1. ...
|
||||
2. ...
|
||||
|
||||
### Expected Behavior (if not covered in the linked issue)
|
||||
## Expected Behavior (if not covered in the linked issue)
|
||||
|
||||
Describe what the expected behavior should have been before the bug occurred.
|
||||
|
||||
@ -50,13 +50,13 @@ Describe the actual behavior that occurred due to the bug.
|
||||
|
||||
---
|
||||
|
||||
### Wiki Updates
|
||||
## Wiki Updates
|
||||
|
||||
[If this bug fix requires any updates to the Wiki, please provide details here.]
|
||||
|
||||
---
|
||||
|
||||
### Agreements
|
||||
## Agreements
|
||||
|
||||
Please confirm the following by inserting an `x` between the brackets:
|
||||
|
||||
|
10
.github/PULL_REQUEST_TEMPLATE/feature.md
vendored
10
.github/PULL_REQUEST_TEMPLATE/feature.md
vendored
@ -5,13 +5,13 @@ Please fill out the following information to help us review your pull request.
|
||||
|
||||
---
|
||||
|
||||
### Feature Summary
|
||||
## Feature Summary
|
||||
|
||||
[Briefly describe the feature you are proposing]
|
||||
|
||||
---
|
||||
|
||||
### Motivation and Context
|
||||
## Motivation and Context
|
||||
|
||||
Explain why this feature is needed and what problem it solves.
|
||||
If it relates to an existing issue, please link it.
|
||||
@ -21,19 +21,19 @@ See [Linking a pull request to an issue](https://docs.github.com/en/issues/track
|
||||
|
||||
---
|
||||
|
||||
### List of Changes
|
||||
## List of Changes
|
||||
|
||||
[Provide a concise list of the main changes introduced by this pull request.]
|
||||
|
||||
- ...
|
||||
|
||||
### Wiki Updates
|
||||
## Wiki Updates
|
||||
|
||||
[If this bug feature requires any updates to the Wiki, please provide details here.]
|
||||
|
||||
---
|
||||
|
||||
### Agreements
|
||||
## Agreements
|
||||
|
||||
Please confirm the following by inserting an `x` between the brackets:
|
||||
|
||||
|
14
.github/PULL_REQUEST_TEMPLATE/translation.md
vendored
14
.github/PULL_REQUEST_TEMPLATE/translation.md
vendored
@ -5,7 +5,7 @@ Please fill out the following information to help us review your translation cha
|
||||
|
||||
---
|
||||
|
||||
### Type of Translation Contribution
|
||||
## Type of Translation Contribution
|
||||
|
||||
Please select the type of contribution:
|
||||
|
||||
@ -15,7 +15,7 @@ Please select the type of contribution:
|
||||
|
||||
---
|
||||
|
||||
### Target Language
|
||||
## Target Language
|
||||
|
||||
Please specify the language you are adding or modifying:
|
||||
|
||||
@ -23,7 +23,7 @@ Please specify the language you are adding or modifying:
|
||||
|
||||
---
|
||||
|
||||
### Motivation and Context
|
||||
## Motivation and Context
|
||||
|
||||
Explain why this translation (addition, fix, or update) is needed.
|
||||
- For fixes, please describe the original error.
|
||||
@ -33,7 +33,7 @@ Explain why this translation (addition, fix, or update) is needed.
|
||||
|
||||
---
|
||||
|
||||
### Scope of Changes
|
||||
## Scope of Changes
|
||||
|
||||
Please describe the scope of your translation changes.
|
||||
Which parts of the project are affected by these translations?
|
||||
@ -42,7 +42,7 @@ Which parts of the project are affected by these translations?
|
||||
|
||||
---
|
||||
|
||||
### List of Changes
|
||||
## List of Changes
|
||||
|
||||
Provide a concise list of the main changes you've made in this pull request.
|
||||
If it's a large update, you can highlight key areas.
|
||||
@ -51,7 +51,7 @@ If it's a large update, you can highlight key areas.
|
||||
|
||||
---
|
||||
|
||||
### Considerations for Reviewers
|
||||
## Considerations for Reviewers
|
||||
|
||||
Are there any specific areas you would like reviewers to pay extra attention to?
|
||||
For example, specific terminology, cultural nuances, or consistency with existing translations.
|
||||
@ -60,7 +60,7 @@ For example, specific terminology, cultural nuances, or consistency with existin
|
||||
|
||||
---
|
||||
|
||||
### Agreements
|
||||
## Agreements
|
||||
|
||||
Please confirm the following:
|
||||
|
||||
|
26
.github/dependabot.yml
vendored
Normal file
26
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
groups:
|
||||
dependencies:
|
||||
patterns: ["*"]
|
||||
labels:
|
||||
- "dependencies"
|
||||
pull-request-branch-name:
|
||||
separator: "-"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
groups:
|
||||
actions:
|
||||
patterns: ["*"]
|
||||
labels:
|
||||
- "actions"
|
||||
pull-request-branch-name:
|
||||
separator: "-"
|
2
.github/workflows/validate.yml
vendored
2
.github/workflows/validate.yml
vendored
@ -9,6 +9,6 @@ jobs:
|
||||
runs-on: "ubuntu-latest"
|
||||
steps:
|
||||
- name: HACS Action
|
||||
uses: "hacs/action@main"
|
||||
uses: "hacs/action@22.5.0"
|
||||
with:
|
||||
category: "plugin"
|
||||
|
19
.github/workflows/webpack.yml
vendored
19
.github/workflows/webpack.yml
vendored
@ -11,24 +11,29 @@ on:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build Distribution
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CI_COMMIT_MESSAGE: Continuous Integration - Build Distribution
|
||||
CI_COMMIT_MESSAGE: |
|
||||
Continuous Integration - Build Distribution
|
||||
|
||||
[skip codacy]
|
||||
CI_COMMIT_AUTHOR: Continuous Integration
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [ 18.x ]
|
||||
node-version: [22.x]
|
||||
|
||||
# Checkout Repository
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.WORKFLOW_GIT_ACCESS_TOKEN }}
|
||||
|
||||
# Build steps
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v3
|
||||
- name: Setup Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
@ -44,9 +49,9 @@ jobs:
|
||||
run: |
|
||||
git diff --quiet . || echo "changed=true" >> $GITHUB_OUTPUT
|
||||
|
||||
# Commit and push all changed files.
|
||||
# Commit and push all changed files.
|
||||
# Must only affect files that are listed in "paths-ignore".
|
||||
- name: GIT Commit Distribution Build
|
||||
- name: Commit Distribution Build
|
||||
# Only run on a main branch push (e.g., pull request merge).
|
||||
if: github.event_name == 'push' && steps.checkDiff.outputs.changed == 'true'
|
||||
run: |
|
||||
|
@ -153,7 +153,7 @@ Enhancement suggestions are tracked as [GitHub issues][issuesUrl].
|
||||
|
||||
### Code Contribution
|
||||
|
||||
You can contribute to this project by following the _fork → clone → edit → pull request_ workflow of GitHub.
|
||||
You can contribute to this project by following the *fork → clone → edit → pull request* workflow of GitHub.
|
||||
|
||||
#### Prevent changes to the distribution directory
|
||||
|
||||
|
23
README.md
23
README.md
@ -1,7 +1,8 @@
|
||||
# Mushroom dashboard strategy
|
||||
|
||||
[![release][releaseBadge]][releaseUrl]
|
||||
[![hacs][hacsBadge]][hacsUrl]
|
||||
[![Release][releaseBadge]][releaseUrl]
|
||||
[![HACS][hacsBadge]][hacsUrl]
|
||||
[![Codacy][codacyBadge]][codacyUrl]
|
||||
|
||||

|
||||
|
||||
@ -26,10 +27,10 @@ For easy access, separate views are generated for entities which belong to speci
|
||||
|
||||
### Features
|
||||
|
||||
- 🛠 Automatically create a dashboard with three lines of YAML.
|
||||
- 😍 Built-in Views for device-specific controls.
|
||||
- 🎨 Many options to customize to fit your needs.
|
||||
- 📈 [Mini graph][miniGraphUrl] cards for sensor entities.
|
||||
* 🛠 Automatically create a dashboard with three lines of YAML.
|
||||
* 😍 Built-in Views for device-specific controls.
|
||||
* 🎨 Many options to customize to fit your needs.
|
||||
* 📈 [Mini graph][miniGraphUrl] cards for sensor entities.
|
||||
|
||||
> [!TIP]
|
||||
> If you like this package, please star the [project at GitHub][repositoryUrl]!
|
||||
@ -59,17 +60,21 @@ Visit the [issues][issuesUrl] page.
|
||||
|
||||
<!-- Badge References -->
|
||||
|
||||
[codacyBadge]: https://app.codacy.com/project/badge/Grade/24de1e79aea445499917d9acd5ce9e04
|
||||
|
||||
[hacsBadge]: https://img.shields.io/badge/HACS-Default-blue
|
||||
|
||||
[releaseBadge]: https://img.shields.io/github/v/tag/digilive/mushroom-strategy?filter=v2.3.3-alpha.1&label=Release
|
||||
|
||||
[sponsorBadge]: https://img.shields.io/badge/Sponsor_him-%E2%9D%A4-%23db61a2.svg?&logo=github&color=%23fe8e86
|
||||
|
||||
[releaseBadge]: https://img.shields.io/github/v/tag/digilive/mushroom-strategy?filter=v2.3.0-alpha.1&label=Release
|
||||
|
||||
<!-- Repository References -->
|
||||
|
||||
[codacyUrl]: https://app.codacy.com/gh/DigiLive/mushroom-strategy/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade
|
||||
|
||||
[repositoryUrl]: https://github.com/DigiLive/mushroom-strategy
|
||||
|
||||
[releaseUrl]: https://github.com/DigiLive/mushroom-strategy/releases/tag/v2.3.0-alpha.1
|
||||
[releaseUrl]: https://github.com/DigiLive/mushroom-strategy/releases/tag/v2.3.3-alpha.1
|
||||
|
||||
[issuesUrl]: https://github.com/DigiLive/mushroom-strategy/issues
|
||||
|
||||
|
182
package-lock.json
generated
182
package-lock.json
generated
@ -1,22 +1,22 @@
|
||||
{
|
||||
"name": "mushroom-strategy",
|
||||
"version": "2.3.0-alpha.1",
|
||||
"version": "2.3.3-alpha.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "mushroom-strategy",
|
||||
"version": "2.3.0-alpha.1",
|
||||
"version": "2.3.2",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"deepmerge": "^4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^8.31.0",
|
||||
"@typescript-eslint/parser": "^8.31.0",
|
||||
"eslint": "^9.25.1",
|
||||
"eslint-config-prettier": "^10.1.2",
|
||||
"eslint-plugin-prettier": "^5.2.6",
|
||||
"@typescript-eslint/eslint-plugin": "^8.32.1",
|
||||
"@typescript-eslint/parser": "^8.32.1",
|
||||
"eslint": "^9.27.0",
|
||||
"eslint-config-prettier": "^10.1.5",
|
||||
"eslint-plugin-prettier": "^5.4.0",
|
||||
"home-assistant-js-websocket": "^9.5.0",
|
||||
"prettier": "^3.5.3",
|
||||
"superstruct": "^2.0.2",
|
||||
@ -24,7 +24,7 @@
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.8.3",
|
||||
"version-bump-prompt": "^6",
|
||||
"webpack": "^5.99.7",
|
||||
"webpack": "^5.99.8",
|
||||
"webpack-cli": "^6.0.1"
|
||||
},
|
||||
"funding": {
|
||||
@ -65,9 +65,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint-community/eslint-utils": {
|
||||
"version": "4.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.6.1.tgz",
|
||||
"integrity": "sha512-KTsJMmobmbrFLe3LDh0PC2FXpcSYJt/MLjlkh/9LEnmKYLSYmT/0EW9JWANjeoemiuZrmogti0tW5Ch+qNUYDw==",
|
||||
"version": "4.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz",
|
||||
"integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -143,9 +143,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/core": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz",
|
||||
"integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==",
|
||||
"version": "0.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz",
|
||||
"integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
@ -204,13 +204,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/js": {
|
||||
"version": "9.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.25.1.tgz",
|
||||
"integrity": "sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==",
|
||||
"version": "9.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.27.0.tgz",
|
||||
"integrity": "sha512-G5JD9Tu5HJEu4z2Uo4aHY2sLV64B7CDMXxFzqzjl3NKd6RVzSXNoE80jk7Y0lJkTTkjiIhBAqmlYwjuBY3tvpA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://eslint.org/donate"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/object-schema": {
|
||||
@ -224,13 +227,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/plugin-kit": {
|
||||
"version": "0.2.8",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz",
|
||||
"integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==",
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.1.tgz",
|
||||
"integrity": "sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@eslint/core": "^0.13.0",
|
||||
"@eslint/core": "^0.14.0",
|
||||
"levn": "^0.4.1"
|
||||
},
|
||||
"engines": {
|
||||
@ -520,21 +523,21 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "8.31.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.31.0.tgz",
|
||||
"integrity": "sha512-evaQJZ/J/S4wisevDvC1KFZkPzRetH8kYZbkgcTRyql3mcKsf+ZFDV1BVWUGTCAW5pQHoqn5gK5b8kn7ou9aFQ==",
|
||||
"version": "8.32.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.1.tgz",
|
||||
"integrity": "sha512-6u6Plg9nP/J1GRpe/vcjjabo6Uc5YQPAMxsgQyGC/I0RuukiG1wIe3+Vtg3IrSCVJDmqK3j8adrtzXSENRtFgg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.10.0",
|
||||
"@typescript-eslint/scope-manager": "8.31.0",
|
||||
"@typescript-eslint/type-utils": "8.31.0",
|
||||
"@typescript-eslint/utils": "8.31.0",
|
||||
"@typescript-eslint/visitor-keys": "8.31.0",
|
||||
"@typescript-eslint/scope-manager": "8.32.1",
|
||||
"@typescript-eslint/type-utils": "8.32.1",
|
||||
"@typescript-eslint/utils": "8.32.1",
|
||||
"@typescript-eslint/visitor-keys": "8.32.1",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.3.1",
|
||||
"ignore": "^7.0.0",
|
||||
"natural-compare": "^1.4.0",
|
||||
"ts-api-utils": "^2.0.1"
|
||||
"ts-api-utils": "^2.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -549,17 +552,27 @@
|
||||
"typescript": ">=4.8.4 <5.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.4.tgz",
|
||||
"integrity": "sha512-gJzzk+PQNznz8ysRrC0aOkBNVRBDtE1n53IqyqEf3PXrYwomFs5q4pGMizBMJF+ykh03insJ27hB8gSrD2Hn8A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "8.31.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.31.0.tgz",
|
||||
"integrity": "sha512-67kYYShjBR0jNI5vsf/c3WG4u+zDnCTHTPqVMQguffaWWFs7artgwKmfwdifl+r6XyM5LYLas/dInj2T0SgJyw==",
|
||||
"version": "8.32.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.32.1.tgz",
|
||||
"integrity": "sha512-LKMrmwCPoLhM45Z00O1ulb6jwyVr2kr3XJp+G+tSEZcbauNnScewcQwtJqXDhXeYPDEjZ8C1SjXm015CirEmGg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.31.0",
|
||||
"@typescript-eslint/types": "8.31.0",
|
||||
"@typescript-eslint/typescript-estree": "8.31.0",
|
||||
"@typescript-eslint/visitor-keys": "8.31.0",
|
||||
"@typescript-eslint/scope-manager": "8.32.1",
|
||||
"@typescript-eslint/types": "8.32.1",
|
||||
"@typescript-eslint/typescript-estree": "8.32.1",
|
||||
"@typescript-eslint/visitor-keys": "8.32.1",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@ -575,14 +588,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "8.31.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.31.0.tgz",
|
||||
"integrity": "sha512-knO8UyF78Nt8O/B64i7TlGXod69ko7z6vJD9uhSlm0qkAbGeRUSudcm0+K/4CrRjrpiHfBCjMWlc08Vav1xwcw==",
|
||||
"version": "8.32.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.32.1.tgz",
|
||||
"integrity": "sha512-7IsIaIDeZn7kffk7qXC3o6Z4UblZJKV3UBpkvRNpr5NSyLji7tvTcvmnMNYuYLyh26mN8W723xpo3i4MlD33vA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.31.0",
|
||||
"@typescript-eslint/visitor-keys": "8.31.0"
|
||||
"@typescript-eslint/types": "8.32.1",
|
||||
"@typescript-eslint/visitor-keys": "8.32.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -593,16 +606,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "8.31.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.31.0.tgz",
|
||||
"integrity": "sha512-DJ1N1GdjI7IS7uRlzJuEDCgDQix3ZVYVtgeWEyhyn4iaoitpMBX6Ndd488mXSx0xah/cONAkEaYyylDyAeHMHg==",
|
||||
"version": "8.32.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.32.1.tgz",
|
||||
"integrity": "sha512-mv9YpQGA8iIsl5KyUPi+FGLm7+bA4fgXaeRcFKRDRwDMu4iwrSHeDPipwueNXhdIIZltwCJv+NkxftECbIZWfA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "8.31.0",
|
||||
"@typescript-eslint/utils": "8.31.0",
|
||||
"@typescript-eslint/typescript-estree": "8.32.1",
|
||||
"@typescript-eslint/utils": "8.32.1",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^2.0.1"
|
||||
"ts-api-utils": "^2.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -617,9 +630,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "8.31.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.31.0.tgz",
|
||||
"integrity": "sha512-Ch8oSjVyYyJxPQk8pMiP2FFGYatqXQfQIaMp+TpuuLlDachRWpUAeEu1u9B/v/8LToehUIWyiKcA/w5hUFRKuQ==",
|
||||
"version": "8.32.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.32.1.tgz",
|
||||
"integrity": "sha512-YmybwXUJcgGqgAp6bEsgpPXEg6dcCyPyCSr0CAAueacR/CCBi25G3V8gGQ2kRzQRBNol7VQknxMs9HvVa9Rvfg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@ -631,20 +644,20 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.31.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.31.0.tgz",
|
||||
"integrity": "sha512-xLmgn4Yl46xi6aDSZ9KkyfhhtnYI15/CvHbpOy/eR5NWhK/BK8wc709KKwhAR0m4ZKRP7h07bm4BWUYOCuRpQQ==",
|
||||
"version": "8.32.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.32.1.tgz",
|
||||
"integrity": "sha512-Y3AP9EIfYwBb4kWGb+simvPaqQoT5oJuzzj9m0i6FCY6SPvlomY2Ei4UEMm7+FXtlNJbor80ximyslzaQF6xhg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.31.0",
|
||||
"@typescript-eslint/visitor-keys": "8.31.0",
|
||||
"@typescript-eslint/types": "8.32.1",
|
||||
"@typescript-eslint/visitor-keys": "8.32.1",
|
||||
"debug": "^4.3.4",
|
||||
"fast-glob": "^3.3.2",
|
||||
"is-glob": "^4.0.3",
|
||||
"minimatch": "^9.0.4",
|
||||
"semver": "^7.6.0",
|
||||
"ts-api-utils": "^2.0.1"
|
||||
"ts-api-utils": "^2.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -658,16 +671,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.31.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.31.0.tgz",
|
||||
"integrity": "sha512-qi6uPLt9cjTFxAb1zGNgTob4x9ur7xC6mHQJ8GwEzGMGE9tYniublmJaowOJ9V2jUzxrltTPfdG2nKlWsq0+Ww==",
|
||||
"version": "8.32.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.32.1.tgz",
|
||||
"integrity": "sha512-DsSFNIgLSrc89gpq1LJB7Hm1YpuhK086DRDJSNrewcGvYloWW1vZLHBTIvarKZDcAORIy/uWNx8Gad+4oMpkSA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"@typescript-eslint/scope-manager": "8.31.0",
|
||||
"@typescript-eslint/types": "8.31.0",
|
||||
"@typescript-eslint/typescript-estree": "8.31.0"
|
||||
"@eslint-community/eslint-utils": "^4.7.0",
|
||||
"@typescript-eslint/scope-manager": "8.32.1",
|
||||
"@typescript-eslint/types": "8.32.1",
|
||||
"@typescript-eslint/typescript-estree": "8.32.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@ -682,13 +695,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "8.31.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.31.0.tgz",
|
||||
"integrity": "sha512-QcGHmlRHWOl93o64ZUMNewCdwKGU6WItOU52H0djgNmn1EOrhVudrDzXz4OycCRSCPwFCDrE2iIt5vmuUdHxuQ==",
|
||||
"version": "8.32.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.32.1.tgz",
|
||||
"integrity": "sha512-ar0tjQfObzhSaW3C3QNmTc5ofj0hDoNQ5XWrCy6zDyabdr0TWhCkClp+rywGNj/odAFBVzzJrK4tEq5M4Hmu4w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.31.0",
|
||||
"@typescript-eslint/types": "8.32.1",
|
||||
"eslint-visitor-keys": "^4.2.0"
|
||||
},
|
||||
"engines": {
|
||||
@ -1481,9 +1494,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "9.25.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.25.1.tgz",
|
||||
"integrity": "sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ==",
|
||||
"version": "9.27.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.27.0.tgz",
|
||||
"integrity": "sha512-ixRawFQuMB9DZ7fjU3iGGganFDp3+45bPOdaRurcFHSXO1e/sYwUX/FtQZpLZJR6SjMoJH8hR2pPEAfDyCoU2Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -1491,10 +1504,10 @@
|
||||
"@eslint-community/regexpp": "^4.12.1",
|
||||
"@eslint/config-array": "^0.20.0",
|
||||
"@eslint/config-helpers": "^0.2.1",
|
||||
"@eslint/core": "^0.13.0",
|
||||
"@eslint/core": "^0.14.0",
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
"@eslint/js": "9.25.1",
|
||||
"@eslint/plugin-kit": "^0.2.8",
|
||||
"@eslint/js": "9.27.0",
|
||||
"@eslint/plugin-kit": "^0.3.1",
|
||||
"@humanfs/node": "^0.16.6",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
"@humanwhocodes/retry": "^0.4.2",
|
||||
@ -1542,22 +1555,25 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-config-prettier": {
|
||||
"version": "10.1.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.2.tgz",
|
||||
"integrity": "sha512-Epgp/EofAUeEpIdZkW60MHKvPyru1ruQJxPL+WIycnaPApuseK0Zpkrh/FwL9oIpQvIhJwV7ptOy0DWUjTlCiA==",
|
||||
"version": "10.1.5",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.5.tgz",
|
||||
"integrity": "sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"eslint-config-prettier": "bin/cli.js"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://opencollective.com/eslint-config-prettier"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-prettier": {
|
||||
"version": "5.2.6",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.6.tgz",
|
||||
"integrity": "sha512-mUcf7QG2Tjk7H055Jk0lGBjbgDnfrvqjhXh9t2xLMSCjZVcw9Rb1V6sVNXO0th3jgeO7zllWPTNRil3JW94TnQ==",
|
||||
"version": "5.4.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.4.0.tgz",
|
||||
"integrity": "sha512-BvQOvUhkVQM1i63iMETK9Hjud9QhqBnbtT1Zc642p9ynzBuCe5pybkOnvqZIBypXmMlsGcnU4HZ8sCTPfpAexA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -3612,9 +3628,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.99.7",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.7.tgz",
|
||||
"integrity": "sha512-CNqKBRMQjwcmKR0idID5va1qlhrqVUKpovi+Ec79ksW8ux7iS1+A6VqzfZXgVYCFRKl7XL5ap3ZoMpwBJxcg0w==",
|
||||
"version": "5.99.8",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.8.tgz",
|
||||
"integrity": "sha512-lQ3CPiSTpfOnrEGeXDwoq5hIGzSjmwD72GdfVzF7CQAI7t47rJG9eDWvcEkEn3CUQymAElVvDg3YNTlCYj+qUQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
14
package.json
14
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mushroom-strategy",
|
||||
"version": "2.3.0-alpha.1",
|
||||
"version": "2.3.3-alpha.1",
|
||||
"description": "Automatically generate a dashboard of Mushroom cards.",
|
||||
"keywords": [
|
||||
"dashboard",
|
||||
@ -30,11 +30,11 @@
|
||||
"deepmerge": "^4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^8.31.0",
|
||||
"@typescript-eslint/parser": "^8.31.0",
|
||||
"eslint": "^9.25.1",
|
||||
"eslint-config-prettier": "^10.1.2",
|
||||
"eslint-plugin-prettier": "^5.2.6",
|
||||
"@typescript-eslint/eslint-plugin": "^8.32.1",
|
||||
"@typescript-eslint/parser": "^8.32.1",
|
||||
"eslint": "^9.27.0",
|
||||
"eslint-config-prettier": "^10.1.5",
|
||||
"eslint-plugin-prettier": "^5.4.0",
|
||||
"home-assistant-js-websocket": "^9.5.0",
|
||||
"prettier": "^3.5.3",
|
||||
"superstruct": "^2.0.2",
|
||||
@ -42,7 +42,7 @@
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.8.3",
|
||||
"version-bump-prompt": "^6",
|
||||
"webpack": "^5.99.7",
|
||||
"webpack": "^5.99.8",
|
||||
"webpack-cli": "^6.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
|
@ -187,7 +187,7 @@ class Registry {
|
||||
}));
|
||||
|
||||
// Process entries of the HASS area registry.
|
||||
if (Registry.strategyOptions.areas._?.hidden) {
|
||||
if (Registry.strategyOptions.areas._.hidden) {
|
||||
Registry._areas = [];
|
||||
} else {
|
||||
// Create and add the undisclosed area if not hidden in the strategy options.
|
||||
@ -201,8 +201,9 @@ class Registry {
|
||||
return { ...area, ...Registry.strategyOptions.areas['_'], ...Registry.strategyOptions.areas?.[area.area_id] };
|
||||
});
|
||||
|
||||
// Ensure the custom configuration of the undisclosed area doesn't overwrite the area_id.
|
||||
// Ensure the custom configuration of the undisclosed area doesn't overwrite the required property values.
|
||||
Registry._strategyOptions.areas.undisclosed.area_id = 'undisclosed';
|
||||
Registry.strategyOptions.areas.undisclosed.type = 'default';
|
||||
|
||||
// Remove hidden areas if configured as so and sort them by name.
|
||||
|
||||
|
@ -28,8 +28,8 @@ class AreaCard extends AbstractCard {
|
||||
configuration.tap_action.navigation_path = area.area_id;
|
||||
}
|
||||
|
||||
// Don't override the default card type if default is set in the strategy options.
|
||||
if (customConfig && customConfig.type === 'default') {
|
||||
// Don't override the card type if set differently in the strategy options.
|
||||
if (customConfig) {
|
||||
customConfig = { ...customConfig, type: configuration.type };
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,9 @@ import { localize } from './utilities/localize';
|
||||
*/
|
||||
export const ConfigurationDefaults: StrategyDefaults = {
|
||||
areas: {
|
||||
_: {
|
||||
type: 'AreaCard',
|
||||
},
|
||||
undisclosed: {
|
||||
// TODO: Refactor undisclosed to other.
|
||||
aliases: [],
|
||||
@ -43,11 +46,14 @@ export const ConfigurationDefaults: StrategyDefaults = {
|
||||
_: {
|
||||
hide_config_entities: undefined,
|
||||
hide_diagnostic_entities: undefined,
|
||||
showControls: true,
|
||||
stack_count: 1,
|
||||
},
|
||||
binary_sensor: {
|
||||
title: `${localize('sensor.binary')} ` + localize('sensor.sensors'),
|
||||
showControls: false,
|
||||
hidden: false,
|
||||
stack_count: 2, // TODO: Add to wiki. also for other configurations.
|
||||
},
|
||||
camera: {
|
||||
title: localize('camera.cameras'),
|
||||
@ -169,6 +175,9 @@ export const ConfigurationDefaults: StrategyDefaults = {
|
||||
extra_views: [],
|
||||
home_view: {
|
||||
hidden: [],
|
||||
stack_count: {
|
||||
_: 2,
|
||||
},
|
||||
},
|
||||
views: {
|
||||
camera: {
|
||||
|
@ -124,6 +124,6 @@ async function main() {
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
main().catch((_) => {
|
||||
throw 'Mushroom Strategy - An error occurred. Check the console (F12) for details.';
|
||||
});
|
||||
|
80
src/translations/pt-BR.json
Normal file
80
src/translations/pt-BR.json
Normal file
@ -0,0 +1,80 @@
|
||||
{
|
||||
"camera": {
|
||||
"all_cameras": "Todas as câmeras",
|
||||
"cameras": "Câmeras"
|
||||
},
|
||||
"climate": {
|
||||
"all_climates": "Todos os climatizadores",
|
||||
"climates": "Climatizadores"
|
||||
},
|
||||
"cover": {
|
||||
"all_covers": "Todas as persianas",
|
||||
"covers": "Persianas"
|
||||
},
|
||||
"fan": {
|
||||
"all_fans": "Todos os ventiladores",
|
||||
"fans": "Ventiladores"
|
||||
},
|
||||
"generic": {
|
||||
"all": "Todos",
|
||||
"areas": "Áreas",
|
||||
"busy": "Ocupado",
|
||||
"good_afternoon": "Boa tarde",
|
||||
"good_evening": "Boa noite",
|
||||
"good_morning": "Bom dia",
|
||||
"hello": "Olá",
|
||||
"home": "Início",
|
||||
"miscellaneous": "Variados",
|
||||
"numbers": "Números",
|
||||
"off": "Desligado",
|
||||
"on": "Ligado",
|
||||
"open": "Aberto",
|
||||
"unavailable": "Indisponível",
|
||||
"unclosed": "Não fechado",
|
||||
"undisclosed": "Outro",
|
||||
"unknown": "Desconhecido"
|
||||
},
|
||||
"input_select": {
|
||||
"input_selects": "Seleção de entrada"
|
||||
},
|
||||
"light": {
|
||||
"all_lights": "Todas as luzes",
|
||||
"lights": "Luzes"
|
||||
},
|
||||
"lock": {
|
||||
"all_locks": "Todas as fechaduras",
|
||||
"locked": "Travado",
|
||||
"locks": "Fechaduras",
|
||||
"unlocked": "Destravado"
|
||||
},
|
||||
"media_player": {
|
||||
"media_players": "Reprodutores de mídia"
|
||||
},
|
||||
"scene": {
|
||||
"scenes": "Cenas"
|
||||
},
|
||||
"select": {
|
||||
"selects": "Seleção"
|
||||
},
|
||||
"sensor": {
|
||||
"binary": "Binário",
|
||||
"sensors": "Sensores"
|
||||
},
|
||||
"switch": {
|
||||
"all_switches": "Todos os interruptores",
|
||||
"switches": "Interruptores"
|
||||
},
|
||||
"vacuum": {
|
||||
"all_vacuums": "Todos os aspiradores",
|
||||
"vacuums": "Aspiradores"
|
||||
},
|
||||
"valve": {
|
||||
"all_valves": "Todas as válvulas",
|
||||
"valves": "Válvulas",
|
||||
"open": "Aberto",
|
||||
"opening": "Abrindo",
|
||||
"closed": "Fechado",
|
||||
"closing": "Fechando",
|
||||
"stopped": "Parado"
|
||||
}
|
||||
}
|
@ -13,7 +13,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
<http://www.apache.org/licenses/LICENSE-2.0>
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -13,7 +13,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
<http://www.apache.org/licenses/LICENSE-2.0>
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { AreaRegistryEntry } from '../homeassistant/data/area_registry';
|
||||
import { DeviceRegistryEntry } from '../homeassistant/data/device_registry';
|
||||
import { EntityRegistryEntry } from '../homeassistant/data/entity_registry';
|
||||
import { LovelaceCardConfig } from '../homeassistant/data/lovelace/config/card';
|
||||
@ -8,6 +7,7 @@ import { HomeAssistant } from '../homeassistant/types';
|
||||
import { LovelaceChipConfig } from '../lovelace-mushroom/utils/lovelace/chip/types';
|
||||
import { HeaderCardConfig } from './strategy-cards';
|
||||
import { ConfigEntry } from '../homeassistant/data/config_entries';
|
||||
import { AreaRegistryEntry } from '../homeassistant/data/area_registry';
|
||||
|
||||
/**
|
||||
* List of supported domains.
|
||||
@ -69,6 +69,7 @@ const SUPPORTED_CHIPS = ['light', 'fan', 'cover', 'switch', 'climate', 'weather'
|
||||
*
|
||||
* This constant array defines the sections that are present in the home view.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const HOME_VIEW_SECTIONS = ['areas', 'areasTitle', 'chips', 'greeting', 'persons'] as const;
|
||||
|
||||
export type SupportedDomains = (typeof SUPPORTED_DOMAINS)[number];
|
||||
@ -136,14 +137,16 @@ export interface ViewInfo {
|
||||
/**
|
||||
* All-Domains Configuration.
|
||||
*
|
||||
* @property {boolean | undefined} hide_config_entities - If True, all configuration entities are hidden from the
|
||||
* dashboard.
|
||||
* @property {boolean | undefined} hide_diagnostic_entities - If True, all diagnostic entities are hidden from the
|
||||
* dashboard.
|
||||
* @property {boolean} [hide_config_entities] - If True, all configuration entities are hidden from the dashboard.
|
||||
* @property {boolean} [hide_diagnostic_entities] - If True, all diagnostic entities are hidden from the dashboard.
|
||||
* @property {boolean} [showControls] - False to hide controls.
|
||||
* @property {number} [stack_count] - Number of cards per row.
|
||||
*/
|
||||
export interface AllDomainsConfig {
|
||||
hide_config_entities: boolean | undefined;
|
||||
hide_diagnostic_entities: boolean | undefined;
|
||||
hide_config_entities?: boolean;
|
||||
hide_diagnostic_entities?: boolean;
|
||||
showControls?: boolean;
|
||||
stack_count?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -151,12 +154,55 @@ export interface AllDomainsConfig {
|
||||
*
|
||||
* @property {boolean} hidden - If True, all entities of the domain are hidden from the dashboard.
|
||||
* @property {number} [order] - Ordering position of the domains in a view.
|
||||
* @property {number} [stack_count] - Number of cards per row.
|
||||
*/
|
||||
export interface SingleDomainConfig extends Partial<HeaderCardConfig> {
|
||||
hidden: boolean;
|
||||
order?: number;
|
||||
stack_count?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strategy Configuration.
|
||||
*
|
||||
* @property {Object.<string, StrategyArea>} areas - The configuration of areas.
|
||||
* @property {Object.<string, CustomCardConfig>} card_options - Card options for entities.
|
||||
* @property {ChipConfiguration} chips - The configuration of chips in the Home view.
|
||||
* @property {boolean} debug - If True, the strategy outputs more verbose debug information in the console.
|
||||
* @property {Object.<string, AllDomainsConfig | SingleDomainConfig>} domains - List of domains.
|
||||
* @property {LovelaceCardConfig[]} extra_cards - List of cards to show below room cards.
|
||||
* @property {StrategyViewConfig[]} extra_views - List of custom-defined views to add to the dashboard.
|
||||
* @property {{ Object }} home_view - List of views to add to the dashboard.
|
||||
* @property {Record<SupportedViews, StrategyViewConfig>} views - The configurations of views.
|
||||
* @property {LovelaceCardConfig[]} quick_access_cards - List of custom-defined cards to show between the welcome card
|
||||
* and rooms cards.
|
||||
*/
|
||||
export interface StrategyConfig {
|
||||
areas: { [S: string]: StrategyArea };
|
||||
card_options: { [S: string]: CustomCardConfig };
|
||||
chips: ChipConfiguration;
|
||||
debug: boolean;
|
||||
domains: { [K in SupportedDomains]: K extends '_' ? AllDomainsConfig : SingleDomainConfig };
|
||||
extra_cards: LovelaceCardConfig[];
|
||||
extra_views: StrategyViewConfig[];
|
||||
home_view: {
|
||||
hidden: HomeViewSections[];
|
||||
stack_count: { _: number } & { [K in HomeViewSections]?: K extends 'areas' ? [number, number] : number };
|
||||
};
|
||||
views: Record<SupportedViews, StrategyViewConfig>;
|
||||
quick_access_cards: LovelaceCardConfig[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the default configuration for a strategy.
|
||||
*/
|
||||
export type StrategyDefaults = Omit<StrategyConfig, 'areas'> & {
|
||||
areas: {
|
||||
_: AllAreasConfig;
|
||||
undisclosed: StrategyArea;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Strategy Area.
|
||||
*
|
||||
@ -173,6 +219,15 @@ export interface StrategyArea extends AreaRegistryEntry {
|
||||
type?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration for all areas.
|
||||
*
|
||||
* @property {string} [type] - The type of area card.
|
||||
*/
|
||||
export interface AllAreasConfig {
|
||||
type?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of chips to show in the Home view.
|
||||
*
|
||||
|
@ -16,7 +16,7 @@ import { logMessage, lvlWarn } from './debug';
|
||||
class RegistryFilter<T extends RegistryEntry, K extends keyof T = keyof T> {
|
||||
private readonly entries: T[];
|
||||
private filters: (((entry: T) => boolean) | ((entry: T, index: number) => boolean))[] = [];
|
||||
private readonly entryIdentifier: ('entity_id' | 'floor_id' | 'entry_id' | 'id') & K;
|
||||
private readonly entryIdentifier: ('entity_id' | 'area_id' | 'id') & K;
|
||||
private invertNext: boolean = false;
|
||||
|
||||
/**
|
||||
@ -27,14 +27,8 @@ class RegistryFilter<T extends RegistryEntry, K extends keyof T = keyof T> {
|
||||
constructor(entries: T[]) {
|
||||
this.entries = entries;
|
||||
this.entryIdentifier = (
|
||||
entries.length === 0 || 'entity_id' in entries[0]
|
||||
? 'entity_id'
|
||||
: 'floor_id' in entries[0]
|
||||
? 'floor_id'
|
||||
: 'entry_id' in entries[0]
|
||||
? 'entry_id'
|
||||
: 'id'
|
||||
) as ('entity_id' | 'floor_id' | 'id') & K;
|
||||
entries.length === 0 || 'entity_id' in entries[0] ? 'entity_id' : 'floor_id' in entries[0] ? 'area_id' : 'id'
|
||||
) as ('entity_id' | 'area_id' | 'id') & K;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -73,49 +67,36 @@ class RegistryFilter<T extends RegistryEntry, K extends keyof T = keyof T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters entries **strictly** by their `area_id`.
|
||||
*
|
||||
* - Entries with a matching `area_id` are kept.
|
||||
* - If `expandToDevice` is `true`, the device's `area_id` is evaluated if the entry's area_id doesn't match.
|
||||
* - If `areaId` is `undefined` (or omitted), entries without an `area_id` property are kept.
|
||||
* Filters entries by their `area_id`.
|
||||
*
|
||||
* @param {string | undefined} areaId - The area id to match.
|
||||
* @param {boolean} [expandToDevice=true] - Whether to use the device's `area_id` if the entry's doesn't match.
|
||||
* @param {boolean} [expandToDevice=true] - Whether to evaluate the device's `area_id` (see remarks).
|
||||
*
|
||||
* @remarks
|
||||
* For area id `undisclosed`, the `area_id` of the entry's device may be `undisclosed` or `undefined`.
|
||||
* For entries with area id `undisclosed` or `undefined`, the device's `area_id` must also match if `expandToDevice`
|
||||
* is `true`.
|
||||
*/
|
||||
whereAreaId(areaId?: string, expandToDevice: boolean = true): this {
|
||||
const predicate = (entry: T) => {
|
||||
if ('entry_id' in entry) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let deviceAreaId: string | null | undefined = undefined;
|
||||
const entryObject = entry as EntityRegistryEntry;
|
||||
|
||||
let deviceAreaId: string | null | undefined = undefined;
|
||||
|
||||
// Retrieve the device area ID only if expandToDevice is true
|
||||
if (expandToDevice && entryObject.device_id) {
|
||||
deviceAreaId = Registry.devices.find((device) => device.id === entryObject.device_id)?.area_id;
|
||||
}
|
||||
|
||||
// Logic for 'undisclosed' areaId
|
||||
if (areaId === 'undisclosed') {
|
||||
return entry.area_id === areaId && (deviceAreaId === areaId || deviceAreaId === undefined);
|
||||
}
|
||||
|
||||
// Logic for undefined areaId
|
||||
if (areaId === undefined) {
|
||||
return entry.area_id === undefined && (!expandToDevice || deviceAreaId === undefined);
|
||||
return entry.area_id === undefined && deviceAreaId === undefined;
|
||||
}
|
||||
|
||||
// Logic for any other areaId
|
||||
return entry.area_id === areaId || (expandToDevice && deviceAreaId === areaId);
|
||||
if (entry.area_id === 'undisclosed' || !entry.area_id) {
|
||||
return deviceAreaId === areaId;
|
||||
}
|
||||
|
||||
return entry.area_id === areaId;
|
||||
};
|
||||
|
||||
this.filters.push(this.checkInversion(predicate));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -273,9 +254,12 @@ class RegistryFilter<T extends RegistryEntry, K extends keyof T = keyof T> {
|
||||
}
|
||||
|
||||
const id = entry[this.entryIdentifier] as keyof StrategyConfig['card_options'];
|
||||
const isHiddenByConfig =
|
||||
Registry.strategyOptions.device_options['_'].hidden ||
|
||||
Registry.strategyOptions.card_options[id]?.hidden === true;
|
||||
const options =
|
||||
this.entryIdentifier === 'area_id'
|
||||
? { ...Registry.strategyOptions.areas['_'], ...Registry.strategyOptions.areas[id] }
|
||||
: Registry.strategyOptions.card_options?.[id];
|
||||
|
||||
const isHiddenByConfig = options?.hidden === true;
|
||||
|
||||
return !isHiddenByProperty && !isHiddenByConfig;
|
||||
};
|
||||
@ -316,7 +300,9 @@ class RegistryFilter<T extends RegistryEntry, K extends keyof T = keyof T> {
|
||||
const predicate = (entry: T) => {
|
||||
const category = 'entity_category' in entry ? entry.entity_category : undefined;
|
||||
const hideOption =
|
||||
typeof category === 'string' ? Registry.strategyOptions.domains['_']?.[`hide_${category}_entities`] : undefined;
|
||||
typeof category === 'string'
|
||||
? Registry.strategyOptions?.domains?.['_']?.[`hide_${category}_entities`]
|
||||
: undefined;
|
||||
|
||||
if (hideOption === true) {
|
||||
return false;
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { LovelaceCardConfig } from '../types/homeassistant/data/lovelace/config/card';
|
||||
import { StackCardConfig } from '../types/homeassistant/panels/lovelace/cards/types';
|
||||
|
||||
// noinspection GrazieInspection
|
||||
/**
|
||||
* Stacks an array of Lovelace card configurations into horizontal stacks based on their type.
|
||||
*
|
||||
@ -9,6 +10,7 @@ import { StackCardConfig } from '../types/homeassistant/panels/lovelace/cards/ty
|
||||
* It returns a new array of stacked card configurations, preserving the original order of the cards.
|
||||
*
|
||||
* @param cardConfigurations - An array of Lovelace card configurations to be stacked.
|
||||
* @param defaultCount - The default number of cards to stack if the type or column count is not found in the mapping.
|
||||
* @param [columnCounts] - An object mapping card types to their respective column counts.
|
||||
* If a type is not found in the mapping, it defaults to 2.
|
||||
* @returns An array of stacked card configurations, where each configuration is a horizontal stack
|
||||
@ -16,17 +18,26 @@ import { StackCardConfig } from '../types/homeassistant/panels/lovelace/cards/ty
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* stackedCards = stackHorizontal(card, {area: 1, "custom:card": 2});
|
||||
* stackedCards = stackHorizontal(card, 2, {area: 1, 'custom:card': 2});
|
||||
* ```
|
||||
*/
|
||||
export function stackHorizontal(
|
||||
cardConfigurations: LovelaceCardConfig[],
|
||||
defaultCount: number = 2,
|
||||
columnCounts?: {
|
||||
[key: string]: number;
|
||||
[key: string]: number | undefined;
|
||||
},
|
||||
): LovelaceCardConfig[] {
|
||||
if (cardConfigurations.length <= 1) {
|
||||
return cardConfigurations;
|
||||
}
|
||||
|
||||
// Function to process a sequence of cards
|
||||
const doStack = (cards: LovelaceCardConfig[], columnCount: number) => {
|
||||
if (cards.length <= 1) {
|
||||
return cards;
|
||||
}
|
||||
|
||||
const stackedCardConfigurations: StackCardConfig[] = [];
|
||||
|
||||
for (let i = 0; i < cards.length; i += columnCount) {
|
||||
@ -44,7 +55,7 @@ export function stackHorizontal(
|
||||
|
||||
for (let i = 0; i < cardConfigurations.length; ) {
|
||||
const currentCard = cardConfigurations[i];
|
||||
const currentType = currentCard.type; // Assuming each card has a 'type' property
|
||||
const currentType = currentCard.type;
|
||||
|
||||
// Start a new sequence
|
||||
const sequence: LovelaceCardConfig[] = [];
|
||||
@ -55,7 +66,7 @@ export function stackHorizontal(
|
||||
i++; // Move to the next card
|
||||
}
|
||||
|
||||
const columnCount = Math.max(columnCounts?.[currentType] || 2, 1);
|
||||
const columnCount = Math.max(columnCounts?.[currentType] || defaultCount, 1);
|
||||
|
||||
// Process the sequence and add the result to the processedConfigurations array
|
||||
processedConfigurations.push(...doStack(sequence, columnCount));
|
||||
|
@ -2,6 +2,7 @@ import * as de from '../translations/de.json';
|
||||
import * as en from '../translations/en.json';
|
||||
import * as es from '../translations/es.json';
|
||||
import * as nl from '../translations/nl.json';
|
||||
import * as pt_br from '../translations/pt-BR.json';
|
||||
import { HomeAssistant } from '../types/homeassistant/types';
|
||||
import { logMessage, lvlWarn } from './debug';
|
||||
|
||||
@ -11,6 +12,7 @@ const languages: Record<string, unknown> = {
|
||||
en,
|
||||
es,
|
||||
nl,
|
||||
'pt-BR': pt_br,
|
||||
};
|
||||
|
||||
/** The fallback language if the user-defined language isn't defined */
|
||||
@ -50,7 +52,7 @@ let _localize: ((key: string) => string) | undefined = undefined;
|
||||
* It reads the user-defined language with a fall-back to English and returns a function to get strings from
|
||||
* language-files by keyword.
|
||||
*
|
||||
* If the keyword is undefined, or on error, the keyword itself is returned.
|
||||
* If the keyword is undefined, or on an error, the keyword itself is returned.
|
||||
*
|
||||
* @param {HomeAssistant} hass The Home Assistant object.
|
||||
*/
|
||||
|
@ -9,6 +9,7 @@ import { ViewConfig, ViewConstructor } from '../types/strategy/strategy-views';
|
||||
import { sanitizeClassName } from '../utilities/auxiliaries';
|
||||
import { logMessage, lvlFatal } from '../utilities/debug';
|
||||
import RegistryFilter from '../utilities/RegistryFilter';
|
||||
import { stackHorizontal } from '../utilities/cardStacking';
|
||||
import { AbstractCardConfig, HeaderCardConfig } from '../types/strategy/strategy-cards';
|
||||
|
||||
/**
|
||||
@ -22,7 +23,7 @@ import { AbstractCardConfig, HeaderCardConfig } from '../types/strategy/strategy
|
||||
*/
|
||||
abstract class AbstractView {
|
||||
/** The base configuration of a view. */
|
||||
protected baseConfiguration: LovelaceViewConfig = {
|
||||
protected baseConfiguration: ViewConfig = {
|
||||
icon: 'mdi:view-dashboard',
|
||||
subview: false,
|
||||
};
|
||||
@ -41,7 +42,7 @@ abstract class AbstractView {
|
||||
*/
|
||||
protected constructor() {
|
||||
if (!Registry.initialized) {
|
||||
logMessage(lvlFatal, 'Registry not initialized!');
|
||||
logMessage(lvlFatal, 'Registry is not initialized!');
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,7 +76,7 @@ abstract class AbstractView {
|
||||
|
||||
// Create card configurations for each area.
|
||||
for (const area of Registry.areas) {
|
||||
const areaCards: AbstractCardConfig[] = [];
|
||||
let areaCards: AbstractCardConfig[] = [];
|
||||
|
||||
// Set the target of the Header card to the current area.
|
||||
let target: HassServiceTarget = {
|
||||
@ -97,8 +98,14 @@ abstract class AbstractView {
|
||||
),
|
||||
);
|
||||
|
||||
// Vertically stack the cards of the current area.
|
||||
// Stack the cards of the current area.
|
||||
if (areaCards.length) {
|
||||
areaCards = stackHorizontal(
|
||||
areaCards,
|
||||
Registry.strategyOptions.domains[this.domain as SupportedDomains].stack_count ??
|
||||
Registry.strategyOptions.domains['_'].stack_count,
|
||||
);
|
||||
|
||||
// Create and insert a Header card.
|
||||
const areaHeaderCardOptions = (
|
||||
'headerCardConfiguration' in this.baseConfiguration ? this.baseConfiguration.headerCardConfiguration : {}
|
||||
@ -132,10 +139,14 @@ abstract class AbstractView {
|
||||
): void {
|
||||
this.baseConfiguration = { ...this.baseConfiguration, ...viewConfiguration, ...customConfiguration };
|
||||
|
||||
this.baseConfiguration.headerCardConfiguration = {
|
||||
showControls:
|
||||
Registry.strategyOptions.domains[this.domain as Exclude<SupportedDomains, 'home'>]?.showControls ??
|
||||
Registry.strategyOptions.domains['_'].showControls,
|
||||
};
|
||||
|
||||
this.viewHeaderCardConfiguration = new HeaderCard(this.getDomainTargets(), {
|
||||
...(('headerCardConfiguration' in this.baseConfiguration
|
||||
? this.baseConfiguration.headerCardConfiguration
|
||||
: {}) as HeaderCardConfig),
|
||||
...(this.baseConfiguration.headerCardConfiguration as HeaderCardConfig),
|
||||
...headerCardConfig,
|
||||
}).createCard();
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ class CameraView extends AbstractView {
|
||||
icon: 'mdi:cctv',
|
||||
subview: false,
|
||||
headerCardConfiguration: {
|
||||
showControls: domainConfig.showControls,
|
||||
showControls: domainConfig.showControls, // FIXME: This should be named "show_controls". Also in other files and Wiki.
|
||||
on: domainConfig.on,
|
||||
off: domainConfig.off,
|
||||
},
|
||||
|
@ -78,7 +78,7 @@ class HomeView extends AbstractView {
|
||||
}
|
||||
|
||||
// Create the greeting section.
|
||||
if (!('greeting' in Registry.strategyOptions.home_view.hidden)) {
|
||||
if (!Registry.strategyOptions.home_view.hidden.includes('greeting')) {
|
||||
homeViewCards.push({
|
||||
type: 'custom:mushroom-template-card',
|
||||
primary: `{% set time = now().hour %}
|
||||
@ -125,7 +125,7 @@ class HomeView extends AbstractView {
|
||||
* If the section is marked as hidden in the strategy option, then the section is not created.
|
||||
*/
|
||||
private async createChipsSection(): Promise<ChipsCardConfig | undefined> {
|
||||
if ((Registry.strategyOptions.home_view.hidden as string[]).includes('chips')) {
|
||||
if (Registry.strategyOptions.home_view.hidden.includes('chips')) {
|
||||
// The section is hidden.
|
||||
return;
|
||||
}
|
||||
@ -193,9 +193,8 @@ class HomeView extends AbstractView {
|
||||
* If the section is marked as hidden in the strategy option, then the section is not created.
|
||||
*/
|
||||
private async createPersonsSection(): Promise<StackCardConfig | undefined> {
|
||||
if ((Registry.strategyOptions.home_view.hidden as string[]).includes('persons')) {
|
||||
if (Registry.strategyOptions.home_view.hidden.includes('persons')) {
|
||||
// The section is hidden.
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -210,7 +209,11 @@ class HomeView extends AbstractView {
|
||||
|
||||
return {
|
||||
type: 'vertical-stack',
|
||||
cards: stackHorizontal(cardConfigurations),
|
||||
cards: stackHorizontal(
|
||||
cardConfigurations,
|
||||
Registry.strategyOptions.home_view.stack_count['persons'] ??
|
||||
Registry.strategyOptions.home_view.stack_count['_'],
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
@ -221,24 +224,19 @@ class HomeView extends AbstractView {
|
||||
* If the section is marked as hidden in the strategy option, then the section is not created.
|
||||
*/
|
||||
private async createAreasSection(): Promise<StackCardConfig | undefined> {
|
||||
if ((Registry.strategyOptions.home_view.hidden as string[]).includes('areas')) {
|
||||
if (Registry.strategyOptions.home_view.hidden.includes('areas')) {
|
||||
// Areas section is hidden.
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const cardConfigurations: (TemplateCardConfig | AreaCardConfig)[] = [];
|
||||
|
||||
let onlyDefaultCards = true;
|
||||
|
||||
for (const area of Registry.areas) {
|
||||
const moduleName =
|
||||
Registry.strategyOptions.areas[area.area_id]?.type ?? Registry.strategyOptions.areas['_']?.type ?? 'default';
|
||||
|
||||
let AreaCard;
|
||||
|
||||
onlyDefaultCards = onlyDefaultCards && moduleName === 'default';
|
||||
|
||||
try {
|
||||
AreaCard = (await import(`../cards/${moduleName}`)).default;
|
||||
} catch (e) {
|
||||
@ -250,15 +248,22 @@ class HomeView extends AbstractView {
|
||||
}
|
||||
}
|
||||
|
||||
cardConfigurations.push(new AreaCard(area).getCard());
|
||||
cardConfigurations.push(
|
||||
new AreaCard(area, {
|
||||
...Registry.strategyOptions.areas['_'],
|
||||
...Registry.strategyOptions.areas[area.area_id],
|
||||
}).getCard(),
|
||||
);
|
||||
}
|
||||
|
||||
// FIXME: The columns are too narrow when having HASS area cards.
|
||||
return {
|
||||
type: 'vertical-stack',
|
||||
title: (Registry.strategyOptions.home_view.hidden as HomeViewSections[]).includes('areasTitle')
|
||||
? undefined
|
||||
: localize('generic.areas'),
|
||||
cards: stackHorizontal(cardConfigurations, { area: 1, 'custom:mushroom-template-card': 2 }),
|
||||
title: Registry.strategyOptions.home_view.hidden.includes('areasTitle') ? undefined : localize('generic.areas'),
|
||||
cards: stackHorizontal(cardConfigurations, Registry.strategyOptions.home_view.stack_count['_'], {
|
||||
'custom:mushroom-template-card': Registry.strategyOptions.home_view.stack_count.areas?.[0],
|
||||
area: Registry.strategyOptions.home_view.stack_count.areas?.[1],
|
||||
}),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -49,8 +49,8 @@ class VacuumView extends AbstractView {
|
||||
return {
|
||||
title: localize('vacuum.all_vacuums'),
|
||||
subtitle:
|
||||
`${Registry.getCountTemplate(VacuumView.domain, 'in', '[cleaning, returning]')} ${localize('vacuum.vacuums')} ` +
|
||||
localize('generic.busy'),
|
||||
Registry.getCountTemplate(VacuumView.domain, 'in', '[cleaning, returning]') +
|
||||
` ${localize('vacuum.vacuums')} ${localize('generic.busy')}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user