mirror of
https://github.com/home-assistant/frontend.git
synced 2025-12-13 19:47:24 +00:00
Compare commits
344 Commits
conditiona
...
dashboard_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b44c7ce64 | ||
|
|
de370d6384 | ||
|
|
1cf928b425 | ||
|
|
b9c62c34a0 | ||
|
|
37554213dc | ||
|
|
3845fd2ef9 | ||
|
|
837b36a430 | ||
|
|
bff09a7a36 | ||
|
|
a5e5efa526 | ||
|
|
1cd5b9ff37 | ||
|
|
6a11155dd7 | ||
|
|
1acb76d2f0 | ||
|
|
2e8a40efd5 | ||
|
|
845a0e4e39 | ||
|
|
9417f13cc9 | ||
|
|
d3f52f3bc0 | ||
|
|
7d0ec00fde | ||
|
|
6dbb5dd4be | ||
|
|
f30e7948cb | ||
|
|
41472d8160 | ||
|
|
e596d32426 | ||
|
|
89de62812f | ||
|
|
3e391fcbe6 | ||
|
|
708ab2ed69 | ||
|
|
1d45cb78fe | ||
|
|
d3f6ebd1d0 | ||
|
|
21644c70b3 | ||
|
|
eb75389cac | ||
|
|
cd4f3a091b | ||
|
|
19c1973ec1 | ||
|
|
a8efbe5b06 | ||
|
|
44b5c66c19 | ||
|
|
3fa3bba4d8 | ||
|
|
ab09c821a2 | ||
|
|
37b7395986 | ||
|
|
4933413140 | ||
|
|
1c16bd5ab2 | ||
|
|
3a926c6f83 | ||
|
|
7a619ad55a | ||
|
|
bc21425981 | ||
|
|
f2505c0798 | ||
|
|
cee8c756fc | ||
|
|
396b3aace9 | ||
|
|
28dc1e4da9 | ||
|
|
aa0419e783 | ||
|
|
fd9c24d05e | ||
|
|
8bdbe8c6a6 | ||
|
|
39550cefa0 | ||
|
|
589e3b63c7 | ||
|
|
0cc38278b9 | ||
|
|
aafdf7bed7 | ||
|
|
a7f6ce3079 | ||
|
|
3d03f74d66 | ||
|
|
e09a6a23fc | ||
|
|
9e4bb6ed0c | ||
|
|
c45c8ab5c0 | ||
|
|
5ef6973933 | ||
|
|
1df344580a | ||
|
|
25acc479b9 | ||
|
|
c9f051374b | ||
|
|
bf5116fc0b | ||
|
|
edc8cb1d2e | ||
|
|
a60bb3ae0a | ||
|
|
784f753f07 | ||
|
|
e63c7e3763 | ||
|
|
cfa522068c | ||
|
|
5f2375fe84 | ||
|
|
a9e34d7590 | ||
|
|
463cfb869f | ||
|
|
acb5a2b283 | ||
|
|
08597d6e91 | ||
|
|
9478485268 | ||
|
|
0af9ec2fff | ||
|
|
f6e74de05e | ||
|
|
8b0373d5c0 | ||
|
|
d4218250af | ||
|
|
78783942be | ||
|
|
17ad8013ca | ||
|
|
f70767f084 | ||
|
|
3972394d82 | ||
|
|
5331fb4f5f | ||
|
|
16df352ba8 | ||
|
|
8e1e75dee1 | ||
|
|
d27b4e04a9 | ||
|
|
36f7b34ac5 | ||
|
|
c0ff24bf1b | ||
|
|
abb5aa348f | ||
|
|
37ab5cbdc3 | ||
|
|
42be3b331c | ||
|
|
71e05f79c2 | ||
|
|
c5a0a5bbbf | ||
|
|
c3d809fcf3 | ||
|
|
cbd0c39091 | ||
|
|
113eb5be24 | ||
|
|
c497669fd3 | ||
|
|
c32ca5885b | ||
|
|
3c792c4019 | ||
|
|
9762e61ee2 | ||
|
|
c09c39998b | ||
|
|
d37e29c247 | ||
|
|
51f22cd74a | ||
|
|
b57dc968bd | ||
|
|
e2e8cb785a | ||
|
|
9961a4ae3f | ||
|
|
c25755bfcd | ||
|
|
40983619d6 | ||
|
|
54758b5962 | ||
|
|
4f09485b20 | ||
|
|
9207f6c407 | ||
|
|
1a2312460a | ||
|
|
951b88ab4c | ||
|
|
d3cc57d8b4 | ||
|
|
4e9b118728 | ||
|
|
f1748e4dd5 | ||
|
|
d491d8f5ac | ||
|
|
cf0fde0f3c | ||
|
|
a7dc2cfaa6 | ||
|
|
d8c7db6ebf | ||
|
|
c3743b57ea | ||
|
|
e16a101de8 | ||
|
|
94ad47c60e | ||
|
|
184ef7b7ff | ||
|
|
81053f2e07 | ||
|
|
e8b4eeec67 | ||
|
|
b0b7e77e28 | ||
|
|
763f80b46a | ||
|
|
0c2531a7ee | ||
|
|
8d2ec8098c | ||
|
|
d2caed2b68 | ||
|
|
402d443843 | ||
|
|
399f12194a | ||
|
|
a745539c33 | ||
|
|
f6fddbc6ec | ||
|
|
01f51f3247 | ||
|
|
80112bb662 | ||
|
|
7ce7cbb755 | ||
|
|
464ecffda7 | ||
|
|
33e0c691c7 | ||
|
|
d94f7c90c0 | ||
|
|
d8d16c4d5f | ||
|
|
1cb238ec2a | ||
|
|
3e6ab8b179 | ||
|
|
10bcaadcdb | ||
|
|
67517643ef | ||
|
|
eb35eb3de5 | ||
|
|
8350d71f6e | ||
|
|
c840f1cbb1 | ||
|
|
8efc0816bb | ||
|
|
b12e4989db | ||
|
|
2b67731906 | ||
|
|
ccba7a7623 | ||
|
|
c0dfc9f73e | ||
|
|
be1624f66f | ||
|
|
32edbd7b33 | ||
|
|
18827db9ba | ||
|
|
191250a66a | ||
|
|
1fdf609606 | ||
|
|
6ffc0625d3 | ||
|
|
c9f5d16745 | ||
|
|
eb4afedf2e | ||
|
|
2b9540fe03 | ||
|
|
53b8d1bb0a | ||
|
|
0ff5bffd0c | ||
|
|
82a464f50f | ||
|
|
fdddc18291 | ||
|
|
463a3244cf | ||
|
|
6cae11f0a6 | ||
|
|
65112b36ce | ||
|
|
58625d2a9d | ||
|
|
9bafbdd989 | ||
|
|
eedb42b2f3 | ||
|
|
4354ad3807 | ||
|
|
aeaf091b50 | ||
|
|
c6be4d6f4d | ||
|
|
c48b620e03 | ||
|
|
77e05decdf | ||
|
|
b24e99c56c | ||
|
|
768344c3f7 | ||
|
|
03a21d5519 | ||
|
|
1247a5c8d3 | ||
|
|
db8287df89 | ||
|
|
71edbd6352 | ||
|
|
9d87a66908 | ||
|
|
11d62cece2 | ||
|
|
f15a65f5a6 | ||
|
|
a03d3f796b | ||
|
|
d0f5b0e864 | ||
|
|
e4a67dd555 | ||
|
|
f72ab94742 | ||
|
|
b521be6d3b | ||
|
|
3fa7001be6 | ||
|
|
b45226509b | ||
|
|
2a5f8097bc | ||
|
|
0ffe0f38e1 | ||
|
|
c48491088e | ||
|
|
f115e4025d | ||
|
|
7be8a799aa | ||
|
|
d992b2d40b | ||
|
|
96fbd8aefb | ||
|
|
17df761a1b | ||
|
|
79b2fa96ed | ||
|
|
c14e3333cf | ||
|
|
4af0ecbaa8 | ||
|
|
ce11301516 | ||
|
|
16766f8878 | ||
|
|
5e933e8e15 | ||
|
|
7eb92be84a | ||
|
|
60ec4d31db | ||
|
|
3526ba308f | ||
|
|
02a212a47d | ||
|
|
49f88a98a5 | ||
|
|
feb371839c | ||
|
|
24c37f5293 | ||
|
|
8f3fea5a33 | ||
|
|
b2bc529d7b | ||
|
|
ad68782b79 | ||
|
|
f432528388 | ||
|
|
f98c0769b0 | ||
|
|
b2cb0d8e0f | ||
|
|
4c7c04bdc0 | ||
|
|
ffb7469a7e | ||
|
|
d88831b719 | ||
|
|
3b2f6d71f5 | ||
|
|
a08185a1a5 | ||
|
|
7ee91ca8fc | ||
|
|
b6fe0cfa1b | ||
|
|
c3a9682861 | ||
|
|
62d21bea4f | ||
|
|
434b9595c0 | ||
|
|
a0f1b7f365 | ||
|
|
628c2c39cf | ||
|
|
4b885cbd93 | ||
|
|
02d9786f8c | ||
|
|
88d14cd7b5 | ||
|
|
4ea8f599cf | ||
|
|
37ef444180 | ||
|
|
4253feb8a2 | ||
|
|
ce33cf7ff3 | ||
|
|
faa4455951 | ||
|
|
08d8b43f44 | ||
|
|
15c67fe299 | ||
|
|
a10ec1f53c | ||
|
|
1b220abf70 | ||
|
|
607175706b | ||
|
|
f8966a2114 | ||
|
|
4c94ac5dda | ||
|
|
6d1e923b83 | ||
|
|
2c743b7b56 | ||
|
|
6686da1f24 | ||
|
|
6bdeb45f6b | ||
|
|
9f05a9679b | ||
|
|
51a6376991 | ||
|
|
c5056eb4d2 | ||
|
|
79f3759756 | ||
|
|
6c3b748279 | ||
|
|
4293192e74 | ||
|
|
ceaceaf47b | ||
|
|
479a625662 | ||
|
|
095d171a61 | ||
|
|
8c3a7de6d9 | ||
|
|
84e743c4c0 | ||
|
|
51f8d91ddf | ||
|
|
8f1a6ef1b1 | ||
|
|
b3f1783269 | ||
|
|
7e630d0fc5 | ||
|
|
a4533251a1 | ||
|
|
659db109aa | ||
|
|
d3fd27910a | ||
|
|
eae3c1309f | ||
|
|
4a5b67e320 | ||
|
|
86c014b677 | ||
|
|
5a6d6dc7d3 | ||
|
|
294df396f4 | ||
|
|
cc01e8d6a8 | ||
|
|
a3532a41da | ||
|
|
ae35fd1eb8 | ||
|
|
63095f1501 | ||
|
|
bf9e2cd404 | ||
|
|
5b7ef941e4 | ||
|
|
352e721d0c | ||
|
|
220b4794c5 | ||
|
|
811ebde42a | ||
|
|
bfeee618f4 | ||
|
|
db9b16e9f5 | ||
|
|
7861d813b1 | ||
|
|
d7760c4b7a | ||
|
|
a60a721ea5 | ||
|
|
36219e1cb4 | ||
|
|
7fdbc9dd32 | ||
|
|
334be93254 | ||
|
|
c14a6d59e2 | ||
|
|
7a8139b650 | ||
|
|
9d2a443217 | ||
|
|
484b166233 | ||
|
|
530208cb6a | ||
|
|
b534ff8ca3 | ||
|
|
02bd50c434 | ||
|
|
9a84ce7b81 | ||
|
|
6e00be6684 | ||
|
|
91ec43b9bc | ||
|
|
4a4d9a08d5 | ||
|
|
0c32d1eb4e | ||
|
|
f43171f91c | ||
|
|
48593eee0d | ||
|
|
c106a0ac85 | ||
|
|
e1a71fbfaa | ||
|
|
0489d8922e | ||
|
|
d7f1e9d091 | ||
|
|
32bc8bd01d | ||
|
|
242b018ece | ||
|
|
c25447d001 | ||
|
|
d2d718475f | ||
|
|
8e1e42cd50 | ||
|
|
014f9b8b73 | ||
|
|
774c7e275c | ||
|
|
75c43d15e1 | ||
|
|
e288b003d8 | ||
|
|
4aa8518ed6 | ||
|
|
6acbf6395c | ||
|
|
2030feabf7 | ||
|
|
46d1dbcb47 | ||
|
|
2f6297ec17 | ||
|
|
a3400a2f9c | ||
|
|
c345f41416 | ||
|
|
292cdc7621 | ||
|
|
c5ba74e0b4 | ||
|
|
41b24de559 | ||
|
|
4fe7b18161 | ||
|
|
399a979c33 | ||
|
|
03c5482860 | ||
|
|
a116a50604 | ||
|
|
0dfa292c40 | ||
|
|
5914a6c1a4 | ||
|
|
47022d3a04 | ||
|
|
60345f3fe8 | ||
|
|
40bb6566b8 | ||
|
|
db272e3e18 | ||
|
|
35496ead23 | ||
|
|
41403a5d35 | ||
|
|
8acf557137 | ||
|
|
4e62370d18 | ||
|
|
f90ab60354 | ||
|
|
d187aa0ac6 | ||
|
|
96597b3963 |
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.0
|
uses: actions/checkout@v4.1.1
|
||||||
with:
|
with:
|
||||||
ref: dev
|
ref: dev
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v3.8.1
|
uses: actions/setup-node@v4.0.0
|
||||||
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.0
|
uses: actions/checkout@v4.1.1
|
||||||
with:
|
with:
|
||||||
ref: master
|
ref: master
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v3.8.1
|
uses: actions/setup-node@v4.0.0
|
||||||
with:
|
with:
|
||||||
node-version-file: ".nvmrc"
|
node-version-file: ".nvmrc"
|
||||||
cache: yarn
|
cache: yarn
|
||||||
|
|||||||
28
.github/workflows/ci.yaml
vendored
28
.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.0
|
uses: actions/checkout@v4.1.1
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v3.8.1
|
uses: actions/setup-node@v4.0.0
|
||||||
with:
|
with:
|
||||||
node-version-file: ".nvmrc"
|
node-version-file: ".nvmrc"
|
||||||
cache: yarn
|
cache: yarn
|
||||||
@@ -55,9 +55,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.0
|
uses: actions/checkout@v4.1.1
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v3.8.1
|
uses: actions/setup-node@v4.0.0
|
||||||
with:
|
with:
|
||||||
node-version-file: ".nvmrc"
|
node-version-file: ".nvmrc"
|
||||||
cache: yarn
|
cache: yarn
|
||||||
@@ -73,9 +73,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.0
|
uses: actions/checkout@v4.1.1
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v3.8.1
|
uses: actions/setup-node@v4.0.0
|
||||||
with:
|
with:
|
||||||
node-version-file: ".nvmrc"
|
node-version-file: ".nvmrc"
|
||||||
cache: yarn
|
cache: yarn
|
||||||
@@ -85,15 +85,21 @@ jobs:
|
|||||||
run: ./node_modules/.bin/gulp build-app
|
run: ./node_modules/.bin/gulp build-app
|
||||||
env:
|
env:
|
||||||
IS_TEST: "true"
|
IS_TEST: "true"
|
||||||
|
- name: Upload bundle stats
|
||||||
|
uses: actions/upload-artifact@v3.1.3
|
||||||
|
with:
|
||||||
|
name: frontend-bundle-stats
|
||||||
|
path: build/stats/*.json
|
||||||
|
if-no-files-found: error
|
||||||
supervisor:
|
supervisor:
|
||||||
name: Build supervisor
|
name: Build supervisor
|
||||||
needs: [lint, test]
|
needs: [lint, test]
|
||||||
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.0
|
uses: actions/checkout@v4.1.1
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v3.8.1
|
uses: actions/setup-node@v4.0.0
|
||||||
with:
|
with:
|
||||||
node-version-file: ".nvmrc"
|
node-version-file: ".nvmrc"
|
||||||
cache: yarn
|
cache: yarn
|
||||||
@@ -103,3 +109,9 @@ jobs:
|
|||||||
run: ./node_modules/.bin/gulp build-hassio
|
run: ./node_modules/.bin/gulp build-hassio
|
||||||
env:
|
env:
|
||||||
IS_TEST: "true"
|
IS_TEST: "true"
|
||||||
|
- name: Upload bundle stats
|
||||||
|
uses: actions/upload-artifact@v3.1.3
|
||||||
|
with:
|
||||||
|
name: supervisor-bundle-stats
|
||||||
|
path: build/stats/*.json
|
||||||
|
if-no-files-found: error
|
||||||
|
|||||||
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.0
|
uses: actions/checkout@v4.1.1
|
||||||
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.0
|
uses: actions/checkout@v4.1.1
|
||||||
with:
|
with:
|
||||||
ref: dev
|
ref: dev
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v3.8.1
|
uses: actions/setup-node@v4.0.0
|
||||||
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.0
|
uses: actions/checkout@v4.1.1
|
||||||
with:
|
with:
|
||||||
ref: master
|
ref: master
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v3.8.1
|
uses: actions/setup-node@v4.0.0
|
||||||
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.0
|
uses: actions/checkout@v4.1.1
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v3.8.1
|
uses: actions/setup-node@v4.0.0
|
||||||
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.0
|
uses: actions/checkout@v4.1.1
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v3.8.1
|
uses: actions/setup-node@v4.0.0
|
||||||
with:
|
with:
|
||||||
node-version-file: ".nvmrc"
|
node-version-file: ".nvmrc"
|
||||||
cache: yarn
|
cache: yarn
|
||||||
|
|||||||
8
.github/workflows/nightly.yaml
vendored
8
.github/workflows/nightly.yaml
vendored
@@ -20,7 +20,7 @@ jobs:
|
|||||||
contents: write
|
contents: write
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v4.1.0
|
uses: actions/checkout@v4.1.1
|
||||||
|
|
||||||
- name: Set up Python ${{ env.PYTHON_VERSION }}
|
- name: Set up Python ${{ env.PYTHON_VERSION }}
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
@@ -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@v3.8.1
|
uses: actions/setup-node@v4.0.0
|
||||||
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@v3
|
uses: actions/upload-artifact@v3.1.3
|
||||||
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@v3
|
uses: actions/upload-artifact@v3.1.3
|
||||||
with:
|
with:
|
||||||
name: translations
|
name: translations
|
||||||
path: translations.tar.gz
|
path: translations.tar.gz
|
||||||
|
|||||||
25
.github/workflows/relative-ci.yaml
vendored
Normal file
25
.github/workflows/relative-ci.yaml
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
name: RelativeCI
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_run:
|
||||||
|
workflows: [CI]
|
||||||
|
types:
|
||||||
|
- completed
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
upload:
|
||||||
|
name: Upload stats
|
||||||
|
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
bundle: [frontend, supervisor]
|
||||||
|
build: [modern, legacy]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Send bundle stats and build information to RelativeCI
|
||||||
|
uses: relative-ci/agent-action@v2.1.10
|
||||||
|
with:
|
||||||
|
key: ${{ secrets[format('RELATIVE_CI_KEY_{0}_{1}', matrix.bundle, matrix.build)] }}
|
||||||
|
token: ${{ github.token }}
|
||||||
|
artifactName: ${{ format('{0}-bundle-stats', matrix.bundle) }}
|
||||||
|
webpackStatsFile: ${{ format('{0}-{1}.json', matrix.bundle, matrix.build) }}
|
||||||
6
.github/workflows/release.yaml
vendored
6
.github/workflows/release.yaml
vendored
@@ -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.0
|
uses: actions/checkout@v4.1.1
|
||||||
|
|
||||||
- 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@v3.8.1
|
uses: actions/setup-node@v4.0.0
|
||||||
with:
|
with:
|
||||||
node-version-file: ".nvmrc"
|
node-version-file: ".nvmrc"
|
||||||
cache: yarn
|
cache: yarn
|
||||||
@@ -74,7 +74,7 @@ jobs:
|
|||||||
echo "home-assistant-frontend==$version" > ./requirements.txt
|
echo "home-assistant-frontend==$version" > ./requirements.txt
|
||||||
|
|
||||||
- name: Build wheels
|
- name: Build wheels
|
||||||
uses: home-assistant/wheels@2023.09.1
|
uses: home-assistant/wheels@2023.10.5
|
||||||
with:
|
with:
|
||||||
abi: cp311
|
abi: cp311
|
||||||
tag: musllinux_1_2
|
tag: musllinux_1_2
|
||||||
|
|||||||
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.0
|
uses: actions/checkout@v4.1.1
|
||||||
|
|
||||||
- name: Upload Translations
|
- name: Upload Translations
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -47,3 +47,6 @@ src/cast/dev_const.ts
|
|||||||
|
|
||||||
# Home Assistant config
|
# Home Assistant config
|
||||||
/config/
|
/config/
|
||||||
|
|
||||||
|
# Jetbrains
|
||||||
|
/.idea/
|
||||||
|
|||||||
541
.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
vendored
541
.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
vendored
File diff suppressed because one or more lines are too long
9
.yarn/plugins/@yarnpkg/plugin-typescript.cjs
vendored
9
.yarn/plugins/@yarnpkg/plugin-typescript.cjs
vendored
File diff suppressed because one or more lines are too long
874
.yarn/releases/yarn-3.6.3.cjs
vendored
874
.yarn/releases/yarn-3.6.3.cjs
vendored
File diff suppressed because one or more lines are too long
893
.yarn/releases/yarn-4.0.1.cjs
vendored
Executable file
893
.yarn/releases/yarn-4.0.1.cjs
vendored
Executable file
File diff suppressed because one or more lines are too long
12
.yarnrc.yml
12
.yarnrc.yml
@@ -1,11 +1,9 @@
|
|||||||
|
compressionLevel: mixed
|
||||||
|
|
||||||
defaultSemverRangePrefix: ""
|
defaultSemverRangePrefix: ""
|
||||||
|
|
||||||
|
enableGlobalCache: false
|
||||||
|
|
||||||
nodeLinker: node-modules
|
nodeLinker: node-modules
|
||||||
|
|
||||||
plugins:
|
yarnPath: .yarn/releases/yarn-4.0.1.cjs
|
||||||
- path: .yarn/plugins/@yarnpkg/plugin-typescript.cjs
|
|
||||||
spec: "@yarnpkg/plugin-typescript"
|
|
||||||
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
|
|
||||||
spec: "@yarnpkg/plugin-interactive-tools"
|
|
||||||
|
|
||||||
yarnPath: .yarn/releases/yarn-3.6.3.cjs
|
|
||||||
|
|||||||
@@ -12,11 +12,7 @@ module.exports.sourceMapURL = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Files from NPM Packages that should not be imported
|
// Files from NPM Packages that should not be imported
|
||||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
module.exports.ignorePackages = () => [];
|
||||||
module.exports.ignorePackages = ({ latestBuild }) => [
|
|
||||||
// Part of yaml.js and only used for !!js functions that we don't use
|
|
||||||
require.resolve("esprima"),
|
|
||||||
];
|
|
||||||
|
|
||||||
// Files from NPM packages that we should replace with empty file
|
// Files from NPM packages that we should replace with empty file
|
||||||
module.exports.emptyPackages = ({ latestBuild, isHassioBuild }) =>
|
module.exports.emptyPackages = ({ latestBuild, isHassioBuild }) =>
|
||||||
@@ -98,7 +94,7 @@ module.exports.babelOptions = ({ latestBuild, isProdBuild, isTestBuild }) => ({
|
|||||||
"@babel/preset-env",
|
"@babel/preset-env",
|
||||||
{
|
{
|
||||||
useBuiltIns: latestBuild ? false : "entry",
|
useBuiltIns: latestBuild ? false : "entry",
|
||||||
corejs: latestBuild ? false : { version: "3.32", proposals: true },
|
corejs: latestBuild ? false : { version: "3.33", proposals: true },
|
||||||
bugfixes: true,
|
bugfixes: true,
|
||||||
shippedProposals: true,
|
shippedProposals: true,
|
||||||
},
|
},
|
||||||
@@ -149,7 +145,7 @@ module.exports.babelOptions = ({ latestBuild, isProdBuild, isTestBuild }) => ({
|
|||||||
sourceMaps: !isTestBuild,
|
sourceMaps: !isTestBuild,
|
||||||
});
|
});
|
||||||
|
|
||||||
const nameSuffix = (latestBuild) => (latestBuild ? "-latest" : "-es5");
|
const nameSuffix = (latestBuild) => (latestBuild ? "-modern" : "-legacy");
|
||||||
|
|
||||||
const outputPath = (outputRoot, latestBuild) =>
|
const outputPath = (outputRoot, latestBuild) =>
|
||||||
path.resolve(outputRoot, latestBuild ? "frontend_latest" : "frontend_es5");
|
path.resolve(outputRoot, latestBuild ? "frontend_latest" : "frontend_es5");
|
||||||
@@ -183,7 +179,7 @@ const publicPath = (latestBuild, root = "") =>
|
|||||||
module.exports.config = {
|
module.exports.config = {
|
||||||
app({ isProdBuild, latestBuild, isStatsBuild, isTestBuild, isWDS }) {
|
app({ isProdBuild, latestBuild, isStatsBuild, isTestBuild, isWDS }) {
|
||||||
return {
|
return {
|
||||||
name: "app" + nameSuffix(latestBuild),
|
name: "frontend" + nameSuffix(latestBuild),
|
||||||
entry: {
|
entry: {
|
||||||
service_worker: "./src/entrypoints/service_worker.ts",
|
service_worker: "./src/entrypoints/service_worker.ts",
|
||||||
app: "./src/entrypoints/app.ts",
|
app: "./src/entrypoints/app.ts",
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ gulp.task(
|
|||||||
gulp.parallel("gen-icons-json", "build-translations", "build-locale-data"),
|
gulp.parallel("gen-icons-json", "build-translations", "build-locale-data"),
|
||||||
"copy-static-app",
|
"copy-static-app",
|
||||||
env.useRollup() ? "rollup-prod-app" : "webpack-prod-app",
|
env.useRollup() ? "rollup-prod-app" : "webpack-prod-app",
|
||||||
|
gulp.parallel("gen-pages-app-prod", "gen-service-worker-app-prod"),
|
||||||
// Don't compress running tests
|
// Don't compress running tests
|
||||||
...(env.isTestBuild() ? [] : ["compress-app"]),
|
...(env.isTestBuild() ? [] : ["compress-app"])
|
||||||
gulp.parallel("gen-pages-app-prod", "gen-service-worker-app-prod")
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import fs from "fs-extra";
|
|||||||
import gulp from "gulp";
|
import gulp from "gulp";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import paths from "../paths.cjs";
|
import paths from "../paths.cjs";
|
||||||
|
import env from "../env.cjs";
|
||||||
|
|
||||||
const npmPath = (...parts) =>
|
const npmPath = (...parts) =>
|
||||||
path.resolve(paths.polymer_dir, "node_modules", ...parts);
|
path.resolve(paths.polymer_dir, "node_modules", ...parts);
|
||||||
@@ -62,6 +63,9 @@ function copyPolyfills(staticDir) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function copyLoaderJS(staticDir) {
|
function copyLoaderJS(staticDir) {
|
||||||
|
if (!env.useRollup()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const staticPath = genStaticPath(staticDir);
|
const staticPath = genStaticPath(staticDir);
|
||||||
copyFileDir(npmPath("systemjs/dist/s.min.js"), staticPath("js"));
|
copyFileDir(npmPath("systemjs/dist/s.min.js"), staticPath("js"));
|
||||||
copyFileDir(npmPath("systemjs/dist/s.min.js.map"), staticPath("js"));
|
copyFileDir(npmPath("systemjs/dist/s.min.js.map"), staticPath("js"));
|
||||||
|
|||||||
@@ -1,51 +1,54 @@
|
|||||||
import { deleteSync } from "del";
|
import { deleteSync } from "del";
|
||||||
import { mkdir, readFile, writeFile } from "fs/promises";
|
import { mkdir, readFile, writeFile } from "fs/promises";
|
||||||
import gulp from "gulp";
|
import gulp from "gulp";
|
||||||
import path from "path";
|
import { join, resolve } from "node:path";
|
||||||
import paths from "../paths.cjs";
|
import paths from "../paths.cjs";
|
||||||
|
|
||||||
const outDir = path.join(paths.build_dir, "locale-data");
|
const formatjsDir = join(paths.polymer_dir, "node_modules", "@formatjs");
|
||||||
|
const outDir = join(paths.build_dir, "locale-data");
|
||||||
|
|
||||||
const INTL_PACKAGES = {
|
const INTL_POLYFILLS = {
|
||||||
"intl-relativetimeformat": "RelativeTimeFormat",
|
|
||||||
"intl-datetimeformat": "DateTimeFormat",
|
"intl-datetimeformat": "DateTimeFormat",
|
||||||
"intl-numberformat": "NumberFormat",
|
|
||||||
"intl-displaynames": "DisplayNames",
|
"intl-displaynames": "DisplayNames",
|
||||||
"intl-listformat": "ListFormat",
|
"intl-listformat": "ListFormat",
|
||||||
|
"intl-numberformat": "NumberFormat",
|
||||||
|
"intl-relativetimeformat": "RelativeTimeFormat",
|
||||||
};
|
};
|
||||||
|
|
||||||
const convertToJSON = async (pkg, lang) => {
|
const convertToJSON = async (
|
||||||
|
pkg,
|
||||||
|
lang,
|
||||||
|
subDir = "locale-data",
|
||||||
|
addFunc = "__addLocaleData",
|
||||||
|
skipMissing = true
|
||||||
|
) => {
|
||||||
let localeData;
|
let localeData;
|
||||||
try {
|
try {
|
||||||
localeData = await readFile(
|
localeData = await readFile(
|
||||||
path.resolve(
|
join(formatjsDir, pkg, subDir, `${lang}.js`),
|
||||||
paths.polymer_dir,
|
|
||||||
`node_modules/@formatjs/${pkg}/locale-data/${lang}.js`
|
|
||||||
),
|
|
||||||
"utf-8"
|
"utf-8"
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Ignore if language is missing (i.e. not supported by @formatjs)
|
// Ignore if language is missing (i.e. not supported by @formatjs)
|
||||||
if (e.code === "ENOENT") {
|
if (e.code === "ENOENT" && skipMissing) {
|
||||||
|
console.warn(`Skipped missing data for language ${lang} from ${pkg}`);
|
||||||
return;
|
return;
|
||||||
} else {
|
}
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Convert to JSON
|
// Convert to JSON
|
||||||
const className = INTL_PACKAGES[pkg];
|
const obj = INTL_POLYFILLS[pkg];
|
||||||
localeData = localeData
|
const dataRegex = new RegExp(
|
||||||
.replace(
|
`Intl\\.${obj}\\.${addFunc}\\((?<data>.*)\\)`,
|
||||||
new RegExp(
|
"s"
|
||||||
`\\/\\*\\s*@generated\\s*\\*\\/\\s*\\/\\/\\s*prettier-ignore\\s*if\\s*\\(Intl\\.${className}\\s*&&\\s*typeof\\s*Intl\\.${className}\\.__addLocaleData\\s*===\\s*'function'\\)\\s*{\\s*Intl\\.${className}\\.__addLocaleData\\(`,
|
);
|
||||||
"im"
|
localeData = localeData.match(dataRegex)?.groups?.data;
|
||||||
),
|
if (!localeData) {
|
||||||
""
|
throw Error(`Failed to extract data for language ${lang} from ${pkg}`);
|
||||||
)
|
}
|
||||||
.replace(/\)\s*}/im, "");
|
|
||||||
// Parse to validate JSON, then stringify to minify
|
// Parse to validate JSON, then stringify to minify
|
||||||
localeData = JSON.stringify(JSON.parse(localeData));
|
localeData = JSON.stringify(JSON.parse(localeData));
|
||||||
await writeFile(path.join(outDir, `${pkg}/${lang}.json`), localeData);
|
await writeFile(join(outDir, `${pkg}/${lang}.json`), localeData);
|
||||||
};
|
};
|
||||||
|
|
||||||
gulp.task("clean-locale-data", async () => deleteSync([outDir]));
|
gulp.task("clean-locale-data", async () => deleteSync([outDir]));
|
||||||
@@ -53,17 +56,27 @@ gulp.task("clean-locale-data", async () => deleteSync([outDir]));
|
|||||||
gulp.task("create-locale-data", async () => {
|
gulp.task("create-locale-data", async () => {
|
||||||
const translationMeta = JSON.parse(
|
const translationMeta = JSON.parse(
|
||||||
await readFile(
|
await readFile(
|
||||||
path.resolve(paths.translations_src, "translationMetadata.json"),
|
resolve(paths.translations_src, "translationMetadata.json"),
|
||||||
"utf-8"
|
"utf-8"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
const conversions = [];
|
const conversions = [];
|
||||||
for (const pkg of Object.keys(INTL_PACKAGES)) {
|
for (const pkg of Object.keys(INTL_POLYFILLS)) {
|
||||||
await mkdir(path.join(outDir, pkg), { recursive: true });
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
await mkdir(join(outDir, pkg), { recursive: true });
|
||||||
for (const lang of Object.keys(translationMeta)) {
|
for (const lang of Object.keys(translationMeta)) {
|
||||||
conversions.push(convertToJSON(pkg, lang));
|
conversions.push(convertToJSON(pkg, lang));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
conversions.push(
|
||||||
|
convertToJSON(
|
||||||
|
"intl-datetimeformat",
|
||||||
|
"add-all-tz",
|
||||||
|
".",
|
||||||
|
"__addTZData",
|
||||||
|
false
|
||||||
|
)
|
||||||
|
);
|
||||||
await Promise.all(conversions);
|
await Promise.all(conversions);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,7 @@
|
|||||||
import { createHash } from "crypto";
|
import { createHash } from "crypto";
|
||||||
import { deleteSync } from "del";
|
import { deleteSync } from "del";
|
||||||
import {
|
import { mkdirSync, readdirSync, readFileSync, renameSync } from "fs";
|
||||||
mkdirSync,
|
import { writeFile } from "node:fs/promises";
|
||||||
readdirSync,
|
|
||||||
readFileSync,
|
|
||||||
renameSync,
|
|
||||||
writeFile,
|
|
||||||
} from "fs";
|
|
||||||
import gulp from "gulp";
|
import gulp from "gulp";
|
||||||
import flatmap from "gulp-flatmap";
|
import flatmap from "gulp-flatmap";
|
||||||
import transform from "gulp-json-transform";
|
import transform from "gulp-json-transform";
|
||||||
@@ -136,27 +131,23 @@ gulp.task("ensure-translations-build-dir", async () => {
|
|||||||
mkdirSync(workDir, { recursive: true });
|
mkdirSync(workDir, { recursive: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task("create-test-metadata", (cb) => {
|
gulp.task("create-test-metadata", () =>
|
||||||
writeFile(
|
env.isProdBuild()
|
||||||
|
? Promise.resolve()
|
||||||
|
: writeFile(
|
||||||
workDir + "/testMetadata.json",
|
workDir + "/testMetadata.json",
|
||||||
JSON.stringify({
|
JSON.stringify({ test: { nativeName: "Test" } })
|
||||||
test: {
|
)
|
||||||
nativeName: "Test",
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
cb
|
|
||||||
);
|
);
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task(
|
gulp.task("create-test-translation", () =>
|
||||||
"create-test-translation",
|
env.isProdBuild()
|
||||||
gulp.series("create-test-metadata", () =>
|
? Promise.resolve()
|
||||||
gulp
|
: gulp
|
||||||
.src(path.join(paths.translations_src, "en.json"))
|
.src(path.join(paths.translations_src, "en.json"))
|
||||||
.pipe(transform((data, _file) => recursiveEmpty(data)))
|
.pipe(transform((data, _file) => recursiveEmpty(data)))
|
||||||
.pipe(rename("test.json"))
|
.pipe(rename("test.json"))
|
||||||
.pipe(gulp.dest(workDir))
|
.pipe(gulp.dest(workDir))
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -188,16 +179,11 @@ gulp.task("build-master-translation", () => {
|
|||||||
|
|
||||||
gulp.task("build-merged-translations", () =>
|
gulp.task("build-merged-translations", () =>
|
||||||
gulp
|
gulp
|
||||||
.src(
|
.src([
|
||||||
[
|
|
||||||
inFrontendDir + "/*.json",
|
inFrontendDir + "/*.json",
|
||||||
"!" + inFrontendDir + "/en.json",
|
"!" + inFrontendDir + "/en.json",
|
||||||
workDir + "/test.json",
|
...(env.isProdBuild() ? [] : [workDir + "/test.json"]),
|
||||||
],
|
])
|
||||||
{
|
|
||||||
allowEmpty: true,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.pipe(transform((data, file) => lokaliseTransform(data, data, file)))
|
.pipe(transform((data, file) => lokaliseTransform(data, data, file)))
|
||||||
.pipe(
|
.pipe(
|
||||||
flatmap((stream, file) => {
|
flatmap((stream, file) => {
|
||||||
@@ -377,14 +363,11 @@ gulp.task("build-translation-flatten-supervisor", () =>
|
|||||||
|
|
||||||
gulp.task("build-translation-write-metadata", () =>
|
gulp.task("build-translation-write-metadata", () =>
|
||||||
gulp
|
gulp
|
||||||
.src(
|
.src([
|
||||||
[
|
|
||||||
path.join(paths.translations_src, "translationMetadata.json"),
|
path.join(paths.translations_src, "translationMetadata.json"),
|
||||||
workDir + "/testMetadata.json",
|
...(env.isProdBuild() ? [] : [workDir + "/testMetadata.json"]),
|
||||||
workDir + "/translationFingerprints.json",
|
workDir + "/translationFingerprints.json",
|
||||||
],
|
])
|
||||||
{ allowEmpty: true }
|
|
||||||
)
|
|
||||||
.pipe(merge({}))
|
.pipe(merge({}))
|
||||||
.pipe(
|
.pipe(
|
||||||
transform((data) => {
|
transform((data) => {
|
||||||
@@ -415,7 +398,7 @@ gulp.task("build-translation-write-metadata", () =>
|
|||||||
gulp.task(
|
gulp.task(
|
||||||
"create-translations",
|
"create-translations",
|
||||||
gulp.series(
|
gulp.series(
|
||||||
...(env.isProdBuild() ? [] : ["create-test-translation"]),
|
gulp.parallel("create-test-metadata", "create-test-translation"),
|
||||||
"build-master-translation",
|
"build-master-translation",
|
||||||
"build-merged-translations",
|
"build-merged-translations",
|
||||||
gulp.parallel(...splitTasks),
|
gulp.parallel(...splitTasks),
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
const { existsSync } = require("fs");
|
const { existsSync } = require("fs");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const webpack = require("webpack");
|
const webpack = require("webpack");
|
||||||
|
const { StatsWriterPlugin } = require("webpack-stats-plugin");
|
||||||
|
const filterStats = require("@bundle-stats/plugin-webpack-filter").default;
|
||||||
const TerserPlugin = require("terser-webpack-plugin");
|
const TerserPlugin = require("terser-webpack-plugin");
|
||||||
const { WebpackManifestPlugin } = require("webpack-manifest-plugin");
|
const { WebpackManifestPlugin } = require("webpack-manifest-plugin");
|
||||||
const log = require("fancy-log");
|
const log = require("fancy-log");
|
||||||
@@ -152,6 +154,15 @@ const createWebpackConfig = ({
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
!isProdBuild && new LogStartCompilePlugin(),
|
!isProdBuild && new LogStartCompilePlugin(),
|
||||||
|
isProdBuild &&
|
||||||
|
new StatsWriterPlugin({
|
||||||
|
filename: path.relative(
|
||||||
|
outputPath,
|
||||||
|
path.join(paths.build_dir, "stats", `${name}.json`)
|
||||||
|
),
|
||||||
|
stats: { assets: true, chunks: true, modules: true },
|
||||||
|
transform: (stats) => JSON.stringify(filterStats(stats)),
|
||||||
|
}),
|
||||||
].filter(Boolean),
|
].filter(Boolean),
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: [".ts", ".js", ".json"],
|
extensions: [".ts", ".js", ".json"],
|
||||||
@@ -171,6 +182,8 @@ const createWebpackConfig = ({
|
|||||||
"@lit-labs/virtualizer/layouts/grid.js",
|
"@lit-labs/virtualizer/layouts/grid.js",
|
||||||
"@lit-labs/virtualizer/polyfills/resize-observer-polyfill/ResizeObserver":
|
"@lit-labs/virtualizer/polyfills/resize-observer-polyfill/ResizeObserver":
|
||||||
"@lit-labs/virtualizer/polyfills/resize-observer-polyfill/ResizeObserver.js",
|
"@lit-labs/virtualizer/polyfills/resize-observer-polyfill/ResizeObserver.js",
|
||||||
|
"@lit-labs/observers/resize-controller":
|
||||||
|
"@lit-labs/observers/resize-controller.js",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
@@ -183,6 +196,7 @@ const createWebpackConfig = ({
|
|||||||
isProdBuild && !isStatsBuild ? "[id]-[contenthash].js" : "[name].js",
|
isProdBuild && !isStatsBuild ? "[id]-[contenthash].js" : "[name].js",
|
||||||
assetModuleFilename:
|
assetModuleFilename:
|
||||||
isProdBuild && !isStatsBuild ? "[id]-[contenthash][ext]" : "[id][ext]",
|
isProdBuild && !isStatsBuild ? "[id]-[contenthash][ext]" : "[id][ext]",
|
||||||
|
crossOriginLoading: "use-credentials",
|
||||||
hashFunction: "xxhash64",
|
hashFunction: "xxhash64",
|
||||||
hashDigest: "base64url",
|
hashDigest: "base64url",
|
||||||
hashDigestLength: 11, // full length of 64 bit base64url
|
hashDigestLength: 11, // full length of 64 bit base64url
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import "../../../src/resources/safari-14-attachshadow-patch";
|
import "../../../src/resources/safari-14-attachshadow-patch";
|
||||||
import "../../../src/resources/ha-style";
|
|
||||||
import "../../../src/resources/roboto";
|
|
||||||
import "./layout/hc-connect";
|
import "./layout/hc-connect";
|
||||||
|
|
||||||
|
import("../../../src/resources/ha-style");
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { mdiCast, mdiCastConnected } from "@mdi/js";
|
|||||||
import "@polymer/paper-item/paper-icon-item";
|
import "@polymer/paper-item/paper-icon-item";
|
||||||
import "@polymer/paper-listbox/paper-listbox";
|
import "@polymer/paper-listbox/paper-listbox";
|
||||||
import { Auth, Connection } from "home-assistant-js-websocket";
|
import { Auth, Connection } from "home-assistant-js-websocket";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { CSSResultGroup, LitElement, TemplateResult, css, html } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { CastManager } from "../../../../src/cast/cast_manager";
|
import { CastManager } from "../../../../src/cast/cast_manager";
|
||||||
import {
|
import {
|
||||||
@@ -22,8 +22,9 @@ import "../../../../src/components/ha-svg-icon";
|
|||||||
import {
|
import {
|
||||||
getLegacyLovelaceCollection,
|
getLegacyLovelaceCollection,
|
||||||
getLovelaceCollection,
|
getLovelaceCollection,
|
||||||
LovelaceConfig,
|
|
||||||
} from "../../../../src/data/lovelace";
|
} from "../../../../src/data/lovelace";
|
||||||
|
import { isStrategyDashboard } from "../../../../src/data/lovelace/config/types";
|
||||||
|
import { LovelaceViewConfig } from "../../../../src/data/lovelace/config/view";
|
||||||
import "../../../../src/layouts/hass-loading-screen";
|
import "../../../../src/layouts/hass-loading-screen";
|
||||||
import { generateDefaultViewConfig } from "../../../../src/panels/lovelace/common/generate-lovelace-config";
|
import { generateDefaultViewConfig } from "../../../../src/panels/lovelace/common/generate-lovelace-config";
|
||||||
import "./hc-layout";
|
import "./hc-layout";
|
||||||
@@ -38,10 +39,10 @@ class HcCast extends LitElement {
|
|||||||
|
|
||||||
@state() private askWrite = false;
|
@state() private askWrite = false;
|
||||||
|
|
||||||
@state() private lovelaceConfig?: LovelaceConfig | null;
|
@state() private lovelaceViews?: LovelaceViewConfig[] | null;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (this.lovelaceConfig === undefined) {
|
if (this.lovelaceViews === undefined) {
|
||||||
return html`<hass-loading-screen no-toolbar></hass-loading-screen>`;
|
return html`<hass-loading-screen no-toolbar></hass-loading-screen>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,9 +87,10 @@ class HcCast extends LitElement {
|
|||||||
attr-for-selected="data-path"
|
attr-for-selected="data-path"
|
||||||
.selected=${this.castManager.status.lovelacePath || ""}
|
.selected=${this.castManager.status.lovelacePath || ""}
|
||||||
>
|
>
|
||||||
${(this.lovelaceConfig
|
${(
|
||||||
? this.lovelaceConfig.views
|
this.lovelaceViews ?? [
|
||||||
: [generateDefaultViewConfig({}, {}, {}, {}, () => "")]
|
generateDefaultViewConfig({}, {}, {}, {}, () => ""),
|
||||||
|
]
|
||||||
).map(
|
).map(
|
||||||
(view, idx) => html`
|
(view, idx) => html`
|
||||||
<paper-icon-item
|
<paper-icon-item
|
||||||
@@ -136,11 +138,15 @@ class HcCast extends LitElement {
|
|||||||
llColl.refresh().then(
|
llColl.refresh().then(
|
||||||
() => {
|
() => {
|
||||||
llColl.subscribe((config) => {
|
llColl.subscribe((config) => {
|
||||||
this.lovelaceConfig = config;
|
if (isStrategyDashboard(config)) {
|
||||||
|
this.lovelaceViews = null;
|
||||||
|
} else {
|
||||||
|
this.lovelaceViews = config.views;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
async () => {
|
async () => {
|
||||||
this.lovelaceConfig = null;
|
this.lovelaceViews = null;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -159,9 +165,7 @@ class HcCast extends LitElement {
|
|||||||
toggleAttribute(
|
toggleAttribute(
|
||||||
this,
|
this,
|
||||||
"hide-icons",
|
"hide-icons",
|
||||||
this.lovelaceConfig
|
this.lovelaceViews ? !this.lovelaceViews.some((view) => view.icon) : true
|
||||||
? !this.lovelaceConfig.views.some((view) => view.icon)
|
|
||||||
: true
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import {
|
import { LovelaceCardConfig } from "../../../../src/data/lovelace/config/card";
|
||||||
LovelaceCardConfig,
|
import { LovelaceConfig } from "../../../../src/data/lovelace/config/types";
|
||||||
LovelaceConfig,
|
|
||||||
} from "../../../../src/data/lovelace";
|
|
||||||
import { castContext } from "../cast_context";
|
import { castContext } from "../cast_context";
|
||||||
|
|
||||||
export const castDemoLovelace: () => LovelaceConfig = () => {
|
export const castDemoLovelace: () => LovelaceConfig = () => {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { html, nothing } from "lit";
|
import { html, nothing } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { mockHistory } from "../../../../demo/src/stubs/history";
|
import { mockHistory } from "../../../../demo/src/stubs/history";
|
||||||
import { LovelaceConfig } from "../../../../src/data/lovelace";
|
import { LovelaceConfig } from "../../../../src/data/lovelace/config/types";
|
||||||
import {
|
import {
|
||||||
MockHomeAssistant,
|
MockHomeAssistant,
|
||||||
provideHass,
|
provideHass,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property, query } from "lit/decorators";
|
import { customElement, property, query } from "lit/decorators";
|
||||||
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
import { fireEvent } from "../../../../src/common/dom/fire_event";
|
||||||
import { LovelaceConfig } from "../../../../src/data/lovelace";
|
import { LovelaceConfig } from "../../../../src/data/lovelace/config/types";
|
||||||
import { Lovelace } from "../../../../src/panels/lovelace/types";
|
import { Lovelace } from "../../../../src/panels/lovelace/types";
|
||||||
import "../../../../src/panels/lovelace/views/hui-view";
|
import "../../../../src/panels/lovelace/views/hui-view";
|
||||||
import { HomeAssistant } from "../../../../src/types";
|
import { HomeAssistant } from "../../../../src/types";
|
||||||
@@ -14,7 +14,8 @@ import "./hc-launch-screen";
|
|||||||
class HcLovelace extends LitElement {
|
class HcLovelace extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ attribute: false }) public lovelaceConfig!: LovelaceConfig;
|
@property({ attribute: false })
|
||||||
|
public lovelaceConfig!: LovelaceConfig;
|
||||||
|
|
||||||
@property() public viewPath?: string | number;
|
@property() public viewPath?: string | number;
|
||||||
|
|
||||||
|
|||||||
@@ -21,18 +21,26 @@ import {
|
|||||||
import { atLeastVersion } from "../../../../src/common/config/version";
|
import { atLeastVersion } from "../../../../src/common/config/version";
|
||||||
import { isNavigationClick } from "../../../../src/common/dom/is-navigation-click";
|
import { isNavigationClick } from "../../../../src/common/dom/is-navigation-click";
|
||||||
import {
|
import {
|
||||||
fetchResources,
|
|
||||||
getLegacyLovelaceCollection,
|
getLegacyLovelaceCollection,
|
||||||
getLovelaceCollection,
|
getLovelaceCollection,
|
||||||
|
} from "../../../../src/data/lovelace";
|
||||||
|
import {
|
||||||
|
isStrategyDashboard,
|
||||||
LegacyLovelaceConfig,
|
LegacyLovelaceConfig,
|
||||||
LovelaceConfig,
|
LovelaceConfig,
|
||||||
} from "../../../../src/data/lovelace";
|
LovelaceDashboardStrategyConfig,
|
||||||
|
} from "../../../../src/data/lovelace/config/types";
|
||||||
|
import { fetchResources } from "../../../../src/data/lovelace/resource";
|
||||||
import { loadLovelaceResources } from "../../../../src/panels/lovelace/common/load-resources";
|
import { loadLovelaceResources } from "../../../../src/panels/lovelace/common/load-resources";
|
||||||
import { HassElement } from "../../../../src/state/hass-element";
|
import { HassElement } from "../../../../src/state/hass-element";
|
||||||
import { castContext } from "../cast_context";
|
import { castContext } from "../cast_context";
|
||||||
import "./hc-launch-screen";
|
import "./hc-launch-screen";
|
||||||
|
|
||||||
const DEFAULT_STRATEGY = "original-states";
|
const DEFAULT_CONFIG: LovelaceDashboardStrategyConfig = {
|
||||||
|
strategy: {
|
||||||
|
type: "original-states",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
let resourcesLoaded = false;
|
let resourcesLoaded = false;
|
||||||
@customElement("hc-main")
|
@customElement("hc-main")
|
||||||
@@ -93,14 +101,16 @@ export class HcMain extends HassElement {
|
|||||||
.lovelaceConfig=${this._lovelaceConfig}
|
.lovelaceConfig=${this._lovelaceConfig}
|
||||||
.viewPath=${this._lovelacePath}
|
.viewPath=${this._lovelacePath}
|
||||||
.urlPath=${this._urlPath}
|
.urlPath=${this._urlPath}
|
||||||
@config-refresh=${this._generateLovelaceConfig}
|
@config-refresh=${this._generateDefaultLovelaceConfig}
|
||||||
></hc-lovelace>
|
></hc-lovelace>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected firstUpdated(changedProps) {
|
protected firstUpdated(changedProps) {
|
||||||
super.firstUpdated(changedProps);
|
super.firstUpdated(changedProps);
|
||||||
import("../second-load");
|
import("./hc-lovelace");
|
||||||
|
import("../../../../src/resources/ha-style");
|
||||||
|
|
||||||
window.addEventListener("location-changed", () => {
|
window.addEventListener("location-changed", () => {
|
||||||
const panelPath = `/${this._urlPath || "lovelace"}/`;
|
const panelPath = `/${this._urlPath || "lovelace"}/`;
|
||||||
if (location.pathname.startsWith(panelPath)) {
|
if (location.pathname.startsWith(panelPath)) {
|
||||||
@@ -260,7 +270,6 @@ export class HcMain extends HassElement {
|
|||||||
{
|
{
|
||||||
strategy: {
|
strategy: {
|
||||||
type: "energy",
|
type: "energy",
|
||||||
show_date_selection: true,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -283,9 +292,20 @@ export class HcMain extends HassElement {
|
|||||||
// configuration.
|
// configuration.
|
||||||
try {
|
try {
|
||||||
await llColl.refresh();
|
await llColl.refresh();
|
||||||
this._unsubLovelace = llColl.subscribe((lovelaceConfig) =>
|
this._unsubLovelace = llColl.subscribe(async (rawConfig) => {
|
||||||
this._handleNewLovelaceConfig(lovelaceConfig)
|
if (isStrategyDashboard(rawConfig)) {
|
||||||
|
const { generateLovelaceDashboardStrategy } = await import(
|
||||||
|
"../../../../src/panels/lovelace/strategies/get-strategy"
|
||||||
);
|
);
|
||||||
|
const config = await generateLovelaceDashboardStrategy(
|
||||||
|
rawConfig.strategy,
|
||||||
|
this.hass!
|
||||||
|
);
|
||||||
|
this._handleNewLovelaceConfig(config);
|
||||||
|
} else {
|
||||||
|
this._handleNewLovelaceConfig(rawConfig);
|
||||||
|
}
|
||||||
|
});
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
if (
|
if (
|
||||||
atLeastVersion(this.hass.connection.haVersion, 0, 107) &&
|
atLeastVersion(this.hass.connection.haVersion, 0, 107) &&
|
||||||
@@ -299,7 +319,7 @@ export class HcMain extends HassElement {
|
|||||||
}
|
}
|
||||||
// Generate a Lovelace config.
|
// Generate a Lovelace config.
|
||||||
this._unsubLovelace = () => undefined;
|
this._unsubLovelace = () => undefined;
|
||||||
await this._generateLovelaceConfig();
|
await this._generateDefaultLovelaceConfig();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!resourcesLoaded) {
|
if (!resourcesLoaded) {
|
||||||
@@ -308,24 +328,21 @@ export class HcMain extends HassElement {
|
|||||||
? await fetchResources(this.hass!.connection)
|
? await fetchResources(this.hass!.connection)
|
||||||
: (this._lovelaceConfig as LegacyLovelaceConfig).resources;
|
: (this._lovelaceConfig as LegacyLovelaceConfig).resources;
|
||||||
if (resources) {
|
if (resources) {
|
||||||
loadLovelaceResources(resources, this.hass!.auth.data.hassUrl);
|
loadLovelaceResources(resources, this.hass!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._sendStatus();
|
this._sendStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _generateLovelaceConfig() {
|
private async _generateDefaultLovelaceConfig() {
|
||||||
const { generateLovelaceDashboardStrategy } = await import(
|
const { generateLovelaceDashboardStrategy } = await import(
|
||||||
"../../../../src/panels/lovelace/strategies/get-strategy"
|
"../../../../src/panels/lovelace/strategies/get-strategy"
|
||||||
);
|
);
|
||||||
this._handleNewLovelaceConfig(
|
this._handleNewLovelaceConfig(
|
||||||
await generateLovelaceDashboardStrategy(
|
await generateLovelaceDashboardStrategy(
|
||||||
{
|
DEFAULT_CONFIG.strategy,
|
||||||
type: DEFAULT_STRATEGY,
|
this.hass!
|
||||||
},
|
|
||||||
this.hass!,
|
|
||||||
{ narrow: false }
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
import "../../../src/resources/ha-style";
|
|
||||||
import "../../../src/resources/roboto";
|
|
||||||
import "./layout/hc-lovelace";
|
|
||||||
@@ -3,6 +3,15 @@ import { DemoConfig } from "../types";
|
|||||||
|
|
||||||
export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
||||||
convertEntities({
|
convertEntities({
|
||||||
|
"todo.shopping_list": {
|
||||||
|
entity_id: "todo.shopping_list",
|
||||||
|
state: "2",
|
||||||
|
attributes: {
|
||||||
|
supported_features: 15,
|
||||||
|
friendly_name: "Shopping List",
|
||||||
|
icon: "mdi:cart",
|
||||||
|
},
|
||||||
|
},
|
||||||
"zone.home": {
|
"zone.home": {
|
||||||
entity_id: "zone.home",
|
entity_id: "zone.home",
|
||||||
state: "zoning",
|
state: "zoning",
|
||||||
|
|||||||
@@ -3,6 +3,15 @@ import { DemoConfig } from "../types";
|
|||||||
|
|
||||||
export const demoEntitiesJimpower: DemoConfig["entities"] = () =>
|
export const demoEntitiesJimpower: DemoConfig["entities"] = () =>
|
||||||
convertEntities({
|
convertEntities({
|
||||||
|
"todo.shopping_list": {
|
||||||
|
entity_id: "todo.shopping_list",
|
||||||
|
state: "2",
|
||||||
|
attributes: {
|
||||||
|
supported_features: 15,
|
||||||
|
friendly_name: "Shopping List",
|
||||||
|
icon: "mdi:cart",
|
||||||
|
},
|
||||||
|
},
|
||||||
"zone.powertec": {
|
"zone.powertec": {
|
||||||
entity_id: "zone.powertec",
|
entity_id: "zone.powertec",
|
||||||
state: "zoning",
|
state: "zoning",
|
||||||
|
|||||||
@@ -4,16 +4,11 @@ export const demoThemeJimpower = () => ({
|
|||||||
"primary-color": "#5294E2",
|
"primary-color": "#5294E2",
|
||||||
"label-badge-red": "var(--accent-color)",
|
"label-badge-red": "var(--accent-color)",
|
||||||
"paper-tabs-selection-bar-color": "green",
|
"paper-tabs-selection-bar-color": "green",
|
||||||
"paper-slider-knob-color": "var(--accent-color)",
|
|
||||||
"light-primary-color": "var(--accent-color)",
|
"light-primary-color": "var(--accent-color)",
|
||||||
"primary-background-color": "#383C45",
|
"primary-background-color": "#383C45",
|
||||||
"primary-text-color": "#FFFFFF",
|
"primary-text-color": "#FFFFFF",
|
||||||
"paper-item-selected_-_background-color": "#434954",
|
"paper-item-selected_-_background-color": "#434954",
|
||||||
"paper-slider-active-color": "var(--accent-color)",
|
|
||||||
"secondary-background-color": "#383C45",
|
"secondary-background-color": "#383C45",
|
||||||
"paper-slider-container-color":
|
|
||||||
"linear-gradient(var(--primary-background-color), var(--secondary-background-color)) no-repeat",
|
|
||||||
"paper-slider-disabled-active-color": "var(--disabled-text-color)",
|
|
||||||
"disabled-text-color": "#7F848E",
|
"disabled-text-color": "#7F848E",
|
||||||
"paper-item-icon_-_color": "green",
|
"paper-item-icon_-_color": "green",
|
||||||
"paper-grey-200": "#414A59",
|
"paper-grey-200": "#414A59",
|
||||||
@@ -32,14 +27,10 @@ export const demoThemeJimpower = () => ({
|
|||||||
"switch-unchecked-button-color": "var(--disabled-text-color)",
|
"switch-unchecked-button-color": "var(--disabled-text-color)",
|
||||||
"label-badge-border-color": "green",
|
"label-badge-border-color": "green",
|
||||||
"paper-listbox-color": "var(--primary-color)",
|
"paper-listbox-color": "var(--primary-color)",
|
||||||
"paper-slider-disabled-secondary-color": "var(--disabled-text-color)",
|
|
||||||
"card-background-color": "#434954",
|
"card-background-color": "#434954",
|
||||||
"label-badge-text-color": "var(--primary-text-color)",
|
"label-badge-text-color": "var(--primary-text-color)",
|
||||||
"paper-slider-knob-start-color": "var(--accent-color)",
|
|
||||||
"switch-unchecked-track-color": "var(--disabled-text-color)",
|
"switch-unchecked-track-color": "var(--disabled-text-color)",
|
||||||
"dark-primary-color": "var(--accent-color)",
|
"dark-primary-color": "var(--accent-color)",
|
||||||
"paper-slider-secondary-color": "var(--secondary-background-color)",
|
|
||||||
"paper-slider-pin-color": "var(--accent-color)",
|
|
||||||
"paper-item-icon-active-color": "#F9C536",
|
"paper-item-icon-active-color": "#F9C536",
|
||||||
"accent-color": "#E45E65",
|
"accent-color": "#E45E65",
|
||||||
"table-row-alternative-background-color": "#3E424B",
|
"table-row-alternative-background-color": "#3E424B",
|
||||||
|
|||||||
@@ -3,6 +3,15 @@ import { DemoConfig } from "../types";
|
|||||||
|
|
||||||
export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
|
export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
|
||||||
convertEntities({
|
convertEntities({
|
||||||
|
"todo.shopping_list": {
|
||||||
|
entity_id: "todo.shopping_list",
|
||||||
|
state: "2",
|
||||||
|
attributes: {
|
||||||
|
supported_features: 15,
|
||||||
|
friendly_name: "Shopping List",
|
||||||
|
icon: "mdi:cart",
|
||||||
|
},
|
||||||
|
},
|
||||||
"zone.anna": {
|
"zone.anna": {
|
||||||
entity_id: "zone.anna",
|
entity_id: "zone.anna",
|
||||||
state: "zoning",
|
state: "zoning",
|
||||||
|
|||||||
@@ -5,17 +5,12 @@ export const demoThemeKernehed = () => ({
|
|||||||
"primary-color": "#2980b9",
|
"primary-color": "#2980b9",
|
||||||
"label-badge-red": "var(--accent-color)",
|
"label-badge-red": "var(--accent-color)",
|
||||||
"paper-tabs-selection-bar-color": "green",
|
"paper-tabs-selection-bar-color": "green",
|
||||||
"paper-slider-knob-color": "var(--accent-color)",
|
|
||||||
"primary-text-color": "#FFFFFF",
|
"primary-text-color": "#FFFFFF",
|
||||||
"light-primary-color": "var(--accent-color)",
|
"light-primary-color": "var(--accent-color)",
|
||||||
"primary-background-color": "#222222",
|
"primary-background-color": "#222222",
|
||||||
"sidebar-icon-color": "#777777",
|
"sidebar-icon-color": "#777777",
|
||||||
"paper-item-selected_-_background-color": "#292929",
|
"paper-item-selected_-_background-color": "#292929",
|
||||||
"paper-slider-active-color": "var(--accent-color)",
|
|
||||||
"secondary-background-color": "#222222",
|
"secondary-background-color": "#222222",
|
||||||
"paper-slider-container-color":
|
|
||||||
"linear-gradient(var(--primary-background-color), var(--secondary-background-color)) no-repeat",
|
|
||||||
"paper-slider-disabled-active-color": "var(--disabled-text-color)",
|
|
||||||
"disabled-text-color": "#777777",
|
"disabled-text-color": "#777777",
|
||||||
"paper-item-icon_-_color": "green",
|
"paper-item-icon_-_color": "green",
|
||||||
"paper-grey-200": "#222222",
|
"paper-grey-200": "#222222",
|
||||||
@@ -33,14 +28,10 @@ export const demoThemeKernehed = () => ({
|
|||||||
"switch-unchecked-button-color": "var(--disabled-text-color)",
|
"switch-unchecked-button-color": "var(--disabled-text-color)",
|
||||||
"label-badge-border-color": "green",
|
"label-badge-border-color": "green",
|
||||||
"paper-listbox-color": "#777777",
|
"paper-listbox-color": "#777777",
|
||||||
"paper-slider-disabled-secondary-color": "var(--disabled-text-color)",
|
|
||||||
"card-background-color": "#292929",
|
"card-background-color": "#292929",
|
||||||
"label-badge-text-color": "var(--primary-text-color)",
|
"label-badge-text-color": "var(--primary-text-color)",
|
||||||
"paper-slider-knob-start-color": "var(--accent-color)",
|
|
||||||
"switch-unchecked-track-color": "var(--disabled-text-color)",
|
"switch-unchecked-track-color": "var(--disabled-text-color)",
|
||||||
"dark-primary-color": "var(--accent-color)",
|
"dark-primary-color": "var(--accent-color)",
|
||||||
"paper-slider-secondary-color": "var(--secondary-background-color)",
|
|
||||||
"paper-slider-pin-color": "var(--accent-color)",
|
|
||||||
"paper-item-icon-active-color": "#b58e31",
|
"paper-item-icon-active-color": "#b58e31",
|
||||||
"accent-color": "#2980b9",
|
"accent-color": "#2980b9",
|
||||||
"table-row-alternative-background-color": "#292929",
|
"table-row-alternative-background-color": "#292929",
|
||||||
|
|||||||
@@ -3,6 +3,15 @@ import { DemoConfig } from "../types";
|
|||||||
|
|
||||||
export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
|
||||||
convertEntities({
|
convertEntities({
|
||||||
|
"todo.shopping_list": {
|
||||||
|
entity_id: "todo.shopping_list",
|
||||||
|
state: "2",
|
||||||
|
attributes: {
|
||||||
|
supported_features: 15,
|
||||||
|
friendly_name: "Shopping List",
|
||||||
|
icon: "mdi:cart",
|
||||||
|
},
|
||||||
|
},
|
||||||
"sensor.pollen_grabo": {
|
"sensor.pollen_grabo": {
|
||||||
entity_id: "sensor.pollen_grabo",
|
entity_id: "sensor.pollen_grabo",
|
||||||
state: "",
|
state: "",
|
||||||
|
|||||||
@@ -220,7 +220,8 @@ export const demoLovelaceTeachingbirds: DemoConfig["lovelace"] = () => ({
|
|||||||
state_filter: ["on"],
|
state_filter: ["on"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "shopping-list",
|
type: "todo-list",
|
||||||
|
entity: "todo.shopping_list",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
entities: [
|
entities: [
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
export const demoThemeTeachingbirds = () => ({
|
export const demoThemeTeachingbirds = () => ({
|
||||||
"paper-card-header-color": "var(--paper-item-icon-color)",
|
"paper-card-header-color": "var(--paper-item-icon-color)",
|
||||||
"paper-slider-pin-color": "var(--primary-color)",
|
|
||||||
"paper-listbox-background-color": "#202020",
|
"paper-listbox-background-color": "#202020",
|
||||||
"paper-grey-50": "var(--primary-text-color)",
|
"paper-grey-50": "var(--primary-text-color)",
|
||||||
"paper-item-icon-color": "#d3d3d3",
|
"paper-item-icon-color": "#d3d3d3",
|
||||||
@@ -8,8 +7,6 @@ export const demoThemeTeachingbirds = () => ({
|
|||||||
"primary-color": "#389638",
|
"primary-color": "#389638",
|
||||||
"light-primary-color": "#6f956f",
|
"light-primary-color": "#6f956f",
|
||||||
"label-badge-red": "var(--primary-color)",
|
"label-badge-red": "var(--primary-color)",
|
||||||
"paper-slider-secondary-color": "var(--light-primary-color)",
|
|
||||||
"paper-slider-knob-color": "var(--primary-color)",
|
|
||||||
"paper-listbox-color": "#FFFFFF",
|
"paper-listbox-color": "#FFFFFF",
|
||||||
"paper-toggle-button-checked-bar-color": "var(--light-primary-color)",
|
"paper-toggle-button-checked-bar-color": "var(--light-primary-color)",
|
||||||
"switch-unchecked-track-color": "var(--primary-text-color)",
|
"switch-unchecked-track-color": "var(--primary-text-color)",
|
||||||
@@ -17,9 +14,7 @@ export const demoThemeTeachingbirds = () => ({
|
|||||||
"label-badge-text-color": "var(--text-primary-color)",
|
"label-badge-text-color": "var(--text-primary-color)",
|
||||||
"primary-background-color": "#303030",
|
"primary-background-color": "#303030",
|
||||||
"sidebar-icon-color": "var(--paper-item-icon-color)",
|
"sidebar-icon-color": "var(--paper-item-icon-color)",
|
||||||
"paper-slider-active-color": "#d8bf50",
|
|
||||||
"secondary-background-color": "#2b2b2b",
|
"secondary-background-color": "#2b2b2b",
|
||||||
"paper-slider-knob-start-color": "var(--primary-color)",
|
|
||||||
"paper-item-icon-active-color": "#d8bf50",
|
"paper-item-icon-active-color": "#d8bf50",
|
||||||
"switch-checked-color": "var(--primary-color)",
|
"switch-checked-color": "var(--primary-color)",
|
||||||
"secondary-text-color": "#389638",
|
"secondary-text-color": "#389638",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { LocalizeFunc } from "../../../src/common/translations/localize";
|
import { LocalizeFunc } from "../../../src/common/translations/localize";
|
||||||
import { LovelaceConfig } from "../../../src/data/lovelace";
|
import { LovelaceConfig } from "../../../src/data/lovelace/config/types";
|
||||||
import { Entity } from "../../../src/fake_data/entity";
|
import { Entity } from "../../../src/fake_data/entity";
|
||||||
|
|
||||||
export interface DemoConfig {
|
export interface DemoConfig {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { customElement, property, state } from "lit/decorators";
|
|||||||
import { until } from "lit/directives/until";
|
import { until } from "lit/directives/until";
|
||||||
import "../../../src/components/ha-card";
|
import "../../../src/components/ha-card";
|
||||||
import "../../../src/components/ha-circular-progress";
|
import "../../../src/components/ha-circular-progress";
|
||||||
import { LovelaceCardConfig } from "../../../src/data/lovelace";
|
import { LovelaceCardConfig } from "../../../src/data/lovelace/config/card";
|
||||||
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||||
import { Lovelace, LovelaceCard } from "../../../src/panels/lovelace/types";
|
import { Lovelace, LovelaceCard } from "../../../src/panels/lovelace/types";
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import "../../src/resources/ha-style";
|
|
||||||
import "../../src/resources/roboto";
|
|
||||||
import "../../src/resources/safari-14-attachshadow-patch";
|
import "../../src/resources/safari-14-attachshadow-patch";
|
||||||
import "./ha-demo";
|
import "./ha-demo";
|
||||||
|
|
||||||
|
import("../../src/resources/ha-style");
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ 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 { mockShoppingList } from "./stubs/shopping_list";
|
import { mockTodo } from "./stubs/todo";
|
||||||
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";
|
||||||
@@ -49,7 +49,7 @@ export class HaDemo extends HomeAssistantAppEl {
|
|||||||
mockTranslations(hass);
|
mockTranslations(hass);
|
||||||
mockHistory(hass);
|
mockHistory(hass);
|
||||||
mockRecorder(hass);
|
mockRecorder(hass);
|
||||||
mockShoppingList(hass);
|
mockTodo(hass);
|
||||||
mockSystemLog(hass);
|
mockSystemLog(hass);
|
||||||
mockTemplate(hass);
|
mockTemplate(hass);
|
||||||
mockEvents(hass);
|
mockEvents(hass);
|
||||||
|
|||||||
@@ -74,19 +74,9 @@
|
|||||||
<body>
|
<body>
|
||||||
<div id="ha-launch-screen">
|
<div id="ha-launch-screen">
|
||||||
<div class="ha-launch-screen-spacer"></div>
|
<div class="ha-launch-screen-spacer"></div>
|
||||||
<svg
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 240">
|
||||||
viewBox="0 0 240 240"
|
<path fill="#18BCF2" d="M240 224.762a15 15 0 0 1-15 15H15a15 15 0 0 1-15-15v-90c0-8.25 4.77-19.769 10.61-25.609l98.78-98.7805c5.83-5.83 15.38-5.83 21.21 0l98.79 98.7895c5.83 5.83 10.61 17.36 10.61 25.61v90-.01Z"/>
|
||||||
fill="none"
|
<path fill="#F2F4F9" d="m107.27 239.762-40.63-40.63c-2.09.72-4.32 1.13-6.64 1.13-11.3 0-20.5-9.2-20.5-20.5s9.2-20.5 20.5-20.5 20.5 9.2 20.5 20.5c0 2.33-.41 4.56-1.13 6.65l31.63 31.63v-115.88c-6.8-3.3395-11.5-10.3195-11.5-18.3895 0-11.3 9.2-20.5 20.5-20.5s20.5 9.2 20.5 20.5c0 8.07-4.7 15.05-11.5 18.3895v81.27l31.46-31.46c-.62-1.96-.96-4.04-.96-6.2 0-11.3 9.2-20.5 20.5-20.5s20.5 9.2 20.5 20.5-9.2 20.5-20.5 20.5c-2.5 0-4.88-.47-7.09-1.29L129 208.892v30.88z"/>
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M240 224.762C240 233.012 233.25 239.762 225 239.762H15C6.75 239.762 0 233.012 0 224.762V134.762C0 126.512 4.77 114.993 10.61 109.153L109.39 10.3725C115.22 4.5425 124.77 4.5425 130.6 10.3725L229.39 109.162C235.22 114.992 240 126.522 240 134.772V224.772V224.762Z"
|
|
||||||
fill="#F2F4F9"
|
|
||||||
/>
|
|
||||||
<path
|
|
||||||
d="M229.39 109.153L130.61 10.3725C124.78 4.5425 115.23 4.5425 109.4 10.3725L10.61 109.153C4.78 114.983 0 126.512 0 134.762V224.762C0 233.012 6.75 239.762 15 239.762H107.27L66.64 199.132C64.55 199.852 62.32 200.262 60 200.262C48.7 200.262 39.5 191.062 39.5 179.762C39.5 168.462 48.7 159.262 60 159.262C71.3 159.262 80.5 168.462 80.5 179.762C80.5 182.092 80.09 184.322 79.37 186.412L111 218.042V102.162C104.2 98.8225 99.5 91.8425 99.5 83.7725C99.5 72.4725 108.7 63.2725 120 63.2725C131.3 63.2725 140.5 72.4725 140.5 83.7725C140.5 91.8425 135.8 98.8225 129 102.162V183.432L160.46 151.972C159.84 150.012 159.5 147.932 159.5 145.772C159.5 134.472 168.7 125.272 180 125.272C191.3 125.272 200.5 134.472 200.5 145.772C200.5 157.072 191.3 166.272 180 166.272C177.5 166.272 175.12 165.802 172.91 164.982L129 208.892V239.772H225C233.25 239.772 240 233.022 240 224.772V134.772C240 126.522 235.23 115.002 229.39 109.162V109.153Z"
|
|
||||||
fill="#18BCF2"
|
|
||||||
/>
|
|
||||||
</svg>
|
</svg>
|
||||||
<div id="ha-launch-screen-info-box" class="ha-launch-screen-spacer"></div>
|
<div id="ha-launch-screen-info-box" class="ha-launch-screen-spacer"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
import { ShoppingListItem } from "../../../src/data/shopping-list";
|
|
||||||
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
|
||||||
|
|
||||||
let items: ShoppingListItem[] = [
|
|
||||||
{
|
|
||||||
id: 12,
|
|
||||||
name: "Milk",
|
|
||||||
complete: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 13,
|
|
||||||
name: "Eggs",
|
|
||||||
complete: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 14,
|
|
||||||
name: "Oranges",
|
|
||||||
complete: true,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export const mockShoppingList = (hass: MockHomeAssistant) => {
|
|
||||||
hass.mockWS("shopping_list/items", () => items);
|
|
||||||
hass.mockWS("shopping_list/items/add", (msg) => {
|
|
||||||
const item: ShoppingListItem = {
|
|
||||||
id: new Date().getTime(),
|
|
||||||
complete: false,
|
|
||||||
name: msg.name,
|
|
||||||
};
|
|
||||||
items.push(item);
|
|
||||||
hass.mockEvent("shopping_list_updated");
|
|
||||||
return item;
|
|
||||||
});
|
|
||||||
hass.mockWS("shopping_list/items/update", ({ type, item_id, ...updates }) => {
|
|
||||||
items = items.map((item) =>
|
|
||||||
item.id === item_id ? { ...item, ...updates } : item
|
|
||||||
);
|
|
||||||
hass.mockEvent("shopping_list_updated");
|
|
||||||
});
|
|
||||||
hass.mockWS("shopping_list/items/clear", () => {
|
|
||||||
items = items.filter((item) => !item.complete);
|
|
||||||
hass.mockEvent("shopping_list_updated");
|
|
||||||
});
|
|
||||||
};
|
|
||||||
24
demo/src/stubs/todo.ts
Normal file
24
demo/src/stubs/todo.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { TodoItem, TodoItemStatus } from "../../../src/data/todo";
|
||||||
|
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||||
|
|
||||||
|
export const mockTodo = (hass: MockHomeAssistant) => {
|
||||||
|
hass.mockWS("todo/item/list", () => ({
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
uid: "12",
|
||||||
|
summary: "Milk",
|
||||||
|
status: TodoItemStatus.NeedsAction,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uid: "13",
|
||||||
|
summary: "Eggs",
|
||||||
|
status: TodoItemStatus.NeedsAction,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uid: "14",
|
||||||
|
summary: "Oranges",
|
||||||
|
status: TodoItemStatus.Completed,
|
||||||
|
},
|
||||||
|
] as TodoItem[],
|
||||||
|
}));
|
||||||
|
};
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import "../../src/resources/ha-style";
|
|
||||||
import "../../src/resources/roboto";
|
|
||||||
import "./ha-gallery";
|
import "./ha-gallery";
|
||||||
|
|
||||||
|
import("../../src/resources/ha-style");
|
||||||
|
|
||||||
document.body.appendChild(document.createElement("ha-gallery"));
|
document.body.appendChild(document.createElement("ha-gallery"));
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import { css, html, LitElement, TemplateResult } from "lit";
|
import { css, html, LitElement, TemplateResult, nothing } from "lit";
|
||||||
import { customElement } from "lit/decorators";
|
import { customElement } from "lit/decorators";
|
||||||
import "../../../../src/components/ha-card";
|
import "../../../../src/components/ha-card";
|
||||||
import "../../../../src/components/ha-chip";
|
import "../../../../src/components/chips/ha-chip-set";
|
||||||
import "../../../../src/components/ha-chip-set";
|
import "../../../../src/components/chips/ha-assist-chip";
|
||||||
|
import "../../../../src/components/chips/ha-input-chip";
|
||||||
|
import "../../../../src/components/chips/ha-filter-chip";
|
||||||
import "../../../../src/components/ha-svg-icon";
|
import "../../../../src/components/ha-svg-icon";
|
||||||
import { mdiHomeAssistant } from "../../../../src/resources/home-assistant-logo-svg";
|
import { mdiHomeAssistant } from "../../../../src/resources/home-assistant-logo-svg";
|
||||||
|
|
||||||
@@ -10,10 +12,6 @@ const chips: {
|
|||||||
icon?: string;
|
icon?: string;
|
||||||
content?: string;
|
content?: string;
|
||||||
}[] = [
|
}[] = [
|
||||||
{},
|
|
||||||
{
|
|
||||||
icon: mdiHomeAssistant,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
content: "Content",
|
content: "Content",
|
||||||
},
|
},
|
||||||
@@ -29,31 +27,73 @@ export class DemoHaChips extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
<ha-card header="ha-chip demo">
|
<ha-card header="ha-chip demo">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
${chips.map(
|
<p>Action chip</p>
|
||||||
(chip) => html`
|
|
||||||
<ha-chip .hasIcon=${chip.icon !== undefined}>
|
|
||||||
${chip.icon
|
|
||||||
? html`<ha-svg-icon slot="icon" .path=${chip.icon}>
|
|
||||||
</ha-svg-icon>`
|
|
||||||
: ""}
|
|
||||||
${chip.content}
|
|
||||||
</ha-chip>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</ha-card>
|
|
||||||
<ha-card header="ha-chip-set demo">
|
|
||||||
<div class="card-content">
|
|
||||||
<ha-chip-set>
|
<ha-chip-set>
|
||||||
${chips.map(
|
${chips.map(
|
||||||
(chip) => html`
|
(chip) => html`
|
||||||
<ha-chip .hasIcon=${chip.icon !== undefined}>
|
<ha-assist-chip .label=${chip.content}>
|
||||||
|
${chip.icon
|
||||||
|
? html`<ha-svg-icon slot="icon" .path=${chip.icon}>
|
||||||
|
</ha-svg-icon>`
|
||||||
|
: nothing}
|
||||||
|
</ha-assist-chip>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
${chips.map(
|
||||||
|
(chip) => html`
|
||||||
|
<ha-assist-chip .label=${chip.content} selected>
|
||||||
|
${chip.icon
|
||||||
|
? html`<ha-svg-icon slot="icon" .path=${chip.icon}>
|
||||||
|
</ha-svg-icon>`
|
||||||
|
: nothing}
|
||||||
|
</ha-assist-chip>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</ha-chip-set>
|
||||||
|
<p>Filter chip</p>
|
||||||
|
<ha-chip-set>
|
||||||
|
${chips.map(
|
||||||
|
(chip) => html`
|
||||||
|
<ha-filter-chip .label=${chip.content}>
|
||||||
|
${chip.icon
|
||||||
|
? html`<ha-svg-icon slot="icon" .path=${chip.icon}>
|
||||||
|
</ha-svg-icon>`
|
||||||
|
: nothing}
|
||||||
|
</ha-filter-chip>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
${chips.map(
|
||||||
|
(chip) => html`
|
||||||
|
<ha-filter-chip .label=${chip.content} selected>
|
||||||
|
${chip.icon
|
||||||
|
? html`<ha-svg-icon slot="icon" .path=${chip.icon}>
|
||||||
|
</ha-svg-icon>`
|
||||||
|
: nothing}
|
||||||
|
</ha-filter-chip>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</ha-chip-set>
|
||||||
|
<p>Input chip</p>
|
||||||
|
<ha-chip-set>
|
||||||
|
${chips.map(
|
||||||
|
(chip) => html`
|
||||||
|
<ha-input-chip .label=${chip.content}>
|
||||||
${chip.icon
|
${chip.icon
|
||||||
? html`<ha-svg-icon slot="icon" .path=${chip.icon}>
|
? html`<ha-svg-icon slot="icon" .path=${chip.icon}>
|
||||||
</ha-svg-icon>`
|
</ha-svg-icon>`
|
||||||
: ""}
|
: ""}
|
||||||
${chip.content}
|
${chip.content}
|
||||||
</ha-chip>
|
</ha-input-chip>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
${chips.map(
|
||||||
|
(chip) => html`
|
||||||
|
<ha-input-chip .label=${chip.content} selected>
|
||||||
|
${chip.icon
|
||||||
|
? html`<ha-svg-icon slot="icon" .path=${chip.icon}>
|
||||||
|
</ha-svg-icon>`
|
||||||
|
: nothing}
|
||||||
|
</ha-input-chip>
|
||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
</ha-chip-set>
|
</ha-chip-set>
|
||||||
@@ -68,12 +108,10 @@ export class DemoHaChips extends LitElement {
|
|||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
margin: 24px auto;
|
margin: 24px auto;
|
||||||
}
|
}
|
||||||
ha-chip {
|
|
||||||
margin-bottom: 4px;
|
|
||||||
}
|
|
||||||
.card-content {
|
.card-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,11 +49,11 @@ export class DemoHaCircularSlider extends LitElement {
|
|||||||
<div class="field">
|
<div class="field">
|
||||||
<p>Current</p>
|
<p>Current</p>
|
||||||
<ha-slider
|
<ha-slider
|
||||||
|
labeled
|
||||||
min="10"
|
min="10"
|
||||||
max="30"
|
max="30"
|
||||||
.value=${this.current}
|
.value=${this.current}
|
||||||
@change=${this._currentChanged}
|
@change=${this._currentChanged}
|
||||||
pin
|
|
||||||
></ha-slider>
|
></ha-slider>
|
||||||
<p>${this.current} °C</p>
|
<p>${this.current} °C</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ const buttons: {
|
|||||||
min?: number;
|
min?: number;
|
||||||
max?: number;
|
max?: number;
|
||||||
step?: number;
|
step?: number;
|
||||||
|
unit?: string;
|
||||||
class?: string;
|
class?: string;
|
||||||
}[] = [
|
}[] = [
|
||||||
{
|
{
|
||||||
@@ -29,6 +30,11 @@ const buttons: {
|
|||||||
label: "Custom",
|
label: "Custom",
|
||||||
class: "custom",
|
class: "custom",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "unit",
|
||||||
|
label: "With unit",
|
||||||
|
unit: "m",
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@customElement("demo-components-ha-control-number-buttons")
|
@customElement("demo-components-ha-control-number-buttons")
|
||||||
@@ -50,6 +56,7 @@ export class DemoHarControlNumberButtons extends LitElement {
|
|||||||
<pre>Config: ${JSON.stringify(config)}</pre>
|
<pre>Config: ${JSON.stringify(config)}</pre>
|
||||||
<ha-control-number-buttons
|
<ha-control-number-buttons
|
||||||
.value=${this.value}
|
.value=${this.value}
|
||||||
|
.unit=${config.unit}
|
||||||
.min=${config.min}
|
.min=${config.min}
|
||||||
.max=${config.max}
|
.max=${config.max}
|
||||||
.step=${config.step}
|
.step=${config.step}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ const sliders: {
|
|||||||
id: string;
|
id: string;
|
||||||
label: string;
|
label: string;
|
||||||
mode?: "start" | "end" | "cursor";
|
mode?: "start" | "end" | "cursor";
|
||||||
|
unit?: string;
|
||||||
class?: string;
|
class?: string;
|
||||||
}[] = [
|
}[] = [
|
||||||
{
|
{
|
||||||
@@ -31,18 +32,21 @@ const sliders: {
|
|||||||
label: "Slider (start mode) and custom style",
|
label: "Slider (start mode) and custom style",
|
||||||
mode: "start",
|
mode: "start",
|
||||||
class: "custom",
|
class: "custom",
|
||||||
|
unit: "mm",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "slider-end-custom",
|
id: "slider-end-custom",
|
||||||
label: "Slider (end mode) and custom style",
|
label: "Slider (end mode) and custom style",
|
||||||
mode: "end",
|
mode: "end",
|
||||||
class: "custom",
|
class: "custom",
|
||||||
|
unit: "mm",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "slider-cursor-custom",
|
id: "slider-cursor-custom",
|
||||||
label: "Slider (cursor mode) and custom style",
|
label: "Slider (cursor mode) and custom style",
|
||||||
mode: "cursor",
|
mode: "cursor",
|
||||||
class: "custom",
|
class: "custom",
|
||||||
|
unit: "mm",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -93,6 +97,7 @@ export class DemoHaBarSlider extends LitElement {
|
|||||||
@value-changed=${this.handleValueChanged}
|
@value-changed=${this.handleValueChanged}
|
||||||
@slider-moved=${this.handleSliderMoved}
|
@slider-moved=${this.handleSliderMoved}
|
||||||
aria-labelledby=${id}
|
aria-labelledby=${id}
|
||||||
|
.unit=${config.unit}
|
||||||
>
|
>
|
||||||
</ha-control-slider>
|
</ha-control-slider>
|
||||||
</div>
|
</div>
|
||||||
@@ -114,6 +119,7 @@ export class DemoHaBarSlider extends LitElement {
|
|||||||
@value-changed=${this.handleValueChanged}
|
@value-changed=${this.handleValueChanged}
|
||||||
@slider-moved=${this.handleSliderMoved}
|
@slider-moved=${this.handleSliderMoved}
|
||||||
aria-label=${label}
|
aria-label=${label}
|
||||||
|
.unit=${config.unit}
|
||||||
>
|
>
|
||||||
</ha-control-slider>
|
</ha-control-slider>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -5,9 +5,22 @@ subtitle: Dialogs provide important prompts in a user flow.
|
|||||||
|
|
||||||
# Material Design 3
|
# Material Design 3
|
||||||
|
|
||||||
Our dialogs are based on the latest version of Material Design. Specs and guidelines can be found on its [website](https://m3.material.io/components/dialogs/overview).
|
Our dialogs are based on the latest version of Material Design. Please note that we have made some well-considered adjustments to these guideliness. Specs and guidelines can be found on its [website](https://m3.material.io/components/dialogs/overview).
|
||||||
|
|
||||||
# Highlighted guidelines
|
# Guidelines
|
||||||
|
|
||||||
|
## Design
|
||||||
|
|
||||||
|
- Dialogs have a max width of 560px. Alert and confirmation dialogs got a fixed width of 320px. If you need more width, consider a dedicated page instead.
|
||||||
|
- The close X-icon is on the top left, on all screen sizes. Except for alert and confirmation dialogs, they only have buttons and no X-icon. This is different compared to the Material guideliness.
|
||||||
|
- Dialogs can't be closed with ESC or clicked outside of the dialog when there is a form that the user needs to fill out. Instead it will animate "no" by a little shake.
|
||||||
|
- Extra icon buttons are on the top right, for example help, settings and expand dialog. More than 2 icon buttons, they will be in an overflow menu.
|
||||||
|
- The submit button is grouped with a cancel button at the bottom right, on all screen sizes. Fullscreen mobile dialogs have them sticky at the bottom.
|
||||||
|
- Keep the labels short, for example `Save`, `Delete`, `Enable`.
|
||||||
|
- Dialog with actions must always have a discard button. On desktop a `Cancel` button and X-icon, on mobile only the X-icon.
|
||||||
|
- Destructive actions should be a red warning button.
|
||||||
|
- Alert or confirmation dialogs only have buttons and no X-icon.
|
||||||
|
- Try to avoid three buttons in one dialog. Especially when you leave the dialog task unfinished.
|
||||||
|
|
||||||
## Content
|
## Content
|
||||||
|
|
||||||
@@ -17,14 +30,6 @@ Our dialogs are based on the latest version of Material Design. Specs and guidel
|
|||||||
- If users become unsure, they read the description. Make sure this explains what will happen.
|
- If users become unsure, they read the description. Make sure this explains what will happen.
|
||||||
- Strive for minimalism.
|
- Strive for minimalism.
|
||||||
|
|
||||||
## Buttons and X-icon
|
|
||||||
|
|
||||||
- Keep the labels short, for example `Save`, `Delete`, `Enable`.
|
|
||||||
- Dialog with actions must always have a discard button. On desktop a `Cancel` button and X-icon, on mobile only the X-icon.
|
|
||||||
- Destructive actions should be a red warning button.
|
|
||||||
- Alert or confirmation dialogs only have buttons and no X-icon.
|
|
||||||
- Try to avoid three buttons in one dialog. Especially when you leave the dialog task unfinished.
|
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
### Confirmation dialog
|
### Confirmation dialog
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ const DEVICES = [
|
|||||||
sw_version: null,
|
sw_version: null,
|
||||||
hw_version: null,
|
hw_version: null,
|
||||||
via_device_id: null,
|
via_device_id: null,
|
||||||
|
serial_number: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
area_id: "backyard",
|
area_id: "backyard",
|
||||||
@@ -74,6 +75,7 @@ const DEVICES = [
|
|||||||
sw_version: null,
|
sw_version: null,
|
||||||
hw_version: null,
|
hw_version: null,
|
||||||
via_device_id: null,
|
via_device_id: null,
|
||||||
|
serial_number: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
area_id: null,
|
area_id: null,
|
||||||
@@ -91,6 +93,7 @@ const DEVICES = [
|
|||||||
sw_version: null,
|
sw_version: null,
|
||||||
hw_version: null,
|
hw_version: null,
|
||||||
via_device_id: null,
|
via_device_id: null,
|
||||||
|
serial_number: null,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -57,8 +57,8 @@ export class DemoHaHsColorPicker extends LitElement {
|
|||||||
></ha-hs-color-picker>
|
></ha-hs-color-picker>
|
||||||
<p>Hue : ${this.value[0]}</p>
|
<p>Hue : ${this.value[0]}</p>
|
||||||
<ha-slider
|
<ha-slider
|
||||||
|
labeled
|
||||||
step="1"
|
step="1"
|
||||||
pin
|
|
||||||
min="0"
|
min="0"
|
||||||
max="360"
|
max="360"
|
||||||
.value=${this.value[0]}
|
.value=${this.value[0]}
|
||||||
@@ -67,8 +67,8 @@ export class DemoHaHsColorPicker extends LitElement {
|
|||||||
</ha-slider>
|
</ha-slider>
|
||||||
<p>Saturation : ${this.value[1]}</p>
|
<p>Saturation : ${this.value[1]}</p>
|
||||||
<ha-slider
|
<ha-slider
|
||||||
|
labeled
|
||||||
step="0.01"
|
step="0.01"
|
||||||
pin
|
|
||||||
min="0"
|
min="0"
|
||||||
max="1"
|
max="1"
|
||||||
.value=${this.value[1]}
|
.value=${this.value[1]}
|
||||||
@@ -77,8 +77,8 @@ export class DemoHaHsColorPicker extends LitElement {
|
|||||||
</ha-slider>
|
</ha-slider>
|
||||||
<p>Color Brighness : ${this.brightness}</p>
|
<p>Color Brighness : ${this.brightness}</p>
|
||||||
<ha-slider
|
<ha-slider
|
||||||
|
labeled
|
||||||
step="1"
|
step="1"
|
||||||
pin
|
|
||||||
min="0"
|
min="0"
|
||||||
max="255"
|
max="255"
|
||||||
.value=${this.brightness}
|
.value=${this.brightness}
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ const DEVICES = [
|
|||||||
sw_version: null,
|
sw_version: null,
|
||||||
hw_version: null,
|
hw_version: null,
|
||||||
via_device_id: null,
|
via_device_id: null,
|
||||||
|
serial_number: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
area_id: "backyard",
|
area_id: "backyard",
|
||||||
@@ -70,6 +71,7 @@ const DEVICES = [
|
|||||||
sw_version: null,
|
sw_version: null,
|
||||||
hw_version: null,
|
hw_version: null,
|
||||||
via_device_id: null,
|
via_device_id: null,
|
||||||
|
serial_number: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
area_id: null,
|
area_id: null,
|
||||||
@@ -87,6 +89,7 @@ const DEVICES = [
|
|||||||
sw_version: null,
|
sw_version: null,
|
||||||
hw_version: null,
|
hw_version: null,
|
||||||
via_device_id: null,
|
via_device_id: null,
|
||||||
|
serial_number: null,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
---
|
|
||||||
title: Shopping List Card
|
|
||||||
---
|
|
||||||
3
gallery/src/pages/lovelace/todo-list-card.markdown
Normal file
3
gallery/src/pages/lovelace/todo-list-card.markdown
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
title: Todo List Card
|
||||||
|
---
|
||||||
@@ -2,25 +2,39 @@ import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
|||||||
import { customElement, query } from "lit/decorators";
|
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 { getEntity } from "../../../../src/fake_data/entity";
|
||||||
|
import { mockTodo } from "../../../../demo/src/stubs/todo";
|
||||||
|
|
||||||
|
const ENTITIES = [
|
||||||
|
getEntity("todo", "shopping_list", "2", {
|
||||||
|
friendly_name: "Shopping List",
|
||||||
|
supported_features: 15,
|
||||||
|
}),
|
||||||
|
getEntity("todo", "read_only", "2", {
|
||||||
|
friendly_name: "Read only",
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
const CONFIGS = [
|
const CONFIGS = [
|
||||||
{
|
{
|
||||||
heading: "List example",
|
heading: "List example",
|
||||||
config: `
|
config: `
|
||||||
- type: shopping-list
|
- type: todo-list
|
||||||
|
entity: todo.shopping_list
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
heading: "List with title example",
|
heading: "List with title example",
|
||||||
config: `
|
config: `
|
||||||
- type: shopping-list
|
- type: todo-list
|
||||||
title: Shopping List
|
title: Shopping List
|
||||||
|
entity: todo.read_only
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@customElement("demo-lovelace-shopping-list-card")
|
@customElement("demo-lovelace-todo-list-card")
|
||||||
class DemoShoppingListEntity extends LitElement {
|
class DemoTodoListEntity extends LitElement {
|
||||||
@query("#demos") private _demoRoot!: HTMLElement;
|
@query("#demos") private _demoRoot!: HTMLElement;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
@@ -32,18 +46,14 @@ class DemoShoppingListEntity extends LitElement {
|
|||||||
const hass = provideHass(this._demoRoot);
|
const hass = provideHass(this._demoRoot);
|
||||||
hass.updateTranslations(null, "en");
|
hass.updateTranslations(null, "en");
|
||||||
hass.updateTranslations("lovelace", "en");
|
hass.updateTranslations("lovelace", "en");
|
||||||
|
hass.addEntities(ENTITIES);
|
||||||
|
|
||||||
hass.mockAPI("shopping_list", () => [
|
mockTodo(hass);
|
||||||
{ name: "list", id: 1, complete: false },
|
|
||||||
{ name: "all", id: 2, complete: false },
|
|
||||||
{ name: "the", id: 3, complete: false },
|
|
||||||
{ name: "things", id: 4, complete: true },
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
"demo-lovelace-shopping-list-card": DemoShoppingListEntity;
|
"demo-lovelace-todo-list-card": DemoTodoListEntity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,6 @@ import { computeStateDisplay } from "../../../../src/common/entity/compute_state
|
|||||||
import "../../../../src/components/data-table/ha-data-table";
|
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 "../../../../src/components/ha-chip";
|
|
||||||
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";
|
||||||
|
|
||||||
|
|||||||
@@ -213,6 +213,7 @@ const createDeviceRegistryEntries = (
|
|||||||
name: "Tag Reader",
|
name: "Tag Reader",
|
||||||
sw_version: null,
|
sw_version: null,
|
||||||
hw_version: "1.0.0",
|
hw_version: "1.0.0",
|
||||||
|
serial_number: "00_12_4B_00_22_98_88_7F",
|
||||||
id: "mock-device-id",
|
id: "mock-device-id",
|
||||||
identifiers: [],
|
identifiers: [],
|
||||||
via_device_id: null,
|
via_device_id: null,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import "@material/mwc-button";
|
|||||||
import { css, html, LitElement, TemplateResult } from "lit";
|
import { css, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement } from "lit/decorators";
|
import { customElement } from "lit/decorators";
|
||||||
import "../../../../src/components/ha-card";
|
import "../../../../src/components/ha-card";
|
||||||
import { ActionHandlerEvent } from "../../../../src/data/lovelace";
|
import { ActionHandlerEvent } from "../../../../src/data/lovelace/action_handler";
|
||||||
import { actionHandler } from "../../../../src/panels/lovelace/common/directives/action-handler-directive";
|
import { actionHandler } from "../../../../src/panels/lovelace/common/directives/action-handler-directive";
|
||||||
|
|
||||||
@customElement("demo-misc-util-long-press")
|
@customElement("demo-misc-util-long-press")
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ import { navigate } from "../../../../src/common/navigate";
|
|||||||
import "../../../../src/components/buttons/ha-progress-button";
|
import "../../../../src/components/buttons/ha-progress-button";
|
||||||
import "../../../../src/components/ha-alert";
|
import "../../../../src/components/ha-alert";
|
||||||
import "../../../../src/components/ha-card";
|
import "../../../../src/components/ha-card";
|
||||||
import "../../../../src/components/ha-chip";
|
import "../../../../src/components/chips/ha-chip-set";
|
||||||
import "../../../../src/components/ha-chip-set";
|
import "../../../../src/components/chips/ha-assist-chip";
|
||||||
import "../../../../src/components/ha-markdown";
|
import "../../../../src/components/ha-markdown";
|
||||||
import "../../../../src/components/ha-settings-row";
|
import "../../../../src/components/ha-settings-row";
|
||||||
import "../../../../src/components/ha-svg-icon";
|
import "../../../../src/components/ha-svg-icon";
|
||||||
@@ -78,6 +78,7 @@ import { showHassioMarkdownDialog } from "../../dialogs/markdown/show-dialog-has
|
|||||||
import { hassioStyle } from "../../resources/hassio-style";
|
import { hassioStyle } from "../../resources/hassio-style";
|
||||||
import "../../update-available/update-available-card";
|
import "../../update-available/update-available-card";
|
||||||
import { addonArchIsSupported, extractChangelog } from "../../util/addon";
|
import { addonArchIsSupported, extractChangelog } from "../../util/addon";
|
||||||
|
import { capitalizeFirstLetter } from "../../../../src/common/string/capitalize-first-letter";
|
||||||
|
|
||||||
const STAGE_ICON = {
|
const STAGE_ICON = {
|
||||||
stable: mdiCheckCircle,
|
stable: mdiCheckCircle,
|
||||||
@@ -234,28 +235,32 @@ class HassioAddonInfo extends LitElement {
|
|||||||
|
|
||||||
<ha-chip-set class="capabilities">
|
<ha-chip-set class="capabilities">
|
||||||
${this.addon.stage !== "stable"
|
${this.addon.stage !== "stable"
|
||||||
? html` <ha-chip
|
? html`
|
||||||
hasIcon
|
<ha-assist-chip
|
||||||
|
filled
|
||||||
class=${classMap({
|
class=${classMap({
|
||||||
yellow: this.addon.stage === "experimental",
|
yellow: this.addon.stage === "experimental",
|
||||||
red: this.addon.stage === "deprecated",
|
red: this.addon.stage === "deprecated",
|
||||||
})}
|
})}
|
||||||
@click=${this._showMoreInfo}
|
@click=${this._showMoreInfo}
|
||||||
id="stage"
|
id="stage"
|
||||||
|
.label=${capitalizeFirstLetter(
|
||||||
|
this.supervisor.localize(
|
||||||
|
`addon.dashboard.capability.stages.${this.addon.stage}`
|
||||||
|
)
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<ha-svg-icon
|
<ha-svg-icon
|
||||||
slot="icon"
|
slot="icon"
|
||||||
.path=${STAGE_ICON[this.addon.stage]}
|
.path=${STAGE_ICON[this.addon.stage]}
|
||||||
>
|
>
|
||||||
</ha-svg-icon>
|
</ha-svg-icon>
|
||||||
${this.supervisor.localize(
|
</ha-assist-chip>
|
||||||
`addon.dashboard.capability.stages.${this.addon.stage}`
|
`
|
||||||
)}
|
|
||||||
</ha-chip>`
|
|
||||||
: ""}
|
: ""}
|
||||||
|
|
||||||
<ha-chip
|
<ha-assist-chip
|
||||||
hasIcon
|
filled
|
||||||
class=${classMap({
|
class=${classMap({
|
||||||
green: Number(this.addon.rating) >= 6,
|
green: Number(this.addon.rating) >= 6,
|
||||||
yellow: [3, 4, 5].includes(Number(this.addon.rating)),
|
yellow: [3, 4, 5].includes(Number(this.addon.rating)),
|
||||||
@@ -263,138 +268,183 @@ class HassioAddonInfo extends LitElement {
|
|||||||
})}
|
})}
|
||||||
@click=${this._showMoreInfo}
|
@click=${this._showMoreInfo}
|
||||||
id="rating"
|
id="rating"
|
||||||
|
.label=${capitalizeFirstLetter(
|
||||||
|
this.supervisor.localize(
|
||||||
|
"addon.dashboard.capability.label.rating"
|
||||||
|
)
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<ha-svg-icon slot="icon" .path=${RATING_ICON[this.addon.rating]}>
|
<ha-svg-icon slot="icon" .path=${RATING_ICON[this.addon.rating]}>
|
||||||
</ha-svg-icon>
|
</ha-svg-icon>
|
||||||
|
</ha-assist-chip>
|
||||||
${this.supervisor.localize(
|
|
||||||
"addon.dashboard.capability.label.rating"
|
|
||||||
)}
|
|
||||||
</ha-chip>
|
|
||||||
${this.addon.host_network
|
${this.addon.host_network
|
||||||
? html`
|
? html`
|
||||||
<ha-chip
|
<ha-assist-chip
|
||||||
hasIcon
|
filled
|
||||||
@click=${this._showMoreInfo}
|
@click=${this._showMoreInfo}
|
||||||
id="host_network"
|
id="host_network"
|
||||||
|
.label=${capitalizeFirstLetter(
|
||||||
|
this.supervisor.localize(
|
||||||
|
"addon.dashboard.capability.label.host"
|
||||||
|
)
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<ha-svg-icon slot="icon" .path=${mdiNetwork}> </ha-svg-icon>
|
<ha-svg-icon slot="icon" .path=${mdiNetwork}> </ha-svg-icon>
|
||||||
${this.supervisor.localize(
|
</ha-assist-chip>
|
||||||
"addon.dashboard.capability.label.host"
|
|
||||||
)}
|
|
||||||
</ha-chip>
|
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
${this.addon.full_access
|
${this.addon.full_access
|
||||||
? html`
|
? html`
|
||||||
<ha-chip
|
<ha-assist-chip
|
||||||
hasIcon
|
filled
|
||||||
@click=${this._showMoreInfo}
|
@click=${this._showMoreInfo}
|
||||||
id="full_access"
|
id="full_access"
|
||||||
|
.label=${capitalizeFirstLetter(
|
||||||
|
this.supervisor.localize(
|
||||||
|
"addon.dashboard.capability.label.hardware"
|
||||||
|
)
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<ha-svg-icon slot="icon" .path=${mdiChip}></ha-svg-icon>
|
<ha-svg-icon slot="icon" .path=${mdiChip}></ha-svg-icon>
|
||||||
${this.supervisor.localize(
|
</ha-assist-chip>
|
||||||
"addon.dashboard.capability.label.hardware"
|
|
||||||
)}
|
|
||||||
</ha-chip>
|
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
${this.addon.homeassistant_api
|
${this.addon.homeassistant_api
|
||||||
? html`
|
? html`
|
||||||
<ha-chip
|
<ha-assist-chip
|
||||||
hasIcon
|
filled
|
||||||
@click=${this._showMoreInfo}
|
@click=${this._showMoreInfo}
|
||||||
id="homeassistant_api"
|
id="homeassistant_api"
|
||||||
|
.label=${capitalizeFirstLetter(
|
||||||
|
this.supervisor.localize(
|
||||||
|
"addon.dashboard.capability.label.core"
|
||||||
|
)
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<ha-svg-icon
|
<ha-svg-icon
|
||||||
slot="icon"
|
slot="icon"
|
||||||
.path=${mdiHomeAssistant}
|
.path=${mdiHomeAssistant}
|
||||||
></ha-svg-icon>
|
></ha-svg-icon>
|
||||||
${this.supervisor.localize(
|
</ha-assist-chip>
|
||||||
"addon.dashboard.capability.label.core"
|
|
||||||
)}
|
|
||||||
</ha-chip>
|
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
${this._computeHassioApi
|
${this._computeHassioApi
|
||||||
? html`
|
? html`
|
||||||
<ha-chip hasIcon @click=${this._showMoreInfo} id="hassio_api">
|
<ha-assist-chip
|
||||||
|
filled
|
||||||
|
@click=${this._showMoreInfo}
|
||||||
|
id="hassio_api"
|
||||||
|
.label=${capitalizeFirstLetter(
|
||||||
|
this.supervisor.localize(
|
||||||
|
`addon.dashboard.capability.role.${this.addon.hassio_role}`
|
||||||
|
) || this.addon.hassio_role
|
||||||
|
)}
|
||||||
|
>
|
||||||
<ha-svg-icon
|
<ha-svg-icon
|
||||||
slot="icon"
|
slot="icon"
|
||||||
.path=${mdiHomeAssistant}
|
.path=${mdiHomeAssistant}
|
||||||
></ha-svg-icon>
|
></ha-svg-icon>
|
||||||
${this.supervisor.localize(
|
</ha-assist-chip>
|
||||||
`addon.dashboard.capability.role.${this.addon.hassio_role}`
|
|
||||||
) || this.addon.hassio_role}
|
|
||||||
</ha-chip>
|
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
${this.addon.docker_api
|
${this.addon.docker_api
|
||||||
? html`
|
? html`
|
||||||
<ha-chip hasIcon @click=${this._showMoreInfo} id="docker_api">
|
<ha-assist-chip
|
||||||
<ha-svg-icon slot="icon" .path=${mdiDocker}></ha-svg-icon>
|
filled
|
||||||
${this.supervisor.localize(
|
@click=${this._showMoreInfo}
|
||||||
|
id="docker_api"
|
||||||
|
.label=${capitalizeFirstLetter(
|
||||||
|
this.supervisor.localize(
|
||||||
"addon.dashboard.capability.label.docker"
|
"addon.dashboard.capability.label.docker"
|
||||||
|
)
|
||||||
)}
|
)}
|
||||||
</ha-chip>
|
>
|
||||||
|
<ha-svg-icon slot="icon" .path=${mdiDocker}></ha-svg-icon>
|
||||||
|
</ha-assist-chip>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
${this.addon.host_pid
|
${this.addon.host_pid
|
||||||
? html`
|
? html`
|
||||||
<ha-chip hasIcon @click=${this._showMoreInfo} id="host_pid">
|
<ha-assist-chip
|
||||||
<ha-svg-icon slot="icon" .path=${mdiPound}></ha-svg-icon>
|
filled
|
||||||
${this.supervisor.localize(
|
@click=${this._showMoreInfo}
|
||||||
|
id="host_pid"
|
||||||
|
.label=${capitalizeFirstLetter(
|
||||||
|
this.supervisor.localize(
|
||||||
"addon.dashboard.capability.label.host_pid"
|
"addon.dashboard.capability.label.host_pid"
|
||||||
|
)
|
||||||
)}
|
)}
|
||||||
</ha-chip>
|
>
|
||||||
|
<ha-svg-icon slot="icon" .path=${mdiPound}></ha-svg-icon>
|
||||||
|
</ha-assist-chip>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
${this.addon.apparmor !== "default"
|
${this.addon.apparmor !== "default"
|
||||||
? html`
|
? html`
|
||||||
<ha-chip
|
<ha-assist-chip
|
||||||
hasIcon
|
filled
|
||||||
@click=${this._showMoreInfo}
|
@click=${this._showMoreInfo}
|
||||||
class=${this._computeApparmorClassName}
|
class=${this._computeApparmorClassName}
|
||||||
id="apparmor"
|
id="apparmor"
|
||||||
|
.label=${capitalizeFirstLetter(
|
||||||
|
this.supervisor.localize(
|
||||||
|
"addon.dashboard.capability.label.apparmor"
|
||||||
|
)
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<ha-svg-icon slot="icon" .path=${mdiShield}></ha-svg-icon>
|
<ha-svg-icon slot="icon" .path=${mdiShield}></ha-svg-icon>
|
||||||
${this.supervisor.localize(
|
</ha-assist-chip>
|
||||||
"addon.dashboard.capability.label.apparmor"
|
|
||||||
)}
|
|
||||||
</ha-chip>
|
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
${this.addon.auth_api
|
${this.addon.auth_api
|
||||||
? html`
|
? html`
|
||||||
<ha-chip hasIcon @click=${this._showMoreInfo} id="auth_api">
|
<ha-assist-chip
|
||||||
<ha-svg-icon slot="icon" .path=${mdiKey}></ha-svg-icon>
|
filled
|
||||||
${this.supervisor.localize(
|
@click=${this._showMoreInfo}
|
||||||
|
id="auth_api"
|
||||||
|
.label=${capitalizeFirstLetter(
|
||||||
|
this.supervisor.localize(
|
||||||
"addon.dashboard.capability.label.auth"
|
"addon.dashboard.capability.label.auth"
|
||||||
|
)
|
||||||
)}
|
)}
|
||||||
</ha-chip>
|
>
|
||||||
|
<ha-svg-icon slot="icon" .path=${mdiKey}></ha-svg-icon>
|
||||||
|
</ha-assist-chip>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
${this.addon.ingress
|
${this.addon.ingress
|
||||||
? html`
|
? html`
|
||||||
<ha-chip hasIcon @click=${this._showMoreInfo} id="ingress">
|
<ha-assist-chip
|
||||||
|
filled
|
||||||
|
@click=${this._showMoreInfo}
|
||||||
|
id="ingress"
|
||||||
|
.label=${capitalizeFirstLetter(
|
||||||
|
this.supervisor.localize(
|
||||||
|
"addon.dashboard.capability.label.ingress"
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
>
|
||||||
<ha-svg-icon
|
<ha-svg-icon
|
||||||
slot="icon"
|
slot="icon"
|
||||||
.path=${mdiCursorDefaultClickOutline}
|
.path=${mdiCursorDefaultClickOutline}
|
||||||
></ha-svg-icon>
|
></ha-svg-icon>
|
||||||
${this.supervisor.localize(
|
</ha-assist-chip>
|
||||||
"addon.dashboard.capability.label.ingress"
|
|
||||||
)}
|
|
||||||
</ha-chip>
|
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
${this.addon.signed
|
${this.addon.signed
|
||||||
? html`
|
? html`
|
||||||
<ha-chip hasIcon @click=${this._showMoreInfo} id="signed">
|
<ha-assist-chip
|
||||||
<ha-svg-icon slot="icon" .path=${mdiLinkLock}></ha-svg-icon>
|
filled
|
||||||
${this.supervisor.localize(
|
@click=${this._showMoreInfo}
|
||||||
|
id="signed"
|
||||||
|
.label=${capitalizeFirstLetter(
|
||||||
|
this.supervisor.localize(
|
||||||
"addon.dashboard.capability.label.signed"
|
"addon.dashboard.capability.label.signed"
|
||||||
|
)
|
||||||
)}
|
)}
|
||||||
</ha-chip>
|
>
|
||||||
|
<ha-svg-icon slot="icon" .path=${mdiLinkLock}></ha-svg-icon>
|
||||||
|
</ha-assist-chip>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
</ha-chip-set>
|
</ha-chip-set>
|
||||||
@@ -1185,23 +1235,35 @@ class HassioAddonInfo extends LitElement {
|
|||||||
.description a {
|
.description a {
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
}
|
}
|
||||||
ha-chip {
|
ha-assist-chip {
|
||||||
text-transform: capitalize;
|
--md-sys-color-primary: var(--text-primary-color);
|
||||||
--ha-chip-text-color: var(--text-primary-color);
|
--md-sys-color-on-surface: var(--text-primary-color);
|
||||||
--ha-chip-background-color: var(--primary-color);
|
--ha-assist-chip-filled-container-color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.red {
|
.red {
|
||||||
--ha-chip-background-color: var(--label-badge-red, #df4c1e);
|
--ha-assist-chip-filled-container-color: var(
|
||||||
|
--label-badge-red,
|
||||||
|
#df4c1e
|
||||||
|
);
|
||||||
}
|
}
|
||||||
.blue {
|
.blue {
|
||||||
--ha-chip-background-color: var(--label-badge-blue, #039be5);
|
--ha-assist-chip-filled-container-color: var(
|
||||||
|
--label-badge-blue,
|
||||||
|
#039be5
|
||||||
|
);
|
||||||
}
|
}
|
||||||
.green {
|
.green {
|
||||||
--ha-chip-background-color: var(--label-badge-green, #0da035);
|
--ha-assist-chip-filled-container-color: var(
|
||||||
|
--label-badge-green,
|
||||||
|
#0da035
|
||||||
|
);
|
||||||
}
|
}
|
||||||
.yellow {
|
.yellow {
|
||||||
--ha-chip-background-color: var(--label-badge-yellow, #f4b400);
|
--ha-assist-chip-filled-container-color: var(
|
||||||
|
--label-badge-yellow,
|
||||||
|
#f4b400
|
||||||
|
);
|
||||||
}
|
}
|
||||||
.capabilities {
|
.capabilities {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
@@ -1260,9 +1322,6 @@ class HassioAddonInfo extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 720px) {
|
@media (max-width: 720px) {
|
||||||
ha-chip {
|
|
||||||
line-height: 36px;
|
|
||||||
}
|
|
||||||
.addon-options {
|
.addon-options {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -360,11 +360,9 @@ export class HassioBackups extends LitElement {
|
|||||||
if (this.supervisor!.info.state !== "running") {
|
if (this.supervisor!.info.state !== "running") {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
title: this.supervisor!.localize("backup.could_not_create"),
|
title: this.supervisor!.localize("backup.could_not_create"),
|
||||||
text: this.supervisor!.localize(
|
text: this.supervisor!.localize("backup.create_blocked_not_running", {
|
||||||
"backup.create_blocked_not_running",
|
state: this.supervisor!.info.state,
|
||||||
"state",
|
}),
|
||||||
this.supervisor!.info.state
|
|
||||||
),
|
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import Fuse from "fuse.js";
|
import Fuse from "fuse.js";
|
||||||
|
import type { IFuseOptions } from "fuse.js";
|
||||||
import { StoreAddon } from "../../../src/data/supervisor/store";
|
import { StoreAddon } from "../../../src/data/supervisor/store";
|
||||||
|
|
||||||
export function filterAndSort(addons: StoreAddon[], filter: string) {
|
export function filterAndSort(addons: StoreAddon[], filter: string) {
|
||||||
const options: Fuse.IFuseOptions<StoreAddon> = {
|
const options: IFuseOptions<StoreAddon> = {
|
||||||
keys: ["name", "description", "slug"],
|
keys: ["name", "description", "slug"],
|
||||||
isCaseSensitive: false,
|
isCaseSensitive: false,
|
||||||
minMatchCharLength: 2,
|
minMatchCharLength: 2,
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import { fileDownload } from "../../../../src/util/file_download";
|
|||||||
import "../../components/supervisor-backup-content";
|
import "../../components/supervisor-backup-content";
|
||||||
import type { SupervisorBackupContent } from "../../components/supervisor-backup-content";
|
import type { SupervisorBackupContent } from "../../components/supervisor-backup-content";
|
||||||
import { HassioBackupDialogParams } from "./show-dialog-hassio-backup";
|
import { HassioBackupDialogParams } from "./show-dialog-hassio-backup";
|
||||||
|
import { BackupOrRestoreKey } from "../../util/translations";
|
||||||
|
|
||||||
@customElement("dialog-hassio-backup")
|
@customElement("dialog-hassio-backup")
|
||||||
class HassioBackupDialog
|
class HassioBackupDialog
|
||||||
@@ -64,6 +65,13 @@ class HassioBackupDialog
|
|||||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _localize(key: BackupOrRestoreKey) {
|
||||||
|
return (
|
||||||
|
this._dialogParams!.supervisor?.localize(`backup.${key}`) ||
|
||||||
|
this._dialogParams!.localize!(`ui.panel.page-onboarding.restore.${key}`)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
if (!this._dialogParams || !this._backup) {
|
if (!this._dialogParams || !this._backup) {
|
||||||
return nothing;
|
return nothing;
|
||||||
@@ -79,7 +87,7 @@ class HassioBackupDialog
|
|||||||
<ha-header-bar>
|
<ha-header-bar>
|
||||||
<span slot="title">${this._backup.name}</span>
|
<span slot="title">${this._backup.name}</span>
|
||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
.label=${this.hass?.localize("ui.common.close") || "Close"}
|
.label=${this._localize("close")}
|
||||||
.path=${mdiClose}
|
.path=${mdiClose}
|
||||||
slot="actionItems"
|
slot="actionItems"
|
||||||
dialogAction="cancel"
|
dialogAction="cancel"
|
||||||
@@ -88,7 +96,8 @@ class HassioBackupDialog
|
|||||||
</div>
|
</div>
|
||||||
${this._restoringBackup
|
${this._restoringBackup
|
||||||
? html`<ha-circular-progress active></ha-circular-progress>`
|
? html`<ha-circular-progress active></ha-circular-progress>`
|
||||||
: html`<supervisor-backup-content
|
: html`
|
||||||
|
<supervisor-backup-content
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.supervisor=${this._dialogParams.supervisor}
|
.supervisor=${this._dialogParams.supervisor}
|
||||||
.backup=${this._backup}
|
.backup=${this._backup}
|
||||||
@@ -96,20 +105,21 @@ class HassioBackupDialog
|
|||||||
.localize=${this._dialogParams.localize}
|
.localize=${this._dialogParams.localize}
|
||||||
dialogInitialFocus
|
dialogInitialFocus
|
||||||
>
|
>
|
||||||
</supervisor-backup-content>`}
|
</supervisor-backup-content>
|
||||||
|
`}
|
||||||
${this._error
|
${this._error
|
||||||
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
|
||||||
: ""}
|
: nothing}
|
||||||
|
|
||||||
<mwc-button
|
<mwc-button
|
||||||
.disabled=${this._restoringBackup}
|
.disabled=${this._restoringBackup}
|
||||||
slot="secondaryAction"
|
slot="secondaryAction"
|
||||||
@click=${this._restoreClicked}
|
@click=${this._restoreClicked}
|
||||||
>
|
>
|
||||||
Restore
|
${this._localize("restore")}
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
|
|
||||||
${!this._dialogParams.onboarding
|
${!this._dialogParams.onboarding && this._dialogParams.supervisor
|
||||||
? html`<ha-button-menu
|
? html`<ha-button-menu
|
||||||
fixed
|
fixed
|
||||||
slot="primaryAction"
|
slot="primaryAction"
|
||||||
@@ -117,22 +127,24 @@ class HassioBackupDialog
|
|||||||
@closed=${stopPropagation}
|
@closed=${stopPropagation}
|
||||||
>
|
>
|
||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
.label=${this.hass!.localize("ui.common.menu") || "Menu"}
|
.label=${this._dialogParams.supervisor.localize(
|
||||||
|
"backup.more_actions"
|
||||||
|
)}
|
||||||
.path=${mdiDotsVertical}
|
.path=${mdiDotsVertical}
|
||||||
slot="trigger"
|
slot="trigger"
|
||||||
></ha-icon-button>
|
></ha-icon-button>
|
||||||
<mwc-list-item
|
<mwc-list-item
|
||||||
>${this._dialogParams.supervisor?.localize(
|
>${this._dialogParams.supervisor.localize(
|
||||||
"backup.download_backup"
|
"backup.download_backup"
|
||||||
)}</mwc-list-item
|
)}</mwc-list-item
|
||||||
>
|
>
|
||||||
<mwc-list-item class="error"
|
<mwc-list-item class="error"
|
||||||
>${this._dialogParams.supervisor?.localize(
|
>${this._dialogParams.supervisor.localize(
|
||||||
"backup.delete_backup_title"
|
"backup.delete_backup_title"
|
||||||
)}</mwc-list-item
|
)}</mwc-list-item
|
||||||
>
|
>
|
||||||
</ha-button-menu>`
|
</ha-button-menu>`
|
||||||
: ""}
|
: nothing}
|
||||||
</ha-dialog>
|
</ha-dialog>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -183,21 +195,22 @@ class HassioBackupDialog
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _partialRestoreClicked(backupDetails) {
|
private async _partialRestoreClicked(backupDetails) {
|
||||||
if (
|
const supervisor = this._dialogParams?.supervisor;
|
||||||
this._dialogParams?.supervisor !== undefined &&
|
if (supervisor !== undefined && supervisor.info.state !== "running") {
|
||||||
this._dialogParams?.supervisor.info.state !== "running"
|
|
||||||
) {
|
|
||||||
await showAlertDialog(this, {
|
await showAlertDialog(this, {
|
||||||
title: "Could not restore backup",
|
title: supervisor.localize("backup.could_not_restore"),
|
||||||
text: `Restoring a backup is not possible right now because the system is in ${this._dialogParams?.supervisor.info.state} state.`,
|
text: supervisor.localize("backup.restore_blocked_not_running", {
|
||||||
|
state: supervisor.info.state,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
!(await showConfirmationDialog(this, {
|
!(await showConfirmationDialog(this, {
|
||||||
title: "Are you sure you want to restore this partial backup?",
|
title: this._localize("confirm_restore_partial_backup_title"),
|
||||||
confirmText: "restore",
|
text: this._localize("confirm_restore_partial_backup_text"),
|
||||||
dismissText: "cancel",
|
confirmText: this._localize("restore"),
|
||||||
|
dismissText: this._localize("cancel"),
|
||||||
}))
|
}))
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
@@ -230,22 +243,22 @@ class HassioBackupDialog
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _fullRestoreClicked(backupDetails) {
|
private async _fullRestoreClicked(backupDetails) {
|
||||||
if (
|
const supervisor = this._dialogParams?.supervisor;
|
||||||
this._dialogParams?.supervisor !== undefined &&
|
if (supervisor !== undefined && supervisor.info.state !== "running") {
|
||||||
this._dialogParams?.supervisor.info.state !== "running"
|
|
||||||
) {
|
|
||||||
await showAlertDialog(this, {
|
await showAlertDialog(this, {
|
||||||
title: "Could not restore backup",
|
title: supervisor.localize("backup.could_not_restore"),
|
||||||
text: `Restoring a backup is not possible right now because the system is in ${this._dialogParams?.supervisor.info.state} state.`,
|
text: supervisor.localize("backup.restore_blocked_not_running", {
|
||||||
|
state: supervisor.info.state,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
!(await showConfirmationDialog(this, {
|
!(await showConfirmationDialog(this, {
|
||||||
title:
|
title: this._localize("confirm_restore_full_backup_title"),
|
||||||
"Are you sure you want to wipe your system and restore this backup?",
|
text: this._localize("confirm_restore_full_backup_text"),
|
||||||
confirmText: "restore",
|
confirmText: this._localize("restore"),
|
||||||
dismissText: "cancel",
|
dismissText: this._localize("cancel"),
|
||||||
}))
|
}))
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
@@ -279,11 +292,15 @@ class HassioBackupDialog
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _deleteClicked() {
|
private async _deleteClicked() {
|
||||||
|
const supervisor = this._dialogParams?.supervisor;
|
||||||
|
if (!supervisor) return;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!(await showConfirmationDialog(this, {
|
!(await showConfirmationDialog(this, {
|
||||||
title: "Are you sure you want to delete this backup?",
|
title: supervisor!.localize("backup.confirm_delete_title"),
|
||||||
confirmText: "delete",
|
text: supervisor!.localize("backup.confirm_delete_text"),
|
||||||
dismissText: "cancel",
|
confirmText: supervisor!.localize("backup.delete"),
|
||||||
|
dismissText: supervisor!.localize("backup.cancel"),
|
||||||
}))
|
}))
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
@@ -301,6 +318,9 @@ class HassioBackupDialog
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _downloadClicked() {
|
private async _downloadClicked() {
|
||||||
|
const supervisor = this._dialogParams?.supervisor;
|
||||||
|
if (!supervisor) return;
|
||||||
|
|
||||||
let signedPath: { path: string };
|
let signedPath: { path: string };
|
||||||
try {
|
try {
|
||||||
signedPath = await getSignedPath(
|
signedPath = await getSignedPath(
|
||||||
@@ -320,10 +340,10 @@ class HassioBackupDialog
|
|||||||
|
|
||||||
if (window.location.href.includes("ui.nabu.casa")) {
|
if (window.location.href.includes("ui.nabu.casa")) {
|
||||||
const confirm = await showConfirmationDialog(this, {
|
const confirm = await showConfirmationDialog(this, {
|
||||||
title: "Potential slow download",
|
title: supervisor.localize("backup.remote_download_title"),
|
||||||
text: "Downloading backups over the Nabu Casa URL will take some time, it is recomended to use your local URL instead, do you want to continue?",
|
text: supervisor.localize("backup.remote_download_text"),
|
||||||
confirmText: "continue",
|
confirmText: supervisor.localize("backup.download"),
|
||||||
dismissText: "cancel",
|
dismissText: this._localize("cancel"),
|
||||||
});
|
});
|
||||||
if (!confirm) {
|
if (!confirm) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -89,8 +89,7 @@ class HassioCreateBackupDialog extends LitElement {
|
|||||||
),
|
),
|
||||||
text: this._dialogParams!.supervisor.localize(
|
text: this._dialogParams!.supervisor.localize(
|
||||||
"backup.create_blocked_not_running",
|
"backup.create_blocked_not_running",
|
||||||
"state",
|
{ state: this._dialogParams!.supervisor.info.state }
|
||||||
this._dialogParams!.supervisor.info.state
|
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { mdiClose } from "@mdi/js";
|
import { mdiClose } from "@mdi/js";
|
||||||
|
import { dump } from "js-yaml";
|
||||||
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
|
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
@@ -9,7 +10,6 @@ import "../../../../src/components/ha-expansion-panel";
|
|||||||
import "../../../../src/components/ha-icon-button";
|
import "../../../../src/components/ha-icon-button";
|
||||||
import "../../../../src/components/search-input";
|
import "../../../../src/components/search-input";
|
||||||
import { HassioHardwareInfo } from "../../../../src/data/hassio/hardware";
|
import { HassioHardwareInfo } from "../../../../src/data/hassio/hardware";
|
||||||
import { dump } from "../../../../src/resources/js-yaml-dump";
|
|
||||||
import { haStyle, haStyleDialog } from "../../../../src/resources/styles";
|
import { haStyle, haStyleDialog } from "../../../../src/resources/styles";
|
||||||
import { HomeAssistant } from "../../../../src/types";
|
import { HomeAssistant } from "../../../../src/types";
|
||||||
import { HassioHardwareDialogParams } from "./show-dialog-hassio-hardware";
|
import { HassioHardwareDialogParams } from "./show-dialog-hassio-hardware";
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
// Compat needs to be first import
|
// Compat needs to be first import
|
||||||
import "../../src/resources/compatibility";
|
import "../../src/resources/compatibility";
|
||||||
import { setCancelSyntheticClickEvents } from "@polymer/polymer/lib/utils/settings";
|
|
||||||
import "../../src/resources/roboto";
|
|
||||||
import "../../src/resources/ha-style";
|
|
||||||
import "../../src/resources/safari-14-attachshadow-patch";
|
import "../../src/resources/safari-14-attachshadow-patch";
|
||||||
import "./hassio-main";
|
import "./hassio-main";
|
||||||
|
|
||||||
setCancelSyntheticClickEvents(false);
|
import("../../src/resources/ha-style");
|
||||||
|
import("@polymer/polymer/lib/utils/settings").then(
|
||||||
|
({ setCancelSyntheticClickEvents }) => setCancelSyntheticClickEvents(false)
|
||||||
|
);
|
||||||
|
|
||||||
const styleEl = document.createElement("style");
|
const styleEl = document.createElement("style");
|
||||||
styleEl.innerHTML = `
|
styleEl.textContent = `
|
||||||
body {
|
body {
|
||||||
font-family: Roboto, sans-serif;
|
font-family: Roboto, sans-serif;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
|||||||
4
hassio/src/util/translations.ts
Normal file
4
hassio/src/util/translations.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import type { TranslationDict } from "../../../src/types";
|
||||||
|
|
||||||
|
export type BackupOrRestoreKey = keyof TranslationDict["supervisor"]["backup"] &
|
||||||
|
keyof TranslationDict["ui"]["panel"]["page-onboarding"]["restore"];
|
||||||
153
package.json
153
package.json
@@ -25,24 +25,24 @@
|
|||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "7.23.1",
|
"@babel/runtime": "7.23.2",
|
||||||
"@braintree/sanitize-url": "6.0.4",
|
"@braintree/sanitize-url": "6.0.4",
|
||||||
"@codemirror/autocomplete": "6.9.1",
|
"@codemirror/autocomplete": "6.11.0",
|
||||||
"@codemirror/commands": "6.2.5",
|
"@codemirror/commands": "6.3.0",
|
||||||
"@codemirror/language": "6.9.1",
|
"@codemirror/language": "6.9.2",
|
||||||
"@codemirror/legacy-modes": "6.3.3",
|
"@codemirror/legacy-modes": "6.3.3",
|
||||||
"@codemirror/search": "6.5.4",
|
"@codemirror/search": "6.5.4",
|
||||||
"@codemirror/state": "6.2.1",
|
"@codemirror/state": "6.3.1",
|
||||||
"@codemirror/view": "6.20.2",
|
"@codemirror/view": "6.22.0",
|
||||||
"@egjs/hammerjs": "2.0.17",
|
"@egjs/hammerjs": "2.0.17",
|
||||||
"@formatjs/intl-datetimeformat": "6.10.3",
|
"@formatjs/intl-datetimeformat": "6.11.2",
|
||||||
"@formatjs/intl-displaynames": "6.5.2",
|
"@formatjs/intl-displaynames": "6.6.2",
|
||||||
"@formatjs/intl-getcanonicallocales": "2.2.1",
|
"@formatjs/intl-getcanonicallocales": "2.3.0",
|
||||||
"@formatjs/intl-listformat": "7.4.2",
|
"@formatjs/intl-listformat": "7.5.1",
|
||||||
"@formatjs/intl-locale": "3.3.4",
|
"@formatjs/intl-locale": "3.4.1",
|
||||||
"@formatjs/intl-numberformat": "8.7.2",
|
"@formatjs/intl-numberformat": "8.8.1",
|
||||||
"@formatjs/intl-pluralrules": "5.2.6",
|
"@formatjs/intl-pluralrules": "5.2.8",
|
||||||
"@formatjs/intl-relativetimeformat": "11.2.6",
|
"@formatjs/intl-relativetimeformat": "11.2.8",
|
||||||
"@fullcalendar/core": "6.1.9",
|
"@fullcalendar/core": "6.1.9",
|
||||||
"@fullcalendar/daygrid": "6.1.9",
|
"@fullcalendar/daygrid": "6.1.9",
|
||||||
"@fullcalendar/interaction": "6.1.9",
|
"@fullcalendar/interaction": "6.1.9",
|
||||||
@@ -51,11 +51,13 @@
|
|||||||
"@fullcalendar/timegrid": "6.1.9",
|
"@fullcalendar/timegrid": "6.1.9",
|
||||||
"@lezer/highlight": "1.1.6",
|
"@lezer/highlight": "1.1.6",
|
||||||
"@lit-labs/context": "0.4.1",
|
"@lit-labs/context": "0.4.1",
|
||||||
"@lit-labs/motion": "1.0.4",
|
"@lit-labs/motion": "1.0.6",
|
||||||
"@lit-labs/virtualizer": "2.0.7",
|
"@lit-labs/observers": "2.0.2",
|
||||||
|
"@lit-labs/virtualizer": "2.0.10",
|
||||||
"@lrnwebcomponents/simple-tooltip": "7.0.18",
|
"@lrnwebcomponents/simple-tooltip": "7.0.18",
|
||||||
"@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-button": "0.27.0",
|
"@material/mwc-button": "0.27.0",
|
||||||
"@material/mwc-checkbox": "0.27.0",
|
"@material/mwc-checkbox": "0.27.0",
|
||||||
"@material/mwc-circular-progress": "0.27.0",
|
"@material/mwc-circular-progress": "0.27.0",
|
||||||
@@ -71,7 +73,6 @@
|
|||||||
"@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-slider": "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,22 +81,21 @@
|
|||||||
"@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.0.0-pre.17",
|
"@material/web": "=1.0.1",
|
||||||
"@mdi/js": "7.2.96",
|
"@mdi/js": "7.3.67",
|
||||||
"@mdi/svg": "7.2.96",
|
"@mdi/svg": "7.3.67",
|
||||||
"@polymer/iron-flex-layout": "3.0.1",
|
"@polymer/iron-flex-layout": "3.0.1",
|
||||||
"@polymer/iron-input": "3.0.1",
|
"@polymer/iron-input": "3.0.1",
|
||||||
"@polymer/iron-resizable-behavior": "3.0.1",
|
"@polymer/iron-resizable-behavior": "3.0.1",
|
||||||
"@polymer/paper-input": "3.2.1",
|
"@polymer/paper-input": "3.2.1",
|
||||||
"@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-slider": "3.0.1",
|
|
||||||
"@polymer/paper-tabs": "3.1.0",
|
"@polymer/paper-tabs": "3.1.0",
|
||||||
"@polymer/paper-toast": "3.0.1",
|
"@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.1.9",
|
"@vaadin/combo-box": "24.2.2",
|
||||||
"@vaadin/vaadin-themable-mixin": "24.1.9",
|
"@vaadin/vaadin-themable-mixin": "24.2.2",
|
||||||
"@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",
|
||||||
@@ -105,28 +105,28 @@
|
|||||||
"app-datepicker": "5.1.1",
|
"app-datepicker": "5.1.1",
|
||||||
"chart.js": "4.4.0",
|
"chart.js": "4.4.0",
|
||||||
"comlink": "4.4.1",
|
"comlink": "4.4.1",
|
||||||
"core-js": "3.32.2",
|
"core-js": "3.33.2",
|
||||||
"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.0",
|
||||||
"deep-clone-simple": "1.1.1",
|
"deep-clone-simple": "1.1.1",
|
||||||
"deep-freeze": "0.0.1",
|
"deep-freeze": "0.0.1",
|
||||||
"fuse.js": "6.6.2",
|
"fuse.js": "7.0.0",
|
||||||
"google-timezones-json": "1.2.0",
|
"google-timezones-json": "1.2.0",
|
||||||
"hls.js": "1.4.12",
|
"hls.js": "1.4.12",
|
||||||
"home-assistant-js-websocket": "8.2.0",
|
"home-assistant-js-websocket": "9.1.0",
|
||||||
"idb-keyval": "6.2.1",
|
"idb-keyval": "6.2.1",
|
||||||
"intl-messageformat": "10.5.3",
|
"intl-messageformat": "10.5.5",
|
||||||
"js-yaml": "4.1.0",
|
"js-yaml": "4.1.0",
|
||||||
"leaflet": "1.9.4",
|
"leaflet": "1.9.4",
|
||||||
"leaflet-draw": "1.0.4",
|
"leaflet-draw": "1.0.4",
|
||||||
"lit": "2.8.0",
|
"lit": "2.8.0",
|
||||||
"luxon": "3.4.3",
|
"luxon": "3.4.3",
|
||||||
"marked": "9.0.3",
|
"marked": "9.1.6",
|
||||||
"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",
|
||||||
"punycode": "2.3.0",
|
"punycode": "2.3.1",
|
||||||
"qr-scanner": "1.4.2",
|
"qr-scanner": "1.4.2",
|
||||||
"qrcode": "1.5.3",
|
"qrcode": "1.5.3",
|
||||||
"resize-observer-polyfill": "1.5.1",
|
"resize-observer-polyfill": "1.5.1",
|
||||||
@@ -138,11 +138,11 @@
|
|||||||
"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",
|
||||||
"ua-parser-js": "1.0.36",
|
"ua-parser-js": "1.0.37",
|
||||||
"unfetch": "5.0.0",
|
"unfetch": "5.0.0",
|
||||||
"vis-data": "7.1.7",
|
"vis-data": "7.1.8",
|
||||||
"vis-network": "9.1.6",
|
"vis-network": "9.1.9",
|
||||||
"vue": "2.7.14",
|
"vue": "2.7.15",
|
||||||
"vue2-daterange-picker": "0.6.8",
|
"vue2-daterange-picker": "0.6.8",
|
||||||
"weekstart": "2.0.0",
|
"weekstart": "2.0.0",
|
||||||
"workbox-cacheable-response": "7.0.0",
|
"workbox-cacheable-response": "7.0.0",
|
||||||
@@ -154,62 +154,61 @@
|
|||||||
"xss": "1.0.14"
|
"xss": "1.0.14"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "7.23.0",
|
"@babel/core": "7.23.3",
|
||||||
"@babel/plugin-proposal-decorators": "7.23.0",
|
"@babel/plugin-proposal-decorators": "7.23.3",
|
||||||
"@babel/plugin-transform-runtime": "7.22.15",
|
"@babel/plugin-transform-runtime": "7.23.3",
|
||||||
"@babel/preset-env": "7.22.20",
|
"@babel/preset-env": "7.23.3",
|
||||||
"@babel/preset-typescript": "7.23.0",
|
"@babel/preset-typescript": "7.23.3",
|
||||||
|
"@bundle-stats/plugin-webpack-filter": "4.8.0",
|
||||||
"@koa/cors": "4.0.0",
|
"@koa/cors": "4.0.0",
|
||||||
"@lokalise/node-api": "12.0.0",
|
"@lokalise/node-api": "12.0.0",
|
||||||
"@octokit/auth-oauth-device": "6.0.1",
|
"@octokit/auth-oauth-device": "6.0.1",
|
||||||
"@octokit/plugin-retry": "6.0.1",
|
"@octokit/plugin-retry": "6.0.1",
|
||||||
"@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.3",
|
"@rollup/plugin-babel": "6.0.4",
|
||||||
"@rollup/plugin-commonjs": "25.0.4",
|
"@rollup/plugin-commonjs": "25.0.7",
|
||||||
"@rollup/plugin-json": "6.0.0",
|
"@rollup/plugin-json": "6.0.1",
|
||||||
"@rollup/plugin-node-resolve": "15.2.1",
|
"@rollup/plugin-node-resolve": "15.2.3",
|
||||||
"@rollup/plugin-replace": "5.0.2",
|
"@rollup/plugin-replace": "5.0.5",
|
||||||
"@types/babel__plugin-transform-runtime": "7.9.3",
|
"@types/babel__plugin-transform-runtime": "7.9.5",
|
||||||
"@types/chromecast-caf-receiver": "6.0.10",
|
"@types/chromecast-caf-receiver": "6.0.12",
|
||||||
"@types/chromecast-caf-sender": "1.0.6",
|
"@types/chromecast-caf-sender": "1.0.8",
|
||||||
"@types/esprima": "4.0.4",
|
|
||||||
"@types/glob": "8.1.0",
|
"@types/glob": "8.1.0",
|
||||||
"@types/html-minifier-terser": "7.0.0",
|
"@types/html-minifier-terser": "7.0.2",
|
||||||
"@types/js-yaml": "4.0.6",
|
"@types/js-yaml": "4.0.9",
|
||||||
"@types/leaflet": "1.9.6",
|
"@types/leaflet": "1.9.8",
|
||||||
"@types/leaflet-draw": "1.0.8",
|
"@types/leaflet-draw": "1.0.10",
|
||||||
"@types/luxon": "3.3.2",
|
"@types/luxon": "3.3.4",
|
||||||
"@types/mocha": "10.0.1",
|
"@types/mocha": "10.0.4",
|
||||||
"@types/qrcode": "1.5.2",
|
"@types/qrcode": "1.5.5",
|
||||||
"@types/serve-handler": "6.1.2",
|
"@types/serve-handler": "6.1.4",
|
||||||
"@types/sortablejs": "1.15.3",
|
"@types/sortablejs": "1.15.5",
|
||||||
"@types/tar": "6.1.6",
|
"@types/tar": "6.1.9",
|
||||||
"@types/ua-parser-js": "0.7.37",
|
"@types/ua-parser-js": "0.7.39",
|
||||||
"@types/webspeechapi": "0.0.29",
|
"@types/webspeechapi": "0.0.29",
|
||||||
"@typescript-eslint/eslint-plugin": "6.7.3",
|
"@typescript-eslint/eslint-plugin": "6.10.0",
|
||||||
"@typescript-eslint/parser": "6.7.3",
|
"@typescript-eslint/parser": "6.10.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": "4.3.8",
|
"chai": "4.3.10",
|
||||||
"del": "7.1.0",
|
"del": "7.1.0",
|
||||||
"eslint": "8.50.0",
|
"eslint": "8.53.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": "17.1.0",
|
||||||
"eslint-config-prettier": "9.0.0",
|
"eslint-config-prettier": "9.0.0",
|
||||||
"eslint-import-resolver-webpack": "0.13.7",
|
"eslint-import-resolver-webpack": "0.13.8",
|
||||||
"eslint-plugin-disable": "2.0.3",
|
"eslint-plugin-disable": "2.0.3",
|
||||||
"eslint-plugin-import": "2.28.1",
|
"eslint-plugin-import": "2.29.0",
|
||||||
"eslint-plugin-lit": "1.9.1",
|
"eslint-plugin-lit": "1.10.1",
|
||||||
"eslint-plugin-lit-a11y": "4.1.0",
|
"eslint-plugin-lit-a11y": "4.1.1",
|
||||||
"eslint-plugin-unused-imports": "3.0.0",
|
"eslint-plugin-unused-imports": "3.0.0",
|
||||||
"eslint-plugin-wc": "2.0.4",
|
"eslint-plugin-wc": "2.0.4",
|
||||||
"esprima": "4.0.1",
|
|
||||||
"fancy-log": "2.0.0",
|
"fancy-log": "2.0.0",
|
||||||
"fs-extra": "11.1.1",
|
"fs-extra": "11.1.1",
|
||||||
"glob": "10.3.7",
|
"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.4.8",
|
||||||
@@ -220,10 +219,10 @@
|
|||||||
"husky": "8.0.3",
|
"husky": "8.0.3",
|
||||||
"instant-mocha": "1.5.2",
|
"instant-mocha": "1.5.2",
|
||||||
"jszip": "3.10.1",
|
"jszip": "3.10.1",
|
||||||
"lint-staged": "14.0.1",
|
"lint-staged": "15.1.0",
|
||||||
"lit-analyzer": "2.0.0-pre.3",
|
"lit-analyzer": "2.0.1",
|
||||||
"lodash.template": "4.5.0",
|
"lodash.template": "4.5.0",
|
||||||
"magic-string": "0.30.3",
|
"magic-string": "0.30.5",
|
||||||
"map-stream": "0.0.7",
|
"map-stream": "0.0.7",
|
||||||
"mocha": "10.2.0",
|
"mocha": "10.2.0",
|
||||||
"object-hash": "3.0.0",
|
"object-hash": "3.0.0",
|
||||||
@@ -235,19 +234,20 @@
|
|||||||
"rollup-plugin-terser": "7.0.2",
|
"rollup-plugin-terser": "7.0.2",
|
||||||
"rollup-plugin-visualizer": "5.9.2",
|
"rollup-plugin-visualizer": "5.9.2",
|
||||||
"serve-handler": "6.1.5",
|
"serve-handler": "6.1.5",
|
||||||
"sinon": "16.0.0",
|
"sinon": "17.0.1",
|
||||||
"source-map-url": "0.4.1",
|
"source-map-url": "0.4.1",
|
||||||
"systemjs": "6.14.2",
|
"systemjs": "6.14.2",
|
||||||
"tar": "6.2.0",
|
"tar": "6.2.0",
|
||||||
"terser-webpack-plugin": "5.3.9",
|
"terser-webpack-plugin": "5.3.9",
|
||||||
"ts-lit-plugin": "2.0.0-pre.1",
|
"ts-lit-plugin": "2.0.1",
|
||||||
"typescript": "5.2.2",
|
"typescript": "5.2.2",
|
||||||
"vinyl-buffer": "1.0.1",
|
"vinyl-buffer": "1.0.1",
|
||||||
"vinyl-source-stream": "2.0.0",
|
"vinyl-source-stream": "2.0.0",
|
||||||
"webpack": "5.88.2",
|
"webpack": "5.89.0",
|
||||||
"webpack-cli": "5.1.4",
|
"webpack-cli": "5.1.4",
|
||||||
"webpack-dev-server": "4.15.1",
|
"webpack-dev-server": "4.15.1",
|
||||||
"webpack-manifest-plugin": "5.0.0",
|
"webpack-manifest-plugin": "5.0.0",
|
||||||
|
"webpack-stats-plugin": "1.1.3",
|
||||||
"webpackbar": "5.0.2",
|
"webpackbar": "5.0.2",
|
||||||
"workbox-build": "7.0.0"
|
"workbox-build": "7.0.0"
|
||||||
},
|
},
|
||||||
@@ -255,8 +255,11 @@
|
|||||||
"resolutions": {
|
"resolutions": {
|
||||||
"@polymer/polymer": "patch:@polymer/polymer@3.5.1#./.yarn/patches/@polymer/polymer/pr-5569.patch",
|
"@polymer/polymer": "patch:@polymer/polymer@3.5.1#./.yarn/patches/@polymer/polymer/pr-5569.patch",
|
||||||
"@material/mwc-button@^0.25.3": "^0.27.0",
|
"@material/mwc-button@^0.25.3": "^0.27.0",
|
||||||
|
"lit": "2.8.0",
|
||||||
|
"clean-css": "5.3.2",
|
||||||
|
"@lit/reactive-element": "1.6.3",
|
||||||
"sortablejs@1.15.0": "patch:sortablejs@npm%3A1.15.0#./.yarn/patches/sortablejs-npm-1.15.0-f3a393abcc.patch",
|
"sortablejs@1.15.0": "patch:sortablejs@npm%3A1.15.0#./.yarn/patches/sortablejs-npm-1.15.0-f3a393abcc.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@3.6.3"
|
"packageManager": "yarn@4.0.1"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1 @@
|
|||||||
<?xml version="1.0" standalone="no"?>
|
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="640" viewBox="0 0 240 240"><path d="M120.001 0c-3.787 0-7.573 1.499-10.444 4.49L12.211 105.905a25.921 25.921 0 0 0-2.098 2.501 35.25 35.25 0 0 0-1.96 2.942c-3.01 5.021-5.285 11.318-6.074 16.898-.03.21-.088.429-.11.636a27.355 27.355 0 0 0-.213 3.317v93.023a14.78 14.78 90 0 0 14.78 14.78h90.92L67.422 198.29a20.2 20.2 90 1 1 12.542-13.06l31.17 32.474V98.726a20.2 20.2 90 1 1 17.734 0v83.44l31.001-32.299a20.2 20.2 90 1 1 12.267 13.357l-43.269 45.082V240h94.9a14.479 14.479 90 0 0 14.478-14.479v-93.314c0-1.059-.069-2.168-.214-3.314-.7-5.73-3.06-12.327-6.183-17.537a35.801 35.801 0 0 0-1.955-2.937 26.271 26.271 0 0 0-2.102-2.506L130.444 4.486C127.573 1.494 123.786-.002 120.001 0"/></svg>
|
||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
|
||||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
|
||||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
|
||||||
width="480.000000pt" height="480.000000pt" viewBox="0 0 480.000000 480.000000"
|
|
||||||
preserveAspectRatio="xMidYMid meet">
|
|
||||||
<g transform="translate(0.000000,480.000000) scale(0.100000,-0.100000)"
|
|
||||||
fill="#000000" stroke="none">
|
|
||||||
<path d="M2313 4666 c-23 -7 -56 -23 -75 -34 -47 -30 -2059 -2048 -2095 -2102
|
|
||||||
-45 -67 -77 -135 -109 -230 l-29 -85 0 -995 0 -995 27 -51 c31 -59 93 -118
|
|
||||||
152 -145 39 -18 83 -19 1001 -19 l960 0 -406 405 c-395 395 -406 406 -433 395
|
|
||||||
-15 -5 -63 -10 -107 -10 -429 0 -566 577 -181 767 67 34 86 38 164 42 105 4
|
|
||||||
165 -13 246 -67 113 -74 175 -190 176 -327 1 -44 -3 -96 -7 -115 l-8 -35 316
|
|
||||||
-315 315 -315 0 1160 -1 1160 -51 35 c-260 177 -226 567 62 704 82 39 209 48
|
|
||||||
293 21 239 -78 354 -352 242 -575 -32 -63 -89 -125 -141 -156 l-44 -26 0 -811
|
|
||||||
0 -812 315 315 c218 217 313 320 309 330 -14 35 -16 134 -4 190 26 122 111
|
|
||||||
227 230 284 82 39 209 48 293 21 115 -38 214 -130 258 -242 19 -46 23 -78 24
|
|
||||||
-153 0 -86 -3 -101 -32 -163 -40 -84 -118 -163 -198 -202 -49 -23 -77 -29
|
|
||||||
-150 -33 -50 -2 -108 1 -130 7 l-40 11 -437 -438 -438 -437 0 -307 0 -308 998
|
|
||||||
0 c981 0 998 1 1042 21 58 26 115 81 148 144 l27 50 0 995 0 995 -33 95 c-72
|
|
||||||
209 -6 135 -1147 1278 -840 843 -1040 1037 -1082 1059 -64 31 -159 39 -220 19z"/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 747 B |
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "home-assistant-frontend"
|
name = "home-assistant-frontend"
|
||||||
version = "20230928.0"
|
version = "20231030.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"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
|
"configMigration": true,
|
||||||
"extends": [
|
"extends": [
|
||||||
":ignoreModulesAndTests",
|
":ignoreModulesAndTests",
|
||||||
":label(Dependencies)",
|
":label(Dependencies)",
|
||||||
@@ -10,7 +11,7 @@
|
|||||||
"group:recommended",
|
"group:recommended",
|
||||||
"npm:unpublishSafe"
|
"npm:unpublishSafe"
|
||||||
],
|
],
|
||||||
"enabledManagers": ["npm"],
|
"enabledManagers": ["npm", "nvm"],
|
||||||
"postUpdateOptions": ["yarnDedupeHighest"],
|
"postUpdateOptions": ["yarnDedupeHighest"],
|
||||||
"lockFileMaintenance": {
|
"lockFileMaintenance": {
|
||||||
"description": ["Run after patch releases but before next beta"],
|
"description": ["Run after patch releases but before next beta"],
|
||||||
@@ -28,11 +29,22 @@
|
|||||||
"matchPackageNames": ["vue"],
|
"matchPackageNames": ["vue"],
|
||||||
"allowedVersions": "< 3"
|
"allowedVersions": "< 3"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"description": "Group MDI packages",
|
||||||
|
"groupName": "Material Design Icons",
|
||||||
|
"matchPackageNames": ["@mdi/js", "@mdi/svg"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"description": "Group tsparticles engine and presets",
|
"description": "Group tsparticles engine and presets",
|
||||||
"groupName": "tsparticles",
|
"groupName": "tsparticles",
|
||||||
"matchPackageNames": ["tsparticles-engine"],
|
"matchPackageNames": ["tsparticles-engine"],
|
||||||
"matchPackagePrefixes": ["tsparticles-preset-"]
|
"matchPackagePrefixes": ["tsparticles-preset-"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Group and temporarily disable WDS packages",
|
||||||
|
"groupName": "Web Dev Server",
|
||||||
|
"matchPackagePrefixes": ["@web/dev-server"],
|
||||||
|
"enabled": false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ fi
|
|||||||
|
|
||||||
docker run \
|
docker run \
|
||||||
-v ${LOCAL_FILE}:/opt/src/${LOCAL_FILE} \
|
-v ${LOCAL_FILE}:/opt/src/${LOCAL_FILE} \
|
||||||
lokalise/lokalise-cli-2@sha256:f1860b26be22fa73b8c93bc5f8690f2afc867610a42de6fc27adc790e5d4425d lokalise2 \
|
lokalise/lokalise-cli-2:v2.6.10 lokalise2 \
|
||||||
--token ${LOKALISE_TOKEN} \
|
--token ${LOKALISE_TOKEN} \
|
||||||
--project-id ${PROJECT_ID} \
|
--project-id ${PROJECT_ID} \
|
||||||
file upload \
|
file upload \
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import "../components/ha-alert";
|
|||||||
import "../components/ha-checkbox";
|
import "../components/ha-checkbox";
|
||||||
import { computeInitialHaFormData } from "../components/ha-form/compute-initial-ha-form-data";
|
import { computeInitialHaFormData } from "../components/ha-form/compute-initial-ha-form-data";
|
||||||
import "../components/ha-formfield";
|
import "../components/ha-formfield";
|
||||||
import "../components/ha-markdown";
|
|
||||||
import { AuthProvider, autocompleteLoginFields } from "../data/auth";
|
import { AuthProvider, autocompleteLoginFields } from "../data/auth";
|
||||||
import {
|
import {
|
||||||
DataEntryFlowStep,
|
DataEntryFlowStep,
|
||||||
@@ -182,24 +181,13 @@ export class HaAuthFlow extends LitElement {
|
|||||||
case "abort":
|
case "abort":
|
||||||
return html`
|
return html`
|
||||||
${this.localize("ui.panel.page-authorize.abort_intro")}:
|
${this.localize("ui.panel.page-authorize.abort_intro")}:
|
||||||
<ha-markdown
|
${this.localize(
|
||||||
allowsvg
|
|
||||||
breaks
|
|
||||||
.content=${this.localize(
|
|
||||||
`ui.panel.page-authorize.form.providers.${step.handler[0]}.abort.${step.reason}`
|
`ui.panel.page-authorize.form.providers.${step.handler[0]}.abort.${step.reason}`
|
||||||
)}
|
)}
|
||||||
></ha-markdown>
|
|
||||||
`;
|
`;
|
||||||
case "form":
|
case "form":
|
||||||
return html`
|
return html`
|
||||||
${this._computeStepDescription(step)
|
${this._computeStepDescription(step)}
|
||||||
? html`
|
|
||||||
<ha-markdown
|
|
||||||
breaks
|
|
||||||
.content=${this._computeStepDescription(step)}
|
|
||||||
></ha-markdown>
|
|
||||||
`
|
|
||||||
: nothing}
|
|
||||||
<ha-auth-form
|
<ha-auth-form
|
||||||
.data=${this._stepData}
|
.data=${this._stepData}
|
||||||
.schema=${autocompleteLoginFields(step.data_schema)}
|
.schema=${autocompleteLoginFields(step.data_schema)}
|
||||||
@@ -314,13 +302,7 @@ export class HaAuthFlow extends LitElement {
|
|||||||
private _computeStepDescription(step: DataEntryFlowStepForm) {
|
private _computeStepDescription(step: DataEntryFlowStepForm) {
|
||||||
const resourceKey =
|
const resourceKey =
|
||||||
`ui.panel.page-authorize.form.providers.${step.handler[0]}.step.${step.step_id}.description` as const;
|
`ui.panel.page-authorize.form.providers.${step.handler[0]}.step.${step.step_id}.description` as const;
|
||||||
const args: string[] = [];
|
return this.localize(resourceKey, step.description_placeholders);
|
||||||
const placeholders = step.description_placeholders || {};
|
|
||||||
Object.keys(placeholders).forEach((key) => {
|
|
||||||
args.push(key);
|
|
||||||
args.push(placeholders[key]);
|
|
||||||
});
|
|
||||||
return this.localize(resourceKey, ...args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _computeLabelCallback(step: DataEntryFlowStepForm) {
|
private _computeLabelCallback(step: DataEntryFlowStepForm) {
|
||||||
|
|||||||
@@ -26,14 +26,13 @@ export class HaAuthFormString extends HaFormString {
|
|||||||
}
|
}
|
||||||
ha-auth-form-string ha-icon-button {
|
ha-auth-form-string ha-icon-button {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 1em;
|
top: 8px;
|
||||||
right: 12px;
|
right: 8px;
|
||||||
--mdc-icon-button-size: 24px;
|
|
||||||
color: var(--secondary-text-color);
|
|
||||||
}
|
|
||||||
ha-auth-form-string ha-icon-button {
|
|
||||||
inset-inline-start: initial;
|
inset-inline-start: initial;
|
||||||
inset-inline-end: 12px;
|
inset-inline-end: 8px;
|
||||||
|
--mdc-icon-button-size: 40px;
|
||||||
|
--mdc-icon-size: 20px;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
direction: var(--direction);
|
direction: var(--direction);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
9
src/common/array/combinations.ts
Normal file
9
src/common/array/combinations.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export function getAllCombinations<T>(arr: T[]) {
|
||||||
|
return arr.reduce<T[][]>(
|
||||||
|
(combinations, element) =>
|
||||||
|
combinations.concat(
|
||||||
|
combinations.map((combination) => [...combination, element])
|
||||||
|
),
|
||||||
|
[[]]
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -58,10 +58,10 @@ const matchMaxScale = (
|
|||||||
return outputColors.map((value) => Math.round(value * factor));
|
return outputColors.map((value) => Math.round(value * factor));
|
||||||
};
|
};
|
||||||
|
|
||||||
const mired2kelvin = (miredTemperature: number) =>
|
export const mired2kelvin = (miredTemperature: number) =>
|
||||||
Math.floor(1000000 / miredTemperature);
|
Math.floor(1000000 / miredTemperature);
|
||||||
|
|
||||||
const kelvin2mired = (kelvintTemperature: number) =>
|
export const kelvin2mired = (kelvintTemperature: number) =>
|
||||||
Math.floor(1000000 / kelvintTemperature);
|
Math.floor(1000000 / kelvintTemperature);
|
||||||
|
|
||||||
export const rgbww2rgb = (
|
export const rgbww2rgb = (
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
mdiCarCoolantLevel,
|
mdiCarCoolantLevel,
|
||||||
mdiCash,
|
mdiCash,
|
||||||
mdiChatSleep,
|
mdiChatSleep,
|
||||||
|
mdiClipboardList,
|
||||||
mdiClock,
|
mdiClock,
|
||||||
mdiCloudUpload,
|
mdiCloudUpload,
|
||||||
mdiCog,
|
mdiCog,
|
||||||
@@ -120,6 +121,7 @@ export const FIXED_DOMAIN_ICONS = {
|
|||||||
siren: mdiBullhorn,
|
siren: mdiBullhorn,
|
||||||
stt: mdiMicrophoneMessage,
|
stt: mdiMicrophoneMessage,
|
||||||
text: mdiFormTextbox,
|
text: mdiFormTextbox,
|
||||||
|
todo: mdiClipboardList,
|
||||||
time: mdiClock,
|
time: mdiClock,
|
||||||
timer: mdiTimerOutline,
|
timer: mdiTimerOutline,
|
||||||
tts: mdiSpeakerMessage,
|
tts: mdiSpeakerMessage,
|
||||||
|
|||||||
@@ -5,12 +5,15 @@ import { FrontendLocaleData, TimeZone } from "../../data/translation";
|
|||||||
const calcZonedDate = (
|
const calcZonedDate = (
|
||||||
date: Date,
|
date: Date,
|
||||||
tz: string,
|
tz: string,
|
||||||
fn: (date: Date, options?: any) => Date,
|
fn: (date: Date, options?: any) => Date | number | boolean,
|
||||||
options?
|
options?
|
||||||
) => {
|
) => {
|
||||||
const inputZoned = utcToZonedTime(date, tz);
|
const inputZoned = utcToZonedTime(date, tz);
|
||||||
const fnZoned = fn(inputZoned, options);
|
const fnZoned = fn(inputZoned, options);
|
||||||
return zonedTimeToUtc(fnZoned, tz);
|
if (fnZoned instanceof Date) {
|
||||||
|
return zonedTimeToUtc(fnZoned, tz) as Date;
|
||||||
|
}
|
||||||
|
return fnZoned;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const calcDate = (
|
export const calcDate = (
|
||||||
@@ -21,5 +24,16 @@ export const calcDate = (
|
|||||||
options?
|
options?
|
||||||
) =>
|
) =>
|
||||||
locale.time_zone === TimeZone.server
|
locale.time_zone === TimeZone.server
|
||||||
? calcZonedDate(date, config.time_zone, fn, options)
|
? (calcZonedDate(date, config.time_zone, fn, options) as Date)
|
||||||
|
: fn(date, options);
|
||||||
|
|
||||||
|
export const calcDateProperty = (
|
||||||
|
date: Date,
|
||||||
|
fn: (date: Date, options?: any) => boolean | number,
|
||||||
|
locale: FrontendLocaleData,
|
||||||
|
config: HassConfig,
|
||||||
|
options?
|
||||||
|
) =>
|
||||||
|
locale.time_zone === TimeZone.server
|
||||||
|
? (calcZonedDate(date, config.time_zone, fn, options) as number | boolean)
|
||||||
: fn(date, options);
|
: fn(date, options);
|
||||||
|
|||||||
@@ -37,6 +37,23 @@ const formatDateMem = memoizeOne(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Aug 10, 2021
|
||||||
|
export const formatDateShort = (
|
||||||
|
dateObj: Date,
|
||||||
|
locale: FrontendLocaleData,
|
||||||
|
config: HassConfig
|
||||||
|
) => formatDateShortMem(locale, config.time_zone).format(dateObj);
|
||||||
|
|
||||||
|
const formatDateShortMem = memoizeOne(
|
||||||
|
(locale: FrontendLocaleData, serverTimeZone: string) =>
|
||||||
|
new Intl.DateTimeFormat(locale.language, {
|
||||||
|
year: "numeric",
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
// 10/08/2021
|
// 10/08/2021
|
||||||
export const formatDateNumeric = (
|
export const formatDateNumeric = (
|
||||||
dateObj: Date,
|
dateObj: Date,
|
||||||
@@ -102,13 +119,13 @@ const formatDateNumericMem = memoizeOne(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Aug 10
|
// Aug 10
|
||||||
export const formatDateShort = (
|
export const formatDateVeryShort = (
|
||||||
dateObj: Date,
|
dateObj: Date,
|
||||||
locale: FrontendLocaleData,
|
locale: FrontendLocaleData,
|
||||||
config: HassConfig
|
config: HassConfig
|
||||||
) => formatDateShortMem(locale, config.time_zone).format(dateObj);
|
) => formatDateVeryShortMem(locale, config.time_zone).format(dateObj);
|
||||||
|
|
||||||
const formatDateShortMem = memoizeOne(
|
const formatDateVeryShortMem = memoizeOne(
|
||||||
(locale: FrontendLocaleData, serverTimeZone: string) =>
|
(locale: FrontendLocaleData, serverTimeZone: string) =>
|
||||||
new Intl.DateTimeFormat(locale.language, {
|
new Intl.DateTimeFormat(locale.language, {
|
||||||
day: "numeric",
|
day: "numeric",
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
import { HaDurationData } from "../../components/ha-duration-input";
|
import { HaDurationData } from "../../components/ha-duration-input";
|
||||||
|
import { FrontendLocaleData } from "../../data/translation";
|
||||||
|
import "../../resources/intl-polyfill";
|
||||||
|
|
||||||
const leftPad = (num: number) => (num < 10 ? `0${num}` : num);
|
const leftPad = (num: number) => (num < 10 ? `0${num}` : num);
|
||||||
|
|
||||||
export const formatDuration = (duration: HaDurationData) => {
|
export const formatDuration = (
|
||||||
|
locale: FrontendLocaleData,
|
||||||
|
duration: HaDurationData
|
||||||
|
) => {
|
||||||
const d = duration.days || 0;
|
const d = duration.days || 0;
|
||||||
const h = duration.hours || 0;
|
const h = duration.hours || 0;
|
||||||
const m = duration.minutes || 0;
|
const m = duration.minutes || 0;
|
||||||
@@ -10,7 +15,11 @@ export const formatDuration = (duration: HaDurationData) => {
|
|||||||
const ms = duration.milliseconds || 0;
|
const ms = duration.milliseconds || 0;
|
||||||
|
|
||||||
if (d > 0) {
|
if (d > 0) {
|
||||||
return `${d} day${d === 1 ? "" : "s"} ${h}:${leftPad(m)}:${leftPad(s)}`;
|
return `${Intl.NumberFormat(locale.language, {
|
||||||
|
style: "unit",
|
||||||
|
unit: "day",
|
||||||
|
unitDisplay: "long",
|
||||||
|
}).format(d)} ${h}:${leftPad(m)}:${leftPad(s)}`;
|
||||||
}
|
}
|
||||||
if (h > 0) {
|
if (h > 0) {
|
||||||
return `${h}:${leftPad(m)}:${leftPad(s)}`;
|
return `${h}:${leftPad(m)}:${leftPad(s)}`;
|
||||||
@@ -19,10 +28,18 @@ export const formatDuration = (duration: HaDurationData) => {
|
|||||||
return `${m}:${leftPad(s)}`;
|
return `${m}:${leftPad(s)}`;
|
||||||
}
|
}
|
||||||
if (s > 0) {
|
if (s > 0) {
|
||||||
return `${s} second${s === 1 ? "" : "s"}`;
|
return Intl.NumberFormat(locale.language, {
|
||||||
|
style: "unit",
|
||||||
|
unit: "second",
|
||||||
|
unitDisplay: "long",
|
||||||
|
}).format(s);
|
||||||
}
|
}
|
||||||
if (ms > 0) {
|
if (ms > 0) {
|
||||||
return `${ms} millisecond${ms === 1 ? "" : "s"}`;
|
return Intl.NumberFormat(locale.language, {
|
||||||
|
style: "unit",
|
||||||
|
unit: "millisecond",
|
||||||
|
unitDisplay: "long",
|
||||||
|
}).format(ms);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ThemeVars } from "../../data/ws-themes";
|
import { ThemeVars } from "../../data/ws-themes";
|
||||||
import { darkStyles, derivedStyles } from "../../resources/styles";
|
import { darkStyles, derivedStyles } from "../../resources/styles-data";
|
||||||
import type { HomeAssistant } from "../../types";
|
import type { HomeAssistant } from "../../types";
|
||||||
import {
|
import {
|
||||||
hex2rgb,
|
hex2rgb,
|
||||||
@@ -41,9 +41,7 @@ export const applyThemesOnElement = (
|
|||||||
// If there is no explicitly desired dark mode provided, we automatically
|
// If there is no explicitly desired dark mode provided, we automatically
|
||||||
// use the active one from `themes`.
|
// use the active one from `themes`.
|
||||||
const darkMode =
|
const darkMode =
|
||||||
themeSettings && themeSettings?.dark !== undefined
|
themeSettings?.dark !== undefined ? themeSettings.dark : themes.darkMode;
|
||||||
? themeSettings?.dark
|
|
||||||
: themes.darkMode;
|
|
||||||
|
|
||||||
let cacheKey = themeToApply;
|
let cacheKey = themeToApply;
|
||||||
let themeRules: Partial<ThemeVars> = {};
|
let themeRules: Partial<ThemeVars> = {};
|
||||||
@@ -135,10 +133,19 @@ export const applyThemesOnElement = (
|
|||||||
|
|
||||||
// Set and/or reset styles
|
// Set and/or reset styles
|
||||||
if (element.updateStyles) {
|
if (element.updateStyles) {
|
||||||
|
// Use updateStyles() method of Polymer elements
|
||||||
element.updateStyles(styles);
|
element.updateStyles(styles);
|
||||||
} else if (window.ShadyCSS) {
|
} else if (window.ShadyCSS) {
|
||||||
// Implement updateStyles() method of Polymer elements
|
// Use ShadyCSS if available
|
||||||
window.ShadyCSS.styleSubtree(/** @type {!HTMLElement} */ element, styles);
|
window.ShadyCSS.styleSubtree(/** @type {!HTMLElement} */ element, styles);
|
||||||
|
} else {
|
||||||
|
for (const s in styles) {
|
||||||
|
if (s === null) {
|
||||||
|
element.style.removeProperty(s);
|
||||||
|
} else {
|
||||||
|
element.style.setProperty(s, styles[s]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { blankBeforePercent } from "../translations/blank_before_percent";
|
|||||||
import { LocalizeFunc } from "../translations/localize";
|
import { LocalizeFunc } from "../translations/localize";
|
||||||
import { computeDomain } from "./compute_domain";
|
import { computeDomain } from "./compute_domain";
|
||||||
import { computeStateDomain } from "./compute_state_domain";
|
import { computeStateDomain } from "./compute_state_domain";
|
||||||
|
import { blankBeforeUnit } from "../translations/blank_before_unit";
|
||||||
|
|
||||||
export const computeAttributeValueDisplay = (
|
export const computeAttributeValueDisplay = (
|
||||||
localize: LocalizeFunc,
|
localize: LocalizeFunc,
|
||||||
@@ -55,20 +56,12 @@ export const computeAttributeValueDisplay = (
|
|||||||
unit = getWeatherUnit(config, stateObj as WeatherEntity, attribute);
|
unit = getWeatherUnit(config, stateObj as WeatherEntity, attribute);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unit === "%") {
|
if (TEMPERATURE_ATTRIBUTES.has(attribute)) {
|
||||||
return `${formattedValue}${blankBeforePercent(locale)}${unit}`;
|
unit = config.unit_system.temperature;
|
||||||
}
|
|
||||||
|
|
||||||
if (unit === "°") {
|
|
||||||
return `${formattedValue}${unit}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unit) {
|
if (unit) {
|
||||||
return `${formattedValue} ${unit}`;
|
return `${formattedValue}${blankBeforeUnit(unit, locale)}${unit}`;
|
||||||
}
|
|
||||||
|
|
||||||
if (TEMPERATURE_ATTRIBUTES.has(attribute)) {
|
|
||||||
return `${formattedValue} ${config.unit_system.temperature}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return formattedValue;
|
return formattedValue;
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ import { UNAVAILABLE, UNKNOWN } from "../../data/entity";
|
|||||||
import { EntityRegistryDisplayEntry } from "../../data/entity_registry";
|
import { EntityRegistryDisplayEntry } from "../../data/entity_registry";
|
||||||
import { FrontendLocaleData, TimeZone } from "../../data/translation";
|
import { FrontendLocaleData, TimeZone } from "../../data/translation";
|
||||||
import {
|
import {
|
||||||
updateIsInstallingFromAttributes,
|
|
||||||
UPDATE_SUPPORT_PROGRESS,
|
UPDATE_SUPPORT_PROGRESS,
|
||||||
|
updateIsInstallingFromAttributes,
|
||||||
} from "../../data/update";
|
} from "../../data/update";
|
||||||
import { HomeAssistant } from "../../types";
|
import { HomeAssistant } from "../../types";
|
||||||
import {
|
import {
|
||||||
formatDuration,
|
|
||||||
UNIT_TO_MILLISECOND_CONVERT,
|
UNIT_TO_MILLISECOND_CONVERT,
|
||||||
|
formatDuration,
|
||||||
} from "../datetime/duration";
|
} from "../datetime/duration";
|
||||||
import { formatDate } from "../datetime/format_date";
|
import { formatDate } from "../datetime/format_date";
|
||||||
import { formatDateTime } from "../datetime/format_date_time";
|
import { formatDateTime } from "../datetime/format_date_time";
|
||||||
@@ -19,10 +19,10 @@ import {
|
|||||||
getNumberFormatOptions,
|
getNumberFormatOptions,
|
||||||
isNumericFromAttributes,
|
isNumericFromAttributes,
|
||||||
} from "../number/format_number";
|
} from "../number/format_number";
|
||||||
import { blankBeforePercent } from "../translations/blank_before_percent";
|
|
||||||
import { LocalizeFunc } from "../translations/localize";
|
import { LocalizeFunc } from "../translations/localize";
|
||||||
import { computeDomain } from "./compute_domain";
|
import { computeDomain } from "./compute_domain";
|
||||||
import { supportsFeatureFromAttributes } from "./supports-feature";
|
import { supportsFeatureFromAttributes } from "./supports-feature";
|
||||||
|
import { blankBeforeUnit } from "../translations/blank_before_unit";
|
||||||
|
|
||||||
export const computeStateDisplaySingleEntity = (
|
export const computeStateDisplaySingleEntity = (
|
||||||
localize: LocalizeFunc,
|
localize: LocalizeFunc,
|
||||||
@@ -108,16 +108,20 @@ export const computeStateDisplayFromEntityAttributes = (
|
|||||||
// fallback to default
|
// fallback to default
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const unit = !attributes.unit_of_measurement
|
|
||||||
? ""
|
const value = formatNumber(
|
||||||
: attributes.unit_of_measurement === "%"
|
|
||||||
? blankBeforePercent(locale) + "%"
|
|
||||||
: ` ${attributes.unit_of_measurement}`;
|
|
||||||
return `${formatNumber(
|
|
||||||
state,
|
state,
|
||||||
locale,
|
locale,
|
||||||
getNumberFormatOptions({ state, attributes } as HassEntity, entity)
|
getNumberFormatOptions({ state, attributes } as HassEntity, entity)
|
||||||
)}${unit}`;
|
);
|
||||||
|
|
||||||
|
const unit = attributes.unit_of_measurement;
|
||||||
|
|
||||||
|
if (unit) {
|
||||||
|
return `${value}${blankBeforeUnit(unit)}${unit}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const domain = computeDomain(entityId);
|
const domain = computeDomain(entityId);
|
||||||
|
|||||||
@@ -1,19 +1,29 @@
|
|||||||
// https://gist.github.com/hagemann/382adfc57adbd5af078dc93feef01fe1
|
// https://gist.github.com/hagemann/382adfc57adbd5af078dc93feef01fe1
|
||||||
export const slugify = (value: string, delimiter = "_") => {
|
export const slugify = (value: string, delimiter = "_") => {
|
||||||
const a =
|
const a =
|
||||||
"àáäâãåăæąçćčđďèéěėëêęğǵḧìíïîįłḿǹńňñòóöôœøṕŕřßşśšșťțùúüûǘůűūųẃẍÿýźžż·/_,:;";
|
"àáâäæãåāăąçćčđďèéêëēėęěğǵḧîïíīįìıİłḿñńǹňôöòóœøōõőṕŕřßśšşșťțûüùúūǘůűųẃẍÿýžźż·";
|
||||||
const b = `aaaaaaaaacccddeeeeeeegghiiiiilmnnnnooooooprrsssssttuuuuuuuuuwxyyzzz${delimiter}${delimiter}${delimiter}${delimiter}${delimiter}${delimiter}`;
|
const b = `aaaaaaaaaacccddeeeeeeeegghiiiiiiiilmnnnnoooooooooprrsssssttuuuuuuuuuwxyyzzz${delimiter}`;
|
||||||
const p = new RegExp(a.split("").join("|"), "g");
|
const p = new RegExp(a.split("").join("|"), "g");
|
||||||
|
|
||||||
return value
|
let slugified;
|
||||||
|
|
||||||
|
if (value === "") {
|
||||||
|
slugified = "";
|
||||||
|
} else {
|
||||||
|
slugified = value
|
||||||
.toString()
|
.toString()
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.replace(/\s+/g, delimiter) // Replace spaces with delimiter
|
|
||||||
.replace(p, (c) => b.charAt(a.indexOf(c))) // Replace special characters
|
.replace(p, (c) => b.charAt(a.indexOf(c))) // Replace special characters
|
||||||
.replace(/&/g, `${delimiter}and${delimiter}`) // Replace & with 'and'
|
.replace(/(\d),(?=\d)/g, "$1") // Remove Commas between numbers
|
||||||
.replace(/[^\w-]+/g, "") // Remove all non-word characters
|
.replace(/[^a-z0-9]+/g, delimiter) // Replace all non-word characters
|
||||||
.replace(/-/g, delimiter) // Replace - with delimiter
|
|
||||||
.replace(new RegExp(`(${delimiter})\\1+`, "g"), "$1") // Replace multiple delimiters with single delimiter
|
.replace(new RegExp(`(${delimiter})\\1+`, "g"), "$1") // Replace multiple delimiters with single delimiter
|
||||||
.replace(new RegExp(`^${delimiter}+`), "") // Trim delimiter from start of text
|
.replace(new RegExp(`^${delimiter}+`), "") // Trim delimiter from start of text
|
||||||
.replace(new RegExp(`${delimiter}+$`), ""); // Trim delimiter from end of text
|
.replace(new RegExp(`${delimiter}+$`), ""); // Trim delimiter from end of text
|
||||||
|
|
||||||
|
if (slugified === "") {
|
||||||
|
slugified = "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return slugified;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,45 +13,33 @@ export const handleStructError = (
|
|||||||
for (const failure of err.failures()) {
|
for (const failure of err.failures()) {
|
||||||
if (failure.value === undefined) {
|
if (failure.value === undefined) {
|
||||||
errors.push(
|
errors.push(
|
||||||
hass.localize(
|
hass.localize("ui.errors.config.key_missing", {
|
||||||
"ui.errors.config.key_missing",
|
key: failure.path.join("."),
|
||||||
"key",
|
})
|
||||||
failure.path.join(".")
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
} else if (failure.type === "never") {
|
} else if (failure.type === "never") {
|
||||||
warnings.push(
|
warnings.push(
|
||||||
hass.localize(
|
hass.localize("ui.errors.config.key_not_expected", {
|
||||||
"ui.errors.config.key_not_expected",
|
key: failure.path.join("."),
|
||||||
"key",
|
})
|
||||||
failure.path.join(".")
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
} else if (failure.type === "union") {
|
} else if (failure.type === "union") {
|
||||||
continue;
|
continue;
|
||||||
} else if (failure.type === "enums") {
|
} else if (failure.type === "enums") {
|
||||||
warnings.push(
|
warnings.push(
|
||||||
hass.localize(
|
hass.localize("ui.errors.config.key_wrong_type", {
|
||||||
"ui.errors.config.key_wrong_type",
|
key: failure.path.join("."),
|
||||||
"key",
|
type_correct: failure.message.replace("Expected ", "").split(", ")[0],
|
||||||
failure.path.join("."),
|
type_wrong: JSON.stringify(failure.value),
|
||||||
"type_correct",
|
})
|
||||||
failure.message.replace("Expected ", "").split(", ")[0],
|
|
||||||
"type_wrong",
|
|
||||||
JSON.stringify(failure.value)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
warnings.push(
|
warnings.push(
|
||||||
hass.localize(
|
hass.localize("ui.errors.config.key_wrong_type", {
|
||||||
"ui.errors.config.key_wrong_type",
|
key: failure.path.join("."),
|
||||||
"key",
|
type_correct: failure.refinement || failure.type,
|
||||||
failure.path.join("."),
|
type_wrong: JSON.stringify(failure.value),
|
||||||
"type_correct",
|
})
|
||||||
failure.refinement || failure.type,
|
|
||||||
"type_wrong",
|
|
||||||
JSON.stringify(failure.value)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
15
src/common/translations/blank_before_unit.ts
Normal file
15
src/common/translations/blank_before_unit.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { FrontendLocaleData } from "../../data/translation";
|
||||||
|
import { blankBeforePercent } from "./blank_before_percent";
|
||||||
|
|
||||||
|
export const blankBeforeUnit = (
|
||||||
|
unit: string,
|
||||||
|
localeOptions?: FrontendLocaleData
|
||||||
|
): string => {
|
||||||
|
if (unit === "°") {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (localeOptions && unit === "%") {
|
||||||
|
return blankBeforePercent(localeOptions);
|
||||||
|
}
|
||||||
|
return " ";
|
||||||
|
};
|
||||||
@@ -23,6 +23,7 @@ export function computeDirectionStyles(isRTL: boolean, element: LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function setDirectionStyles(direction: string, element: LitElement) {
|
export function setDirectionStyles(direction: string, element: LitElement) {
|
||||||
|
document.dir = direction;
|
||||||
element.style.direction = direction;
|
element.style.direction = direction;
|
||||||
element.style.setProperty("--direction", direction);
|
element.style.setProperty("--direction", direction);
|
||||||
element.style.setProperty(
|
element.style.setProperty(
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
import { mdiAlertOctagram, mdiCheckBold } from "@mdi/js";
|
import { mdiAlertOctagram, mdiCheckBold } from "@mdi/js";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import {
|
||||||
|
css,
|
||||||
|
CSSResultGroup,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
nothing,
|
||||||
|
TemplateResult,
|
||||||
|
} from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import "../ha-circular-progress";
|
import "../ha-circular-progress";
|
||||||
import "../ha-svg-icon";
|
import "../ha-svg-icon";
|
||||||
@@ -27,7 +34,7 @@ export class HaProgressButton extends LitElement {
|
|||||||
<slot></slot>
|
<slot></slot>
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
${!overlay
|
${!overlay
|
||||||
? ""
|
? nothing
|
||||||
: html`
|
: html`
|
||||||
<div class="progress">
|
<div class="progress">
|
||||||
${this._result === "success"
|
${this._result === "success"
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ import {
|
|||||||
formatDate,
|
formatDate,
|
||||||
formatDateMonth,
|
formatDateMonth,
|
||||||
formatDateMonthYear,
|
formatDateMonthYear,
|
||||||
formatDateShort,
|
formatDateVeryShort,
|
||||||
formatDateWeekdayDay,
|
formatDateWeekdayDay,
|
||||||
formatDateYear,
|
formatDateYear,
|
||||||
} from "../../common/datetime/format_date";
|
} from "../../common/datetime/format_date";
|
||||||
@@ -128,13 +128,13 @@ _adapters._date.override({
|
|||||||
this.options.config
|
this.options.config
|
||||||
);
|
);
|
||||||
case "day":
|
case "day":
|
||||||
return formatDateShort(
|
return formatDateVeryShort(
|
||||||
new Date(time),
|
new Date(time),
|
||||||
this.options.locale,
|
this.options.locale,
|
||||||
this.options.config
|
this.options.config
|
||||||
);
|
);
|
||||||
case "week":
|
case "week":
|
||||||
return formatDate(
|
return formatDateVeryShort(
|
||||||
new Date(time),
|
new Date(time),
|
||||||
this.options.locale,
|
this.options.locale,
|
||||||
this.options.config
|
this.options.config
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { styleMap } from "lit/directives/style-map";
|
|||||||
import { clamp } from "../../common/number/clamp";
|
import { clamp } from "../../common/number/clamp";
|
||||||
import { computeRTL } from "../../common/util/compute_rtl";
|
import { computeRTL } from "../../common/util/compute_rtl";
|
||||||
import { HomeAssistant } from "../../types";
|
import { HomeAssistant } from "../../types";
|
||||||
|
import { debounce } from "../../common/util/debounce";
|
||||||
|
|
||||||
export const MIN_TIME_BETWEEN_UPDATES = 60 * 5 * 1000;
|
export const MIN_TIME_BETWEEN_UPDATES = 60 * 5 * 1000;
|
||||||
|
|
||||||
@@ -52,6 +53,12 @@ export class HaChartBase extends LitElement {
|
|||||||
|
|
||||||
@state() private _hiddenDatasets: Set<number> = new Set();
|
@state() private _hiddenDatasets: Set<number> = new Set();
|
||||||
|
|
||||||
|
private _paddingUpdateCount = 0;
|
||||||
|
|
||||||
|
private _paddingUpdateLock = false;
|
||||||
|
|
||||||
|
private _paddingYAxisInternal = 0;
|
||||||
|
|
||||||
public disconnectedCallback() {
|
public disconnectedCallback() {
|
||||||
super.disconnectedCallback();
|
super.disconnectedCallback();
|
||||||
this._releaseCanvas();
|
this._releaseCanvas();
|
||||||
@@ -104,9 +111,44 @@ export class HaChartBase extends LitElement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public shouldUpdate(changedProps: PropertyValues): boolean {
|
||||||
|
if (
|
||||||
|
this._paddingUpdateLock &&
|
||||||
|
changedProps.size === 1 &&
|
||||||
|
changedProps.has("paddingYAxis")
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _debouncedClearUpdates = debounce(
|
||||||
|
() => {
|
||||||
|
this._paddingUpdateCount = 0;
|
||||||
|
},
|
||||||
|
2000,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
public willUpdate(changedProps: PropertyValues): void {
|
public willUpdate(changedProps: PropertyValues): void {
|
||||||
super.willUpdate(changedProps);
|
super.willUpdate(changedProps);
|
||||||
|
|
||||||
|
if (!this._paddingUpdateLock) {
|
||||||
|
this._paddingYAxisInternal = this.paddingYAxis;
|
||||||
|
if (changedProps.size === 1 && changedProps.has("paddingYAxis")) {
|
||||||
|
this._paddingUpdateCount++;
|
||||||
|
if (this._paddingUpdateCount > 300) {
|
||||||
|
this._paddingUpdateLock = true;
|
||||||
|
// eslint-disable-next-line
|
||||||
|
console.error(
|
||||||
|
"Detected excessive chart padding updates, possibly an infinite loop. Disabling axis padding."
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this._debouncedClearUpdates();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.hasUpdated || !this.chart) {
|
if (!this.hasUpdated || !this.chart) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -171,10 +213,10 @@ export class HaChartBase extends LitElement {
|
|||||||
this.height ?? this._chartHeight ?? this.clientWidth / 2
|
this.height ?? this._chartHeight ?? this.clientWidth / 2
|
||||||
}px`,
|
}px`,
|
||||||
"padding-left": `${
|
"padding-left": `${
|
||||||
computeRTL(this.hass) ? 0 : this.paddingYAxis
|
computeRTL(this.hass) ? 0 : this._paddingYAxisInternal
|
||||||
}px`,
|
}px`,
|
||||||
"padding-right": `${
|
"padding-right": `${
|
||||||
computeRTL(this.hass) ? this.paddingYAxis : 0
|
computeRTL(this.hass) ? this._paddingYAxisInternal : 0
|
||||||
}px`,
|
}px`,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
@@ -324,7 +366,7 @@ export class HaChartBase extends LitElement {
|
|||||||
clamp(
|
clamp(
|
||||||
context.tooltip.caretX,
|
context.tooltip.caretX,
|
||||||
100,
|
100,
|
||||||
this.clientWidth - 100 - this.paddingYAxis
|
this.clientWidth - 100 - this._paddingYAxisInternal
|
||||||
) -
|
) -
|
||||||
100 +
|
100 +
|
||||||
"px",
|
"px",
|
||||||
|
|||||||
@@ -141,16 +141,10 @@ export class StateHistoryChartLine extends LitElement {
|
|||||||
`${context.dataset.label}: ${formatNumber(
|
`${context.dataset.label}: ${formatNumber(
|
||||||
context.parsed.y,
|
context.parsed.y,
|
||||||
this.hass.locale,
|
this.hass.locale,
|
||||||
this.data[context.datasetIndex]?.entity_id
|
getNumberFormatOptions(
|
||||||
? getNumberFormatOptions(
|
undefined,
|
||||||
this.hass.states[
|
this.hass.entities[this._entityIds[context.datasetIndex]]
|
||||||
this.data[context.datasetIndex].entity_id
|
|
||||||
],
|
|
||||||
this.hass.entities[
|
|
||||||
this.data[context.datasetIndex].entity_id
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
: undefined
|
|
||||||
)} ${this.unit}`,
|
)} ${this.unit}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -180,7 +174,9 @@ export class StateHistoryChartLine extends LitElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const points = e.chart.getElementsAtEventForMode(
|
const chart = e.chart;
|
||||||
|
|
||||||
|
const points = chart.getElementsAtEventForMode(
|
||||||
e,
|
e,
|
||||||
"nearest",
|
"nearest",
|
||||||
{ intersect: true },
|
{ intersect: true },
|
||||||
@@ -192,6 +188,7 @@ export class StateHistoryChartLine extends LitElement {
|
|||||||
fireEvent(this, "hass-more-info", {
|
fireEvent(this, "hass-more-info", {
|
||||||
entityId: this._entityIds[firstPoint.datasetIndex],
|
entityId: this._entityIds[firstPoint.datasetIndex],
|
||||||
});
|
});
|
||||||
|
chart.canvas.dispatchEvent(new Event("mouseout")); // to hide tooltip
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -238,6 +238,7 @@ export class StateHistoryChartTimeline extends LitElement {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
entityId: this._chartData?.datasets[index]?.label,
|
entityId: this._chartData?.datasets[index]?.label,
|
||||||
});
|
});
|
||||||
|
chart.canvas.dispatchEvent(new Event("mouseout")); // to hide tooltip
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,9 +73,9 @@ export class StateHistoryCharts extends LitElement {
|
|||||||
|
|
||||||
@property({ type: Boolean }) public isLoadingData = false;
|
@property({ type: Boolean }) public isLoadingData = false;
|
||||||
|
|
||||||
@state() private _computedStartTime!: Date;
|
private _computedStartTime!: Date;
|
||||||
|
|
||||||
@state() private _computedEndTime!: Date;
|
private _computedEndTime!: Date;
|
||||||
|
|
||||||
@state() private _maxYWidth = 0;
|
@state() private _maxYWidth = 0;
|
||||||
|
|
||||||
@@ -114,31 +114,6 @@ export class StateHistoryCharts extends LitElement {
|
|||||||
${this.hass.localize("ui.components.history_charts.no_history_found")}
|
${this.hass.localize("ui.components.history_charts.no_history_found")}
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const now = new Date();
|
|
||||||
|
|
||||||
this._computedEndTime =
|
|
||||||
this.upToNow || !this.endTime || this.endTime > now ? now : this.endTime;
|
|
||||||
|
|
||||||
if (this.startTime) {
|
|
||||||
this._computedStartTime = this.startTime;
|
|
||||||
} else if (this.hoursToShow) {
|
|
||||||
this._computedStartTime = new Date(
|
|
||||||
new Date().getTime() - 60 * 60 * this.hoursToShow * 1000
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
this._computedStartTime = new Date(
|
|
||||||
this.historyData.timeline.reduce(
|
|
||||||
(minTime, stateInfo) =>
|
|
||||||
Math.min(
|
|
||||||
minTime,
|
|
||||||
new Date(stateInfo.data[0].last_changed).getTime()
|
|
||||||
),
|
|
||||||
new Date().getTime()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const combinedItems = this.historyData.timeline.length
|
const combinedItems = this.historyData.timeline.length
|
||||||
? (this.virtualize
|
? (this.virtualize
|
||||||
? chunkData(this.historyData.timeline, CANVAS_TIMELINE_ROWS_CHUNK)
|
? chunkData(this.historyData.timeline, CANVAS_TIMELINE_ROWS_CHUNK)
|
||||||
@@ -220,10 +195,45 @@ export class StateHistoryCharts extends LitElement {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected willUpdate() {
|
protected willUpdate(changedProps: PropertyValues) {
|
||||||
if (!this.hasUpdated) {
|
if (!this.hasUpdated) {
|
||||||
loadVirtualizer();
|
loadVirtualizer();
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
[...changedProps.keys()].some(
|
||||||
|
(prop) =>
|
||||||
|
!(
|
||||||
|
["_maxYWidth", "_childYWidths", "_chartCount"] as PropertyKey[]
|
||||||
|
).includes(prop)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
// Don't recompute times when we just want to update layout
|
||||||
|
const now = new Date();
|
||||||
|
|
||||||
|
this._computedEndTime =
|
||||||
|
this.upToNow || !this.endTime || this.endTime > now
|
||||||
|
? now
|
||||||
|
: this.endTime;
|
||||||
|
|
||||||
|
if (this.startTime) {
|
||||||
|
this._computedStartTime = this.startTime;
|
||||||
|
} else if (this.hoursToShow) {
|
||||||
|
this._computedStartTime = new Date(
|
||||||
|
new Date().getTime() - 60 * 60 * this.hoursToShow * 1000
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this._computedStartTime = new Date(
|
||||||
|
(this.historyData?.timeline ?? []).reduce(
|
||||||
|
(minTime, stateInfo) =>
|
||||||
|
Math.min(
|
||||||
|
minTime,
|
||||||
|
new Date(stateInfo.data[0].last_changed).getTime()
|
||||||
|
),
|
||||||
|
new Date().getTime()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected updated(changedProps: PropertyValues) {
|
protected updated(changedProps: PropertyValues) {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import { isComponentLoaded } from "../../common/config/is_component_loaded";
|
|||||||
import {
|
import {
|
||||||
formatNumber,
|
formatNumber,
|
||||||
numberFormatToLocale,
|
numberFormatToLocale,
|
||||||
|
getNumberFormatOptions,
|
||||||
} from "../../common/number/format_number";
|
} from "../../common/number/format_number";
|
||||||
import {
|
import {
|
||||||
getDisplayUnit,
|
getDisplayUnit,
|
||||||
@@ -72,8 +73,12 @@ export class StatisticsChart extends LitElement {
|
|||||||
|
|
||||||
@property({ type: Boolean }) public isLoadingData = false;
|
@property({ type: Boolean }) public isLoadingData = false;
|
||||||
|
|
||||||
|
@property() public period?: string;
|
||||||
|
|
||||||
@state() private _chartData: ChartData = { datasets: [] };
|
@state() private _chartData: ChartData = { datasets: [] };
|
||||||
|
|
||||||
|
@state() private _statisticIds: string[] = [];
|
||||||
|
|
||||||
@state() private _chartOptions?: ChartOptions;
|
@state() private _chartOptions?: ChartOptions;
|
||||||
|
|
||||||
@query("ha-chart-base") private _chart?: HaChartBase;
|
@query("ha-chart-base") private _chart?: HaChartBase;
|
||||||
@@ -89,7 +94,12 @@ export class StatisticsChart extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public willUpdate(changedProps: PropertyValues) {
|
public willUpdate(changedProps: PropertyValues) {
|
||||||
if (!this.hasUpdated || changedProps.has("unit")) {
|
if (
|
||||||
|
!this.hasUpdated ||
|
||||||
|
changedProps.has("unit") ||
|
||||||
|
changedProps.has("period") ||
|
||||||
|
changedProps.has("chartType")
|
||||||
|
) {
|
||||||
this._createOptions();
|
this._createOptions();
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
@@ -157,6 +167,7 @@ export class StatisticsChart extends LitElement {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
ticks: {
|
ticks: {
|
||||||
|
source: this.chartType === "bar" ? "data" : undefined,
|
||||||
maxRotation: 0,
|
maxRotation: 0,
|
||||||
sampleSize: 5,
|
sampleSize: 5,
|
||||||
autoSkipPadding: 20,
|
autoSkipPadding: 20,
|
||||||
@@ -170,6 +181,12 @@ export class StatisticsChart extends LitElement {
|
|||||||
},
|
},
|
||||||
time: {
|
time: {
|
||||||
tooltipFormat: "datetime",
|
tooltipFormat: "datetime",
|
||||||
|
unit:
|
||||||
|
this.chartType === "bar" &&
|
||||||
|
this.period &&
|
||||||
|
["hour", "day", "week", "month"].includes(this.period)
|
||||||
|
? this.period
|
||||||
|
: undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
y: {
|
y: {
|
||||||
@@ -189,7 +206,11 @@ export class StatisticsChart extends LitElement {
|
|||||||
label: (context) =>
|
label: (context) =>
|
||||||
`${context.dataset.label}: ${formatNumber(
|
`${context.dataset.label}: ${formatNumber(
|
||||||
context.parsed.y,
|
context.parsed.y,
|
||||||
this.hass.locale
|
this.hass.locale,
|
||||||
|
getNumberFormatOptions(
|
||||||
|
undefined,
|
||||||
|
this.hass.entities[this._statisticIds[context.datasetIndex]]
|
||||||
|
)
|
||||||
)} ${
|
)} ${
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
context.dataset.unit || ""
|
context.dataset.unit || ""
|
||||||
@@ -248,6 +269,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 statisticIds: string[] = [];
|
||||||
let endTime: Date;
|
let endTime: Date;
|
||||||
|
|
||||||
if (statisticsData.length === 0) {
|
if (statisticsData.length === 0) {
|
||||||
@@ -386,6 +408,7 @@ export class StatisticsChart extends LitElement {
|
|||||||
unit: meta?.unit_of_measurement,
|
unit: meta?.unit_of_measurement,
|
||||||
band,
|
band,
|
||||||
});
|
});
|
||||||
|
statisticIds.push(statistic_id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -411,11 +434,7 @@ export class StatisticsChart extends LitElement {
|
|||||||
} else {
|
} else {
|
||||||
val = stat[type];
|
val = stat[type];
|
||||||
}
|
}
|
||||||
dataValues.push(
|
dataValues.push(val ?? null);
|
||||||
val !== null && val !== undefined
|
|
||||||
? Math.round(val * 100) / 100
|
|
||||||
: null
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
pushData(startDate, new Date(stat.end), dataValues);
|
pushData(startDate, new Date(stat.end), dataValues);
|
||||||
});
|
});
|
||||||
@@ -431,6 +450,7 @@ export class StatisticsChart extends LitElement {
|
|||||||
this._chartData = {
|
this._chartData = {
|
||||||
datasets: totalDataSets,
|
datasets: totalDataSets,
|
||||||
};
|
};
|
||||||
|
this._statisticIds = statisticIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
|
|||||||
53
src/components/chips/ha-assist-chip.ts
Normal file
53
src/components/chips/ha-assist-chip.ts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import { MdAssistChip } from "@material/web/chips/assist-chip";
|
||||||
|
import { css, html } from "lit";
|
||||||
|
import { customElement, property } from "lit/decorators";
|
||||||
|
|
||||||
|
@customElement("ha-assist-chip")
|
||||||
|
export class HaAssistChip extends MdAssistChip {
|
||||||
|
@property({ type: Boolean, reflect: true }) filled = false;
|
||||||
|
|
||||||
|
static override styles = [
|
||||||
|
...super.styles,
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
--md-sys-color-primary: var(--primary-text-color);
|
||||||
|
--md-sys-color-on-surface: var(--primary-text-color);
|
||||||
|
--md-assist-chip-container-shape: 16px;
|
||||||
|
--md-assist-chip-outline-color: var(--outline-color);
|
||||||
|
--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 **/
|
||||||
|
.filled {
|
||||||
|
display: flex;
|
||||||
|
pointer-events: none;
|
||||||
|
border-radius: inherit;
|
||||||
|
inset: 0;
|
||||||
|
position: absolute;
|
||||||
|
background-color: var(--ha-assist-chip-filled-container-color);
|
||||||
|
}
|
||||||
|
/** Set the size of mdc icons **/
|
||||||
|
::slotted([slot="icon"]) {
|
||||||
|
display: flex;
|
||||||
|
--mdc-icon-size: var(--md-input-chip-icon-size, 18px);
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
protected override renderOutline() {
|
||||||
|
if (this.filled) {
|
||||||
|
return html`<span class="filled"></span>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.renderOutline();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-assist-chip": HaAssistChip;
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/components/chips/ha-chip-set.ts
Normal file
11
src/components/chips/ha-chip-set.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { MdChipSet } from "@material/web/chips/chip-set";
|
||||||
|
import { customElement } from "lit/decorators";
|
||||||
|
|
||||||
|
@customElement("ha-chip-set")
|
||||||
|
export class HaChipSet extends MdChipSet {}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-chip-set": HaChipSet;
|
||||||
|
}
|
||||||
|
}
|
||||||
41
src/components/chips/ha-filter-chip.ts
Normal file
41
src/components/chips/ha-filter-chip.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { MdFilterChip } from "@material/web/chips/filter-chip";
|
||||||
|
import { css, html } from "lit";
|
||||||
|
import { customElement, property } from "lit/decorators";
|
||||||
|
|
||||||
|
@customElement("ha-filter-chip")
|
||||||
|
export class HaFilterChip extends MdFilterChip {
|
||||||
|
@property({ type: Boolean, reflect: true, attribute: "no-leading-icon" })
|
||||||
|
noLeadingIcon = false;
|
||||||
|
|
||||||
|
static override styles = [
|
||||||
|
...super.styles,
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
--md-sys-color-primary: var(--primary-text-color);
|
||||||
|
--md-sys-color-on-surface: var(--primary-text-color);
|
||||||
|
--md-sys-color-on-surface-variant: var(--primary-text-color);
|
||||||
|
--md-sys-color-on-secondary-container: var(--primary-text-color);
|
||||||
|
--md-filter-chip-container-shape: 16px;
|
||||||
|
--md-filter-chip-outline-color: var(--outline-color);
|
||||||
|
--md-filter-chip-selected-container-color: rgba(
|
||||||
|
var(--rgb-primary-text-color),
|
||||||
|
0.15
|
||||||
|
);
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
protected renderLeadingIcon() {
|
||||||
|
if (this.noLeadingIcon) {
|
||||||
|
// eslint-disable-next-line lit/prefer-nothing
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
return super.renderLeadingIcon();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-filter-chip": HaFilterChip;
|
||||||
|
}
|
||||||
|
}
|
||||||
35
src/components/chips/ha-input-chip.ts
Normal file
35
src/components/chips/ha-input-chip.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { MdInputChip } from "@material/web/chips/input-chip";
|
||||||
|
import { css } from "lit";
|
||||||
|
import { customElement } from "lit/decorators";
|
||||||
|
|
||||||
|
@customElement("ha-input-chip")
|
||||||
|
export class HaInputChip extends MdInputChip {
|
||||||
|
static override styles = [
|
||||||
|
...super.styles,
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
--md-sys-color-primary: var(--primary-text-color);
|
||||||
|
--md-sys-color-on-surface: var(--primary-text-color);
|
||||||
|
--md-sys-color-on-surface-variant: var(--primary-text-color);
|
||||||
|
--md-sys-color-on-secondary-container: var(--primary-text-color);
|
||||||
|
--md-input-chip-container-shape: 16px;
|
||||||
|
--md-input-chip-outline-color: var(--outline-color);
|
||||||
|
--md-input-chip-selected-container-color: rgba(
|
||||||
|
var(--rgb-primary-text-color),
|
||||||
|
0.15
|
||||||
|
);
|
||||||
|
}
|
||||||
|
/** Set the size of mdc icons **/
|
||||||
|
::slotted([slot="icon"]) {
|
||||||
|
display: flex;
|
||||||
|
--mdc-icon-size: var(--md-input-chip-icon-size, 18px);
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-input-chip": HaInputChip;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,6 +31,10 @@ const Component = Vue.extend({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
openingDirection: {
|
||||||
|
type: String,
|
||||||
|
default: "right",
|
||||||
|
},
|
||||||
disabled: {
|
disabled: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
@@ -66,7 +70,7 @@ const Component = Vue.extend({
|
|||||||
props: {
|
props: {
|
||||||
"time-picker": this.timePicker,
|
"time-picker": this.timePicker,
|
||||||
"auto-apply": this.autoApply,
|
"auto-apply": this.autoApply,
|
||||||
opens: "right",
|
opens: this.openingDirection,
|
||||||
"show-dropdowns": false,
|
"show-dropdowns": false,
|
||||||
"time-picker24-hour": this.twentyfourHours,
|
"time-picker24-hour": this.twentyfourHours,
|
||||||
disabled: this.disabled,
|
disabled: this.disabled,
|
||||||
@@ -126,9 +130,9 @@ class DateRangePickerElement extends WrappedElement {
|
|||||||
${dateRangePickerStyles}
|
${dateRangePickerStyles}
|
||||||
.calendars {
|
.calendars {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-wrap: nowrap !important;
|
||||||
}
|
}
|
||||||
.daterangepicker {
|
.daterangepicker {
|
||||||
left: 0px !important;
|
|
||||||
top: auto;
|
top: auto;
|
||||||
box-shadow: var(--ha-card-box-shadow, none);
|
box-shadow: var(--ha-card-box-shadow, none);
|
||||||
background-color: var(--card-background-color);
|
background-color: var(--card-background-color);
|
||||||
@@ -252,6 +256,10 @@ class DateRangePickerElement extends WrappedElement {
|
|||||||
direction: ltr;
|
direction: ltr;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
.vue-daterange-picker{
|
||||||
|
min-width: unset !important;
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
const shadowRoot = this.shadowRoot!;
|
const shadowRoot = this.shadowRoot!;
|
||||||
shadowRoot.appendChild(style);
|
shadowRoot.appendChild(style);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user