mirror of
https://github.com/home-assistant/frontend.git
synced 2025-12-02 22:27:23 +00:00
Compare commits
367 Commits
20240207.0
...
fix-menu-o
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
29a103e884 | ||
|
|
912d2cbd79 | ||
|
|
48ee3a34eb | ||
|
|
21263a1ffb | ||
|
|
db59e138e9 | ||
|
|
bc8012dcc9 | ||
|
|
d8b43597a0 | ||
|
|
871949e760 | ||
|
|
4fb42d3545 | ||
|
|
2e58d6656c | ||
|
|
a3024b38e9 | ||
|
|
85f2016371 | ||
|
|
1ce3347c2e | ||
|
|
4f8415e8a7 | ||
|
|
b202a36feb | ||
|
|
7e3e224746 | ||
|
|
503a7979d0 | ||
|
|
f3ba6e7996 | ||
|
|
f13dcb4139 | ||
|
|
e8dc61ec36 | ||
|
|
88c59c5c13 | ||
|
|
85f80ff863 | ||
|
|
d56abe6b72 | ||
|
|
bc14b8468d | ||
|
|
f924f81ec1 | ||
|
|
3a6382df55 | ||
|
|
1dba049038 | ||
|
|
f539516252 | ||
|
|
abd02eda0f | ||
|
|
99695d6cb3 | ||
|
|
cb1c2b59df | ||
|
|
8368f977b9 | ||
|
|
e05595f318 | ||
|
|
11cf2ec39d | ||
|
|
e5c43fcfcd | ||
|
|
520581c165 | ||
|
|
d1119a3b61 | ||
|
|
5dd029cc05 | ||
|
|
510e010f97 | ||
|
|
1300cffa3b | ||
|
|
8fbcbb0b68 | ||
|
|
7b26c1ffcb | ||
|
|
d3e62454a5 | ||
|
|
6b8f4e92a7 | ||
|
|
b590b21183 | ||
|
|
a08484f450 | ||
|
|
2978ca13c5 | ||
|
|
31c0850b14 | ||
|
|
1d85f0717a | ||
|
|
55c8589841 | ||
|
|
4687add37a | ||
|
|
c25e23ccd6 | ||
|
|
e42ddb8f0f | ||
|
|
705c0e58fc | ||
|
|
7427e17926 | ||
|
|
2c4b31dcaa | ||
|
|
ae8671af96 | ||
|
|
f5ff55abc5 | ||
|
|
b662512995 | ||
|
|
64c3fb1723 | ||
|
|
fb99dc4cd0 | ||
|
|
e08a0c44ba | ||
|
|
68935d46ce | ||
|
|
141c8c5192 | ||
|
|
7ca5467f4c | ||
|
|
5de53964d9 | ||
|
|
8d8807e659 | ||
|
|
9347944cbd | ||
|
|
480448acbb | ||
|
|
202fa82646 | ||
|
|
feecc9f838 | ||
|
|
2f9e667517 | ||
|
|
5547bc7356 | ||
|
|
eb4ae926b7 | ||
|
|
b239ec2b71 | ||
|
|
e9cac94aee | ||
|
|
5289cd3af1 | ||
|
|
45a5c1c235 | ||
|
|
db3709952c | ||
|
|
447932eedb | ||
|
|
10cc3bdd3f | ||
|
|
6ee2bfed36 | ||
|
|
01efb831b7 | ||
|
|
9e1e20bd94 | ||
|
|
869ace74ad | ||
|
|
94d56367fc | ||
|
|
68a5ba668e | ||
|
|
b2b590cf67 | ||
|
|
6f7c071769 | ||
|
|
c1a7164ce7 | ||
|
|
b77839c139 | ||
|
|
e2f2a9322c | ||
|
|
e4bd6c885d | ||
|
|
8201701d17 | ||
|
|
a5e6b78e1d | ||
|
|
027eccba06 | ||
|
|
12f10513f0 | ||
|
|
9907ed51f0 | ||
|
|
90e9f79841 | ||
|
|
c30b9cdfcf | ||
|
|
7e1fa0cf38 | ||
|
|
b6587488d4 | ||
|
|
552eeeddf6 | ||
|
|
cbc150bad2 | ||
|
|
8a4ed121b5 | ||
|
|
a9793dc0a5 | ||
|
|
c9deef84ca | ||
|
|
1582aaeb4c | ||
|
|
707520c15c | ||
|
|
d5de435f06 | ||
|
|
9e3dfaa400 | ||
|
|
7aa92ec249 | ||
|
|
2fdcd40f00 | ||
|
|
3b15b786ff | ||
|
|
b212b30e58 | ||
|
|
6fd89f8585 | ||
|
|
0406d21703 | ||
|
|
293f89a07b | ||
|
|
520a0b4075 | ||
|
|
488602e232 | ||
|
|
1e8d353162 | ||
|
|
b3718b8b4a | ||
|
|
097cba5c60 | ||
|
|
fa6d8d0891 | ||
|
|
31797c55df | ||
|
|
56a23c5c3d | ||
|
|
adc89f1487 | ||
|
|
7facc375bc | ||
|
|
91d3fb0ea8 | ||
|
|
4ab0047dc1 | ||
|
|
279eeaa442 | ||
|
|
d4d0fb2a03 | ||
|
|
d56fe8a542 | ||
|
|
292701925d | ||
|
|
52fc854cc3 | ||
|
|
90ca039768 | ||
|
|
9e81055070 | ||
|
|
cea402ebf8 | ||
|
|
6b939b95c0 | ||
|
|
b24621d1ea | ||
|
|
cc0fde2c08 | ||
|
|
3732998fb7 | ||
|
|
c699e265ef | ||
|
|
98bb726f1a | ||
|
|
c132e7ed85 | ||
|
|
298cebe17f | ||
|
|
d03825d200 | ||
|
|
d9ab9db211 | ||
|
|
58a607561a | ||
|
|
0ae1f11ffc | ||
|
|
db48c5a6a3 | ||
|
|
effefdbff1 | ||
|
|
233c969402 | ||
|
|
3b885dd01f | ||
|
|
52c8554d89 | ||
|
|
b55baef985 | ||
|
|
b593b15f27 | ||
|
|
00669ac0c3 | ||
|
|
33a4258c06 | ||
|
|
d4a8fcbe03 | ||
|
|
36c3b938ce | ||
|
|
bf2fad2a2a | ||
|
|
9cbd49b867 | ||
|
|
9de59131f4 | ||
|
|
7f44e89829 | ||
|
|
572e4457b3 | ||
|
|
a5bcf87c08 | ||
|
|
8ca5b7528b | ||
|
|
d951e68c10 | ||
|
|
32e8d2043c | ||
|
|
bf028915ec | ||
|
|
b03f483e4f | ||
|
|
6f6202eb69 | ||
|
|
7ab2d1496e | ||
|
|
acc229a7e1 | ||
|
|
64ffa86fe3 | ||
|
|
8b77024fb9 | ||
|
|
42aa18ac16 | ||
|
|
54d21666d0 | ||
|
|
aac00a5e78 | ||
|
|
63d93f2a36 | ||
|
|
a9f453ea36 | ||
|
|
d248de92e5 | ||
|
|
0ed483ba51 | ||
|
|
68fbadf21b | ||
|
|
ac66079d41 | ||
|
|
56c681bcf8 | ||
|
|
c5c4253760 | ||
|
|
84e6f2fc4f | ||
|
|
8cedaae645 | ||
|
|
e350ba4726 | ||
|
|
1b7742ef7f | ||
|
|
0c6bf701c7 | ||
|
|
05e2e305e4 | ||
|
|
5523cd6203 | ||
|
|
50da4bcd37 | ||
|
|
b99072d986 | ||
|
|
b9a7a7c422 | ||
|
|
88ccbcd883 | ||
|
|
b5bb6c6fe5 | ||
|
|
19a3810168 | ||
|
|
8ccc38eb00 | ||
|
|
70146a08c1 | ||
|
|
19d50b9c92 | ||
|
|
05c1328ca7 | ||
|
|
99c2dd9765 | ||
|
|
edbe6851f7 | ||
|
|
a7867a9253 | ||
|
|
94e70f81ed | ||
|
|
3d8654253a | ||
|
|
69dbcec678 | ||
|
|
de8b0ba8c5 | ||
|
|
730cd9f983 | ||
|
|
67d8765624 | ||
|
|
39bd07de73 | ||
|
|
3202ea55d2 | ||
|
|
329a8c0c90 | ||
|
|
c05824c641 | ||
|
|
3abdffda9c | ||
|
|
67da851efc | ||
|
|
5463a27255 | ||
|
|
ec0434c9b0 | ||
|
|
7d8cb5c863 | ||
|
|
4f01348ffb | ||
|
|
ca7e257e95 | ||
|
|
a34332b48d | ||
|
|
962912c43c | ||
|
|
2af3400464 | ||
|
|
b6e220a4c5 | ||
|
|
d5d45f100e | ||
|
|
6b9ca60c47 | ||
|
|
bc445a1e27 | ||
|
|
a087b4c43e | ||
|
|
8f67ddf968 | ||
|
|
9ef07484dd | ||
|
|
7475cb56a1 | ||
|
|
5287061699 | ||
|
|
3ef1110109 | ||
|
|
2efe2589d2 | ||
|
|
4fb596357d | ||
|
|
dd98ec771d | ||
|
|
94f74308d8 | ||
|
|
b982884933 | ||
|
|
c47c6e358b | ||
|
|
46394d0bf9 | ||
|
|
4dc154201a | ||
|
|
ebdbab81d3 | ||
|
|
155098bc41 | ||
|
|
291638a9dd | ||
|
|
763c672e36 | ||
|
|
c945534640 | ||
|
|
5b3074d939 | ||
|
|
3b89b72568 | ||
|
|
1d9fa1522c | ||
|
|
4db743db00 | ||
|
|
d5f8231f97 | ||
|
|
32c403d069 | ||
|
|
220da51606 | ||
|
|
9ae234a02f | ||
|
|
401bbed67b | ||
|
|
83190c21db | ||
|
|
ccdd906e2f | ||
|
|
f4c932ef9c | ||
|
|
0892ed18e5 | ||
|
|
3afc218adc | ||
|
|
841b9c0917 | ||
|
|
a479c6e786 | ||
|
|
babb723521 | ||
|
|
29954e530e | ||
|
|
fb3c94f403 | ||
|
|
dd8c1d359c | ||
|
|
45e09a262b | ||
|
|
d6d61a4137 | ||
|
|
8fe7711634 | ||
|
|
a5ec7fc251 | ||
|
|
b9935717dc | ||
|
|
bb25817bae | ||
|
|
bf8a33e086 | ||
|
|
bf56f50e0a | ||
|
|
3a8e2c429f | ||
|
|
e8fca5d93c | ||
|
|
a39cf99024 | ||
|
|
0ff27154e6 | ||
|
|
766fd4cbf5 | ||
|
|
1869260868 | ||
|
|
93046d78f6 | ||
|
|
3e51f9a505 | ||
|
|
d95bf64edf | ||
|
|
47f7cf5419 | ||
|
|
267fc3743d | ||
|
|
a6d73f7615 | ||
|
|
b360c854a8 | ||
|
|
a088b20987 | ||
|
|
af6dd545dc | ||
|
|
a26df88022 | ||
|
|
86ec272581 | ||
|
|
2a803e09a4 | ||
|
|
50cf6d2af9 | ||
|
|
86626b1855 | ||
|
|
63603a281e | ||
|
|
faf05f5339 | ||
|
|
4de3db52cb | ||
|
|
9a9fbda08b | ||
|
|
ea642515c1 | ||
|
|
add2dedc7f | ||
|
|
4ba4a28aa0 | ||
|
|
7050453783 | ||
|
|
8f984517bb | ||
|
|
2524c96db6 | ||
|
|
26600e3d78 | ||
|
|
316756d06a | ||
|
|
7357b914d0 | ||
|
|
8548c9767b | ||
|
|
a30a35f82f | ||
|
|
84938ccc94 | ||
|
|
8136cc8008 | ||
|
|
2dc9d268ec | ||
|
|
226dad309c | ||
|
|
33cdd51f00 | ||
|
|
a3a099126e | ||
|
|
4e22fea6e2 | ||
|
|
fd06f28253 | ||
|
|
553230ca23 | ||
|
|
208bfebc12 | ||
|
|
802b0949ac | ||
|
|
b65dc47f72 | ||
|
|
c5a3670838 | ||
|
|
cd167ac645 | ||
|
|
eb3e756637 | ||
|
|
5049210524 | ||
|
|
eeaad86c4b | ||
|
|
71483e0bc7 | ||
|
|
10650e8937 | ||
|
|
99d72ba817 | ||
|
|
e21ad742b1 | ||
|
|
1bcb1e7768 | ||
|
|
618fee98ce | ||
|
|
83da89437f | ||
|
|
35ebfc15c9 | ||
|
|
f0a9185e4a | ||
|
|
b3766cbc62 | ||
|
|
fac82fa185 | ||
|
|
3469013f1a | ||
|
|
03486e4125 | ||
|
|
20560fb847 | ||
|
|
bad18da658 | ||
|
|
e26c7c491a | ||
|
|
b0c8ae0c94 | ||
|
|
cc1658cbab | ||
|
|
4b768f0635 | ||
|
|
989057d947 | ||
|
|
6671d24fa6 | ||
|
|
297c721229 | ||
|
|
17bd7f9476 | ||
|
|
045ff7a45e | ||
|
|
8624853ec4 | ||
|
|
336376d2a5 | ||
|
|
189793bff4 | ||
|
|
1e35f973d6 | ||
|
|
6033f8b31a | ||
|
|
c3b2ebf380 | ||
|
|
23cbecb2c4 | ||
|
|
b1e1b44c75 | ||
|
|
abb014745a | ||
|
|
e51c98e1a7 | ||
|
|
9513699332 | ||
|
|
b57bc8cd06 |
@@ -1,5 +1,5 @@
|
|||||||
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.148.1/containers/python-3/.devcontainer/base.Dockerfile
|
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.148.1/containers/python-3/.devcontainer/base.Dockerfile
|
||||||
FROM mcr.microsoft.com/vscode/devcontainers/python:0-3.11
|
FROM mcr.microsoft.com/devcontainers/python:3.12
|
||||||
|
|
||||||
ENV \
|
ENV \
|
||||||
DEBIAN_FRONTEND=noninteractive \
|
DEBIAN_FRONTEND=noninteractive \
|
||||||
|
|||||||
@@ -2,12 +2,13 @@
|
|||||||
"name": "Home Assistant Frontend",
|
"name": "Home Assistant Frontend",
|
||||||
"build": {
|
"build": {
|
||||||
"dockerfile": "Dockerfile",
|
"dockerfile": "Dockerfile",
|
||||||
"context": "..",
|
"context": ".."
|
||||||
},
|
},
|
||||||
"appPort": "8124:8123",
|
"appPort": "8124:8123",
|
||||||
|
"postCreateCommand": "sudo apt update && sudo apt upgrade -y && sudo apt install -y libpcap-dev",
|
||||||
"postStartCommand": "script/bootstrap",
|
"postStartCommand": "script/bootstrap",
|
||||||
"containerEnv": {
|
"containerEnv": {
|
||||||
"WORKSPACE_DIRECTORY": "${containerWorkspaceFolder}",
|
"WORKSPACE_DIRECTORY": "${containerWorkspaceFolder}"
|
||||||
},
|
},
|
||||||
"customizations": {
|
"customizations": {
|
||||||
"vscode": {
|
"vscode": {
|
||||||
@@ -16,7 +17,7 @@
|
|||||||
"esbenp.prettier-vscode",
|
"esbenp.prettier-vscode",
|
||||||
"runem.lit-plugin",
|
"runem.lit-plugin",
|
||||||
"github.vscode-pull-request-github",
|
"github.vscode-pull-request-github",
|
||||||
"eamodio.gitlens",
|
"eamodio.gitlens"
|
||||||
],
|
],
|
||||||
"settings": {
|
"settings": {
|
||||||
"files.eol": "\n",
|
"files.eol": "\n",
|
||||||
@@ -27,17 +28,17 @@
|
|||||||
"editor.renderWhitespace": "boundary",
|
"editor.renderWhitespace": "boundary",
|
||||||
"editor.rulers": [80],
|
"editor.rulers": [80],
|
||||||
"[typescript]": {
|
"[typescript]": {
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
},
|
},
|
||||||
"[javascript]": {
|
"[javascript]": {
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||||
},
|
},
|
||||||
"files.trimTrailingWhitespace": true,
|
"files.trimTrailingWhitespace": true,
|
||||||
"terminal.integrated.shell.linux": "/usr/bin/zsh",
|
"terminal.integrated.shell.linux": "/usr/bin/zsh",
|
||||||
"gitlens.showWelcomeOnInstall": false,
|
"gitlens.showWelcomeOnInstall": false,
|
||||||
"gitlens.showWhatsNewAfterUpgrades": false,
|
"gitlens.showWhatsNewAfterUpgrades": false,
|
||||||
"workbench.startupEditor": "none",
|
"workbench.startupEditor": "none"
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
8
.github/workflows/cast_deployment.yaml
vendored
8
.github/workflows/cast_deployment.yaml
vendored
@@ -21,12 +21,12 @@ jobs:
|
|||||||
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@v4.1.1
|
uses: actions/checkout@v4.1.2
|
||||||
with:
|
with:
|
||||||
ref: dev
|
ref: dev
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v4.0.1
|
uses: actions/setup-node@v4.0.2
|
||||||
with:
|
with:
|
||||||
node-version-file: ".nvmrc"
|
node-version-file: ".nvmrc"
|
||||||
cache: yarn
|
cache: yarn
|
||||||
@@ -57,12 +57,12 @@ jobs:
|
|||||||
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@v4.1.1
|
uses: actions/checkout@v4.1.2
|
||||||
with:
|
with:
|
||||||
ref: master
|
ref: master
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v4.0.1
|
uses: actions/setup-node@v4.0.2
|
||||||
with:
|
with:
|
||||||
node-version-file: ".nvmrc"
|
node-version-file: ".nvmrc"
|
||||||
cache: yarn
|
cache: yarn
|
||||||
|
|||||||
22
.github/workflows/ci.yaml
vendored
22
.github/workflows/ci.yaml
vendored
@@ -24,9 +24,9 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@v4.1.1
|
uses: actions/checkout@v4.1.2
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v4.0.1
|
uses: actions/setup-node@v4.0.2
|
||||||
with:
|
with:
|
||||||
node-version-file: ".nvmrc"
|
node-version-file: ".nvmrc"
|
||||||
cache: yarn
|
cache: yarn
|
||||||
@@ -37,7 +37,7 @@ jobs:
|
|||||||
- name: Build resources
|
- name: Build resources
|
||||||
run: ./node_modules/.bin/gulp gen-icons-json build-translations build-locale-data gather-gallery-pages
|
run: ./node_modules/.bin/gulp gen-icons-json build-translations build-locale-data gather-gallery-pages
|
||||||
- name: Setup lint cache
|
- name: Setup lint cache
|
||||||
uses: actions/cache@v4.0.0
|
uses: actions/cache@v4.0.2
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
node_modules/.cache/prettier
|
node_modules/.cache/prettier
|
||||||
@@ -58,9 +58,9 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@v4.1.1
|
uses: actions/checkout@v4.1.2
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v4.0.1
|
uses: actions/setup-node@v4.0.2
|
||||||
with:
|
with:
|
||||||
node-version-file: ".nvmrc"
|
node-version-file: ".nvmrc"
|
||||||
cache: yarn
|
cache: yarn
|
||||||
@@ -76,9 +76,9 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@v4.1.1
|
uses: actions/checkout@v4.1.2
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v4.0.1
|
uses: actions/setup-node@v4.0.2
|
||||||
with:
|
with:
|
||||||
node-version-file: ".nvmrc"
|
node-version-file: ".nvmrc"
|
||||||
cache: yarn
|
cache: yarn
|
||||||
@@ -89,7 +89,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
IS_TEST: "true"
|
IS_TEST: "true"
|
||||||
- name: Upload bundle stats
|
- name: Upload bundle stats
|
||||||
uses: actions/upload-artifact@v4.3.0
|
uses: actions/upload-artifact@v4.3.1
|
||||||
with:
|
with:
|
||||||
name: frontend-bundle-stats
|
name: frontend-bundle-stats
|
||||||
path: build/stats/*.json
|
path: build/stats/*.json
|
||||||
@@ -100,9 +100,9 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@v4.1.1
|
uses: actions/checkout@v4.1.2
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v4.0.1
|
uses: actions/setup-node@v4.0.2
|
||||||
with:
|
with:
|
||||||
node-version-file: ".nvmrc"
|
node-version-file: ".nvmrc"
|
||||||
cache: yarn
|
cache: yarn
|
||||||
@@ -113,7 +113,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
IS_TEST: "true"
|
IS_TEST: "true"
|
||||||
- name: Upload bundle stats
|
- name: Upload bundle stats
|
||||||
uses: actions/upload-artifact@v4.3.0
|
uses: actions/upload-artifact@v4.3.1
|
||||||
with:
|
with:
|
||||||
name: supervisor-bundle-stats
|
name: supervisor-bundle-stats
|
||||||
path: build/stats/*.json
|
path: build/stats/*.json
|
||||||
|
|||||||
2
.github/workflows/codeql-analysis.yml
vendored
2
.github/workflows/codeql-analysis.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4.1.1
|
uses: actions/checkout@v4.1.2
|
||||||
with:
|
with:
|
||||||
# We must fetch at least the immediate parents so that if this is
|
# We must fetch at least the immediate parents so that if this is
|
||||||
# a pull request then we can checkout the head.
|
# a pull request then we can checkout the head.
|
||||||
|
|||||||
8
.github/workflows/demo_deployment.yaml
vendored
8
.github/workflows/demo_deployment.yaml
vendored
@@ -22,12 +22,12 @@ jobs:
|
|||||||
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@v4.1.1
|
uses: actions/checkout@v4.1.2
|
||||||
with:
|
with:
|
||||||
ref: dev
|
ref: dev
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v4.0.1
|
uses: actions/setup-node@v4.0.2
|
||||||
with:
|
with:
|
||||||
node-version-file: ".nvmrc"
|
node-version-file: ".nvmrc"
|
||||||
cache: yarn
|
cache: yarn
|
||||||
@@ -58,12 +58,12 @@ jobs:
|
|||||||
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@v4.1.1
|
uses: actions/checkout@v4.1.2
|
||||||
with:
|
with:
|
||||||
ref: master
|
ref: master
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v4.0.1
|
uses: actions/setup-node@v4.0.2
|
||||||
with:
|
with:
|
||||||
node-version-file: ".nvmrc"
|
node-version-file: ".nvmrc"
|
||||||
cache: yarn
|
cache: yarn
|
||||||
|
|||||||
4
.github/workflows/design_deployment.yaml
vendored
4
.github/workflows/design_deployment.yaml
vendored
@@ -16,10 +16,10 @@ jobs:
|
|||||||
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@v4.1.1
|
uses: actions/checkout@v4.1.2
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v4.0.1
|
uses: actions/setup-node@v4.0.2
|
||||||
with:
|
with:
|
||||||
node-version-file: ".nvmrc"
|
node-version-file: ".nvmrc"
|
||||||
cache: yarn
|
cache: yarn
|
||||||
|
|||||||
4
.github/workflows/design_preview.yaml
vendored
4
.github/workflows/design_preview.yaml
vendored
@@ -21,10 +21,10 @@ jobs:
|
|||||||
if: github.repository == 'home-assistant/frontend' && contains(github.event.pull_request.labels.*.name, 'needs design preview')
|
if: github.repository == 'home-assistant/frontend' && contains(github.event.pull_request.labels.*.name, 'needs design preview')
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@v4.1.1
|
uses: actions/checkout@v4.1.2
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v4.0.1
|
uses: actions/setup-node@v4.0.2
|
||||||
with:
|
with:
|
||||||
node-version-file: ".nvmrc"
|
node-version-file: ".nvmrc"
|
||||||
cache: yarn
|
cache: yarn
|
||||||
|
|||||||
10
.github/workflows/nightly.yaml
vendored
10
.github/workflows/nightly.yaml
vendored
@@ -6,7 +6,7 @@ on:
|
|||||||
- cron: "0 1 * * *"
|
- cron: "0 1 * * *"
|
||||||
|
|
||||||
env:
|
env:
|
||||||
PYTHON_VERSION: "3.11"
|
PYTHON_VERSION: "3.12"
|
||||||
NODE_OPTIONS: --max_old_space_size=6144
|
NODE_OPTIONS: --max_old_space_size=6144
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
@@ -20,7 +20,7 @@ jobs:
|
|||||||
contents: write
|
contents: write
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v4.1.1
|
uses: actions/checkout@v4.1.2
|
||||||
|
|
||||||
- name: Set up Python ${{ env.PYTHON_VERSION }}
|
- name: Set up Python ${{ env.PYTHON_VERSION }}
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@v5
|
||||||
@@ -28,7 +28,7 @@ jobs:
|
|||||||
python-version: ${{ env.PYTHON_VERSION }}
|
python-version: ${{ env.PYTHON_VERSION }}
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v4.0.1
|
uses: actions/setup-node@v4.0.2
|
||||||
with:
|
with:
|
||||||
node-version-file: ".nvmrc"
|
node-version-file: ".nvmrc"
|
||||||
cache: yarn
|
cache: yarn
|
||||||
@@ -57,14 +57,14 @@ jobs:
|
|||||||
run: tar -czvf translations.tar.gz translations
|
run: tar -czvf translations.tar.gz translations
|
||||||
|
|
||||||
- name: Upload build artifacts
|
- name: Upload build artifacts
|
||||||
uses: actions/upload-artifact@v4.3.0
|
uses: actions/upload-artifact@v4.3.1
|
||||||
with:
|
with:
|
||||||
name: wheels
|
name: wheels
|
||||||
path: dist/home_assistant_frontend*.whl
|
path: dist/home_assistant_frontend*.whl
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
- name: Upload translations
|
- name: Upload translations
|
||||||
uses: actions/upload-artifact@v4.3.0
|
uses: actions/upload-artifact@v4.3.1
|
||||||
with:
|
with:
|
||||||
name: translations
|
name: translations
|
||||||
path: translations.tar.gz
|
path: translations.tar.gz
|
||||||
|
|||||||
8
.github/workflows/release.yaml
vendored
8
.github/workflows/release.yaml
vendored
@@ -6,7 +6,7 @@ on:
|
|||||||
- published
|
- published
|
||||||
|
|
||||||
env:
|
env:
|
||||||
PYTHON_VERSION: "3.11"
|
PYTHON_VERSION: "3.12"
|
||||||
NODE_OPTIONS: --max_old_space_size=6144
|
NODE_OPTIONS: --max_old_space_size=6144
|
||||||
|
|
||||||
# Set default workflow permissions
|
# Set default workflow permissions
|
||||||
@@ -23,7 +23,7 @@ jobs:
|
|||||||
contents: write # Required to upload release assets
|
contents: write # Required to upload release assets
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v4.1.1
|
uses: actions/checkout@v4.1.2
|
||||||
|
|
||||||
- name: Verify version
|
- name: Verify version
|
||||||
uses: home-assistant/actions/helpers/verify-version@master
|
uses: home-assistant/actions/helpers/verify-version@master
|
||||||
@@ -34,7 +34,7 @@ jobs:
|
|||||||
python-version: ${{ env.PYTHON_VERSION }}
|
python-version: ${{ env.PYTHON_VERSION }}
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v4.0.1
|
uses: actions/setup-node@v4.0.2
|
||||||
with:
|
with:
|
||||||
node-version-file: ".nvmrc"
|
node-version-file: ".nvmrc"
|
||||||
cache: yarn
|
cache: yarn
|
||||||
@@ -55,7 +55,7 @@ jobs:
|
|||||||
script/release
|
script/release
|
||||||
|
|
||||||
- name: Upload release assets
|
- name: Upload release assets
|
||||||
uses: softprops/action-gh-release@v0.1.15
|
uses: softprops/action-gh-release@v2.0.4
|
||||||
with:
|
with:
|
||||||
files: |
|
files: |
|
||||||
dist/*.whl
|
dist/*.whl
|
||||||
|
|||||||
2
.github/workflows/translations.yaml
vendored
2
.github/workflows/translations.yaml
vendored
@@ -13,7 +13,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v4.1.1
|
uses: actions/checkout@v4.1.2
|
||||||
|
|
||||||
- name: Upload Translations
|
- name: Upload Translations
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
18
.yarn/patches/hls.js-npm-1.5.7-f5bbd3d060.patch
Normal file
18
.yarn/patches/hls.js-npm-1.5.7-f5bbd3d060.patch
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
diff --git a/dist/hls.light.mjs b/dist/hls.light.mjs
|
||||||
|
index eed9d788fafdb159975e1a2eb08ac88ba9c9ac33..ace881935e6665946f1c8110ebd2f739cde4427e 100644
|
||||||
|
--- a/dist/hls.light.mjs
|
||||||
|
+++ b/dist/hls.light.mjs
|
||||||
|
@@ -20523,9 +20523,9 @@ class Hls {
|
||||||
|
}
|
||||||
|
Hls.defaultConfig = void 0;
|
||||||
|
|
||||||
|
-var KeySystemFormats = empty.KeySystemFormats;
|
||||||
|
-var KeySystems = empty.KeySystems;
|
||||||
|
-var SubtitleStreamController = empty.SubtitleStreamController;
|
||||||
|
-var TimelineController = empty.TimelineController;
|
||||||
|
+var KeySystemFormats = empty;
|
||||||
|
+var KeySystems = empty;
|
||||||
|
+var SubtitleStreamController = empty;
|
||||||
|
+var TimelineController = empty;
|
||||||
|
export { AbrController, AttrList, Cues as AudioStreamController, Cues as AudioTrackController, BasePlaylistController, BaseSegment, BaseStreamController, BufferController, Cues as CMCDController, CapLevelController, ChunkMetadata, ContentSteeringController, DateRange, Cues as EMEController, ErrorActionFlags, ErrorController, ErrorDetails, ErrorTypes, Events, FPSController, Fragment, Hls, HlsSkip, HlsUrlParameters, KeySystemFormats, KeySystems, Level, LevelDetails, LevelKey, LoadStats, MetadataSchema, NetworkErrorAction, Part, PlaylistLevelType, SubtitleStreamController, Cues as SubtitleTrackController, TimelineController, Hls as default, getMediaSource, isMSESupported, isSupported };
|
||||||
|
//# sourceMappingURL=hls.light.mjs.map
|
||||||
File diff suppressed because one or more lines are too long
@@ -6,4 +6,4 @@ enableGlobalCache: false
|
|||||||
|
|
||||||
nodeLinker: node-modules
|
nodeLinker: node-modules
|
||||||
|
|
||||||
yarnPath: .yarn/releases/yarn-4.1.0.cjs
|
yarnPath: .yarn/releases/yarn-4.1.1.cjs
|
||||||
|
|||||||
@@ -115,7 +115,9 @@ gulp.task("webpack-prod-app", () =>
|
|||||||
|
|
||||||
gulp.task("webpack-dev-server-demo", () =>
|
gulp.task("webpack-dev-server-demo", () =>
|
||||||
runDevServer({
|
runDevServer({
|
||||||
compiler: webpack(bothBuilds(createDemoConfig, { isProdBuild: false })),
|
compiler: webpack(
|
||||||
|
createDemoConfig({ isProdBuild: false, latestBuild: true })
|
||||||
|
),
|
||||||
contentBase: paths.demo_output_root,
|
contentBase: paths.demo_output_root,
|
||||||
port: 8090,
|
port: 8090,
|
||||||
})
|
})
|
||||||
@@ -131,7 +133,9 @@ gulp.task("webpack-prod-demo", () =>
|
|||||||
|
|
||||||
gulp.task("webpack-dev-server-cast", () =>
|
gulp.task("webpack-dev-server-cast", () =>
|
||||||
runDevServer({
|
runDevServer({
|
||||||
compiler: webpack(bothBuilds(createCastConfig, { isProdBuild: false })),
|
compiler: webpack(
|
||||||
|
createCastConfig({ isProdBuild: false, latestBuild: true })
|
||||||
|
),
|
||||||
contentBase: paths.cast_output_root,
|
contentBase: paths.cast_output_root,
|
||||||
port: 8080,
|
port: 8080,
|
||||||
// Accessible from the network, because that's how Cast hits it.
|
// Accessible from the network, because that's how Cast hits it.
|
||||||
@@ -174,8 +178,9 @@ gulp.task("webpack-prod-hassio", () =>
|
|||||||
|
|
||||||
gulp.task("webpack-dev-server-gallery", () =>
|
gulp.task("webpack-dev-server-gallery", () =>
|
||||||
runDevServer({
|
runDevServer({
|
||||||
// We don't use the es5 build, but the dev server will fuck up the publicPath if we don't
|
compiler: webpack(
|
||||||
compiler: webpack(bothBuilds(createGalleryConfig, { isProdBuild: false })),
|
createGalleryConfig({ isProdBuild: false, latestBuild: true })
|
||||||
|
),
|
||||||
contentBase: paths.gallery_output_root,
|
contentBase: paths.gallery_output_root,
|
||||||
port: 8100,
|
port: 8100,
|
||||||
listenHost: "0.0.0.0",
|
listenHost: "0.0.0.0",
|
||||||
|
|||||||
@@ -28,25 +28,23 @@ class HcLaunchScreen extends LitElement {
|
|||||||
:host {
|
:host {
|
||||||
display: block;
|
display: block;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
padding-top: 64px;
|
background-color: #f2f4f9;
|
||||||
background-color: white;
|
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
}
|
}
|
||||||
.container {
|
.container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
justify-content: space-evenly;
|
||||||
}
|
}
|
||||||
img {
|
img {
|
||||||
width: 717px;
|
max-width: 80%;
|
||||||
height: 376px;
|
object-fit: cover;
|
||||||
display: block;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
}
|
||||||
.status {
|
.status {
|
||||||
padding-right: 54px;
|
color: #1d2126;
|
||||||
padding-inline-end: 54px;
|
|
||||||
padding-inline-start: initial;
|
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class HcLovelace extends LitElement {
|
|||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
public lovelaceConfig!: LovelaceConfig;
|
public lovelaceConfig!: LovelaceConfig;
|
||||||
|
|
||||||
@property() public viewPath?: string | number;
|
@property() public viewPath?: string | number | null;
|
||||||
|
|
||||||
@property() public urlPath: string | null = null;
|
@property() public urlPath: string | null = null;
|
||||||
|
|
||||||
@@ -93,6 +93,9 @@ class HcLovelace extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private get _viewIndex() {
|
private get _viewIndex() {
|
||||||
|
if (this.viewPath === null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
const selectedView = this.viewPath;
|
const selectedView = this.viewPath;
|
||||||
const selectedViewInt = parseInt(selectedView as string, 10);
|
const selectedViewInt = parseInt(selectedView as string, 10);
|
||||||
for (let i = 0; i < this.lovelaceConfig.views.length; i++) {
|
for (let i = 0; i < this.lovelaceConfig.views.length; i++) {
|
||||||
|
|||||||
@@ -51,10 +51,10 @@ export class HcMain extends HassElement {
|
|||||||
|
|
||||||
@state() private _lovelacePath: string | number | null = null;
|
@state() private _lovelacePath: string | number | null = null;
|
||||||
|
|
||||||
@state() private _error?: string;
|
|
||||||
|
|
||||||
@state() private _urlPath?: string | null;
|
@state() private _urlPath?: string | null;
|
||||||
|
|
||||||
|
@state() private _error?: string;
|
||||||
|
|
||||||
private _hassUUID?: string;
|
private _hassUUID?: string;
|
||||||
|
|
||||||
private _unsubLovelace?: UnsubscribeFunc;
|
private _unsubLovelace?: UnsubscribeFunc;
|
||||||
@@ -81,7 +81,7 @@ export class HcMain extends HassElement {
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
!this._lovelaceConfig ||
|
!this._lovelaceConfig ||
|
||||||
this._lovelacePath === null ||
|
this._urlPath === undefined ||
|
||||||
// Guard against part of HA not being loaded yet.
|
// Guard against part of HA not being loaded yet.
|
||||||
!this.hass ||
|
!this.hass ||
|
||||||
!this.hass.states ||
|
!this.hass.states ||
|
||||||
@@ -99,8 +99,8 @@ export class HcMain extends HassElement {
|
|||||||
<hc-lovelace
|
<hc-lovelace
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.lovelaceConfig=${this._lovelaceConfig}
|
.lovelaceConfig=${this._lovelaceConfig}
|
||||||
.viewPath=${this._lovelacePath}
|
|
||||||
.urlPath=${this._urlPath}
|
.urlPath=${this._urlPath}
|
||||||
|
.viewPath=${this._lovelacePath}
|
||||||
@config-refresh=${this._generateDefaultLovelaceConfig}
|
@config-refresh=${this._generateDefaultLovelaceConfig}
|
||||||
></hc-lovelace>
|
></hc-lovelace>
|
||||||
`;
|
`;
|
||||||
@@ -226,9 +226,9 @@ export class HcMain extends HassElement {
|
|||||||
this.initializeHass(auth, connection);
|
this.initializeHass(auth, connection);
|
||||||
if (this._hassUUID !== msg.hassUUID) {
|
if (this._hassUUID !== msg.hassUUID) {
|
||||||
this._hassUUID = msg.hassUUID;
|
this._hassUUID = msg.hassUUID;
|
||||||
this._lovelacePath = null;
|
|
||||||
this._urlPath = undefined;
|
|
||||||
this._lovelaceConfig = undefined;
|
this._lovelaceConfig = undefined;
|
||||||
|
this._urlPath = undefined;
|
||||||
|
this._lovelacePath = null;
|
||||||
if (this._unsubLovelace) {
|
if (this._unsubLovelace) {
|
||||||
this._unsubLovelace();
|
this._unsubLovelace();
|
||||||
this._unsubLovelace = undefined;
|
this._unsubLovelace = undefined;
|
||||||
@@ -270,7 +270,7 @@ export class HcMain extends HassElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._error = undefined;
|
this._error = undefined;
|
||||||
if (msg.urlPath === "lovelace") {
|
if (msg.urlPath === "lovelace" || msg.urlPath === undefined) {
|
||||||
msg.urlPath = null;
|
msg.urlPath = null;
|
||||||
}
|
}
|
||||||
this._lovelacePath = msg.viewPath;
|
this._lovelacePath = msg.viewPath;
|
||||||
@@ -285,7 +285,7 @@ export class HcMain extends HassElement {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
this._urlPath = "energy";
|
this._urlPath = "energy";
|
||||||
this._lovelacePath = 0;
|
this._lovelacePath = null;
|
||||||
this._sendStatus();
|
this._sendStatus();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { energyEntities } from "../stubs/entities";
|
|||||||
import { DemoConfig } from "./types";
|
import { DemoConfig } from "./types";
|
||||||
|
|
||||||
export const demoConfigs: Array<() => Promise<DemoConfig>> = [
|
export const demoConfigs: Array<() => Promise<DemoConfig>> = [
|
||||||
|
() => import("./sections").then((mod) => mod.demoSections),
|
||||||
() => import("./arsaboo").then((mod) => mod.demoArsaboo),
|
() => import("./arsaboo").then((mod) => mod.demoArsaboo),
|
||||||
() => import("./teachingbirds").then((mod) => mod.demoTeachingbirds),
|
() => import("./teachingbirds").then((mod) => mod.demoTeachingbirds),
|
||||||
() => import("./kernehed").then((mod) => mod.demoKernehed),
|
() => import("./kernehed").then((mod) => mod.demoKernehed),
|
||||||
|
|||||||
16
demo/src/configs/sections/description.ts
Normal file
16
demo/src/configs/sections/description.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { html } from "lit";
|
||||||
|
import { DemoConfig } from "../types";
|
||||||
|
|
||||||
|
export const demoLovelaceDescription: DemoConfig["description"] = (
|
||||||
|
localize
|
||||||
|
) => html`
|
||||||
|
<p>
|
||||||
|
${localize("ui.panel.page-demo.config.sections.description", {
|
||||||
|
blog_post: html`<a
|
||||||
|
href="https://www.home-assistant.io/blog/2024/03/04/dashboard-chapter-1/"
|
||||||
|
target="_blank"
|
||||||
|
>${localize("ui.panel.page-demo.config.sections.description_blog_post")}
|
||||||
|
</a>`,
|
||||||
|
})}
|
||||||
|
</p>
|
||||||
|
`;
|
||||||
474
demo/src/configs/sections/entities.ts
Normal file
474
demo/src/configs/sections/entities.ts
Normal file
@@ -0,0 +1,474 @@
|
|||||||
|
import { convertEntities } from "../../../../src/fake_data/entity";
|
||||||
|
import { DemoConfig } from "../types";
|
||||||
|
|
||||||
|
export const demoEntitiesSections: DemoConfig["entities"] = () =>
|
||||||
|
convertEntities({
|
||||||
|
"cover.living_room_garden_shutter": {
|
||||||
|
entity_id: "cover.living_room_garden_shutter",
|
||||||
|
state: "open",
|
||||||
|
attributes: {
|
||||||
|
current_position: 100,
|
||||||
|
device_class: "shutter",
|
||||||
|
friendly_name: "Living room garden shutter",
|
||||||
|
supported_features: 15,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"cover.living_room_graveyard_shutter": {
|
||||||
|
entity_id: "cover.living_room_graveyard_shutter",
|
||||||
|
state: "open",
|
||||||
|
attributes: {
|
||||||
|
current_position: 100,
|
||||||
|
device_class: "shutter",
|
||||||
|
friendly_name: "Living room graveyard shutter",
|
||||||
|
supported_features: 15,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"cover.living_room_left_shutter": {
|
||||||
|
entity_id: "cover.living_room_left_shutter",
|
||||||
|
state: "open",
|
||||||
|
attributes: {
|
||||||
|
current_position: 100,
|
||||||
|
device_class: "shutter",
|
||||||
|
friendly_name: "Living room left shutter",
|
||||||
|
supported_features: 15,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"cover.living_room_right_shutter": {
|
||||||
|
entity_id: "cover.living_room_right_shutter",
|
||||||
|
state: "open",
|
||||||
|
attributes: {
|
||||||
|
current_position: 100,
|
||||||
|
device_class: "shutter",
|
||||||
|
friendly_name: "Living room right shutter",
|
||||||
|
supported_features: 15,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"light.floor_lamp": {
|
||||||
|
entity_id: "light.floor_lamp",
|
||||||
|
state: "on",
|
||||||
|
attributes: {
|
||||||
|
min_color_temp_kelvin: 2000,
|
||||||
|
max_color_temp_kelvin: 6535,
|
||||||
|
min_mireds: 153,
|
||||||
|
max_mireds: 500,
|
||||||
|
supported_color_modes: ["color_temp", "xy"],
|
||||||
|
color_mode: "color_temp",
|
||||||
|
brightness: 178,
|
||||||
|
color_temp_kelvin: 2583,
|
||||||
|
color_temp: 387,
|
||||||
|
hs_color: [28.664, 69.597],
|
||||||
|
rgb_color: [255, 162, 77],
|
||||||
|
xy_color: [0.538, 0.389],
|
||||||
|
icon: "mdi:floor-lamp",
|
||||||
|
friendly_name: "Floor lamp",
|
||||||
|
supported_features: 44,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"light.living_room_spotlights": {
|
||||||
|
entity_id: "light.living_room_spotlights",
|
||||||
|
state: "on",
|
||||||
|
attributes: {
|
||||||
|
supported_color_modes: ["brightness"],
|
||||||
|
color_mode: "brightness",
|
||||||
|
brightness: 126,
|
||||||
|
icon: "mdi:ceiling-light-multiple",
|
||||||
|
friendly_name: "Living room spotlights",
|
||||||
|
supported_features: 32,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"light.bar_lamp": {
|
||||||
|
entity_id: "light.bar_lamp",
|
||||||
|
state: "on",
|
||||||
|
attributes: {
|
||||||
|
min_color_temp_kelvin: 2202,
|
||||||
|
max_color_temp_kelvin: 4504,
|
||||||
|
min_mireds: 222,
|
||||||
|
max_mireds: 454,
|
||||||
|
effect_list: ["None", "candle"],
|
||||||
|
supported_color_modes: ["color_temp"],
|
||||||
|
effect: null,
|
||||||
|
color_mode: null,
|
||||||
|
brightness: null,
|
||||||
|
color_temp_kelvin: null,
|
||||||
|
color_temp: null,
|
||||||
|
hs_color: null,
|
||||||
|
rgb_color: null,
|
||||||
|
xy_color: null,
|
||||||
|
mode: "normal",
|
||||||
|
dynamics: "none",
|
||||||
|
icon: "mdi:lightbulb-variant",
|
||||||
|
friendly_name: "Bar lamp",
|
||||||
|
supported_features: 44,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sensor.living_room_temperature": {
|
||||||
|
entity_id: "sensor.living_room_temperature",
|
||||||
|
state: "22.8",
|
||||||
|
attributes: {
|
||||||
|
state_class: "measurement",
|
||||||
|
unit_of_measurement: "°C",
|
||||||
|
device_class: "temperature",
|
||||||
|
friendly_name: "Living room Temperature",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"media_player.living_room_nest_mini": {
|
||||||
|
entity_id: "media_player.living_room_nest_mini",
|
||||||
|
state: "off",
|
||||||
|
attributes: {
|
||||||
|
device_class: "speaker",
|
||||||
|
friendly_name: "Living room Nest Mini",
|
||||||
|
supported_features: 152461,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"cover.kitchen_shutter": {
|
||||||
|
entity_id: "cover.kitchen_shutter",
|
||||||
|
state: "open",
|
||||||
|
attributes: {
|
||||||
|
current_position: 100,
|
||||||
|
device_class: "shutter",
|
||||||
|
friendly_name: "Kitchen shutter ",
|
||||||
|
supported_features: 15,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"light.kitchen_spotlights": {
|
||||||
|
entity_id: "light.kitchen_spotlights",
|
||||||
|
state: "off",
|
||||||
|
attributes: {
|
||||||
|
supported_color_modes: ["brightness"],
|
||||||
|
color_mode: null,
|
||||||
|
brightness: null,
|
||||||
|
icon: "mdi:ceiling-light-multiple",
|
||||||
|
friendly_name: "Kitchen spotlights ",
|
||||||
|
supported_features: 32,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"light.worktop_spotlights": {
|
||||||
|
entity_id: "light.worktop_spotlights",
|
||||||
|
state: "off",
|
||||||
|
attributes: {
|
||||||
|
supported_color_modes: ["brightness"],
|
||||||
|
color_mode: null,
|
||||||
|
brightness: null,
|
||||||
|
icon: "mdi:ceiling-light-multiple",
|
||||||
|
friendly_name: "Worktop spotlights ",
|
||||||
|
supported_features: 32,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"binary_sensor.fridge_door": {
|
||||||
|
entity_id: "binary_sensor.fridge_door",
|
||||||
|
state: "off",
|
||||||
|
attributes: {
|
||||||
|
device_class: "door",
|
||||||
|
icon: "mdi:fridge",
|
||||||
|
friendly_name: "Fridge door",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"media_player.kitchen_nest_audio": {
|
||||||
|
entity_id: "media_player.kitchen_nest_audio",
|
||||||
|
state: "on",
|
||||||
|
attributes: {
|
||||||
|
device_class: "speaker",
|
||||||
|
friendly_name: "Kitchen Nest Audio",
|
||||||
|
supported_features: 152461,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"binary_sensor.tesla_wall_connector_vehicle_connected": {
|
||||||
|
entity_id: "binary_sensor.tesla_wall_connector_vehicle_connected",
|
||||||
|
state: "off",
|
||||||
|
attributes: {
|
||||||
|
device_class: "plug",
|
||||||
|
friendly_name: "Wall Connector Vehicle connected",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sensor.tesla_wall_connector_session_energy": {
|
||||||
|
entity_id: "sensor.tesla_wall_connector_session_energy",
|
||||||
|
state: "16.3",
|
||||||
|
attributes: {
|
||||||
|
state_class: "total_increasing",
|
||||||
|
unit_of_measurement: "kWh",
|
||||||
|
device_class: "energy",
|
||||||
|
friendly_name: "Tesla Wall Connector Session energy",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sensor.electric_meter_power": {
|
||||||
|
entity_id: "sensor.electric_meter_power",
|
||||||
|
state: "797.86",
|
||||||
|
attributes: {
|
||||||
|
state_class: "measurement",
|
||||||
|
unit_of_measurement: "W",
|
||||||
|
device_class: "power",
|
||||||
|
icon: "mdi:meter-electric",
|
||||||
|
friendly_name: "Electric meter Power",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sensor.eletric_meter_voltage": {
|
||||||
|
entity_id: "sensor.eletric_meter_voltage",
|
||||||
|
state: "232.19",
|
||||||
|
attributes: {
|
||||||
|
state_class: "measurement",
|
||||||
|
unit_of_measurement: "V",
|
||||||
|
device_class: "voltage",
|
||||||
|
friendly_name: "Electric meter voltage",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sensor.electricity_maps_grid_fossil_fuel_percentage": {
|
||||||
|
entity_id: "sensor.electricity_maps_grid_fossil_fuel_percentage",
|
||||||
|
state: "9.84",
|
||||||
|
attributes: {
|
||||||
|
state_class: "measurement",
|
||||||
|
country_code: "FR",
|
||||||
|
unit_of_measurement: "%",
|
||||||
|
attribution: "Data provided by Electricity Maps",
|
||||||
|
icon: "mdi:barrel",
|
||||||
|
friendly_name: "Electricity Maps Grid fossil fuel percentage",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sensor.electricity_maps_co2_intensity": {
|
||||||
|
entity_id: "sensor.electricity_maps_co2_intensity",
|
||||||
|
state: "62.0",
|
||||||
|
attributes: {
|
||||||
|
state_class: "measurement",
|
||||||
|
country_code: "FR",
|
||||||
|
unit_of_measurement: "gCO2eq/kWh",
|
||||||
|
attribution: "Data provided by Electricity Maps",
|
||||||
|
friendly_name: "Electricity Maps CO2 intensity",
|
||||||
|
icon: "mdi:molecule-co2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sun.sun": {
|
||||||
|
entity_id: "sun.sun",
|
||||||
|
state: "above_horizon",
|
||||||
|
attributes: {
|
||||||
|
next_dawn: "2024-03-05T05:50:21.964405+00:00",
|
||||||
|
next_dusk: "2024-03-04T18:08:54.311334+00:00",
|
||||||
|
next_midnight: "2024-03-05T00:00:00+00:00",
|
||||||
|
next_noon: "2024-03-05T12:00:05+00:00",
|
||||||
|
next_rising: "2024-03-05T06:23:42.739159+00:00",
|
||||||
|
next_setting: "2024-03-04T17:35:26.271171+00:00",
|
||||||
|
elevation: 30.38,
|
||||||
|
azimuth: 204.42,
|
||||||
|
rising: false,
|
||||||
|
friendly_name: "Sun",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sensor.rain": {
|
||||||
|
entity_id: "sensor.moon_phase",
|
||||||
|
state: "7.2",
|
||||||
|
attributes: {
|
||||||
|
state_class: "total_increasing",
|
||||||
|
unit_of_measurement: "mm",
|
||||||
|
device_class: "precipitation",
|
||||||
|
friendly_name: "Rain",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"climate.ground_floor": {
|
||||||
|
entity_id: "climate.ground_floor",
|
||||||
|
state: "heat",
|
||||||
|
attributes: {
|
||||||
|
hvac_modes: ["auto", "heat", "off"],
|
||||||
|
min_temp: 7,
|
||||||
|
max_temp: 35,
|
||||||
|
preset_modes: [
|
||||||
|
"comfort",
|
||||||
|
"away",
|
||||||
|
"eco",
|
||||||
|
"frost_protection",
|
||||||
|
"external",
|
||||||
|
"home",
|
||||||
|
],
|
||||||
|
current_temperature: 20.8,
|
||||||
|
temperature: 21,
|
||||||
|
preset_mode: "comfort",
|
||||||
|
icon: "mdi:home-floor-0",
|
||||||
|
friendly_name: "Ground floor Thermostat",
|
||||||
|
supported_features: 401,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"climate.first_floor": {
|
||||||
|
entity_id: "climate.first_floor",
|
||||||
|
state: "heat",
|
||||||
|
attributes: {
|
||||||
|
hvac_modes: ["auto", "heat", "off"],
|
||||||
|
min_temp: 7,
|
||||||
|
max_temp: 35,
|
||||||
|
preset_modes: [
|
||||||
|
"comfort",
|
||||||
|
"away",
|
||||||
|
"eco",
|
||||||
|
"frost_protection",
|
||||||
|
"external",
|
||||||
|
"home",
|
||||||
|
],
|
||||||
|
current_temperature: 21.7,
|
||||||
|
temperature: 21,
|
||||||
|
preset_mode: "comfort",
|
||||||
|
icon: "mdi:home-floor-1",
|
||||||
|
friendly_name: "First floor Thermostat",
|
||||||
|
supported_features: 401,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"cover.study_shutter": {
|
||||||
|
entity_id: "cover.study_shutter",
|
||||||
|
state: "open",
|
||||||
|
attributes: {
|
||||||
|
current_position: 100,
|
||||||
|
device_class: "shutter",
|
||||||
|
friendly_name: "Study shutter",
|
||||||
|
supported_features: 15,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"light.study_spotlights": {
|
||||||
|
entity_id: "light.study_spotlights",
|
||||||
|
state: "off",
|
||||||
|
attributes: {
|
||||||
|
supported_color_modes: ["brightness"],
|
||||||
|
color_mode: null,
|
||||||
|
brightness: null,
|
||||||
|
icon: "mdi:ceiling-light-multiple",
|
||||||
|
friendly_name: "Study spotlights",
|
||||||
|
supported_features: 32,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"media_player.study_nest_hub": {
|
||||||
|
entity_id: "media_player.study_nest_hub",
|
||||||
|
state: "off",
|
||||||
|
attributes: {
|
||||||
|
friendly_name: "Study Nest Hub",
|
||||||
|
supported_features: 152461,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sensor.standing_desk_height": {
|
||||||
|
entity_id: "sensor.standing_desk_height",
|
||||||
|
state: "72",
|
||||||
|
attributes: {
|
||||||
|
unit_of_measurement: "cm",
|
||||||
|
icon: "mdi:tape-measure",
|
||||||
|
friendly_name: "Standing desk Height",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"light.outdoor_light": {
|
||||||
|
entity_id: "light.outdoor_light",
|
||||||
|
state: "on",
|
||||||
|
attributes: {
|
||||||
|
supported_color_modes: ["brightness"],
|
||||||
|
color_mode: null,
|
||||||
|
brightness: 255,
|
||||||
|
icon: "mdi:outdoor-lamp",
|
||||||
|
friendly_name: "Outdoor light",
|
||||||
|
supported_features: 32,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"light.flood_light": {
|
||||||
|
entity_id: "light.flood_light",
|
||||||
|
state: "off",
|
||||||
|
attributes: {
|
||||||
|
effect_list: ["None", "candle"],
|
||||||
|
supported_color_modes: ["brightness"],
|
||||||
|
effect: null,
|
||||||
|
color_mode: null,
|
||||||
|
brightness: null,
|
||||||
|
mode: "normal",
|
||||||
|
dynamics: "none",
|
||||||
|
icon: "mdi:light-flood-down",
|
||||||
|
friendly_name: "Flood light",
|
||||||
|
supported_features: 44,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sensor.outdoor_motion_sensor_temperature": {
|
||||||
|
entity_id: "sensor.outdoor_motion_sensor_temperature",
|
||||||
|
state: "10.2",
|
||||||
|
attributes: {
|
||||||
|
state_class: "measurement",
|
||||||
|
unit_of_measurement: "°C",
|
||||||
|
device_class: "temperature",
|
||||||
|
friendly_name: "Outdoor motion sensor Temperature",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"binary_sensor.outdoor_motion_sensor_motion": {
|
||||||
|
entity_id: "binary_sensor.outdoor_motion_sensor_motion",
|
||||||
|
state: "off",
|
||||||
|
attributes: {
|
||||||
|
device_class: "motion",
|
||||||
|
friendly_name: "Outdoor motion sensor Motion",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"sensor.outdoor_motion_sensor_illuminance": {
|
||||||
|
entity_id: "sensor.outdoor_motion_sensor_illuminance",
|
||||||
|
state: "555",
|
||||||
|
attributes: {
|
||||||
|
state_class: "measurement",
|
||||||
|
light_level: 27444,
|
||||||
|
unit_of_measurement: "lx",
|
||||||
|
device_class: "illuminance",
|
||||||
|
friendly_name: "Outdoor motion sensor Illuminance",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"automation.home_assistant_auto_update": {
|
||||||
|
entity_id: "automation.home_assistant_auto_update",
|
||||||
|
state: "off",
|
||||||
|
attributes: {
|
||||||
|
id: "1700669321947",
|
||||||
|
last_triggered: "2024-02-29T18:02:05.343139+00:00",
|
||||||
|
mode: "queued",
|
||||||
|
current: 0,
|
||||||
|
max: 50,
|
||||||
|
icon: "mdi:auto-mode",
|
||||||
|
friendly_name: "Home Assistant Auto-update",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"update.home_assistant_operating_system_update": {
|
||||||
|
entity_id: "update.home_assistant_operating_system_update",
|
||||||
|
state: "off",
|
||||||
|
attributes: {
|
||||||
|
auto_update: false,
|
||||||
|
installed_version: "12.1",
|
||||||
|
in_progress: false,
|
||||||
|
latest_version: "12.1",
|
||||||
|
release_summary: null,
|
||||||
|
release_url:
|
||||||
|
"https://github.com/home-assistant/operating-system/commits/dev",
|
||||||
|
skipped_version: null,
|
||||||
|
title: "Home Assistant Operating System",
|
||||||
|
entity_picture:
|
||||||
|
"https://brands.home-assistant.io/homeassistant/icon.png",
|
||||||
|
friendly_name: "Home Assistant Operating System Update",
|
||||||
|
supported_features: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"update.home_assistant_supervisor_update": {
|
||||||
|
entity_id: "update.home_assistant_supervisor_update",
|
||||||
|
state: "off",
|
||||||
|
attributes: {
|
||||||
|
auto_update: true,
|
||||||
|
installed_version: "2024.02.2",
|
||||||
|
in_progress: false,
|
||||||
|
latest_version: "2024.02.2",
|
||||||
|
release_summary: null,
|
||||||
|
release_url:
|
||||||
|
"https://github.com/home-assistant/supervisor/commits/main",
|
||||||
|
skipped_version: null,
|
||||||
|
title: "Home Assistant Supervisor",
|
||||||
|
entity_picture: "https://brands.home-assistant.io/hassio/icon.png",
|
||||||
|
friendly_name: "Home Assistant Supervisor Update",
|
||||||
|
supported_features: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"update.home_assistant_core_update": {
|
||||||
|
entity_id: "update.home_assistant_supervisor_update",
|
||||||
|
state: "off",
|
||||||
|
attributes: {
|
||||||
|
auto_update: false,
|
||||||
|
installed_version: "2024.4.0",
|
||||||
|
in_progress: false,
|
||||||
|
latest_version: "2024.4.0",
|
||||||
|
release_summary: null,
|
||||||
|
release_url: "https://github.com/home-assistant/core/commits/dev",
|
||||||
|
skipped_version: null,
|
||||||
|
title: "Home Assistant Core",
|
||||||
|
entity_picture:
|
||||||
|
"https://brands.home-assistant.io/homeassistant/icon.png",
|
||||||
|
friendly_name: "Home Assistant Core Update",
|
||||||
|
supported_features: 11,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
14
demo/src/configs/sections/index.ts
Normal file
14
demo/src/configs/sections/index.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { DemoConfig } from "../types";
|
||||||
|
import { demoLovelaceDescription } from "./description";
|
||||||
|
import { demoEntitiesSections } from "./entities";
|
||||||
|
import { demoLovelaceSections } from "./lovelace";
|
||||||
|
|
||||||
|
export const demoSections: DemoConfig = {
|
||||||
|
authorName: "Home Assistant",
|
||||||
|
authorUrl: "https://github.com/home-assistant/frontend/",
|
||||||
|
name: "Home Demo",
|
||||||
|
description: demoLovelaceDescription,
|
||||||
|
lovelace: demoLovelaceSections,
|
||||||
|
entities: demoEntitiesSections,
|
||||||
|
theme: () => ({}),
|
||||||
|
};
|
||||||
281
demo/src/configs/sections/lovelace.ts
Normal file
281
demo/src/configs/sections/lovelace.ts
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
import { DemoConfig } from "../types";
|
||||||
|
|
||||||
|
export const demoLovelaceSections: DemoConfig["lovelace"] = () => ({
|
||||||
|
title: "Home Assistant Demo",
|
||||||
|
views: [
|
||||||
|
{
|
||||||
|
type: "sections",
|
||||||
|
title: "Demo",
|
||||||
|
path: "home",
|
||||||
|
icon: "mdi:home-assistant",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
title: "Welcome 👋",
|
||||||
|
cards: [{ type: "custom:ha-demo-card" }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cards: [
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "cover.living_room_garden_shutter",
|
||||||
|
name: "Garden",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "cover.living_room_graveyard_shutter",
|
||||||
|
name: "Rear",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "cover.living_room_left_shutter",
|
||||||
|
name: "Left",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "cover.living_room_right_shutter",
|
||||||
|
name: "Right",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "light.floor_lamp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "light.living_room_spotlights",
|
||||||
|
name: "Spotlights",
|
||||||
|
features: [
|
||||||
|
{
|
||||||
|
type: "light-brightness",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "light.bar_lamp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
graph: "line",
|
||||||
|
type: "sensor",
|
||||||
|
entity: "sensor.living_room_temperature",
|
||||||
|
detail: 1,
|
||||||
|
name: "Temperature",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "media_player.living_room_nest_mini",
|
||||||
|
name: "Nest Mini",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
title: "🛋️ Living room ",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "grid",
|
||||||
|
cards: [
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "cover.kitchen_shutter",
|
||||||
|
name: "Shutter",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "light.kitchen_spotlights",
|
||||||
|
name: "Spotlights",
|
||||||
|
features: [
|
||||||
|
{
|
||||||
|
type: "light-brightness",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "light.worktop_spotlights",
|
||||||
|
name: "Worktop",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "binary_sensor.fridge_door",
|
||||||
|
name: "Fridge",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "media_player.kitchen_nest_audio",
|
||||||
|
name: "Nest Audio",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
title: "👩🍳 Kitchen",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "grid",
|
||||||
|
cards: [
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "binary_sensor.tesla_wall_connector_vehicle_connected",
|
||||||
|
name: "EV",
|
||||||
|
icon: "mdi:car",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "sensor.tesla_wall_connector_session_energy",
|
||||||
|
name: "Last charge",
|
||||||
|
color: "green",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "sensor.electric_meter_power",
|
||||||
|
color: "deep-orange",
|
||||||
|
name: "Home power",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "sensor.eletric_meter_voltage",
|
||||||
|
name: "Voltage",
|
||||||
|
color: "deep-orange",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "sensor.electricity_maps_grid_fossil_fuel_percentage",
|
||||||
|
name: "Fossil fuel",
|
||||||
|
color: "brown",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "sensor.electricity_maps_co2_intensity",
|
||||||
|
name: "CO2 Intensity",
|
||||||
|
color: "dark-grey",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
title: "⚡️ Energy",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "grid",
|
||||||
|
cards: [
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "sun.sun",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "sensor.rain",
|
||||||
|
color: "blue",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
features: [
|
||||||
|
{
|
||||||
|
type: "target-temperature",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: "tile",
|
||||||
|
name: "Downstairs",
|
||||||
|
entity: "climate.ground_floor",
|
||||||
|
state_content: ["preset_mode", "current_temperature"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
features: [
|
||||||
|
{
|
||||||
|
type: "target-temperature",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
type: "tile",
|
||||||
|
name: "Upstairs",
|
||||||
|
entity: "climate.first_floor",
|
||||||
|
state_content: ["preset_mode", "current_temperature"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
title: "🌤️ Climate",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "grid",
|
||||||
|
cards: [
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "cover.study_shutter",
|
||||||
|
name: "Shutter",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "light.study_spotlights",
|
||||||
|
name: "Spotlights",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "media_player.study_nest_hub",
|
||||||
|
name: "Nest Hub",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "sensor.standing_desk_height",
|
||||||
|
name: "Desk",
|
||||||
|
color: "brown",
|
||||||
|
icon: "mdi:desk",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
title: "🧑💻 Study",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "grid",
|
||||||
|
cards: [
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "light.outdoor_light",
|
||||||
|
name: "Door light",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "light.flood_light",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
graph: "line",
|
||||||
|
type: "sensor",
|
||||||
|
entity: "sensor.outdoor_motion_sensor_temperature",
|
||||||
|
detail: 1,
|
||||||
|
name: "Temperature",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "binary_sensor.outdoor_motion_sensor_motion",
|
||||||
|
name: "Motion",
|
||||||
|
color: "blue",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "sensor.outdoor_motion_sensor_illuminance",
|
||||||
|
color: "amber",
|
||||||
|
name: "Illuminance",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
title: "🌳 Outdoor",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "grid",
|
||||||
|
cards: [
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "automation.home_assistant_auto_update",
|
||||||
|
name: "Auto-update",
|
||||||
|
color: "green",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "update.home_assistant_operating_system_update",
|
||||||
|
name: "OS",
|
||||||
|
icon: "mdi:home-assistant",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "update.home_assistant_supervisor_update",
|
||||||
|
icon: "mdi:home-assistant",
|
||||||
|
name: "Supervisor",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "tile",
|
||||||
|
entity: "update.home_assistant_core_update",
|
||||||
|
name: "Core",
|
||||||
|
icon: "mdi:home-assistant",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
title: "🎉 Updates",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { TemplateResult } from "lit";
|
||||||
import { LocalizeFunc } from "../../../src/common/translations/localize";
|
import { LocalizeFunc } from "../../../src/common/translations/localize";
|
||||||
import { LovelaceConfig } from "../../../src/data/lovelace/config/types";
|
import { LovelaceConfig } from "../../../src/data/lovelace/config/types";
|
||||||
import { Entity } from "../../../src/fake_data/entity";
|
import { Entity } from "../../../src/fake_data/entity";
|
||||||
@@ -7,6 +8,9 @@ export interface DemoConfig {
|
|||||||
name: string;
|
name: string;
|
||||||
authorName: string;
|
authorName: string;
|
||||||
authorUrl: string;
|
authorUrl: string;
|
||||||
|
description?:
|
||||||
|
| string
|
||||||
|
| ((localize: LocalizeFunc) => string | TemplateResult<1>);
|
||||||
lovelace: (localize: LocalizeFunc) => LovelaceConfig;
|
lovelace: (localize: LocalizeFunc) => LovelaceConfig;
|
||||||
entities: (localize: LocalizeFunc) => Entity[];
|
entities: (localize: LocalizeFunc) => Entity[];
|
||||||
theme: () => Record<string, string> | null;
|
theme: () => Record<string, string> | null;
|
||||||
|
|||||||
@@ -39,32 +39,51 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
|||||||
<div class="picker">
|
<div class="picker">
|
||||||
<div class="label">
|
<div class="label">
|
||||||
${this._switching
|
${this._switching
|
||||||
? html`<ha-circular-progress
|
? html`
|
||||||
indeterminate
|
<ha-circular-progress indeterminate></ha-circular-progress>
|
||||||
></ha-circular-progress>`
|
`
|
||||||
: until(
|
: until(
|
||||||
selectedDemoConfig.then(
|
selectedDemoConfig.then(
|
||||||
(conf) => html`
|
(conf) => html`
|
||||||
${conf.name}
|
${conf.name}
|
||||||
<small>
|
<small>
|
||||||
<a target="_blank" href=${conf.authorUrl}>
|
${this.hass.localize(
|
||||||
${this.hass.localize(
|
"ui.panel.page-demo.cards.demo.demo_by",
|
||||||
"ui.panel.page-demo.cards.demo.demo_by",
|
{
|
||||||
{ name: conf.authorName }
|
name: html`
|
||||||
)}
|
<a target="_blank" href=${conf.authorUrl}>
|
||||||
</a>
|
${conf.authorName}
|
||||||
|
</a>
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
)}
|
||||||
</small>
|
</small>
|
||||||
`
|
`
|
||||||
),
|
),
|
||||||
""
|
""
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<mwc-button @click=${this._nextConfig} .disabled=${this._switching}>
|
<mwc-button @click=${this._nextConfig} .disabled=${this._switching}>
|
||||||
${this.hass.localize("ui.panel.page-demo.cards.demo.next_demo")}
|
${this.hass.localize("ui.panel.page-demo.cards.demo.next_demo")}
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="content small-hidden">
|
<div class="content">
|
||||||
${this.hass.localize("ui.panel.page-demo.cards.demo.introduction")}
|
<p class="small-hidden">
|
||||||
|
${this.hass.localize("ui.panel.page-demo.cards.demo.introduction")}
|
||||||
|
</p>
|
||||||
|
${until(
|
||||||
|
selectedDemoConfig.then((conf) => {
|
||||||
|
if (typeof conf.description === "function") {
|
||||||
|
return conf.description(this.hass.localize);
|
||||||
|
}
|
||||||
|
if (conf.description) {
|
||||||
|
return html`<p>${conf.description}</p>`;
|
||||||
|
}
|
||||||
|
return nothing;
|
||||||
|
}),
|
||||||
|
nothing
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div class="actions small-hidden">
|
<div class="actions small-hidden">
|
||||||
<a href="https://www.home-assistant.io" target="_blank">
|
<a href="https://www.home-assistant.io" target="_blank">
|
||||||
@@ -108,6 +127,7 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
|||||||
css`
|
css`
|
||||||
a {
|
a {
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.actions a {
|
.actions a {
|
||||||
@@ -115,7 +135,11 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
padding: 16px;
|
padding: 0 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content p {
|
||||||
|
margin: 16px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.picker {
|
.picker {
|
||||||
@@ -138,9 +162,8 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.actions {
|
.actions {
|
||||||
padding-left: 8px;
|
padding: 0px 8px 4px 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: 500px) {
|
@media only screen and (max-width: 500px) {
|
||||||
.small-hidden {
|
.small-hidden {
|
||||||
display: none;
|
display: none;
|
||||||
|
|||||||
@@ -17,12 +17,14 @@ import { energyEntities } from "./stubs/entities";
|
|||||||
import { mockEntityRegistry } from "./stubs/entity_registry";
|
import { mockEntityRegistry } from "./stubs/entity_registry";
|
||||||
import { mockEvents } from "./stubs/events";
|
import { mockEvents } from "./stubs/events";
|
||||||
import { mockFrontend } from "./stubs/frontend";
|
import { mockFrontend } from "./stubs/frontend";
|
||||||
|
import { mockIcons } from "./stubs/icons";
|
||||||
import { mockHistory } from "./stubs/history";
|
import { mockHistory } from "./stubs/history";
|
||||||
import { mockLovelace } from "./stubs/lovelace";
|
import { mockLovelace } from "./stubs/lovelace";
|
||||||
import { mockMediaPlayer } from "./stubs/media_player";
|
import { mockMediaPlayer } from "./stubs/media_player";
|
||||||
import { mockPersistentNotification } from "./stubs/persistent_notification";
|
import { mockPersistentNotification } from "./stubs/persistent_notification";
|
||||||
import { mockRecorder } from "./stubs/recorder";
|
import { mockRecorder } from "./stubs/recorder";
|
||||||
import { mockTodo } from "./stubs/todo";
|
import { mockTodo } from "./stubs/todo";
|
||||||
|
import { mockSensor } from "./stubs/sensor";
|
||||||
import { mockSystemLog } from "./stubs/system_log";
|
import { mockSystemLog } from "./stubs/system_log";
|
||||||
import { mockTemplate } from "./stubs/template";
|
import { mockTemplate } from "./stubs/template";
|
||||||
import { mockTranslations } from "./stubs/translations";
|
import { mockTranslations } from "./stubs/translations";
|
||||||
@@ -50,11 +52,13 @@ export class HaDemo extends HomeAssistantAppEl {
|
|||||||
mockHistory(hass);
|
mockHistory(hass);
|
||||||
mockRecorder(hass);
|
mockRecorder(hass);
|
||||||
mockTodo(hass);
|
mockTodo(hass);
|
||||||
|
mockSensor(hass);
|
||||||
mockSystemLog(hass);
|
mockSystemLog(hass);
|
||||||
mockTemplate(hass);
|
mockTemplate(hass);
|
||||||
mockEvents(hass);
|
mockEvents(hass);
|
||||||
mockMediaPlayer(hass);
|
mockMediaPlayer(hass);
|
||||||
mockFrontend(hass);
|
mockFrontend(hass);
|
||||||
|
mockIcons(hass);
|
||||||
mockEnergy(hass);
|
mockEnergy(hass);
|
||||||
mockPersistentNotification(hass);
|
mockPersistentNotification(hass);
|
||||||
mockConfigEntries(hass);
|
mockConfigEntries(hass);
|
||||||
@@ -68,6 +72,8 @@ export class HaDemo extends HomeAssistantAppEl {
|
|||||||
id: "sensor.co2_intensity",
|
id: "sensor.co2_intensity",
|
||||||
name: null,
|
name: null,
|
||||||
icon: null,
|
icon: null,
|
||||||
|
labels: [],
|
||||||
|
categories: {},
|
||||||
platform: "co2signal",
|
platform: "co2signal",
|
||||||
hidden_by: null,
|
hidden_by: null,
|
||||||
entity_category: null,
|
entity_category: null,
|
||||||
@@ -84,6 +90,8 @@ export class HaDemo extends HomeAssistantAppEl {
|
|||||||
id: "sensor.co2_intensity",
|
id: "sensor.co2_intensity",
|
||||||
name: null,
|
name: null,
|
||||||
icon: null,
|
icon: null,
|
||||||
|
labels: [],
|
||||||
|
categories: {},
|
||||||
platform: "co2signal",
|
platform: "co2signal",
|
||||||
hidden_by: null,
|
hidden_by: null,
|
||||||
entity_category: null,
|
entity_category: null,
|
||||||
|
|||||||
@@ -4,4 +4,11 @@ import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
|||||||
export const mockAreaRegistry = (
|
export const mockAreaRegistry = (
|
||||||
hass: MockHomeAssistant,
|
hass: MockHomeAssistant,
|
||||||
data: AreaRegistryEntry[] = []
|
data: AreaRegistryEntry[] = []
|
||||||
) => hass.mockWS("config/area_registry/list", () => data);
|
) => {
|
||||||
|
hass.mockWS("config/area_registry/list", () => data);
|
||||||
|
const areas = {};
|
||||||
|
data.forEach((area) => {
|
||||||
|
areas[area.area_id] = area;
|
||||||
|
});
|
||||||
|
hass.updateHass({ areas });
|
||||||
|
};
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ export const mockConfigEntries = (hass: MockHomeAssistant) => {
|
|||||||
supports_options: false,
|
supports_options: false,
|
||||||
supports_remove_device: false,
|
supports_remove_device: false,
|
||||||
supports_unload: true,
|
supports_unload: true,
|
||||||
|
supports_reconfigure: true,
|
||||||
pref_disable_new_entities: false,
|
pref_disable_new_entities: false,
|
||||||
pref_disable_polling: false,
|
pref_disable_polling: false,
|
||||||
disabled_by: null,
|
disabled_by: null,
|
||||||
|
|||||||
@@ -4,4 +4,11 @@ import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
|||||||
export const mockDeviceRegistry = (
|
export const mockDeviceRegistry = (
|
||||||
hass: MockHomeAssistant,
|
hass: MockHomeAssistant,
|
||||||
data: DeviceRegistryEntry[] = []
|
data: DeviceRegistryEntry[] = []
|
||||||
) => hass.mockWS("config/device_registry/list", () => data);
|
) => {
|
||||||
|
hass.mockWS("config/device_registry/list", () => data);
|
||||||
|
const devices = {};
|
||||||
|
data.forEach((device) => {
|
||||||
|
devices[device.id] = device;
|
||||||
|
});
|
||||||
|
hass.updateHass({ devices });
|
||||||
|
};
|
||||||
|
|||||||
7
demo/src/stubs/floor_registry.ts
Normal file
7
demo/src/stubs/floor_registry.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { FloorRegistryEntry } from "../../../src/data/floor_registry";
|
||||||
|
import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||||
|
|
||||||
|
export const mockFloorRegistry = (
|
||||||
|
hass: MockHomeAssistant,
|
||||||
|
data: FloorRegistryEntry[] = []
|
||||||
|
) => hass.mockWS("config/floor_registry/list", () => data);
|
||||||
33
demo/src/stubs/icons.ts
Normal file
33
demo/src/stubs/icons.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { IconCategory } from "../../../src/data/icons";
|
||||||
|
import { ENTITY_COMPONENT_ICONS } from "../../../src/fake_data/entity_component_icons";
|
||||||
|
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||||
|
|
||||||
|
export const mockIcons = (hass: MockHomeAssistant) => {
|
||||||
|
hass.mockWS(
|
||||||
|
"frontend/get_icons",
|
||||||
|
async ({
|
||||||
|
category,
|
||||||
|
integration,
|
||||||
|
}: {
|
||||||
|
category: IconCategory;
|
||||||
|
integration?: string;
|
||||||
|
}) => {
|
||||||
|
if (integration) {
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
`https://raw.githubusercontent.com/home-assistant/core/dev/homeassistant/components/${integration}/icons.json`
|
||||||
|
).then((resp) => resp.json());
|
||||||
|
return { resources: { [integration]: response[category] || {} } };
|
||||||
|
} catch {
|
||||||
|
return { resources: {} };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (category === "entity_component") {
|
||||||
|
return {
|
||||||
|
resources: ENTITY_COMPONENT_ICONS,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return { resources: {} };
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
7
demo/src/stubs/label_registry.ts
Normal file
7
demo/src/stubs/label_registry.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { LabelRegistryEntry } from "../../../src/data/label_registry";
|
||||||
|
import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||||
|
|
||||||
|
export const mockLabelRegistry = (
|
||||||
|
hass: MockHomeAssistant,
|
||||||
|
data: LabelRegistryEntry[] = []
|
||||||
|
) => hass.mockWS("config/label_registry/list", () => data);
|
||||||
58
demo/src/stubs/sensor.ts
Normal file
58
demo/src/stubs/sensor.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||||
|
|
||||||
|
export const mockSensor = (hass: MockHomeAssistant) => {
|
||||||
|
hass.mockWS("sensor/numeric_device_classes", () => [
|
||||||
|
{
|
||||||
|
numeric_device_classes: [
|
||||||
|
"volume_storage",
|
||||||
|
"gas",
|
||||||
|
"data_size",
|
||||||
|
"irradiance",
|
||||||
|
"wind_speed",
|
||||||
|
"volatile_organic_compounds",
|
||||||
|
"volatile_organic_compounds_parts",
|
||||||
|
"voltage",
|
||||||
|
"frequency",
|
||||||
|
"precipitation_intensity",
|
||||||
|
"volume",
|
||||||
|
"precipitation",
|
||||||
|
"battery",
|
||||||
|
"nitrogen_dioxide",
|
||||||
|
"speed",
|
||||||
|
"signal_strength",
|
||||||
|
"pm1",
|
||||||
|
"nitrous_oxide",
|
||||||
|
"atmospheric_pressure",
|
||||||
|
"data_rate",
|
||||||
|
"temperature",
|
||||||
|
"power_factor",
|
||||||
|
"aqi",
|
||||||
|
"current",
|
||||||
|
"volume_flow_rate",
|
||||||
|
"humidity",
|
||||||
|
"duration",
|
||||||
|
"ozone",
|
||||||
|
"distance",
|
||||||
|
"pressure",
|
||||||
|
"pm25",
|
||||||
|
"weight",
|
||||||
|
"energy",
|
||||||
|
"carbon_monoxide",
|
||||||
|
"apparent_power",
|
||||||
|
"illuminance",
|
||||||
|
"energy_storage",
|
||||||
|
"moisture",
|
||||||
|
"power",
|
||||||
|
"water",
|
||||||
|
"carbon_dioxide",
|
||||||
|
"ph",
|
||||||
|
"reactive_power",
|
||||||
|
"monetary",
|
||||||
|
"nitrogen_monoxide",
|
||||||
|
"pm10",
|
||||||
|
"sound_pressure",
|
||||||
|
"sulphur_dioxide",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
};
|
||||||
@@ -21,4 +21,5 @@ export const mockTodo = (hass: MockHomeAssistant) => {
|
|||||||
},
|
},
|
||||||
] as TodoItem[],
|
] as TodoItem[],
|
||||||
}));
|
}));
|
||||||
|
hass.mockWS("todo/item/subscribe", (_msg, _hass) => () => {});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Button } from "@material/mwc-button";
|
import { Button } from "@material/mwc-button";
|
||||||
import { html, LitElement, css, TemplateResult } from "lit";
|
import { html, LitElement, css, TemplateResult, nothing } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import { applyThemesOnElement } from "../../../src/common/dom/apply_themes_on_element";
|
import { applyThemesOnElement } from "../../../src/common/dom/apply_themes_on_element";
|
||||||
import { fireEvent } from "../../../src/common/dom/fire_event";
|
import { fireEvent } from "../../../src/common/dom/fire_event";
|
||||||
@@ -9,7 +9,7 @@ import "../../../src/components/ha-card";
|
|||||||
class DemoBlackWhiteRow extends LitElement {
|
class DemoBlackWhiteRow extends LitElement {
|
||||||
@property() title!: string;
|
@property() title!: string;
|
||||||
|
|
||||||
@property() value!: any;
|
@property() value?: any;
|
||||||
|
|
||||||
@property({ type: Boolean }) public disabled = false;
|
@property({ type: Boolean }) public disabled = false;
|
||||||
|
|
||||||
@@ -45,7 +45,9 @@ class DemoBlackWhiteRow extends LitElement {
|
|||||||
</mwc-button>
|
</mwc-button>
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
<pre>${JSON.stringify(this.value, undefined, 2)}</pre>
|
${this.value
|
||||||
|
? html`<pre>${JSON.stringify(this.value, undefined, 2)}</pre>`
|
||||||
|
: nothing}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ export const basicTrace: DemoTrace = {
|
|||||||
{
|
{
|
||||||
path: "trigger/0",
|
path: "trigger/0",
|
||||||
timestamp: "2021-03-25T04:36:51.223693+00:00",
|
timestamp: "2021-03-25T04:36:51.223693+00:00",
|
||||||
|
changed_variables: {},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"condition/0": [
|
"condition/0": [
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ export const motionLightTrace: DemoTrace = {
|
|||||||
{
|
{
|
||||||
path: "trigger/0",
|
path: "trigger/0",
|
||||||
timestamp: "2021-03-25T04:36:51.223693+00:00",
|
timestamp: "2021-03-25T04:36:51.223693+00:00",
|
||||||
|
changed_variables: {},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"action/0": [
|
"action/0": [
|
||||||
|
|||||||
@@ -21,10 +21,10 @@ const ENTITIES = [
|
|||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
const conditions = [
|
const conditions: Condition[] = [
|
||||||
{ condition: "and" },
|
{ condition: "and", conditions: [] },
|
||||||
{ condition: "not" },
|
{ condition: "not", conditions: [] },
|
||||||
{ condition: "or" },
|
{ condition: "or", conditions: [] },
|
||||||
{ condition: "state", entity_id: "light.kitchen", state: "on" },
|
{ condition: "state", entity_id: "light.kitchen", state: "on" },
|
||||||
{
|
{
|
||||||
condition: "numeric_state",
|
condition: "numeric_state",
|
||||||
@@ -34,11 +34,11 @@ const conditions = [
|
|||||||
above: 20,
|
above: 20,
|
||||||
},
|
},
|
||||||
{ condition: "sun", after: "sunset" },
|
{ condition: "sun", after: "sunset" },
|
||||||
{ condition: "sun", after: "sunrise", offset: "-01:00" },
|
{ condition: "sun", after: "sunrise", before_offset: 3600 },
|
||||||
{ condition: "zone", entity_id: "device_tracker.person", zone: "zone.home" },
|
{ condition: "zone", entity_id: "device_tracker.person", zone: "zone.home" },
|
||||||
{ condition: "trigger", id: "motion" },
|
{ condition: "trigger", id: "motion" },
|
||||||
{ condition: "time" },
|
{ condition: "time" },
|
||||||
{ condition: "template" },
|
{ condition: "template", value_template: "" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const initialCondition: Condition = {
|
const initialCondition: Condition = {
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
import { css, html, LitElement, nothing } from "lit";
|
import { css, html, LitElement, nothing } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import "../../../../src/components/ha-card";
|
import "../../../../src/components/ha-card";
|
||||||
import "../../../../src/components/trace/hat-script-graph";
|
|
||||||
import "../../../../src/components/trace/hat-trace-timeline";
|
import "../../../../src/components/trace/hat-trace-timeline";
|
||||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||||
import { HomeAssistant } from "../../../../src/types";
|
import { HomeAssistant } from "../../../../src/types";
|
||||||
@@ -56,6 +55,7 @@ export class DemoAutomationTraceTimeline extends LitElement {
|
|||||||
super.firstUpdated(changedProps);
|
super.firstUpdated(changedProps);
|
||||||
const hass = provideHass(this);
|
const hass = provideHass(this);
|
||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
|
hass.updateTranslations("config", "en");
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ export class DemoAutomationTrace extends LitElement {
|
|||||||
super.firstUpdated(changedProps);
|
super.firstUpdated(changedProps);
|
||||||
const hass = provideHass(this);
|
const hass = provideHass(this);
|
||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
|
hass.updateTranslations("config", "en");
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ export class DemoHaBarButton extends LitElement {
|
|||||||
}
|
}
|
||||||
.custom-group {
|
.custom-group {
|
||||||
--control-button-group-thickness: 100px;
|
--control-button-group-thickness: 100px;
|
||||||
--control-button-group-border-radius: 18px;
|
--control-button-group-border-radius: 36px;
|
||||||
--control-button-group-spacing: 20px;
|
--control-button-group-spacing: 20px;
|
||||||
}
|
}
|
||||||
.custom-group ha-control-button {
|
.custom-group ha-control-button {
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ export class DemoHarControlNumberButtons extends LitElement {
|
|||||||
--control-number-buttons-background-color: #2196f3;
|
--control-number-buttons-background-color: #2196f3;
|
||||||
--control-number-buttons-background-opacity: 0.1;
|
--control-number-buttons-background-opacity: 0.1;
|
||||||
--control-number-buttons-thickness: 100px;
|
--control-number-buttons-thickness: 100px;
|
||||||
--control-number-buttons-border-radius: 24px;
|
--control-number-buttons-border-radius: 36px;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -186,8 +186,8 @@ export class DemoHaControlSelect extends LitElement {
|
|||||||
.custom {
|
.custom {
|
||||||
--mdc-icon-size: 24px;
|
--mdc-icon-size: 24px;
|
||||||
--control-select-color: var(--state-fan-active-color);
|
--control-select-color: var(--state-fan-active-color);
|
||||||
--control-select-thickness: 100px;
|
--control-select-thickness: 130px;
|
||||||
--control-select-border-radius: 24px;
|
--control-select-border-radius: 48px;
|
||||||
}
|
}
|
||||||
.vertical-selects {
|
.vertical-selects {
|
||||||
height: 300px;
|
height: 300px;
|
||||||
|
|||||||
@@ -150,8 +150,8 @@ export class DemoHaBarSlider extends LitElement {
|
|||||||
--control-slider-color: #ffcf4c;
|
--control-slider-color: #ffcf4c;
|
||||||
--control-slider-background: #ffcf4c;
|
--control-slider-background: #ffcf4c;
|
||||||
--control-slider-background-opacity: 0.2;
|
--control-slider-background-opacity: 0.2;
|
||||||
--control-slider-thickness: 100px;
|
--control-slider-thickness: 130px;
|
||||||
--control-slider-border-radius: 24px;
|
--control-slider-border-radius: 48px;
|
||||||
}
|
}
|
||||||
.vertical-sliders {
|
.vertical-sliders {
|
||||||
height: 300px;
|
height: 300px;
|
||||||
|
|||||||
@@ -117,8 +117,8 @@ export class DemoHaControlSwitch extends LitElement {
|
|||||||
.custom {
|
.custom {
|
||||||
--control-switch-on-color: var(--green-color);
|
--control-switch-on-color: var(--green-color);
|
||||||
--control-switch-off-color: var(--red-color);
|
--control-switch-off-color: var(--red-color);
|
||||||
--control-switch-thickness: 100px;
|
--control-switch-thickness: 130px;
|
||||||
--control-switch-border-radius: 24px;
|
--control-switch-border-radius: 48px;
|
||||||
--control-switch-padding: 6px;
|
--control-switch-padding: 6px;
|
||||||
--mdc-icon-size: 24px;
|
--mdc-icon-size: 24px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ const DEVICES = [
|
|||||||
hw_version: null,
|
hw_version: null,
|
||||||
via_device_id: null,
|
via_device_id: null,
|
||||||
serial_number: null,
|
serial_number: null,
|
||||||
|
labels: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
area_id: "backyard",
|
area_id: "backyard",
|
||||||
@@ -77,6 +78,7 @@ const DEVICES = [
|
|||||||
hw_version: null,
|
hw_version: null,
|
||||||
via_device_id: null,
|
via_device_id: null,
|
||||||
serial_number: null,
|
serial_number: null,
|
||||||
|
labels: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
area_id: null,
|
area_id: null,
|
||||||
@@ -95,30 +97,37 @@ const DEVICES = [
|
|||||||
hw_version: null,
|
hw_version: null,
|
||||||
via_device_id: null,
|
via_device_id: null,
|
||||||
serial_number: null,
|
serial_number: null,
|
||||||
|
labels: [],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const AREAS: AreaRegistryEntry[] = [
|
const AREAS: AreaRegistryEntry[] = [
|
||||||
{
|
{
|
||||||
area_id: "backyard",
|
area_id: "backyard",
|
||||||
|
floor_id: null,
|
||||||
name: "Backyard",
|
name: "Backyard",
|
||||||
icon: null,
|
icon: null,
|
||||||
picture: null,
|
picture: null,
|
||||||
aliases: [],
|
aliases: [],
|
||||||
|
labels: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
area_id: "bedroom",
|
area_id: "bedroom",
|
||||||
|
floor_id: null,
|
||||||
name: "Bedroom",
|
name: "Bedroom",
|
||||||
icon: "mdi:bed",
|
icon: "mdi:bed",
|
||||||
picture: null,
|
picture: null,
|
||||||
aliases: [],
|
aliases: [],
|
||||||
|
labels: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
area_id: "livingroom",
|
area_id: "livingroom",
|
||||||
|
floor_id: null,
|
||||||
name: "Livingroom",
|
name: "Livingroom",
|
||||||
icon: "mdi:sofa",
|
icon: "mdi:sofa",
|
||||||
picture: null,
|
picture: null,
|
||||||
aliases: [],
|
aliases: [],
|
||||||
|
labels: [],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ import { provideHass } from "../../../../src/fake_data/provide_hass";
|
|||||||
import { ProvideHassElement } from "../../../../src/mixins/provide-hass-lit-mixin";
|
import { ProvideHassElement } from "../../../../src/mixins/provide-hass-lit-mixin";
|
||||||
import type { HomeAssistant } from "../../../../src/types";
|
import type { HomeAssistant } from "../../../../src/types";
|
||||||
import "../../components/demo-black-white-row";
|
import "../../components/demo-black-white-row";
|
||||||
|
import { FloorRegistryEntry } from "../../../../src/data/floor_registry";
|
||||||
|
import { LabelRegistryEntry } from "../../../../src/data/label_registry";
|
||||||
|
import { mockFloorRegistry } from "../../../../demo/src/stubs/floor_registry";
|
||||||
|
import { mockLabelRegistry } from "../../../../demo/src/stubs/label_registry";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
getEntity("alarm_control_panel", "alarm", "disarmed", {
|
getEntity("alarm_control_panel", "alarm", "disarmed", {
|
||||||
@@ -55,6 +59,7 @@ const DEVICES = [
|
|||||||
hw_version: null,
|
hw_version: null,
|
||||||
via_device_id: null,
|
via_device_id: null,
|
||||||
serial_number: null,
|
serial_number: null,
|
||||||
|
labels: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
area_id: "backyard",
|
area_id: "backyard",
|
||||||
@@ -73,6 +78,7 @@ const DEVICES = [
|
|||||||
hw_version: null,
|
hw_version: null,
|
||||||
via_device_id: null,
|
via_device_id: null,
|
||||||
serial_number: null,
|
serial_number: null,
|
||||||
|
labels: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
area_id: null,
|
area_id: null,
|
||||||
@@ -91,30 +97,76 @@ const DEVICES = [
|
|||||||
hw_version: null,
|
hw_version: null,
|
||||||
via_device_id: null,
|
via_device_id: null,
|
||||||
serial_number: null,
|
serial_number: null,
|
||||||
|
labels: [],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const AREAS: AreaRegistryEntry[] = [
|
const AREAS: AreaRegistryEntry[] = [
|
||||||
{
|
{
|
||||||
area_id: "backyard",
|
area_id: "backyard",
|
||||||
|
floor_id: "ground",
|
||||||
name: "Backyard",
|
name: "Backyard",
|
||||||
icon: null,
|
icon: null,
|
||||||
picture: null,
|
picture: null,
|
||||||
aliases: [],
|
aliases: [],
|
||||||
|
labels: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
area_id: "bedroom",
|
area_id: "bedroom",
|
||||||
|
floor_id: "first",
|
||||||
name: "Bedroom",
|
name: "Bedroom",
|
||||||
icon: "mdi:bed",
|
icon: "mdi:bed",
|
||||||
picture: null,
|
picture: null,
|
||||||
aliases: [],
|
aliases: [],
|
||||||
|
labels: [],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
area_id: "livingroom",
|
area_id: "livingroom",
|
||||||
|
floor_id: "ground",
|
||||||
name: "Livingroom",
|
name: "Livingroom",
|
||||||
icon: "mdi:sofa",
|
icon: "mdi:sofa",
|
||||||
picture: null,
|
picture: null,
|
||||||
aliases: [],
|
aliases: [],
|
||||||
|
labels: [],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const FLOORS: FloorRegistryEntry[] = [
|
||||||
|
{
|
||||||
|
floor_id: "ground",
|
||||||
|
name: "Ground floor",
|
||||||
|
level: 0,
|
||||||
|
icon: null,
|
||||||
|
aliases: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
floor_id: "first",
|
||||||
|
name: "First floor",
|
||||||
|
level: 1,
|
||||||
|
icon: "mdi:numeric-1",
|
||||||
|
aliases: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
floor_id: "second",
|
||||||
|
name: "Second floor",
|
||||||
|
level: 2,
|
||||||
|
icon: "mdi:numeric-2",
|
||||||
|
aliases: [],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const LABELS: LabelRegistryEntry[] = [
|
||||||
|
{
|
||||||
|
label_id: "energy",
|
||||||
|
name: "Energy",
|
||||||
|
icon: null,
|
||||||
|
color: "yellow",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label_id: "entertainment",
|
||||||
|
name: "Entertainment",
|
||||||
|
icon: "mdi:popcorn",
|
||||||
|
color: "blue",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -125,7 +177,12 @@ const SCHEMAS: {
|
|||||||
{
|
{
|
||||||
name: "One of each",
|
name: "One of each",
|
||||||
input: {
|
input: {
|
||||||
|
label: { name: "Label", selector: { label: {} } },
|
||||||
|
floor: { name: "Floor", selector: { floor: {} } },
|
||||||
|
area: { name: "Area", selector: { area: {} } },
|
||||||
|
device: { name: "Device", selector: { device: {} } },
|
||||||
entity: { name: "Entity", selector: { entity: {} } },
|
entity: { name: "Entity", selector: { entity: {} } },
|
||||||
|
target: { name: "Target", selector: { target: {} } },
|
||||||
state: {
|
state: {
|
||||||
name: "State",
|
name: "State",
|
||||||
selector: { state: { entity_id: "alarm_control_panel.alarm" } },
|
selector: { state: { entity_id: "alarm_control_panel.alarm" } },
|
||||||
@@ -134,15 +191,12 @@ const SCHEMAS: {
|
|||||||
name: "Attribute",
|
name: "Attribute",
|
||||||
selector: { attribute: { entity_id: "" } },
|
selector: { attribute: { entity_id: "" } },
|
||||||
},
|
},
|
||||||
device: { name: "Device", selector: { device: {} } },
|
|
||||||
config_entry: {
|
config_entry: {
|
||||||
name: "Integration",
|
name: "Integration",
|
||||||
selector: { config_entry: {} },
|
selector: { config_entry: {} },
|
||||||
},
|
},
|
||||||
duration: { name: "Duration", selector: { duration: {} } },
|
duration: { name: "Duration", selector: { duration: {} } },
|
||||||
addon: { name: "Addon", selector: { addon: {} } },
|
addon: { name: "Addon", selector: { addon: {} } },
|
||||||
area: { name: "Area", selector: { area: {} } },
|
|
||||||
target: { name: "Target", selector: { target: {} } },
|
|
||||||
number_box: {
|
number_box: {
|
||||||
name: "Number Box",
|
name: "Number Box",
|
||||||
selector: {
|
selector: {
|
||||||
@@ -275,6 +329,14 @@ const SCHEMAS: {
|
|||||||
selector: { color_temp: {} },
|
selector: { color_temp: {} },
|
||||||
},
|
},
|
||||||
color_rgb: { name: "Color", selector: { color_rgb: {} } },
|
color_rgb: { name: "Color", selector: { color_rgb: {} } },
|
||||||
|
qr_code: {
|
||||||
|
name: "QR Code",
|
||||||
|
selector: { qr_code: { data: "https://home-assistant.io" } },
|
||||||
|
},
|
||||||
|
constant: {
|
||||||
|
name: "Constant",
|
||||||
|
selector: { constant: { value: true, label: "Yes!" } },
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -283,6 +345,8 @@ const SCHEMAS: {
|
|||||||
entity: { name: "Entity", selector: { entity: { multiple: true } } },
|
entity: { name: "Entity", selector: { entity: { multiple: true } } },
|
||||||
device: { name: "Device", selector: { device: { multiple: true } } },
|
device: { name: "Device", selector: { device: { multiple: true } } },
|
||||||
area: { name: "Area", selector: { area: { multiple: true } } },
|
area: { name: "Area", selector: { area: { multiple: true } } },
|
||||||
|
floor: { name: "Floor", selector: { floor: { multiple: true } } },
|
||||||
|
label: { name: "Label", selector: { label: { multiple: true } } },
|
||||||
select: {
|
select: {
|
||||||
name: "Select Multiple",
|
name: "Select Multiple",
|
||||||
selector: {
|
selector: {
|
||||||
@@ -339,6 +403,8 @@ class DemoHaSelector extends LitElement implements ProvideHassElement {
|
|||||||
mockDeviceRegistry(hass, DEVICES);
|
mockDeviceRegistry(hass, DEVICES);
|
||||||
mockConfigEntries(hass);
|
mockConfigEntries(hass);
|
||||||
mockAreaRegistry(hass, AREAS);
|
mockAreaRegistry(hass, AREAS);
|
||||||
|
mockFloorRegistry(hass, FLOORS);
|
||||||
|
mockLabelRegistry(hass, LABELS);
|
||||||
mockHassioSupervisor(hass);
|
mockHassioSupervisor(hass);
|
||||||
hass.mockWS("auth/sign_path", (params) => params);
|
hass.mockWS("auth/sign_path", (params) => params);
|
||||||
hass.mockWS("media_player/browse_media", this._browseMedia);
|
hass.mockWS("media_player/browse_media", this._browseMedia);
|
||||||
@@ -501,7 +567,7 @@ class DemoHaSelector extends LitElement implements ProvideHassElement {
|
|||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
};
|
};
|
||||||
return html`
|
return html`
|
||||||
<demo-black-white-row .title=${info.name} .value=${this.data[idx]}>
|
<demo-black-white-row .title=${info.name}>
|
||||||
${["light", "dark"].map((slot) =>
|
${["light", "dark"].map((slot) =>
|
||||||
Object.entries(info.input).map(
|
Object.entries(info.input).map(
|
||||||
([key, value]) => html`
|
([key, value]) => html`
|
||||||
@@ -534,8 +600,8 @@ class DemoHaSelector extends LitElement implements ProvideHassElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static styles = css`
|
static styles = css`
|
||||||
ha-selector {
|
ha-settings-row {
|
||||||
width: 60;
|
--paper-item-body-two-line-min-height: 0;
|
||||||
}
|
}
|
||||||
.options {
|
.options {
|
||||||
max-width: 800px;
|
max-width: 800px;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { customElement, query } from "lit/decorators";
|
|||||||
import { getEntity } from "../../../../src/fake_data/entity";
|
import { getEntity } from "../../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||||
import "../../components/demo-cards";
|
import "../../components/demo-cards";
|
||||||
|
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
getEntity("alarm_control_panel", "alarm", "disarmed", {
|
getEntity("alarm_control_panel", "alarm", "disarmed", {
|
||||||
@@ -84,6 +85,7 @@ class DemoAlarmPanelEntity extends LitElement {
|
|||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
hass.updateTranslations("lovelace", "en");
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
|
mockIcons(hass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { customElement, query } from "lit/decorators";
|
|||||||
import { getEntity } from "../../../../src/fake_data/entity";
|
import { getEntity } from "../../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||||
import "../../components/demo-cards";
|
import "../../components/demo-cards";
|
||||||
|
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
getEntity("light", "bed_light", "on", {
|
getEntity("light", "bed_light", "on", {
|
||||||
@@ -146,6 +147,7 @@ class DemoArea extends LitElement {
|
|||||||
entity_id: "binary_sensor.kitchen_door",
|
entity_id: "binary_sensor.kitchen_door",
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
mockIcons(hass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { customElement, query } from "lit/decorators";
|
|||||||
import { getEntity } from "../../../../src/fake_data/entity";
|
import { getEntity } from "../../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||||
import "../../components/demo-cards";
|
import "../../components/demo-cards";
|
||||||
|
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
getEntity("light", "controller_1", "on", {
|
getEntity("light", "controller_1", "on", {
|
||||||
@@ -66,6 +67,7 @@ class DemoConditional extends LitElement {
|
|||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
hass.updateTranslations("lovelace", "en");
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
|
mockIcons(hass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { customElement, query } from "lit/decorators";
|
|||||||
import { getEntity } from "../../../../src/fake_data/entity";
|
import { getEntity } from "../../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||||
import "../../components/demo-cards";
|
import "../../components/demo-cards";
|
||||||
|
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
getEntity("light", "bed_light", "on", {
|
getEntity("light", "bed_light", "on", {
|
||||||
@@ -323,6 +324,7 @@ class DemoEntities extends LitElement {
|
|||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
hass.updateTranslations("lovelace", "en");
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
|
mockIcons(hass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { customElement, query } from "lit/decorators";
|
|||||||
import { getEntity } from "../../../../src/fake_data/entity";
|
import { getEntity } from "../../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||||
import "../../components/demo-cards";
|
import "../../components/demo-cards";
|
||||||
|
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
getEntity("light", "bed_light", "on", {
|
getEntity("light", "bed_light", "on", {
|
||||||
@@ -82,6 +83,7 @@ class DemoButtonEntity extends LitElement {
|
|||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
hass.updateTranslations("lovelace", "en");
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
|
mockIcons(hass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { customElement, query } from "lit/decorators";
|
|||||||
import { getEntity } from "../../../../src/fake_data/entity";
|
import { getEntity } from "../../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||||
import "../../components/demo-cards";
|
import "../../components/demo-cards";
|
||||||
|
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
getEntity("device_tracker", "demo_paulus", "work", {
|
getEntity("device_tracker", "demo_paulus", "work", {
|
||||||
@@ -10,7 +11,7 @@ const ENTITIES = [
|
|||||||
latitude: 32.877105,
|
latitude: 32.877105,
|
||||||
longitude: 117.232185,
|
longitude: 117.232185,
|
||||||
gps_accuracy: 91,
|
gps_accuracy: 91,
|
||||||
battery: 71,
|
battery: 25,
|
||||||
friendly_name: "Paulus",
|
friendly_name: "Paulus",
|
||||||
}),
|
}),
|
||||||
getEntity("device_tracker", "demo_anne_therese", "school", {
|
getEntity("device_tracker", "demo_anne_therese", "school", {
|
||||||
@@ -18,7 +19,7 @@ const ENTITIES = [
|
|||||||
latitude: 32.877105,
|
latitude: 32.877105,
|
||||||
longitude: 117.232185,
|
longitude: 117.232185,
|
||||||
gps_accuracy: 91,
|
gps_accuracy: 91,
|
||||||
battery: 71,
|
battery: 50,
|
||||||
friendly_name: "Anne Therese",
|
friendly_name: "Anne Therese",
|
||||||
}),
|
}),
|
||||||
getEntity("device_tracker", "demo_home_boy", "home", {
|
getEntity("device_tracker", "demo_home_boy", "home", {
|
||||||
@@ -26,7 +27,7 @@ const ENTITIES = [
|
|||||||
latitude: 32.877105,
|
latitude: 32.877105,
|
||||||
longitude: 117.232185,
|
longitude: 117.232185,
|
||||||
gps_accuracy: 91,
|
gps_accuracy: 91,
|
||||||
battery: 71,
|
battery: 75,
|
||||||
friendly_name: "Home Boy",
|
friendly_name: "Home Boy",
|
||||||
}),
|
}),
|
||||||
getEntity("light", "bed_light", "on", {
|
getEntity("light", "bed_light", "on", {
|
||||||
@@ -38,21 +39,53 @@ const ENTITIES = [
|
|||||||
getEntity("light", "ceiling_lights", "off", {
|
getEntity("light", "ceiling_lights", "off", {
|
||||||
friendly_name: "Ceiling Lights",
|
friendly_name: "Ceiling Lights",
|
||||||
}),
|
}),
|
||||||
|
getEntity("sensor", "battery_1", 20, {
|
||||||
|
device_class: "battery",
|
||||||
|
friendly_name: "Battery 1",
|
||||||
|
unit_of_measurement: "%",
|
||||||
|
}),
|
||||||
|
getEntity("sensor", "battery_2", 35, {
|
||||||
|
device_class: "battery",
|
||||||
|
friendly_name: "Battery 2",
|
||||||
|
unit_of_measurement: "%",
|
||||||
|
}),
|
||||||
|
getEntity("sensor", "battery_3", 40, {
|
||||||
|
device_class: "battery",
|
||||||
|
friendly_name: "Battery 3",
|
||||||
|
unit_of_measurement: "%",
|
||||||
|
}),
|
||||||
|
getEntity("sensor", "battery_4", 80, {
|
||||||
|
device_class: "battery",
|
||||||
|
friendly_name: "Battery 4",
|
||||||
|
unit_of_measurement: "%",
|
||||||
|
}),
|
||||||
|
getEntity("input_number", "min_battery_level", 30, {
|
||||||
|
mode: "slider",
|
||||||
|
step: 10,
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
icon: "mdi:battery-alert-variant",
|
||||||
|
friendly_name: "Minimum Battery Level",
|
||||||
|
unit_of_measurement: "%",
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
const CONFIGS = [
|
const CONFIGS = [
|
||||||
{
|
{
|
||||||
heading: "Unfiltered controller",
|
heading: "Unfiltered entities",
|
||||||
config: `
|
config: `
|
||||||
- type: entities
|
- type: entities
|
||||||
entities:
|
entities:
|
||||||
- light.bed_light
|
- device_tracker.demo_anne_therese
|
||||||
- light.ceiling_lights
|
- device_tracker.demo_home_boy
|
||||||
- light.kitchen_lights
|
- device_tracker.demo_paulus
|
||||||
|
- light.bed_light
|
||||||
|
- light.ceiling_lights
|
||||||
|
- light.kitchen_lights
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
heading: "Filtered entities card",
|
heading: "On and home entities",
|
||||||
config: `
|
config: `
|
||||||
- type: entity-filter
|
- type: entity-filter
|
||||||
entities:
|
entities:
|
||||||
@@ -62,9 +95,28 @@ const CONFIGS = [
|
|||||||
- light.bed_light
|
- light.bed_light
|
||||||
- light.ceiling_lights
|
- light.ceiling_lights
|
||||||
- light.kitchen_lights
|
- light.kitchen_lights
|
||||||
state_filter:
|
conditions:
|
||||||
- "on"
|
- condition: state
|
||||||
- home
|
state:
|
||||||
|
- "on"
|
||||||
|
- home
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Same state as Bed Light",
|
||||||
|
config: `
|
||||||
|
- type: entity-filter
|
||||||
|
entities:
|
||||||
|
- device_tracker.demo_anne_therese
|
||||||
|
- device_tracker.demo_home_boy
|
||||||
|
- device_tracker.demo_paulus
|
||||||
|
- light.bed_light
|
||||||
|
- light.ceiling_lights
|
||||||
|
- light.kitchen_lights
|
||||||
|
conditions:
|
||||||
|
- condition: state
|
||||||
|
state:
|
||||||
|
- light.bed_light
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -78,9 +130,11 @@ const CONFIGS = [
|
|||||||
- light.bed_light
|
- light.bed_light
|
||||||
- light.ceiling_lights
|
- light.ceiling_lights
|
||||||
- light.kitchen_lights
|
- light.kitchen_lights
|
||||||
state_filter:
|
conditions:
|
||||||
- "on"
|
- condition: state
|
||||||
- not_home
|
state:
|
||||||
|
- "on"
|
||||||
|
- home
|
||||||
card:
|
card:
|
||||||
type: entities
|
type: entities
|
||||||
title: Custom Title
|
title: Custom Title
|
||||||
@@ -98,15 +152,101 @@ const CONFIGS = [
|
|||||||
- light.bed_light
|
- light.bed_light
|
||||||
- light.ceiling_lights
|
- light.ceiling_lights
|
||||||
- light.kitchen_lights
|
- light.kitchen_lights
|
||||||
state_filter:
|
conditions:
|
||||||
- "on"
|
- condition: state
|
||||||
- not_home
|
state:
|
||||||
|
- "on"
|
||||||
|
- home
|
||||||
card:
|
card:
|
||||||
type: glance
|
type: glance
|
||||||
show_state: true
|
show_state: true
|
||||||
title: Custom Title
|
title: Custom Title
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
heading:
|
||||||
|
"Filtered entities by battery attribute (< '30') using state filter",
|
||||||
|
config: `
|
||||||
|
- type: entity-filter
|
||||||
|
entities:
|
||||||
|
- device_tracker.demo_anne_therese
|
||||||
|
- device_tracker.demo_home_boy
|
||||||
|
- device_tracker.demo_paulus
|
||||||
|
state_filter:
|
||||||
|
- operator: <
|
||||||
|
attribute: battery
|
||||||
|
value: "30"
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Unfiltered number entities",
|
||||||
|
config: `
|
||||||
|
- type: entities
|
||||||
|
entities:
|
||||||
|
- input_number.min_battery_level
|
||||||
|
- sensor.battery_1
|
||||||
|
- sensor.battery_3
|
||||||
|
- sensor.battery_2
|
||||||
|
- sensor.battery_4
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Battery lower than 50%",
|
||||||
|
config: `
|
||||||
|
- type: entity-filter
|
||||||
|
entities:
|
||||||
|
- sensor.battery_1
|
||||||
|
- sensor.battery_3
|
||||||
|
- sensor.battery_2
|
||||||
|
- sensor.battery_4
|
||||||
|
conditions:
|
||||||
|
- condition: numeric_state
|
||||||
|
below: 50
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Battery lower than min battery level",
|
||||||
|
config: `
|
||||||
|
- type: entity-filter
|
||||||
|
entities:
|
||||||
|
- sensor.battery_1
|
||||||
|
- sensor.battery_3
|
||||||
|
- sensor.battery_2
|
||||||
|
- sensor.battery_4
|
||||||
|
conditions:
|
||||||
|
- condition: numeric_state
|
||||||
|
below: input_number.min_battery_level
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Battery between min battery level and 70%",
|
||||||
|
config: `
|
||||||
|
- type: entity-filter
|
||||||
|
entities:
|
||||||
|
- sensor.battery_1
|
||||||
|
- sensor.battery_3
|
||||||
|
- sensor.battery_2
|
||||||
|
- sensor.battery_4
|
||||||
|
conditions:
|
||||||
|
- condition: numeric_state
|
||||||
|
above: input_number.min_battery_level
|
||||||
|
below: 70
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Error: Entities must be specified",
|
||||||
|
config: `
|
||||||
|
- type: entity-filter
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Error: Incorrect filter config",
|
||||||
|
config: `
|
||||||
|
- type: entity-filter
|
||||||
|
entities:
|
||||||
|
- sensor.gas_station_lowest_price
|
||||||
|
`,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@customElement("demo-lovelace-entity-filter-card")
|
@customElement("demo-lovelace-entity-filter-card")
|
||||||
@@ -123,6 +263,7 @@ class DemoEntityFilter extends LitElement {
|
|||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
hass.updateTranslations("lovelace", "en");
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
|
mockIcons(hass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { customElement, query } from "lit/decorators";
|
|||||||
import { getEntity } from "../../../../src/fake_data/entity";
|
import { getEntity } from "../../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||||
import "../../components/demo-cards";
|
import "../../components/demo-cards";
|
||||||
|
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
getEntity("sensor", "brightness", "12", {}),
|
getEntity("sensor", "brightness", "12", {}),
|
||||||
@@ -128,6 +129,7 @@ class DemoGaugeEntity extends LitElement {
|
|||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
hass.updateTranslations("lovelace", "en");
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
|
mockIcons(hass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { customElement, query } from "lit/decorators";
|
|||||||
import { getEntity } from "../../../../src/fake_data/entity";
|
import { getEntity } from "../../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||||
import "../../components/demo-cards";
|
import "../../components/demo-cards";
|
||||||
|
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
getEntity("device_tracker", "demo_paulus", "home", {
|
getEntity("device_tracker", "demo_paulus", "home", {
|
||||||
@@ -238,6 +239,7 @@ class DemoGlanceEntity extends LitElement {
|
|||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
hass.updateTranslations("lovelace", "en");
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
|
mockIcons(hass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { mockHistory } from "../../../../demo/src/stubs/history";
|
|||||||
import { getEntity } from "../../../../src/fake_data/entity";
|
import { getEntity } from "../../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||||
import "../../components/demo-cards";
|
import "../../components/demo-cards";
|
||||||
|
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
getEntity("light", "kitchen_lights", "on", {
|
getEntity("light", "kitchen_lights", "on", {
|
||||||
@@ -214,6 +215,7 @@ class DemoStack extends LitElement {
|
|||||||
hass.updateTranslations("lovelace", "en");
|
hass.updateTranslations("lovelace", "en");
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
mockHistory(hass);
|
mockHistory(hass);
|
||||||
|
mockIcons(hass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { customElement, query } from "lit/decorators";
|
|||||||
import { getEntity } from "../../../../src/fake_data/entity";
|
import { getEntity } from "../../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||||
import "../../components/demo-cards";
|
import "../../components/demo-cards";
|
||||||
|
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
getEntity("light", "bed_light", "on", {
|
getEntity("light", "bed_light", "on", {
|
||||||
@@ -76,6 +77,7 @@ class DemoLightEntity extends LitElement {
|
|||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
hass.updateTranslations("lovelace", "en");
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
|
mockIcons(hass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { customElement, query } from "lit/decorators";
|
|||||||
import { getEntity } from "../../../../src/fake_data/entity";
|
import { getEntity } from "../../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||||
import "../../components/demo-cards";
|
import "../../components/demo-cards";
|
||||||
|
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
getEntity("light", "bed_light", "on", {
|
getEntity("light", "bed_light", "on", {
|
||||||
@@ -138,6 +139,7 @@ class DemoPictureElements extends LitElement {
|
|||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
hass.updateTranslations("lovelace", "en");
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
|
mockIcons(hass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { customElement, query } from "lit/decorators";
|
|||||||
import { getEntity } from "../../../../src/fake_data/entity";
|
import { getEntity } from "../../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||||
import "../../components/demo-cards";
|
import "../../components/demo-cards";
|
||||||
|
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
getEntity("light", "kitchen_lights", "on", {
|
getEntity("light", "kitchen_lights", "on", {
|
||||||
@@ -93,6 +94,7 @@ class DemoPictureEntity extends LitElement {
|
|||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
hass.updateTranslations("lovelace", "en");
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
|
mockIcons(hass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { customElement, query } from "lit/decorators";
|
|||||||
import { getEntity } from "../../../../src/fake_data/entity";
|
import { getEntity } from "../../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||||
import "../../components/demo-cards";
|
import "../../components/demo-cards";
|
||||||
|
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
getEntity("switch", "decorative_lights", "on", {
|
getEntity("switch", "decorative_lights", "on", {
|
||||||
@@ -134,6 +135,7 @@ class DemoPictureGlance extends LitElement {
|
|||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
hass.updateTranslations("lovelace", "en");
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
|
mockIcons(hass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { customElement, query } from "lit/decorators";
|
|||||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||||
import "../../components/demo-cards";
|
import "../../components/demo-cards";
|
||||||
import { createPlantEntities } from "../../data/plants";
|
import { createPlantEntities } from "../../data/plants";
|
||||||
|
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||||
|
|
||||||
const CONFIGS = [
|
const CONFIGS = [
|
||||||
{
|
{
|
||||||
@@ -43,6 +44,7 @@ export class DemoPlantEntity extends LitElement {
|
|||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
hass.updateTranslations("lovelace", "en");
|
||||||
hass.addEntities(createPlantEntities());
|
hass.addEntities(createPlantEntities());
|
||||||
|
mockIcons(hass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { customElement, query } from "lit/decorators";
|
|||||||
import { getEntity } from "../../../../src/fake_data/entity";
|
import { getEntity } from "../../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||||
import "../../components/demo-cards";
|
import "../../components/demo-cards";
|
||||||
|
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
getEntity("climate", "ecobee", "auto", {
|
getEntity("climate", "ecobee", "auto", {
|
||||||
@@ -35,6 +36,45 @@ const ENTITIES = [
|
|||||||
friendly_name: "Nest",
|
friendly_name: "Nest",
|
||||||
supported_features: 43,
|
supported_features: 43,
|
||||||
}),
|
}),
|
||||||
|
getEntity("climate", "overkiz_radiator", "heat", {
|
||||||
|
current_temperature: 18,
|
||||||
|
min_temp: 7,
|
||||||
|
max_temp: 35,
|
||||||
|
temperature: 20,
|
||||||
|
hvac_modes: ["heat", "auto", "off"],
|
||||||
|
friendly_name: "Overkiz radiator",
|
||||||
|
supported_features: 17,
|
||||||
|
preset_mode: "comfort",
|
||||||
|
preset_modes: [
|
||||||
|
"none",
|
||||||
|
"frost_protection",
|
||||||
|
"eco",
|
||||||
|
"comfort",
|
||||||
|
"comfort-1",
|
||||||
|
"comfort-2",
|
||||||
|
"auto",
|
||||||
|
"boost",
|
||||||
|
"external",
|
||||||
|
"prog",
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
getEntity("climate", "overkiz_towel_dryer", "heat", {
|
||||||
|
current_temperature: null,
|
||||||
|
min_temp: 7,
|
||||||
|
max_temp: 35,
|
||||||
|
hvac_modes: ["heat", "off"],
|
||||||
|
friendly_name: "Overkiz towel dryer",
|
||||||
|
supported_features: 16,
|
||||||
|
preset_mode: "eco",
|
||||||
|
preset_modes: [
|
||||||
|
"none",
|
||||||
|
"frost_protection",
|
||||||
|
"eco",
|
||||||
|
"comfort",
|
||||||
|
"comfort-1",
|
||||||
|
"comfort-2",
|
||||||
|
],
|
||||||
|
}),
|
||||||
getEntity("climate", "sensibo", "fan_only", {
|
getEntity("climate", "sensibo", "fan_only", {
|
||||||
current_temperature: null,
|
current_temperature: null,
|
||||||
temperature: null,
|
temperature: null,
|
||||||
@@ -45,7 +85,9 @@ const ENTITIES = [
|
|||||||
friendly_name: "Sensibo purifier",
|
friendly_name: "Sensibo purifier",
|
||||||
fan_modes: ["low", "high"],
|
fan_modes: ["low", "high"],
|
||||||
fan_mode: "low",
|
fan_mode: "low",
|
||||||
supported_features: 9,
|
swing_modes: ["on", "off", "both", "vertical", "horizontal"],
|
||||||
|
swing_mode: "vertical",
|
||||||
|
supported_features: 41,
|
||||||
}),
|
}),
|
||||||
getEntity("climate", "unavailable", "unavailable", {
|
getEntity("climate", "unavailable", "unavailable", {
|
||||||
supported_features: 43,
|
supported_features: 43,
|
||||||
@@ -58,8 +100,6 @@ const CONFIGS = [
|
|||||||
config: `
|
config: `
|
||||||
- type: thermostat
|
- type: thermostat
|
||||||
entity: climate.ecobee
|
entity: climate.ecobee
|
||||||
- type: thermostat
|
|
||||||
entity: climate.nest
|
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -69,6 +109,66 @@ const CONFIGS = [
|
|||||||
entity: climate.nest
|
entity: climate.nest
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
heading: "Feature example",
|
||||||
|
config: `
|
||||||
|
- type: thermostat
|
||||||
|
entity: climate.overkiz_radiator
|
||||||
|
features:
|
||||||
|
- type: climate-hvac-modes
|
||||||
|
hvac_modes:
|
||||||
|
- heat
|
||||||
|
- 'off'
|
||||||
|
- auto
|
||||||
|
- type: climate-preset-modes
|
||||||
|
style: icons
|
||||||
|
preset_modes:
|
||||||
|
- none
|
||||||
|
- frost_protection
|
||||||
|
- eco
|
||||||
|
- comfort
|
||||||
|
- comfort-1
|
||||||
|
- comfort-2
|
||||||
|
- auto
|
||||||
|
- boost
|
||||||
|
- external
|
||||||
|
- prog
|
||||||
|
- type: climate-preset-modes
|
||||||
|
style: dropdown
|
||||||
|
preset_modes:
|
||||||
|
- none
|
||||||
|
- frost_protection
|
||||||
|
- eco
|
||||||
|
- comfort
|
||||||
|
- comfort-1
|
||||||
|
- comfort-2
|
||||||
|
- auto
|
||||||
|
- boost
|
||||||
|
- external
|
||||||
|
- prog
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Preset only example",
|
||||||
|
config: `
|
||||||
|
- type: thermostat
|
||||||
|
entity: climate.overkiz_towel_dryer
|
||||||
|
features:
|
||||||
|
- type: climate-hvac-modes
|
||||||
|
hvac_modes:
|
||||||
|
- heat
|
||||||
|
- 'off'
|
||||||
|
- type: climate-preset-modes
|
||||||
|
style: icons
|
||||||
|
preset_modes:
|
||||||
|
- none
|
||||||
|
- frost_protection
|
||||||
|
- eco
|
||||||
|
- comfort
|
||||||
|
- comfort-1
|
||||||
|
- comfort-2
|
||||||
|
`,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
heading: "Fan only example",
|
heading: "Fan only example",
|
||||||
config: `
|
config: `
|
||||||
@@ -84,6 +184,14 @@ const CONFIGS = [
|
|||||||
fan_modes:
|
fan_modes:
|
||||||
- low
|
- low
|
||||||
- high
|
- high
|
||||||
|
- type: climate-swing-modes
|
||||||
|
style: icons
|
||||||
|
swing_modes:
|
||||||
|
- 'on'
|
||||||
|
- 'off'
|
||||||
|
- 'both'
|
||||||
|
- 'vertical'
|
||||||
|
- 'horizontal'
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -116,6 +224,7 @@ class DemoThermostatEntity extends LitElement {
|
|||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
hass.updateTranslations("lovelace", "en");
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
|
mockIcons(hass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { VacuumEntityFeature } from "../../../../src/data/vacuum";
|
|||||||
import { getEntity } from "../../../../src/fake_data/entity";
|
import { getEntity } from "../../../../src/fake_data/entity";
|
||||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||||
import "../../components/demo-cards";
|
import "../../components/demo-cards";
|
||||||
|
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
getEntity("switch", "tv_outlet", "on", {
|
getEntity("switch", "tv_outlet", "on", {
|
||||||
@@ -184,6 +185,7 @@ class DemoTile extends LitElement {
|
|||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
hass.updateTranslations("lovelace", "en");
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
|
mockIcons(hass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { provideHass } from "../../../../src/fake_data/provide_hass";
|
|||||||
import "../../components/demo-cards";
|
import "../../components/demo-cards";
|
||||||
import { getEntity } from "../../../../src/fake_data/entity";
|
import { getEntity } from "../../../../src/fake_data/entity";
|
||||||
import { mockTodo } from "../../../../demo/src/stubs/todo";
|
import { mockTodo } from "../../../../demo/src/stubs/todo";
|
||||||
|
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
getEntity("todo", "shopping_list", "2", {
|
getEntity("todo", "shopping_list", "2", {
|
||||||
@@ -47,6 +48,7 @@ class DemoTodoListEntity extends LitElement {
|
|||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
hass.updateTranslations("lovelace", "en");
|
||||||
hass.addEntities(ENTITIES);
|
hass.addEntities(ENTITIES);
|
||||||
|
mockIcons(hass);
|
||||||
|
|
||||||
mockTodo(hass);
|
mockTodo(hass);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import "../../../../src/components/data-table/ha-data-table";
|
|||||||
import type { DataTableColumnContainer } from "../../../../src/components/data-table/ha-data-table";
|
import type { DataTableColumnContainer } from "../../../../src/components/data-table/ha-data-table";
|
||||||
import "../../../../src/components/entity/state-badge";
|
import "../../../../src/components/entity/state-badge";
|
||||||
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||||
|
import { mockIcons } from "../../../../demo/src/stubs/icons";
|
||||||
import { HomeAssistant } from "../../../../src/types";
|
import { HomeAssistant } from "../../../../src/types";
|
||||||
|
|
||||||
const SENSOR_DEVICE_CLASSES = [
|
const SENSOR_DEVICE_CLASSES = [
|
||||||
@@ -291,6 +292,7 @@ const ENTITIES: HassEntity[] = [
|
|||||||
createEntity("water_heater.high_demand", "high_demand"),
|
createEntity("water_heater.high_demand", "high_demand"),
|
||||||
createEntity("water_heater.heat_pump", "heat_pump"),
|
createEntity("water_heater.heat_pump", "heat_pump"),
|
||||||
createEntity("water_heater.gas", "gas"),
|
createEntity("water_heater.gas", "gas"),
|
||||||
|
createEntity("select.speed", "ridiculous_speed"),
|
||||||
];
|
];
|
||||||
|
|
||||||
function createEntity(
|
function createEntity(
|
||||||
@@ -397,6 +399,17 @@ export class DemoEntityState extends LitElement {
|
|||||||
protected firstUpdated(changedProps) {
|
protected firstUpdated(changedProps) {
|
||||||
super.firstUpdated(changedProps);
|
super.firstUpdated(changedProps);
|
||||||
const hass = provideHass(this);
|
const hass = provideHass(this);
|
||||||
|
mockIcons(hass);
|
||||||
|
hass.updateHass({
|
||||||
|
entities: {
|
||||||
|
"select.speed": {
|
||||||
|
entity_id: "select.speed",
|
||||||
|
translation_key: "speed",
|
||||||
|
platform: "demo",
|
||||||
|
labels: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("config", "en");
|
hass.updateTranslations("config", "en");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ const createConfigEntry = (
|
|||||||
supports_options: false,
|
supports_options: false,
|
||||||
supports_remove_device: false,
|
supports_remove_device: false,
|
||||||
supports_unload: true,
|
supports_unload: true,
|
||||||
|
supports_reconfigure: true,
|
||||||
disabled_by: null,
|
disabled_by: null,
|
||||||
pref_disable_new_entities: false,
|
pref_disable_new_entities: false,
|
||||||
pref_disable_polling: false,
|
pref_disable_polling: false,
|
||||||
@@ -198,6 +199,8 @@ const createEntityRegistryEntries = (
|
|||||||
has_entity_name: false,
|
has_entity_name: false,
|
||||||
unique_id: "updater",
|
unique_id: "updater",
|
||||||
options: null,
|
options: null,
|
||||||
|
labels: [],
|
||||||
|
categories: {},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -221,6 +224,7 @@ const createDeviceRegistryEntries = (
|
|||||||
name_by_user: null,
|
name_by_user: null,
|
||||||
disabled_by: null,
|
disabled_by: null,
|
||||||
configuration_url: null,
|
configuration_url: null,
|
||||||
|
labels: [],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import "../../components/demo-more-infos";
|
|||||||
import { ClimateEntityFeature } from "../../../../src/data/climate";
|
import { ClimateEntityFeature } from "../../../../src/data/climate";
|
||||||
|
|
||||||
const ENTITIES = [
|
const ENTITIES = [
|
||||||
getEntity("climate", "thermostat", "heat", {
|
getEntity("climate", "radiator", "heat", {
|
||||||
friendly_name: "Basic heater",
|
friendly_name: "Basic heater",
|
||||||
hvac_modes: ["heat", "off"],
|
hvac_modes: ["heat", "off"],
|
||||||
hvac_mode: "heat",
|
hvac_mode: "heat",
|
||||||
@@ -80,6 +80,24 @@ const ENTITIES = [
|
|||||||
max_humidity: 100,
|
max_humidity: 100,
|
||||||
humidity: 50,
|
humidity: 50,
|
||||||
}),
|
}),
|
||||||
|
getEntity("climate", "towel_dryer", "heat", {
|
||||||
|
friendly_name: "Preset only heater",
|
||||||
|
hvac_modes: ["heat", "off"],
|
||||||
|
hvac_mode: "heat",
|
||||||
|
preset_modes: [
|
||||||
|
"none",
|
||||||
|
"frost_protection",
|
||||||
|
"eco",
|
||||||
|
"comfort",
|
||||||
|
"comfort-1",
|
||||||
|
"comfort-2",
|
||||||
|
],
|
||||||
|
preset_mode: "eco",
|
||||||
|
current_temperature: null,
|
||||||
|
min_temp: 7,
|
||||||
|
max_temp: 35,
|
||||||
|
supported_features: ClimateEntityFeature.PRESET_MODE,
|
||||||
|
}),
|
||||||
getEntity("climate", "unavailable", "unavailable", {
|
getEntity("climate", "unavailable", "unavailable", {
|
||||||
friendly_name: "Unavailable heater",
|
friendly_name: "Unavailable heater",
|
||||||
hvac_modes: ["heat", "off"],
|
hvac_modes: ["heat", "off"],
|
||||||
|
|||||||
@@ -1263,6 +1263,7 @@ class HassioAddonInfo extends LitElement {
|
|||||||
.card-actions {
|
.card-actions {
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
direction: var(--direction);
|
||||||
}
|
}
|
||||||
.changelog {
|
.changelog {
|
||||||
display: contents;
|
display: contents;
|
||||||
|
|||||||
@@ -154,12 +154,16 @@ class HassioHardwareDialog extends LitElement {
|
|||||||
ha-icon-button {
|
ha-icon-button {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 16px;
|
right: 16px;
|
||||||
|
inset-inline-end: 16px;
|
||||||
|
inset-inline-start: initial;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: var(--primary-text-color);
|
color: var(--primary-text-color);
|
||||||
}
|
}
|
||||||
h2 {
|
h2 {
|
||||||
margin: 18px 42px 0 18px;
|
margin: 18px 42px 0 18px;
|
||||||
|
margin-inline-start: 18px;
|
||||||
|
margin-inline-end: 42px;
|
||||||
color: var(--primary-text-color);
|
color: var(--primary-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import "@material/mwc-button/mwc-button";
|
import "@material/mwc-button/mwc-button";
|
||||||
import { mdiDelete, mdiDeleteOff } from "@mdi/js";
|
import { mdiDelete, mdiDeleteOff } from "@mdi/js";
|
||||||
import "@polymer/paper-item/paper-item";
|
|
||||||
import "@polymer/paper-item/paper-item-body";
|
|
||||||
import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
|
import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
|
||||||
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
|
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
|
||||||
import { customElement, property, query, state } from "lit/decorators";
|
import { customElement, property, query, state } from "lit/decorators";
|
||||||
@@ -27,6 +25,8 @@ import type { HomeAssistant } from "../../../../src/types";
|
|||||||
import { HassioRepositoryDialogParams } from "./show-dialog-repositories";
|
import { HassioRepositoryDialogParams } from "./show-dialog-repositories";
|
||||||
import type { HaTextField } from "../../../../src/components/ha-textfield";
|
import type { HaTextField } from "../../../../src/components/ha-textfield";
|
||||||
import "../../../../src/components/ha-textfield";
|
import "../../../../src/components/ha-textfield";
|
||||||
|
import "../../../../src/components/ha-list-new";
|
||||||
|
import "../../../../src/components/ha-list-item-new";
|
||||||
|
|
||||||
@customElement("dialog-hassio-repositories")
|
@customElement("dialog-hassio-repositories")
|
||||||
class HassioRepositoriesDialog extends LitElement {
|
class HassioRepositoriesDialog extends LitElement {
|
||||||
@@ -106,44 +106,46 @@ class HassioRepositoriesDialog extends LitElement {
|
|||||||
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||||
: ""}
|
: ""}
|
||||||
<div class="form">
|
<div class="form">
|
||||||
${repositories.length
|
<ha-list-new>
|
||||||
? repositories.map(
|
${repositories.length
|
||||||
(repo) => html`
|
? repositories.map(
|
||||||
<paper-item class="option">
|
(repo) => html`
|
||||||
<paper-item-body three-line>
|
<ha-list-item-new class="option">
|
||||||
<div>${repo.name}</div>
|
${repo.name}
|
||||||
<div secondary>${repo.maintainer}</div>
|
<div slot="supporting-text">
|
||||||
<div secondary>${repo.url}</div>
|
<div>${repo.maintainer}</div>
|
||||||
</paper-item-body>
|
<div>${repo.url}</div>
|
||||||
<div class="delete">
|
</div>
|
||||||
<ha-icon-button
|
<div class="delete" slot="end">
|
||||||
.label=${this._dialogParams!.supervisor.localize(
|
<ha-icon-button
|
||||||
"dialog.repositories.remove"
|
.label=${this._dialogParams!.supervisor.localize(
|
||||||
)}
|
"dialog.repositories.remove"
|
||||||
.disabled=${usedRepositories.includes(repo.slug)}
|
)}
|
||||||
.slug=${repo.slug}
|
.disabled=${usedRepositories.includes(repo.slug)}
|
||||||
.path=${usedRepositories.includes(repo.slug)
|
.slug=${repo.slug}
|
||||||
? mdiDeleteOff
|
.path=${usedRepositories.includes(repo.slug)
|
||||||
: mdiDelete}
|
? mdiDeleteOff
|
||||||
@click=${this._removeRepository}
|
: mdiDelete}
|
||||||
>
|
@click=${this._removeRepository}
|
||||||
</ha-icon-button>
|
>
|
||||||
<simple-tooltip
|
</ha-icon-button>
|
||||||
animation-delay="0"
|
<simple-tooltip
|
||||||
position="bottom"
|
animation-delay="0"
|
||||||
offset="1"
|
position="bottom"
|
||||||
>
|
offset="1"
|
||||||
${this._dialogParams!.supervisor.localize(
|
>
|
||||||
usedRepositories.includes(repo.slug)
|
${this._dialogParams!.supervisor.localize(
|
||||||
? "dialog.repositories.used"
|
usedRepositories.includes(repo.slug)
|
||||||
: "dialog.repositories.remove"
|
? "dialog.repositories.used"
|
||||||
)}
|
: "dialog.repositories.remove"
|
||||||
</simple-tooltip>
|
)}
|
||||||
</div>
|
</simple-tooltip>
|
||||||
</paper-item>
|
</div>
|
||||||
`
|
</ha-list-item-new>
|
||||||
)
|
`
|
||||||
: html`<paper-item> No repositories </paper-item>`}
|
)
|
||||||
|
: html`<ha-list-item-new> No repositories </ha-list-item-new>`}
|
||||||
|
</ha-list-new>
|
||||||
<div class="layout horizontal bottom">
|
<div class="layout horizontal bottom">
|
||||||
<ha-textfield
|
<ha-textfield
|
||||||
class="flex-auto"
|
class="flex-auto"
|
||||||
@@ -206,6 +208,9 @@ class HassioRepositoriesDialog extends LitElement {
|
|||||||
div.delete ha-icon-button {
|
div.delete ha-icon-button {
|
||||||
color: var(--error-color);
|
color: var(--error-color);
|
||||||
}
|
}
|
||||||
|
ha-list-item-new {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
122
package.json
122
package.json
@@ -25,36 +25,36 @@
|
|||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "7.23.9",
|
"@babel/runtime": "7.24.1",
|
||||||
"@braintree/sanitize-url": "7.0.0",
|
"@braintree/sanitize-url": "7.0.1",
|
||||||
"@codemirror/autocomplete": "6.12.0",
|
"@codemirror/autocomplete": "6.15.0",
|
||||||
"@codemirror/commands": "6.3.3",
|
"@codemirror/commands": "6.3.3",
|
||||||
"@codemirror/language": "6.10.1",
|
"@codemirror/language": "6.10.1",
|
||||||
"@codemirror/legacy-modes": "6.3.3",
|
"@codemirror/legacy-modes": "6.3.3",
|
||||||
"@codemirror/search": "6.5.5",
|
"@codemirror/search": "6.5.6",
|
||||||
"@codemirror/state": "6.4.0",
|
"@codemirror/state": "6.4.1",
|
||||||
"@codemirror/view": "6.23.1",
|
"@codemirror/view": "6.26.1",
|
||||||
"@egjs/hammerjs": "2.0.17",
|
"@egjs/hammerjs": "2.0.17",
|
||||||
"@formatjs/intl-datetimeformat": "6.12.2",
|
"@formatjs/intl-datetimeformat": "6.12.3",
|
||||||
"@formatjs/intl-displaynames": "6.6.6",
|
"@formatjs/intl-displaynames": "6.6.6",
|
||||||
"@formatjs/intl-getcanonicallocales": "2.3.0",
|
"@formatjs/intl-getcanonicallocales": "2.3.0",
|
||||||
"@formatjs/intl-listformat": "7.5.5",
|
"@formatjs/intl-listformat": "7.5.5",
|
||||||
"@formatjs/intl-locale": "3.4.5",
|
"@formatjs/intl-locale": "3.4.5",
|
||||||
"@formatjs/intl-numberformat": "8.10.0",
|
"@formatjs/intl-numberformat": "8.10.1",
|
||||||
"@formatjs/intl-pluralrules": "5.2.12",
|
"@formatjs/intl-pluralrules": "5.2.12",
|
||||||
"@formatjs/intl-relativetimeformat": "11.2.12",
|
"@formatjs/intl-relativetimeformat": "11.2.12",
|
||||||
"@fullcalendar/core": "6.1.10",
|
"@fullcalendar/core": "6.1.11",
|
||||||
"@fullcalendar/daygrid": "6.1.10",
|
"@fullcalendar/daygrid": "6.1.11",
|
||||||
"@fullcalendar/interaction": "6.1.10",
|
"@fullcalendar/interaction": "6.1.11",
|
||||||
"@fullcalendar/list": "6.1.10",
|
"@fullcalendar/list": "6.1.11",
|
||||||
"@fullcalendar/luxon3": "6.1.10",
|
"@fullcalendar/luxon3": "6.1.11",
|
||||||
"@fullcalendar/timegrid": "6.1.10",
|
"@fullcalendar/timegrid": "6.1.11",
|
||||||
"@lezer/highlight": "1.2.0",
|
"@lezer/highlight": "1.2.0",
|
||||||
"@lit-labs/context": "0.4.1",
|
"@lit-labs/context": "0.4.1",
|
||||||
"@lit-labs/motion": "1.0.7",
|
"@lit-labs/motion": "1.0.7",
|
||||||
"@lit-labs/observers": "2.0.2",
|
"@lit-labs/observers": "2.0.2",
|
||||||
"@lit-labs/virtualizer": "2.0.12",
|
"@lit-labs/virtualizer": "2.0.12",
|
||||||
"@lrnwebcomponents/simple-tooltip": "8.0.0",
|
"@lrnwebcomponents/simple-tooltip": "8.0.2",
|
||||||
"@material/chips": "=14.0.0-canary.53b3cad2f.0",
|
"@material/chips": "=14.0.0-canary.53b3cad2f.0",
|
||||||
"@material/data-table": "=14.0.0-canary.53b3cad2f.0",
|
"@material/data-table": "=14.0.0-canary.53b3cad2f.0",
|
||||||
"@material/mwc-base": "0.27.0",
|
"@material/mwc-base": "0.27.0",
|
||||||
@@ -72,6 +72,7 @@
|
|||||||
"@material/mwc-radio": "0.27.0",
|
"@material/mwc-radio": "0.27.0",
|
||||||
"@material/mwc-ripple": "0.27.0",
|
"@material/mwc-ripple": "0.27.0",
|
||||||
"@material/mwc-select": "0.27.0",
|
"@material/mwc-select": "0.27.0",
|
||||||
|
"@material/mwc-snackbar": "0.27.0",
|
||||||
"@material/mwc-switch": "0.27.0",
|
"@material/mwc-switch": "0.27.0",
|
||||||
"@material/mwc-tab": "0.27.0",
|
"@material/mwc-tab": "0.27.0",
|
||||||
"@material/mwc-tab-bar": "0.27.0",
|
"@material/mwc-tab-bar": "0.27.0",
|
||||||
@@ -80,17 +81,16 @@
|
|||||||
"@material/mwc-top-app-bar": "0.27.0",
|
"@material/mwc-top-app-bar": "0.27.0",
|
||||||
"@material/mwc-top-app-bar-fixed": "0.27.0",
|
"@material/mwc-top-app-bar-fixed": "0.27.0",
|
||||||
"@material/top-app-bar": "=14.0.0-canary.53b3cad2f.0",
|
"@material/top-app-bar": "=14.0.0-canary.53b3cad2f.0",
|
||||||
"@material/web": "=1.2.0",
|
"@material/web": "=1.3.0",
|
||||||
"@mdi/js": "7.4.47",
|
"@mdi/js": "7.4.47",
|
||||||
"@mdi/svg": "7.4.47",
|
"@mdi/svg": "7.4.47",
|
||||||
"@polymer/paper-item": "3.0.1",
|
"@polymer/paper-item": "3.0.1",
|
||||||
"@polymer/paper-listbox": "3.0.1",
|
"@polymer/paper-listbox": "3.0.1",
|
||||||
"@polymer/paper-tabs": "3.1.0",
|
"@polymer/paper-tabs": "3.1.0",
|
||||||
"@polymer/paper-toast": "3.0.1",
|
|
||||||
"@polymer/polymer": "3.5.1",
|
"@polymer/polymer": "3.5.1",
|
||||||
"@thomasloven/round-slider": "0.6.0",
|
"@thomasloven/round-slider": "0.6.0",
|
||||||
"@vaadin/combo-box": "24.3.5",
|
"@vaadin/combo-box": "24.3.10",
|
||||||
"@vaadin/vaadin-themable-mixin": "24.3.5",
|
"@vaadin/vaadin-themable-mixin": "24.3.10",
|
||||||
"@vibrant/color": "3.2.1-alpha.1",
|
"@vibrant/color": "3.2.1-alpha.1",
|
||||||
"@vibrant/core": "3.2.1-alpha.1",
|
"@vibrant/core": "3.2.1-alpha.1",
|
||||||
"@vibrant/quantizer-mmcq": "3.2.1-alpha.1",
|
"@vibrant/quantizer-mmcq": "3.2.1-alpha.1",
|
||||||
@@ -98,19 +98,20 @@
|
|||||||
"@webcomponents/scoped-custom-element-registry": "0.0.9",
|
"@webcomponents/scoped-custom-element-registry": "0.0.9",
|
||||||
"@webcomponents/webcomponentsjs": "2.8.0",
|
"@webcomponents/webcomponentsjs": "2.8.0",
|
||||||
"app-datepicker": "5.1.1",
|
"app-datepicker": "5.1.1",
|
||||||
"chart.js": "4.4.1",
|
"chart.js": "4.4.2",
|
||||||
|
"color-name": "2.0.0",
|
||||||
"comlink": "4.4.1",
|
"comlink": "4.4.1",
|
||||||
"core-js": "3.35.1",
|
"core-js": "3.36.1",
|
||||||
"cropperjs": "1.6.1",
|
"cropperjs": "1.6.1",
|
||||||
"date-fns": "2.30.0",
|
"date-fns": "2.30.0",
|
||||||
"date-fns-tz": "2.0.0",
|
"date-fns-tz": "2.0.1",
|
||||||
"deep-clone-simple": "1.1.1",
|
"deep-clone-simple": "1.1.1",
|
||||||
"deep-freeze": "0.0.1",
|
"deep-freeze": "0.0.1",
|
||||||
"element-internals-polyfill": "1.3.10",
|
"element-internals-polyfill": "1.3.10",
|
||||||
"fuse.js": "7.0.0",
|
"fuse.js": "7.0.0",
|
||||||
"google-timezones-json": "1.2.0",
|
"google-timezones-json": "1.2.0",
|
||||||
"hls.js": "1.5.3",
|
"hls.js": "patch:hls.js@npm%3A1.5.7#~/.yarn/patches/hls.js-npm-1.5.7-f5bbd3d060.patch",
|
||||||
"home-assistant-js-websocket": "9.1.0",
|
"home-assistant-js-websocket": "9.2.1",
|
||||||
"idb-keyval": "6.2.1",
|
"idb-keyval": "6.2.1",
|
||||||
"intl-messageformat": "10.5.11",
|
"intl-messageformat": "10.5.11",
|
||||||
"js-yaml": "4.1.0",
|
"js-yaml": "4.1.0",
|
||||||
@@ -118,7 +119,7 @@
|
|||||||
"leaflet-draw": "1.0.4",
|
"leaflet-draw": "1.0.4",
|
||||||
"lit": "2.8.0",
|
"lit": "2.8.0",
|
||||||
"luxon": "3.4.4",
|
"luxon": "3.4.4",
|
||||||
"marked": "11.2.0",
|
"marked": "12.0.1",
|
||||||
"memoize-one": "6.0.0",
|
"memoize-one": "6.0.0",
|
||||||
"node-vibrant": "3.2.1-alpha.1",
|
"node-vibrant": "3.2.1-alpha.1",
|
||||||
"proxy-polyfill": "0.3.2",
|
"proxy-polyfill": "0.3.2",
|
||||||
@@ -129,7 +130,7 @@
|
|||||||
"rrule": "2.8.1",
|
"rrule": "2.8.1",
|
||||||
"sortablejs": "1.15.2",
|
"sortablejs": "1.15.2",
|
||||||
"stacktrace-js": "2.0.2",
|
"stacktrace-js": "2.0.2",
|
||||||
"superstruct": "1.0.3",
|
"superstruct": "1.0.4",
|
||||||
"tinykeys": "2.1.0",
|
"tinykeys": "2.1.0",
|
||||||
"tsparticles-engine": "2.12.0",
|
"tsparticles-engine": "2.12.0",
|
||||||
"tsparticles-preset-links": "2.12.0",
|
"tsparticles-preset-links": "2.12.0",
|
||||||
@@ -146,20 +147,20 @@
|
|||||||
"workbox-precaching": "7.0.0",
|
"workbox-precaching": "7.0.0",
|
||||||
"workbox-routing": "7.0.0",
|
"workbox-routing": "7.0.0",
|
||||||
"workbox-strategies": "7.0.0",
|
"workbox-strategies": "7.0.0",
|
||||||
"xss": "1.0.14"
|
"xss": "1.0.15"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "7.23.9",
|
"@babel/core": "7.24.3",
|
||||||
"@babel/helper-define-polyfill-provider": "0.5.0",
|
"@babel/helper-define-polyfill-provider": "0.6.1",
|
||||||
"@babel/plugin-proposal-decorators": "7.23.9",
|
"@babel/plugin-proposal-decorators": "7.24.1",
|
||||||
"@babel/plugin-transform-runtime": "7.23.9",
|
"@babel/plugin-transform-runtime": "7.24.3",
|
||||||
"@babel/preset-env": "7.23.9",
|
"@babel/preset-env": "7.24.3",
|
||||||
"@babel/preset-typescript": "7.23.3",
|
"@babel/preset-typescript": "7.24.1",
|
||||||
"@bundle-stats/plugin-webpack-filter": "4.9.2",
|
"@bundle-stats/plugin-webpack-filter": "4.12.2",
|
||||||
"@koa/cors": "5.0.0",
|
"@koa/cors": "5.0.0",
|
||||||
"@lokalise/node-api": "12.1.0",
|
"@lokalise/node-api": "12.3.0",
|
||||||
"@octokit/auth-oauth-device": "6.0.1",
|
"@octokit/auth-oauth-device": "7.0.1",
|
||||||
"@octokit/plugin-retry": "6.0.1",
|
"@octokit/plugin-retry": "7.0.3",
|
||||||
"@octokit/rest": "20.0.2",
|
"@octokit/rest": "20.0.2",
|
||||||
"@open-wc/dev-server-hmr": "0.1.4",
|
"@open-wc/dev-server-hmr": "0.1.4",
|
||||||
"@rollup/plugin-babel": "6.0.4",
|
"@rollup/plugin-babel": "6.0.4",
|
||||||
@@ -169,7 +170,8 @@
|
|||||||
"@rollup/plugin-replace": "5.0.5",
|
"@rollup/plugin-replace": "5.0.5",
|
||||||
"@types/babel__plugin-transform-runtime": "7.9.5",
|
"@types/babel__plugin-transform-runtime": "7.9.5",
|
||||||
"@types/chromecast-caf-receiver": "6.0.13",
|
"@types/chromecast-caf-receiver": "6.0.13",
|
||||||
"@types/chromecast-caf-sender": "1.0.8",
|
"@types/chromecast-caf-sender": "1.0.9",
|
||||||
|
"@types/color-name": "1.1.3",
|
||||||
"@types/glob": "8.1.0",
|
"@types/glob": "8.1.0",
|
||||||
"@types/html-minifier-terser": "7.0.2",
|
"@types/html-minifier-terser": "7.0.2",
|
||||||
"@types/js-yaml": "4.0.9",
|
"@types/js-yaml": "4.0.9",
|
||||||
@@ -179,52 +181,52 @@
|
|||||||
"@types/mocha": "10.0.6",
|
"@types/mocha": "10.0.6",
|
||||||
"@types/qrcode": "1.5.5",
|
"@types/qrcode": "1.5.5",
|
||||||
"@types/serve-handler": "6.1.4",
|
"@types/serve-handler": "6.1.4",
|
||||||
"@types/sortablejs": "1.15.7",
|
"@types/sortablejs": "1.15.8",
|
||||||
"@types/tar": "6.1.11",
|
"@types/tar": "6.1.11",
|
||||||
"@types/ua-parser-js": "0.7.39",
|
"@types/ua-parser-js": "0.7.39",
|
||||||
"@types/webspeechapi": "0.0.29",
|
"@types/webspeechapi": "0.0.29",
|
||||||
"@typescript-eslint/eslint-plugin": "6.20.0",
|
"@typescript-eslint/eslint-plugin": "7.4.0",
|
||||||
"@typescript-eslint/parser": "6.20.0",
|
"@typescript-eslint/parser": "7.4.0",
|
||||||
"@web/dev-server": "0.1.38",
|
"@web/dev-server": "0.1.38",
|
||||||
"@web/dev-server-rollup": "0.4.1",
|
"@web/dev-server-rollup": "0.4.1",
|
||||||
"babel-loader": "9.1.3",
|
"babel-loader": "9.1.3",
|
||||||
"babel-plugin-template-html-minifier": "4.1.0",
|
"babel-plugin-template-html-minifier": "4.1.0",
|
||||||
"chai": "5.0.3",
|
"chai": "5.1.0",
|
||||||
"del": "7.1.0",
|
"del": "7.1.0",
|
||||||
"eslint": "8.56.0",
|
"eslint": "8.57.0",
|
||||||
"eslint-config-airbnb-base": "15.0.0",
|
"eslint-config-airbnb-base": "15.0.0",
|
||||||
"eslint-config-airbnb-typescript": "17.1.0",
|
"eslint-config-airbnb-typescript": "18.0.0",
|
||||||
"eslint-config-prettier": "9.1.0",
|
"eslint-config-prettier": "9.1.0",
|
||||||
"eslint-import-resolver-webpack": "0.13.8",
|
"eslint-import-resolver-webpack": "0.13.8",
|
||||||
"eslint-plugin-disable": "2.0.3",
|
"eslint-plugin-disable": "2.0.3",
|
||||||
"eslint-plugin-import": "2.29.1",
|
"eslint-plugin-import": "2.29.1",
|
||||||
"eslint-plugin-lit": "1.11.0",
|
"eslint-plugin-lit": "1.11.0",
|
||||||
"eslint-plugin-lit-a11y": "4.1.2",
|
"eslint-plugin-lit-a11y": "4.1.2",
|
||||||
"eslint-plugin-unused-imports": "3.0.0",
|
"eslint-plugin-unused-imports": "3.1.0",
|
||||||
"eslint-plugin-wc": "2.0.4",
|
"eslint-plugin-wc": "2.0.4",
|
||||||
"fancy-log": "2.0.0",
|
"fancy-log": "2.0.0",
|
||||||
"fs-extra": "11.2.0",
|
"fs-extra": "11.2.0",
|
||||||
"glob": "10.3.10",
|
"glob": "10.3.10",
|
||||||
"gulp": "4.0.2",
|
"gulp": "4.0.2",
|
||||||
"gulp-flatmap": "1.0.2",
|
"gulp-flatmap": "1.0.2",
|
||||||
"gulp-json-transform": "0.4.8",
|
"gulp-json-transform": "0.5.0",
|
||||||
"gulp-merge-json": "2.1.2",
|
"gulp-merge-json": "2.2.1",
|
||||||
"gulp-rename": "2.0.0",
|
"gulp-rename": "2.0.0",
|
||||||
"gulp-zopfli-green": "6.0.1",
|
"gulp-zopfli-green": "6.0.1",
|
||||||
"html-minifier-terser": "7.2.0",
|
"html-minifier-terser": "7.2.0",
|
||||||
"husky": "9.0.10",
|
"husky": "9.0.11",
|
||||||
"instant-mocha": "1.5.2",
|
"instant-mocha": "1.5.2",
|
||||||
"jszip": "3.10.1",
|
"jszip": "3.10.1",
|
||||||
"lint-staged": "15.2.1",
|
"lint-staged": "15.2.2",
|
||||||
"lit-analyzer": "2.0.3",
|
"lit-analyzer": "2.0.3",
|
||||||
"lodash.template": "4.5.0",
|
"lodash.template": "4.5.0",
|
||||||
"magic-string": "0.30.6",
|
"magic-string": "0.30.8",
|
||||||
"map-stream": "0.0.7",
|
"map-stream": "0.0.7",
|
||||||
"mocha": "10.2.0",
|
"mocha": "10.3.0",
|
||||||
"object-hash": "3.0.0",
|
"object-hash": "3.0.0",
|
||||||
"open": "10.0.3",
|
"open": "10.1.0",
|
||||||
"pinst": "3.0.0",
|
"pinst": "3.0.0",
|
||||||
"prettier": "3.2.4",
|
"prettier": "3.2.5",
|
||||||
"rollup": "2.79.1",
|
"rollup": "2.79.1",
|
||||||
"rollup-plugin-string": "3.0.0",
|
"rollup-plugin-string": "3.0.0",
|
||||||
"rollup-plugin-terser": "7.0.2",
|
"rollup-plugin-terser": "7.0.2",
|
||||||
@@ -233,19 +235,19 @@
|
|||||||
"sinon": "17.0.1",
|
"sinon": "17.0.1",
|
||||||
"source-map-url": "0.4.1",
|
"source-map-url": "0.4.1",
|
||||||
"systemjs": "6.14.3",
|
"systemjs": "6.14.3",
|
||||||
"tar": "6.2.0",
|
"tar": "6.2.1",
|
||||||
"terser-webpack-plugin": "5.3.10",
|
"terser-webpack-plugin": "5.3.10",
|
||||||
"transform-async-modules-webpack-plugin": "1.0.2",
|
"transform-async-modules-webpack-plugin": "1.0.4",
|
||||||
"ts-lit-plugin": "2.0.2",
|
"ts-lit-plugin": "2.0.2",
|
||||||
"typescript": "5.3.3",
|
"typescript": "5.4.3",
|
||||||
"vinyl-buffer": "1.0.1",
|
"vinyl-buffer": "1.0.1",
|
||||||
"vinyl-source-stream": "2.0.0",
|
"vinyl-source-stream": "2.0.0",
|
||||||
"webpack": "5.90.1",
|
"webpack": "5.91.0",
|
||||||
"webpack-cli": "5.1.4",
|
"webpack-cli": "5.1.4",
|
||||||
"webpack-dev-server": "4.15.1",
|
"webpack-dev-server": "5.0.4",
|
||||||
"webpack-manifest-plugin": "5.0.0",
|
"webpack-manifest-plugin": "5.0.0",
|
||||||
"webpack-stats-plugin": "1.1.3",
|
"webpack-stats-plugin": "1.1.3",
|
||||||
"webpackbar": "6.0.0",
|
"webpackbar": "6.0.1",
|
||||||
"workbox-build": "7.0.0"
|
"workbox-build": "7.0.0"
|
||||||
},
|
},
|
||||||
"_comment": "Polymer 3.2 contained a bug, fixed in https://github.com/Polymer/polymer/pull/5569, add as patch",
|
"_comment": "Polymer 3.2 contained a bug, fixed in https://github.com/Polymer/polymer/pull/5569, add as patch",
|
||||||
@@ -258,5 +260,5 @@
|
|||||||
"sortablejs@1.15.2": "patch:sortablejs@npm%3A1.15.2#~/.yarn/patches/sortablejs-npm-1.15.2-73347ae85a.patch",
|
"sortablejs@1.15.2": "patch:sortablejs@npm%3A1.15.2#~/.yarn/patches/sortablejs-npm-1.15.2-73347ae85a.patch",
|
||||||
"leaflet-draw@1.0.4": "patch:leaflet-draw@npm%3A1.0.4#./.yarn/patches/leaflet-draw-npm-1.0.4-0ca0ebcf65.patch"
|
"leaflet-draw@1.0.4": "patch:leaflet-draw@npm%3A1.0.4#./.yarn/patches/leaflet-draw-npm-1.0.4-0ca0ebcf65.patch"
|
||||||
},
|
},
|
||||||
"packageManager": "yarn@4.1.0"
|
"packageManager": "yarn@4.1.1"
|
||||||
}
|
}
|
||||||
|
|||||||
1
public/static/images/appstore.svg
Normal file
1
public/static/images/appstore.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 7.1 KiB |
BIN
public/static/images/logo_apple_home.png
Normal file
BIN
public/static/images/logo_apple_home.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
BIN
public/static/images/logo_google_home.png
Normal file
BIN
public/static/images/logo_google_home.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.6 KiB |
1
public/static/images/playstore.svg
Normal file
1
public/static/images/playstore.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 6.2 KiB |
1
public/static/images/qr-appstore.svg
Normal file
1
public/static/images/qr-appstore.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 52 KiB |
1
public/static/images/qr-playstore.svg
Normal file
1
public/static/images/qr-playstore.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 69 KiB |
@@ -4,14 +4,14 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "home-assistant-frontend"
|
name = "home-assistant-frontend"
|
||||||
version = "20240207.0"
|
version = "20240402.0"
|
||||||
license = {text = "Apache-2.0"}
|
license = {text = "Apache-2.0"}
|
||||||
description = "The Home Assistant frontend"
|
description = "The Home Assistant frontend"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
authors = [
|
authors = [
|
||||||
{name = "The Home Assistant Authors", email = "hello@home-assistant.io"}
|
{name = "The Home Assistant Authors", email = "hello@home-assistant.io"}
|
||||||
]
|
]
|
||||||
requires-python = ">=3.10.0"
|
requires-python = ">=3.11.0"
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
"Homepage" = "https://github.com/home-assistant/frontend"
|
"Homepage" = "https://github.com/home-assistant/frontend"
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ if [ -n "$ref" ]; then
|
|||||||
echo "Installing Home Assistant core at ${ref}..."
|
echo "Installing Home Assistant core at ${ref}..."
|
||||||
python3 -m pip install --user --upgrade --src "$HOME/src" \
|
python3 -m pip install --user --upgrade --src "$HOME/src" \
|
||||||
--editable "git+${coreURL}@${ref}#egg=homeassistant"
|
--editable "git+${coreURL}@${ref}#egg=homeassistant"
|
||||||
|
(cd ~/src/homeassistant && exec python3 -m script.translations develop --all)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -d "${WD}/config" ]; then
|
if [ ! -d "${WD}/config" ]; then
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { theme2hex } from "./convert-color";
|
||||||
|
|
||||||
export const COLORS = [
|
export const COLORS = [
|
||||||
"#44739e",
|
"#44739e",
|
||||||
"#984ea3",
|
"#984ea3",
|
||||||
@@ -65,10 +67,10 @@ export function getColorByIndex(index: number) {
|
|||||||
export function getGraphColorByIndex(
|
export function getGraphColorByIndex(
|
||||||
index: number,
|
index: number,
|
||||||
style: CSSStyleDeclaration
|
style: CSSStyleDeclaration
|
||||||
) {
|
): string {
|
||||||
// The CSS vars for the colors use range 1..n, so we need to adjust the index from the internal 0..n color index range.
|
// The CSS vars for the colors use range 1..n, so we need to adjust the index from the internal 0..n color index range.
|
||||||
return (
|
const themeColor =
|
||||||
style.getPropertyValue(`--graph-color-${index + 1}`) ||
|
style.getPropertyValue(`--graph-color-${index + 1}`) ||
|
||||||
getColorByIndex(index)
|
getColorByIndex(index);
|
||||||
);
|
return theme2hex(themeColor);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import colors from "color-name";
|
||||||
import { expandHex } from "./hex";
|
import { expandHex } from "./hex";
|
||||||
|
|
||||||
const rgb_hex = (component: number): string => {
|
const rgb_hex = (component: number): string => {
|
||||||
@@ -126,3 +127,18 @@ export const rgb2hs = (rgb: [number, number, number]): [number, number] =>
|
|||||||
|
|
||||||
export const hs2rgb = (hs: [number, number]): [number, number, number] =>
|
export const hs2rgb = (hs: [number, number]): [number, number, number] =>
|
||||||
hsv2rgb([hs[0], hs[1], 255]);
|
hsv2rgb([hs[0], hs[1], 255]);
|
||||||
|
|
||||||
|
export function theme2hex(themeColor: string): string {
|
||||||
|
if (themeColor.startsWith("#")) {
|
||||||
|
return themeColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rgbFromColorName = colors[themeColor];
|
||||||
|
if (!rgbFromColorName) {
|
||||||
|
// We have a named color, and there's nothing in the table,
|
||||||
|
// so nothing further we can do with it.
|
||||||
|
// Compare/border/background color will all be the same.
|
||||||
|
return themeColor;
|
||||||
|
}
|
||||||
|
return rgb2hex(rgbFromColorName);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,19 +1,25 @@
|
|||||||
import { PageNavigation } from "../../layouts/hass-tabs-subpage";
|
import { PageNavigation } from "../../layouts/hass-tabs-subpage";
|
||||||
import { HomeAssistant } from "../../types";
|
import { HomeAssistant } from "../../types";
|
||||||
|
import { ensureArray } from "../array/ensure-array";
|
||||||
import { isComponentLoaded } from "./is_component_loaded";
|
import { isComponentLoaded } from "./is_component_loaded";
|
||||||
|
|
||||||
export const canShowPage = (hass: HomeAssistant, page: PageNavigation) =>
|
export const canShowPage = (hass: HomeAssistant, page: PageNavigation) =>
|
||||||
(isCore(page) || isLoadedIntegration(hass, page)) &&
|
(isCore(page) || isLoadedIntegration(hass, page)) &&
|
||||||
!hideAdvancedPage(hass, page);
|
!hideAdvancedPage(hass, page) &&
|
||||||
|
isNotLoadedIntegration(hass, page);
|
||||||
|
|
||||||
const isLoadedIntegration = (hass: HomeAssistant, page: PageNavigation) =>
|
const isLoadedIntegration = (hass: HomeAssistant, page: PageNavigation) =>
|
||||||
page.component
|
!page.component ||
|
||||||
? isComponentLoaded(hass, page.component)
|
ensureArray(page.component).some((integration) =>
|
||||||
: page.components
|
isComponentLoaded(hass, integration)
|
||||||
? page.components.some((integration) =>
|
);
|
||||||
isComponentLoaded(hass, integration)
|
|
||||||
)
|
const isNotLoadedIntegration = (hass: HomeAssistant, page: PageNavigation) =>
|
||||||
: true;
|
!page.not_component ||
|
||||||
|
!ensureArray(page.not_component).some((integration) =>
|
||||||
|
isComponentLoaded(hass, integration)
|
||||||
|
);
|
||||||
|
|
||||||
const isCore = (page: PageNavigation) => page.core;
|
const isCore = (page: PageNavigation) => page.core;
|
||||||
const isAdvancedPage = (page: PageNavigation) => page.advancedOnly;
|
const isAdvancedPage = (page: PageNavigation) => page.advancedOnly;
|
||||||
const userWantsAdvanced = (hass: HomeAssistant) => hass.userData?.showAdvanced;
|
const userWantsAdvanced = (hass: HomeAssistant) => hass.userData?.showAdvanced;
|
||||||
|
|||||||
@@ -231,6 +231,7 @@ export const SENSOR_ENTITIES = [
|
|||||||
"calendar",
|
"calendar",
|
||||||
"camera",
|
"camera",
|
||||||
"device_tracker",
|
"device_tracker",
|
||||||
|
"image",
|
||||||
"weather",
|
"weather",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -37,3 +37,20 @@ export const calcDateProperty = (
|
|||||||
locale.time_zone === TimeZone.server
|
locale.time_zone === TimeZone.server
|
||||||
? (calcZonedDate(date, config.time_zone, fn, options) as number | boolean)
|
? (calcZonedDate(date, config.time_zone, fn, options) as number | boolean)
|
||||||
: fn(date, options);
|
: fn(date, options);
|
||||||
|
|
||||||
|
export const calcDateDifferenceProperty = (
|
||||||
|
endDate: Date,
|
||||||
|
startDate: Date,
|
||||||
|
fn: (date: Date, options?: any) => boolean | number,
|
||||||
|
locale: FrontendLocaleData,
|
||||||
|
config: HassConfig
|
||||||
|
) =>
|
||||||
|
calcDateProperty(
|
||||||
|
endDate,
|
||||||
|
fn,
|
||||||
|
locale,
|
||||||
|
config,
|
||||||
|
locale.time_zone === TimeZone.server
|
||||||
|
? utcToZonedTime(startDate, config.time_zone)
|
||||||
|
: startDate
|
||||||
|
);
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
import { MAIN_WINDOW_NAME } from "../../data/main_window";
|
import { MAIN_WINDOW_NAME } from "../../data/main_window";
|
||||||
|
|
||||||
export const mainWindow =
|
export const mainWindow = (() => {
|
||||||
window.name === MAIN_WINDOW_NAME
|
try {
|
||||||
? window
|
return window.name === MAIN_WINDOW_NAME
|
||||||
: parent.name === MAIN_WINDOW_NAME
|
? window
|
||||||
? parent
|
: parent.name === MAIN_WINDOW_NAME
|
||||||
: top!;
|
? parent
|
||||||
|
: top!;
|
||||||
|
} catch {
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|||||||
@@ -53,9 +53,7 @@ export const computeAttributeValueDisplay = (
|
|||||||
|
|
||||||
if (domain === "weather") {
|
if (domain === "weather") {
|
||||||
unit = getWeatherUnit(config, stateObj as WeatherEntity, attribute);
|
unit = getWeatherUnit(config, stateObj as WeatherEntity, attribute);
|
||||||
}
|
} else if (TEMPERATURE_ATTRIBUTES.has(attribute)) {
|
||||||
|
|
||||||
if (TEMPERATURE_ATTRIBUTES.has(attribute)) {
|
|
||||||
unit = config.unit_system.temperature;
|
unit = config.unit_system.temperature;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,14 +20,14 @@ function findNestedItem(
|
|||||||
}, obj);
|
}, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function nestedArrayMove<T>(
|
export function nestedArrayMove<A>(
|
||||||
obj: T | T[],
|
obj: A,
|
||||||
oldIndex: number,
|
oldIndex: number,
|
||||||
newIndex: number,
|
newIndex: number,
|
||||||
oldPath?: ItemPath,
|
oldPath?: ItemPath,
|
||||||
newPath?: ItemPath
|
newPath?: ItemPath
|
||||||
): T | T[] {
|
): A {
|
||||||
const newObj = Array.isArray(obj) ? [...obj] : { ...obj };
|
const newObj = (Array.isArray(obj) ? [...obj] : { ...obj }) as A;
|
||||||
const from = oldPath ? findNestedItem(newObj, oldPath) : newObj;
|
const from = oldPath ? findNestedItem(newObj, oldPath) : newObj;
|
||||||
const to = newPath ? findNestedItem(newObj, newPath, true) : newObj;
|
const to = newPath ? findNestedItem(newObj, newPath, true) : newObj;
|
||||||
|
|
||||||
|
|||||||
@@ -5,10 +5,18 @@ import type {
|
|||||||
ChartOptions,
|
ChartOptions,
|
||||||
TooltipModel,
|
TooltipModel,
|
||||||
} from "chart.js";
|
} from "chart.js";
|
||||||
import { css, CSSResultGroup, html, LitElement, PropertyValues } from "lit";
|
import {
|
||||||
|
css,
|
||||||
|
CSSResultGroup,
|
||||||
|
html,
|
||||||
|
nothing,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues,
|
||||||
|
} from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { classMap } from "lit/directives/class-map";
|
import { classMap } from "lit/directives/class-map";
|
||||||
import { styleMap } from "lit/directives/style-map";
|
import { styleMap } from "lit/directives/style-map";
|
||||||
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
import { clamp } from "../../common/number/clamp";
|
import { clamp } from "../../common/number/clamp";
|
||||||
import { HomeAssistant } from "../../types";
|
import { HomeAssistant } from "../../types";
|
||||||
import { debounce } from "../../common/util/debounce";
|
import { debounce } from "../../common/util/debounce";
|
||||||
@@ -27,6 +35,11 @@ interface Tooltip
|
|||||||
left: string;
|
left: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ChartDatasetExtra {
|
||||||
|
show_legend?: boolean;
|
||||||
|
legend_label?: string;
|
||||||
|
}
|
||||||
|
|
||||||
@customElement("ha-chart-base")
|
@customElement("ha-chart-base")
|
||||||
export class HaChartBase extends LitElement {
|
export class HaChartBase extends LitElement {
|
||||||
public chart?: Chart;
|
public chart?: Chart;
|
||||||
@@ -38,6 +51,8 @@ export class HaChartBase extends LitElement {
|
|||||||
|
|
||||||
@property({ attribute: false }) public data: ChartData = { datasets: [] };
|
@property({ attribute: false }) public data: ChartData = { datasets: [] };
|
||||||
|
|
||||||
|
@property({ attribute: false }) public extraData?: ChartDatasetExtra[];
|
||||||
|
|
||||||
@property({ attribute: false }) public options?: ChartOptions;
|
@property({ attribute: false }) public options?: ChartOptions;
|
||||||
|
|
||||||
@property({ attribute: false }) public plugins?: any[];
|
@property({ attribute: false }) public plugins?: any[];
|
||||||
@@ -46,6 +61,8 @@ export class HaChartBase extends LitElement {
|
|||||||
|
|
||||||
@property({ type: Number }) public paddingYAxis = 0;
|
@property({ type: Number }) public paddingYAxis = 0;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public externalHidden = false;
|
||||||
|
|
||||||
@state() private _chartHeight?: number;
|
@state() private _chartHeight?: number;
|
||||||
|
|
||||||
@state() private _tooltip?: Tooltip;
|
@state() private _tooltip?: Tooltip;
|
||||||
@@ -58,6 +75,8 @@ export class HaChartBase extends LitElement {
|
|||||||
|
|
||||||
private _paddingYAxisInternal = 0;
|
private _paddingYAxisInternal = 0;
|
||||||
|
|
||||||
|
private _datasetOrder: number[] = [];
|
||||||
|
|
||||||
public disconnectedCallback() {
|
public disconnectedCallback() {
|
||||||
super.disconnectedCallback();
|
super.disconnectedCallback();
|
||||||
this._releaseCanvas();
|
this._releaseCanvas();
|
||||||
@@ -148,6 +167,29 @@ export class HaChartBase extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// put the legend labels in sorted order if provided
|
||||||
|
if (changedProps.has("data")) {
|
||||||
|
this._datasetOrder = this.data.datasets.map((_, index) => index);
|
||||||
|
if (this.data?.datasets.some((dataset) => dataset.order)) {
|
||||||
|
this._datasetOrder.sort(
|
||||||
|
(a, b) =>
|
||||||
|
(this.data.datasets[a].order || 0) -
|
||||||
|
(this.data.datasets[b].order || 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.externalHidden) {
|
||||||
|
this._hiddenDatasets = new Set();
|
||||||
|
if (this.data?.datasets) {
|
||||||
|
this.data.datasets.forEach((dataset, index) => {
|
||||||
|
if (dataset.hidden) {
|
||||||
|
this._hiddenDatasets.add(index);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.hasUpdated || !this.chart) {
|
if (!this.hasUpdated || !this.chart) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -157,7 +199,7 @@ export class HaChartBase extends LitElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (changedProps.has("data")) {
|
if (changedProps.has("data")) {
|
||||||
if (this._hiddenDatasets.size) {
|
if (this._hiddenDatasets.size && !this.externalHidden) {
|
||||||
this.data.datasets.forEach((dataset, index) => {
|
this.data.datasets.forEach((dataset, index) => {
|
||||||
dataset.hidden = this._hiddenDatasets.has(index);
|
dataset.hidden = this._hiddenDatasets.has(index);
|
||||||
});
|
});
|
||||||
@@ -175,26 +217,32 @@ export class HaChartBase extends LitElement {
|
|||||||
${this.options?.plugins?.legend?.display === true
|
${this.options?.plugins?.legend?.display === true
|
||||||
? html`<div class="chartLegend">
|
? html`<div class="chartLegend">
|
||||||
<ul>
|
<ul>
|
||||||
${this.data.datasets.map(
|
${this._datasetOrder.map((index) => {
|
||||||
(dataset, index) =>
|
const dataset = this.data.datasets[index];
|
||||||
html`<li
|
return this.extraData?.[index]?.show_legend === false
|
||||||
.datasetIndex=${index}
|
? nothing
|
||||||
@click=${this._legendClick}
|
: html`<li
|
||||||
class=${classMap({
|
.datasetIndex=${index}
|
||||||
hidden: this._hiddenDatasets.has(index),
|
@click=${this._legendClick}
|
||||||
})}
|
class=${classMap({
|
||||||
.title=${dataset.label}
|
hidden: this._hiddenDatasets.has(index),
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="bullet"
|
|
||||||
style=${styleMap({
|
|
||||||
backgroundColor: dataset.backgroundColor as string,
|
|
||||||
borderColor: dataset.borderColor as string,
|
|
||||||
})}
|
})}
|
||||||
></div>
|
.title=${this.extraData?.[index]?.legend_label ??
|
||||||
<div class="label">${dataset.label}</div>
|
dataset.label}
|
||||||
</li>`
|
>
|
||||||
)}
|
<div
|
||||||
|
class="bullet"
|
||||||
|
style=${styleMap({
|
||||||
|
backgroundColor: dataset.backgroundColor as string,
|
||||||
|
borderColor: dataset.borderColor as string,
|
||||||
|
})}
|
||||||
|
></div>
|
||||||
|
<div class="label">
|
||||||
|
${this.extraData?.[index]?.legend_label ??
|
||||||
|
dataset.label}
|
||||||
|
</div>
|
||||||
|
</li>`;
|
||||||
|
})}
|
||||||
</ul>
|
</ul>
|
||||||
</div>`
|
</div>`
|
||||||
: ""}
|
: ""}
|
||||||
@@ -211,9 +259,9 @@ export class HaChartBase extends LitElement {
|
|||||||
height: `${
|
height: `${
|
||||||
this.height ?? this._chartHeight ?? this.clientWidth / 2
|
this.height ?? this._chartHeight ?? this.clientWidth / 2
|
||||||
}px`,
|
}px`,
|
||||||
"padding-left": `${this._paddingYAxisInternal}`,
|
"padding-left": `${this._paddingYAxisInternal}px`,
|
||||||
"padding-right": 0,
|
"padding-right": 0,
|
||||||
"padding-inline-start": `${this._paddingYAxisInternal}`,
|
"padding-inline-start": `${this._paddingYAxisInternal}px`,
|
||||||
"padding-inline-end": 0,
|
"padding-inline-end": 0,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
@@ -339,9 +387,19 @@ export class HaChartBase extends LitElement {
|
|||||||
if (this.chart.isDatasetVisible(index)) {
|
if (this.chart.isDatasetVisible(index)) {
|
||||||
this.chart.setDatasetVisibility(index, false);
|
this.chart.setDatasetVisibility(index, false);
|
||||||
this._hiddenDatasets.add(index);
|
this._hiddenDatasets.add(index);
|
||||||
|
if (this.externalHidden) {
|
||||||
|
fireEvent(this, "dataset-hidden", {
|
||||||
|
index,
|
||||||
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.chart.setDatasetVisibility(index, true);
|
this.chart.setDatasetVisibility(index, true);
|
||||||
this._hiddenDatasets.delete(index);
|
this._hiddenDatasets.delete(index);
|
||||||
|
if (this.externalHidden) {
|
||||||
|
fireEvent(this, "dataset-unhidden", {
|
||||||
|
index,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.chart.update("none");
|
this.chart.update("none");
|
||||||
this.requestUpdate("_hiddenDatasets");
|
this.requestUpdate("_hiddenDatasets");
|
||||||
@@ -486,4 +544,8 @@ declare global {
|
|||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
"ha-chart-base": HaChartBase;
|
"ha-chart-base": HaChartBase;
|
||||||
}
|
}
|
||||||
|
interface HASSDomEvents {
|
||||||
|
"dataset-hidden": { index: number };
|
||||||
|
"dataset-unhidden": { index: number };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ export class StateHistoryChartLine extends LitElement {
|
|||||||
config: this.hass.config,
|
config: this.hass.config,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
suggestedMin: this.startTime,
|
min: this.startTime,
|
||||||
suggestedMax: this.endTime,
|
suggestedMax: this.endTime,
|
||||||
ticks: {
|
ticks: {
|
||||||
maxRotation: 0,
|
maxRotation: 0,
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ export class StateHistoryChartTimeline extends LitElement {
|
|||||||
config: this.hass.config,
|
config: this.hass.config,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
suggestedMin: this.startTime,
|
min: this.startTime,
|
||||||
suggestedMax: this.endTime,
|
suggestedMax: this.endTime,
|
||||||
ticks: {
|
ticks: {
|
||||||
autoSkip: true,
|
autoSkip: true,
|
||||||
|
|||||||
@@ -233,16 +233,32 @@ export class StateHistoryCharts extends LitElement {
|
|||||||
new Date().getTime() - 60 * 60 * this.hoursToShow * 1000
|
new Date().getTime() - 60 * 60 * this.hoursToShow * 1000
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
this._computedStartTime = new Date(
|
let minTimeAll = (this.historyData?.timeline ?? []).reduce(
|
||||||
(this.historyData?.timeline ?? []).reduce(
|
(minTime, stateInfo) =>
|
||||||
(minTime, stateInfo) =>
|
Math.min(
|
||||||
Math.min(
|
minTime,
|
||||||
minTime,
|
new Date(stateInfo.data[0].last_changed).getTime()
|
||||||
new Date(stateInfo.data[0].last_changed).getTime()
|
),
|
||||||
),
|
new Date().getTime()
|
||||||
new Date().getTime()
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
minTimeAll = (this.historyData?.line ?? []).reduce(
|
||||||
|
(minTimeLine, line) =>
|
||||||
|
Math.min(
|
||||||
|
minTimeLine,
|
||||||
|
line.data.reduce(
|
||||||
|
(minTimeData, data) =>
|
||||||
|
Math.min(
|
||||||
|
minTimeData,
|
||||||
|
new Date(data.states[0].last_changed).getTime()
|
||||||
|
),
|
||||||
|
minTimeLine
|
||||||
|
)
|
||||||
|
),
|
||||||
|
minTimeAll
|
||||||
|
);
|
||||||
|
|
||||||
|
this._computedStartTime = new Date(minTimeAll);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { customElement, property, state, query } from "lit/decorators";
|
|||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { getGraphColorByIndex } from "../../common/color/colors";
|
import { getGraphColorByIndex } from "../../common/color/colors";
|
||||||
import { isComponentLoaded } from "../../common/config/is_component_loaded";
|
import { isComponentLoaded } from "../../common/config/is_component_loaded";
|
||||||
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
import {
|
import {
|
||||||
formatNumber,
|
formatNumber,
|
||||||
numberFormatToLocale,
|
numberFormatToLocale,
|
||||||
@@ -25,6 +26,7 @@ import {
|
|||||||
getDisplayUnit,
|
getDisplayUnit,
|
||||||
getStatisticLabel,
|
getStatisticLabel,
|
||||||
getStatisticMetadata,
|
getStatisticMetadata,
|
||||||
|
isExternalStatistic,
|
||||||
Statistics,
|
Statistics,
|
||||||
statisticsHaveType,
|
statisticsHaveType,
|
||||||
StatisticsMetaData,
|
StatisticsMetaData,
|
||||||
@@ -32,7 +34,11 @@ import {
|
|||||||
} from "../../data/recorder";
|
} from "../../data/recorder";
|
||||||
import type { HomeAssistant } from "../../types";
|
import type { HomeAssistant } from "../../types";
|
||||||
import "./ha-chart-base";
|
import "./ha-chart-base";
|
||||||
import type { ChartResizeOptions, HaChartBase } from "./ha-chart-base";
|
import type {
|
||||||
|
ChartResizeOptions,
|
||||||
|
ChartDatasetExtra,
|
||||||
|
HaChartBase,
|
||||||
|
} from "./ha-chart-base";
|
||||||
|
|
||||||
export const supportedStatTypeMap: Record<StatisticType, StatisticType> = {
|
export const supportedStatTypeMap: Record<StatisticType, StatisticType> = {
|
||||||
mean: "mean",
|
mean: "mean",
|
||||||
@@ -75,14 +81,20 @@ export class StatisticsChart extends LitElement {
|
|||||||
|
|
||||||
@property({ type: Boolean }) public isLoadingData = false;
|
@property({ type: Boolean }) public isLoadingData = false;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public clickForMoreInfo = true;
|
||||||
|
|
||||||
@property() public period?: string;
|
@property() public period?: string;
|
||||||
|
|
||||||
@state() private _chartData: ChartData = { datasets: [] };
|
@state() private _chartData: ChartData = { datasets: [] };
|
||||||
|
|
||||||
|
@state() private _chartDatasetExtra: ChartDatasetExtra[] = [];
|
||||||
|
|
||||||
@state() private _statisticIds: string[] = [];
|
@state() private _statisticIds: string[] = [];
|
||||||
|
|
||||||
@state() private _chartOptions?: ChartOptions;
|
@state() private _chartOptions?: ChartOptions;
|
||||||
|
|
||||||
|
@state() private _hiddenStats = new Set<string>();
|
||||||
|
|
||||||
@query("ha-chart-base") private _chart?: HaChartBase;
|
@query("ha-chart-base") private _chart?: HaChartBase;
|
||||||
|
|
||||||
private _computedStyle?: CSSStyleDeclaration;
|
private _computedStyle?: CSSStyleDeclaration;
|
||||||
@@ -96,6 +108,9 @@ export class StatisticsChart extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public willUpdate(changedProps: PropertyValues) {
|
public willUpdate(changedProps: PropertyValues) {
|
||||||
|
if (changedProps.has("legendMode")) {
|
||||||
|
this._hiddenStats.clear();
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
!this.hasUpdated ||
|
!this.hasUpdated ||
|
||||||
changedProps.has("unit") ||
|
changedProps.has("unit") ||
|
||||||
@@ -110,7 +125,8 @@ export class StatisticsChart extends LitElement {
|
|||||||
changedProps.has("statisticsData") ||
|
changedProps.has("statisticsData") ||
|
||||||
changedProps.has("statTypes") ||
|
changedProps.has("statTypes") ||
|
||||||
changedProps.has("chartType") ||
|
changedProps.has("chartType") ||
|
||||||
changedProps.has("hideLegend")
|
changedProps.has("hideLegend") ||
|
||||||
|
changedProps.has("_hiddenStats")
|
||||||
) {
|
) {
|
||||||
this._generateData();
|
this._generateData();
|
||||||
}
|
}
|
||||||
@@ -145,14 +161,30 @@ export class StatisticsChart extends LitElement {
|
|||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-chart-base
|
<ha-chart-base
|
||||||
|
externalHidden
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.data=${this._chartData}
|
.data=${this._chartData}
|
||||||
|
.extraData=${this._chartDatasetExtra}
|
||||||
.options=${this._chartOptions}
|
.options=${this._chartOptions}
|
||||||
.chartType=${this.chartType}
|
.chartType=${this.chartType}
|
||||||
|
@dataset-hidden=${this._datasetHidden}
|
||||||
|
@dataset-unhidden=${this._datasetUnhidden}
|
||||||
></ha-chart-base>
|
></ha-chart-base>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _datasetHidden(ev) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this._hiddenStats.add(this._statisticIds[ev.detail.index]);
|
||||||
|
this.requestUpdate("_hiddenStats");
|
||||||
|
}
|
||||||
|
|
||||||
|
private _datasetUnhidden(ev) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this._hiddenStats.delete(this._statisticIds[ev.detail.index]);
|
||||||
|
this.requestUpdate("_hiddenStats");
|
||||||
|
}
|
||||||
|
|
||||||
private _createOptions(unit?: string) {
|
private _createOptions(unit?: string) {
|
||||||
this._chartOptions = {
|
this._chartOptions = {
|
||||||
parsing: false,
|
parsing: false,
|
||||||
@@ -245,6 +277,33 @@ export class StatisticsChart extends LitElement {
|
|||||||
},
|
},
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
locale: numberFormatToLocale(this.hass.locale),
|
locale: numberFormatToLocale(this.hass.locale),
|
||||||
|
onClick: (e: any) => {
|
||||||
|
if (
|
||||||
|
!this.clickForMoreInfo ||
|
||||||
|
!(e.native instanceof MouseEvent) ||
|
||||||
|
(e.native instanceof PointerEvent && e.native.pointerType !== "mouse")
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const chart = e.chart;
|
||||||
|
|
||||||
|
const points = chart.getElementsAtEventForMode(
|
||||||
|
e,
|
||||||
|
"nearest",
|
||||||
|
{ intersect: true },
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
if (points.length) {
|
||||||
|
const firstPoint = points[0];
|
||||||
|
const statisticId = this._statisticIds[firstPoint.datasetIndex];
|
||||||
|
if (!isExternalStatistic(statisticId)) {
|
||||||
|
fireEvent(this, "hass-more-info", { entityId: statisticId });
|
||||||
|
chart.canvas.dispatchEvent(new Event("mouseout")); // to hide tooltip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,6 +333,7 @@ export class StatisticsChart extends LitElement {
|
|||||||
let colorIndex = 0;
|
let colorIndex = 0;
|
||||||
const statisticsData = Object.entries(this.statisticsData);
|
const statisticsData = Object.entries(this.statisticsData);
|
||||||
const totalDataSets: ChartDataset<"line">[] = [];
|
const totalDataSets: ChartDataset<"line">[] = [];
|
||||||
|
const totalDatasetExtras: ChartDatasetExtra[] = [];
|
||||||
const statisticIds: string[] = [];
|
const statisticIds: string[] = [];
|
||||||
let endTime: Date;
|
let endTime: Date;
|
||||||
|
|
||||||
@@ -324,6 +384,7 @@ export class StatisticsChart extends LitElement {
|
|||||||
|
|
||||||
// The datasets for the current statistic
|
// The datasets for the current statistic
|
||||||
const statDataSets: ChartDataset<"line">[] = [];
|
const statDataSets: ChartDataset<"line">[] = [];
|
||||||
|
const statDatasetExtras: ChartDatasetExtra[] = [];
|
||||||
|
|
||||||
const pushData = (
|
const pushData = (
|
||||||
start: Date,
|
start: Date,
|
||||||
@@ -384,9 +445,20 @@ export class StatisticsChart extends LitElement {
|
|||||||
})
|
})
|
||||||
: this.statTypes;
|
: this.statTypes;
|
||||||
|
|
||||||
|
let displayed_legend = false;
|
||||||
sortedTypes.forEach((type) => {
|
sortedTypes.forEach((type) => {
|
||||||
if (statisticsHaveType(stats, type)) {
|
if (statisticsHaveType(stats, type)) {
|
||||||
const band = drawBands && (type === "min" || type === "max");
|
const band = drawBands && (type === "min" || type === "max");
|
||||||
|
if (!this.hideLegend) {
|
||||||
|
const show_legend = hasMean
|
||||||
|
? type === "mean"
|
||||||
|
: displayed_legend === false;
|
||||||
|
statDatasetExtras.push({
|
||||||
|
legend_label: name,
|
||||||
|
show_legend,
|
||||||
|
});
|
||||||
|
displayed_legend = displayed_legend || show_legend;
|
||||||
|
}
|
||||||
statTypes.push(type);
|
statTypes.push(type);
|
||||||
statDataSets.push({
|
statDataSets.push({
|
||||||
label: name
|
label: name
|
||||||
@@ -408,6 +480,9 @@ export class StatisticsChart extends LitElement {
|
|||||||
band && hasMean ? color + (this.hideLegend ? "00" : "7F") : color,
|
band && hasMean ? color + (this.hideLegend ? "00" : "7F") : color,
|
||||||
backgroundColor: band ? color + "3F" : color + "7F",
|
backgroundColor: band ? color + "3F" : color + "7F",
|
||||||
pointRadius: 0,
|
pointRadius: 0,
|
||||||
|
hidden: !this.hideLegend
|
||||||
|
? this._hiddenStats.has(statistic_id)
|
||||||
|
: false,
|
||||||
data: [],
|
data: [],
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
unit: meta?.unit_of_measurement,
|
unit: meta?.unit_of_measurement,
|
||||||
@@ -446,6 +521,7 @@ export class StatisticsChart extends LitElement {
|
|||||||
|
|
||||||
// Concat two arrays
|
// Concat two arrays
|
||||||
Array.prototype.push.apply(totalDataSets, statDataSets);
|
Array.prototype.push.apply(totalDataSets, statDataSets);
|
||||||
|
Array.prototype.push.apply(totalDatasetExtras, statDatasetExtras);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (unit) {
|
if (unit) {
|
||||||
@@ -455,6 +531,7 @@ export class StatisticsChart extends LitElement {
|
|||||||
this._chartData = {
|
this._chartData = {
|
||||||
datasets: totalDataSets,
|
datasets: totalDataSets,
|
||||||
};
|
};
|
||||||
|
this._chartDatasetExtra = totalDatasetExtras;
|
||||||
this._statisticIds = statisticIds;
|
this._statisticIds = statisticIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -205,7 +205,9 @@ export class TimelineController extends BarController {
|
|||||||
|
|
||||||
const y = vScale.getPixelForValue(this.index);
|
const y = vScale.getPixelForValue(this.index);
|
||||||
|
|
||||||
const xStart = iScale.getPixelForValue(data.start.getTime());
|
const xStart = iScale.getPixelForValue(
|
||||||
|
Math.max(iScale.min, data.start.getTime())
|
||||||
|
);
|
||||||
const xEnd = iScale.getPixelForValue(data.end.getTime());
|
const xEnd = iScale.getPixelForValue(data.end.getTime());
|
||||||
const width = xEnd - xStart;
|
const width = xEnd - xStart;
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ export class TimeLineScale extends TimeScale {
|
|||||||
max = isFinite(max) && !isNaN(max) ? max : +adapter.endOf(Date.now(), unit);
|
max = isFinite(max) && !isNaN(max) ? max : +adapter.endOf(Date.now(), unit);
|
||||||
|
|
||||||
// Make sure that max is strictly higher than min (required by the lookup table)
|
// Make sure that max is strictly higher than min (required by the lookup table)
|
||||||
this.min = Math.min(min, max - 1);
|
this.min = adapter.parse(options.min, this) ?? Math.min(min, max - 1);
|
||||||
this.max = Math.max(min + 1, max);
|
this.max = adapter.parse(options.max, this) ?? Math.max(min + 1, max);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,22 +4,24 @@ import { css, html } from "lit";
|
|||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
|
|
||||||
@customElement("ha-assist-chip")
|
@customElement("ha-assist-chip")
|
||||||
|
// @ts-ignore
|
||||||
export class HaAssistChip extends MdAssistChip {
|
export class HaAssistChip extends MdAssistChip {
|
||||||
@property({ type: Boolean, reflect: true }) filled = false;
|
@property({ type: Boolean, reflect: true }) filled = false;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) active = false;
|
||||||
|
|
||||||
static override styles = [
|
static override styles = [
|
||||||
...super.styles,
|
...super.styles,
|
||||||
css`
|
css`
|
||||||
:host {
|
:host {
|
||||||
--md-sys-color-primary: var(--primary-text-color);
|
--md-sys-color-primary: var(--primary-text-color);
|
||||||
--md-sys-color-on-surface: var(--primary-text-color);
|
--md-sys-color-on-surface: var(--primary-text-color);
|
||||||
--md-assist-chip-container-shape: 16px;
|
--md-assist-chip-container-shape: var(
|
||||||
|
--ha-assist-chip-container-shape,
|
||||||
|
16px
|
||||||
|
);
|
||||||
--md-assist-chip-outline-color: var(--outline-color);
|
--md-assist-chip-outline-color: var(--outline-color);
|
||||||
--md-assist-chip-label-text-weight: 400;
|
--md-assist-chip-label-text-weight: 400;
|
||||||
--ha-assist-chip-filled-container-color: rgba(
|
|
||||||
var(--rgb-primary-text-color),
|
|
||||||
0.15
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
/** Material 3 doesn't have a filled chip, so we have to make our own **/
|
/** Material 3 doesn't have a filled chip, so we have to make our own **/
|
||||||
.filled {
|
.filled {
|
||||||
@@ -31,10 +33,28 @@ export class HaAssistChip extends MdAssistChip {
|
|||||||
background-color: var(--ha-assist-chip-filled-container-color);
|
background-color: var(--ha-assist-chip-filled-container-color);
|
||||||
}
|
}
|
||||||
/** Set the size of mdc icons **/
|
/** Set the size of mdc icons **/
|
||||||
::slotted([slot="icon"]) {
|
::slotted([slot="icon"]),
|
||||||
|
::slotted([slot="trailingIcon"]) {
|
||||||
display: flex;
|
display: flex;
|
||||||
--mdc-icon-size: var(--md-input-chip-icon-size, 18px);
|
--mdc-icon-size: var(--md-input-chip-icon-size, 18px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.trailing.icon ::slotted(*),
|
||||||
|
.trailing.icon svg {
|
||||||
|
margin-inline-end: unset;
|
||||||
|
margin-inline-start: var(--_icon-label-space);
|
||||||
|
}
|
||||||
|
::before {
|
||||||
|
background: var(--ha-assist-chip-container-color);
|
||||||
|
opacity: var(--ha-assist-chip-container-opacity);
|
||||||
|
}
|
||||||
|
:where(.active)::before {
|
||||||
|
background: var(--ha-assist-chip-active-container-color);
|
||||||
|
opacity: var(--ha-assist-chip-active-container-opacity);
|
||||||
|
}
|
||||||
|
.label {
|
||||||
|
font-family: Roboto, sans-serif;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -45,6 +65,30 @@ export class HaAssistChip extends MdAssistChip {
|
|||||||
|
|
||||||
return super.renderOutline();
|
return super.renderOutline();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override getContainerClasses() {
|
||||||
|
return {
|
||||||
|
...super.getContainerClasses(),
|
||||||
|
active: this.active,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override renderPrimaryContent() {
|
||||||
|
return html`
|
||||||
|
<span class="leading icon" aria-hidden="true">
|
||||||
|
${this.renderLeadingIcon()}
|
||||||
|
</span>
|
||||||
|
<span class="label">${this.label}</span>
|
||||||
|
<span class="touch"></span>
|
||||||
|
<span class="trailing leading icon" aria-hidden="true">
|
||||||
|
${this.renderTrailingIcon()}
|
||||||
|
</span>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected renderTrailingIcon() {
|
||||||
|
return html`<slot name="trailing-icon"></slot>`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
|||||||
@@ -19,12 +19,16 @@ export class HaInputChip extends MdInputChip {
|
|||||||
var(--rgb-primary-text-color),
|
var(--rgb-primary-text-color),
|
||||||
0.15
|
0.15
|
||||||
);
|
);
|
||||||
|
--ha-input-chip-selected-container-opacity: 1;
|
||||||
}
|
}
|
||||||
/** Set the size of mdc icons **/
|
/** Set the size of mdc icons **/
|
||||||
::slotted([slot="icon"]) {
|
::slotted([slot="icon"]) {
|
||||||
display: flex;
|
display: flex;
|
||||||
--mdc-icon-size: var(--md-input-chip-icon-size, 18px);
|
--mdc-icon-size: var(--md-input-chip-icon-size, 18px);
|
||||||
}
|
}
|
||||||
|
.selected::before {
|
||||||
|
opacity: var(--ha-input-chip-selected-container-opacity);
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ class HaDataTableIcon extends LitElement {
|
|||||||
div {
|
div {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 28px;
|
right: 28px;
|
||||||
|
inset-inline-end: 28px;
|
||||||
|
inset-inline-start: initial;
|
||||||
z-index: 1002;
|
z-index: 1002;
|
||||||
outline: none;
|
outline: none;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
|
|||||||
130
src/components/data-table/ha-data-table-labels.ts
Normal file
130
src/components/data-table/ha-data-table-labels.ts
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
import { css, html, LitElement, nothing, TemplateResult } from "lit";
|
||||||
|
import { customElement, property } from "lit/decorators";
|
||||||
|
import { repeat } from "lit/directives/repeat";
|
||||||
|
import { LabelRegistryEntry } from "../../data/label_registry";
|
||||||
|
import { computeCssColor } from "../../common/color/compute-color";
|
||||||
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
|
import "../ha-label";
|
||||||
|
import { stringCompare } from "../../common/string/compare";
|
||||||
|
|
||||||
|
@customElement("ha-data-table-labels")
|
||||||
|
class HaDataTableLabels extends LitElement {
|
||||||
|
@property({ attribute: false }) public labels!: LabelRegistryEntry[];
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
const labels = this.labels.sort((a, b) => stringCompare(a.name, b.name));
|
||||||
|
return html`
|
||||||
|
<ha-chip-set>
|
||||||
|
${repeat(
|
||||||
|
labels.slice(0, 2),
|
||||||
|
(label) => label.label_id,
|
||||||
|
(label) => this._renderLabel(label, true)
|
||||||
|
)}
|
||||||
|
${labels.length > 2
|
||||||
|
? html`<ha-button-menu
|
||||||
|
absolute
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
@click=${this._handleIconOverflowMenuOpened}
|
||||||
|
@closed=${this._handleIconOverflowMenuClosed}
|
||||||
|
>
|
||||||
|
<ha-label slot="trigger" class="plus" dense>
|
||||||
|
+${labels.length - 2}
|
||||||
|
</ha-label>
|
||||||
|
${repeat(
|
||||||
|
labels.slice(2),
|
||||||
|
(label) => label.label_id,
|
||||||
|
(label) => html`
|
||||||
|
<ha-list-item @click=${this._labelClicked} .item=${label}>
|
||||||
|
${this._renderLabel(label, false)}
|
||||||
|
</ha-list-item>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</ha-button-menu>`
|
||||||
|
: nothing}
|
||||||
|
</ha-chip-set>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _renderLabel(label: LabelRegistryEntry, clickAction: boolean) {
|
||||||
|
const color = label?.color ? computeCssColor(label.color) : undefined;
|
||||||
|
return html`
|
||||||
|
<ha-label
|
||||||
|
dense
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
.item=${label}
|
||||||
|
@click=${clickAction ? this._labelClicked : undefined}
|
||||||
|
@keydown=${clickAction ? this._labelClicked : undefined}
|
||||||
|
style=${color ? `--color: ${color}` : ""}
|
||||||
|
>
|
||||||
|
${label?.icon
|
||||||
|
? html`<ha-icon slot="icon" .icon=${label.icon}></ha-icon>`
|
||||||
|
: nothing}
|
||||||
|
${label.name}
|
||||||
|
</ha-label>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _labelClicked(ev) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
if (ev.type === "keydown" && ev.key !== "Enter" && ev.key !== " ") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const label = (ev.currentTarget as any).item as LabelRegistryEntry;
|
||||||
|
fireEvent(this, "label-clicked", { label });
|
||||||
|
}
|
||||||
|
|
||||||
|
protected _handleIconOverflowMenuOpened(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
// If this component is used inside a data table, the z-index of the row
|
||||||
|
// needs to be increased. Otherwise the ha-button-menu would be displayed
|
||||||
|
// underneath the next row in the table.
|
||||||
|
const row = this.closest(".mdc-data-table__row") as HTMLDivElement | null;
|
||||||
|
if (row) {
|
||||||
|
row.style.zIndex = "1";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected _handleIconOverflowMenuClosed() {
|
||||||
|
const row = this.closest(".mdc-data-table__row") as HTMLDivElement | null;
|
||||||
|
if (row) {
|
||||||
|
row.style.zIndex = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return css`
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
flex-grow: 1;
|
||||||
|
margin-top: 4px;
|
||||||
|
height: 22px;
|
||||||
|
}
|
||||||
|
ha-chip-set {
|
||||||
|
position: fixed;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
}
|
||||||
|
ha-label {
|
||||||
|
--ha-label-background-color: var(--color, var(--grey-color));
|
||||||
|
--ha-label-background-opacity: 0.5;
|
||||||
|
}
|
||||||
|
ha-button-menu {
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
.plus {
|
||||||
|
--ha-label-background-color: transparent;
|
||||||
|
border: 1px solid var(--divider-color);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-data-table-labels": HaDataTableLabels;
|
||||||
|
}
|
||||||
|
interface HASSDomEvents {
|
||||||
|
"label-clicked": { label: LabelRegistryEntry };
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -32,6 +32,7 @@ import type { HaCheckbox } from "../ha-checkbox";
|
|||||||
import "../ha-svg-icon";
|
import "../ha-svg-icon";
|
||||||
import "../search-input";
|
import "../search-input";
|
||||||
import { filterData, sortData } from "./sort-filter";
|
import { filterData, sortData } from "./sort-filter";
|
||||||
|
import { groupBy } from "../../common/util/group-by";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
// for fire event
|
// for fire event
|
||||||
@@ -67,13 +68,20 @@ export interface DataTableSortColumnData {
|
|||||||
filterKey?: string;
|
filterKey?: string;
|
||||||
valueColumn?: string;
|
valueColumn?: string;
|
||||||
direction?: SortingDirection;
|
direction?: SortingDirection;
|
||||||
|
groupable?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DataTableColumnData<T = any> extends DataTableSortColumnData {
|
export interface DataTableColumnData<T = any> extends DataTableSortColumnData {
|
||||||
main?: boolean;
|
main?: boolean;
|
||||||
title: TemplateResult | string;
|
title: TemplateResult | string;
|
||||||
label?: TemplateResult | string;
|
label?: TemplateResult | string;
|
||||||
type?: "numeric" | "icon" | "icon-button" | "overflow-menu" | "flex";
|
type?:
|
||||||
|
| "numeric"
|
||||||
|
| "icon"
|
||||||
|
| "icon-button"
|
||||||
|
| "overflow"
|
||||||
|
| "overflow-menu"
|
||||||
|
| "flex";
|
||||||
template?: (row: T) => TemplateResult | string | typeof nothing;
|
template?: (row: T) => TemplateResult | string | typeof nothing;
|
||||||
width?: string;
|
width?: string;
|
||||||
maxWidth?: string;
|
maxWidth?: string;
|
||||||
@@ -95,6 +103,8 @@ export interface SortableColumnContainer {
|
|||||||
[key: string]: ClonedDataTableColumnData;
|
[key: string]: ClonedDataTableColumnData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const UNDEFINED_GROUP_KEY = "zzzzz_undefined";
|
||||||
|
|
||||||
@customElement("ha-data-table")
|
@customElement("ha-data-table")
|
||||||
export class HaDataTable extends LitElement {
|
export class HaDataTable extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
@@ -129,14 +139,16 @@ export class HaDataTable extends LitElement {
|
|||||||
|
|
||||||
@property({ type: String }) public filter = "";
|
@property({ type: String }) public filter = "";
|
||||||
|
|
||||||
|
@property() public groupColumn?: string;
|
||||||
|
|
||||||
|
@property() public sortColumn?: string;
|
||||||
|
|
||||||
|
@property() public sortDirection: SortingDirection = null;
|
||||||
|
|
||||||
@state() private _filterable = false;
|
@state() private _filterable = false;
|
||||||
|
|
||||||
@state() private _filter = "";
|
@state() private _filter = "";
|
||||||
|
|
||||||
@state() private _sortColumn?: string;
|
|
||||||
|
|
||||||
@state() private _sortDirection: SortingDirection = null;
|
|
||||||
|
|
||||||
@state() private _filteredData: DataTableRowData[] = [];
|
@state() private _filteredData: DataTableRowData[] = [];
|
||||||
|
|
||||||
@state() private _headerHeight = 0;
|
@state() private _headerHeight = 0;
|
||||||
@@ -169,6 +181,13 @@ export class HaDataTable extends LitElement {
|
|||||||
this._checkedRowsChanged();
|
this._checkedRowsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public selectAll(): void {
|
||||||
|
this._checkedRows = this._filteredData
|
||||||
|
.filter((data) => data.selectable !== false)
|
||||||
|
.map((data) => data[this.id]);
|
||||||
|
this._checkedRowsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
public connectedCallback() {
|
public connectedCallback() {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
if (this._items.length) {
|
if (this._items.length) {
|
||||||
@@ -195,8 +214,14 @@ export class HaDataTable extends LitElement {
|
|||||||
|
|
||||||
for (const columnId in this.columns) {
|
for (const columnId in this.columns) {
|
||||||
if (this.columns[columnId].direction) {
|
if (this.columns[columnId].direction) {
|
||||||
this._sortDirection = this.columns[columnId].direction!;
|
this.sortDirection = this.columns[columnId].direction!;
|
||||||
this._sortColumn = columnId;
|
this.sortColumn = columnId;
|
||||||
|
|
||||||
|
fireEvent(this, "sorting-changed", {
|
||||||
|
column: columnId,
|
||||||
|
direction: this.sortDirection,
|
||||||
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -226,11 +251,16 @@ export class HaDataTable extends LitElement {
|
|||||||
properties.has("data") ||
|
properties.has("data") ||
|
||||||
properties.has("columns") ||
|
properties.has("columns") ||
|
||||||
properties.has("_filter") ||
|
properties.has("_filter") ||
|
||||||
properties.has("_sortColumn") ||
|
properties.has("sortColumn") ||
|
||||||
properties.has("_sortDirection")
|
properties.has("sortDirection") ||
|
||||||
|
properties.has("groupColumn")
|
||||||
) {
|
) {
|
||||||
this._sortFilterData();
|
this._sortFilterData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (properties.has("selectable")) {
|
||||||
|
this._items = [...this._items];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
@@ -263,75 +293,79 @@ export class HaDataTable extends LitElement {
|
|||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<div class="mdc-data-table__header-row" role="row" aria-rowindex="1">
|
<div class="mdc-data-table__header-row" role="row" aria-rowindex="1">
|
||||||
${this.selectable
|
<slot name="header-row">
|
||||||
? html`
|
${this.selectable
|
||||||
<div
|
? html`
|
||||||
class="mdc-data-table__header-cell mdc-data-table__header-cell--checkbox"
|
<div
|
||||||
role="columnheader"
|
class="mdc-data-table__header-cell mdc-data-table__header-cell--checkbox"
|
||||||
>
|
role="columnheader"
|
||||||
<ha-checkbox
|
|
||||||
class="mdc-data-table__row-checkbox"
|
|
||||||
@change=${this._handleHeaderRowCheckboxClick}
|
|
||||||
.indeterminate=${this._checkedRows.length &&
|
|
||||||
this._checkedRows.length !== this._checkableRowsCount}
|
|
||||||
.checked=${this._checkedRows.length &&
|
|
||||||
this._checkedRows.length === this._checkableRowsCount}
|
|
||||||
>
|
>
|
||||||
</ha-checkbox>
|
<ha-checkbox
|
||||||
|
class="mdc-data-table__row-checkbox"
|
||||||
|
@change=${this._handleHeaderRowCheckboxClick}
|
||||||
|
.indeterminate=${this._checkedRows.length &&
|
||||||
|
this._checkedRows.length !== this._checkableRowsCount}
|
||||||
|
.checked=${this._checkedRows.length &&
|
||||||
|
this._checkedRows.length === this._checkableRowsCount}
|
||||||
|
>
|
||||||
|
</ha-checkbox>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
${Object.entries(this.columns).map(([key, column]) => {
|
||||||
|
if (column.hidden) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
const sorted = key === this.sortColumn;
|
||||||
|
const classes = {
|
||||||
|
"mdc-data-table__header-cell--numeric":
|
||||||
|
column.type === "numeric",
|
||||||
|
"mdc-data-table__header-cell--icon": column.type === "icon",
|
||||||
|
"mdc-data-table__header-cell--icon-button":
|
||||||
|
column.type === "icon-button",
|
||||||
|
"mdc-data-table__header-cell--overflow-menu":
|
||||||
|
column.type === "overflow-menu",
|
||||||
|
"mdc-data-table__header-cell--overflow":
|
||||||
|
column.type === "overflow",
|
||||||
|
sortable: Boolean(column.sortable),
|
||||||
|
"not-sorted": Boolean(column.sortable && !sorted),
|
||||||
|
grows: Boolean(column.grows),
|
||||||
|
};
|
||||||
|
return html`
|
||||||
|
<div
|
||||||
|
aria-label=${ifDefined(column.label)}
|
||||||
|
class="mdc-data-table__header-cell ${classMap(classes)}"
|
||||||
|
style=${column.width
|
||||||
|
? styleMap({
|
||||||
|
[column.grows ? "minWidth" : "width"]: column.width,
|
||||||
|
maxWidth: column.maxWidth || "",
|
||||||
|
})
|
||||||
|
: ""}
|
||||||
|
role="columnheader"
|
||||||
|
aria-sort=${ifDefined(
|
||||||
|
sorted
|
||||||
|
? this.sortDirection === "desc"
|
||||||
|
? "descending"
|
||||||
|
: "ascending"
|
||||||
|
: undefined
|
||||||
|
)}
|
||||||
|
@click=${this._handleHeaderClick}
|
||||||
|
.columnId=${key}
|
||||||
|
>
|
||||||
|
${column.sortable
|
||||||
|
? html`
|
||||||
|
<ha-svg-icon
|
||||||
|
.path=${sorted && this.sortDirection === "desc"
|
||||||
|
? mdiArrowDown
|
||||||
|
: mdiArrowUp}
|
||||||
|
></ha-svg-icon>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
<span>${column.title}</span>
|
||||||
</div>
|
</div>
|
||||||
`
|
`;
|
||||||
: ""}
|
})}
|
||||||
${Object.entries(this.columns).map(([key, column]) => {
|
</slot>
|
||||||
if (column.hidden) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
const sorted = key === this._sortColumn;
|
|
||||||
const classes = {
|
|
||||||
"mdc-data-table__header-cell--numeric":
|
|
||||||
column.type === "numeric",
|
|
||||||
"mdc-data-table__header-cell--icon": column.type === "icon",
|
|
||||||
"mdc-data-table__header-cell--icon-button":
|
|
||||||
column.type === "icon-button",
|
|
||||||
"mdc-data-table__header-cell--overflow-menu":
|
|
||||||
column.type === "overflow-menu",
|
|
||||||
sortable: Boolean(column.sortable),
|
|
||||||
"not-sorted": Boolean(column.sortable && !sorted),
|
|
||||||
grows: Boolean(column.grows),
|
|
||||||
};
|
|
||||||
return html`
|
|
||||||
<div
|
|
||||||
aria-label=${ifDefined(column.label)}
|
|
||||||
class="mdc-data-table__header-cell ${classMap(classes)}"
|
|
||||||
style=${column.width
|
|
||||||
? styleMap({
|
|
||||||
[column.grows ? "minWidth" : "width"]: column.width,
|
|
||||||
maxWidth: column.maxWidth || "",
|
|
||||||
})
|
|
||||||
: ""}
|
|
||||||
role="columnheader"
|
|
||||||
aria-sort=${ifDefined(
|
|
||||||
sorted
|
|
||||||
? this._sortDirection === "desc"
|
|
||||||
? "descending"
|
|
||||||
: "ascending"
|
|
||||||
: undefined
|
|
||||||
)}
|
|
||||||
@click=${this._handleHeaderClick}
|
|
||||||
.columnId=${key}
|
|
||||||
>
|
|
||||||
${column.sortable
|
|
||||||
? html`
|
|
||||||
<ha-svg-icon
|
|
||||||
.path=${sorted && this._sortDirection === "desc"
|
|
||||||
? mdiArrowDown
|
|
||||||
: mdiArrowUp}
|
|
||||||
></ha-svg-icon>
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
<span>${column.title}</span>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
${!this._filteredData.length
|
${!this._filteredData.length
|
||||||
? html`
|
? html`
|
||||||
@@ -359,7 +393,7 @@ export class HaDataTable extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _keyFunction = (row: DataTableRowData) => row[this.id] || row;
|
private _keyFunction = (row: DataTableRowData) => row?.[this.id] || row;
|
||||||
|
|
||||||
private _renderRow = (row: DataTableRowData, index: number) => {
|
private _renderRow = (row: DataTableRowData, index: number) => {
|
||||||
// not sure how this happens...
|
// not sure how this happens...
|
||||||
@@ -408,7 +442,7 @@ export class HaDataTable extends LitElement {
|
|||||||
: ""}
|
: ""}
|
||||||
${Object.entries(this.columns).map(([key, column]) => {
|
${Object.entries(this.columns).map(([key, column]) => {
|
||||||
if (column.hidden) {
|
if (column.hidden) {
|
||||||
return "";
|
return nothing;
|
||||||
}
|
}
|
||||||
return html`
|
return html`
|
||||||
<div
|
<div
|
||||||
@@ -421,6 +455,7 @@ export class HaDataTable extends LitElement {
|
|||||||
column.type === "icon-button",
|
column.type === "icon-button",
|
||||||
"mdc-data-table__cell--overflow-menu":
|
"mdc-data-table__cell--overflow-menu":
|
||||||
column.type === "overflow-menu",
|
column.type === "overflow-menu",
|
||||||
|
"mdc-data-table__cell--overflow": column.type === "overflow",
|
||||||
grows: Boolean(column.grows),
|
grows: Boolean(column.grows),
|
||||||
forceLTR: Boolean(column.forceLTR),
|
forceLTR: Boolean(column.forceLTR),
|
||||||
})}"
|
})}"
|
||||||
@@ -453,12 +488,12 @@ export class HaDataTable extends LitElement {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const prom = this._sortColumn
|
const prom = this.sortColumn
|
||||||
? sortData(
|
? sortData(
|
||||||
filteredData,
|
filteredData,
|
||||||
this._sortColumns[this._sortColumn],
|
this._sortColumns[this.sortColumn],
|
||||||
this._sortDirection,
|
this.sortDirection,
|
||||||
this._sortColumn,
|
this.sortColumn,
|
||||||
this.hass.locale.language
|
this.hass.locale.language
|
||||||
)
|
)
|
||||||
: filteredData;
|
: filteredData;
|
||||||
@@ -477,17 +512,56 @@ export class HaDataTable extends LitElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.appendRow || this.hasFab) {
|
if (this.appendRow || this.hasFab || this.groupColumn) {
|
||||||
const items = [...data];
|
const items = [...data];
|
||||||
|
|
||||||
if (this.appendRow) {
|
if (this.appendRow) {
|
||||||
items.push({ append: true, content: this.appendRow });
|
items.push({ append: true, content: this.appendRow });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.hasFab) {
|
if (this.groupColumn) {
|
||||||
items.push({ empty: true });
|
const grouped = groupBy(items, (item) => item[this.groupColumn!]);
|
||||||
|
if (grouped.undefined) {
|
||||||
|
// make sure ungrouped items are at the bottom
|
||||||
|
grouped[UNDEFINED_GROUP_KEY] = grouped.undefined;
|
||||||
|
delete grouped.undefined;
|
||||||
|
}
|
||||||
|
const sorted: {
|
||||||
|
[key: string]: DataTableRowData[];
|
||||||
|
} = Object.keys(grouped)
|
||||||
|
.sort()
|
||||||
|
.reduce((obj, key) => {
|
||||||
|
obj[key] = grouped[key];
|
||||||
|
return obj;
|
||||||
|
}, {});
|
||||||
|
const groupedItems: DataTableRowData[] = [];
|
||||||
|
Object.entries(sorted).forEach(([groupName, rows]) => {
|
||||||
|
if (
|
||||||
|
groupName !== UNDEFINED_GROUP_KEY ||
|
||||||
|
Object.keys(sorted).length > 1
|
||||||
|
) {
|
||||||
|
groupedItems.push({
|
||||||
|
append: true,
|
||||||
|
content: html`<div
|
||||||
|
class="mdc-data-table__cell group-header"
|
||||||
|
role="cell"
|
||||||
|
>
|
||||||
|
${groupName === UNDEFINED_GROUP_KEY ? "" : groupName || ""}
|
||||||
|
</div>`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
groupedItems.push(...rows);
|
||||||
|
});
|
||||||
|
|
||||||
|
this._items = groupedItems;
|
||||||
|
} else {
|
||||||
|
this._items = items;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.hasFab) {
|
||||||
|
this._items = [...this._items, { empty: true }];
|
||||||
}
|
}
|
||||||
this._items = items;
|
|
||||||
} else {
|
} else {
|
||||||
this._items = data;
|
this._items = data;
|
||||||
}
|
}
|
||||||
@@ -507,29 +581,26 @@ export class HaDataTable extends LitElement {
|
|||||||
if (!this.columns[columnId].sortable) {
|
if (!this.columns[columnId].sortable) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!this._sortDirection || this._sortColumn !== columnId) {
|
if (!this.sortDirection || this.sortColumn !== columnId) {
|
||||||
this._sortDirection = "asc";
|
this.sortDirection = "asc";
|
||||||
} else if (this._sortDirection === "asc") {
|
} else if (this.sortDirection === "asc") {
|
||||||
this._sortDirection = "desc";
|
this.sortDirection = "desc";
|
||||||
} else {
|
} else {
|
||||||
this._sortDirection = null;
|
this.sortDirection = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._sortColumn = this._sortDirection === null ? undefined : columnId;
|
this.sortColumn = this.sortDirection === null ? undefined : columnId;
|
||||||
|
|
||||||
fireEvent(this, "sorting-changed", {
|
fireEvent(this, "sorting-changed", {
|
||||||
column: columnId,
|
column: columnId,
|
||||||
direction: this._sortDirection,
|
direction: this.sortDirection,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleHeaderRowCheckboxClick(ev: Event) {
|
private _handleHeaderRowCheckboxClick(ev: Event) {
|
||||||
const checkbox = ev.target as HaCheckbox;
|
const checkbox = ev.target as HaCheckbox;
|
||||||
if (checkbox.checked) {
|
if (checkbox.checked) {
|
||||||
this._checkedRows = this._filteredData
|
this.selectAll();
|
||||||
.filter((data) => data.selectable !== false)
|
|
||||||
.map((data) => data[this.id]);
|
|
||||||
this._checkedRowsChanged();
|
|
||||||
} else {
|
} else {
|
||||||
this._checkedRows = [];
|
this._checkedRows = [];
|
||||||
this._checkedRowsChanged();
|
this._checkedRowsChanged();
|
||||||
@@ -552,8 +623,19 @@ export class HaDataTable extends LitElement {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private _handleRowClick = (ev: Event) => {
|
private _handleRowClick = (ev: Event) => {
|
||||||
const target = ev.target as HTMLElement;
|
if (
|
||||||
if (["HA-CHECKBOX", "MWC-BUTTON"].includes(target.tagName)) {
|
ev
|
||||||
|
.composedPath()
|
||||||
|
.find((el) =>
|
||||||
|
[
|
||||||
|
"ha-checkbox",
|
||||||
|
"mwc-button",
|
||||||
|
"ha-button",
|
||||||
|
"ha-icon-button",
|
||||||
|
"ha-assist-chip",
|
||||||
|
].includes((el as HTMLElement).localName)
|
||||||
|
)
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const rowId = (ev.currentTarget as any).rowId;
|
const rowId = (ev.currentTarget as any).rowId;
|
||||||
@@ -629,7 +711,7 @@ export class HaDataTable extends LitElement {
|
|||||||
.mdc-data-table__row {
|
.mdc-data-table__row {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 52px;
|
height: var(--data-table-row-height, 52px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.mdc-data-table__row ~ .mdc-data-table__row {
|
.mdc-data-table__row ~ .mdc-data-table__row {
|
||||||
@@ -655,7 +737,6 @@ export class HaDataTable extends LitElement {
|
|||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-bottom: 1px solid var(--divider-color);
|
border-bottom: 1px solid var(--divider-color);
|
||||||
overflow-x: auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mdc-data-table__header-row::-webkit-scrollbar {
|
.mdc-data-table__header-row::-webkit-scrollbar {
|
||||||
@@ -809,7 +890,9 @@ export class HaDataTable extends LitElement {
|
|||||||
padding-inline-start: initial;
|
padding-inline-start: initial;
|
||||||
}
|
}
|
||||||
.mdc-data-table__cell--overflow-menu,
|
.mdc-data-table__cell--overflow-menu,
|
||||||
.mdc-data-table__header-cell--overflow-menu {
|
.mdc-data-table__cell--overflow,
|
||||||
|
.mdc-data-table__header-cell--overflow-menu,
|
||||||
|
.mdc-data-table__header-cell--overflow {
|
||||||
overflow: initial;
|
overflow: initial;
|
||||||
}
|
}
|
||||||
.mdc-data-table__cell--icon-button a {
|
.mdc-data-table__cell--icon-button a {
|
||||||
@@ -839,6 +922,12 @@ export class HaDataTable extends LitElement {
|
|||||||
|
|
||||||
/* custom from here */
|
/* custom from here */
|
||||||
|
|
||||||
|
.group-header {
|
||||||
|
padding-top: 12px;
|
||||||
|
width: 100%;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
:host {
|
:host {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,9 @@ export class StateBadge extends LitElement {
|
|||||||
|
|
||||||
@property() public overrideImage?: string;
|
@property() public overrideImage?: string;
|
||||||
|
|
||||||
@property({ type: Boolean }) public stateColor = false;
|
// Cannot be a boolean attribute because undefined is treated different than
|
||||||
|
// false. When it is undefined, state is still colored for light entities.
|
||||||
|
@property({ attribute: false }) public stateColor?: boolean;
|
||||||
|
|
||||||
@property() public color?: string;
|
@property() public color?: string;
|
||||||
|
|
||||||
@@ -70,7 +72,7 @@ export class StateBadge extends LitElement {
|
|||||||
const domain = this.stateObj
|
const domain = this.stateObj
|
||||||
? computeStateDomain(this.stateObj)
|
? computeStateDomain(this.stateObj)
|
||||||
: undefined;
|
: undefined;
|
||||||
return this.stateColor || (domain === "light" && this.stateColor !== false);
|
return this.stateColor ?? domain === "light";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user