Compare commits
619 Commits
delay-init
...
20231206.0
Author | SHA1 | Date | |
---|---|---|---|
![]() |
fce4e5e382 | ||
![]() |
39260d172f | ||
![]() |
e646528b86 | ||
![]() |
86726102fb | ||
![]() |
1330558819 | ||
![]() |
b4ab0fc10b | ||
![]() |
15becf9ef6 | ||
![]() |
ef3785ce9f | ||
![]() |
134e13005d | ||
![]() |
eb5e7ba3f3 | ||
![]() |
dccd9b2541 | ||
![]() |
de83ad7a7a | ||
![]() |
7e55b9e6b8 | ||
![]() |
1b74ca47bf | ||
![]() |
c3d4be9ceb | ||
![]() |
b8d0c7f7c7 | ||
![]() |
92bce4078f | ||
![]() |
ff8f0697c2 | ||
![]() |
dddba7af00 | ||
![]() |
14a49d6664 | ||
![]() |
22da402d56 | ||
![]() |
aa4acc6572 | ||
![]() |
4d432fba57 | ||
![]() |
97b71c785b | ||
![]() |
8a93284bb3 | ||
![]() |
bb2abe4efc | ||
![]() |
ccada33caf | ||
![]() |
c5f15ee6ba | ||
![]() |
6f240ec681 | ||
![]() |
fc6aef138d | ||
![]() |
ae2e8e7402 | ||
![]() |
6d0eb05954 | ||
![]() |
96fbbc55e1 | ||
![]() |
7e74502ba3 | ||
![]() |
b273b31b03 | ||
![]() |
cf00ac74c6 | ||
![]() |
cc702f0fb3 | ||
![]() |
cc6eb5789d | ||
![]() |
669b80a9e1 | ||
![]() |
4c4fddee94 | ||
![]() |
b28a4e6b50 | ||
![]() |
bdd6a55a84 | ||
![]() |
d1ebc06994 | ||
![]() |
2a150788b4 | ||
![]() |
b854d23431 | ||
![]() |
72caf72e80 | ||
![]() |
a6ff1899df | ||
![]() |
6a999597df | ||
![]() |
219fc9e53a | ||
![]() |
861959ed2d | ||
![]() |
f7f50294e7 | ||
![]() |
a226333c1e | ||
![]() |
75f18aa69b | ||
![]() |
60ff4fdc1f | ||
![]() |
8d14cb0ab7 | ||
![]() |
606c809880 | ||
![]() |
f1692038f8 | ||
![]() |
79f5ec0cd5 | ||
![]() |
416a2a080d | ||
![]() |
92dc8b1561 | ||
![]() |
07b807adfc | ||
![]() |
843430ef41 | ||
![]() |
b5b2392dd2 | ||
![]() |
ef735d65cf | ||
![]() |
bf24740c7b | ||
![]() |
4ec11c7cf6 | ||
![]() |
2803e6aa95 | ||
![]() |
8ff36d0ccf | ||
![]() |
e7e465df69 | ||
![]() |
0c042079ed | ||
![]() |
a5a9bcafa7 | ||
![]() |
867f625b0a | ||
![]() |
3876c67588 | ||
![]() |
93158bb3af | ||
![]() |
5c47d8652d | ||
![]() |
eda0d12867 | ||
![]() |
4a53de4466 | ||
![]() |
e730649a8d | ||
![]() |
3a94deef69 | ||
![]() |
c1c186d279 | ||
![]() |
7356db919a | ||
![]() |
44157a5df3 | ||
![]() |
2acd1ff5e8 | ||
![]() |
150a5571cf | ||
![]() |
1eb25f4829 | ||
![]() |
d8d4ecf79f | ||
![]() |
081bd98e98 | ||
![]() |
6134f415e9 | ||
![]() |
b6a7581eca | ||
![]() |
7727f34e8f | ||
![]() |
9b20e1cf56 | ||
![]() |
b901ecacca | ||
![]() |
7691f7eb05 | ||
![]() |
8c0c56b954 | ||
![]() |
d968a20862 | ||
![]() |
9f1cd80a31 | ||
![]() |
5a9ccc5ae7 | ||
![]() |
6d7b0c5626 | ||
![]() |
400b8034e1 | ||
![]() |
05a22e3271 | ||
![]() |
c1f76e0565 | ||
![]() |
4582c3ba0a | ||
![]() |
f4ee734ea3 | ||
![]() |
2087028c47 | ||
![]() |
37a56b250a | ||
![]() |
71a41be20a | ||
![]() |
ffb19b31a5 | ||
![]() |
db68c7faa9 | ||
![]() |
07ae958eb0 | ||
![]() |
b62b5f6575 | ||
![]() |
2e1fb9df66 | ||
![]() |
31c91cea9a | ||
![]() |
9dc844ca28 | ||
![]() |
02ebc028c8 | ||
![]() |
5d35605b82 | ||
![]() |
22e86af5b3 | ||
![]() |
8c39ed46a8 | ||
![]() |
5965c3fdaa | ||
![]() |
15a5d2bc38 | ||
![]() |
0432cc95fc | ||
![]() |
6dafaac021 | ||
![]() |
d8929c9252 | ||
![]() |
5fa3a720b3 | ||
![]() |
6d3b838b6a | ||
![]() |
58e0179321 | ||
![]() |
eaf7e29b8a | ||
![]() |
260f1df1b9 | ||
![]() |
a88a4ef82c | ||
![]() |
075cca5991 | ||
![]() |
1d2dc37f75 | ||
![]() |
3da7025d78 | ||
![]() |
15b1d8ee14 | ||
![]() |
239d8fa948 | ||
![]() |
1de2e6161d | ||
![]() |
3e7f008277 | ||
![]() |
31a93d360d | ||
![]() |
2afd2788e2 | ||
![]() |
322fa99147 | ||
![]() |
c43ad52ff1 | ||
![]() |
6aa9737481 | ||
![]() |
7d9d6b99d9 | ||
![]() |
9c69e6f87c | ||
![]() |
0c90021895 | ||
![]() |
9163b9c124 | ||
![]() |
61717e1529 | ||
![]() |
168d418c27 | ||
![]() |
c787c920fc | ||
![]() |
1526209f82 | ||
![]() |
cf355c419d | ||
![]() |
eef024587b | ||
![]() |
270d463d02 | ||
![]() |
0735705dd3 | ||
![]() |
0a1dbe6d9d | ||
![]() |
15395275ba | ||
![]() |
6e66ba202f | ||
![]() |
5ebe1e0369 | ||
![]() |
860ab7a3ba | ||
![]() |
d499640304 | ||
![]() |
4f3f516767 | ||
![]() |
0996dbf2a1 | ||
![]() |
bc59e52cea | ||
![]() |
b8d4e957e2 | ||
![]() |
8002ec75bc | ||
![]() |
a45eefa742 | ||
![]() |
a1236924aa | ||
![]() |
9320e8c1a3 | ||
![]() |
addcd3a983 | ||
![]() |
e1dc73e992 | ||
![]() |
ba8849ed4d | ||
![]() |
36bca04341 | ||
![]() |
fb95de1f73 | ||
![]() |
3addfc3548 | ||
![]() |
e2e80d1f49 | ||
![]() |
a96eba2637 | ||
![]() |
274810b954 | ||
![]() |
842df983c3 | ||
![]() |
0eeadcd31a | ||
![]() |
8d37c5612b | ||
![]() |
e94461f7fe | ||
![]() |
f5edee1e91 | ||
![]() |
98cdbb4559 | ||
![]() |
f3f63d95b5 | ||
![]() |
244340f211 | ||
![]() |
75626431b1 | ||
![]() |
244868348b | ||
![]() |
a909c6d905 | ||
![]() |
f2efff9d71 | ||
![]() |
08a7a10e1c | ||
![]() |
b35e5abd83 | ||
![]() |
291e9fc0a2 | ||
![]() |
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 | ||
![]() |
18b5215ce6 | ||
![]() |
00a311bd63 | ||
![]() |
749c2ab8ac | ||
![]() |
d06fdeb265 | ||
![]() |
06d76be2c2 | ||
![]() |
6728e8d107 | ||
![]() |
533e2bed8a | ||
![]() |
310a08f3e6 | ||
![]() |
0566889a1e | ||
![]() |
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 | ||
![]() |
ddca7584ef | ||
![]() |
e6cfe74cac | ||
![]() |
d4218250af | ||
![]() |
78783942be | ||
![]() |
17ad8013ca | ||
![]() |
f70767f084 | ||
![]() |
3972394d82 | ||
![]() |
5331fb4f5f | ||
![]() |
16df352ba8 | ||
![]() |
3b553a3a4b | ||
![]() |
8e1e75dee1 | ||
![]() |
d27b4e04a9 | ||
![]() |
36f7b34ac5 | ||
![]() |
c0ff24bf1b | ||
![]() |
abb5aa348f | ||
![]() |
37ab5cbdc3 | ||
![]() |
42be3b331c | ||
![]() |
71e05f79c2 | ||
![]() |
c5a0a5bbbf | ||
![]() |
c3d809fcf3 | ||
![]() |
cbd0c39091 | ||
![]() |
113eb5be24 | ||
![]() |
c497669fd3 | ||
![]() |
c32ca5885b | ||
![]() |
3c792c4019 | ||
![]() |
9762e61ee2 | ||
![]() |
c09c39998b | ||
![]() |
d37e29c247 | ||
![]() |
51f22cd74a | ||
![]() |
b57dc968bd | ||
![]() |
e2e8cb785a | ||
![]() |
3d674cf237 | ||
![]() |
9961a4ae3f | ||
![]() |
c25755bfcd | ||
![]() |
40983619d6 | ||
![]() |
54758b5962 | ||
![]() |
4f09485b20 | ||
![]() |
9207f6c407 | ||
![]() |
1a2312460a | ||
![]() |
951b88ab4c | ||
![]() |
d3cc57d8b4 | ||
![]() |
4e9b118728 | ||
![]() |
4e6e924a40 | ||
![]() |
f1748e4dd5 | ||
![]() |
d491d8f5ac | ||
![]() |
cf0fde0f3c | ||
![]() |
a7dc2cfaa6 | ||
![]() |
d8c7db6ebf | ||
![]() |
c3743b57ea | ||
![]() |
e16a101de8 | ||
![]() |
94ad47c60e | ||
![]() |
184ef7b7ff | ||
![]() |
81053f2e07 | ||
![]() |
e8b4eeec67 | ||
![]() |
b0b7e77e28 | ||
![]() |
073ead5828 | ||
![]() |
763f80b46a | ||
![]() |
0c2531a7ee | ||
![]() |
8d2ec8098c | ||
![]() |
fdaefadd18 | ||
![]() |
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 | ||
![]() |
8daff17d6a | ||
![]() |
59bd852e7a | ||
![]() |
246fe2861e | ||
![]() |
dbf623ada2 | ||
![]() |
c848356a6d | ||
![]() |
47022d3a04 | ||
![]() |
d732bd4776 | ||
![]() |
5a5265723c | ||
![]() |
30c6e4e35e | ||
![]() |
c5f909d89f | ||
![]() |
13a691606f | ||
![]() |
44748df3ac | ||
![]() |
4f3dc82fd9 | ||
![]() |
b2e260d6ba | ||
![]() |
7111a21173 | ||
![]() |
ad51d313a1 | ||
![]() |
60345f3fe8 | ||
![]() |
956723cf15 | ||
![]() |
dd6a69ea03 | ||
![]() |
98bd08c9dd | ||
![]() |
6b31c07459 | ||
![]() |
c3b41afb68 | ||
![]() |
46d8f2eefb | ||
![]() |
0ffc7b59d6 | ||
![]() |
74be4ae20a | ||
![]() |
5455ce2e0f | ||
![]() |
01405d96b6 | ||
![]() |
965f893a65 | ||
![]() |
0b6813d9dc | ||
![]() |
cbd424ff5a | ||
![]() |
b899e39a9e | ||
![]() |
49a66961e2 | ||
![]() |
c69fb77b62 | ||
![]() |
d794ec3408 | ||
![]() |
d8c98d8f96 | ||
![]() |
acb32ae5c8 | ||
![]() |
c567a61dd7 | ||
![]() |
2a8d98307e | ||
![]() |
5aaf0cd579 | ||
![]() |
f38e4dcf54 | ||
![]() |
1df1ce5423 | ||
![]() |
a68381a4d9 | ||
![]() |
f7604b136e | ||
![]() |
362d950515 | ||
![]() |
22f9dbd65d | ||
![]() |
579050bfc7 | ||
![]() |
6b33b4e656 | ||
![]() |
dac7c0f5fd | ||
![]() |
aaceff0d23 | ||
![]() |
48e5cc6b63 | ||
![]() |
799a0933ba | ||
![]() |
940618f72d | ||
![]() |
d8ff69b65d | ||
![]() |
391aca6388 | ||
![]() |
071d078e84 | ||
![]() |
61982bcb77 | ||
![]() |
1c79fcc244 | ||
![]() |
f3513e3e52 | ||
![]() |
b3b10fa2ef | ||
![]() |
0ffabcc055 | ||
![]() |
9da8499004 | ||
![]() |
04d1fccb87 | ||
![]() |
fdf1eb5170 | ||
![]() |
4e2877b035 | ||
![]() |
467059f515 | ||
![]() |
e6db63bb63 | ||
![]() |
78ddec2c8c | ||
![]() |
9217d5bf40 | ||
![]() |
90d01e4b63 | ||
![]() |
e7960bf8c0 | ||
![]() |
bf12eaa1b3 | ||
![]() |
6179c75182 | ||
![]() |
40bb6566b8 | ||
![]() |
db272e3e18 | ||
![]() |
35496ead23 | ||
![]() |
41403a5d35 | ||
![]() |
8acf557137 | ||
![]() |
4e62370d18 | ||
![]() |
f90ab60354 | ||
![]() |
d187aa0ac6 | ||
![]() |
96597b3963 |
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -9,7 +9,7 @@ body:
|
|||||||
|
|
||||||
If you have a feature or enhancement request for the frontend, please [start an discussion][fr] instead of creating an issue.
|
If you have a feature or enhancement request for the frontend, please [start an discussion][fr] instead of creating an issue.
|
||||||
|
|
||||||
**Please not not report issues for custom cards.**
|
**Please do not report issues for custom cards.**
|
||||||
|
|
||||||
[fr]: https://github.com/home-assistant/frontend/discussions
|
[fr]: https://github.com/home-assistant/frontend/discussions
|
||||||
[releases]: https://github.com/home-assistant/home-assistant/releases
|
[releases]: https://github.com/home-assistant/home-assistant/releases
|
||||||
|
9
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -2,9 +2,7 @@
|
|||||||
You are amazing! Thanks for contributing to our project!
|
You are amazing! Thanks for contributing to our project!
|
||||||
Please, DO NOT DELETE ANY TEXT from this template! (unless instructed).
|
Please, DO NOT DELETE ANY TEXT from this template! (unless instructed).
|
||||||
-->
|
-->
|
||||||
|
|
||||||
## Breaking change
|
## Breaking change
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
If your PR contains a breaking change for existing users, it is important
|
If your PR contains a breaking change for existing users, it is important
|
||||||
to tell them what breaks, how to make it work again and why we did this.
|
to tell them what breaks, how to make it work again and why we did this.
|
||||||
@@ -13,8 +11,8 @@
|
|||||||
Note: Remove this section if this PR is NOT a breaking change.
|
Note: Remove this section if this PR is NOT a breaking change.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
## Proposed change
|
|
||||||
|
|
||||||
|
## Proposed change
|
||||||
<!--
|
<!--
|
||||||
Describe the big picture of your changes here to communicate to the
|
Describe the big picture of your changes here to communicate to the
|
||||||
maintainers why we should accept this pull request. If it fixes a bug
|
maintainers why we should accept this pull request. If it fixes a bug
|
||||||
@@ -22,8 +20,8 @@
|
|||||||
in the additional information section.
|
in the additional information section.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
## Type of change
|
|
||||||
|
|
||||||
|
## Type of change
|
||||||
<!--
|
<!--
|
||||||
What type of change does your PR introduce to the Home Assistant frontend?
|
What type of change does your PR introduce to the Home Assistant frontend?
|
||||||
NOTE: Please, check only 1! box!
|
NOTE: Please, check only 1! box!
|
||||||
@@ -38,7 +36,6 @@
|
|||||||
- [ ] Code quality improvements to existing code or addition of tests
|
- [ ] Code quality improvements to existing code or addition of tests
|
||||||
|
|
||||||
## Example configuration
|
## Example configuration
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Supplying a configuration snippet, makes it easier for a maintainer to test
|
Supplying a configuration snippet, makes it easier for a maintainer to test
|
||||||
your PR.
|
your PR.
|
||||||
@@ -49,7 +46,6 @@
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Additional information
|
## Additional information
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Details are important, and help maintainers processing your PR.
|
Details are important, and help maintainers processing your PR.
|
||||||
Please be sure to fill out additional details, if applicable.
|
Please be sure to fill out additional details, if applicable.
|
||||||
@@ -60,7 +56,6 @@
|
|||||||
- Link to documentation pull request:
|
- Link to documentation pull request:
|
||||||
|
|
||||||
## Checklist
|
## Checklist
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Put an `x` in the boxes that apply. You can also fill these out after
|
Put an `x` in the boxes that apply. You can also fill these out after
|
||||||
creating the PR. If you're unsure about any of them, don't hesitate to ask.
|
creating the PR. If you're unsure about any of them, don't hesitate to ask.
|
||||||
|
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.0.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.0.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
@@ -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.0.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.0.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.0.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.0.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
@@ -23,7 +23,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4.0.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
@@ -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.0.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.0.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
@@ -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.0.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
@@ -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.0.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
|
||||||
|
3
.github/workflows/lock.yml
vendored
@@ -9,9 +9,10 @@ jobs:
|
|||||||
lock:
|
lock:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: dessant/lock-threads@v4.0.1
|
- uses: dessant/lock-threads@v5.0.1
|
||||||
with:
|
with:
|
||||||
github-token: ${{ github.token }}
|
github-token: ${{ github.token }}
|
||||||
|
process-only: "issues, prs"
|
||||||
issue-lock-inactive-days: "30"
|
issue-lock-inactive-days: "30"
|
||||||
issue-exclude-created-before: "2020-10-01T00:00:00Z"
|
issue-exclude-created-before: "2020-10-01T00:00:00Z"
|
||||||
issue-lock-reason: ""
|
issue-lock-reason: ""
|
||||||
|
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.0.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
@@ -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
@@ -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.0.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.04.0
|
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
@@ -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.0.0
|
uses: actions/checkout@v4.1.1
|
||||||
|
|
||||||
- name: Upload Translations
|
- name: Upload Translations
|
||||||
run: |
|
run: |
|
||||||
|
3
.gitignore
vendored
@@ -47,3 +47,6 @@ src/cast/dev_const.ts
|
|||||||
|
|
||||||
# Home Assistant config
|
# Home Assistant config
|
||||||
/config/
|
/config/
|
||||||
|
|
||||||
|
# Jetbrains
|
||||||
|
/.idea/
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
CLA.md
|
CLA.md
|
||||||
CODE_OF_CONDUCT.md
|
CODE_OF_CONDUCT.md
|
||||||
LICENSE.md
|
LICENSE.md
|
||||||
|
PULL_REQUEST_TEMPLATE.md
|
541
.yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
vendored
9
.yarn/plugins/@yarnpkg/plugin-typescript.cjs
vendored
874
.yarn/releases/yarn-3.6.3.cjs
vendored
893
.yarn/releases/yarn-4.0.2.cjs
vendored
Executable file
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.2.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
|
|
||||||
|
56
build-scripts/babel-plugins/custom-polyfill-plugin.js
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import defineProvider from "@babel/helper-define-polyfill-provider";
|
||||||
|
|
||||||
|
// List of polyfill keys with supported browser targets for the functionality
|
||||||
|
const PolyfillSupport = {
|
||||||
|
fetch: {
|
||||||
|
android: 42,
|
||||||
|
chrome: 42,
|
||||||
|
edge: 14,
|
||||||
|
firefox: 39,
|
||||||
|
ios: 10.3,
|
||||||
|
opera: 29,
|
||||||
|
opera_mobile: 29,
|
||||||
|
safari: 10.1,
|
||||||
|
samsung: 4.0,
|
||||||
|
},
|
||||||
|
proxy: {
|
||||||
|
android: 49,
|
||||||
|
chrome: 49,
|
||||||
|
edge: 12,
|
||||||
|
firefox: 18,
|
||||||
|
ios: 10.0,
|
||||||
|
opera: 36,
|
||||||
|
opera_mobile: 36,
|
||||||
|
safari: 10.0,
|
||||||
|
samsung: 5.0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Map of global variables and/or instance and static properties to the
|
||||||
|
// corresponding polyfill key and actual module to import
|
||||||
|
const polyfillMap = {
|
||||||
|
global: {
|
||||||
|
Proxy: { key: "proxy", module: "proxy-polyfill" },
|
||||||
|
fetch: { key: "fetch", module: "unfetch/polyfill" },
|
||||||
|
},
|
||||||
|
instance: {},
|
||||||
|
static: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create plugin using the same factory as for CoreJS
|
||||||
|
export default defineProvider(
|
||||||
|
({ createMetaResolver, debug, shouldInjectPolyfill }) => {
|
||||||
|
const resolvePolyfill = createMetaResolver(polyfillMap);
|
||||||
|
return {
|
||||||
|
name: "HA Custom",
|
||||||
|
polyfills: PolyfillSupport,
|
||||||
|
usageGlobal(meta, utils) {
|
||||||
|
const polyfill = resolvePolyfill(meta);
|
||||||
|
if (polyfill && shouldInjectPolyfill(polyfill.desc.key)) {
|
||||||
|
debug(polyfill.desc.key);
|
||||||
|
utils.injectGlobalImport(polyfill.desc.module);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
@@ -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 }) =>
|
||||||
@@ -35,8 +31,6 @@ module.exports.emptyPackages = ({ latestBuild, isHassioBuild }) =>
|
|||||||
require.resolve(
|
require.resolve(
|
||||||
path.resolve(paths.polymer_dir, "src/resources/compatibility.ts")
|
path.resolve(paths.polymer_dir, "src/resources/compatibility.ts")
|
||||||
),
|
),
|
||||||
// This polyfill is loaded in workers to support ES5, filter it out.
|
|
||||||
latestBuild && require.resolve("proxy-polyfill/src/index.js"),
|
|
||||||
// Icons in supervisor conflict with icons in HA so we don't load.
|
// Icons in supervisor conflict with icons in HA so we don't load.
|
||||||
isHassioBuild &&
|
isHassioBuild &&
|
||||||
require.resolve(
|
require.resolve(
|
||||||
@@ -91,14 +85,12 @@ module.exports.babelOptions = ({ latestBuild, isProdBuild, isTestBuild }) => ({
|
|||||||
setSpreadProperties: true,
|
setSpreadProperties: true,
|
||||||
},
|
},
|
||||||
browserslistEnv: latestBuild ? "modern" : "legacy",
|
browserslistEnv: latestBuild ? "modern" : "legacy",
|
||||||
// Must be unambiguous because some dependencies are CommonJS only
|
|
||||||
sourceType: "unambiguous",
|
|
||||||
presets: [
|
presets: [
|
||||||
[
|
[
|
||||||
"@babel/preset-env",
|
"@babel/preset-env",
|
||||||
{
|
{
|
||||||
useBuiltIns: latestBuild ? false : "entry",
|
useBuiltIns: latestBuild ? false : "usage",
|
||||||
corejs: latestBuild ? false : { version: "3.32", proposals: true },
|
corejs: latestBuild ? false : "3.33",
|
||||||
bugfixes: true,
|
bugfixes: true,
|
||||||
shippedProposals: true,
|
shippedProposals: true,
|
||||||
},
|
},
|
||||||
@@ -116,21 +108,33 @@ module.exports.babelOptions = ({ latestBuild, isProdBuild, isTestBuild }) => ({
|
|||||||
ignoreModuleNotFound: true,
|
ignoreModuleNotFound: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
path.resolve(
|
||||||
|
paths.polymer_dir,
|
||||||
|
"build-scripts/babel-plugins/custom-polyfill-plugin.js"
|
||||||
|
),
|
||||||
|
{ method: "usage-global" },
|
||||||
|
],
|
||||||
// Minify template literals for production
|
// Minify template literals for production
|
||||||
isProdBuild && [
|
isProdBuild && [
|
||||||
"template-html-minifier",
|
"template-html-minifier",
|
||||||
{
|
{
|
||||||
modules: {
|
modules: {
|
||||||
lit: [
|
...Object.fromEntries(
|
||||||
"html",
|
["lit", "lit-element", "lit-html"].map((m) => [
|
||||||
{ name: "svg", encapsulation: "svg" },
|
m,
|
||||||
{ name: "css", encapsulation: "style" },
|
[
|
||||||
],
|
"html",
|
||||||
"@polymer/polymer/lib/utils/html-tag": ["html"],
|
{ name: "svg", encapsulation: "svg" },
|
||||||
|
{ name: "css", encapsulation: "style" },
|
||||||
|
],
|
||||||
|
])
|
||||||
|
),
|
||||||
|
"@polymer/polymer/lib/utils/html-tag.js": ["html"],
|
||||||
},
|
},
|
||||||
strictCSS: true,
|
strictCSS: true,
|
||||||
htmlMinifier: module.exports.htmlMinifierOptions,
|
htmlMinifier: module.exports.htmlMinifierOptions,
|
||||||
failOnError: true, // we can turn this off in case of false positives
|
failOnError: false, // we can turn this off in case of false positives
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
// Import helpers and regenerator from runtime package
|
// Import helpers and regenerator from runtime package
|
||||||
@@ -147,9 +151,21 @@ module.exports.babelOptions = ({ latestBuild, isProdBuild, isTestBuild }) => ({
|
|||||||
/node_modules[\\/]webpack[\\/]buildin/,
|
/node_modules[\\/]webpack[\\/]buildin/,
|
||||||
],
|
],
|
||||||
sourceMaps: !isTestBuild,
|
sourceMaps: !isTestBuild,
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
// Use unambiguous for dependencies so that require() is correctly injected into CommonJS files
|
||||||
|
// Exclusions are needed in some cases where ES modules have no static imports or exports, such as polyfills
|
||||||
|
sourceType: "unambiguous",
|
||||||
|
include: /\/node_modules\//,
|
||||||
|
exclude: [
|
||||||
|
"element-internals-polyfill",
|
||||||
|
"@?lit(?:-labs|-element|-html)?",
|
||||||
|
].map((p) => new RegExp(`/node_modules/${p}/`)),
|
||||||
|
},
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
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 +199,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",
|
||||||
|
@@ -30,8 +30,8 @@ gulp.task(
|
|||||||
env.useWDS()
|
env.useWDS()
|
||||||
? "wds-watch-app"
|
? "wds-watch-app"
|
||||||
: env.useRollup()
|
: env.useRollup()
|
||||||
? "rollup-watch-app"
|
? "rollup-watch-app"
|
||||||
: "webpack-watch-app"
|
: "webpack-watch-app"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -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")
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@@ -161,6 +161,10 @@ gulp.task("fetch-lokalise", async function () {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
throw err;
|
||||||
|
})
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@@ -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()
|
||||||
workDir + "/testMetadata.json",
|
? Promise.resolve()
|
||||||
JSON.stringify({
|
: writeFile(
|
||||||
test: {
|
workDir + "/testMetadata.json",
|
||||||
nativeName: "Test",
|
JSON.stringify({ 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",
|
...(env.isProdBuild() ? [] : [workDir + "/test.json"]),
|
||||||
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"),
|
...(env.isProdBuild() ? [] : [workDir + "/testMetadata.json"]),
|
||||||
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");
|
||||||
@@ -49,8 +51,8 @@ const createWebpackConfig = ({
|
|||||||
devtool: isTestBuild
|
devtool: isTestBuild
|
||||||
? false
|
? false
|
||||||
: isProdBuild
|
: isProdBuild
|
||||||
? "nosources-source-map"
|
? "nosources-source-map"
|
||||||
: "eval-cheap-module-source-map",
|
: "eval-cheap-module-source-map",
|
||||||
entry,
|
entry,
|
||||||
node: false,
|
node: false,
|
||||||
module: {
|
module: {
|
||||||
@@ -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"],
|
||||||
@@ -165,11 +176,14 @@ const createWebpackConfig = ({
|
|||||||
"lit/directives/guard$": "lit/directives/guard.js",
|
"lit/directives/guard$": "lit/directives/guard.js",
|
||||||
"lit/directives/cache$": "lit/directives/cache.js",
|
"lit/directives/cache$": "lit/directives/cache.js",
|
||||||
"lit/directives/repeat$": "lit/directives/repeat.js",
|
"lit/directives/repeat$": "lit/directives/repeat.js",
|
||||||
|
"lit/directives/live$": "lit/directives/live.js",
|
||||||
"lit/polyfill-support$": "lit/polyfill-support.js",
|
"lit/polyfill-support$": "lit/polyfill-support.js",
|
||||||
"@lit-labs/virtualizer/layouts/grid":
|
"@lit-labs/virtualizer/layouts/grid":
|
||||||
"@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: {
|
||||||
@@ -177,11 +191,12 @@ const createWebpackConfig = ({
|
|||||||
filename: ({ chunk }) =>
|
filename: ({ chunk }) =>
|
||||||
!isProdBuild || isStatsBuild || dontHash.has(chunk.name)
|
!isProdBuild || isStatsBuild || dontHash.has(chunk.name)
|
||||||
? "[name].js"
|
? "[name].js"
|
||||||
: "[name]-[contenthash].js",
|
: "[name].[contenthash].js",
|
||||||
chunkFilename:
|
chunkFilename:
|
||||||
isProdBuild && !isStatsBuild ? "[id]-[contenthash].js" : "[name].js",
|
isProdBuild && !isStatsBuild ? "[name].[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
|
||||||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 15 KiB |
@@ -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>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,43 +73,44 @@ class HcCast extends LitElement {
|
|||||||
${error
|
${error
|
||||||
? html` <div class="card-content">${error}</div> `
|
? html` <div class="card-content">${error}</div> `
|
||||||
: !this.castManager.status
|
: !this.castManager.status
|
||||||
? html`
|
? html`
|
||||||
<p class="center-item">
|
<p class="center-item">
|
||||||
<mwc-button raised @click=${this._handleLaunch}>
|
<mwc-button raised @click=${this._handleLaunch}>
|
||||||
<ha-svg-icon .path=${mdiCast}></ha-svg-icon>
|
<ha-svg-icon .path=${mdiCast}></ha-svg-icon>
|
||||||
Start Casting
|
Start Casting
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
</p>
|
</p>
|
||||||
`
|
`
|
||||||
: html`
|
: html`
|
||||||
<div class="section-header">PICK A VIEW</div>
|
<div class="section-header">PICK A VIEW</div>
|
||||||
<paper-listbox
|
<paper-listbox
|
||||||
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(
|
]
|
||||||
(view, idx) => html`
|
).map(
|
||||||
<paper-icon-item
|
(view, idx) => html`
|
||||||
@click=${this._handlePickView}
|
<paper-icon-item
|
||||||
data-path=${view.path || idx}
|
@click=${this._handlePickView}
|
||||||
>
|
data-path=${view.path || idx}
|
||||||
${view.icon
|
>
|
||||||
? html`
|
${view.icon
|
||||||
<ha-icon
|
? html`
|
||||||
.icon=${view.icon}
|
<ha-icon
|
||||||
slot="item-icon"
|
.icon=${view.icon}
|
||||||
></ha-icon>
|
slot="item-icon"
|
||||||
`
|
></ha-icon>
|
||||||
: ""}
|
`
|
||||||
${view.title || view.path}
|
: ""}
|
||||||
</paper-icon-item>
|
${view.title || view.path}
|
||||||
`
|
</paper-icon-item>
|
||||||
)}
|
`
|
||||||
</paper-listbox>
|
)}
|
||||||
`}
|
</paper-listbox>
|
||||||
|
`}
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
${this.castManager.status
|
${this.castManager.status
|
||||||
? html`
|
? html`
|
||||||
@@ -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,6 +1,5 @@
|
|||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
import { mdiCastConnected, mdiCast } from "@mdi/js";
|
import { mdiCastConnected, mdiCast } from "@mdi/js";
|
||||||
import "@polymer/paper-input/paper-input";
|
|
||||||
import {
|
import {
|
||||||
Auth,
|
Auth,
|
||||||
Connection,
|
Connection,
|
||||||
@@ -24,6 +23,7 @@ import "../../../../src/components/ha-svg-icon";
|
|||||||
import "../../../../src/layouts/hass-loading-screen";
|
import "../../../../src/layouts/hass-loading-screen";
|
||||||
import { registerServiceWorker } from "../../../../src/util/register-service-worker";
|
import { registerServiceWorker } from "../../../../src/util/register-service-worker";
|
||||||
import "./hc-layout";
|
import "./hc-layout";
|
||||||
|
import "../../../../src/components/ha-textfield";
|
||||||
|
|
||||||
const seeFAQ = (qid) => html`
|
const seeFAQ = (qid) => html`
|
||||||
See <a href="./faq.html${qid ? `#${qid}` : ""}">the FAQ</a> for more
|
See <a href="./faq.html${qid ? `#${qid}` : ""}">the FAQ</a> for more
|
||||||
@@ -33,13 +33,13 @@ const translateErr = (err) =>
|
|||||||
err === ERR_CANNOT_CONNECT
|
err === ERR_CANNOT_CONNECT
|
||||||
? "Unable to connect"
|
? "Unable to connect"
|
||||||
: err === ERR_HASS_HOST_REQUIRED
|
: err === ERR_HASS_HOST_REQUIRED
|
||||||
? "Please enter a Home Assistant URL."
|
? "Please enter a Home Assistant URL."
|
||||||
: err === ERR_INVALID_HTTPS_TO_HTTP
|
: err === ERR_INVALID_HTTPS_TO_HTTP
|
||||||
? html`
|
? html`
|
||||||
Cannot connect to Home Assistant instances over "http://".
|
Cannot connect to Home Assistant instances over "http://".
|
||||||
${seeFAQ("https")}
|
${seeFAQ("https")}
|
||||||
`
|
`
|
||||||
: `Unknown error (${err}).`;
|
: `Unknown error (${err}).`;
|
||||||
|
|
||||||
const INTRO = html`
|
const INTRO = html`
|
||||||
<p>
|
<p>
|
||||||
@@ -116,13 +116,11 @@ export class HcConnect extends LitElement {
|
|||||||
To get started, enter your Home Assistant URL and click authorize.
|
To get started, enter your Home Assistant URL and click authorize.
|
||||||
If you want a preview instead, click the show demo button.
|
If you want a preview instead, click the show demo button.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<ha-textfield
|
||||||
<paper-input
|
label="Home Assistant URL"
|
||||||
label="Home Assistant URL"
|
placeholder="https://abcdefghijklmnop.ui.nabu.casa"
|
||||||
placeholder="https://abcdefghijklmnop.ui.nabu.casa"
|
@keydown=${this._handleInputKeyDown}
|
||||||
@keydown=${this._handleInputKeyDown}
|
></ha-textfield>
|
||||||
></paper-input>
|
|
||||||
</p>
|
|
||||||
${this.error ? html` <p class="error">${this.error}</p> ` : ""}
|
${this.error ? html` <p class="error">${this.error}</p> ` : ""}
|
||||||
</div>
|
</div>
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
@@ -196,7 +194,7 @@ export class HcConnect extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _handleConnect() {
|
private async _handleConnect() {
|
||||||
const inputEl = this.shadowRoot!.querySelector("paper-input")!;
|
const inputEl = this.shadowRoot!.querySelector("ha-textfield")!;
|
||||||
const value = inputEl.value || "";
|
const value = inputEl.value || "";
|
||||||
this.error = undefined;
|
this.error = undefined;
|
||||||
|
|
||||||
@@ -315,6 +313,10 @@ export class HcConnect extends LitElement {
|
|||||||
.spacer {
|
.spacer {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ha-textfield {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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,17 +21,27 @@ 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_CONFIG: LovelaceDashboardStrategyConfig = {
|
||||||
|
strategy: {
|
||||||
|
type: "original-states",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
let resourcesLoaded = false;
|
let resourcesLoaded = false;
|
||||||
@customElement("hc-main")
|
@customElement("hc-main")
|
||||||
export class HcMain extends HassElement {
|
export class HcMain extends HassElement {
|
||||||
@@ -91,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)) {
|
||||||
@@ -258,7 +270,6 @@ export class HcMain extends HassElement {
|
|||||||
{
|
{
|
||||||
strategy: {
|
strategy: {
|
||||||
type: "energy",
|
type: "energy",
|
||||||
options: { show_date_selection: true },
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -281,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) &&
|
||||||
@@ -297,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) {
|
||||||
@@ -306,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,
|
||||||
hass: this.hass!,
|
this.hass!
|
||||||
narrow: false,
|
|
||||||
},
|
|
||||||
"original-states"
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -1,3 +0,0 @@
|
|||||||
import "../../../src/resources/ha-style";
|
|
||||||
import "../../../src/resources/roboto";
|
|
||||||
import "./layout/hc-lovelace";
|
|
@@ -8,25 +8,67 @@
|
|||||||
"src": "/static/icons/favicon-192x192.png",
|
"src": "/static/icons/favicon-192x192.png",
|
||||||
"sizes": "192x192",
|
"sizes": "192x192",
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"purpose": "maskable any"
|
"purpose": "any"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "/static/icons/favicon-384x384.png",
|
"src": "/static/icons/favicon-384x384.png",
|
||||||
"sizes": "384x384",
|
"sizes": "384x384",
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"purpose": "maskable any"
|
"purpose": "any"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "/static/icons/favicon-512x512.png",
|
"src": "/static/icons/favicon-512x512.png",
|
||||||
"sizes": "512x512",
|
"sizes": "512x512",
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"purpose": "maskable any"
|
"purpose": "any"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "/static/icons/favicon-1024x1024.png",
|
"src": "/static/icons/favicon-1024x1024.png",
|
||||||
"sizes": "1024x1024",
|
"sizes": "1024x1024",
|
||||||
"type": "image/png",
|
"type": "image/png",
|
||||||
"purpose": "maskable any"
|
"purpose": "any"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/static/icons/maskable_icon-48x48.png",
|
||||||
|
"sizes": "48x48",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/static/icons/maskable_icon-72x72.png",
|
||||||
|
"sizes": "72x72",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/static/icons/maskable_icon-96x96.png",
|
||||||
|
"sizes": "96x96",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/static/icons/maskable_icon-128x128.png",
|
||||||
|
"sizes": "128x128",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/static/icons/maskable_icon-192x192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/static/icons/maskable_icon-384x384.png",
|
||||||
|
"sizes": "384x384",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/static/icons/maskable_icon-512x512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"lang": "en-US",
|
"lang": "en-US",
|
||||||
|
@@ -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 {
|
||||||
@@ -39,7 +39,9 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
|||||||
<div class="picker">
|
<div class="picker">
|
||||||
<div class="label">
|
<div class="label">
|
||||||
${this._switching
|
${this._switching
|
||||||
? html`<ha-circular-progress active></ha-circular-progress>`
|
? html`<ha-circular-progress
|
||||||
|
indeterminate
|
||||||
|
></ha-circular-progress>`
|
||||||
: until(
|
: until(
|
||||||
selectedDemoConfig.then(
|
selectedDemoConfig.then(
|
||||||
(conf) => html`
|
(conf) => html`
|
||||||
@@ -48,8 +50,7 @@ export class HADemoCard extends LitElement implements LovelaceCard {
|
|||||||
<a target="_blank" href=${conf.authorUrl}>
|
<a target="_blank" href=${conf.authorUrl}>
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
"ui.panel.page-demo.cards.demo.demo_by",
|
"ui.panel.page-demo.cards.demo.demo_by",
|
||||||
"name",
|
{ name: conf.authorName }
|
||||||
conf.authorName
|
|
||||||
)}
|
)}
|
||||||
</a>
|
</a>
|
||||||
</small>
|
</small>
|
||||||
|
@@ -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);
|
||||||
|
@@ -62,10 +62,24 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
#ha-launch-screen svg {
|
||||||
|
width: 170px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
#ha-launch-screen .ha-launch-screen-spacer {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="ha-launch-screen"></div>
|
<div id="ha-launch-screen">
|
||||||
|
<div class="ha-launch-screen-spacer"></div>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" 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"/>
|
||||||
|
<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"/>
|
||||||
|
</svg>
|
||||||
|
<div id="ha-launch-screen-info-box" class="ha-launch-screen-spacer"></div>
|
||||||
|
</div>
|
||||||
<ha-demo></ha-demo>
|
<ha-demo></ha-demo>
|
||||||
<%= renderTemplate("../../../src/html/_js_base.html.template") %>
|
<%= renderTemplate("../../../src/html/_js_base.html.template") %>
|
||||||
<%= renderTemplate("../../../src/html/_preload_roboto.html.template") %>
|
<%= renderTemplate("../../../src/html/_preload_roboto.html.template") %>
|
||||||
|
@@ -43,8 +43,8 @@ const generateMeanStatistics = (
|
|||||||
period === "day"
|
period === "day"
|
||||||
? addDays(currentDate, 1)
|
? addDays(currentDate, 1)
|
||||||
: period === "month"
|
: period === "month"
|
||||||
? addMonths(currentDate, 1)
|
? addMonths(currentDate, 1)
|
||||||
: addHours(currentDate, 1);
|
: addHours(currentDate, 1);
|
||||||
}
|
}
|
||||||
return statistics;
|
return statistics;
|
||||||
};
|
};
|
||||||
@@ -80,8 +80,8 @@ const generateSumStatistics = (
|
|||||||
period === "day"
|
period === "day"
|
||||||
? addDays(currentDate, 1)
|
? addDays(currentDate, 1)
|
||||||
: period === "month"
|
: period === "month"
|
||||||
? addMonths(currentDate, 1)
|
? addMonths(currentDate, 1)
|
||||||
: addHours(currentDate, 1);
|
: addHours(currentDate, 1);
|
||||||
}
|
}
|
||||||
return statistics;
|
return statistics;
|
||||||
};
|
};
|
||||||
|
@@ -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
@@ -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[],
|
||||||
|
}));
|
||||||
|
};
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 10 KiB |
@@ -23,7 +23,7 @@ class DemoMoreInfo extends LitElement {
|
|||||||
<state-card-content
|
<state-card-content
|
||||||
.stateObj=${state}
|
.stateObj=${state}
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
in-dialog
|
inDialog
|
||||||
></state-card-content>
|
></state-card-content>
|
||||||
|
|
||||||
<more-info-content
|
<more-info-content
|
||||||
|
@@ -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,19 +1,17 @@
|
|||||||
import { mdiHomeAssistant } from "@mdi/js";
|
import { css, html, LitElement, TemplateResult, nothing } 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 "../../../../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";
|
||||||
|
|
||||||
const chips: {
|
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;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
title: Circular Progress
|
||||||
|
subtitle: Can be used to indicate an ongoing task.
|
||||||
|
---
|
64
gallery/src/pages/components/ha-circular-progress.ts
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import { html, css, LitElement, TemplateResult } from "lit";
|
||||||
|
import { customElement, property } from "lit/decorators";
|
||||||
|
import "../../../../src/components/ha-bar";
|
||||||
|
import "../../../../src/components/ha-card";
|
||||||
|
import "../../../../src/components/ha-circular-progress";
|
||||||
|
import "@material/web/progress/circular-progress";
|
||||||
|
import { HomeAssistant } from "../../../../src/types";
|
||||||
|
|
||||||
|
@customElement("demo-components-ha-circular-progress")
|
||||||
|
export class DemoHaCircularProgress extends LitElement {
|
||||||
|
@property({ attribute: false }) hass!: HomeAssistant;
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
return html`<ha-card header="Basic circular progress">
|
||||||
|
<div class="card-content">
|
||||||
|
<ha-circular-progress indeterminate></ha-circular-progress></div
|
||||||
|
></ha-card>
|
||||||
|
<ha-card header="Different circular progress sizes">
|
||||||
|
<div class="card-content">
|
||||||
|
<ha-circular-progress
|
||||||
|
indeterminate
|
||||||
|
size="tiny"
|
||||||
|
></ha-circular-progress>
|
||||||
|
<ha-circular-progress
|
||||||
|
indeterminate
|
||||||
|
size="small"
|
||||||
|
></ha-circular-progress>
|
||||||
|
<ha-circular-progress
|
||||||
|
indeterminate
|
||||||
|
size="medium"
|
||||||
|
></ha-circular-progress>
|
||||||
|
<ha-circular-progress
|
||||||
|
indeterminate
|
||||||
|
size="large"
|
||||||
|
></ha-circular-progress></div
|
||||||
|
></ha-card>
|
||||||
|
<ha-card header="Circular progress with an aria-label">
|
||||||
|
<div class="card-content">
|
||||||
|
<ha-circular-progress
|
||||||
|
indeterminate
|
||||||
|
aria-label="Doing something..."
|
||||||
|
></ha-circular-progress>
|
||||||
|
<ha-circular-progress
|
||||||
|
indeterminate
|
||||||
|
.ariaLabel=${"Doing something..."}
|
||||||
|
></ha-circular-progress></div
|
||||||
|
></ha-card>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return css`
|
||||||
|
ha-card {
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 24px auto;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"demo-components-ha-circular-progress": DemoHaCircularProgress;
|
||||||
|
}
|
||||||
|
}
|
@@ -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,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@@ -18,7 +18,7 @@ The Home Assistant interface is based on Material Design. It's a design system c
|
|||||||
|
|
||||||
We want to make it as easy for designers to contribute as it is for developers. There’s a lot a designer can contribute to:
|
We want to make it as easy for designers to contribute as it is for developers. There’s a lot a designer can contribute to:
|
||||||
|
|
||||||
- Meet us at <a href="https://discord.gg/BPBc8rZ9" rel="noopener noreferrer" target="_blank">devs_ux Discord</a>. Feel free to share your designs, user test or strategic ideas.
|
- Meet us at <a href="https://www.home-assistant.io/join-chat" rel="noopener noreferrer" target="_blank">devs_ux Discord</a>. Feel free to share your designs, user test or strategic ideas.
|
||||||
- Start designing with our <a href="https://www.figma.com/community/file/967153512097289521/Home-Assistant-DesignKit" rel="noopener noreferrer" target="_blank">Figma DesignKit</a>.
|
- Start designing with our <a href="https://www.figma.com/community/file/967153512097289521/Home-Assistant-DesignKit" rel="noopener noreferrer" target="_blank">Figma DesignKit</a>.
|
||||||
- Find the latest UX <a href="https://github.com/home-assistant/frontend/discussions?discussions_q=label%3Aux" rel="noopener noreferrer" target="_blank">discussions</a> and <a href="https://github.com/home-assistant/frontend/labels/ux" rel="noopener noreferrer" target="_blank">issues</a> on GitHub. Everyone can start a new issue or discussion!
|
- Find the latest UX <a href="https://github.com/home-assistant/frontend/discussions?discussions_q=label%3Aux" rel="noopener noreferrer" target="_blank">discussions</a> and <a href="https://github.com/home-assistant/frontend/labels/ux" rel="noopener noreferrer" target="_blank">issues</a> on GitHub. Everyone can start a new issue or discussion!
|
||||||
|
|
||||||
|
@@ -1,3 +0,0 @@
|
|||||||
---
|
|
||||||
title: Shopping List Card
|
|
||||||
---
|
|
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")
|
||||||
|
3
gallery/src/pages/more-info/input-text.markdown
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
title: Input Text
|
||||||
|
---
|
46
gallery/src/pages/more-info/input-text.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||||
|
import { customElement, property, query } from "lit/decorators";
|
||||||
|
import "../../../../src/components/ha-card";
|
||||||
|
import "../../../../src/dialogs/more-info/more-info-content";
|
||||||
|
import { getEntity } from "../../../../src/fake_data/entity";
|
||||||
|
import {
|
||||||
|
MockHomeAssistant,
|
||||||
|
provideHass,
|
||||||
|
} from "../../../../src/fake_data/provide_hass";
|
||||||
|
import "../../components/demo-more-infos";
|
||||||
|
|
||||||
|
const ENTITIES = [
|
||||||
|
getEntity("input_text", "text", "Inspiration", {
|
||||||
|
friendly_name: "Text",
|
||||||
|
mode: "text",
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
@customElement("demo-more-info-input-text")
|
||||||
|
class DemoMoreInfoInputText extends LitElement {
|
||||||
|
@property() public hass!: MockHomeAssistant;
|
||||||
|
|
||||||
|
@query("demo-more-infos") private _demoRoot!: HTMLElement;
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<demo-more-infos
|
||||||
|
.hass=${this.hass}
|
||||||
|
.entities=${ENTITIES.map((ent) => ent.entityId)}
|
||||||
|
></demo-more-infos>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected firstUpdated(changedProperties: PropertyValues) {
|
||||||
|
super.firstUpdated(changedProperties);
|
||||||
|
const hass = provideHass(this._demoRoot);
|
||||||
|
hass.updateTranslations(null, "en");
|
||||||
|
hass.addEntities(ENTITIES);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"demo-more-info-input-text": DemoMoreInfoInputText;
|
||||||
|
}
|
||||||
|
}
|
3
gallery/src/pages/more-info/lock.markdown
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
title: Lock
|
||||||
|
---
|
49
gallery/src/pages/more-info/lock.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||||
|
import { customElement, property, query } from "lit/decorators";
|
||||||
|
import "../../../../src/components/ha-card";
|
||||||
|
import "../../../../src/dialogs/more-info/more-info-content";
|
||||||
|
import { getEntity } from "../../../../src/fake_data/entity";
|
||||||
|
import {
|
||||||
|
MockHomeAssistant,
|
||||||
|
provideHass,
|
||||||
|
} from "../../../../src/fake_data/provide_hass";
|
||||||
|
import "../../components/demo-more-infos";
|
||||||
|
|
||||||
|
const ENTITIES = [
|
||||||
|
getEntity("lock", "lock", "locked", {
|
||||||
|
friendly_name: "Lock",
|
||||||
|
device_class: "lock",
|
||||||
|
}),
|
||||||
|
getEntity("lock", "unavailable", "unavailable", {
|
||||||
|
friendly_name: "Unavailable lock",
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
@customElement("demo-more-info-lock")
|
||||||
|
class DemoMoreInfoLock extends LitElement {
|
||||||
|
@property() public hass!: MockHomeAssistant;
|
||||||
|
|
||||||
|
@query("demo-more-infos") private _demoRoot!: HTMLElement;
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<demo-more-infos
|
||||||
|
.hass=${this.hass}
|
||||||
|
.entities=${ENTITIES.map((ent) => ent.entityId)}
|
||||||
|
></demo-more-infos>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected firstUpdated(changedProperties: PropertyValues) {
|
||||||
|
super.firstUpdated(changedProperties);
|
||||||
|
const hass = provideHass(this._demoRoot);
|
||||||
|
hass.updateTranslations(null, "en");
|
||||||
|
hass.addEntities(ENTITIES);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"demo-more-info-lock": DemoMoreInfoLock;
|
||||||
|
}
|
||||||
|
}
|
3
gallery/src/pages/more-info/media-player.markdown
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
title: Media Player
|
||||||
|
---
|
41
gallery/src/pages/more-info/media-player.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||||
|
import { customElement, property, query } from "lit/decorators";
|
||||||
|
import "../../../../src/components/ha-card";
|
||||||
|
import "../../../../src/dialogs/more-info/more-info-content";
|
||||||
|
import {
|
||||||
|
MockHomeAssistant,
|
||||||
|
provideHass,
|
||||||
|
} from "../../../../src/fake_data/provide_hass";
|
||||||
|
import "../../components/demo-more-infos";
|
||||||
|
import { createMediaPlayerEntities } from "../../data/media_players";
|
||||||
|
|
||||||
|
const ENTITIES = createMediaPlayerEntities();
|
||||||
|
|
||||||
|
@customElement("demo-more-info-media-player")
|
||||||
|
class DemoMoreInfoMediaPlayer extends LitElement {
|
||||||
|
@property() public hass!: MockHomeAssistant;
|
||||||
|
|
||||||
|
@query("demo-more-infos") private _demoRoot!: HTMLElement;
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<demo-more-infos
|
||||||
|
.hass=${this.hass}
|
||||||
|
.entities=${ENTITIES.map((ent) => ent.entityId)}
|
||||||
|
></demo-more-infos>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected firstUpdated(changedProperties: PropertyValues) {
|
||||||
|
super.firstUpdated(changedProperties);
|
||||||
|
const hass = provideHass(this._demoRoot);
|
||||||
|
hass.updateTranslations(null, "en");
|
||||||
|
hass.addEntities(ENTITIES);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"demo-more-info-media-player": DemoMoreInfoMediaPlayer;
|
||||||
|
}
|
||||||
|
}
|
3
gallery/src/pages/more-info/number.markdown
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
title: Number
|
||||||
|
---
|
78
gallery/src/pages/more-info/number.ts
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||||
|
import { customElement, property, query } from "lit/decorators";
|
||||||
|
import "../../../../src/components/ha-card";
|
||||||
|
import "../../../../src/dialogs/more-info/more-info-content";
|
||||||
|
import { getEntity } from "../../../../src/fake_data/entity";
|
||||||
|
import {
|
||||||
|
MockHomeAssistant,
|
||||||
|
provideHass,
|
||||||
|
} from "../../../../src/fake_data/provide_hass";
|
||||||
|
import "../../components/demo-more-infos";
|
||||||
|
|
||||||
|
const ENTITIES = [
|
||||||
|
getEntity("number", "box1", 0, {
|
||||||
|
friendly_name: "Box1",
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
step: 1,
|
||||||
|
initial: 0,
|
||||||
|
mode: "box",
|
||||||
|
unit_of_measurement: "items",
|
||||||
|
}),
|
||||||
|
getEntity("number", "slider1", 0, {
|
||||||
|
friendly_name: "Slider1",
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
step: 1,
|
||||||
|
initial: 0,
|
||||||
|
mode: "slider",
|
||||||
|
unit_of_measurement: "items",
|
||||||
|
}),
|
||||||
|
getEntity("number", "auto1", 0, {
|
||||||
|
friendly_name: "Auto1",
|
||||||
|
min: 0,
|
||||||
|
max: 1000,
|
||||||
|
step: 1,
|
||||||
|
initial: 0,
|
||||||
|
mode: "auto",
|
||||||
|
unit_of_measurement: "items",
|
||||||
|
}),
|
||||||
|
getEntity("number", "auto2", 0, {
|
||||||
|
friendly_name: "Auto2",
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
step: 1,
|
||||||
|
initial: 0,
|
||||||
|
mode: "auto",
|
||||||
|
unit_of_measurement: "items",
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
@customElement("demo-more-info-number")
|
||||||
|
class DemoMoreInfoNumber extends LitElement {
|
||||||
|
@property() public hass!: MockHomeAssistant;
|
||||||
|
|
||||||
|
@query("demo-more-infos") private _demoRoot!: HTMLElement;
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<demo-more-infos
|
||||||
|
.hass=${this.hass}
|
||||||
|
.entities=${ENTITIES.map((ent) => ent.entityId)}
|
||||||
|
></demo-more-infos>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected firstUpdated(changedProperties: PropertyValues) {
|
||||||
|
super.firstUpdated(changedProperties);
|
||||||
|
const hass = provideHass(this._demoRoot);
|
||||||
|
hass.updateTranslations(null, "en");
|
||||||
|
hass.addEntities(ENTITIES);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"demo-more-info-number": DemoMoreInfoNumber;
|
||||||
|
}
|
||||||
|
}
|
3
gallery/src/pages/more-info/scene.markdown
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
title: Scene
|
||||||
|
---
|
49
gallery/src/pages/more-info/scene.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||||
|
import { customElement, property, query } from "lit/decorators";
|
||||||
|
import "../../../../src/components/ha-card";
|
||||||
|
import "../../../../src/dialogs/more-info/more-info-content";
|
||||||
|
import { getEntity } from "../../../../src/fake_data/entity";
|
||||||
|
import {
|
||||||
|
MockHomeAssistant,
|
||||||
|
provideHass,
|
||||||
|
} from "../../../../src/fake_data/provide_hass";
|
||||||
|
import "../../components/demo-more-infos";
|
||||||
|
|
||||||
|
const ENTITIES = [
|
||||||
|
getEntity("scene", "romantic_lights", "scening", {
|
||||||
|
entity_id: ["light.bed_light", "light.ceiling_lights"],
|
||||||
|
friendly_name: "Romantic Scene",
|
||||||
|
}),
|
||||||
|
getEntity("scene", "unavailable", "unavailable", {
|
||||||
|
friendly_name: "Romantic Scene",
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
@customElement("demo-more-info-scene")
|
||||||
|
class DemoMoreInfoScene extends LitElement {
|
||||||
|
@property() public hass!: MockHomeAssistant;
|
||||||
|
|
||||||
|
@query("demo-more-infos") private _demoRoot!: HTMLElement;
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<demo-more-infos
|
||||||
|
.hass=${this.hass}
|
||||||
|
.entities=${ENTITIES.map((ent) => ent.entityId)}
|
||||||
|
></demo-more-infos>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected firstUpdated(changedProperties: PropertyValues) {
|
||||||
|
super.firstUpdated(changedProperties);
|
||||||
|
const hass = provideHass(this._demoRoot);
|
||||||
|
hass.updateTranslations(null, "en");
|
||||||
|
hass.addEntities(ENTITIES);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"demo-more-info-scene": DemoMoreInfoScene;
|
||||||
|
}
|
||||||
|
}
|
3
gallery/src/pages/more-info/timer.markdown
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
title: Timer
|
||||||
|
---
|
46
gallery/src/pages/more-info/timer.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||||
|
import { customElement, property, query } from "lit/decorators";
|
||||||
|
import "../../../../src/components/ha-card";
|
||||||
|
import "../../../../src/dialogs/more-info/more-info-content";
|
||||||
|
import { getEntity } from "../../../../src/fake_data/entity";
|
||||||
|
import {
|
||||||
|
MockHomeAssistant,
|
||||||
|
provideHass,
|
||||||
|
} from "../../../../src/fake_data/provide_hass";
|
||||||
|
import "../../components/demo-more-infos";
|
||||||
|
|
||||||
|
const ENTITIES = [
|
||||||
|
getEntity("timer", "timer", "idle", {
|
||||||
|
friendly_name: "Timer",
|
||||||
|
duration: "0:05:00",
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
@customElement("demo-more-info-timer")
|
||||||
|
class DemoMoreInfoTimer extends LitElement {
|
||||||
|
@property() public hass!: MockHomeAssistant;
|
||||||
|
|
||||||
|
@query("demo-more-infos") private _demoRoot!: HTMLElement;
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<demo-more-infos
|
||||||
|
.hass=${this.hass}
|
||||||
|
.entities=${ENTITIES.map((ent) => ent.entityId)}
|
||||||
|
></demo-more-infos>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected firstUpdated(changedProperties: PropertyValues) {
|
||||||
|
super.firstUpdated(changedProperties);
|
||||||
|
const hass = provideHass(this._demoRoot);
|
||||||
|
hass.updateTranslations(null, "en");
|
||||||
|
hass.addEntities(ENTITIES);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"demo-more-info-timer": DemoMoreInfoTimer;
|
||||||
|
}
|
||||||
|
}
|
3
gallery/src/pages/more-info/vacuum.markdown
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
title: Vacuum
|
||||||
|
---
|
50
gallery/src/pages/more-info/vacuum.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
|
||||||
|
import { customElement, property, query } from "lit/decorators";
|
||||||
|
import "../../../../src/components/ha-card";
|
||||||
|
import "../../../../src/dialogs/more-info/more-info-content";
|
||||||
|
import { getEntity } from "../../../../src/fake_data/entity";
|
||||||
|
import {
|
||||||
|
MockHomeAssistant,
|
||||||
|
provideHass,
|
||||||
|
} from "../../../../src/fake_data/provide_hass";
|
||||||
|
import "../../components/demo-more-infos";
|
||||||
|
import { VacuumEntityFeature } from "../../../../src/data/vacuum";
|
||||||
|
|
||||||
|
const ENTITIES = [
|
||||||
|
getEntity("vacuum", "first_floor_vacuum", "docked", {
|
||||||
|
friendly_name: "First floor vacuum",
|
||||||
|
supported_features:
|
||||||
|
VacuumEntityFeature.START +
|
||||||
|
VacuumEntityFeature.STOP +
|
||||||
|
VacuumEntityFeature.RETURN_HOME,
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
@customElement("demo-more-info-vacuum")
|
||||||
|
class DemoMoreInfoVacuum extends LitElement {
|
||||||
|
@property() public hass!: MockHomeAssistant;
|
||||||
|
|
||||||
|
@query("demo-more-infos") private _demoRoot!: HTMLElement;
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<demo-more-infos
|
||||||
|
.hass=${this.hass}
|
||||||
|
.entities=${ENTITIES.map((ent) => ent.entityId)}
|
||||||
|
></demo-more-infos>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected firstUpdated(changedProperties: PropertyValues) {
|
||||||
|
super.firstUpdated(changedProperties);
|
||||||
|
const hass = provideHass(this._demoRoot);
|
||||||
|
hass.updateTranslations(null, "en");
|
||||||
|
hass.addEntities(ENTITIES);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"demo-more-info-vacuum": DemoMoreInfoVacuum;
|
||||||
|
}
|
||||||
|
}
|
@@ -49,11 +49,9 @@ export class HassioAddonRepositoryEl extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<p class="description">
|
<p class="description">
|
||||||
${this.supervisor.localize(
|
${this.supervisor.localize("store.no_results_found", {
|
||||||
"store.no_results_found",
|
repository: repo.name,
|
||||||
"repository",
|
})}
|
||||||
repo.name
|
|
||||||
)}
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@@ -86,15 +84,15 @@ export class HassioAddonRepositoryEl extends LitElement {
|
|||||||
)
|
)
|
||||||
: this.supervisor.localize("addon.state.installed")
|
: this.supervisor.localize("addon.state.installed")
|
||||||
: addon.available
|
: addon.available
|
||||||
? this.supervisor.localize("addon.state.not_installed")
|
? this.supervisor.localize("addon.state.not_installed")
|
||||||
: this.supervisor.localize("addon.state.not_available")}
|
: this.supervisor.localize("addon.state.not_available")}
|
||||||
.iconClass=${addon.installed
|
.iconClass=${addon.installed
|
||||||
? addon.update_available
|
? addon.update_available
|
||||||
? "update"
|
? "update"
|
||||||
: "installed"
|
: "installed"
|
||||||
: !addon.available
|
: !addon.available
|
||||||
? "not_available"
|
? "not_available"
|
||||||
: ""}
|
: ""}
|
||||||
.iconImage=${atLeastVersion(
|
.iconImage=${atLeastVersion(
|
||||||
this.hass.config.version,
|
this.hass.config.version,
|
||||||
0,
|
0,
|
||||||
@@ -108,8 +106,8 @@ export class HassioAddonRepositoryEl extends LitElement {
|
|||||||
? "update"
|
? "update"
|
||||||
: "installed"
|
: "installed"
|
||||||
: !addon.available
|
: !addon.available
|
||||||
? "unavailable"
|
? "unavailable"
|
||||||
: ""}
|
: ""}
|
||||||
></hassio-card-content>
|
></hassio-card-content>
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
|
@@ -20,7 +20,7 @@ class HassioAddonConfigDashboard extends LitElement {
|
|||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (!this.addon) {
|
if (!this.addon) {
|
||||||
return html`<ha-circular-progress active></ha-circular-progress>`;
|
return html`<ha-circular-progress indeterminate></ha-circular-progress>`;
|
||||||
}
|
}
|
||||||
const hasConfiguration =
|
const hasConfiguration =
|
||||||
(this.addon.options && Object.keys(this.addon.options).length) ||
|
(this.addon.options && Object.keys(this.addon.options).length) ||
|
||||||
|
@@ -104,50 +104,50 @@ class HassioAddonConfig extends LitElement {
|
|||||||
selector: { select: { options: entry.options } },
|
selector: { select: { options: entry.options } },
|
||||||
}
|
}
|
||||||
: entry.type === "string"
|
: entry.type === "string"
|
||||||
? entry.multiple
|
? entry.multiple
|
||||||
? {
|
? {
|
||||||
name: entry.name,
|
name: entry.name,
|
||||||
required: entry.required,
|
required: entry.required,
|
||||||
selector: {
|
selector: {
|
||||||
select: { options: [], multiple: true, custom_value: true },
|
select: { options: [], multiple: true, custom_value: true },
|
||||||
},
|
|
||||||
}
|
|
||||||
: {
|
|
||||||
name: entry.name,
|
|
||||||
required: entry.required,
|
|
||||||
selector: {
|
|
||||||
text: {
|
|
||||||
type:
|
|
||||||
entry.format || MASKED_FIELDS.includes(entry.name)
|
|
||||||
? "password"
|
|
||||||
: "text",
|
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
}
|
: {
|
||||||
: entry.type === "boolean"
|
name: entry.name,
|
||||||
? {
|
required: entry.required,
|
||||||
name: entry.name,
|
selector: {
|
||||||
required: entry.required,
|
text: {
|
||||||
selector: { boolean: {} },
|
type:
|
||||||
}
|
entry.format || MASKED_FIELDS.includes(entry.name)
|
||||||
: entry.type === "schema"
|
? "password"
|
||||||
? {
|
: "text",
|
||||||
name: entry.name,
|
},
|
||||||
required: entry.required,
|
},
|
||||||
selector: { object: {} },
|
}
|
||||||
}
|
: entry.type === "boolean"
|
||||||
: entry.type === "float" || entry.type === "integer"
|
? {
|
||||||
? {
|
name: entry.name,
|
||||||
name: entry.name,
|
required: entry.required,
|
||||||
required: entry.required,
|
selector: { boolean: {} },
|
||||||
selector: {
|
}
|
||||||
number: {
|
: entry.type === "schema"
|
||||||
mode: "box",
|
? {
|
||||||
step: entry.type === "float" ? "any" : undefined,
|
name: entry.name,
|
||||||
},
|
required: entry.required,
|
||||||
},
|
selector: { object: {} },
|
||||||
}
|
}
|
||||||
: entry
|
: entry.type === "float" || entry.type === "integer"
|
||||||
|
? {
|
||||||
|
name: entry.name,
|
||||||
|
required: entry.required,
|
||||||
|
selector: {
|
||||||
|
number: {
|
||||||
|
mode: "box",
|
||||||
|
step: entry.type === "float" ? "any" : undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: entry
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -340,11 +340,9 @@ class HassioAddonConfig extends LitElement {
|
|||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize("addon.failed_to_reset", {
|
||||||
"addon.failed_to_reset",
|
error: extractApiErrorMessage(err),
|
||||||
"error",
|
});
|
||||||
extractApiErrorMessage(err)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
button.progress = false;
|
button.progress = false;
|
||||||
}
|
}
|
||||||
@@ -381,11 +379,9 @@ class HassioAddonConfig extends LitElement {
|
|||||||
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
|
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
|
||||||
}
|
}
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize("addon.failed_to_save", {
|
||||||
"addon.failed_to_save",
|
error: extractApiErrorMessage(err),
|
||||||
"error",
|
});
|
||||||
extractApiErrorMessage(err)
|
|
||||||
);
|
|
||||||
eventdata.success = false;
|
eventdata.success = false;
|
||||||
}
|
}
|
||||||
button.progress = false;
|
button.progress = false;
|
||||||
|
@@ -180,11 +180,9 @@ class HassioAddonNetwork extends LitElement {
|
|||||||
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
|
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
|
||||||
}
|
}
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize("addon.failed_to_reset", {
|
||||||
"addon.failed_to_reset",
|
error: extractApiErrorMessage(err),
|
||||||
"error",
|
});
|
||||||
extractApiErrorMessage(err)
|
|
||||||
);
|
|
||||||
button.actionError();
|
button.actionError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -220,11 +218,9 @@ class HassioAddonNetwork extends LitElement {
|
|||||||
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
|
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
|
||||||
}
|
}
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize("addon.failed_to_save", {
|
||||||
"addon.failed_to_save",
|
error: extractApiErrorMessage(err),
|
||||||
"error",
|
});
|
||||||
extractApiErrorMessage(err)
|
|
||||||
);
|
|
||||||
button.actionError();
|
button.actionError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -34,7 +34,7 @@ class HassioAddonDocumentationDashboard extends LitElement {
|
|||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (!this.addon) {
|
if (!this.addon) {
|
||||||
return html`<ha-circular-progress active></ha-circular-progress>`;
|
return html`<ha-circular-progress indeterminate></ha-circular-progress>`;
|
||||||
}
|
}
|
||||||
return html`
|
return html`
|
||||||
<div class="content">
|
<div class="content">
|
||||||
@@ -85,8 +85,7 @@ class HassioAddonDocumentationDashboard extends LitElement {
|
|||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize(
|
||||||
"addon.documentation.get_documentation",
|
"addon.documentation.get_documentation",
|
||||||
"error",
|
{ error: extractApiErrorMessage(err) }
|
||||||
extractApiErrorMessage(err)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -22,7 +22,7 @@ class HassioAddonInfoDashboard extends LitElement {
|
|||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (!this.addon) {
|
if (!this.addon) {
|
||||||
return html`<ha-circular-progress active></ha-circular-progress>`;
|
return html`<ha-circular-progress indeterminate></ha-circular-progress>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
|
@@ -7,7 +7,6 @@ import {
|
|||||||
mdiDocker,
|
mdiDocker,
|
||||||
mdiExclamationThick,
|
mdiExclamationThick,
|
||||||
mdiFlask,
|
mdiFlask,
|
||||||
mdiHomeAssistant,
|
|
||||||
mdiKey,
|
mdiKey,
|
||||||
mdiLinkLock,
|
mdiLinkLock,
|
||||||
mdiNetwork,
|
mdiNetwork,
|
||||||
@@ -22,7 +21,7 @@ import {
|
|||||||
mdiPound,
|
mdiPound,
|
||||||
mdiShield,
|
mdiShield,
|
||||||
} from "@mdi/js";
|
} from "@mdi/js";
|
||||||
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 { classMap } from "lit/directives/class-map";
|
import { classMap } from "lit/directives/class-map";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
@@ -32,19 +31,19 @@ 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";
|
||||||
import "../../../../src/components/ha-switch";
|
import "../../../../src/components/ha-switch";
|
||||||
import {
|
import {
|
||||||
AddonCapability,
|
AddonCapability,
|
||||||
fetchHassioAddonChangelog,
|
|
||||||
fetchHassioAddonInfo,
|
|
||||||
HassioAddonDetails,
|
HassioAddonDetails,
|
||||||
HassioAddonSetOptionParams,
|
HassioAddonSetOptionParams,
|
||||||
HassioAddonSetSecurityParams,
|
HassioAddonSetSecurityParams,
|
||||||
|
fetchHassioAddonChangelog,
|
||||||
|
fetchHassioAddonInfo,
|
||||||
installHassioAddon,
|
installHassioAddon,
|
||||||
rebuildLocalAddon,
|
rebuildLocalAddon,
|
||||||
restartHassioAddon,
|
restartHassioAddon,
|
||||||
@@ -56,9 +55,9 @@ import {
|
|||||||
validateHassioAddonOption,
|
validateHassioAddonOption,
|
||||||
} from "../../../../src/data/hassio/addon";
|
} from "../../../../src/data/hassio/addon";
|
||||||
import {
|
import {
|
||||||
|
HassioStats,
|
||||||
extractApiErrorMessage,
|
extractApiErrorMessage,
|
||||||
fetchHassioStats,
|
fetchHassioStats,
|
||||||
HassioStats,
|
|
||||||
} from "../../../../src/data/hassio/common";
|
} from "../../../../src/data/hassio/common";
|
||||||
import {
|
import {
|
||||||
StoreAddon,
|
StoreAddon,
|
||||||
@@ -69,6 +68,7 @@ import {
|
|||||||
showAlertDialog,
|
showAlertDialog,
|
||||||
showConfirmationDialog,
|
showConfirmationDialog,
|
||||||
} from "../../../../src/dialogs/generic/show-dialog-box";
|
} from "../../../../src/dialogs/generic/show-dialog-box";
|
||||||
|
import { mdiHomeAssistant } from "../../../../src/resources/home-assistant-logo-svg";
|
||||||
import { haStyle } from "../../../../src/resources/styles";
|
import { haStyle } from "../../../../src/resources/styles";
|
||||||
import { HomeAssistant, Route } from "../../../../src/types";
|
import { HomeAssistant, Route } from "../../../../src/types";
|
||||||
import { bytesToString } from "../../../../src/util/bytes-to-string";
|
import { bytesToString } from "../../../../src/util/bytes-to-string";
|
||||||
@@ -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
|
||||||
class=${classMap({
|
filled
|
||||||
yellow: this.addon.stage === "experimental",
|
class=${classMap({
|
||||||
red: this.addon.stage === "deprecated",
|
yellow: this.addon.stage === "experimental",
|
||||||
})}
|
red: this.addon.stage === "deprecated",
|
||||||
@click=${this._showMoreInfo}
|
})}
|
||||||
id="stage"
|
@click=${this._showMoreInfo}
|
||||||
>
|
id="stage"
|
||||||
<ha-svg-icon
|
.label=${capitalizeFirstLetter(
|
||||||
slot="icon"
|
this.supervisor.localize(
|
||||||
.path=${STAGE_ICON[this.addon.stage]}
|
`addon.dashboard.capability.stages.${this.addon.stage}`
|
||||||
|
)
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
</ha-svg-icon>
|
<ha-svg-icon
|
||||||
${this.supervisor.localize(
|
slot="icon"
|
||||||
`addon.dashboard.capability.stages.${this.addon.stage}`
|
.path=${STAGE_ICON[this.addon.stage]}
|
||||||
)}
|
>
|
||||||
</ha-chip>`
|
</ha-svg-icon>
|
||||||
|
</ha-assist-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,151 +268,197 @@ 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}
|
||||||
"addon.dashboard.capability.label.docker"
|
id="docker_api"
|
||||||
|
.label=${capitalizeFirstLetter(
|
||||||
|
this.supervisor.localize(
|
||||||
|
"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}
|
||||||
"addon.dashboard.capability.label.host_pid"
|
id="host_pid"
|
||||||
|
.label=${capitalizeFirstLetter(
|
||||||
|
this.supervisor.localize(
|
||||||
|
"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}
|
||||||
"addon.dashboard.capability.label.auth"
|
id="auth_api"
|
||||||
|
.label=${capitalizeFirstLetter(
|
||||||
|
this.supervisor.localize(
|
||||||
|
"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}
|
||||||
"addon.dashboard.capability.label.signed"
|
id="signed"
|
||||||
|
.label=${capitalizeFirstLetter(
|
||||||
|
this.supervisor.localize(
|
||||||
|
"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>
|
||||||
|
|
||||||
<div class="description light-color">
|
<div class="description light-color">
|
||||||
${this.addon.description}.<br />
|
${this.addon.description}.<br />
|
||||||
${this.supervisor.localize(
|
${this.supervisor.localize("addon.dashboard.visit_addon_page", {
|
||||||
"addon.dashboard.visit_addon_page",
|
name: html`<a
|
||||||
"name",
|
href=${this.addon.url!}
|
||||||
html`<a href=${this.addon.url!} target="_blank" rel="noreferrer"
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
>${this.addon.name}</a
|
>${this.addon.name}</a
|
||||||
>`
|
>`,
|
||||||
)}
|
})}
|
||||||
</div>
|
</div>
|
||||||
<div class="addon-container">
|
<div class="addon-container">
|
||||||
<div>
|
<div>
|
||||||
@@ -574,10 +625,10 @@ class HassioAddonInfo extends LitElement {
|
|||||||
<ha-alert alert-type="warning">
|
<ha-alert alert-type="warning">
|
||||||
${this.supervisor.localize(
|
${this.supervisor.localize(
|
||||||
"addon.dashboard.not_available_version",
|
"addon.dashboard.not_available_version",
|
||||||
"core_version_installed",
|
{
|
||||||
this.supervisor.core.version,
|
core_version_installed: this.supervisor.core.version,
|
||||||
"core_version_needed",
|
core_version_needed: addonStoreInfo!.homeassistant,
|
||||||
addonStoreInfo!.homeassistant
|
}
|
||||||
)}
|
)}
|
||||||
</ha-alert>
|
</ha-alert>
|
||||||
`
|
`
|
||||||
@@ -750,12 +801,11 @@ class HassioAddonInfo extends LitElement {
|
|||||||
id === "stage"
|
id === "stage"
|
||||||
? this.supervisor.localize(
|
? this.supervisor.localize(
|
||||||
`addon.dashboard.capability.${id}.description`,
|
`addon.dashboard.capability.${id}.description`,
|
||||||
"icon_stable",
|
{
|
||||||
`<ha-svg-icon path="${STAGE_ICON.stable}"></ha-svg-icon>`,
|
icon_stable: `<ha-svg-icon path="${STAGE_ICON.stable}"></ha-svg-icon>`,
|
||||||
"icon_experimental",
|
icon_experimental: `<ha-svg-icon path="${STAGE_ICON.experimental}"></ha-svg-icon>`,
|
||||||
`<ha-svg-icon path="${STAGE_ICON.experimental}"></ha-svg-icon>`,
|
icon_deprecated: `<ha-svg-icon path="${STAGE_ICON.deprecated}"></ha-svg-icon>`,
|
||||||
"icon_deprecated",
|
}
|
||||||
`<ha-svg-icon path="${STAGE_ICON.deprecated}"></ha-svg-icon>`
|
|
||||||
)
|
)
|
||||||
: this.supervisor.localize(
|
: this.supervisor.localize(
|
||||||
`addon.dashboard.capability.${id}.description`
|
`addon.dashboard.capability.${id}.description`
|
||||||
@@ -817,11 +867,9 @@ class HassioAddonInfo extends LitElement {
|
|||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize("addon.failed_to_save", {
|
||||||
"addon.failed_to_save",
|
error: extractApiErrorMessage(err),
|
||||||
"error",
|
});
|
||||||
extractApiErrorMessage(err)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -839,11 +887,9 @@ class HassioAddonInfo extends LitElement {
|
|||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize("addon.failed_to_save", {
|
||||||
"addon.failed_to_save",
|
error: extractApiErrorMessage(err),
|
||||||
"error",
|
});
|
||||||
extractApiErrorMessage(err)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -861,11 +907,9 @@ class HassioAddonInfo extends LitElement {
|
|||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize("addon.failed_to_save", {
|
||||||
"addon.failed_to_save",
|
error: extractApiErrorMessage(err),
|
||||||
"error",
|
});
|
||||||
extractApiErrorMessage(err)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -883,11 +927,9 @@ class HassioAddonInfo extends LitElement {
|
|||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize("addon.failed_to_save", {
|
||||||
"addon.failed_to_save",
|
error: extractApiErrorMessage(err),
|
||||||
"error",
|
});
|
||||||
extractApiErrorMessage(err)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -905,11 +947,9 @@ class HassioAddonInfo extends LitElement {
|
|||||||
};
|
};
|
||||||
fireEvent(this, "hass-api-called", eventdata);
|
fireEvent(this, "hass-api-called", eventdata);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize("addon.failed_to_save", {
|
||||||
"addon.failed_to_save",
|
error: extractApiErrorMessage(err),
|
||||||
"error",
|
});
|
||||||
extractApiErrorMessage(err)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1185,23 +1225,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 +1312,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%;
|
||||||
}
|
}
|
||||||
|
@@ -18,7 +18,9 @@ class HassioAddonLogDashboard extends LitElement {
|
|||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (!this.addon) {
|
if (!this.addon) {
|
||||||
return html` <ha-circular-progress active></ha-circular-progress> `;
|
return html`
|
||||||
|
<ha-circular-progress indeterminate></ha-circular-progress>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
return html`
|
return html`
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
@@ -72,11 +72,9 @@ class HassioAddonLogs extends LitElement {
|
|||||||
try {
|
try {
|
||||||
this._content = await fetchHassioAddonLogs(this.hass, this.addon.slug);
|
this._content = await fetchHassioAddonLogs(this.hass, this.addon.slug);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
this._error = this.supervisor.localize(
|
this._error = this.supervisor.localize("addon.logs.get_logs", {
|
||||||
"addon.logs.get_logs",
|
error: extractApiErrorMessage(err),
|
||||||
"error",
|
});
|
||||||
extractApiErrorMessage(err)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|