mirror of
https://github.com/home-assistant/frontend.git
synced 2025-08-17 13:19:26 +00:00
Compare commits
1845 Commits
Move-parti
...
20221201.0
Author | SHA1 | Date | |
---|---|---|---|
![]() |
77a53ffc6c | ||
![]() |
b6f1d78b7f | ||
![]() |
1fda303b23 | ||
![]() |
241645fe8d | ||
![]() |
faa57e4c02 | ||
![]() |
915563ce6c | ||
![]() |
44502d2c8d | ||
![]() |
b97a9ef311 | ||
![]() |
1a66b8a374 | ||
![]() |
4190ff5a2b | ||
![]() |
dfc461ce05 | ||
![]() |
dff7f653b1 | ||
![]() |
eccc6a8cdb | ||
![]() |
52235c6187 | ||
![]() |
594b402bd5 | ||
![]() |
684f6db4df | ||
![]() |
883e5e3a6c | ||
![]() |
29452841c2 | ||
![]() |
9b6e33cfec | ||
![]() |
e43f3b193e | ||
![]() |
40d0455936 | ||
![]() |
90a7c2d2ff | ||
![]() |
d4cda0c106 | ||
![]() |
92d022747b | ||
![]() |
ee6f97b802 | ||
![]() |
cb97918005 | ||
![]() |
f1f0baf787 | ||
![]() |
c0240eed67 | ||
![]() |
aeeacc6cad | ||
![]() |
fcfdad3d94 | ||
![]() |
566b93ec1f | ||
![]() |
5c452cb9e0 | ||
![]() |
06c1d9f6ef | ||
![]() |
bfd96944f9 | ||
![]() |
c119163422 | ||
![]() |
4846fa1a74 | ||
![]() |
aec0eb3c78 | ||
![]() |
92e7254c54 | ||
![]() |
bafe581562 | ||
![]() |
e6a153a802 | ||
![]() |
fce87ff0fe | ||
![]() |
e6b3475b5b | ||
![]() |
f969299567 | ||
![]() |
7a87dc4d8a | ||
![]() |
d6fa1427f1 | ||
![]() |
aa1e9cedca | ||
![]() |
147b1f34ac | ||
![]() |
0cfba81eae | ||
![]() |
a9d44fcb61 | ||
![]() |
0aa2c9044a | ||
![]() |
9bae4a646d | ||
![]() |
15a0847db8 | ||
![]() |
8b817b35b0 | ||
![]() |
f95a3c75f6 | ||
![]() |
2223ffd7ee | ||
![]() |
590ad5b8a0 | ||
![]() |
2bb9961fc2 | ||
![]() |
3e2fb09251 | ||
![]() |
fc80daa3e0 | ||
![]() |
2aa7b95a5a | ||
![]() |
c2436fb157 | ||
![]() |
a958c6296b | ||
![]() |
fe4191aea9 | ||
![]() |
49d9cf41fe | ||
![]() |
0bfb2b4a56 | ||
![]() |
1a68a2f4d7 | ||
![]() |
1197e5a35b | ||
![]() |
c6386284d1 | ||
![]() |
185d2f1d52 | ||
![]() |
c5ec1797f6 | ||
![]() |
048b345c75 | ||
![]() |
70868da305 | ||
![]() |
cef3dbfdf0 | ||
![]() |
bda5b97c91 | ||
![]() |
ae15dd678b | ||
![]() |
681c745e84 | ||
![]() |
23b59978ab | ||
![]() |
90b9eaeb19 | ||
![]() |
65426bd2d0 | ||
![]() |
1cb44ce857 | ||
![]() |
1c03dc9b77 | ||
![]() |
238e844068 | ||
![]() |
ec6a4b4e7a | ||
![]() |
ac65882fdd | ||
![]() |
c92e6423e8 | ||
![]() |
db0d24c807 | ||
![]() |
9e56ddcc69 | ||
![]() |
dd4c3c28ee | ||
![]() |
245202c125 | ||
![]() |
8b8a85b4b8 | ||
![]() |
0aae285236 | ||
![]() |
31ac274a51 | ||
![]() |
6f07e7ca59 | ||
![]() |
fa506202ac | ||
![]() |
c810c67a53 | ||
![]() |
663c58512d | ||
![]() |
3cd64675df | ||
![]() |
79c8b7dc27 | ||
![]() |
98a32041d4 | ||
![]() |
ffbcb0a343 | ||
![]() |
ab4dd47e51 | ||
![]() |
c7cb8cf762 | ||
![]() |
a5ab4eaf0e | ||
![]() |
d52dbde909 | ||
![]() |
1cde9e882e | ||
![]() |
8cb0d38d78 | ||
![]() |
9cb168c439 | ||
![]() |
2add29c4eb | ||
![]() |
e2104c1591 | ||
![]() |
17ac81a708 | ||
![]() |
42386c7dee | ||
![]() |
2e988bf5c3 | ||
![]() |
3356d559c9 | ||
![]() |
43755deb39 | ||
![]() |
9778c0731c | ||
![]() |
ebc0edac10 | ||
![]() |
effc9467c2 | ||
![]() |
68e94d7222 | ||
![]() |
c4992c477b | ||
![]() |
449c1f2469 | ||
![]() |
d52e521ef8 | ||
![]() |
03d03f9903 | ||
![]() |
1122698351 | ||
![]() |
9d730919d5 | ||
![]() |
6326bb010f | ||
![]() |
2ab5da6d84 | ||
![]() |
a56b2e3270 | ||
![]() |
523d936010 | ||
![]() |
b3e2beac5a | ||
![]() |
4c8e863c0e | ||
![]() |
69074df1ab | ||
![]() |
16848d03ae | ||
![]() |
dd9683674d | ||
![]() |
822917d060 | ||
![]() |
7cc6809f53 | ||
![]() |
57291183ca | ||
![]() |
504e8dd946 | ||
![]() |
5c4517517d | ||
![]() |
1b917a5b04 | ||
![]() |
527c4f71c2 | ||
![]() |
3ac6e6f307 | ||
![]() |
9e955dbaaa | ||
![]() |
e0a56956e0 | ||
![]() |
66ed1b18be | ||
![]() |
d445bf2505 | ||
![]() |
16bd1f5883 | ||
![]() |
c12e6662dd | ||
![]() |
0b18875d70 | ||
![]() |
57fb8f9f01 | ||
![]() |
f1139e09f9 | ||
![]() |
51febc2218 | ||
![]() |
c8d16af1b5 | ||
![]() |
66a75c4714 | ||
![]() |
cb8e602340 | ||
![]() |
de008f65a3 | ||
![]() |
ab1b778439 | ||
![]() |
62ac9155fc | ||
![]() |
68302d0896 | ||
![]() |
a76f456ebc | ||
![]() |
9d3eaba46b | ||
![]() |
5bb9538861 | ||
![]() |
fe1beb0d59 | ||
![]() |
153161d2cb | ||
![]() |
370864e0ed | ||
![]() |
9b6fca2c0e | ||
![]() |
55467666f7 | ||
![]() |
928f20ada5 | ||
![]() |
b53e86ad03 | ||
![]() |
112ec10b30 | ||
![]() |
1b4989a7dc | ||
![]() |
1f9763d6c8 | ||
![]() |
b495667e8d | ||
![]() |
a46e72ffbd | ||
![]() |
0a2eb05062 | ||
![]() |
c9b5fe9a85 | ||
![]() |
58d5a07a43 | ||
![]() |
c44de09a7c | ||
![]() |
a0b645d1b9 | ||
![]() |
0b6c6b2b98 | ||
![]() |
bad3edc340 | ||
![]() |
d3015c362d | ||
![]() |
fbb8ff4362 | ||
![]() |
6393d59035 | ||
![]() |
62de708b2b | ||
![]() |
6c4c65730c | ||
![]() |
23f8373b16 | ||
![]() |
dec8883f2a | ||
![]() |
a475b06d49 | ||
![]() |
0972cb4583 | ||
![]() |
dad7c43fd2 | ||
![]() |
7e6a9f1653 | ||
![]() |
f627e98902 | ||
![]() |
0d623794ed | ||
![]() |
0a3fa3e218 | ||
![]() |
19887fbd54 | ||
![]() |
fe9967550b | ||
![]() |
9b19b6f203 | ||
![]() |
797718f478 | ||
![]() |
9ea0e3a75f | ||
![]() |
0b76b60f6e | ||
![]() |
d8be662bd6 | ||
![]() |
c478a15846 | ||
![]() |
811208363b | ||
![]() |
969772663b | ||
![]() |
c3b9438b3b | ||
![]() |
9b51df02d6 | ||
![]() |
8a4b0b081a | ||
![]() |
1ecc88291d | ||
![]() |
fb80da013e | ||
![]() |
a4fcb743fa | ||
![]() |
8444fe0a07 | ||
![]() |
1442f6d546 | ||
![]() |
c468fba36f | ||
![]() |
2afbfb01bd | ||
![]() |
907466d060 | ||
![]() |
4deee46864 | ||
![]() |
391cc95883 | ||
![]() |
0c800344d2 | ||
![]() |
08279f35cf | ||
![]() |
05f2ef8a37 | ||
![]() |
3a41b4e65b | ||
![]() |
e08c12c4dd | ||
![]() |
bb0884c4bb | ||
![]() |
45646eaf0b | ||
![]() |
d735b2b722 | ||
![]() |
310b110b8b | ||
![]() |
06557709ae | ||
![]() |
1b5571557c | ||
![]() |
712ecbd13c | ||
![]() |
ea286b6fac | ||
![]() |
a2953138f4 | ||
![]() |
b327d6e0bc | ||
![]() |
88983806ae | ||
![]() |
1ac701d1c8 | ||
![]() |
aaeca323d4 | ||
![]() |
83a4fd6c1b | ||
![]() |
ef9643ddaf | ||
![]() |
af93ec1b92 | ||
![]() |
4dce9404a4 | ||
![]() |
ed54c70e75 | ||
![]() |
114507b5cb | ||
![]() |
8eddaa1914 | ||
![]() |
37394f7bc5 | ||
![]() |
d5cdd53fab | ||
![]() |
0ac2393ecb | ||
![]() |
c38892a162 | ||
![]() |
c77e5dee84 | ||
![]() |
3752336a9a | ||
![]() |
70d4fe1285 | ||
![]() |
d3738adf11 | ||
![]() |
7ededd2766 | ||
![]() |
ed8b07b7e2 | ||
![]() |
c12189b27f | ||
![]() |
9c923e45c5 | ||
![]() |
66bfdb6d12 | ||
![]() |
aa673774a8 | ||
![]() |
8c7974e466 | ||
![]() |
a70e2342a2 | ||
![]() |
b5c9aae1aa | ||
![]() |
93893d0237 | ||
![]() |
ad3dcb355f | ||
![]() |
952b433b2c | ||
![]() |
200fff506c | ||
![]() |
e84b9b7c6f | ||
![]() |
e2a89b1157 | ||
![]() |
cb0310593c | ||
![]() |
c14d9ab957 | ||
![]() |
dd695545d3 | ||
![]() |
176d8567f4 | ||
![]() |
4f4a95c04e | ||
![]() |
6393944a1b | ||
![]() |
f768c5ef7f | ||
![]() |
650d579d05 | ||
![]() |
9811f2681c | ||
![]() |
6a3ac9116e | ||
![]() |
2a6ef9b955 | ||
![]() |
b9395e1c97 | ||
![]() |
cd8c1f42ca | ||
![]() |
0ec887ad50 | ||
![]() |
f8a7737eb9 | ||
![]() |
3e01597a38 | ||
![]() |
6d230ebd65 | ||
![]() |
9035e8e9dc | ||
![]() |
7ff138534f | ||
![]() |
0b76183acd | ||
![]() |
9f658c10c3 | ||
![]() |
72ed6fdd6b | ||
![]() |
3bdc5ad420 | ||
![]() |
8d2f7d99af | ||
![]() |
b88317f1d3 | ||
![]() |
8ccd0426dd | ||
![]() |
c17e8ba65a | ||
![]() |
d9f1540115 | ||
![]() |
1b480248d1 | ||
![]() |
e88bb1114b | ||
![]() |
80e868e281 | ||
![]() |
d8a49c6eec | ||
![]() |
594ee85bbe | ||
![]() |
182b8f809c | ||
![]() |
8e4bebb694 | ||
![]() |
dddb922593 | ||
![]() |
da38cbccf1 | ||
![]() |
71c43058ea | ||
![]() |
f9d119d33d | ||
![]() |
d3b97ae91c | ||
![]() |
5146fa1d9e | ||
![]() |
fc86a66c33 | ||
![]() |
3959a7475c | ||
![]() |
61d09072a7 | ||
![]() |
4a07d3d39b | ||
![]() |
be30cdb51f | ||
![]() |
894258d7b8 | ||
![]() |
296d5f8ffe | ||
![]() |
d1c2020ee4 | ||
![]() |
3c1b2aa4f3 | ||
![]() |
17a11809de | ||
![]() |
3083d5b04c | ||
![]() |
0848c096b9 | ||
![]() |
8d5c36a96a | ||
![]() |
cc76a6c5ed | ||
![]() |
01fd2787be | ||
![]() |
c79955e76a | ||
![]() |
51874329d1 | ||
![]() |
6252955bb5 | ||
![]() |
5422fda990 | ||
![]() |
db8bc9d34a | ||
![]() |
9f19bdde65 | ||
![]() |
7336c1280f | ||
![]() |
8e245c8a83 | ||
![]() |
5a150ac80d | ||
![]() |
eac13980ff | ||
![]() |
977fdd9fbb | ||
![]() |
cedde3d6a2 | ||
![]() |
56c78ae108 | ||
![]() |
82a641a200 | ||
![]() |
04181e9c28 | ||
![]() |
4b8960c236 | ||
![]() |
fc104e7280 | ||
![]() |
8c125f4dee | ||
![]() |
b93f457d53 | ||
![]() |
e8ce6ad919 | ||
![]() |
0ce695577c | ||
![]() |
50b67751d9 | ||
![]() |
05515f21c3 | ||
![]() |
063c377797 | ||
![]() |
aee11da671 | ||
![]() |
5fcb219fcd | ||
![]() |
a97dfbb51f | ||
![]() |
c5f4e8ffdd | ||
![]() |
7ffd30643a | ||
![]() |
dcfcd54f10 | ||
![]() |
3b103619ec | ||
![]() |
614c1574ca | ||
![]() |
e1e3f9d925 | ||
![]() |
0ba4a07b92 | ||
![]() |
5a5f31b32c | ||
![]() |
ff92768973 | ||
![]() |
bb0529ecd2 | ||
![]() |
bc62e9372b | ||
![]() |
087a897cbe | ||
![]() |
589efa8cc5 | ||
![]() |
c93179c307 | ||
![]() |
9e416e829c | ||
![]() |
e13c632afa | ||
![]() |
544c8fe3bb | ||
![]() |
81b21f874b | ||
![]() |
ea319d55ef | ||
![]() |
8c03bbdccc | ||
![]() |
321914d53a | ||
![]() |
fe46f759c9 | ||
![]() |
490d46396e | ||
![]() |
7ec28c4314 | ||
![]() |
e9f4307d15 | ||
![]() |
3c62bc9b18 | ||
![]() |
28bae5071c | ||
![]() |
e9281ad9f1 | ||
![]() |
78187c5b0b | ||
![]() |
f164ad0b89 | ||
![]() |
48b10005e3 | ||
![]() |
b3d64fc52a | ||
![]() |
23e5a47b3b | ||
![]() |
55d84973c6 | ||
![]() |
de90a62de7 | ||
![]() |
3a17f2d73e | ||
![]() |
8f6a09f44c | ||
![]() |
d78191efa6 | ||
![]() |
749d869e03 | ||
![]() |
5d6f446c30 | ||
![]() |
3cf14bb2e1 | ||
![]() |
f7253a73a5 | ||
![]() |
cfabaa8716 | ||
![]() |
032f497687 | ||
![]() |
432483b3d2 | ||
![]() |
e95d5b1afb | ||
![]() |
330f3e5ce4 | ||
![]() |
fee6ae3045 | ||
![]() |
5e431a07ad | ||
![]() |
5d4c090b26 | ||
![]() |
b84240edbc | ||
![]() |
f4dc74b2e8 | ||
![]() |
c95d19299b | ||
![]() |
7696df56ac | ||
![]() |
771733d326 | ||
![]() |
4f3c708109 | ||
![]() |
d2078a7e50 | ||
![]() |
d70cb24722 | ||
![]() |
6902537666 | ||
![]() |
9ea1f61971 | ||
![]() |
782c95cf04 | ||
![]() |
d5d6216cfe | ||
![]() |
1086c85964 | ||
![]() |
47c0901df2 | ||
![]() |
d323ab6726 | ||
![]() |
07b5856190 | ||
![]() |
462dee0351 | ||
![]() |
f181a085de | ||
![]() |
bf5589b88d | ||
![]() |
c5428d8581 | ||
![]() |
fd431f36f7 | ||
![]() |
7acf3a049e | ||
![]() |
cfb0e8b39e | ||
![]() |
a3abbf3812 | ||
![]() |
980156d23a | ||
![]() |
37c2a3636e | ||
![]() |
b682d13486 | ||
![]() |
7f82b90c25 | ||
![]() |
3e9d6ea2c5 | ||
![]() |
57c5c1c191 | ||
![]() |
b553a3fd92 | ||
![]() |
d1964e92ea | ||
![]() |
a889969bb8 | ||
![]() |
f80b2c578b | ||
![]() |
579f73e08f | ||
![]() |
d13c6d3e7b | ||
![]() |
e78c875e8e | ||
![]() |
5e8c54b00f | ||
![]() |
71bc74893f | ||
![]() |
df72e5099e | ||
![]() |
e6862daa38 | ||
![]() |
66db8c999f | ||
![]() |
00bc315fc1 | ||
![]() |
f461825a59 | ||
![]() |
8c98326e31 | ||
![]() |
7bb619b0c3 | ||
![]() |
07bc9081b8 | ||
![]() |
91fa5972d1 | ||
![]() |
abbfde19a2 | ||
![]() |
ccd617d68e | ||
![]() |
8a7f35cee6 | ||
![]() |
e510e5b371 | ||
![]() |
aa6ee0f6d2 | ||
![]() |
f3449c4d9b | ||
![]() |
3c289deb21 | ||
![]() |
847d163cc8 | ||
![]() |
28d11703fc | ||
![]() |
1f003ae3be | ||
![]() |
a57d7813e7 | ||
![]() |
5842b10a10 | ||
![]() |
8ee9655bd5 | ||
![]() |
3ef567dcd5 | ||
![]() |
37f6b4f6be | ||
![]() |
a817faae54 | ||
![]() |
ab745f6e8e | ||
![]() |
02d608b704 | ||
![]() |
310df387e7 | ||
![]() |
fe8e79a67f | ||
![]() |
8ffe676827 | ||
![]() |
f032d0dbcf | ||
![]() |
81cc745c0a | ||
![]() |
43f9c9ebc9 | ||
![]() |
a9d1feb196 | ||
![]() |
8ec2c38f72 | ||
![]() |
72aea57105 | ||
![]() |
031ecf5be8 | ||
![]() |
93e7927686 | ||
![]() |
320d8e6190 | ||
![]() |
efa4f65686 | ||
![]() |
ec257710ff | ||
![]() |
ffad6f340f | ||
![]() |
0b637fc9bd | ||
![]() |
9f9b0b6457 | ||
![]() |
a4227680de | ||
![]() |
5cfd263617 | ||
![]() |
430e671901 | ||
![]() |
8fcd396445 | ||
![]() |
e273b6b659 | ||
![]() |
2751adf440 | ||
![]() |
d661450121 | ||
![]() |
4511ded205 | ||
![]() |
2bf0c5d72d | ||
![]() |
604e5d5e09 | ||
![]() |
5466705d97 | ||
![]() |
774aee406c | ||
![]() |
775837b60f | ||
![]() |
030b2b921a | ||
![]() |
229bc26327 | ||
![]() |
99e85173eb | ||
![]() |
be0c22d7ae | ||
![]() |
fee1092a08 | ||
![]() |
d041bd9fd3 | ||
![]() |
93debac19a | ||
![]() |
3fc94106b8 | ||
![]() |
e976f9c119 | ||
![]() |
be4dcbe405 | ||
![]() |
c116ad67ed | ||
![]() |
1e19799da9 | ||
![]() |
9b2dcbdb59 | ||
![]() |
ae4a37f23a | ||
![]() |
e463a997c1 | ||
![]() |
92c8de307d | ||
![]() |
c751b0b759 | ||
![]() |
cb5621032d | ||
![]() |
e861460318 | ||
![]() |
8fd99fcb15 | ||
![]() |
260855abbb | ||
![]() |
3648c8c07a | ||
![]() |
e74fd5fcdc | ||
![]() |
2e46b04204 | ||
![]() |
989a0b9173 | ||
![]() |
80a2a7b989 | ||
![]() |
2547a975f6 | ||
![]() |
35fa763086 | ||
![]() |
44e38cd24e | ||
![]() |
ad58d16dfa | ||
![]() |
98352ae7b7 | ||
![]() |
b9fbad663d | ||
![]() |
fd166fa89e | ||
![]() |
88decba851 | ||
![]() |
8db1881a93 | ||
![]() |
0038f54cea | ||
![]() |
a3d80f1280 | ||
![]() |
1c05bc6380 | ||
![]() |
5d1536030a | ||
![]() |
a8833a5ec1 | ||
![]() |
6446534e0b | ||
![]() |
d64c81a123 | ||
![]() |
80e7993923 | ||
![]() |
700af72303 | ||
![]() |
255cb23c7d | ||
![]() |
669f7efa97 | ||
![]() |
166d6f1c88 | ||
![]() |
d64ade3848 | ||
![]() |
c2542a3baa | ||
![]() |
6b7c00edbc | ||
![]() |
89c6fa7383 | ||
![]() |
ca91f71d2e | ||
![]() |
25e0c05723 | ||
![]() |
8fd5273fae | ||
![]() |
807bb10199 | ||
![]() |
5ce81232b5 | ||
![]() |
a1bc748bc1 | ||
![]() |
be169f9c83 | ||
![]() |
ed82ae9f68 | ||
![]() |
8bcbeb299b | ||
![]() |
fc1481d365 | ||
![]() |
2475f6bd41 | ||
![]() |
dff3ffe935 | ||
![]() |
1616911ba9 | ||
![]() |
8d18fb79fb | ||
![]() |
f5b44656cf | ||
![]() |
c82782fa1b | ||
![]() |
ab14cf9e9b | ||
![]() |
c0051aeb68 | ||
![]() |
44422086d7 | ||
![]() |
738367a7c7 | ||
![]() |
5fb2e3316a | ||
![]() |
82f48d106f | ||
![]() |
bbc5b02a22 | ||
![]() |
dfface6904 | ||
![]() |
9ed0cb3011 | ||
![]() |
4b54cb4a35 | ||
![]() |
1b5c30712e | ||
![]() |
7d3d800d4c | ||
![]() |
d4262ecb09 | ||
![]() |
ec7dea93a0 | ||
![]() |
aa2641d5c9 | ||
![]() |
5ecde44243 | ||
![]() |
209ba79823 | ||
![]() |
52a1594969 | ||
![]() |
24509425ca | ||
![]() |
7e5cd9a1c8 | ||
![]() |
8b13a9ff2e | ||
![]() |
b33c546610 | ||
![]() |
38fd6108b4 | ||
![]() |
57fdea19fd | ||
![]() |
d2a19e04ef | ||
![]() |
196456d0c4 | ||
![]() |
5c16447eed | ||
![]() |
f3d92ba0e0 | ||
![]() |
088b3587e0 | ||
![]() |
ede9d8a073 | ||
![]() |
8c71885b4c | ||
![]() |
47b820d28f | ||
![]() |
d7b888f761 | ||
![]() |
12e57dfcae | ||
![]() |
9a1fc02755 | ||
![]() |
eb4dbef610 | ||
![]() |
33ce27de02 | ||
![]() |
089f531492 | ||
![]() |
3aa813e391 | ||
![]() |
a989eb1c66 | ||
![]() |
e0448be24d | ||
![]() |
651cafc464 | ||
![]() |
38607a6410 | ||
![]() |
9046c0d0bf | ||
![]() |
589cec10f6 | ||
![]() |
dba9658658 | ||
![]() |
d21bdf2807 | ||
![]() |
3fe5075ad4 | ||
![]() |
f76a3ea2ce | ||
![]() |
e95a5ebbbf | ||
![]() |
ae28eb3813 | ||
![]() |
b0807cb80c | ||
![]() |
95231554d5 | ||
![]() |
f3b543f46c | ||
![]() |
9eb81e2211 | ||
![]() |
1322ff9295 | ||
![]() |
5f169b48d9 | ||
![]() |
75d05cdb0e | ||
![]() |
b444d0030f | ||
![]() |
e241b20378 | ||
![]() |
ca28feca80 | ||
![]() |
f5d9a7d662 | ||
![]() |
3d236a8f49 | ||
![]() |
0ebeec0db6 | ||
![]() |
d23d774ec1 | ||
![]() |
0d5b86e2b6 | ||
![]() |
825558c8db | ||
![]() |
12239d7fe3 | ||
![]() |
6eac6aef18 | ||
![]() |
a79d6b6a4d | ||
![]() |
1d47303127 | ||
![]() |
150bc00c31 | ||
![]() |
df4b83349e | ||
![]() |
d4232a2256 | ||
![]() |
f7e348c19b | ||
![]() |
f44fd35b90 | ||
![]() |
dac1d76bd2 | ||
![]() |
0ab823bcf5 | ||
![]() |
65e952aaeb | ||
![]() |
cfdf043444 | ||
![]() |
ecc1bf5206 | ||
![]() |
57d664d87d | ||
![]() |
cf2cd4043d | ||
![]() |
98761cab3f | ||
![]() |
4a622f9424 | ||
![]() |
61b42249ec | ||
![]() |
c27e3325d9 | ||
![]() |
08efc2fdd1 | ||
![]() |
53519ae8ab | ||
![]() |
9baeabed19 | ||
![]() |
f3229bb8a7 | ||
![]() |
86c971b76a | ||
![]() |
afc69cb270 | ||
![]() |
a379d29a6c | ||
![]() |
0769b14566 | ||
![]() |
1dc68b72da | ||
![]() |
40616b6af2 | ||
![]() |
c08be957ce | ||
![]() |
140e269697 | ||
![]() |
7c18d5aa0e | ||
![]() |
1acdc9cd6c | ||
![]() |
7501849044 | ||
![]() |
26ed13e548 | ||
![]() |
086c33d8b3 | ||
![]() |
c73677f15d | ||
![]() |
f7090583ac | ||
![]() |
68517018cc | ||
![]() |
62a0a64554 | ||
![]() |
adf3fa6a0e | ||
![]() |
b443ec0af5 | ||
![]() |
b9ae0e72b1 | ||
![]() |
63ea8e6568 | ||
![]() |
5be624f45d | ||
![]() |
38f19b6180 | ||
![]() |
c99f00ba50 | ||
![]() |
ce5776f59d | ||
![]() |
12ff70020a | ||
![]() |
5d605447a5 | ||
![]() |
6d88d46ce4 | ||
![]() |
cbe2643146 | ||
![]() |
d332b8ab14 | ||
![]() |
adfef05110 | ||
![]() |
ca6a7bfbe2 | ||
![]() |
a22f96a481 | ||
![]() |
688109524d | ||
![]() |
62dd7111ce | ||
![]() |
1267575f62 | ||
![]() |
b7da4dc68f | ||
![]() |
826474518f | ||
![]() |
a4b92fef3a | ||
![]() |
d41159591c | ||
![]() |
cb256bc386 | ||
![]() |
bd50d6a6a3 | ||
![]() |
05418fc83b | ||
![]() |
8b675cdbba | ||
![]() |
36b4909950 | ||
![]() |
157b3ba5f2 | ||
![]() |
72443b4f24 | ||
![]() |
1c7d3fe610 | ||
![]() |
6ac4560b36 | ||
![]() |
9309a4c7bc | ||
![]() |
b582a4d014 | ||
![]() |
e4d233afa8 | ||
![]() |
b131b255ec | ||
![]() |
20bdb9ff35 | ||
![]() |
666ef7a978 | ||
![]() |
24a97347df | ||
![]() |
0825d5c64e | ||
![]() |
535e752ec7 | ||
![]() |
b611a58fce | ||
![]() |
24e54554ad | ||
![]() |
d23fca4dd1 | ||
![]() |
729e2f5248 | ||
![]() |
437723c6a6 | ||
![]() |
a30c8205b1 | ||
![]() |
c50cf78bb4 | ||
![]() |
be52ba0ea9 | ||
![]() |
55e9ebc4d2 | ||
![]() |
29c3fb0f92 | ||
![]() |
7c3cd9d88d | ||
![]() |
4881d699e3 | ||
![]() |
414db83359 | ||
![]() |
cd4f6e19f4 | ||
![]() |
da709cbbd1 | ||
![]() |
ee9ca16eb5 | ||
![]() |
399efca411 | ||
![]() |
f8bccf9e79 | ||
![]() |
87aab72b63 | ||
![]() |
24688ba18e | ||
![]() |
e8086b6a6f | ||
![]() |
4358437278 | ||
![]() |
e0a9c57a54 | ||
![]() |
e63953ecbc | ||
![]() |
72af200190 | ||
![]() |
2094ae534b | ||
![]() |
f6d6fd179f | ||
![]() |
153ebb2a20 | ||
![]() |
5d58e52eea | ||
![]() |
5038f9c3c6 | ||
![]() |
b285fda61b | ||
![]() |
6cd38472cd | ||
![]() |
8fd5f53f96 | ||
![]() |
b70eee77ef | ||
![]() |
4148b8c7aa | ||
![]() |
e22dd0c49d | ||
![]() |
30a254f98f | ||
![]() |
8fcb3a017b | ||
![]() |
5e29c7efa9 | ||
![]() |
b6cc3e3ef0 | ||
![]() |
184bdc0c85 | ||
![]() |
f7fb731dc8 | ||
![]() |
77977f64a3 | ||
![]() |
e8da573ba2 | ||
![]() |
07332bf155 | ||
![]() |
f3c7583bf7 | ||
![]() |
1cc02415d3 | ||
![]() |
6ca3f06ea0 | ||
![]() |
198e2b7bdf | ||
![]() |
5a68e2c977 | ||
![]() |
d9d29db560 | ||
![]() |
124c6dc2b8 | ||
![]() |
0f3886e053 | ||
![]() |
68bb3558b4 | ||
![]() |
b8bd15aa33 | ||
![]() |
ed39aa6a7c | ||
![]() |
405cae9b5f | ||
![]() |
3ca2cbb3f9 | ||
![]() |
c295ae56ab | ||
![]() |
830364721b | ||
![]() |
19089213e3 | ||
![]() |
b633067e5c | ||
![]() |
1b8874cbd4 | ||
![]() |
a5f8ce85ba | ||
![]() |
56eacf5733 | ||
![]() |
9324061d05 | ||
![]() |
eafcbdc65b | ||
![]() |
0175522c17 | ||
![]() |
cff3f51d34 | ||
![]() |
0f580a91c9 | ||
![]() |
389f50b29a | ||
![]() |
b689bb8fcf | ||
![]() |
36f067ede4 | ||
![]() |
c2178622dd | ||
![]() |
014448e7ea | ||
![]() |
08eff0509a | ||
![]() |
62d0882e82 | ||
![]() |
86a574dbbd | ||
![]() |
71ac4620c5 | ||
![]() |
f611049517 | ||
![]() |
45fa8c272f | ||
![]() |
28a1c97571 | ||
![]() |
d9a5ae0cf1 | ||
![]() |
c03849d30b | ||
![]() |
535fe2686b | ||
![]() |
709bc87a36 | ||
![]() |
2812b467ec | ||
![]() |
7d118a5715 | ||
![]() |
8bd7370a02 | ||
![]() |
9fa8a96d09 | ||
![]() |
508d1fffef | ||
![]() |
3633daa814 | ||
![]() |
05346ae9fc | ||
![]() |
ea667cf0b9 | ||
![]() |
048ac3965e | ||
![]() |
276b6f4d1f | ||
![]() |
e765d7749c | ||
![]() |
9a3b4d6df2 | ||
![]() |
529e27992e | ||
![]() |
6c5cf2a0ec | ||
![]() |
a4cb270f09 | ||
![]() |
5160a1f55c | ||
![]() |
6a3a0db338 | ||
![]() |
765d4eb3b4 | ||
![]() |
cc09e24d66 | ||
![]() |
e7848262ea | ||
![]() |
0926202eca | ||
![]() |
e83af02410 | ||
![]() |
74d6a52fa9 | ||
![]() |
5baa975632 | ||
![]() |
4ad49ef07f | ||
![]() |
bc47ecaa57 | ||
![]() |
2bd617ce6e | ||
![]() |
dbaf955525 | ||
![]() |
578ff5b53f | ||
![]() |
e386942ea7 | ||
![]() |
2fdd50f45f | ||
![]() |
4b36770adf | ||
![]() |
54377225ec | ||
![]() |
f020add6be | ||
![]() |
b1a3996cf1 | ||
![]() |
a47a0ed716 | ||
![]() |
91cd584b4b | ||
![]() |
75562efb79 | ||
![]() |
f464bcfc14 | ||
![]() |
f8af66d310 | ||
![]() |
4922e575f8 | ||
![]() |
ac08daa64e | ||
![]() |
97f082a384 | ||
![]() |
ced37aab4c | ||
![]() |
1938fb89e6 | ||
![]() |
6842c479d6 | ||
![]() |
881f6b0531 | ||
![]() |
a564ceb9e3 | ||
![]() |
077fa3f6b2 | ||
![]() |
ceda911670 | ||
![]() |
afd41e79f0 | ||
![]() |
10f63180eb | ||
![]() |
e54802bd87 | ||
![]() |
c1d6b51065 | ||
![]() |
ab65ce819f | ||
![]() |
1e011bfe34 | ||
![]() |
5951f5c5c4 | ||
![]() |
0183e32267 | ||
![]() |
588fd87654 | ||
![]() |
e2944b098d | ||
![]() |
cbb962f084 | ||
![]() |
93f4ae1bea | ||
![]() |
d810cae194 | ||
![]() |
6797e17fc8 | ||
![]() |
6e58cd5d12 | ||
![]() |
a72fd19b73 | ||
![]() |
41c61a2895 | ||
![]() |
f35af9ed98 | ||
![]() |
abf7cb7a74 | ||
![]() |
6ec2e32241 | ||
![]() |
b7cdd9a22f | ||
![]() |
6278eefc5d | ||
![]() |
73cf0b54c9 | ||
![]() |
00dcecabb7 | ||
![]() |
c9df93bc54 | ||
![]() |
3550a8c263 | ||
![]() |
c0d30c56d6 | ||
![]() |
10813d06b6 | ||
![]() |
d0ead1fdb8 | ||
![]() |
b0e6c41238 | ||
![]() |
2c1550b10f | ||
![]() |
ffc4ca5b56 | ||
![]() |
85ad6619b7 | ||
![]() |
7358faf88e | ||
![]() |
19d014307a | ||
![]() |
5217f5c50c | ||
![]() |
c4624faa71 | ||
![]() |
b35ba4d673 | ||
![]() |
f8303bff76 | ||
![]() |
e61aa266a6 | ||
![]() |
d7971c69ad | ||
![]() |
d65e45ecfd | ||
![]() |
966a624ef6 | ||
![]() |
7cc576a616 | ||
![]() |
2dec8e70ec | ||
![]() |
97663aef42 | ||
![]() |
3f1a2526b3 | ||
![]() |
e7517a8b61 | ||
![]() |
e3d394eb32 | ||
![]() |
536ea822b3 | ||
![]() |
8e4e22b6f8 | ||
![]() |
2eaa246a03 | ||
![]() |
e841bf89be | ||
![]() |
36e1203fb1 | ||
![]() |
3acab5a39c | ||
![]() |
49cfde1fe7 | ||
![]() |
49c018c000 | ||
![]() |
b71b230bfd | ||
![]() |
e1fd7244a5 | ||
![]() |
067c2fdfa8 | ||
![]() |
a02b817d7f | ||
![]() |
7db6e0b779 | ||
![]() |
1d5cc91a2d | ||
![]() |
0623e7dce4 | ||
![]() |
da106d278c | ||
![]() |
51c5ab33f0 | ||
![]() |
8ac4a6d900 | ||
![]() |
fae1bcf0e0 | ||
![]() |
9a9eec40b2 | ||
![]() |
6ab19d66d5 | ||
![]() |
a0a7ce014f | ||
![]() |
bfeb90780f | ||
![]() |
1f105b6c15 | ||
![]() |
5b7b0ea326 | ||
![]() |
32a991989f | ||
![]() |
788f76ab9c | ||
![]() |
f6411dce66 | ||
![]() |
6f19ea1d84 | ||
![]() |
448609533f | ||
![]() |
6c48ace41e | ||
![]() |
c41e100c1c | ||
![]() |
8216b522c2 | ||
![]() |
82035d587a | ||
![]() |
2796c3570a | ||
![]() |
f4f51e1de5 | ||
![]() |
af6b0d3266 | ||
![]() |
7d1c77a38f | ||
![]() |
f807618f75 | ||
![]() |
4cfb6713cb | ||
![]() |
d32f84f28d | ||
![]() |
5fb1504211 | ||
![]() |
c37e1f0c9d | ||
![]() |
90c234ffad | ||
![]() |
dd3a3ec586 | ||
![]() |
6f67da09c0 | ||
![]() |
ba27c184f6 | ||
![]() |
b37f97128a | ||
![]() |
ee0de942f7 | ||
![]() |
ae2d48f2f4 | ||
![]() |
1bd760b455 | ||
![]() |
3d66a68791 | ||
![]() |
01a53439c4 | ||
![]() |
09ee8dbeb6 | ||
![]() |
f36c91550d | ||
![]() |
6be6c711d0 | ||
![]() |
72a36fb1cd | ||
![]() |
4c982b3323 | ||
![]() |
c9c3be71cc | ||
![]() |
f1b965dcc5 | ||
![]() |
a08a23a93d | ||
![]() |
2040a49458 | ||
![]() |
df94f4f907 | ||
![]() |
96d375cb84 | ||
![]() |
7a9c2f56c5 | ||
![]() |
5ec7193e5c | ||
![]() |
d89e4337f2 | ||
![]() |
2e192d5021 | ||
![]() |
7db28c0156 | ||
![]() |
f09c842981 | ||
![]() |
b295bbd706 | ||
![]() |
8d3132fefc | ||
![]() |
00c5d3dbbb | ||
![]() |
ca37aff47d | ||
![]() |
9ed069ef6a | ||
![]() |
6faa3eb848 | ||
![]() |
1b158d8310 | ||
![]() |
6c73ae5bf7 | ||
![]() |
9d2fcec458 | ||
![]() |
60cd6c65f0 | ||
![]() |
ce77ddf365 | ||
![]() |
cf05fbaa9d | ||
![]() |
552c474feb | ||
![]() |
a39af9c307 | ||
![]() |
a4f8e886bc | ||
![]() |
cc0c96b8b4 | ||
![]() |
445f0e23fe | ||
![]() |
6f240297d1 | ||
![]() |
6da4981b70 | ||
![]() |
cfadf4d700 | ||
![]() |
7e60de0531 | ||
![]() |
aaef6d7b91 | ||
![]() |
02af4c2156 | ||
![]() |
58c5ce2638 | ||
![]() |
a9d01c7b55 | ||
![]() |
c5de8a4361 | ||
![]() |
b53645ce92 | ||
![]() |
de34a5a597 | ||
![]() |
bd8e15bdd1 | ||
![]() |
45c7e0eeeb | ||
![]() |
a35a380ec7 | ||
![]() |
02e67d1146 | ||
![]() |
a5411f7ac4 | ||
![]() |
e8da203fe1 | ||
![]() |
10aa0a8829 | ||
![]() |
85a37e2d2f | ||
![]() |
ba8621fa2c | ||
![]() |
43e80f1a2e | ||
![]() |
3a305a44b6 | ||
![]() |
e99143139e | ||
![]() |
f0c7232704 | ||
![]() |
b2186592df | ||
![]() |
e51e3e79d5 | ||
![]() |
3b6b4d7664 | ||
![]() |
239e71b414 | ||
![]() |
080cad0ccd | ||
![]() |
dd49fd2788 | ||
![]() |
a571fb5528 | ||
![]() |
1369c1ae8c | ||
![]() |
f5864181af | ||
![]() |
a4a0d7cf19 | ||
![]() |
092dfd1e87 | ||
![]() |
a29ac33810 | ||
![]() |
1421df2a5a | ||
![]() |
591b8cc503 | ||
![]() |
011467ece0 | ||
![]() |
f52e8c3392 | ||
![]() |
c8b87b65bd | ||
![]() |
98cc82db44 | ||
![]() |
f510e2a8e0 | ||
![]() |
3438912ba5 | ||
![]() |
671c8e387f | ||
![]() |
0108ec65cf | ||
![]() |
39f7034578 | ||
![]() |
bf8affaf2b | ||
![]() |
e16a61eb53 | ||
![]() |
cadbe45bab | ||
![]() |
51f971337d | ||
![]() |
1f3c23de29 | ||
![]() |
bdfb17d957 | ||
![]() |
8c97aee1fe | ||
![]() |
38b4090daa | ||
![]() |
b8c55f2f65 | ||
![]() |
7ca379e0a1 | ||
![]() |
1617a9dfed | ||
![]() |
2c9411c6c3 | ||
![]() |
67626d4a06 | ||
![]() |
8135611688 | ||
![]() |
3ccbf6983e | ||
![]() |
e4f91195d8 | ||
![]() |
2751f8f33b | ||
![]() |
57f2df3b3e | ||
![]() |
6822f0d067 | ||
![]() |
cfba957313 | ||
![]() |
3149ffbf19 | ||
![]() |
4cd8b76d7e | ||
![]() |
4b644d8bc5 | ||
![]() |
307cd5ad8c | ||
![]() |
ebc807a6a4 | ||
![]() |
66adecdfc9 | ||
![]() |
2cc6432a0f | ||
![]() |
a2c0c0474a | ||
![]() |
27884b9a54 | ||
![]() |
293df61872 | ||
![]() |
f82dada3e5 | ||
![]() |
e5824c4794 | ||
![]() |
186550229c | ||
![]() |
7877dd8e6b | ||
![]() |
b03abc249b | ||
![]() |
fda03918b9 | ||
![]() |
6747375a1b | ||
![]() |
53b6e31881 | ||
![]() |
fa004de2d1 | ||
![]() |
3605f7b70f | ||
![]() |
5348c54c91 | ||
![]() |
684e4421bc | ||
![]() |
28f5611df5 | ||
![]() |
8da73d49d7 | ||
![]() |
049ddd5f84 | ||
![]() |
8ae2d4e93a | ||
![]() |
824bb9ba35 | ||
![]() |
d550b1a18e | ||
![]() |
dea6c0e761 | ||
![]() |
9caee357c0 | ||
![]() |
35d892c418 | ||
![]() |
9572a2a46b | ||
![]() |
8996361b26 | ||
![]() |
02ee731602 | ||
![]() |
bb1e6bf35b | ||
![]() |
c1b65285c1 | ||
![]() |
8b8d6e5fa3 | ||
![]() |
c34fe184e8 | ||
![]() |
7363838f86 | ||
![]() |
3081425ccd | ||
![]() |
95d494a54c | ||
![]() |
145e5d7bc6 | ||
![]() |
876fd9e85a | ||
![]() |
e8c30cabca | ||
![]() |
490f84a7b1 | ||
![]() |
ca28178b86 | ||
![]() |
2fceb0aeee | ||
![]() |
86f39d1d43 | ||
![]() |
1faf60444d | ||
![]() |
e927091d21 | ||
![]() |
cff2f856b3 | ||
![]() |
a743e3bbba | ||
![]() |
f8a52d250e | ||
![]() |
b70a523bdf | ||
![]() |
8f2ed747e6 | ||
![]() |
5deccefb15 | ||
![]() |
3f04abfa9d | ||
![]() |
8e55c83996 | ||
![]() |
dee59486ba | ||
![]() |
77ef509aea | ||
![]() |
bfa7bccfa6 | ||
![]() |
a8c365edc8 | ||
![]() |
94953ddf6c | ||
![]() |
6b67546daf | ||
![]() |
3e188d1f87 | ||
![]() |
f69eb15a90 | ||
![]() |
dfe348187f | ||
![]() |
9706c56c5c | ||
![]() |
3677c5be2c | ||
![]() |
bd339fa963 | ||
![]() |
28f1b6bdf4 | ||
![]() |
c5aac3b81d | ||
![]() |
70836597e9 | ||
![]() |
958a1de2fd | ||
![]() |
36d30266e3 | ||
![]() |
558ab9761d | ||
![]() |
269ef370e4 | ||
![]() |
ba2958ecd2 | ||
![]() |
3b8b6eb315 | ||
![]() |
4f13db3178 | ||
![]() |
ee7aa54ab4 | ||
![]() |
c305dd4cd5 | ||
![]() |
6865791596 | ||
![]() |
2099259393 | ||
![]() |
27ca45dc70 | ||
![]() |
d290c11219 | ||
![]() |
cabe10ffdb | ||
![]() |
aa562c21a8 | ||
![]() |
22175a7271 | ||
![]() |
1e0647c0d1 | ||
![]() |
58d94da8b3 | ||
![]() |
d97763a3e8 | ||
![]() |
aa129aa123 | ||
![]() |
f648317206 | ||
![]() |
0685fdf7c6 | ||
![]() |
6fd4cda534 | ||
![]() |
511368da13 | ||
![]() |
76e1721c58 | ||
![]() |
bad5a389b5 | ||
![]() |
85d1f49763 | ||
![]() |
7723d47ac1 | ||
![]() |
30b130ca74 | ||
![]() |
a124ec0717 | ||
![]() |
323d98ecf7 | ||
![]() |
125a601ae3 | ||
![]() |
3c549c6b31 | ||
![]() |
9c1494c74d | ||
![]() |
e751abd775 | ||
![]() |
714f2447b7 | ||
![]() |
d900e40d04 | ||
![]() |
8b82383790 | ||
![]() |
5a2cc2646c | ||
![]() |
16a0902989 | ||
![]() |
8f67aa38af | ||
![]() |
34184cf2ab | ||
![]() |
611cd2818e | ||
![]() |
0a4e8fd5d0 | ||
![]() |
11f0361f48 | ||
![]() |
cfa048ea4e | ||
![]() |
bbca7b762b | ||
![]() |
1dba849567 | ||
![]() |
aff1ec10bf | ||
![]() |
351ec08a71 | ||
![]() |
d02cd122a9 | ||
![]() |
a1a6a2cd30 | ||
![]() |
4e82c23b29 | ||
![]() |
59595aabde | ||
![]() |
358f91c2a9 | ||
![]() |
e0e01e68b4 | ||
![]() |
61dc4eaaea | ||
![]() |
65c4d02452 | ||
![]() |
f78ce2c844 | ||
![]() |
4d1ab83b30 | ||
![]() |
fb4b40b828 | ||
![]() |
db0c4ef941 | ||
![]() |
c5b60b826b | ||
![]() |
718f0330a7 | ||
![]() |
89e31486c5 | ||
![]() |
717eec1860 | ||
![]() |
b6e51352e3 | ||
![]() |
2ade728bc3 | ||
![]() |
8e962fdecb | ||
![]() |
62f227da83 | ||
![]() |
1f65193a97 | ||
![]() |
9557b604da | ||
![]() |
b45c355c9f | ||
![]() |
0b47d2c687 | ||
![]() |
8baa0b2a9b | ||
![]() |
c68a1d21ff | ||
![]() |
419d659311 | ||
![]() |
ba8b20d877 | ||
![]() |
8de542388f | ||
![]() |
e6c580aadc | ||
![]() |
11696c566a | ||
![]() |
edc15940a2 | ||
![]() |
bf35ee549d | ||
![]() |
4c3baa678c | ||
![]() |
0bb2767696 | ||
![]() |
80a4852325 | ||
![]() |
24484d0e74 | ||
![]() |
9c3e0fc997 | ||
![]() |
9e4bee123f | ||
![]() |
c2c09b1284 | ||
![]() |
bad776b979 | ||
![]() |
396791b805 | ||
![]() |
2b1457e1cd | ||
![]() |
b5861869e3 | ||
![]() |
9444228907 | ||
![]() |
86afd883a5 | ||
![]() |
062f21aa91 | ||
![]() |
ba235ac797 | ||
![]() |
505c22248b | ||
![]() |
624cb48f78 | ||
![]() |
7ab54ee5ce | ||
![]() |
f5af63a50e | ||
![]() |
ff80ab34ee | ||
![]() |
cfc1999a28 | ||
![]() |
7ca28469b7 | ||
![]() |
ac670614b4 | ||
![]() |
e263b57296 | ||
![]() |
c7050e4676 | ||
![]() |
00cbd1d9e6 | ||
![]() |
2a12172eeb | ||
![]() |
85d3011625 | ||
![]() |
ca22ec6340 | ||
![]() |
61f6e8855b | ||
![]() |
a44b8981e1 | ||
![]() |
b080bca9ce | ||
![]() |
d30e8ee9d8 | ||
![]() |
637e4203e5 | ||
![]() |
2648a53bbc | ||
![]() |
b3fa0cccb4 | ||
![]() |
dd963be723 | ||
![]() |
224df896a1 | ||
![]() |
a58b4fb262 | ||
![]() |
27ca61ec85 | ||
![]() |
859f49f3eb | ||
![]() |
40d878689f | ||
![]() |
420e8fe1ff | ||
![]() |
df96199433 | ||
![]() |
f493280f0a | ||
![]() |
cbd030a379 | ||
![]() |
95b80accc9 | ||
![]() |
c522670815 | ||
![]() |
7b6d3c0e36 | ||
![]() |
504b043159 | ||
![]() |
dffc66ccc3 | ||
![]() |
c7e9ee785d | ||
![]() |
079cc39a6e | ||
![]() |
d6a1d5af79 | ||
![]() |
c0dce08e19 | ||
![]() |
a7a347ed05 | ||
![]() |
2d9b50defc | ||
![]() |
840858b18c | ||
![]() |
afd2e71f6c | ||
![]() |
88af0aa788 | ||
![]() |
49124f6f09 | ||
![]() |
73f5580555 | ||
![]() |
bdde5268c6 | ||
![]() |
15e972c158 | ||
![]() |
0fc4c24f5a | ||
![]() |
9eba50df0c | ||
![]() |
0e0e07437f | ||
![]() |
6ac51ede52 | ||
![]() |
ccf1fb573a | ||
![]() |
fa537968c4 | ||
![]() |
6bf2111a3c | ||
![]() |
f5f8be8276 | ||
![]() |
ddf1cc0733 | ||
![]() |
9c1d1cb6f6 | ||
![]() |
470225abde | ||
![]() |
ee230b86c1 | ||
![]() |
f927fc64a9 | ||
![]() |
03677c33f7 | ||
![]() |
bc36a206da | ||
![]() |
af06ab1e2d | ||
![]() |
3e2135a485 | ||
![]() |
2e7f8fb46f | ||
![]() |
102568c4bd | ||
![]() |
4fcdae842e | ||
![]() |
ea19740f5a | ||
![]() |
3e0942b631 | ||
![]() |
0261cea796 | ||
![]() |
5247b2813f | ||
![]() |
8a5090684e | ||
![]() |
1784ba5e68 | ||
![]() |
4fbe9a7b10 | ||
![]() |
1ca9c7838a | ||
![]() |
4fc2c3ef05 | ||
![]() |
73ff8e28a8 | ||
![]() |
dde1c5e03c | ||
![]() |
01eed22592 | ||
![]() |
94ebb63589 | ||
![]() |
29119db5ce | ||
![]() |
9908162ac2 | ||
![]() |
1e929ae78a | ||
![]() |
ab5df0fe6e | ||
![]() |
d5010dda9e | ||
![]() |
4ac097f32b | ||
![]() |
5d3d15072f | ||
![]() |
5c53bc4225 | ||
![]() |
d5a307f8f4 | ||
![]() |
a27dd1e7f1 | ||
![]() |
c86ed1fb3e | ||
![]() |
7fa7a48072 | ||
![]() |
4e0fc8ee08 | ||
![]() |
5f6490e54e | ||
![]() |
db78b046a2 | ||
![]() |
c37fe1e7ff | ||
![]() |
f1ec479d41 | ||
![]() |
e01cb3ca82 | ||
![]() |
b8d3c68a7a | ||
![]() |
641003bb2a | ||
![]() |
3358fc2b18 | ||
![]() |
f9ccfa00a2 | ||
![]() |
070e11a2db | ||
![]() |
dcf50e055b | ||
![]() |
fc1c6cea24 | ||
![]() |
1fa04baa16 | ||
![]() |
c6a103bd30 | ||
![]() |
84ffa2369a | ||
![]() |
9d1618024e | ||
![]() |
307aa161a6 | ||
![]() |
affa6a92e7 | ||
![]() |
1e5ec241d5 | ||
![]() |
27a98a32fc | ||
![]() |
2c8ac58f97 | ||
![]() |
6b995969b1 | ||
![]() |
72c107484a | ||
![]() |
d1085b6657 | ||
![]() |
cc27ddb362 | ||
![]() |
c4dc6bfb0d | ||
![]() |
4fbcc30a37 | ||
![]() |
4916527e5f | ||
![]() |
fad8a27232 | ||
![]() |
a993d3a753 | ||
![]() |
5dfe17a43a | ||
![]() |
9b6c935ffb | ||
![]() |
f4e28da0a3 | ||
![]() |
294a69d7e4 | ||
![]() |
f89b8cffcf | ||
![]() |
99fd3a1b6f | ||
![]() |
246e426182 | ||
![]() |
9f1e9b43fe | ||
![]() |
8301ae262c | ||
![]() |
d968fe41ee | ||
![]() |
db830e9014 | ||
![]() |
fc6b594a27 | ||
![]() |
86dbf99ebe | ||
![]() |
68e7ce1883 | ||
![]() |
e9003ac35e | ||
![]() |
1dd5214b42 | ||
![]() |
96738350bb | ||
![]() |
5bdecf57cf | ||
![]() |
ec12282f8c | ||
![]() |
552dbca201 | ||
![]() |
0bbc0ebb3c | ||
![]() |
ac7acc5802 | ||
![]() |
64e1d160d1 | ||
![]() |
8e51878b6d | ||
![]() |
7c94ced303 | ||
![]() |
a040e1d5e0 | ||
![]() |
87c7407857 | ||
![]() |
d0d0c44ec7 | ||
![]() |
4cdff3faea | ||
![]() |
0dac10aa23 | ||
![]() |
4b8b14a69d | ||
![]() |
9d28df31bd | ||
![]() |
8258641443 | ||
![]() |
dfcb0f6ba0 | ||
![]() |
2e10eb04b6 | ||
![]() |
b4b52d3872 | ||
![]() |
3873203721 | ||
![]() |
ccb91e0b49 | ||
![]() |
bd20c15a55 | ||
![]() |
0936fd9ae4 | ||
![]() |
adefc7a4e2 | ||
![]() |
8f8017ecff | ||
![]() |
604b79696e | ||
![]() |
8c445f6409 | ||
![]() |
797c871137 | ||
![]() |
24829bd903 | ||
![]() |
add92a559d | ||
![]() |
7f086c0900 | ||
![]() |
17018c0f26 | ||
![]() |
cd6a478130 | ||
![]() |
4f6d7ca5c9 | ||
![]() |
c2994343b4 | ||
![]() |
e5f77c35d4 | ||
![]() |
a9e5a5dd44 | ||
![]() |
1159798b8d | ||
![]() |
437de42c55 | ||
![]() |
89e0bb3f16 | ||
![]() |
28c9631b6c | ||
![]() |
8882624618 | ||
![]() |
a769f84755 | ||
![]() |
7abf9c2473 | ||
![]() |
298296a81f | ||
![]() |
6907fa5c8e | ||
![]() |
546461b70f | ||
![]() |
4031009c26 | ||
![]() |
91e4557625 | ||
![]() |
f0c4b92dbb | ||
![]() |
ffac3d055e | ||
![]() |
04ae8c9d14 | ||
![]() |
0158610d42 | ||
![]() |
5ab6121581 | ||
![]() |
3d9c31aef9 | ||
![]() |
acfeea5c92 | ||
![]() |
75e8e17073 | ||
![]() |
976fd4b32d | ||
![]() |
49beafbe5f | ||
![]() |
151f8d5524 | ||
![]() |
48355aa98e | ||
![]() |
fc31929f41 | ||
![]() |
b7c149fcc1 | ||
![]() |
02d058561b | ||
![]() |
4e57fb1ec1 | ||
![]() |
30f79c5a46 | ||
![]() |
30f7252d84 | ||
![]() |
8af795a7ce | ||
![]() |
8576eeae41 | ||
![]() |
cd740ed135 | ||
![]() |
892f774792 | ||
![]() |
aa504fe1f8 | ||
![]() |
be491451d5 | ||
![]() |
bad184210d | ||
![]() |
a43b3b64b3 | ||
![]() |
aa831a9adf | ||
![]() |
43d4f55392 | ||
![]() |
130c66fb24 | ||
![]() |
684c232c8c | ||
![]() |
09f8f816d1 | ||
![]() |
1719d062b3 | ||
![]() |
87290c4330 | ||
![]() |
fec0dc0032 | ||
![]() |
70ca27c8c9 | ||
![]() |
9ae1f01ad6 | ||
![]() |
0113cc3cf6 | ||
![]() |
2a98ace0b3 | ||
![]() |
5f69a4c165 | ||
![]() |
8db22d4f88 | ||
![]() |
3204dbfc4d | ||
![]() |
430b47fc4a | ||
![]() |
5d8b3227f3 | ||
![]() |
b341ee9d38 | ||
![]() |
e6dbbc31a8 | ||
![]() |
0010bf5a8f | ||
![]() |
6e2e80a297 | ||
![]() |
aa9ff01030 | ||
![]() |
7f8ecf57d7 | ||
![]() |
6be6755f6f | ||
![]() |
64459a06c6 | ||
![]() |
df35496c6e | ||
![]() |
aa988c758d | ||
![]() |
1dd1095d19 | ||
![]() |
7e68393c84 | ||
![]() |
540c06c9f7 | ||
![]() |
f633cc2b0d | ||
![]() |
1baaf76471 | ||
![]() |
8263e299a8 | ||
![]() |
ebd6a26554 | ||
![]() |
5335772a7a | ||
![]() |
f5b5414461 | ||
![]() |
1e6f402d0f | ||
![]() |
ed9d886009 | ||
![]() |
940f5c0002 | ||
![]() |
15d1b8b2ac | ||
![]() |
73855e6f99 | ||
![]() |
d230541256 | ||
![]() |
b1f369a355 | ||
![]() |
e6d1e86c64 | ||
![]() |
eb1f94c370 | ||
![]() |
27750b8b5d | ||
![]() |
564a725284 | ||
![]() |
a5ee610af5 | ||
![]() |
eaf97ee7f5 | ||
![]() |
a14d75deec | ||
![]() |
72b5721c88 | ||
![]() |
94b4b818aa | ||
![]() |
98699b640a | ||
![]() |
decc0d3e0d | ||
![]() |
2281f5bafa | ||
![]() |
6cac7eeff0 | ||
![]() |
794bc161c8 | ||
![]() |
28cd9b6408 | ||
![]() |
9b4c6eea63 | ||
![]() |
afe044d152 | ||
![]() |
dc2038916b | ||
![]() |
cf8e2a6d02 | ||
![]() |
3269b2878b | ||
![]() |
29e1b7b452 | ||
![]() |
3d6d07e5bd | ||
![]() |
7bac41fe41 | ||
![]() |
6e4b027575 | ||
![]() |
728c391b5d | ||
![]() |
8999ca2ea0 | ||
![]() |
4fc0617289 | ||
![]() |
494cc3a569 | ||
![]() |
cc177ef911 | ||
![]() |
41ec65ef3d | ||
![]() |
79e1e195a0 | ||
![]() |
dfbf7fb436 | ||
![]() |
f37a5fa021 | ||
![]() |
5e2fcf928c | ||
![]() |
bc6ef7780c | ||
![]() |
b29563a254 | ||
![]() |
fe8a1152c4 | ||
![]() |
26689a0a85 | ||
![]() |
4f6a241817 | ||
![]() |
eae7e82127 | ||
![]() |
9500ac498c | ||
![]() |
5c5459bcaf | ||
![]() |
246724c59e | ||
![]() |
8f5c9295d3 | ||
![]() |
0abafff4c9 | ||
![]() |
f88ce269a7 | ||
![]() |
0dc56d7983 | ||
![]() |
cbd0ef6b65 | ||
![]() |
f923228078 | ||
![]() |
b55c7edd70 | ||
![]() |
bfb90632ac | ||
![]() |
3a664d45a9 | ||
![]() |
53607fe8c6 | ||
![]() |
9dec0f8ccd | ||
![]() |
89f4fe9d20 | ||
![]() |
f43655eea5 | ||
![]() |
6563984fdd | ||
![]() |
16d8eb0be3 | ||
![]() |
965fc9bc4e | ||
![]() |
56cb958a47 | ||
![]() |
f5feb1d8aa | ||
![]() |
e95065ed08 | ||
![]() |
68a411838d | ||
![]() |
ba63ab8b7a | ||
![]() |
26d4599ef4 | ||
![]() |
d049990f04 | ||
![]() |
9c8d683a19 | ||
![]() |
901677bbdf | ||
![]() |
8bb2374b1b | ||
![]() |
520896a3c2 | ||
![]() |
92db272759 | ||
![]() |
fc654d86c6 | ||
![]() |
523afe2f6f | ||
![]() |
460b9003fc | ||
![]() |
2ac0ad1d98 | ||
![]() |
a321432175 | ||
![]() |
63c9b3f830 | ||
![]() |
806b1296b0 | ||
![]() |
7f90ffa82f | ||
![]() |
db33c38e21 | ||
![]() |
a8c1fdd21e | ||
![]() |
d86a18b80b | ||
![]() |
bef6591548 | ||
![]() |
e1c07f109c | ||
![]() |
fb66d224ae | ||
![]() |
ee1fd3e865 | ||
![]() |
a9bfea233c | ||
![]() |
35cc291118 | ||
![]() |
35a41b3490 | ||
![]() |
db7cac5782 | ||
![]() |
099fa706a0 | ||
![]() |
f59cb661cd | ||
![]() |
ed84ce9692 | ||
![]() |
9912d427f2 | ||
![]() |
76f574f875 | ||
![]() |
ac90bb7088 | ||
![]() |
ce9f83e9a2 | ||
![]() |
fca7d2c5b0 | ||
![]() |
d7a5921e7b | ||
![]() |
cefa2ee183 | ||
![]() |
0eeed85193 | ||
![]() |
fd80408de2 | ||
![]() |
467a5169c0 | ||
![]() |
b0b3222b33 | ||
![]() |
b053881cef | ||
![]() |
92a9ed7080 | ||
![]() |
830b449006 | ||
![]() |
d38a8a317e | ||
![]() |
a0aed9112c | ||
![]() |
ce3b8544b9 | ||
![]() |
134ed7d303 | ||
![]() |
dc27871189 | ||
![]() |
9c9bfa2b77 | ||
![]() |
f02dd39619 | ||
![]() |
d37d99223d | ||
![]() |
4db943c5ff | ||
![]() |
ed001fb10b | ||
![]() |
5f43715dd8 | ||
![]() |
5435218187 | ||
![]() |
4ef5f3af89 | ||
![]() |
9eea17b793 | ||
![]() |
6a51e2aaad | ||
![]() |
2d33327d88 | ||
![]() |
e9ec2da917 | ||
![]() |
09d46dac61 | ||
![]() |
236fa14ec3 | ||
![]() |
2cb37820df | ||
![]() |
869fa91ae5 | ||
![]() |
22df03427f | ||
![]() |
e72a4e4a20 | ||
![]() |
ca8d31c6bb | ||
![]() |
354ea88984 | ||
![]() |
76af6e48cd | ||
![]() |
d05f807b9d | ||
![]() |
4092f7f75d | ||
![]() |
04668ad809 | ||
![]() |
9be5a15c77 | ||
![]() |
21d86f4797 | ||
![]() |
45e6ec1ee2 | ||
![]() |
9b97faa5e3 | ||
![]() |
8730c122fd | ||
![]() |
0046252e32 | ||
![]() |
f47440083e | ||
![]() |
bfaf44f9d1 | ||
![]() |
deba6a0db4 | ||
![]() |
51938fb51f | ||
![]() |
890ad9a1c8 | ||
![]() |
8466ef371a | ||
![]() |
4e55460799 | ||
![]() |
5fde6e659d | ||
![]() |
148bb99d89 | ||
![]() |
0540bae707 | ||
![]() |
0c6f647f53 | ||
![]() |
3aca67d511 | ||
![]() |
0e41a408e7 | ||
![]() |
19e1eaf2d7 | ||
![]() |
5e80a2b465 | ||
![]() |
866a57cde4 | ||
![]() |
c85236e251 | ||
![]() |
a88da0e39a | ||
![]() |
21a8fac477 | ||
![]() |
ca5ce04a38 | ||
![]() |
7c4b9a0410 | ||
![]() |
de6f06ea6d | ||
![]() |
bbc8e323e8 | ||
![]() |
89b6863ae3 | ||
![]() |
3f1850e9eb | ||
![]() |
54d6b5b6f3 | ||
![]() |
fb55ab197f | ||
![]() |
cc2db9a761 | ||
![]() |
58ba3e5c22 | ||
![]() |
182ffccd0c | ||
![]() |
ce99d14ee0 | ||
![]() |
8ce160b9ce | ||
![]() |
fe33714c8b | ||
![]() |
afbe85625c | ||
![]() |
cb47ee7721 | ||
![]() |
5caa256f1b | ||
![]() |
c66dfb84f9 | ||
![]() |
df1d703e4e | ||
![]() |
ce0ced0b6a | ||
![]() |
730e9b144d | ||
![]() |
69ff8dd0c4 | ||
![]() |
8d2c716fbe | ||
![]() |
389a100b46 | ||
![]() |
9fee7a2829 | ||
![]() |
a91897821a | ||
![]() |
815a2a07ff | ||
![]() |
b8d3eb76ac | ||
![]() |
ba75c2e7af | ||
![]() |
f04b844223 | ||
![]() |
242bad0a29 | ||
![]() |
8b20b2b63c | ||
![]() |
e0c8efc5e6 | ||
![]() |
f59c30ac04 | ||
![]() |
e4b9c08b45 | ||
![]() |
04e63eefe2 | ||
![]() |
a064ca0856 | ||
![]() |
6044ea92ad | ||
![]() |
17e8215420 | ||
![]() |
a4ae1bee79 | ||
![]() |
7d335d7d85 | ||
![]() |
7c194d8910 | ||
![]() |
a92100bb0a | ||
![]() |
303af611d1 | ||
![]() |
559b6e9d5b | ||
![]() |
75a95ff675 | ||
![]() |
3024ee43f9 | ||
![]() |
b34b92fa87 | ||
![]() |
1832ed0a48 | ||
![]() |
f398692e75 | ||
![]() |
68bee4dd58 | ||
![]() |
f1297e1f36 | ||
![]() |
953e3e060b | ||
![]() |
c37f660718 | ||
![]() |
02754369a6 | ||
![]() |
0df9e9932f | ||
![]() |
eddb392ad0 | ||
![]() |
e8ba349447 | ||
![]() |
5be22d46ab | ||
![]() |
ffaff30b46 | ||
![]() |
c4cad5bccd | ||
![]() |
e4085fe1f6 | ||
![]() |
8bfef92c86 | ||
![]() |
0c07178c0a | ||
![]() |
1010777139 | ||
![]() |
e57477c16a | ||
![]() |
30fa92c120 | ||
![]() |
b32438dc18 | ||
![]() |
614bd2f451 | ||
![]() |
6c12a5a4b1 | ||
![]() |
bbcec38450 | ||
![]() |
416e2e26c0 | ||
![]() |
1a7164b466 | ||
![]() |
3ddcd2d0f6 | ||
![]() |
648c02e622 | ||
![]() |
b0b953bfac | ||
![]() |
abeaa63005 | ||
![]() |
9cd23374f4 | ||
![]() |
72bd5f84d6 | ||
![]() |
22b4550fdf | ||
![]() |
87c22229e0 | ||
![]() |
971fd8dc60 | ||
![]() |
049c3caadd | ||
![]() |
fb2a24d11e | ||
![]() |
d4646bac01 | ||
![]() |
14e5b2a7a5 | ||
![]() |
734a733a4c | ||
![]() |
8f31c182f6 | ||
![]() |
e51a819bfd | ||
![]() |
05d7e85aa3 | ||
![]() |
cf527e4bc2 | ||
![]() |
197b581e8e | ||
![]() |
f75bf1f676 | ||
![]() |
28df79cfda | ||
![]() |
3bf19883a8 | ||
![]() |
303e065433 | ||
![]() |
7ad0b37a9e | ||
![]() |
930c7e4afa | ||
![]() |
81faae6f74 | ||
![]() |
f7fc83ac12 | ||
![]() |
21a099ee9f | ||
![]() |
7d1ce1b240 | ||
![]() |
d1f1309198 | ||
![]() |
68dd818f7a | ||
![]() |
50bea33a19 | ||
![]() |
27cae037ce | ||
![]() |
dbb5bf7550 | ||
![]() |
9ef743a695 | ||
![]() |
f3642a1677 | ||
![]() |
2d651c2a66 | ||
![]() |
ef39317019 | ||
![]() |
441f1fbcb5 | ||
![]() |
09a27a6791 | ||
![]() |
32bbdc194a | ||
![]() |
52588a3915 | ||
![]() |
9fffc93e5d | ||
![]() |
effec839af | ||
![]() |
884ed561a1 | ||
![]() |
4165e64ce0 | ||
![]() |
6053b64b2e | ||
![]() |
ed462dc257 | ||
![]() |
74a05929be | ||
![]() |
5e388b1f02 | ||
![]() |
ff2fa9a78c | ||
![]() |
6d1be9e73f | ||
![]() |
ba570f4004 | ||
![]() |
6ab497edf8 | ||
![]() |
8c1cd273df | ||
![]() |
8f68bcbba9 | ||
![]() |
8291cf9daa | ||
![]() |
bb40e66833 | ||
![]() |
f852208eff | ||
![]() |
3bbe1603eb | ||
![]() |
25d60e11da | ||
![]() |
78d06426cf | ||
![]() |
320b2bb48b | ||
![]() |
a7b8382617 | ||
![]() |
77fe687ec2 | ||
![]() |
069f08b55e | ||
![]() |
204ccf8b40 | ||
![]() |
4b9ff641ba | ||
![]() |
1520b5832a | ||
![]() |
04f2e2e70c | ||
![]() |
920d2972ea | ||
![]() |
e94fc493b8 | ||
![]() |
3e22270c2c | ||
![]() |
27fa34e24e | ||
![]() |
4e0cebaf32 | ||
![]() |
f021480bc5 | ||
![]() |
34c3374d84 | ||
![]() |
4cb7154917 | ||
![]() |
08863348dc | ||
![]() |
2bcf816b77 | ||
![]() |
d2b99e6963 | ||
![]() |
48a800882e | ||
![]() |
595e13ecac | ||
![]() |
5261d583a8 | ||
![]() |
5c488f8298 | ||
![]() |
6fc87a6f66 | ||
![]() |
3133f9b01f | ||
![]() |
2c0d330f1f | ||
![]() |
fb9ea981ed | ||
![]() |
63c113f78d | ||
![]() |
a67799a670 | ||
![]() |
e3d78d6dc5 | ||
![]() |
76a4b1efbd | ||
![]() |
882e79524b | ||
![]() |
0ab8f8fd7c | ||
![]() |
86b9eb0bd7 | ||
![]() |
011cbe7d22 | ||
![]() |
9b0b2c5b71 | ||
![]() |
be72bf7b3c | ||
![]() |
3e062ba673 | ||
![]() |
322d965539 | ||
![]() |
7b840527b5 | ||
![]() |
dced053ba2 | ||
![]() |
fe4322e64b | ||
![]() |
0800c702fb | ||
![]() |
b6d6e2fd4b | ||
![]() |
2bbb1bfa7e | ||
![]() |
e2af8ac3cc | ||
![]() |
25ff5fef14 | ||
![]() |
2f9c088091 | ||
![]() |
50c397901b | ||
![]() |
1f7d4c25d4 | ||
![]() |
29819fac23 | ||
![]() |
cc301df57d | ||
![]() |
7d5b566312 | ||
![]() |
07cd68f5d0 | ||
![]() |
99bf6fa781 | ||
![]() |
bfad1eb5ac | ||
![]() |
b7bd7c1065 | ||
![]() |
61bae5da64 | ||
![]() |
bdd13db8cf | ||
![]() |
cdc3d11181 | ||
![]() |
8f729e2a95 | ||
![]() |
bc9195f7d5 | ||
![]() |
7f1a321075 | ||
![]() |
72b9f8636d | ||
![]() |
c9cd316c0c | ||
![]() |
6cf3580fb4 | ||
![]() |
5d91aefb55 | ||
![]() |
e3c0530941 | ||
![]() |
2c9223ed80 |
@@ -16,6 +16,9 @@
|
|||||||
"runem.lit-plugin",
|
"runem.lit-plugin",
|
||||||
"ms-python.vscode-pylance"
|
"ms-python.vscode-pylance"
|
||||||
],
|
],
|
||||||
|
"containerEnv": {
|
||||||
|
"WORKSPACE_DIRECTORY": "${containerWorkspaceFolder}"
|
||||||
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"terminal.integrated.shell.linux": "/bin/bash",
|
"terminal.integrated.shell.linux": "/bin/bash",
|
||||||
"files.eol": "\n",
|
"files.eol": "\n",
|
||||||
|
2
.github/ISSUE_TEMPLATE.md
vendored
2
.github/ISSUE_TEMPLATE.md
vendored
@@ -51,7 +51,7 @@ DO NOT DELETE ANY TEXT from this template! Otherwise, your issue may be closed w
|
|||||||
<!--
|
<!--
|
||||||
Provide details about the versions you are using, which helps us reproducing
|
Provide details about the versions you are using, which helps us reproducing
|
||||||
and finding the issue quicker. Version information is found in the
|
and finding the issue quicker. Version information is found in the
|
||||||
Home Assistant frontend: Configuration -> Info.
|
Home Assistant frontend: Settings -> About.
|
||||||
|
|
||||||
Browser version and operating system is important! Please try to replicate
|
Browser version and operating system is important! Please try to replicate
|
||||||
your issue in a different browser and be sure to include your findings.
|
your issue in a different browser and be sure to include your findings.
|
||||||
|
6
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
6
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -1,4 +1,4 @@
|
|||||||
name: Report a bug with the UI, Frontend or Lovelace
|
name: Report a bug with the UI / Dashboards
|
||||||
description: Report an issue related to the Home Assistant frontend.
|
description: Report an issue related to the Home Assistant frontend.
|
||||||
labels: bug
|
labels: bug
|
||||||
body:
|
body:
|
||||||
@@ -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 Lovelace cards.**
|
**Please not 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
|
||||||
@@ -64,7 +64,7 @@ body:
|
|||||||
label: What version of Home Assistant Core has the issue?
|
label: What version of Home Assistant Core has the issue?
|
||||||
placeholder: core-
|
placeholder: core-
|
||||||
description: >
|
description: >
|
||||||
Can be found in the Configuration panel -> Info.
|
Can be found in: [Settings -> About](https://my.home-assistant.io/redirect/info/).
|
||||||
- type: input
|
- type: input
|
||||||
attributes:
|
attributes:
|
||||||
label: What was the last working version of Home Assistant Core?
|
label: What was the last working version of Home Assistant Core?
|
||||||
|
8
.github/ISSUE_TEMPLATE/config.yml
vendored
8
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,17 +1,17 @@
|
|||||||
blank_issues_enabled: false
|
blank_issues_enabled: false
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: Request a feature for the UI, Frontend or Lovelace
|
- name: Request a feature for the UI / Dashboards
|
||||||
url: https://github.com/home-assistant/frontend/discussions/category_choices
|
url: https://github.com/home-assistant/frontend/discussions/category_choices
|
||||||
about: Request an new feature for the Home Assistant frontend.
|
about: Request an new feature for the Home Assistant frontend.
|
||||||
- name: Report a bug that is NOT related to the UI, Frontend or Lovelace
|
- name: Report a bug that is NOT related to the UI / Dashboards
|
||||||
url: https://github.com/home-assistant/core/issues
|
url: https://github.com/home-assistant/core/issues
|
||||||
about: This is the issue tracker for our frontend. Please report other issues with the backend repository.
|
about: This is the issue tracker for our frontend. Please report other issues in the backend ("core") repository.
|
||||||
- name: Report incorrect or missing information on our website
|
- name: Report incorrect or missing information on our website
|
||||||
url: https://github.com/home-assistant/home-assistant.io/issues
|
url: https://github.com/home-assistant/home-assistant.io/issues
|
||||||
about: Our documentation has its own issue tracker. Please report issues with the website there.
|
about: Our documentation has its own issue tracker. Please report issues with the website there.
|
||||||
- name: I have a question or need support
|
- name: I have a question or need support
|
||||||
url: https://www.home-assistant.io/help
|
url: https://www.home-assistant.io/help
|
||||||
about: We use GitHub for tracking bugs, check our website for resources on getting help.
|
about: We use GitHub for tracking bugs. Check our website for resources on getting help.
|
||||||
- name: I'm unsure where to go
|
- name: I'm unsure where to go
|
||||||
url: https://www.home-assistant.io/join-chat
|
url: https://www.home-assistant.io/join-chat
|
||||||
about: If you are unsure where to go, then joining our chat is recommended; Just ask!
|
about: If you are unsure where to go, then joining our chat is recommended; Just ask!
|
||||||
|
8
.github/dependabot.yml
vendored
Normal file
8
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: weekly
|
||||||
|
time: "06:00"
|
||||||
|
open-pull-requests-limit: 10
|
21
.github/workflows/ci.yaml
vendored
21
.github/workflows/ci.yaml
vendored
@@ -11,17 +11,18 @@ on:
|
|||||||
- master
|
- master
|
||||||
|
|
||||||
env:
|
env:
|
||||||
NODE_VERSION: 14
|
NODE_VERSION: 16
|
||||||
NODE_OPTIONS: --max_old_space_size=6144
|
NODE_OPTIONS: --max_old_space_size=6144
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint:
|
lint:
|
||||||
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@v2
|
uses: actions/checkout@v3
|
||||||
- name: Set up Node ${{ env.NODE_VERSION }}
|
- name: Set up Node ${{ env.NODE_VERSION }}
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
cache: yarn
|
cache: yarn
|
||||||
@@ -30,7 +31,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
CI: true
|
CI: true
|
||||||
- name: Build resources
|
- name: Build resources
|
||||||
run: ./node_modules/.bin/gulp gen-icons-json build-translations build-locale-data gather-gallery-demos
|
run: ./node_modules/.bin/gulp gen-icons-json build-translations build-locale-data gather-gallery-pages
|
||||||
- name: Run eslint
|
- name: Run eslint
|
||||||
run: yarn run lint:eslint
|
run: yarn run lint:eslint
|
||||||
- name: Run tsc
|
- name: Run tsc
|
||||||
@@ -43,9 +44,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@v2
|
uses: actions/checkout@v3
|
||||||
- name: Set up Node ${{ env.NODE_VERSION }}
|
- name: Set up Node ${{ env.NODE_VERSION }}
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
cache: yarn
|
cache: yarn
|
||||||
@@ -62,9 +63,9 @@ jobs:
|
|||||||
needs: [lint, test]
|
needs: [lint, test]
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
- name: Set up Node ${{ env.NODE_VERSION }}
|
- name: Set up Node ${{ env.NODE_VERSION }}
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
cache: yarn
|
cache: yarn
|
||||||
@@ -81,9 +82,9 @@ jobs:
|
|||||||
needs: [lint, test]
|
needs: [lint, test]
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
- name: Set up Node ${{ env.NODE_VERSION }}
|
- name: Set up Node ${{ env.NODE_VERSION }}
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
cache: yarn
|
cache: yarn
|
||||||
|
8
.github/workflows/codeql-analysis.yml
vendored
8
.github/workflows/codeql-analysis.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
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.
|
||||||
@@ -36,14 +36,14 @@ jobs:
|
|||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v1
|
uses: github/codeql-action/init@v2
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
|
|
||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@v1
|
uses: github/codeql-action/autobuild@v2
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
# 📚 https://git.io/JvXDl
|
# 📚 https://git.io/JvXDl
|
||||||
@@ -57,4 +57,4 @@ jobs:
|
|||||||
# make release
|
# make release
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v1
|
uses: github/codeql-action/analyze@v2
|
||||||
|
12
.github/workflows/demo.yaml
vendored
12
.github/workflows/demo.yaml
vendored
@@ -6,7 +6,7 @@ on:
|
|||||||
- dev
|
- dev
|
||||||
|
|
||||||
env:
|
env:
|
||||||
NODE_VERSION: 14
|
NODE_VERSION: 16
|
||||||
NODE_OPTIONS: --max_old_space_size=6144
|
NODE_OPTIONS: --max_old_space_size=6144
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -14,9 +14,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@v2
|
uses: actions/checkout@v3
|
||||||
- name: Set up Node ${{ env.NODE_VERSION }}
|
- name: Set up Node ${{ env.NODE_VERSION }}
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
cache: yarn
|
cache: yarn
|
||||||
@@ -26,10 +26,10 @@ jobs:
|
|||||||
CI: true
|
CI: true
|
||||||
- name: Build Demo
|
- name: Build Demo
|
||||||
run: ./node_modules/.bin/gulp build-demo
|
run: ./node_modules/.bin/gulp build-demo
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Deploy to Netlify
|
- name: Deploy to Netlify
|
||||||
uses: netlify/actions/cli@master
|
run: npx netlify-cli deploy --dir=demo/dist --prod
|
||||||
env:
|
env:
|
||||||
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
||||||
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_DEMO_DEV_SITE_ID }}
|
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_DEMO_DEV_SITE_ID }}
|
||||||
with:
|
|
||||||
args: deploy --dir=demo/dist --prod
|
|
||||||
|
2
.github/workflows/lock.yml
vendored
2
.github/workflows/lock.yml
vendored
@@ -9,7 +9,7 @@ jobs:
|
|||||||
lock:
|
lock:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: dessant/lock-threads@v2.0.1
|
- uses: dessant/lock-threads@v3.0.0
|
||||||
with:
|
with:
|
||||||
github-token: ${{ github.token }}
|
github-token: ${{ github.token }}
|
||||||
issue-lock-inactive-days: "30"
|
issue-lock-inactive-days: "30"
|
||||||
|
4
.github/workflows/netflify.yml
vendored
4
.github/workflows/netflify.yml
vendored
@@ -15,5 +15,5 @@ jobs:
|
|||||||
- name: Trigger Demo build
|
- name: Trigger Demo build
|
||||||
run: curl -X POST -d {} https://api.netlify.com/build_hooks/${{ secrets.NETLIFY_DEMO_DEV_BUILD_HOOK }}
|
run: curl -X POST -d {} https://api.netlify.com/build_hooks/${{ secrets.NETLIFY_DEMO_DEV_BUILD_HOOK }}
|
||||||
|
|
||||||
- name: Trigger Gallery build
|
- name: Trigger Design build
|
||||||
run: curl -X POST -d {} https://api.netlify.com/build_hooks/${{ secrets.NETLIFY_GALLERY_DEV_BUILD_HOOK }}
|
run: curl -X POST -d "NIGHTLY" https://api.netlify.com/build_hooks/${{ secrets.NETLIFY_GALLERY_DEV_BUILD_HOOK }}
|
||||||
|
72
.github/workflows/nightly.yaml
vendored
Normal file
72
.github/workflows/nightly.yaml
vendored
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
name: Nightly
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: "0 1 * * *"
|
||||||
|
|
||||||
|
env:
|
||||||
|
PYTHON_VERSION: "3.10"
|
||||||
|
NODE_VERSION: 16
|
||||||
|
NODE_OPTIONS: --max_old_space_size=6144
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
actions: none
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
nightly:
|
||||||
|
name: Nightly
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- name: Checkout the repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Set up Python ${{ env.PYTHON_VERSION }}
|
||||||
|
uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: ${{ env.PYTHON_VERSION }}
|
||||||
|
|
||||||
|
- name: Set up Node ${{ env.NODE_VERSION }}
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
|
cache: yarn
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: yarn install
|
||||||
|
|
||||||
|
- name: Download translations
|
||||||
|
run: ./script/translations_download
|
||||||
|
env:
|
||||||
|
LOKALISE_TOKEN: ${{ secrets.LOKALISE_TOKEN }}
|
||||||
|
|
||||||
|
- name: Bump version
|
||||||
|
run: script/version_bump.js nightly
|
||||||
|
|
||||||
|
- name: Build nightly Python wheels
|
||||||
|
run: |
|
||||||
|
pip install build
|
||||||
|
yarn install
|
||||||
|
export SKIP_FETCH_NIGHTLY_TRANSLATIONS=1
|
||||||
|
script/build_frontend
|
||||||
|
rm -rf dist home_assistant_frontend.egg-info
|
||||||
|
python3 -m build
|
||||||
|
|
||||||
|
- name: Archive translations
|
||||||
|
run: tar -czvf translations.tar.gz translations
|
||||||
|
|
||||||
|
- name: Upload build artifacts
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: wheels
|
||||||
|
path: dist/home_assistant_frontend*.whl
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
- name: Upload translations
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: translations
|
||||||
|
path: translations.tar.gz
|
||||||
|
if-no-files-found: error
|
59
.github/workflows/release.yaml
vendored
59
.github/workflows/release.yaml
vendored
@@ -6,28 +6,36 @@ on:
|
|||||||
- published
|
- published
|
||||||
|
|
||||||
env:
|
env:
|
||||||
PYTHON_VERSION: 3.8
|
PYTHON_VERSION: "3.10"
|
||||||
NODE_VERSION: 14
|
NODE_VERSION: 16
|
||||||
NODE_OPTIONS: --max_old_space_size=6144
|
NODE_OPTIONS: --max_old_space_size=6144
|
||||||
|
|
||||||
|
# Set default workflow permissions
|
||||||
|
# All scopes not mentioned here are set to no access
|
||||||
|
# https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token
|
||||||
|
permissions:
|
||||||
|
actions: none
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
name: Release
|
name: Release
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write # Required to upload release assets
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Verify version
|
- name: Verify version
|
||||||
uses: home-assistant/actions/helpers/verify-version@master
|
uses: home-assistant/actions/helpers/verify-version@master
|
||||||
|
|
||||||
- name: Set up Python ${{ env.PYTHON_VERSION }}
|
- name: Set up Python ${{ env.PYTHON_VERSION }}
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.PYTHON_VERSION }}
|
python-version: ${{ env.PYTHON_VERSION }}
|
||||||
|
|
||||||
- name: Set up Node ${{ env.NODE_VERSION }}
|
- name: Set up Node ${{ env.NODE_VERSION }}
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
cache: yarn
|
cache: yarn
|
||||||
@@ -41,12 +49,19 @@ jobs:
|
|||||||
LOKALISE_TOKEN: ${{ secrets.LOKALISE_TOKEN }}
|
LOKALISE_TOKEN: ${{ secrets.LOKALISE_TOKEN }}
|
||||||
- name: Build and release package
|
- name: Build and release package
|
||||||
run: |
|
run: |
|
||||||
python3 -m pip install twine
|
python3 -m pip install twine build
|
||||||
export TWINE_USERNAME="__token__"
|
export TWINE_USERNAME="__token__"
|
||||||
export TWINE_PASSWORD="${{ secrets.TWINE_TOKEN }}"
|
export TWINE_PASSWORD="${{ secrets.TWINE_TOKEN }}"
|
||||||
|
export SKIP_FETCH_NIGHTLY_TRANSLATIONS=1
|
||||||
script/release
|
script/release
|
||||||
|
|
||||||
|
- name: Upload release assets
|
||||||
|
uses: softprops/action-gh-release@v0.1.15
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
dist/*.whl
|
||||||
|
dist/*.tar.gz
|
||||||
|
|
||||||
wheels-init:
|
wheels-init:
|
||||||
name: Init wheels build
|
name: Init wheels build
|
||||||
needs: release
|
needs: release
|
||||||
@@ -59,33 +74,11 @@ jobs:
|
|||||||
version=$(echo "${{ github.ref }}" | awk -F"/" '{print $NF}' )
|
version=$(echo "${{ github.ref }}" | awk -F"/" '{print $NF}' )
|
||||||
echo "home-assistant-frontend==$version" > ./requirements.txt
|
echo "home-assistant-frontend==$version" > ./requirements.txt
|
||||||
|
|
||||||
- name: Upload requirements.txt
|
|
||||||
uses: actions/upload-artifact@v2
|
|
||||||
with:
|
|
||||||
name: requirements
|
|
||||||
path: ./requirements.txt
|
|
||||||
|
|
||||||
build-wheels:
|
|
||||||
name: Build wheels for ${{ matrix.arch }}
|
|
||||||
needs: wheels-init
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
arch: ["aarch64", "armhf", "armv7", "amd64", "i386"]
|
|
||||||
tag:
|
|
||||||
- "3.9-alpine3.14"
|
|
||||||
steps:
|
|
||||||
- name: Download requirements.txt
|
|
||||||
uses: actions/download-artifact@v2
|
|
||||||
with:
|
|
||||||
name: requirements
|
|
||||||
|
|
||||||
- name: Build wheels
|
- name: Build wheels
|
||||||
uses: home-assistant/wheels@master
|
uses: home-assistant/wheels@2022.10.1
|
||||||
with:
|
with:
|
||||||
tag: ${{ matrix.tag }}
|
abi: cp310
|
||||||
arch: ${{ matrix.arch }}
|
tag: musllinux_1_2
|
||||||
wheels-host: ${{ secrets.WHEELS_HOST }}
|
arch: amd64
|
||||||
wheels-key: ${{ secrets.WHEELS_KEY }}
|
wheels-key: ${{ secrets.WHEELS_KEY }}
|
||||||
wheels-user: wheels
|
|
||||||
requirements: "requirements.txt"
|
requirements: "requirements.txt"
|
||||||
|
2
.github/workflows/stale.yml
vendored
2
.github/workflows/stale.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: 90 days stale policy
|
- name: 90 days stale policy
|
||||||
uses: actions/stale@v3.0.13
|
uses: actions/stale@v6.0.1
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
days-before-stale: 90
|
days-before-stale: 90
|
||||||
|
4
.github/workflows/translations.yaml
vendored
4
.github/workflows/translations.yaml
vendored
@@ -8,7 +8,7 @@ on:
|
|||||||
- src/translations/en.json
|
- src/translations/en.json
|
||||||
|
|
||||||
env:
|
env:
|
||||||
NODE_VERSION: 14
|
NODE_VERSION: 16
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
upload:
|
upload:
|
||||||
@@ -16,7 +16,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Upload Translations
|
- name: Upload Translations
|
||||||
run: |
|
run: |
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,6 +5,7 @@
|
|||||||
build
|
build
|
||||||
hass_frontend/*
|
hass_frontend/*
|
||||||
dist
|
dist
|
||||||
|
translations
|
||||||
|
|
||||||
# yarn
|
# yarn
|
||||||
.yarn/*
|
.yarn/*
|
||||||
|
4
.husky/pre-commit
Executable file
4
.husky/pre-commit
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
. "$(dirname -- "$0")/_/husky.sh"
|
||||||
|
|
||||||
|
yarn run lint-staged --relative --shell "/bin/bash"
|
10
.vscode/tasks.json
vendored
10
.vscode/tasks.json
vendored
@@ -181,7 +181,7 @@
|
|||||||
{
|
{
|
||||||
"label": "Run HA Core for Supervisor in devcontainer",
|
"label": "Run HA Core for Supervisor in devcontainer",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command": "HASSIO=${input:supervisorHost} HASSIO_TOKEN=${input:supervisorToken} script/core",
|
"command": "SUPERVISOR=${input:supervisorHost} SUPERVISOR_TOKEN=${input:supervisorToken} script/core",
|
||||||
"isBackground": true,
|
"isBackground": true,
|
||||||
"group": {
|
"group": {
|
||||||
"kind": "build",
|
"kind": "build",
|
||||||
@@ -191,7 +191,13 @@
|
|||||||
"runOptions": {
|
"runOptions": {
|
||||||
"instanceLimit": 1
|
"instanceLimit": 1
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
"label": "Setup and fetch nightly translations",
|
||||||
|
"type": "gulp",
|
||||||
|
"task": "setup-and-fetch-nightly-translations",
|
||||||
|
"problemMatcher": []
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
|
File diff suppressed because one or more lines are too long
@@ -1,11 +1,10 @@
|
|||||||
diff --git a/lib/uni-virtualizer/lib/polyfillLoaders/EventTarget.js b/lib/uni-virtualizer/lib/polyfillLoaders/EventTarget.js
|
diff --git a/polyfillLoaders/EventTarget.js b/polyfillLoaders/EventTarget.js
|
||||||
index d92179f7fd5315203f870a6963e871dc8ddf6c0c..362e284121b97e0fba0925225777aebc32e26b8d 100644
|
index 4e18ade7ba485849f17f28c94c42f0e0e01ac387..8f34f4f646c7f7becc208fb5a546c96034fc74dc 100644
|
||||||
--- a/lib/uni-virtualizer/lib/polyfillLoaders/EventTarget.js
|
--- a/polyfillLoaders/EventTarget.js
|
||||||
+++ b/lib/uni-virtualizer/lib/polyfillLoaders/EventTarget.js
|
+++ b/polyfillLoaders/EventTarget.js
|
||||||
@@ -1,14 +1,15 @@
|
@@ -6,16 +6,15 @@
|
||||||
-let _ET, ET;
|
let _ET;
|
||||||
+let _ET;
|
let ET;
|
||||||
+let ET;
|
|
||||||
export default async function EventTarget() {
|
export default async function EventTarget() {
|
||||||
- return ET || init();
|
- return ET || init();
|
||||||
+ return ET || init();
|
+ return ET || init();
|
||||||
@@ -26,4 +25,5 @@ index d92179f7fd5315203f870a6963e871dc8ddf6c0c..362e284121b97e0fba0925225777aebc
|
|||||||
+ _ET = (await import("event-target-shim")).default.EventTarget;
|
+ _ET = (await import("event-target-shim")).default.EventTarget;
|
||||||
+ }
|
+ }
|
||||||
+ return (ET = _ET);
|
+ return (ET = _ET);
|
||||||
}
|
}
|
||||||
|
//# sourceMappingURL=EventTarget.js.map
|
631
.yarn/releases/yarn-3.0.2.cjs
vendored
631
.yarn/releases/yarn-3.0.2.cjs
vendored
File diff suppressed because one or more lines are too long
783
.yarn/releases/yarn-3.2.3.cjs
vendored
Executable file
783
.yarn/releases/yarn-3.2.3.cjs
vendored
Executable file
File diff suppressed because one or more lines are too long
@@ -6,4 +6,4 @@ plugins:
|
|||||||
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
|
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
|
||||||
spec: "@yarnpkg/plugin-interactive-tools"
|
spec: "@yarnpkg/plugin-interactive-tools"
|
||||||
|
|
||||||
yarnPath: .yarn/releases/yarn-3.0.2.cjs
|
yarnPath: .yarn/releases/yarn-3.2.3.cjs
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
include README.md
|
include README.md
|
||||||
include LICENSE.md
|
|
||||||
graft hass_frontend
|
graft hass_frontend
|
||||||
graft hass_frontend_es5
|
graft hass_frontend_es5
|
||||||
recursive-exclude * *.py[co]
|
recursive-exclude * *.py[co]
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
This is the repository for the official [Home Assistant](https://home-assistant.io) frontend.
|
This is the repository for the official [Home Assistant](https://home-assistant.io) frontend.
|
||||||
|
|
||||||
[](https://demo.home-assistant.io/)
|
[](https://demo.home-assistant.io/)
|
||||||
|
|
||||||
- [View demo of Home Assistant](https://demo.home-assistant.io/)
|
- [View demo of Home Assistant](https://demo.home-assistant.io/)
|
||||||
- [More information about Home Assistant](https://home-assistant.io)
|
- [More information about Home Assistant](https://home-assistant.io)
|
||||||
|
@@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"rules": {
|
|
||||||
"import/no-extraneous-dependencies": 0,
|
|
||||||
"no-restricted-syntax": 0,
|
|
||||||
"no-console": 0
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,7 +1,12 @@
|
|||||||
{
|
{
|
||||||
"extends": "../.eslintrc.json",
|
"extends": "../.eslintrc.json",
|
||||||
"rules": {
|
"rules": {
|
||||||
"import/no-extraneous-dependencies": 0,
|
"no-console": "off",
|
||||||
"global-require": 0
|
"import/no-extraneous-dependencies": "off",
|
||||||
|
"import/extensions": "off",
|
||||||
|
"import/no-dynamic-require": "off",
|
||||||
|
"global-require": "off",
|
||||||
|
"@typescript-eslint/no-var-requires": "off",
|
||||||
|
"prefer-arrow-callback": "off"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
|
|
||||||
// Currently only supports CommonJS modules, as require is synchronous. `import` would need babel running asynchronous.
|
// Currently only supports CommonJS modules, as require is synchronous. `import` would need babel running asynchronous.
|
||||||
@@ -29,7 +28,6 @@ module.exports = function inlineConstants(babel, options, cwd) {
|
|||||||
const absolute = module.startsWith(".")
|
const absolute = module.startsWith(".")
|
||||||
? require.resolve(module, { paths: [cwd] })
|
? require.resolve(module, { paths: [cwd] })
|
||||||
: module;
|
: module;
|
||||||
// eslint-disable-next-line import/no-dynamic-require
|
|
||||||
return [absolute, require(absolute)];
|
return [absolute, require(absolute)];
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@@ -1,16 +1,16 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const env = require("./env.js");
|
const env = require("./env.js");
|
||||||
const paths = require("./paths.js");
|
const paths = require("./paths.js");
|
||||||
|
|
||||||
// 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 = ({ latestBuild }) => [
|
module.exports.ignorePackages = ({ latestBuild }) => [
|
||||||
// Part of yaml.js and only used for !!js functions that we don't use
|
// Part of yaml.js and only used for !!js functions that we don't use
|
||||||
require.resolve("esprima"),
|
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 }) =>
|
module.exports.emptyPackages = ({ latestBuild, isHassioBuild }) =>
|
||||||
[
|
[
|
||||||
// Contains all color definitions for all material color sets.
|
// Contains all color definitions for all material color sets.
|
||||||
// We don't use it
|
// We don't use it
|
||||||
@@ -28,6 +28,15 @@ module.exports.emptyPackages = ({ latestBuild }) =>
|
|||||||
),
|
),
|
||||||
// This polyfill is loaded in workers to support ES5, filter it out.
|
// This polyfill is loaded in workers to support ES5, filter it out.
|
||||||
latestBuild && require.resolve("proxy-polyfill/src/index.js"),
|
latestBuild && require.resolve("proxy-polyfill/src/index.js"),
|
||||||
|
// Icons in supervisor conflict with icons in HA so we don't load.
|
||||||
|
isHassioBuild &&
|
||||||
|
require.resolve(
|
||||||
|
path.resolve(paths.polymer_dir, "src/components/ha-icon.ts")
|
||||||
|
),
|
||||||
|
isHassioBuild &&
|
||||||
|
require.resolve(
|
||||||
|
path.resolve(paths.polymer_dir, "src/components/ha-icon-picker.ts")
|
||||||
|
),
|
||||||
].filter(Boolean);
|
].filter(Boolean);
|
||||||
|
|
||||||
module.exports.definedVars = ({ isProdBuild, latestBuild, defineOverlay }) => ({
|
module.exports.definedVars = ({ isProdBuild, latestBuild, defineOverlay }) => ({
|
||||||
@@ -196,6 +205,7 @@ module.exports.config = {
|
|||||||
publicPath: publicPath(latestBuild, paths.hassio_publicPath),
|
publicPath: publicPath(latestBuild, paths.hassio_publicPath),
|
||||||
isProdBuild,
|
isProdBuild,
|
||||||
latestBuild,
|
latestBuild,
|
||||||
|
isHassioBuild: true,
|
||||||
defineOverlay: {
|
defineOverlay: {
|
||||||
__SUPERVISOR__: true,
|
__SUPERVISOR__: true,
|
||||||
},
|
},
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const paths = require("./paths.js");
|
const paths = require("./paths.js");
|
||||||
@@ -26,11 +25,11 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
version() {
|
version() {
|
||||||
const version = fs
|
const version = fs
|
||||||
.readFileSync(path.resolve(paths.polymer_dir, "setup.py"), "utf8")
|
.readFileSync(path.resolve(paths.polymer_dir, "pyproject.toml"), "utf8")
|
||||||
.match(/\d{8}\.\d+/);
|
.match(/version\W+=\W"(\d{8}\.\d(?:\.dev)?)"/);
|
||||||
if (!version) {
|
if (!version) {
|
||||||
throw Error("Version not found");
|
throw Error("Version not found");
|
||||||
}
|
}
|
||||||
return version[0];
|
return version[1];
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@@ -31,6 +31,6 @@ gulp.task("clean-hassio", () =>
|
|||||||
gulp.task(
|
gulp.task(
|
||||||
"clean-gallery",
|
"clean-gallery",
|
||||||
gulp.parallel("clean-translations", () =>
|
gulp.parallel("clean-translations", () =>
|
||||||
del([paths.gallery_output_root, paths.build_dir])
|
del([paths.gallery_output_root, paths.gallery_build, paths.build_dir])
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@@ -1,17 +1,12 @@
|
|||||||
const del = require("del");
|
|
||||||
const gulp = require("gulp");
|
const gulp = require("gulp");
|
||||||
const fs = require("fs");
|
const fs = require("fs/promises");
|
||||||
const mapStream = require("map-stream");
|
const mapStream = require("map-stream");
|
||||||
|
|
||||||
const inDirFrontend = "translations/frontend";
|
const inDirFrontend = "translations/frontend";
|
||||||
const inDirBackend = "translations/backend";
|
const inDirBackend = "translations/backend";
|
||||||
const downloadDir = "translations/downloads";
|
|
||||||
const srcMeta = "src/translations/translationMetadata.json";
|
const srcMeta = "src/translations/translationMetadata.json";
|
||||||
|
|
||||||
const encoding = "utf8";
|
const encoding = "utf8";
|
||||||
|
|
||||||
const tasks = [];
|
|
||||||
|
|
||||||
function hasHtml(data) {
|
function hasHtml(data) {
|
||||||
return /<[a-z][\s\S]*>/i.test(data);
|
return /<[a-z][\s\S]*>/i.test(data);
|
||||||
}
|
}
|
||||||
@@ -46,50 +41,29 @@ function checkHtml() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let taskName = "clean-downloaded-translations";
|
// Backend translations do not currently pass HTML check so are excluded here for now
|
||||||
gulp.task(taskName, function () {
|
gulp.task("check-translations-html", function () {
|
||||||
return del([`${downloadDir}/**`]);
|
return gulp.src([`${inDirFrontend}/*.json`]).pipe(checkHtml());
|
||||||
});
|
});
|
||||||
tasks.push(taskName);
|
|
||||||
|
|
||||||
taskName = "check-translations-html";
|
gulp.task("check-all-files-exist", async function () {
|
||||||
gulp.task(taskName, function () {
|
const file = await fs.readFile(srcMeta, { encoding });
|
||||||
return gulp.src(`${downloadDir}/*.json`).pipe(checkHtml());
|
|
||||||
});
|
|
||||||
tasks.push(taskName);
|
|
||||||
|
|
||||||
taskName = "check-all-files-exist";
|
|
||||||
gulp.task(taskName, function () {
|
|
||||||
const file = fs.readFileSync(srcMeta, { encoding });
|
|
||||||
const meta = JSON.parse(file);
|
const meta = JSON.parse(file);
|
||||||
|
const writings = [];
|
||||||
Object.keys(meta).forEach((lang) => {
|
Object.keys(meta).forEach((lang) => {
|
||||||
if (!fs.existsSync(`${inDirFrontend}/${lang}.json`)) {
|
writings.push(
|
||||||
fs.writeFileSync(`${inDirFrontend}/${lang}.json`, JSON.stringify({}));
|
fs.writeFile(`${inDirFrontend}/${lang}.json`, JSON.stringify({}), {
|
||||||
}
|
flag: "wx",
|
||||||
if (!fs.existsSync(`${inDirBackend}/${lang}.json`)) {
|
}),
|
||||||
fs.writeFileSync(`${inDirBackend}/${lang}.json`, JSON.stringify({}));
|
fs.writeFile(`${inDirBackend}/${lang}.json`, JSON.stringify({}), {
|
||||||
}
|
flag: "wx",
|
||||||
|
})
|
||||||
|
);
|
||||||
});
|
});
|
||||||
return Promise.resolve();
|
await Promise.allSettled(writings);
|
||||||
});
|
});
|
||||||
tasks.push(taskName);
|
|
||||||
|
|
||||||
taskName = "move-downloaded-translations";
|
|
||||||
gulp.task(taskName, function () {
|
|
||||||
return gulp.src(`${downloadDir}/*.json`).pipe(gulp.dest(inDirFrontend));
|
|
||||||
});
|
|
||||||
tasks.push(taskName);
|
|
||||||
|
|
||||||
taskName = "check-downloaded-translations";
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
taskName,
|
"check-downloaded-translations",
|
||||||
gulp.series(
|
gulp.series("check-translations-html", "check-all-files-exist")
|
||||||
"check-translations-html",
|
|
||||||
"move-downloaded-translations",
|
|
||||||
"check-all-files-exist",
|
|
||||||
"clean-downloaded-translations"
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
tasks.push(taskName);
|
|
||||||
|
|
||||||
module.exports = tasks;
|
|
||||||
|
@@ -1,6 +1,4 @@
|
|||||||
// Tasks to generate entry HTML
|
// Tasks to generate entry HTML
|
||||||
/* eslint-disable import/no-dynamic-require */
|
|
||||||
/* eslint-disable global-require */
|
|
||||||
const gulp = require("gulp");
|
const gulp = require("gulp");
|
||||||
const fs = require("fs-extra");
|
const fs = require("fs-extra");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
@@ -91,7 +89,9 @@ gulp.task("gen-pages-prod", (done) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
gulp.task("gen-index-app-dev", (done) => {
|
gulp.task("gen-index-app-dev", (done) => {
|
||||||
let latestAppJS, latestCoreJS, latestCustomPanelJS;
|
let latestAppJS;
|
||||||
|
let latestCoreJS;
|
||||||
|
let latestCustomPanelJS;
|
||||||
|
|
||||||
if (env.useWDS()) {
|
if (env.useWDS()) {
|
||||||
latestAppJS = "http://localhost:8000/src/entrypoints/app.ts";
|
latestAppJS = "http://localhost:8000/src/entrypoints/app.ts";
|
||||||
|
170
build-scripts/gulp/fetch-nightly_translations.js
Normal file
170
build-scripts/gulp/fetch-nightly_translations.js
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
// Task to download the latest Lokalise translations from the nightly workflow artifacts
|
||||||
|
|
||||||
|
const fs = require("fs/promises");
|
||||||
|
const path = require("path");
|
||||||
|
const process = require("process");
|
||||||
|
const del = require("del");
|
||||||
|
const gulp = require("gulp");
|
||||||
|
const jszip = require("jszip");
|
||||||
|
const tar = require("tar");
|
||||||
|
const { Octokit } = require("@octokit/rest");
|
||||||
|
const { createOAuthDeviceAuth } = require("@octokit/auth-oauth-device");
|
||||||
|
|
||||||
|
const MAX_AGE = 24; // hours
|
||||||
|
const OWNER = "home-assistant";
|
||||||
|
const REPO = "frontend";
|
||||||
|
const WORKFLOW_NAME = "nightly.yaml";
|
||||||
|
const ARTIFACT_NAME = "translations";
|
||||||
|
const CLIENT_ID = "Iv1.3914e28cb27834d1";
|
||||||
|
const EXTRACT_DIR = "translations";
|
||||||
|
const TOKEN_FILE = path.join(EXTRACT_DIR, "token.json");
|
||||||
|
const ARTIFACT_FILE = path.join(EXTRACT_DIR, "artifact.json");
|
||||||
|
|
||||||
|
let allowTokenSetup = false;
|
||||||
|
gulp.task("allow-setup-fetch-nightly-translations", (done) => {
|
||||||
|
allowTokenSetup = true;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task("fetch-nightly-translations", async function () {
|
||||||
|
// Skip all when environment flag is set (assumes translations are already in place)
|
||||||
|
if (process.env?.SKIP_FETCH_NIGHTLY_TRANSLATIONS) {
|
||||||
|
console.log("Skipping fetch due to environment signal");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read current translations artifact info if it exists,
|
||||||
|
// and stop if they are not old enough
|
||||||
|
let currentArtifact;
|
||||||
|
try {
|
||||||
|
currentArtifact = JSON.parse(await fs.readFile(ARTIFACT_FILE, "utf-8"));
|
||||||
|
const currentAge =
|
||||||
|
(Date.now() - Date.parse(currentArtifact.created_at)) / 3600000;
|
||||||
|
if (currentAge < MAX_AGE) {
|
||||||
|
console.log(
|
||||||
|
"Keeping current translations (only %s hours old)",
|
||||||
|
currentAge.toFixed(1)
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
currentArtifact = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// To store file writing promises
|
||||||
|
const createExtractDir = fs.mkdir(EXTRACT_DIR, { recursive: true });
|
||||||
|
const writings = [];
|
||||||
|
|
||||||
|
// Authenticate to GitHub using GitHub action token if it exists,
|
||||||
|
// otherwise look for a saved user token or generate a new one if none
|
||||||
|
let tokenAuth;
|
||||||
|
if (process.env.GITHUB_TOKEN) {
|
||||||
|
tokenAuth = { token: process.env.GITHUB_TOKEN };
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
tokenAuth = JSON.parse(await fs.readFile(TOKEN_FILE, "utf-8"));
|
||||||
|
} catch {
|
||||||
|
if (!allowTokenSetup) {
|
||||||
|
console.log("No token found so build wil continue with English only");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auth = createOAuthDeviceAuth({
|
||||||
|
clientType: "github-app",
|
||||||
|
clientId: CLIENT_ID,
|
||||||
|
onVerification: (verification) => {
|
||||||
|
console.log(
|
||||||
|
"Task needs to authenticate to GitHub to fetch the translations from nightly workflow\n" +
|
||||||
|
"Please go to %s to authorize this task\n" +
|
||||||
|
"\nEnter user code: %s\n\n" +
|
||||||
|
"This code will expire in %s minutes\n" +
|
||||||
|
"Task will automatically continue after authorization and token will be saved for future use",
|
||||||
|
verification.verification_uri,
|
||||||
|
verification.user_code,
|
||||||
|
(verification.expires_in / 60).toFixed(0)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
tokenAuth = await auth({ type: "oauth" });
|
||||||
|
writings.push(
|
||||||
|
createExtractDir.then(
|
||||||
|
fs.writeFile(TOKEN_FILE, JSON.stringify(tokenAuth, null, 2))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authenticate with token and request workflow runs from GitHub
|
||||||
|
console.log("Fetching new translations...");
|
||||||
|
const octokit = new Octokit({
|
||||||
|
userAgent: "Fetch Nightly Translations",
|
||||||
|
auth: tokenAuth.token,
|
||||||
|
});
|
||||||
|
|
||||||
|
const workflowRunsResponse = await octokit.rest.actions.listWorkflowRuns({
|
||||||
|
owner: OWNER,
|
||||||
|
repo: REPO,
|
||||||
|
workflow_id: WORKFLOW_NAME,
|
||||||
|
status: "success",
|
||||||
|
event: "schedule",
|
||||||
|
per_page: 1,
|
||||||
|
exclude_pull_requests: true,
|
||||||
|
});
|
||||||
|
if (workflowRunsResponse.data.total_count === 0) {
|
||||||
|
throw Error("No successful nightly workflow runs found");
|
||||||
|
}
|
||||||
|
const latestNightlyRun = workflowRunsResponse.data.workflow_runs[0];
|
||||||
|
|
||||||
|
// Stop if current is already the latest, otherwise Find the translations artifact
|
||||||
|
if (currentArtifact?.workflow_run.id === latestNightlyRun.id) {
|
||||||
|
console.log("Stopping because current translations are still the latest");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const latestArtifact = (
|
||||||
|
await octokit.actions.listWorkflowRunArtifacts({
|
||||||
|
owner: OWNER,
|
||||||
|
repo: REPO,
|
||||||
|
run_id: latestNightlyRun.id,
|
||||||
|
})
|
||||||
|
).data.artifacts.find((artifact) => artifact.name === ARTIFACT_NAME);
|
||||||
|
if (!latestArtifact) {
|
||||||
|
throw Error("Latest nightly workflow run has no translations artifact");
|
||||||
|
}
|
||||||
|
writings.push(
|
||||||
|
createExtractDir.then(
|
||||||
|
fs.writeFile(ARTIFACT_FILE, JSON.stringify(latestArtifact, null, 2))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Remove the current translations
|
||||||
|
const deleteCurrent = Promise.all(writings).then(
|
||||||
|
del([`${EXTRACT_DIR}/*`, `!${ARTIFACT_FILE}`, `!${TOKEN_FILE}`])
|
||||||
|
);
|
||||||
|
|
||||||
|
// Get the download URL and follow the redirect to download (stored as ArrayBuffer)
|
||||||
|
const downloadResponse = await octokit.actions.downloadArtifact({
|
||||||
|
owner: OWNER,
|
||||||
|
repo: REPO,
|
||||||
|
artifact_id: latestArtifact.id,
|
||||||
|
archive_format: "zip",
|
||||||
|
});
|
||||||
|
if (downloadResponse.status !== 200) {
|
||||||
|
throw Error("Failure downloading translations artifact");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Artifact is a tarball, but GitHub adds it to a zip file
|
||||||
|
console.log("Unpacking downloaded translations...");
|
||||||
|
const zip = await jszip.loadAsync(downloadResponse.data);
|
||||||
|
await deleteCurrent;
|
||||||
|
const extractStream = zip.file(/.*/)[0].nodeStream().pipe(tar.extract());
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
extractStream.on("close", resolve).on("error", reject);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task(
|
||||||
|
"setup-and-fetch-nightly-translations",
|
||||||
|
gulp.series(
|
||||||
|
"allow-setup-fetch-nightly-translations",
|
||||||
|
"fetch-nightly-translations"
|
||||||
|
)
|
||||||
|
);
|
@@ -2,6 +2,9 @@
|
|||||||
const gulp = require("gulp");
|
const gulp = require("gulp");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
|
const { marked } = require("marked");
|
||||||
|
const glob = require("glob");
|
||||||
|
const yaml = require("js-yaml");
|
||||||
|
|
||||||
const env = require("../env");
|
const env = require("../env");
|
||||||
const paths = require("../paths");
|
const paths = require("../paths");
|
||||||
@@ -15,26 +18,129 @@ require("./service-worker.js");
|
|||||||
require("./entry-html.js");
|
require("./entry-html.js");
|
||||||
require("./rollup.js");
|
require("./rollup.js");
|
||||||
|
|
||||||
gulp.task("gather-gallery-demos", async function gatherDemos() {
|
gulp.task("gather-gallery-pages", async function gatherPages() {
|
||||||
const files = await fs.promises.readdir(
|
const pageDir = path.resolve(paths.gallery_dir, "src/pages");
|
||||||
path.resolve(paths.gallery_dir, "src/demos")
|
const files = glob.sync(path.resolve(pageDir, "**/*"));
|
||||||
);
|
|
||||||
|
|
||||||
let content = "export const DEMOS = {\n";
|
|
||||||
|
|
||||||
for (const file of files) {
|
|
||||||
const demoId = path.basename(file, ".ts");
|
|
||||||
const demoPath = "../src/demos/" + demoId;
|
|
||||||
content += ` "${demoId}": () => import("${demoPath}"),\n`;
|
|
||||||
}
|
|
||||||
|
|
||||||
content += "};";
|
|
||||||
|
|
||||||
const galleryBuild = path.resolve(paths.gallery_dir, "build");
|
const galleryBuild = path.resolve(paths.gallery_dir, "build");
|
||||||
|
|
||||||
fs.mkdirSync(galleryBuild, { recursive: true });
|
fs.mkdirSync(galleryBuild, { recursive: true });
|
||||||
|
|
||||||
|
let content = "export const PAGES = {\n";
|
||||||
|
|
||||||
|
const processed = new Set();
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
if (fs.lstatSync(file).isDirectory()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const pageId = file.substring(pageDir.length + 1, file.lastIndexOf("."));
|
||||||
|
|
||||||
|
if (processed.has(pageId)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
processed.add(pageId);
|
||||||
|
|
||||||
|
const [category] = pageId.split("/", 2);
|
||||||
|
|
||||||
|
const demoFile = path.resolve(pageDir, `${pageId}.ts`);
|
||||||
|
const descriptionFile = path.resolve(pageDir, `${pageId}.markdown`);
|
||||||
|
const hasDemo = fs.existsSync(demoFile);
|
||||||
|
let hasDescription = fs.existsSync(descriptionFile);
|
||||||
|
let metadata = {};
|
||||||
|
if (hasDescription) {
|
||||||
|
let descriptionContent = fs.readFileSync(descriptionFile, "utf-8");
|
||||||
|
|
||||||
|
if (descriptionContent.startsWith("---")) {
|
||||||
|
const metadataEnd = descriptionContent.indexOf("---", 3);
|
||||||
|
metadata = yaml.load(descriptionContent.substring(3, metadataEnd));
|
||||||
|
descriptionContent = descriptionContent
|
||||||
|
.substring(metadataEnd + 3)
|
||||||
|
.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If description is just metadata
|
||||||
|
if (descriptionContent === "") {
|
||||||
|
hasDescription = false;
|
||||||
|
} else {
|
||||||
|
descriptionContent = marked(descriptionContent).replace(/`/g, "\\`");
|
||||||
|
fs.mkdirSync(path.resolve(galleryBuild, category), { recursive: true });
|
||||||
|
fs.writeFileSync(
|
||||||
|
path.resolve(galleryBuild, `${pageId}-description.ts`),
|
||||||
|
`
|
||||||
|
import {html} from "lit";
|
||||||
|
export default html\`${descriptionContent}\`
|
||||||
|
`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
content += ` "${pageId}": {
|
||||||
|
metadata: ${JSON.stringify(metadata)},
|
||||||
|
${
|
||||||
|
hasDescription
|
||||||
|
? `description: () => import("./${pageId}-description").then(m => m.default),`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
${hasDemo ? `demo: () => import("../src/pages/${pageId}")` : ""}
|
||||||
|
|
||||||
|
},\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
content += "};\n";
|
||||||
|
|
||||||
|
// Generate sidebar
|
||||||
|
const sidebarPath = path.resolve(paths.gallery_dir, "sidebar.js");
|
||||||
|
// To make watch work during development
|
||||||
|
delete require.cache[sidebarPath];
|
||||||
|
const sidebar = require(sidebarPath);
|
||||||
|
|
||||||
|
const pagesToProcess = {};
|
||||||
|
for (const key of processed) {
|
||||||
|
const [category, page] = key.split("/", 2);
|
||||||
|
if (!(category in pagesToProcess)) {
|
||||||
|
pagesToProcess[category] = new Set();
|
||||||
|
}
|
||||||
|
pagesToProcess[category].add(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const group of Object.values(sidebar)) {
|
||||||
|
const toProcess = pagesToProcess[group.category];
|
||||||
|
delete pagesToProcess[group.category];
|
||||||
|
|
||||||
|
if (!toProcess) {
|
||||||
|
console.error("Unknown category", group.category);
|
||||||
|
if (!group.pages) {
|
||||||
|
group.pages = [];
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any pre-defined groups will not be sorted.
|
||||||
|
if (group.pages) {
|
||||||
|
for (const page of group.pages) {
|
||||||
|
if (!toProcess.delete(page)) {
|
||||||
|
console.error("Found unreferenced demo", page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
group.pages = [];
|
||||||
|
}
|
||||||
|
for (const page of Array.from(toProcess).sort()) {
|
||||||
|
group.pages.push(page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [category, pages] of Object.entries(pagesToProcess)) {
|
||||||
|
sidebar.push({
|
||||||
|
category,
|
||||||
|
header: category,
|
||||||
|
pages: Array.from(pages).sort(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
content += `export const SIDEBAR = ${JSON.stringify(sidebar, null, 2)};\n`;
|
||||||
|
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
path.resolve(galleryBuild, "import-demos.ts"),
|
path.resolve(galleryBuild, "import-pages.ts"),
|
||||||
content,
|
content,
|
||||||
"utf-8"
|
"utf-8"
|
||||||
);
|
);
|
||||||
@@ -52,11 +158,24 @@ gulp.task(
|
|||||||
"gen-icons-json",
|
"gen-icons-json",
|
||||||
"build-translations",
|
"build-translations",
|
||||||
"build-locale-data",
|
"build-locale-data",
|
||||||
"gather-gallery-demos"
|
"gather-gallery-pages"
|
||||||
),
|
),
|
||||||
"copy-static-gallery",
|
"copy-static-gallery",
|
||||||
"gen-index-gallery-dev",
|
"gen-index-gallery-dev",
|
||||||
env.useRollup() ? "rollup-dev-server-gallery" : "webpack-dev-server-gallery"
|
gulp.parallel(
|
||||||
|
env.useRollup()
|
||||||
|
? "rollup-dev-server-gallery"
|
||||||
|
: "webpack-dev-server-gallery",
|
||||||
|
async function watchMarkdownFiles() {
|
||||||
|
gulp.watch(
|
||||||
|
[
|
||||||
|
path.resolve(paths.gallery_dir, "src/pages/**/*.markdown"),
|
||||||
|
path.resolve(paths.gallery_dir, "sidebar.js"),
|
||||||
|
],
|
||||||
|
gulp.series("gather-gallery-pages")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -72,7 +191,7 @@ gulp.task(
|
|||||||
"gen-icons-json",
|
"gen-icons-json",
|
||||||
"build-translations",
|
"build-translations",
|
||||||
"build-locale-data",
|
"build-locale-data",
|
||||||
"gather-gallery-demos"
|
"gather-gallery-pages"
|
||||||
),
|
),
|
||||||
"copy-static-gallery",
|
"copy-static-gallery",
|
||||||
env.useRollup() ? "rollup-prod-gallery" : "webpack-prod-gallery",
|
env.useRollup() ? "rollup-prod-gallery" : "webpack-prod-gallery",
|
||||||
|
@@ -156,3 +156,12 @@ gulp.task("gen-icons-json", (done) => {
|
|||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
gulp.task("gen-dummy-icons-json", (done) => {
|
||||||
|
if (!fs.existsSync(OUTPUT_DIR)) {
|
||||||
|
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync(path.resolve(OUTPUT_DIR, "iconList.json"), "[]");
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
@@ -9,6 +9,7 @@ require("./compress.js");
|
|||||||
require("./rollup.js");
|
require("./rollup.js");
|
||||||
require("./gather-static.js");
|
require("./gather-static.js");
|
||||||
require("./translations.js");
|
require("./translations.js");
|
||||||
|
require("./gen-icons-json.js");
|
||||||
|
|
||||||
gulp.task(
|
gulp.task(
|
||||||
"develop-hassio",
|
"develop-hassio",
|
||||||
@@ -17,6 +18,7 @@ gulp.task(
|
|||||||
process.env.NODE_ENV = "development";
|
process.env.NODE_ENV = "development";
|
||||||
},
|
},
|
||||||
"clean-hassio",
|
"clean-hassio",
|
||||||
|
"gen-dummy-icons-json",
|
||||||
"gen-index-hassio-dev",
|
"gen-index-hassio-dev",
|
||||||
"build-supervisor-translations",
|
"build-supervisor-translations",
|
||||||
"copy-translations-supervisor",
|
"copy-translations-supervisor",
|
||||||
@@ -33,6 +35,7 @@ gulp.task(
|
|||||||
process.env.NODE_ENV = "production";
|
process.env.NODE_ENV = "production";
|
||||||
},
|
},
|
||||||
"clean-hassio",
|
"clean-hassio",
|
||||||
|
"gen-dummy-icons-json",
|
||||||
"build-supervisor-translations",
|
"build-supervisor-translations",
|
||||||
"copy-translations-supervisor",
|
"copy-translations-supervisor",
|
||||||
"build-locale-data",
|
"build-locale-data",
|
||||||
|
@@ -1,5 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
|
|
||||||
const del = require("del");
|
const del = require("del");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const gulp = require("gulp");
|
const gulp = require("gulp");
|
||||||
|
@@ -5,9 +5,9 @@ const rollup = require("rollup");
|
|||||||
const handler = require("serve-handler");
|
const handler = require("serve-handler");
|
||||||
const http = require("http");
|
const http = require("http");
|
||||||
const log = require("fancy-log");
|
const log = require("fancy-log");
|
||||||
|
const open = require("open");
|
||||||
const rollupConfig = require("../rollup");
|
const rollupConfig = require("../rollup");
|
||||||
const paths = require("../paths");
|
const paths = require("../paths");
|
||||||
const open = require("open");
|
|
||||||
|
|
||||||
const bothBuilds = (createConfigFunc, params) =>
|
const bothBuilds = (createConfigFunc, params) =>
|
||||||
gulp.series(
|
gulp.series(
|
||||||
@@ -30,11 +30,11 @@ const bothBuilds = (createConfigFunc, params) =>
|
|||||||
);
|
);
|
||||||
|
|
||||||
function createServer(serveOptions) {
|
function createServer(serveOptions) {
|
||||||
const server = http.createServer((request, response) => {
|
const server = http.createServer((request, response) =>
|
||||||
return handler(request, response, {
|
handler(request, response, {
|
||||||
public: serveOptions.root,
|
public: serveOptions.root,
|
||||||
});
|
})
|
||||||
});
|
);
|
||||||
|
|
||||||
server.listen(
|
server.listen(
|
||||||
serveOptions.port,
|
serveOptions.port,
|
||||||
|
@@ -1,7 +1,5 @@
|
|||||||
// Generate service worker.
|
// Generate service worker.
|
||||||
// Based on manifest, create a file with the content as service_worker.js
|
// Based on manifest, create a file with the content as service_worker.js
|
||||||
/* eslint-disable import/no-dynamic-require */
|
|
||||||
/* eslint-disable global-require */
|
|
||||||
const gulp = require("gulp");
|
const gulp = require("gulp");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const fs = require("fs-extra");
|
const fs = require("fs-extra");
|
||||||
|
@@ -1,5 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
|
|
||||||
const crypto = require("crypto");
|
const crypto = require("crypto");
|
||||||
const del = require("del");
|
const del = require("del");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
@@ -7,7 +5,7 @@ const source = require("vinyl-source-stream");
|
|||||||
const vinylBuffer = require("vinyl-buffer");
|
const vinylBuffer = require("vinyl-buffer");
|
||||||
const gulp = require("gulp");
|
const gulp = require("gulp");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const foreach = require("gulp-foreach");
|
const flatmap = require("gulp-flatmap");
|
||||||
const merge = require("gulp-merge-json");
|
const merge = require("gulp-merge-json");
|
||||||
const rename = require("gulp-rename");
|
const rename = require("gulp-rename");
|
||||||
const transform = require("gulp-json-transform");
|
const transform = require("gulp-json-transform");
|
||||||
@@ -15,6 +13,8 @@ const { mapFiles } = require("../util");
|
|||||||
const env = require("../env");
|
const env = require("../env");
|
||||||
const paths = require("../paths");
|
const paths = require("../paths");
|
||||||
|
|
||||||
|
require("./fetch-nightly_translations");
|
||||||
|
|
||||||
const inFrontendDir = "translations/frontend";
|
const inFrontendDir = "translations/frontend";
|
||||||
const inBackendDir = "translations/backend";
|
const inBackendDir = "translations/backend";
|
||||||
const workDir = "build/translations";
|
const workDir = "build/translations";
|
||||||
@@ -23,10 +23,13 @@ const coreDir = workDir + "/core";
|
|||||||
const outDir = workDir + "/output";
|
const outDir = workDir + "/output";
|
||||||
let mergeBackend = false;
|
let mergeBackend = false;
|
||||||
|
|
||||||
gulp.task("translations-enable-merge-backend", (done) => {
|
gulp.task(
|
||||||
mergeBackend = true;
|
"translations-enable-merge-backend",
|
||||||
done();
|
gulp.parallel((done) => {
|
||||||
});
|
mergeBackend = true;
|
||||||
|
done();
|
||||||
|
}, "allow-setup-fetch-nightly-translations")
|
||||||
|
);
|
||||||
|
|
||||||
// Panel translations which should be split from the core translations.
|
// Panel translations which should be split from the core translations.
|
||||||
const TRANSLATION_FRAGMENTS = Object.keys(
|
const TRANSLATION_FRAGMENTS = Object.keys(
|
||||||
@@ -170,20 +173,27 @@ gulp.task("build-master-translation", () => {
|
|||||||
.pipe(transform((data, file) => lokaliseTransform(data, data, file)))
|
.pipe(transform((data, file) => lokaliseTransform(data, data, file)))
|
||||||
.pipe(
|
.pipe(
|
||||||
merge({
|
merge({
|
||||||
fileName: "translationMaster.json",
|
fileName: "en.json",
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.pipe(gulp.dest(workDir));
|
.pipe(gulp.dest(fullDir));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task("build-merged-translations", () =>
|
gulp.task("build-merged-translations", () =>
|
||||||
gulp
|
gulp
|
||||||
.src([inFrontendDir + "/*.json", workDir + "/test.json"], {
|
.src(
|
||||||
allowEmpty: true,
|
[
|
||||||
})
|
inFrontendDir + "/*.json",
|
||||||
|
"!" + inFrontendDir + "/en.json",
|
||||||
|
workDir + "/test.json",
|
||||||
|
],
|
||||||
|
{
|
||||||
|
allowEmpty: true,
|
||||||
|
}
|
||||||
|
)
|
||||||
.pipe(transform((data, file) => lokaliseTransform(data, data, file)))
|
.pipe(transform((data, file) => lokaliseTransform(data, data, file)))
|
||||||
.pipe(
|
.pipe(
|
||||||
foreach((stream, file) => {
|
flatmap((stream, file) => {
|
||||||
// For each language generate a merged json file. It begins with the master
|
// For each language generate a merged json file. It begins with the master
|
||||||
// translation as a failsafe for untranslated strings, and merges all parent
|
// translation as a failsafe for untranslated strings, and merges all parent
|
||||||
// tags into one file for each specific subtag
|
// tags into one file for each specific subtag
|
||||||
@@ -193,7 +203,7 @@ gulp.task("build-merged-translations", () =>
|
|||||||
// than a base translation + region.
|
// than a base translation + region.
|
||||||
const tr = path.basename(file.history[0], ".json");
|
const tr = path.basename(file.history[0], ".json");
|
||||||
const subtags = tr.split("-");
|
const subtags = tr.split("-");
|
||||||
const src = [workDir + "/translationMaster.json"];
|
const src = [fullDir + "/en.json"];
|
||||||
for (let i = 1; i <= subtags.length; i++) {
|
for (let i = 1; i <= subtags.length; i++) {
|
||||||
const lang = subtags.slice(0, i).join("-");
|
const lang = subtags.slice(0, i).join("-");
|
||||||
if (lang === "test") {
|
if (lang === "test") {
|
||||||
@@ -378,7 +388,6 @@ gulp.task("build-translation-write-metadata", () =>
|
|||||||
if (value.nativeName) {
|
if (value.nativeName) {
|
||||||
newData[key] = value;
|
newData[key] = value;
|
||||||
} else {
|
} else {
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.warn(
|
console.warn(
|
||||||
`Skipping language ${key}. Native name was not translated.`
|
`Skipping language ${key}. Native name was not translated.`
|
||||||
);
|
);
|
||||||
@@ -411,8 +420,10 @@ gulp.task(
|
|||||||
gulp.task(
|
gulp.task(
|
||||||
"build-translations",
|
"build-translations",
|
||||||
gulp.series(
|
gulp.series(
|
||||||
"clean-translations",
|
gulp.parallel(
|
||||||
"ensure-translations-build-dir",
|
"fetch-nightly-translations",
|
||||||
|
gulp.series("clean-translations", "ensure-translations-build-dir")
|
||||||
|
),
|
||||||
"create-translations",
|
"create-translations",
|
||||||
"build-translation-fingerprints",
|
"build-translation-fingerprints",
|
||||||
"build-translation-write-metadata"
|
"build-translation-write-metadata"
|
||||||
@@ -422,8 +433,10 @@ gulp.task(
|
|||||||
gulp.task(
|
gulp.task(
|
||||||
"build-supervisor-translations",
|
"build-supervisor-translations",
|
||||||
gulp.series(
|
gulp.series(
|
||||||
"clean-translations",
|
gulp.parallel(
|
||||||
"ensure-translations-build-dir",
|
"fetch-nightly-translations",
|
||||||
|
gulp.series("clean-translations", "ensure-translations-build-dir")
|
||||||
|
),
|
||||||
"build-master-translation",
|
"build-master-translation",
|
||||||
"build-merged-translations",
|
"build-merged-translations",
|
||||||
"build-translation-fragment-supervisor",
|
"build-translation-fragment-supervisor",
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
// Tasks to run webpack.
|
// Tasks to run webpack.
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const gulp = require("gulp");
|
const gulp = require("gulp");
|
||||||
@@ -69,7 +68,6 @@ const doneHandler = (done) => (err, stats) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (stats.hasErrors() || stats.hasWarnings()) {
|
if (stats.hasErrors() || stats.hasWarnings()) {
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log(stats.toString("minimal"));
|
console.log(stats.toString("minimal"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
@@ -26,6 +25,7 @@ module.exports = {
|
|||||||
cast_output_es5: path.resolve(__dirname, "../cast/dist/frontend_es5"),
|
cast_output_es5: path.resolve(__dirname, "../cast/dist/frontend_es5"),
|
||||||
|
|
||||||
gallery_dir: path.resolve(__dirname, "../gallery"),
|
gallery_dir: path.resolve(__dirname, "../gallery"),
|
||||||
|
gallery_build: path.resolve(__dirname, "../gallery/build"),
|
||||||
gallery_output_root: path.resolve(__dirname, "../gallery/dist"),
|
gallery_output_root: path.resolve(__dirname, "../gallery/dist"),
|
||||||
gallery_output_latest: path.resolve(
|
gallery_output_latest: path.resolve(
|
||||||
__dirname,
|
__dirname,
|
||||||
|
@@ -1 +1,30 @@
|
|||||||
[]
|
[
|
||||||
|
{
|
||||||
|
"path": "M20,20H7A2,2 0 0,1 5,18V8.94L2.23,5.64C2.09,5.47 2,5.24 2,5A1,1 0 0,1 3,4H20A2,2 0 0,1 22,6V18A2,2 0 0,1 20,20M8.5,7A0.5,0.5 0 0,0 8,7.5V8.5A0.5,0.5 0 0,0 8.5,9H18.5A0.5,0.5 0 0,0 19,8.5V7.5A0.5,0.5 0 0,0 18.5,7H8.5M8.5,11A0.5,0.5 0 0,0 8,11.5V12.5A0.5,0.5 0 0,0 8.5,13H18.5A0.5,0.5 0 0,0 19,12.5V11.5A0.5,0.5 0 0,0 18.5,11H8.5M8.5,15A0.5,0.5 0 0,0 8,15.5V16.5A0.5,0.5 0 0,0 8.5,17H13.5A0.5,0.5 0 0,0 14,16.5V15.5A0.5,0.5 0 0,0 13.5,15H8.5Z",
|
||||||
|
"name": "android-messages"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "M4,6H2V20A2,2 0 0,0 4,22H18V20H4V6M20,2H8A2,2 0 0,0 6,4V16A2,2 0 0,0 8,18H20A2,2 0 0,0 22,16V4A2,2 0 0,0 20,2M20,12L17.5,10.5L15,12V4H20V12Z",
|
||||||
|
"name": "book-variant-multiple"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "M21,14H3V4H21M21,2H3C1.89,2 1,2.89 1,4V16A2,2 0 0,0 3,18H10L8,21V22H16V21L14,18H21A2,2 0 0,0 23,16V4C23,2.89 22.1,2 21,2Z",
|
||||||
|
"name": "desktop-mac"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "M21,14V4H3V14H21M21,2A2,2 0 0,1 23,4V16A2,2 0 0,1 21,18H14L16,21V22H8V21L10,18H3C1.89,18 1,17.1 1,16V4C1,2.89 1.89,2 3,2H21M4,5H15V10H4V5M16,5H20V7H16V5M20,8V13H16V8H20M4,11H9V13H4V11M10,11H15V13H10V11Z",
|
||||||
|
"name": "desktop-mac-dashboard"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "M22,24L16.75,19L17.38,21H4.5A2.5,2.5 0 0,1 2,18.5V3.5A2.5,2.5 0 0,1 4.5,1H19.5A2.5,2.5 0 0,1 22,3.5V24M12,6.8C9.32,6.8 7.44,7.95 7.44,7.95C8.47,7.03 10.27,6.5 10.27,6.5L10.1,6.33C8.41,6.36 6.88,7.53 6.88,7.53C5.16,11.12 5.27,14.22 5.27,14.22C6.67,16.03 8.75,15.9 8.75,15.9L9.46,15C8.21,14.73 7.42,13.62 7.42,13.62C7.42,13.62 9.3,14.9 12,14.9C14.7,14.9 16.58,13.62 16.58,13.62C16.58,13.62 15.79,14.73 14.54,15L15.25,15.9C15.25,15.9 17.33,16.03 18.73,14.22C18.73,14.22 18.84,11.12 17.12,7.53C17.12,7.53 15.59,6.36 13.9,6.33L13.73,6.5C13.73,6.5 15.53,7.03 16.56,7.95C16.56,7.95 14.68,6.8 12,6.8M9.93,10.59C10.58,10.59 11.11,11.16 11.1,11.86C11.1,12.55 10.58,13.13 9.93,13.13C9.29,13.13 8.77,12.55 8.77,11.86C8.77,11.16 9.28,10.59 9.93,10.59M14.1,10.59C14.75,10.59 15.27,11.16 15.27,11.86C15.27,12.55 14.75,13.13 14.1,13.13C13.46,13.13 12.94,12.55 12.94,11.86C12.94,11.16 13.45,10.59 14.1,10.59Z",
|
||||||
|
"name": "discord"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "M8.06,7.78C7.5,7.78 7.17,7.73 7.08,7.64L6.66,13.73C7.19,14.05 7.88,14.3 8.72,14.5C9.56,14.71 10.78,14.77 12.38,14.67C13.97,14.58 15.63,14.23 17.34,13.64L16.55,4.22C15.67,5.09 14.38,5.91 12.66,6.66C11.13,7.31 9.81,7.69 8.72,7.78H8.06M7.97,5.34C7.28,5.94 7,6.34 7.13,6.56C7.22,6.78 7.7,6.84 8.58,6.75C9.67,6.66 10.91,6.31 12.28,5.72C13.22,5.31 14.03,4.88 14.72,4.41C15.41,3.94 15.88,3.55 16.13,3.23C16.38,2.92 16.47,2.7 16.41,2.58C16.34,2.42 16.03,2.34 15.47,2.34C14.34,2.34 12.94,2.7 11.25,3.42C9.81,4.05 8.72,4.69 7.97,5.34M17.34,2.2C17.41,2.33 17.44,2.47 17.44,2.63L18.61,17C18.61,18.73 18,20.09 16.83,21.07C15.64,22.05 14.03,22.55 12,22.55C10,22.55 8.4,22.04 7.2,21C6,20 5.39,18.64 5.39,16.92L6.09,6.47C6.09,6.22 6.2,5.94 6.42,5.63C6.64,5.31 6.84,5.06 7.03,4.88L7.36,4.59C8.33,3.78 9.5,3.08 10.88,2.5C11.81,2.08 12.73,1.77 13.62,1.57C14.5,1.37 15.3,1.3 16,1.38C16.71,1.46 17.16,1.73 17.34,2.2Z",
|
||||||
|
"name": "google-home"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "M19.25,19H4.75V3H19.25M14,22H10V21H14M18,0H6A3,3 0 0,0 3,3V21A3,3 0 0,0 6,24H18A3,3 0 0,0 21,21V3A3,3 0 0,0 18,0Z",
|
||||||
|
"name": "tablet-android"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
@@ -81,13 +81,13 @@ module.exports = function (opts = {}) {
|
|||||||
opts.workerRegexp.flags
|
opts.workerRegexp.flags
|
||||||
);
|
);
|
||||||
if (!workerRegexp.test(code)) {
|
if (!workerRegexp.test(code)) {
|
||||||
return;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ms = new MagicString(code);
|
const ms = new MagicString(code);
|
||||||
// Reset the regexp
|
// Reset the regexp
|
||||||
workerRegexp.lastIndex = 0;
|
workerRegexp.lastIndex = 0;
|
||||||
while (true) {
|
for (;;) {
|
||||||
const match = workerRegexp.exec(code);
|
const match = workerRegexp.exec(code);
|
||||||
if (!match) {
|
if (!match) {
|
||||||
break;
|
break;
|
||||||
@@ -98,6 +98,7 @@ module.exports = function (opts = {}) {
|
|||||||
// Parse the optional options object
|
// Parse the optional options object
|
||||||
if (match[3] && match[3].length > 0) {
|
if (match[3] && match[3].length > 0) {
|
||||||
// FIXME: ooooof!
|
// FIXME: ooooof!
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-implied-eval
|
||||||
optionsObject = new Function(`return ${match[3].slice(1)};`)();
|
optionsObject = new Function(`return ${match[3].slice(1)};`)();
|
||||||
}
|
}
|
||||||
delete optionsObject.type;
|
delete optionsObject.type;
|
||||||
@@ -110,12 +111,14 @@ module.exports = function (opts = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find worker file and store it as a chunk with ID prefixed for our loader
|
// Find worker file and store it as a chunk with ID prefixed for our loader
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
const resolvedWorkerFile = (await this.resolve(workerFile, id)).id;
|
const resolvedWorkerFile = (await this.resolve(workerFile, id)).id;
|
||||||
let chunkRefId;
|
let chunkRefId;
|
||||||
if (resolvedWorkerFile in refIds) {
|
if (resolvedWorkerFile in refIds) {
|
||||||
chunkRefId = refIds[resolvedWorkerFile];
|
chunkRefId = refIds[resolvedWorkerFile];
|
||||||
} else {
|
} else {
|
||||||
this.addWatchFile(resolvedWorkerFile);
|
this.addWatchFile(resolvedWorkerFile);
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
const source = await getBundledWorker(
|
const source = await getBundledWorker(
|
||||||
resolvedWorkerFile,
|
resolvedWorkerFile,
|
||||||
rollupOptions
|
rollupOptions
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
|
|
||||||
const commonjs = require("@rollup/plugin-commonjs");
|
const commonjs = require("@rollup/plugin-commonjs");
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
|
|
||||||
|
@@ -1,12 +1,11 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
const webpack = require("webpack");
|
const webpack = require("webpack");
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
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 paths = require("./paths.js");
|
|
||||||
const bundle = require("./bundle.js");
|
|
||||||
const log = require("fancy-log");
|
const log = require("fancy-log");
|
||||||
const WebpackBar = require("webpackbar");
|
const WebpackBar = require("webpackbar");
|
||||||
|
const paths = require("./paths.js");
|
||||||
|
const bundle = require("./bundle.js");
|
||||||
|
|
||||||
class LogStartCompilePlugin {
|
class LogStartCompilePlugin {
|
||||||
ignoredFirst = false;
|
ignoredFirst = false;
|
||||||
@@ -30,6 +29,7 @@ const createWebpackConfig = ({
|
|||||||
isProdBuild,
|
isProdBuild,
|
||||||
latestBuild,
|
latestBuild,
|
||||||
isStatsBuild,
|
isStatsBuild,
|
||||||
|
isHassioBuild,
|
||||||
dontHash,
|
dontHash,
|
||||||
}) => {
|
}) => {
|
||||||
if (!dontHash) {
|
if (!dontHash) {
|
||||||
@@ -75,7 +75,7 @@ const createWebpackConfig = ({
|
|||||||
chunkIds: isProdBuild && !isStatsBuild ? "deterministic" : "named",
|
chunkIds: isProdBuild && !isStatsBuild ? "deterministic" : "named",
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new WebpackBar({ fancy: !isProdBuild }),
|
!isStatsBuild && new WebpackBar({ fancy: !isProdBuild }),
|
||||||
new WebpackManifestPlugin({
|
new WebpackManifestPlugin({
|
||||||
// Only include the JS of entrypoints
|
// Only include the JS of entrypoints
|
||||||
filter: (file) => file.isInitial && !file.name.endsWith(".map"),
|
filter: (file) => file.isInitial && !file.name.endsWith(".map"),
|
||||||
@@ -102,7 +102,6 @@ const createWebpackConfig = ({
|
|||||||
? path.resolve(context, resource)
|
? path.resolve(context, resource)
|
||||||
: require.resolve(resource);
|
: require.resolve(resource);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.error(
|
console.error(
|
||||||
"Error in Home Assistant ignore plugin",
|
"Error in Home Assistant ignore plugin",
|
||||||
resource,
|
resource,
|
||||||
@@ -117,7 +116,9 @@ const createWebpackConfig = ({
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
new webpack.NormalModuleReplacementPlugin(
|
new webpack.NormalModuleReplacementPlugin(
|
||||||
new RegExp(bundle.emptyPackages({ latestBuild }).join("|")),
|
new RegExp(
|
||||||
|
bundle.emptyPackages({ latestBuild, isHassioBuild }).join("|")
|
||||||
|
),
|
||||||
path.resolve(paths.polymer_dir, "src/util/empty.js")
|
path.resolve(paths.polymer_dir, "src/util/empty.js")
|
||||||
),
|
),
|
||||||
!isProdBuild && new LogStartCompilePlugin(),
|
!isProdBuild && new LogStartCompilePlugin(),
|
||||||
@@ -135,6 +136,8 @@ const createWebpackConfig = ({
|
|||||||
"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/polyfill-support$": "lit/polyfill-support.js",
|
"lit/polyfill-support$": "lit/polyfill-support.js",
|
||||||
|
"@lit-labs/virtualizer/layouts/grid":
|
||||||
|
"@lit-labs/virtualizer/layouts/grid.js",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
|
9
cast/public/_redirects
Normal file
9
cast/public/_redirects
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# These redirects are handled by Netlify
|
||||||
|
#
|
||||||
|
|
||||||
|
# Some custom cards are not prefixing the instance URL when fetching data
|
||||||
|
# and can end up fetching the data from the Cast domain instead of HA.
|
||||||
|
# This will make sure that some common ones are replaced with a placeholder.
|
||||||
|
/api/camera_proxy/* /images/google-nest-hub.png
|
||||||
|
/api/camera_proxy_stream/* /images/google-nest-hub.png
|
||||||
|
/api/media_player_proxy/* /images/google-nest-hub.png
|
@@ -213,7 +213,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Google Chrome (all platforms except iOS)</li>
|
<li>Google Chrome (all platforms except iOS)</li>
|
||||||
<li>Microsoft Edge (all platforms)</li>
|
<li>Microsoft Edge (all platforms except iOS)</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@@ -88,7 +88,7 @@ class HcCast extends LitElement {
|
|||||||
>
|
>
|
||||||
${(this.lovelaceConfig
|
${(this.lovelaceConfig
|
||||||
? this.lovelaceConfig.views
|
? this.lovelaceConfig.views
|
||||||
: [generateDefaultViewConfig([], [], [], {}, () => "")]
|
: [generateDefaultViewConfig({}, {}, {}, {}, () => "")]
|
||||||
).map(
|
).map(
|
||||||
(view, idx) => html`
|
(view, idx) => html`
|
||||||
<paper-icon-item
|
<paper-icon-item
|
||||||
|
@@ -44,7 +44,7 @@ class HcLayout extends LitElement {
|
|||||||
<div class="footer">
|
<div class="footer">
|
||||||
<a href="./faq.html">Frequently Asked Questions</a> – Found a bug?
|
<a href="./faq.html">Frequently Asked Questions</a> – Found a bug?
|
||||||
<a
|
<a
|
||||||
href="https://github.com/home-assistant/home-assistant-polymer/issues"
|
href="https://github.com/home-assistant/frontend/issues"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>Let us know!</a
|
>Let us know!</a
|
||||||
>
|
>
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property } 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";
|
||||||
import { Lovelace } from "../../../../src/panels/lovelace/types";
|
import { Lovelace } from "../../../../src/panels/lovelace/types";
|
||||||
@@ -7,6 +7,9 @@ import "../../../../src/panels/lovelace/views/hui-view";
|
|||||||
import { HomeAssistant } from "../../../../src/types";
|
import { HomeAssistant } from "../../../../src/types";
|
||||||
import "./hc-launch-screen";
|
import "./hc-launch-screen";
|
||||||
|
|
||||||
|
(window as any).loadCardHelpers = () =>
|
||||||
|
import("../../../../src/panels/lovelace/custom-card-helpers");
|
||||||
|
|
||||||
@customElement("hc-lovelace")
|
@customElement("hc-lovelace")
|
||||||
class HcLovelace extends LitElement {
|
class HcLovelace extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
@@ -17,6 +20,8 @@ class HcLovelace extends LitElement {
|
|||||||
|
|
||||||
@property() public urlPath: string | null = null;
|
@property() public urlPath: string | null = null;
|
||||||
|
|
||||||
|
@query("hui-view") private _huiView?: HTMLElement;
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
const index = this._viewIndex;
|
const index = this._viewIndex;
|
||||||
if (index === undefined) {
|
if (index === undefined) {
|
||||||
@@ -75,12 +80,12 @@ class HcLovelace extends LitElement {
|
|||||||
this.lovelaceConfig.background;
|
this.lovelaceConfig.background;
|
||||||
|
|
||||||
if (configBackground) {
|
if (configBackground) {
|
||||||
(this.shadowRoot!.querySelector(
|
this._huiView!.style.setProperty(
|
||||||
"hui-view"
|
|
||||||
) as HTMLElement)!.style.setProperty(
|
|
||||||
"--lovelace-background",
|
"--lovelace-background",
|
||||||
configBackground
|
configBackground
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
this._huiView!.style.removeProperty("--lovelace-background");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,6 +118,9 @@ class HcLovelace extends LitElement {
|
|||||||
:host > * {
|
:host > * {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
hui-view {
|
||||||
|
background: var(--lovelace-background, var(--primary-background-color));
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
import "web-animations-js/web-animations-next-lite.min";
|
|
||||||
import "../../../src/resources/ha-style";
|
import "../../../src/resources/ha-style";
|
||||||
import "../../../src/resources/roboto";
|
import "../../../src/resources/roboto";
|
||||||
import "./layout/hc-lovelace";
|
import "./layout/hc-lovelace";
|
||||||
|
@@ -508,7 +508,7 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
|||||||
origin_addresses: ["XYZ"],
|
origin_addresses: ["XYZ"],
|
||||||
status: "OK",
|
status: "OK",
|
||||||
mode: "driving",
|
mode: "driving",
|
||||||
units: "imperial",
|
units: "us_customary",
|
||||||
duration_in_traffic: "41 mins",
|
duration_in_traffic: "41 mins",
|
||||||
duration: "44 mins",
|
duration: "44 mins",
|
||||||
distance: "34.3 mi",
|
distance: "34.3 mi",
|
||||||
@@ -527,7 +527,7 @@ export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
|
|||||||
origin_addresses: ["XYZ"],
|
origin_addresses: ["XYZ"],
|
||||||
status: "OK",
|
status: "OK",
|
||||||
mode: "driving",
|
mode: "driving",
|
||||||
units: "imperial",
|
units: "us_customary",
|
||||||
duration_in_traffic: "37 mins",
|
duration_in_traffic: "37 mins",
|
||||||
duration: "37 mins",
|
duration: "37 mins",
|
||||||
distance: "30.2 mi",
|
distance: "30.2 mi",
|
||||||
|
@@ -194,7 +194,7 @@ export const demoLovelaceJimpower: DemoConfig["lovelace"] = () => ({
|
|||||||
type: "state-icon",
|
type: "state-icon",
|
||||||
tap_action: {
|
tap_action: {
|
||||||
action: "call-service",
|
action: "call-service",
|
||||||
service_data: {
|
data: {
|
||||||
entity_id: "group.downstairs_lights",
|
entity_id: "group.downstairs_lights",
|
||||||
},
|
},
|
||||||
service: "homeassistant.toggle",
|
service: "homeassistant.toggle",
|
||||||
@@ -1196,7 +1196,7 @@ export const demoLovelaceJimpower: DemoConfig["lovelace"] = () => ({
|
|||||||
left: "15%",
|
left: "15%",
|
||||||
},
|
},
|
||||||
type: "state-icon",
|
type: "state-icon",
|
||||||
entity: "binary_sensor.water_leak_sensor_158d0002338651",
|
entity: "binary_sensor.water_leak_sensor_158d00026e26dc",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prefix: "Kitchen: ",
|
prefix: "Kitchen: ",
|
||||||
@@ -1206,7 +1206,7 @@ export const demoLovelaceJimpower: DemoConfig["lovelace"] = () => ({
|
|||||||
top: "89%",
|
top: "89%",
|
||||||
left: "32%",
|
left: "32%",
|
||||||
},
|
},
|
||||||
entity: "binary_sensor.water_leak_sensor_158d0002338651",
|
entity: "binary_sensor.water_leak_sensor_158d00026e26dc",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
style: {
|
style: {
|
||||||
@@ -1215,7 +1215,7 @@ export const demoLovelaceJimpower: DemoConfig["lovelace"] = () => ({
|
|||||||
left: "60%",
|
left: "60%",
|
||||||
},
|
},
|
||||||
type: "state-icon",
|
type: "state-icon",
|
||||||
entity: "binary_sensor.water_leak_sensor_158d00026e26dc",
|
entity: "binary_sensor.water_leak_sensor_158d0002338651",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prefix: "Bathroom: ",
|
prefix: "Bathroom: ",
|
||||||
@@ -1225,7 +1225,7 @@ export const demoLovelaceJimpower: DemoConfig["lovelace"] = () => ({
|
|||||||
top: "89%",
|
top: "89%",
|
||||||
left: "77%",
|
left: "77%",
|
||||||
},
|
},
|
||||||
entity: "binary_sensor.water_leak_sensor_158d00026e26dc",
|
entity: "binary_sensor.water_leak_sensor_158d0002338651",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
type: "picture-elements",
|
type: "picture-elements",
|
||||||
|
@@ -59,7 +59,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
|
|||||||
attributes: {
|
attributes: {
|
||||||
hidden: true,
|
hidden: true,
|
||||||
radius: 50,
|
radius: 50,
|
||||||
friendly_name: "Skolan",
|
friendly_name: "School",
|
||||||
icon: "mdi:school",
|
icon: "mdi:school",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -137,7 +137,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
|
|||||||
state: "73",
|
state: "73",
|
||||||
attributes: {
|
attributes: {
|
||||||
unit_of_measurement: "%",
|
unit_of_measurement: "%",
|
||||||
friendly_name: "oskar batteri",
|
friendly_name: "Oskar battery",
|
||||||
device_class: "battery",
|
device_class: "battery",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -146,7 +146,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
|
|||||||
state: "88",
|
state: "88",
|
||||||
attributes: {
|
attributes: {
|
||||||
unit_of_measurement: "%",
|
unit_of_measurement: "%",
|
||||||
friendly_name: "bella batteri",
|
friendly_name: "Bella battery",
|
||||||
device_class: "battery",
|
device_class: "battery",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -154,7 +154,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
|
|||||||
entity_id: "binary_sensor.unifi_camera",
|
entity_id: "binary_sensor.unifi_camera",
|
||||||
state: "off",
|
state: "off",
|
||||||
attributes: {
|
attributes: {
|
||||||
friendly_name: "R\u00f6relsesensor kamera",
|
friendly_name: "Motion sensor camera",
|
||||||
icon: "mdi:walk",
|
icon: "mdi:walk",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -707,7 +707,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
cloudiness: 25,
|
cloudiness: 25,
|
||||||
friendly_name: "V\u00e4der",
|
friendly_name: "Weather",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"binary_sensor.ubiquiti_switch": {
|
"binary_sensor.ubiquiti_switch": {
|
||||||
@@ -731,7 +731,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
|
|||||||
round_trip_time_max: "0.626",
|
round_trip_time_max: "0.626",
|
||||||
round_trip_time_mdev: "",
|
round_trip_time_mdev: "",
|
||||||
round_trip_time_min: "0.358",
|
round_trip_time_min: "0.358",
|
||||||
friendly_name: "Entr\u00e9 kamera",
|
friendly_name: "Entrance camera",
|
||||||
device_class: "connectivity",
|
device_class: "connectivity",
|
||||||
icon: "mdi:cctv",
|
icon: "mdi:cctv",
|
||||||
},
|
},
|
||||||
@@ -797,7 +797,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
|
|||||||
attributes: {
|
attributes: {
|
||||||
battery_level: 34,
|
battery_level: 34,
|
||||||
on: true,
|
on: true,
|
||||||
friendly_name: "altan_motion_sensor",
|
friendly_name: "Porch motion sensor",
|
||||||
device_class: "motion",
|
device_class: "motion",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -807,7 +807,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
|
|||||||
attributes: {
|
attributes: {
|
||||||
battery_level: 88,
|
battery_level: 88,
|
||||||
on: true,
|
on: true,
|
||||||
friendly_name: "Altand\u00f6rren sensor",
|
friendly_name: "Back door sensor",
|
||||||
device_class: "opening",
|
device_class: "opening",
|
||||||
icon: "mdi:door",
|
icon: "mdi:door",
|
||||||
},
|
},
|
||||||
@@ -818,7 +818,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
|
|||||||
attributes: {
|
attributes: {
|
||||||
battery_level: 74,
|
battery_level: 74,
|
||||||
on: true,
|
on: true,
|
||||||
friendly_name: "badrumssensor",
|
friendly_name: "Bathroom motion sensor",
|
||||||
device_class: "motion",
|
device_class: "motion",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -829,7 +829,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
|
|||||||
battery_level: 47,
|
battery_level: 47,
|
||||||
on: true,
|
on: true,
|
||||||
dark: true,
|
dark: true,
|
||||||
friendly_name: "R\u00f6relsesensor k\u00e4llaren 1",
|
friendly_name: "Basement motion sensor",
|
||||||
device_class: "motion",
|
device_class: "motion",
|
||||||
icon: "mdi:walk",
|
icon: "mdi:walk",
|
||||||
},
|
},
|
||||||
@@ -841,7 +841,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
|
|||||||
battery_level: 60,
|
battery_level: 60,
|
||||||
on: true,
|
on: true,
|
||||||
dark: true,
|
dark: true,
|
||||||
friendly_name: "R\u00f6relsesensor tv\u00e4ttstugan",
|
friendly_name: "Laundy room motion sensor",
|
||||||
device_class: "motion",
|
device_class: "motion",
|
||||||
icon: "mdi:walk",
|
icon: "mdi:walk",
|
||||||
},
|
},
|
||||||
@@ -863,7 +863,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
|
|||||||
attributes: {
|
attributes: {
|
||||||
battery_level: 60,
|
battery_level: 60,
|
||||||
on: true,
|
on: true,
|
||||||
friendly_name: "R\u00f6relsesensor skafferiet",
|
friendly_name: "Pantry motion sensor",
|
||||||
device_class: "motion",
|
device_class: "motion",
|
||||||
icon: "mdi:walk",
|
icon: "mdi:walk",
|
||||||
},
|
},
|
||||||
@@ -875,7 +875,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
|
|||||||
battery_level: 60,
|
battery_level: 60,
|
||||||
on: true,
|
on: true,
|
||||||
dark: true,
|
dark: true,
|
||||||
friendly_name: "R\u00f6relsesensor k\u00e4llaren 2",
|
friendly_name: "Stair motion sensor",
|
||||||
device_class: "motion",
|
device_class: "motion",
|
||||||
icon: "mdi:walk",
|
icon: "mdi:walk",
|
||||||
},
|
},
|
||||||
@@ -887,7 +887,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
|
|||||||
battery_level: 47,
|
battery_level: 47,
|
||||||
on: true,
|
on: true,
|
||||||
dark: true,
|
dark: true,
|
||||||
friendly_name: "B\u00e4nksensor",
|
friendly_name: "Bench sensor",
|
||||||
device_class: "motion",
|
device_class: "motion",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@@ -277,7 +277,7 @@ export const demoLovelaceKernehed: DemoConfig["lovelace"] = () => ({
|
|||||||
],
|
],
|
||||||
show_header_toggle: false,
|
show_header_toggle: false,
|
||||||
type: "entities",
|
type: "entities",
|
||||||
title: "Bandbredd",
|
title: "Bandwidth",
|
||||||
},
|
},
|
||||||
// {
|
// {
|
||||||
// title: "Updater",
|
// title: "Updater",
|
||||||
|
@@ -377,7 +377,7 @@ export const demoLovelaceTeachingbirds: DemoConfig["lovelace"] = () => ({
|
|||||||
name: "AC bed",
|
name: "AC bed",
|
||||||
tap_action: {
|
tap_action: {
|
||||||
action: "call-service",
|
action: "call-service",
|
||||||
service_data: {
|
data: {
|
||||||
entity_id: "script.air_cleaner_quiet",
|
entity_id: "script.air_cleaner_quiet",
|
||||||
},
|
},
|
||||||
service: "script.turn_on",
|
service: "script.turn_on",
|
||||||
@@ -390,7 +390,7 @@ export const demoLovelaceTeachingbirds: DemoConfig["lovelace"] = () => ({
|
|||||||
name: "AC bed",
|
name: "AC bed",
|
||||||
tap_action: {
|
tap_action: {
|
||||||
action: "call-service",
|
action: "call-service",
|
||||||
service_data: {
|
data: {
|
||||||
entity_id: "script.air_cleaner_auto",
|
entity_id: "script.air_cleaner_auto",
|
||||||
},
|
},
|
||||||
service: "script.turn_on",
|
service: "script.turn_on",
|
||||||
@@ -403,7 +403,7 @@ export const demoLovelaceTeachingbirds: DemoConfig["lovelace"] = () => ({
|
|||||||
name: "AC bed",
|
name: "AC bed",
|
||||||
tap_action: {
|
tap_action: {
|
||||||
action: "call-service",
|
action: "call-service",
|
||||||
service_data: {
|
data: {
|
||||||
entity_id: "script.air_cleaner_turbo",
|
entity_id: "script.air_cleaner_turbo",
|
||||||
},
|
},
|
||||||
service: "script.turn_on",
|
service: "script.turn_on",
|
||||||
@@ -416,7 +416,7 @@ export const demoLovelaceTeachingbirds: DemoConfig["lovelace"] = () => ({
|
|||||||
name: "AC",
|
name: "AC",
|
||||||
tap_action: {
|
tap_action: {
|
||||||
action: "call-service",
|
action: "call-service",
|
||||||
service_data: {
|
data: {
|
||||||
entity_id: "script.ac_off",
|
entity_id: "script.ac_off",
|
||||||
},
|
},
|
||||||
service: "script.turn_on",
|
service: "script.turn_on",
|
||||||
@@ -429,7 +429,7 @@ export const demoLovelaceTeachingbirds: DemoConfig["lovelace"] = () => ({
|
|||||||
name: "AC",
|
name: "AC",
|
||||||
tap_action: {
|
tap_action: {
|
||||||
action: "call-service",
|
action: "call-service",
|
||||||
service_data: {
|
data: {
|
||||||
entity_id: "script.ac_on",
|
entity_id: "script.ac_on",
|
||||||
},
|
},
|
||||||
service: "script.turn_on",
|
service: "script.turn_on",
|
||||||
@@ -629,7 +629,7 @@ export const demoLovelaceTeachingbirds: DemoConfig["lovelace"] = () => ({
|
|||||||
entity: "scene.morning_lights",
|
entity: "scene.morning_lights",
|
||||||
tap_action: {
|
tap_action: {
|
||||||
action: "call-service",
|
action: "call-service",
|
||||||
service_data: {
|
data: {
|
||||||
entity_id: "scene.morning_lights",
|
entity_id: "scene.morning_lights",
|
||||||
},
|
},
|
||||||
service: "scene.turn_on",
|
service: "scene.turn_on",
|
||||||
@@ -641,7 +641,7 @@ export const demoLovelaceTeachingbirds: DemoConfig["lovelace"] = () => ({
|
|||||||
entity: "scene.movie_time",
|
entity: "scene.movie_time",
|
||||||
tap_action: {
|
tap_action: {
|
||||||
action: "call-service",
|
action: "call-service",
|
||||||
service_data: {
|
data: {
|
||||||
entity_id: "scene.movie_time",
|
entity_id: "scene.movie_time",
|
||||||
},
|
},
|
||||||
service: "scene.turn_on",
|
service: "scene.turn_on",
|
||||||
@@ -702,7 +702,7 @@ export const demoLovelaceTeachingbirds: DemoConfig["lovelace"] = () => ({
|
|||||||
entity: "light.downstairs_lights",
|
entity: "light.downstairs_lights",
|
||||||
tap_action: {
|
tap_action: {
|
||||||
action: "call-service",
|
action: "call-service",
|
||||||
service_data: {
|
data: {
|
||||||
entity_id: "light.downstairs_lights",
|
entity_id: "light.downstairs_lights",
|
||||||
},
|
},
|
||||||
service: "light.toggle",
|
service: "light.toggle",
|
||||||
@@ -714,7 +714,7 @@ export const demoLovelaceTeachingbirds: DemoConfig["lovelace"] = () => ({
|
|||||||
entity: "light.upstairs_lights",
|
entity: "light.upstairs_lights",
|
||||||
tap_action: {
|
tap_action: {
|
||||||
action: "call-service",
|
action: "call-service",
|
||||||
service_data: {
|
data: {
|
||||||
entity_id: "light.upstairs_lights",
|
entity_id: "light.upstairs_lights",
|
||||||
},
|
},
|
||||||
service: "light.toggle",
|
service: "light.toggle",
|
||||||
|
@@ -138,7 +138,7 @@ if (!window.cardTools) {
|
|||||||
return cardTools.createThing("row", config);
|
return cardTools.createThing("row", config);
|
||||||
|
|
||||||
const domain = config.entity.split(".", 1)[0];
|
const domain = config.entity.split(".", 1)[0];
|
||||||
Object.assign(config, { type: DEFAULT_ROWS[domain] || "text" });
|
Object.assign(config, { type: DEFAULT_ROWS[domain] || "simple" });
|
||||||
return cardTools.createThing("entity-row", config);
|
return cardTools.createThing("entity-row", config);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -2,8 +2,3 @@ import "../../src/resources/ha-style";
|
|||||||
import "../../src/resources/roboto";
|
import "../../src/resources/roboto";
|
||||||
import "../../src/resources/safari-14-attachshadow-patch";
|
import "../../src/resources/safari-14-attachshadow-patch";
|
||||||
import "./ha-demo";
|
import "./ha-demo";
|
||||||
|
|
||||||
/* polyfill for paper-dropdown */
|
|
||||||
setTimeout(() => {
|
|
||||||
import("web-animations-js/web-animations-next-lite.min");
|
|
||||||
}, 1000);
|
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
// Compat needs to be first import
|
// Compat needs to be first import
|
||||||
import "../../src/resources/compatibility";
|
|
||||||
import { isNavigationClick } from "../../src/common/dom/is-navigation-click";
|
import { isNavigationClick } from "../../src/common/dom/is-navigation-click";
|
||||||
import { navigate } from "../../src/common/navigate";
|
import { navigate } from "../../src/common/navigate";
|
||||||
import {
|
import {
|
||||||
@@ -7,22 +6,25 @@ import {
|
|||||||
provideHass,
|
provideHass,
|
||||||
} from "../../src/fake_data/provide_hass";
|
} from "../../src/fake_data/provide_hass";
|
||||||
import { HomeAssistantAppEl } from "../../src/layouts/home-assistant";
|
import { HomeAssistantAppEl } from "../../src/layouts/home-assistant";
|
||||||
|
import "../../src/resources/compatibility";
|
||||||
import { HomeAssistant } from "../../src/types";
|
import { HomeAssistant } from "../../src/types";
|
||||||
import { selectedDemoConfig } from "./configs/demo-configs";
|
import { selectedDemoConfig } from "./configs/demo-configs";
|
||||||
import { mockAuth } from "./stubs/auth";
|
import { mockAuth } from "./stubs/auth";
|
||||||
|
import { mockConfigEntries } from "./stubs/config_entries";
|
||||||
|
import { mockEnergy } from "./stubs/energy";
|
||||||
|
import { energyEntities } from "./stubs/entities";
|
||||||
|
import { mockEntityRegistry } from "./stubs/entity_registry";
|
||||||
import { mockEvents } from "./stubs/events";
|
import { mockEvents } from "./stubs/events";
|
||||||
import { mockFrontend } from "./stubs/frontend";
|
import { mockFrontend } from "./stubs/frontend";
|
||||||
import { mockHistory } from "./stubs/history";
|
import { mockHistory } from "./stubs/history";
|
||||||
import { mockLovelace } from "./stubs/lovelace";
|
import { mockLovelace } from "./stubs/lovelace";
|
||||||
import { mockMediaPlayer } from "./stubs/media_player";
|
import { mockMediaPlayer } from "./stubs/media_player";
|
||||||
import { mockPersistentNotification } from "./stubs/persistent_notification";
|
import { mockPersistentNotification } from "./stubs/persistent_notification";
|
||||||
|
import { mockRecorder } from "./stubs/recorder";
|
||||||
import { mockShoppingList } from "./stubs/shopping_list";
|
import { mockShoppingList } from "./stubs/shopping_list";
|
||||||
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";
|
||||||
import { mockEnergy } from "./stubs/energy";
|
|
||||||
import { mockConfig } from "./stubs/config";
|
|
||||||
import { energyEntities } from "./stubs/entities";
|
|
||||||
|
|
||||||
class HaDemo extends HomeAssistantAppEl {
|
class HaDemo extends HomeAssistantAppEl {
|
||||||
protected async _initializeHass() {
|
protected async _initializeHass() {
|
||||||
@@ -44,6 +46,7 @@ class HaDemo extends HomeAssistantAppEl {
|
|||||||
mockAuth(hass);
|
mockAuth(hass);
|
||||||
mockTranslations(hass);
|
mockTranslations(hass);
|
||||||
mockHistory(hass);
|
mockHistory(hass);
|
||||||
|
mockRecorder(hass);
|
||||||
mockShoppingList(hass);
|
mockShoppingList(hass);
|
||||||
mockSystemLog(hass);
|
mockSystemLog(hass);
|
||||||
mockTemplate(hass);
|
mockTemplate(hass);
|
||||||
@@ -51,8 +54,40 @@ class HaDemo extends HomeAssistantAppEl {
|
|||||||
mockMediaPlayer(hass);
|
mockMediaPlayer(hass);
|
||||||
mockFrontend(hass);
|
mockFrontend(hass);
|
||||||
mockEnergy(hass);
|
mockEnergy(hass);
|
||||||
mockConfig(hass);
|
|
||||||
mockPersistentNotification(hass);
|
mockPersistentNotification(hass);
|
||||||
|
mockConfigEntries(hass);
|
||||||
|
mockEntityRegistry(hass, [
|
||||||
|
{
|
||||||
|
config_entry_id: "co2signal",
|
||||||
|
device_id: "co2signal",
|
||||||
|
area_id: null,
|
||||||
|
disabled_by: null,
|
||||||
|
entity_id: "sensor.co2_intensity",
|
||||||
|
id: "sensor.co2_intensity",
|
||||||
|
name: null,
|
||||||
|
icon: null,
|
||||||
|
platform: "co2signal",
|
||||||
|
hidden_by: null,
|
||||||
|
entity_category: null,
|
||||||
|
has_entity_name: false,
|
||||||
|
unique_id: "co2_intensity",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
config_entry_id: "co2signal",
|
||||||
|
device_id: "co2signal",
|
||||||
|
area_id: null,
|
||||||
|
disabled_by: null,
|
||||||
|
entity_id: "sensor.grid_fossil_fuel_percentage",
|
||||||
|
id: "sensor.co2_intensity",
|
||||||
|
name: null,
|
||||||
|
icon: null,
|
||||||
|
platform: "co2signal",
|
||||||
|
hidden_by: null,
|
||||||
|
entity_category: null,
|
||||||
|
has_entity_name: false,
|
||||||
|
unique_id: "grid_fossil_fuel_percentage",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
hass.addEntities(energyEntities());
|
hass.addEntities(energyEntities());
|
||||||
|
|
||||||
@@ -87,3 +122,9 @@ class HaDemo extends HomeAssistantAppEl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("ha-demo", HaDemo);
|
customElements.define("ha-demo", HaDemo);
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-demo": HaDemo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -1,41 +0,0 @@
|
|||||||
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
|
||||||
|
|
||||||
export const mockConfig = (hass: MockHomeAssistant) => {
|
|
||||||
hass.mockAPI("config/config_entries/entry", () => [
|
|
||||||
{
|
|
||||||
entry_id: "co2signal",
|
|
||||||
domain: "co2signal",
|
|
||||||
title: "CO2 Signal",
|
|
||||||
source: "user",
|
|
||||||
state: "loaded",
|
|
||||||
supports_options: false,
|
|
||||||
supports_unload: true,
|
|
||||||
pref_disable_new_entities: false,
|
|
||||||
pref_disable_polling: false,
|
|
||||||
disabled_by: null,
|
|
||||||
reason: null,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
hass.mockWS("config/entity_registry/list", () => [
|
|
||||||
{
|
|
||||||
config_entry_id: "co2signal",
|
|
||||||
device_id: "co2signal",
|
|
||||||
area_id: null,
|
|
||||||
disabled_by: null,
|
|
||||||
entity_id: "sensor.co2_intensity",
|
|
||||||
name: null,
|
|
||||||
icon: null,
|
|
||||||
platform: "co2signal",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
config_entry_id: "co2signal",
|
|
||||||
device_id: "co2signal",
|
|
||||||
area_id: null,
|
|
||||||
disabled_by: null,
|
|
||||||
entity_id: "sensor.grid_fossil_fuel_percentage",
|
|
||||||
name: null,
|
|
||||||
icon: null,
|
|
||||||
platform: "co2signal",
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
};
|
|
20
demo/src/stubs/config_entries.ts
Normal file
20
demo/src/stubs/config_entries.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||||
|
|
||||||
|
export const mockConfigEntries = (hass: MockHomeAssistant) => {
|
||||||
|
hass.mockWS("config_entries/get", () => [
|
||||||
|
{
|
||||||
|
entry_id: "co2signal",
|
||||||
|
domain: "co2signal",
|
||||||
|
title: "CO2 Signal",
|
||||||
|
source: "user",
|
||||||
|
state: "loaded",
|
||||||
|
supports_options: false,
|
||||||
|
supports_remove_device: false,
|
||||||
|
supports_unload: true,
|
||||||
|
pref_disable_new_entities: false,
|
||||||
|
pref_disable_polling: false,
|
||||||
|
disabled_by: null,
|
||||||
|
reason: null,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
};
|
@@ -1,90 +1,101 @@
|
|||||||
import { format, startOfToday, startOfTomorrow } from "date-fns";
|
import { format, startOfToday, startOfTomorrow } from "date-fns/esm";
|
||||||
import { EnergySolarForecasts } from "../../../src/data/energy";
|
import {
|
||||||
|
EnergyInfo,
|
||||||
|
EnergyPreferences,
|
||||||
|
EnergySolarForecasts,
|
||||||
|
FossilEnergyConsumption,
|
||||||
|
} from "../../../src/data/energy";
|
||||||
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||||
|
|
||||||
export const mockEnergy = (hass: MockHomeAssistant) => {
|
export const mockEnergy = (hass: MockHomeAssistant) => {
|
||||||
hass.mockWS("energy/get_prefs", () => ({
|
hass.mockWS(
|
||||||
energy_sources: [
|
"energy/get_prefs",
|
||||||
{
|
(): EnergyPreferences => ({
|
||||||
type: "grid",
|
energy_sources: [
|
||||||
flow_from: [
|
{
|
||||||
{
|
type: "grid",
|
||||||
stat_energy_from: "sensor.energy_consumption_tarif_1",
|
flow_from: [
|
||||||
stat_cost: "sensor.energy_consumption_tarif_1_cost",
|
{
|
||||||
entity_energy_from: "sensor.energy_consumption_tarif_1",
|
stat_energy_from: "sensor.energy_consumption_tarif_1",
|
||||||
entity_energy_price: null,
|
stat_cost: "sensor.energy_consumption_tarif_1_cost",
|
||||||
number_energy_price: null,
|
entity_energy_price: null,
|
||||||
},
|
number_energy_price: null,
|
||||||
{
|
},
|
||||||
stat_energy_from: "sensor.energy_consumption_tarif_2",
|
{
|
||||||
stat_cost: "sensor.energy_consumption_tarif_2_cost",
|
stat_energy_from: "sensor.energy_consumption_tarif_2",
|
||||||
entity_energy_from: "sensor.energy_consumption_tarif_2",
|
stat_cost: "sensor.energy_consumption_tarif_2_cost",
|
||||||
entity_energy_price: null,
|
entity_energy_price: null,
|
||||||
number_energy_price: null,
|
number_energy_price: null,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
flow_to: [
|
flow_to: [
|
||||||
{
|
{
|
||||||
stat_energy_to: "sensor.energy_production_tarif_1",
|
stat_energy_to: "sensor.energy_production_tarif_1",
|
||||||
stat_compensation: "sensor.energy_production_tarif_1_compensation",
|
stat_compensation:
|
||||||
entity_energy_to: "sensor.energy_production_tarif_1",
|
"sensor.energy_production_tarif_1_compensation",
|
||||||
entity_energy_price: null,
|
entity_energy_price: null,
|
||||||
number_energy_price: null,
|
number_energy_price: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
stat_energy_to: "sensor.energy_production_tarif_2",
|
stat_energy_to: "sensor.energy_production_tarif_2",
|
||||||
stat_compensation: "sensor.energy_production_tarif_2_compensation",
|
stat_compensation:
|
||||||
entity_energy_to: "sensor.energy_production_tarif_2",
|
"sensor.energy_production_tarif_2_compensation",
|
||||||
entity_energy_price: null,
|
entity_energy_price: null,
|
||||||
number_energy_price: null,
|
number_energy_price: null,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
cost_adjustment_day: 0,
|
cost_adjustment_day: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "solar",
|
type: "solar",
|
||||||
stat_energy_from: "sensor.solar_production",
|
stat_energy_from: "sensor.solar_production",
|
||||||
config_entry_solar_forecast: ["solar_forecast"],
|
config_entry_solar_forecast: ["solar_forecast"],
|
||||||
},
|
},
|
||||||
/* {
|
/* {
|
||||||
type: "battery",
|
type: "battery",
|
||||||
stat_energy_from: "sensor.battery_output",
|
stat_energy_from: "sensor.battery_output",
|
||||||
stat_energy_to: "sensor.battery_input",
|
stat_energy_to: "sensor.battery_input",
|
||||||
}, */
|
}, */
|
||||||
{
|
{
|
||||||
type: "gas",
|
type: "gas",
|
||||||
stat_energy_from: "sensor.energy_gas",
|
stat_energy_from: "sensor.energy_gas",
|
||||||
stat_cost: "sensor.energy_gas_cost",
|
stat_cost: "sensor.energy_gas_cost",
|
||||||
entity_energy_from: "sensor.energy_gas",
|
entity_energy_price: null,
|
||||||
entity_energy_price: null,
|
number_energy_price: null,
|
||||||
number_energy_price: null,
|
},
|
||||||
},
|
],
|
||||||
],
|
device_consumption: [
|
||||||
device_consumption: [
|
{
|
||||||
{
|
stat_consumption: "sensor.energy_car",
|
||||||
stat_consumption: "sensor.energy_car",
|
},
|
||||||
},
|
{
|
||||||
{
|
stat_consumption: "sensor.energy_ac",
|
||||||
stat_consumption: "sensor.energy_ac",
|
},
|
||||||
},
|
{
|
||||||
{
|
stat_consumption: "sensor.energy_washing_machine",
|
||||||
stat_consumption: "sensor.energy_washing_machine",
|
},
|
||||||
},
|
{
|
||||||
{
|
stat_consumption: "sensor.energy_dryer",
|
||||||
stat_consumption: "sensor.energy_dryer",
|
},
|
||||||
},
|
{
|
||||||
{
|
stat_consumption: "sensor.energy_heat_pump",
|
||||||
stat_consumption: "sensor.energy_heat_pump",
|
},
|
||||||
},
|
{
|
||||||
{
|
stat_consumption: "sensor.energy_boiler",
|
||||||
stat_consumption: "sensor.energy_boiler",
|
},
|
||||||
},
|
],
|
||||||
],
|
})
|
||||||
}));
|
);
|
||||||
hass.mockWS("energy/info", () => ({ cost_sensors: [] }));
|
hass.mockWS(
|
||||||
hass.mockWS("energy/fossil_energy_consumption", ({ period }) => ({
|
"energy/info",
|
||||||
start: period === "month" ? 500 : period === "day" ? 20 : 5,
|
(): EnergyInfo => ({ cost_sensors: {}, solar_forecast_domains: [] })
|
||||||
}));
|
);
|
||||||
|
hass.mockWS(
|
||||||
|
"energy/fossil_energy_consumption",
|
||||||
|
({ period }): FossilEnergyConsumption => ({
|
||||||
|
start: period === "month" ? 250 : period === "day" ? 10 : 2,
|
||||||
|
})
|
||||||
|
);
|
||||||
const todayString = format(startOfToday(), "yyyy-MM-dd");
|
const todayString = format(startOfToday(), "yyyy-MM-dd");
|
||||||
const tomorrowString = format(startOfTomorrow(), "yyyy-MM-dd");
|
const tomorrowString = format(startOfTomorrow(), "yyyy-MM-dd");
|
||||||
hass.mockWS(
|
hass.mockWS(
|
||||||
|
@@ -4,4 +4,6 @@ import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
|||||||
export const mockEntityRegistry = (
|
export const mockEntityRegistry = (
|
||||||
hass: MockHomeAssistant,
|
hass: MockHomeAssistant,
|
||||||
data: EntityRegistryEntry[] = []
|
data: EntityRegistryEntry[] = []
|
||||||
) => hass.mockWS("config/entity_registry/list", () => data);
|
) => {
|
||||||
|
hass.mockWS("config/entity_registry/list", () => data);
|
||||||
|
};
|
||||||
|
@@ -31,7 +31,7 @@ export const mockHassioSupervisor = (hass: MockHomeAssistant) => {
|
|||||||
version_latest: "3.6.2",
|
version_latest: "3.6.2",
|
||||||
update_available: false,
|
update_available: false,
|
||||||
repository: "a0d7b954",
|
repository: "a0d7b954",
|
||||||
icon: true,
|
icon: false,
|
||||||
logo: true,
|
logo: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@@ -1,12 +1,4 @@
|
|||||||
import {
|
|
||||||
addDays,
|
|
||||||
addHours,
|
|
||||||
addMonths,
|
|
||||||
differenceInHours,
|
|
||||||
endOfDay,
|
|
||||||
} from "date-fns";
|
|
||||||
import { HassEntity } from "home-assistant-js-websocket";
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
import { StatisticValue } from "../../../src/data/history";
|
|
||||||
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||||
|
|
||||||
interface HistoryQueryParams {
|
interface HistoryQueryParams {
|
||||||
@@ -72,331 +64,6 @@ const generateHistory = (state, deltas) => {
|
|||||||
|
|
||||||
const incrementalUnits = ["clients", "queries", "ads"];
|
const incrementalUnits = ["clients", "queries", "ads"];
|
||||||
|
|
||||||
const generateMeanStatistics = (
|
|
||||||
id: string,
|
|
||||||
start: Date,
|
|
||||||
end: Date,
|
|
||||||
period: "5minute" | "hour" | "day" | "month" = "hour",
|
|
||||||
initValue: number,
|
|
||||||
maxDiff: number
|
|
||||||
) => {
|
|
||||||
const statistics: StatisticValue[] = [];
|
|
||||||
let currentDate = new Date(start);
|
|
||||||
currentDate.setMinutes(0, 0, 0);
|
|
||||||
let lastVal = initValue;
|
|
||||||
const now = new Date();
|
|
||||||
while (end > currentDate && currentDate < now) {
|
|
||||||
const delta = Math.random() * maxDiff;
|
|
||||||
const mean = lastVal + delta;
|
|
||||||
statistics.push({
|
|
||||||
statistic_id: id,
|
|
||||||
start: currentDate.toISOString(),
|
|
||||||
end: currentDate.toISOString(),
|
|
||||||
mean,
|
|
||||||
min: mean - Math.random() * maxDiff,
|
|
||||||
max: mean + Math.random() * maxDiff,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: mean,
|
|
||||||
sum: null,
|
|
||||||
});
|
|
||||||
lastVal = mean;
|
|
||||||
currentDate =
|
|
||||||
period === "day"
|
|
||||||
? addDays(currentDate, 1)
|
|
||||||
: period === "month"
|
|
||||||
? addMonths(currentDate, 1)
|
|
||||||
: addHours(currentDate, 1);
|
|
||||||
}
|
|
||||||
return statistics;
|
|
||||||
};
|
|
||||||
|
|
||||||
const generateSumStatistics = (
|
|
||||||
id: string,
|
|
||||||
start: Date,
|
|
||||||
end: Date,
|
|
||||||
period: "5minute" | "hour" | "day" | "month" = "hour",
|
|
||||||
initValue: number,
|
|
||||||
maxDiff: number
|
|
||||||
) => {
|
|
||||||
const statistics: StatisticValue[] = [];
|
|
||||||
let currentDate = new Date(start);
|
|
||||||
currentDate.setMinutes(0, 0, 0);
|
|
||||||
let sum = initValue;
|
|
||||||
const now = new Date();
|
|
||||||
while (end > currentDate && currentDate < now) {
|
|
||||||
const add = Math.random() * maxDiff;
|
|
||||||
sum += add;
|
|
||||||
statistics.push({
|
|
||||||
statistic_id: id,
|
|
||||||
start: currentDate.toISOString(),
|
|
||||||
end: currentDate.toISOString(),
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
max: null,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: initValue + sum,
|
|
||||||
sum,
|
|
||||||
});
|
|
||||||
currentDate =
|
|
||||||
period === "day"
|
|
||||||
? addDays(currentDate, 1)
|
|
||||||
: period === "month"
|
|
||||||
? addMonths(currentDate, 1)
|
|
||||||
: addHours(currentDate, 1);
|
|
||||||
}
|
|
||||||
return statistics;
|
|
||||||
};
|
|
||||||
|
|
||||||
const generateCurvedStatistics = (
|
|
||||||
id: string,
|
|
||||||
start: Date,
|
|
||||||
end: Date,
|
|
||||||
_period: "5minute" | "hour" | "day" | "month" = "hour",
|
|
||||||
initValue: number,
|
|
||||||
maxDiff: number,
|
|
||||||
metered: boolean
|
|
||||||
) => {
|
|
||||||
const statistics: StatisticValue[] = [];
|
|
||||||
let currentDate = new Date(start);
|
|
||||||
currentDate.setMinutes(0, 0, 0);
|
|
||||||
let sum = initValue;
|
|
||||||
const hours = differenceInHours(end, start) - 1;
|
|
||||||
let i = 0;
|
|
||||||
let half = false;
|
|
||||||
const now = new Date();
|
|
||||||
while (end > currentDate && currentDate < now) {
|
|
||||||
const add = Math.random() * maxDiff;
|
|
||||||
sum += i * add;
|
|
||||||
statistics.push({
|
|
||||||
statistic_id: id,
|
|
||||||
start: currentDate.toISOString(),
|
|
||||||
end: currentDate.toISOString(),
|
|
||||||
mean: null,
|
|
||||||
min: null,
|
|
||||||
max: null,
|
|
||||||
last_reset: "1970-01-01T00:00:00+00:00",
|
|
||||||
state: initValue + sum,
|
|
||||||
sum: metered ? sum : null,
|
|
||||||
});
|
|
||||||
currentDate = addHours(currentDate, 1);
|
|
||||||
if (!half && i > hours / 2) {
|
|
||||||
half = true;
|
|
||||||
}
|
|
||||||
i += half ? -1 : 1;
|
|
||||||
}
|
|
||||||
return statistics;
|
|
||||||
};
|
|
||||||
|
|
||||||
const statisticsFunctions: Record<
|
|
||||||
string,
|
|
||||||
(
|
|
||||||
id: string,
|
|
||||||
start: Date,
|
|
||||||
end: Date,
|
|
||||||
period: "5minute" | "hour" | "day" | "month"
|
|
||||||
) => StatisticValue[]
|
|
||||||
> = {
|
|
||||||
"sensor.energy_consumption_tarif_1": (
|
|
||||||
id: string,
|
|
||||||
start: Date,
|
|
||||||
end: Date,
|
|
||||||
period = "hour"
|
|
||||||
) => {
|
|
||||||
if (period !== "hour") {
|
|
||||||
return generateSumStatistics(
|
|
||||||
id,
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
period,
|
|
||||||
0,
|
|
||||||
period === "day" ? 17 : 504
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const morningEnd = new Date(start.getTime() + 10 * 60 * 60 * 1000);
|
|
||||||
const morningLow = generateSumStatistics(
|
|
||||||
id,
|
|
||||||
start,
|
|
||||||
morningEnd,
|
|
||||||
period,
|
|
||||||
0,
|
|
||||||
0.7
|
|
||||||
);
|
|
||||||
const eveningStart = new Date(start.getTime() + 20 * 60 * 60 * 1000);
|
|
||||||
const morningFinalVal = morningLow.length
|
|
||||||
? morningLow[morningLow.length - 1].sum!
|
|
||||||
: 0;
|
|
||||||
const empty = generateSumStatistics(
|
|
||||||
id,
|
|
||||||
morningEnd,
|
|
||||||
eveningStart,
|
|
||||||
period,
|
|
||||||
morningFinalVal,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
const eveningLow = generateSumStatistics(
|
|
||||||
id,
|
|
||||||
eveningStart,
|
|
||||||
end,
|
|
||||||
period,
|
|
||||||
morningFinalVal,
|
|
||||||
0.7
|
|
||||||
);
|
|
||||||
return [...morningLow, ...empty, ...eveningLow];
|
|
||||||
},
|
|
||||||
"sensor.energy_consumption_tarif_2": (
|
|
||||||
id: string,
|
|
||||||
start: Date,
|
|
||||||
end: Date,
|
|
||||||
period = "hour"
|
|
||||||
) => {
|
|
||||||
if (period !== "hour") {
|
|
||||||
return generateSumStatistics(
|
|
||||||
id,
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
period,
|
|
||||||
0,
|
|
||||||
period === "day" ? 17 : 504
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const morningEnd = new Date(start.getTime() + 9 * 60 * 60 * 1000);
|
|
||||||
const eveningStart = new Date(start.getTime() + 20 * 60 * 60 * 1000);
|
|
||||||
const highTarif = generateSumStatistics(
|
|
||||||
id,
|
|
||||||
morningEnd,
|
|
||||||
eveningStart,
|
|
||||||
period,
|
|
||||||
0,
|
|
||||||
0.3
|
|
||||||
);
|
|
||||||
const highTarifFinalVal = highTarif.length
|
|
||||||
? highTarif[highTarif.length - 1].sum!
|
|
||||||
: 0;
|
|
||||||
const morning = generateSumStatistics(id, start, morningEnd, period, 0, 0);
|
|
||||||
const evening = generateSumStatistics(
|
|
||||||
id,
|
|
||||||
eveningStart,
|
|
||||||
end,
|
|
||||||
period,
|
|
||||||
highTarifFinalVal,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
return [...morning, ...highTarif, ...evening];
|
|
||||||
},
|
|
||||||
"sensor.energy_production_tarif_1": (id, start, end, period = "hour") =>
|
|
||||||
generateSumStatistics(id, start, end, period, 0, 0),
|
|
||||||
"sensor.energy_production_tarif_1_compensation": (
|
|
||||||
id,
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
period = "hour"
|
|
||||||
) => generateSumStatistics(id, start, end, period, 0, 0),
|
|
||||||
"sensor.energy_production_tarif_2": (id, start, end, period = "hour") => {
|
|
||||||
if (period !== "hour") {
|
|
||||||
return generateSumStatistics(
|
|
||||||
id,
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
period,
|
|
||||||
0,
|
|
||||||
period === "day" ? 17 : 504
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const productionStart = new Date(start.getTime() + 9 * 60 * 60 * 1000);
|
|
||||||
const productionEnd = new Date(start.getTime() + 21 * 60 * 60 * 1000);
|
|
||||||
const dayEnd = new Date(endOfDay(productionEnd));
|
|
||||||
const production = generateCurvedStatistics(
|
|
||||||
id,
|
|
||||||
productionStart,
|
|
||||||
productionEnd,
|
|
||||||
period,
|
|
||||||
0,
|
|
||||||
0.15,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
const productionFinalVal = production.length
|
|
||||||
? production[production.length - 1].sum!
|
|
||||||
: 0;
|
|
||||||
const morning = generateSumStatistics(
|
|
||||||
id,
|
|
||||||
start,
|
|
||||||
productionStart,
|
|
||||||
period,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
const evening = generateSumStatistics(
|
|
||||||
id,
|
|
||||||
productionEnd,
|
|
||||||
dayEnd,
|
|
||||||
period,
|
|
||||||
productionFinalVal,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
const rest = generateSumStatistics(
|
|
||||||
id,
|
|
||||||
dayEnd,
|
|
||||||
end,
|
|
||||||
period,
|
|
||||||
productionFinalVal,
|
|
||||||
1
|
|
||||||
);
|
|
||||||
return [...morning, ...production, ...evening, ...rest];
|
|
||||||
},
|
|
||||||
"sensor.solar_production": (id, start, end, period = "hour") => {
|
|
||||||
if (period !== "hour") {
|
|
||||||
return generateSumStatistics(
|
|
||||||
id,
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
period,
|
|
||||||
0,
|
|
||||||
period === "day" ? 17 : 504
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const productionStart = new Date(start.getTime() + 7 * 60 * 60 * 1000);
|
|
||||||
const productionEnd = new Date(start.getTime() + 23 * 60 * 60 * 1000);
|
|
||||||
const dayEnd = new Date(endOfDay(productionEnd));
|
|
||||||
const production = generateCurvedStatistics(
|
|
||||||
id,
|
|
||||||
productionStart,
|
|
||||||
productionEnd,
|
|
||||||
period,
|
|
||||||
0,
|
|
||||||
0.3,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
const productionFinalVal = production.length
|
|
||||||
? production[production.length - 1].sum!
|
|
||||||
: 0;
|
|
||||||
const morning = generateSumStatistics(
|
|
||||||
id,
|
|
||||||
start,
|
|
||||||
productionStart,
|
|
||||||
period,
|
|
||||||
0,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
const evening = generateSumStatistics(
|
|
||||||
id,
|
|
||||||
productionEnd,
|
|
||||||
dayEnd,
|
|
||||||
period,
|
|
||||||
productionFinalVal,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
const rest = generateSumStatistics(
|
|
||||||
id,
|
|
||||||
dayEnd,
|
|
||||||
end,
|
|
||||||
period,
|
|
||||||
productionFinalVal,
|
|
||||||
2
|
|
||||||
);
|
|
||||||
return [...morning, ...production, ...evening, ...rest];
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const mockHistory = (mockHass: MockHomeAssistant) => {
|
export const mockHistory = (mockHass: MockHomeAssistant) => {
|
||||||
mockHass.mockAPI(
|
mockHass.mockAPI(
|
||||||
new RegExp("history/period/.+"),
|
new RegExp("history/period/.+"),
|
||||||
@@ -466,42 +133,4 @@ export const mockHistory = (mockHass: MockHomeAssistant) => {
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
mockHass.mockWS("history/list_statistic_ids", () => []);
|
|
||||||
mockHass.mockWS(
|
|
||||||
"history/statistics_during_period",
|
|
||||||
({ statistic_ids, start_time, end_time, period }, hass) => {
|
|
||||||
const start = new Date(start_time);
|
|
||||||
const end = end_time ? new Date(end_time) : new Date();
|
|
||||||
|
|
||||||
const statistics: Record<string, StatisticValue[]> = {};
|
|
||||||
|
|
||||||
statistic_ids.forEach((id: string) => {
|
|
||||||
if (id in statisticsFunctions) {
|
|
||||||
statistics[id] = statisticsFunctions[id](id, start, end, period);
|
|
||||||
} else {
|
|
||||||
const entityState = hass.states[id];
|
|
||||||
const state = entityState ? Number(entityState.state) : 1;
|
|
||||||
statistics[id] =
|
|
||||||
entityState && "last_reset" in entityState.attributes
|
|
||||||
? generateSumStatistics(
|
|
||||||
id,
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
period,
|
|
||||||
state,
|
|
||||||
state * (state > 80 ? 0.01 : 0.05)
|
|
||||||
)
|
|
||||||
: generateMeanStatistics(
|
|
||||||
id,
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
period,
|
|
||||||
state,
|
|
||||||
state * (state > 80 ? 0.05 : 0.1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return statistics;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
342
demo/src/stubs/recorder.ts
Normal file
342
demo/src/stubs/recorder.ts
Normal file
@@ -0,0 +1,342 @@
|
|||||||
|
import {
|
||||||
|
addDays,
|
||||||
|
addHours,
|
||||||
|
addMonths,
|
||||||
|
differenceInHours,
|
||||||
|
endOfDay,
|
||||||
|
} from "date-fns";
|
||||||
|
import {
|
||||||
|
Statistics,
|
||||||
|
StatisticsMetaData,
|
||||||
|
StatisticValue,
|
||||||
|
} from "../../../src/data/recorder";
|
||||||
|
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
|
||||||
|
|
||||||
|
const generateMeanStatistics = (
|
||||||
|
start: Date,
|
||||||
|
end: Date,
|
||||||
|
period: "5minute" | "hour" | "day" | "month" = "hour",
|
||||||
|
initValue: number,
|
||||||
|
maxDiff: number
|
||||||
|
): StatisticValue[] => {
|
||||||
|
const statistics: StatisticValue[] = [];
|
||||||
|
let currentDate = new Date(start);
|
||||||
|
currentDate.setMinutes(0, 0, 0);
|
||||||
|
let lastVal = initValue;
|
||||||
|
const now = new Date();
|
||||||
|
while (end > currentDate && currentDate < now) {
|
||||||
|
const delta = Math.random() * maxDiff;
|
||||||
|
const mean = lastVal + delta;
|
||||||
|
statistics.push({
|
||||||
|
start: currentDate.getTime(),
|
||||||
|
end: currentDate.getTime(),
|
||||||
|
mean,
|
||||||
|
min: mean - Math.random() * maxDiff,
|
||||||
|
max: mean + Math.random() * maxDiff,
|
||||||
|
last_reset: 0,
|
||||||
|
state: mean,
|
||||||
|
sum: null,
|
||||||
|
});
|
||||||
|
lastVal = mean;
|
||||||
|
currentDate =
|
||||||
|
period === "day"
|
||||||
|
? addDays(currentDate, 1)
|
||||||
|
: period === "month"
|
||||||
|
? addMonths(currentDate, 1)
|
||||||
|
: addHours(currentDate, 1);
|
||||||
|
}
|
||||||
|
return statistics;
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateSumStatistics = (
|
||||||
|
start: Date,
|
||||||
|
end: Date,
|
||||||
|
period: "5minute" | "hour" | "day" | "month" = "hour",
|
||||||
|
initValue: number,
|
||||||
|
maxDiff: number
|
||||||
|
): StatisticValue[] => {
|
||||||
|
const statistics: StatisticValue[] = [];
|
||||||
|
let currentDate = new Date(start);
|
||||||
|
currentDate.setMinutes(0, 0, 0);
|
||||||
|
let sum = initValue;
|
||||||
|
const now = new Date();
|
||||||
|
while (end > currentDate && currentDate < now) {
|
||||||
|
const add = Math.random() * maxDiff;
|
||||||
|
sum += add;
|
||||||
|
statistics.push({
|
||||||
|
start: currentDate.getTime(),
|
||||||
|
end: currentDate.getTime(),
|
||||||
|
mean: null,
|
||||||
|
min: null,
|
||||||
|
max: null,
|
||||||
|
last_reset: 0,
|
||||||
|
state: initValue + sum,
|
||||||
|
sum,
|
||||||
|
});
|
||||||
|
currentDate =
|
||||||
|
period === "day"
|
||||||
|
? addDays(currentDate, 1)
|
||||||
|
: period === "month"
|
||||||
|
? addMonths(currentDate, 1)
|
||||||
|
: addHours(currentDate, 1);
|
||||||
|
}
|
||||||
|
return statistics;
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateCurvedStatistics = (
|
||||||
|
start: Date,
|
||||||
|
end: Date,
|
||||||
|
_period: "5minute" | "hour" | "day" | "month" = "hour",
|
||||||
|
initValue: number,
|
||||||
|
maxDiff: number,
|
||||||
|
metered: boolean
|
||||||
|
): StatisticValue[] => {
|
||||||
|
const statistics: StatisticValue[] = [];
|
||||||
|
let currentDate = new Date(start);
|
||||||
|
currentDate.setMinutes(0, 0, 0);
|
||||||
|
let sum = initValue;
|
||||||
|
const hours = differenceInHours(end, start) - 1;
|
||||||
|
let i = 0;
|
||||||
|
let half = false;
|
||||||
|
const now = new Date();
|
||||||
|
while (end > currentDate && currentDate < now) {
|
||||||
|
const add = Math.random() * maxDiff;
|
||||||
|
sum += i * add;
|
||||||
|
statistics.push({
|
||||||
|
start: currentDate.getTime(),
|
||||||
|
end: currentDate.getTime(),
|
||||||
|
mean: null,
|
||||||
|
min: null,
|
||||||
|
max: null,
|
||||||
|
last_reset: 0,
|
||||||
|
state: initValue + sum,
|
||||||
|
sum: metered ? sum : null,
|
||||||
|
});
|
||||||
|
currentDate = addHours(currentDate, 1);
|
||||||
|
if (!half && i > hours / 2) {
|
||||||
|
half = true;
|
||||||
|
}
|
||||||
|
i += half ? -1 : 1;
|
||||||
|
}
|
||||||
|
return statistics;
|
||||||
|
};
|
||||||
|
|
||||||
|
const statisticsFunctions: Record<
|
||||||
|
string,
|
||||||
|
(
|
||||||
|
id: string,
|
||||||
|
start: Date,
|
||||||
|
end: Date,
|
||||||
|
period: "5minute" | "hour" | "day" | "month"
|
||||||
|
) => StatisticValue[]
|
||||||
|
> = {
|
||||||
|
"sensor.energy_consumption_tarif_1": (
|
||||||
|
_id: string,
|
||||||
|
start: Date,
|
||||||
|
end: Date,
|
||||||
|
period = "hour"
|
||||||
|
) => {
|
||||||
|
if (period !== "hour") {
|
||||||
|
return generateSumStatistics(
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
period,
|
||||||
|
0,
|
||||||
|
period === "day" ? 17 : 504
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const morningEnd = new Date(start.getTime() + 10 * 60 * 60 * 1000);
|
||||||
|
const morningLow = generateSumStatistics(start, morningEnd, period, 0, 0.7);
|
||||||
|
const eveningStart = new Date(start.getTime() + 20 * 60 * 60 * 1000);
|
||||||
|
const morningFinalVal = morningLow.length
|
||||||
|
? morningLow[morningLow.length - 1].sum!
|
||||||
|
: 0;
|
||||||
|
const empty = generateSumStatistics(
|
||||||
|
morningEnd,
|
||||||
|
eveningStart,
|
||||||
|
period,
|
||||||
|
morningFinalVal,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
const eveningLow = generateSumStatistics(
|
||||||
|
eveningStart,
|
||||||
|
end,
|
||||||
|
period,
|
||||||
|
morningFinalVal,
|
||||||
|
0.7
|
||||||
|
);
|
||||||
|
return [...morningLow, ...empty, ...eveningLow];
|
||||||
|
},
|
||||||
|
"sensor.energy_consumption_tarif_2": (
|
||||||
|
_id: string,
|
||||||
|
start: Date,
|
||||||
|
end: Date,
|
||||||
|
period = "hour"
|
||||||
|
) => {
|
||||||
|
if (period !== "hour") {
|
||||||
|
return generateSumStatistics(
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
period,
|
||||||
|
0,
|
||||||
|
period === "day" ? 17 : 504
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const morningEnd = new Date(start.getTime() + 9 * 60 * 60 * 1000);
|
||||||
|
const eveningStart = new Date(start.getTime() + 20 * 60 * 60 * 1000);
|
||||||
|
const highTarif = generateSumStatistics(
|
||||||
|
morningEnd,
|
||||||
|
eveningStart,
|
||||||
|
period,
|
||||||
|
0,
|
||||||
|
0.3
|
||||||
|
);
|
||||||
|
const highTarifFinalVal = highTarif.length
|
||||||
|
? highTarif[highTarif.length - 1].sum!
|
||||||
|
: 0;
|
||||||
|
const morning = generateSumStatistics(start, morningEnd, period, 0, 0);
|
||||||
|
const evening = generateSumStatistics(
|
||||||
|
eveningStart,
|
||||||
|
end,
|
||||||
|
period,
|
||||||
|
highTarifFinalVal,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
return [...morning, ...highTarif, ...evening];
|
||||||
|
},
|
||||||
|
"sensor.energy_production_tarif_1": (_id, start, end, period = "hour") =>
|
||||||
|
generateSumStatistics(start, end, period, 0, 0),
|
||||||
|
"sensor.energy_production_tarif_1_compensation": (
|
||||||
|
_id,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
period = "hour"
|
||||||
|
) => generateSumStatistics(start, end, period, 0, 0),
|
||||||
|
"sensor.energy_production_tarif_2": (_id, start, end, period = "hour") => {
|
||||||
|
if (period !== "hour") {
|
||||||
|
return generateSumStatistics(
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
period,
|
||||||
|
0,
|
||||||
|
period === "day" ? 17 : 504
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const productionStart = new Date(start.getTime() + 9 * 60 * 60 * 1000);
|
||||||
|
const productionEnd = new Date(start.getTime() + 21 * 60 * 60 * 1000);
|
||||||
|
const dayEnd = new Date(endOfDay(productionEnd));
|
||||||
|
const production = generateCurvedStatistics(
|
||||||
|
productionStart,
|
||||||
|
productionEnd,
|
||||||
|
period,
|
||||||
|
0,
|
||||||
|
0.15,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
const productionFinalVal = production.length
|
||||||
|
? production[production.length - 1].sum!
|
||||||
|
: 0;
|
||||||
|
const morning = generateSumStatistics(start, productionStart, period, 0, 0);
|
||||||
|
const evening = generateSumStatistics(
|
||||||
|
productionEnd,
|
||||||
|
dayEnd,
|
||||||
|
period,
|
||||||
|
productionFinalVal,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
const rest = generateSumStatistics(
|
||||||
|
dayEnd,
|
||||||
|
end,
|
||||||
|
period,
|
||||||
|
productionFinalVal,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
return [...morning, ...production, ...evening, ...rest];
|
||||||
|
},
|
||||||
|
"sensor.solar_production": (_id, start, end, period = "hour") => {
|
||||||
|
if (period !== "hour") {
|
||||||
|
return generateSumStatistics(
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
period,
|
||||||
|
0,
|
||||||
|
period === "day" ? 17 : 504
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const productionStart = new Date(start.getTime() + 7 * 60 * 60 * 1000);
|
||||||
|
const productionEnd = new Date(start.getTime() + 23 * 60 * 60 * 1000);
|
||||||
|
const dayEnd = new Date(endOfDay(productionEnd));
|
||||||
|
const production = generateCurvedStatistics(
|
||||||
|
productionStart,
|
||||||
|
productionEnd,
|
||||||
|
period,
|
||||||
|
0,
|
||||||
|
0.3,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
const productionFinalVal = production.length
|
||||||
|
? production[production.length - 1].sum!
|
||||||
|
: 0;
|
||||||
|
const morning = generateSumStatistics(start, productionStart, period, 0, 0);
|
||||||
|
const evening = generateSumStatistics(
|
||||||
|
productionEnd,
|
||||||
|
dayEnd,
|
||||||
|
period,
|
||||||
|
productionFinalVal,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
const rest = generateSumStatistics(
|
||||||
|
dayEnd,
|
||||||
|
end,
|
||||||
|
period,
|
||||||
|
productionFinalVal,
|
||||||
|
2
|
||||||
|
);
|
||||||
|
return [...morning, ...production, ...evening, ...rest];
|
||||||
|
},
|
||||||
|
};
|
||||||
|
export const mockRecorder = (mockHass: MockHomeAssistant) => {
|
||||||
|
mockHass.mockWS(
|
||||||
|
"recorder/get_statistics_metadata",
|
||||||
|
(): StatisticsMetaData[] => []
|
||||||
|
);
|
||||||
|
mockHass.mockWS(
|
||||||
|
"recorder/list_statistic_ids",
|
||||||
|
(): StatisticsMetaData[] => []
|
||||||
|
);
|
||||||
|
mockHass.mockWS(
|
||||||
|
"recorder/statistics_during_period",
|
||||||
|
({ statistic_ids, start_time, end_time, period }, hass): Statistics => {
|
||||||
|
const start = new Date(start_time);
|
||||||
|
const end = end_time ? new Date(end_time) : new Date();
|
||||||
|
|
||||||
|
const statistics: Record<string, StatisticValue[]> = {};
|
||||||
|
|
||||||
|
statistic_ids.forEach((id: string) => {
|
||||||
|
if (id in statisticsFunctions) {
|
||||||
|
statistics[id] = statisticsFunctions[id](id, start, end, period);
|
||||||
|
} else {
|
||||||
|
const entityState = hass.states[id];
|
||||||
|
const state = entityState ? Number(entityState.state) : 1;
|
||||||
|
statistics[id] =
|
||||||
|
entityState && "last_reset" in entityState.attributes
|
||||||
|
? generateSumStatistics(
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
period,
|
||||||
|
state,
|
||||||
|
state * (state > 80 ? 0.01 : 0.05)
|
||||||
|
)
|
||||||
|
: generateMeanStatistics(
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
period,
|
||||||
|
state,
|
||||||
|
state * (state > 80 ? 0.05 : 0.1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return statistics;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
BIN
gallery/public/api/hassio/addons/core_zwave_js/icon
Normal file
BIN
gallery/public/api/hassio/addons/core_zwave_js/icon
Normal file
Binary file not shown.
BIN
gallery/public/images/clearspace.png
Normal file
BIN
gallery/public/images/clearspace.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
BIN
gallery/public/images/logo-variants.png
Normal file
BIN
gallery/public/images/logo-variants.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
BIN
gallery/public/images/logo-with-text.png
Normal file
BIN
gallery/public/images/logo-with-text.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 46 KiB |
BIN
gallery/public/images/logo.png
Normal file
BIN
gallery/public/images/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
Binary file not shown.
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 90 KiB |
@@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
TARGET_LABEL="Needs gallery preview"
|
TARGET_LABEL="needs design preview"
|
||||||
|
|
||||||
if [[ "$NETLIFY" != "true" ]]; then
|
if [[ "$NETLIFY" != "true" ]]; then
|
||||||
echo "This script can only be run on Netlify"
|
echo "This script can only be run on Netlify"
|
||||||
@@ -13,23 +13,23 @@ function createStatus() {
|
|||||||
target_url="$3"
|
target_url="$3"
|
||||||
curl -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: token $GITHUB_TOKEN" \
|
curl -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: token $GITHUB_TOKEN" \
|
||||||
"https://api.github.com/repos/home-assistant/frontend/statuses/$COMMIT_REF" \
|
"https://api.github.com/repos/home-assistant/frontend/statuses/$COMMIT_REF" \
|
||||||
-d '{"state": "'"${state}"'", "context": "Netlify/Gallery Preview Build", "description": "'"$description"'", "target_url": "'"$target_url"'"}'
|
-d '{"state": "'"${state}"'", "context": "Netlify/Design Preview Build", "description": "'"$description"'", "target_url": "'"$target_url"'"}'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if [[ "${PULL_REQUEST}" == "false" ]]; then
|
if [[ "${PULL_REQUEST}" == "true" ]]; then
|
||||||
gulp build-gallery
|
|
||||||
else
|
|
||||||
if [[ "$(curl -sSLf -H "Accept: application/vnd.github.v3+json" -H "Authorization: token $GITHUB_TOKEN" \
|
if [[ "$(curl -sSLf -H "Accept: application/vnd.github.v3+json" -H "Authorization: token $GITHUB_TOKEN" \
|
||||||
"https://api.github.com/repos/home-assistant/frontend/pulls/${REVIEW_ID}" | jq '.labels[].name' -r)" =~ "$TARGET_LABEL" ]]; then
|
"https://api.github.com/repos/home-assistant/frontend/pulls/${REVIEW_ID}" | jq '.labels[].name' -r)" =~ "$TARGET_LABEL" ]]; then
|
||||||
createStatus "pending" "Building gallery preview" "https://app.netlify.com/sites/home-assistant-gallery/deploys/$BUILD_ID"
|
createStatus "pending" "Building design preview" "https://app.netlify.com/sites/home-assistant-gallery/deploys/$BUILD_ID"
|
||||||
gulp build-gallery
|
gulp build-gallery
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
createStatus "success" "Build complete" "$DEPLOY_URL"
|
createStatus "success" "Build complete" "$DEPLOY_PRIME_URL"
|
||||||
else
|
else
|
||||||
createStatus "error" "Build failed" "https://app.netlify.com/sites/home-assistant-gallery/deploys/$BUILD_ID"
|
createStatus "error" "Build failed" "https://app.netlify.com/sites/home-assistant-gallery/deploys/$BUILD_ID"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
createStatus "success" "Build was not requested by PR label"
|
createStatus "success" "Build was not requested by PR label"
|
||||||
fi
|
fi
|
||||||
|
elif [[ "$INCOMING_HOOK_BODY" == "NIGHTLY" ]]; then
|
||||||
|
gulp build-gallery
|
||||||
fi
|
fi
|
||||||
|
52
gallery/sidebar.js
Normal file
52
gallery/sidebar.js
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
module.exports = [
|
||||||
|
{
|
||||||
|
// This section has no header and so all page links are shown directly in the sidebar
|
||||||
|
category: "concepts",
|
||||||
|
pages: ["home"],
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
category: "lovelace",
|
||||||
|
// Label for in the sidebar
|
||||||
|
header: "Dashboards",
|
||||||
|
// Specify order of pages. Any pages in the category folder but not listed here will
|
||||||
|
// automatically be added after the pages listed here.
|
||||||
|
pages: ["introduction"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: "automation",
|
||||||
|
header: "Automation",
|
||||||
|
pages: [
|
||||||
|
"editor-trigger",
|
||||||
|
"editor-condition",
|
||||||
|
"editor-action",
|
||||||
|
"trace",
|
||||||
|
"trace-timeline",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: "components",
|
||||||
|
header: "Components",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: "more-info",
|
||||||
|
header: "More Info dialogs",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: "misc",
|
||||||
|
header: "Miscellaneous",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: "brand",
|
||||||
|
header: "Brand",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: "user-test",
|
||||||
|
header: "Users",
|
||||||
|
pages: ["user-types", "configuration-menu"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: "design.home-assistant.io",
|
||||||
|
header: "About",
|
||||||
|
},
|
||||||
|
];
|
@@ -3,6 +3,7 @@ import { html, LitElement, css, TemplateResult } from "lit";
|
|||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import { applyThemesOnElement } from "../../../src/common/dom/apply_themes_on_element";
|
import { applyThemesOnElement } from "../../../src/common/dom/apply_themes_on_element";
|
||||||
import { fireEvent } from "../../../src/common/dom/fire_event";
|
import { fireEvent } from "../../../src/common/dom/fire_event";
|
||||||
|
import "../../../src/components/ha-card";
|
||||||
|
|
||||||
@customElement("demo-black-white-row")
|
@customElement("demo-black-white-row")
|
||||||
class DemoBlackWhiteRow extends LitElement {
|
class DemoBlackWhiteRow extends LitElement {
|
||||||
@@ -52,13 +53,19 @@ class DemoBlackWhiteRow extends LitElement {
|
|||||||
|
|
||||||
firstUpdated(changedProps) {
|
firstUpdated(changedProps) {
|
||||||
super.firstUpdated(changedProps);
|
super.firstUpdated(changedProps);
|
||||||
applyThemesOnElement(this.shadowRoot!.querySelector(".dark"), {
|
applyThemesOnElement(
|
||||||
default_theme: "default",
|
this.shadowRoot!.querySelector(".dark"),
|
||||||
default_dark_theme: "default",
|
{
|
||||||
themes: {},
|
default_theme: "default",
|
||||||
darkMode: true,
|
default_dark_theme: "default",
|
||||||
theme: "default",
|
themes: {},
|
||||||
});
|
darkMode: true,
|
||||||
|
theme: "default",
|
||||||
|
},
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
true
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSubmit(ev) {
|
handleSubmit(ev) {
|
||||||
|
@@ -1,129 +0,0 @@
|
|||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
|
||||||
/* eslint-plugin-disable lit */
|
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
|
||||||
import { load } from "js-yaml";
|
|
||||||
import { createCardElement } from "../../../src/panels/lovelace/create-element/create-card-element";
|
|
||||||
|
|
||||||
class DemoCard extends PolymerElement {
|
|
||||||
static get template() {
|
|
||||||
return html`
|
|
||||||
<style>
|
|
||||||
.root {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
h2 {
|
|
||||||
margin: 0 0 20px;
|
|
||||||
color: var(--primary-color);
|
|
||||||
}
|
|
||||||
h2 small {
|
|
||||||
font-size: 0.5em;
|
|
||||||
color: var(--primary-text-color);
|
|
||||||
}
|
|
||||||
#card {
|
|
||||||
max-width: 400px;
|
|
||||||
width: 100vw;
|
|
||||||
}
|
|
||||||
pre {
|
|
||||||
width: 400px;
|
|
||||||
margin: 0 16px;
|
|
||||||
overflow: auto;
|
|
||||||
color: var(--primary-text-color);
|
|
||||||
}
|
|
||||||
@media only screen and (max-width: 800px) {
|
|
||||||
.root {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
pre {
|
|
||||||
margin: 16px 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<h2>
|
|
||||||
[[config.heading]]
|
|
||||||
<template is="dom-if" if="[[_size]]">
|
|
||||||
<small>(size [[_size]])</small>
|
|
||||||
</template>
|
|
||||||
</h2>
|
|
||||||
<div class="root">
|
|
||||||
<div id="card"></div>
|
|
||||||
<template is="dom-if" if="[[showConfig]]">
|
|
||||||
<pre>[[_trim(config.config)]]</pre>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get properties() {
|
|
||||||
return {
|
|
||||||
hass: {
|
|
||||||
type: Object,
|
|
||||||
observer: "_hassChanged",
|
|
||||||
},
|
|
||||||
config: {
|
|
||||||
type: Object,
|
|
||||||
observer: "_configChanged",
|
|
||||||
},
|
|
||||||
showConfig: Boolean,
|
|
||||||
_size: {
|
|
||||||
type: Number,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
ready() {
|
|
||||||
super.ready();
|
|
||||||
}
|
|
||||||
|
|
||||||
_configChanged(config) {
|
|
||||||
const card = this.$.card;
|
|
||||||
while (card.lastChild) {
|
|
||||||
card.removeChild(card.lastChild);
|
|
||||||
}
|
|
||||||
|
|
||||||
const el = this._createCardElement(load(config.config)[0]);
|
|
||||||
card.appendChild(el);
|
|
||||||
this._getSize(el);
|
|
||||||
}
|
|
||||||
|
|
||||||
async _getSize(el) {
|
|
||||||
await customElements.whenDefined(el.localName);
|
|
||||||
|
|
||||||
if (!("getCardSize" in el)) {
|
|
||||||
this._size = undefined;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._size = await el.getCardSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
_createCardElement(cardConfig) {
|
|
||||||
const element = createCardElement(cardConfig);
|
|
||||||
if (this.hass) {
|
|
||||||
element.hass = this.hass;
|
|
||||||
}
|
|
||||||
element.addEventListener(
|
|
||||||
"ll-rebuild",
|
|
||||||
(ev) => {
|
|
||||||
ev.stopPropagation();
|
|
||||||
this._rebuildCard(element, cardConfig);
|
|
||||||
},
|
|
||||||
{ once: true }
|
|
||||||
);
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
|
|
||||||
_rebuildCard(cardElToReplace, config) {
|
|
||||||
const newCardEl = this._createCardElement(config);
|
|
||||||
cardElToReplace.parentElement.replaceChild(newCardEl, cardElToReplace);
|
|
||||||
}
|
|
||||||
|
|
||||||
_hassChanged(hass) {
|
|
||||||
const card = this.$.card.lastChild;
|
|
||||||
if (card) card.hass = hass;
|
|
||||||
}
|
|
||||||
|
|
||||||
_trim(config) {
|
|
||||||
return config.trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
customElements.define("demo-card", DemoCard);
|
|
129
gallery/src/components/demo-card.ts
Normal file
129
gallery/src/components/demo-card.ts
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
import { load } from "js-yaml";
|
||||||
|
import { html, css, LitElement, PropertyValues } from "lit";
|
||||||
|
import { customElement, property, query, state } from "lit/decorators";
|
||||||
|
import { createCardElement } from "../../../src/panels/lovelace/create-element/create-card-element";
|
||||||
|
import { HomeAssistant } from "../../../src/types";
|
||||||
|
|
||||||
|
export interface DemoCardConfig {
|
||||||
|
heading: string;
|
||||||
|
config: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@customElement("demo-card")
|
||||||
|
class DemoCard extends LitElement {
|
||||||
|
@property() public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property() public config!: DemoCardConfig;
|
||||||
|
|
||||||
|
@property() public showConfig = false;
|
||||||
|
|
||||||
|
@state() private _size?: number;
|
||||||
|
|
||||||
|
@query("#card") private _card!: HTMLElement;
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
<h2>
|
||||||
|
${this.config.heading}
|
||||||
|
${this._size !== undefined
|
||||||
|
? html`<small>(size ${this._size})</small>`
|
||||||
|
: ""}
|
||||||
|
</h2>
|
||||||
|
<div class="root">
|
||||||
|
<div id="card"></div>
|
||||||
|
${this.showConfig ? html`<pre>${this.config.config.trim()}</pre>` : ""}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
updated(changedProps: PropertyValues) {
|
||||||
|
super.updated(changedProps);
|
||||||
|
|
||||||
|
if (changedProps.has("config")) {
|
||||||
|
const card = this._card;
|
||||||
|
while (card.lastChild) {
|
||||||
|
card.removeChild(card.lastChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
const el = this._createCardElement((load(this.config.config) as any)[0]);
|
||||||
|
card.appendChild(el);
|
||||||
|
this._getSize(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changedProps.has("hass")) {
|
||||||
|
const card = this._card.lastChild;
|
||||||
|
if (card) {
|
||||||
|
(card as any).hass = this.hass;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async _getSize(el) {
|
||||||
|
await customElements.whenDefined(el.localName);
|
||||||
|
|
||||||
|
if (!("getCardSize" in el)) {
|
||||||
|
this._size = undefined;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._size = await el.getCardSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
_createCardElement(cardConfig) {
|
||||||
|
const element = createCardElement(cardConfig);
|
||||||
|
if (this.hass) {
|
||||||
|
element.hass = this.hass;
|
||||||
|
}
|
||||||
|
element.addEventListener(
|
||||||
|
"ll-rebuild",
|
||||||
|
(ev) => {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this._rebuildCard(element, cardConfig);
|
||||||
|
},
|
||||||
|
{ once: true }
|
||||||
|
);
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
_rebuildCard(cardElToReplace, config) {
|
||||||
|
const newCardEl = this._createCardElement(config);
|
||||||
|
cardElToReplace.parentElement.replaceChild(newCardEl, cardElToReplace);
|
||||||
|
}
|
||||||
|
|
||||||
|
static styles = css`
|
||||||
|
.root {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
margin: 0 0 20px;
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
h2 small {
|
||||||
|
font-size: 0.5em;
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
}
|
||||||
|
#card {
|
||||||
|
max-width: 400px;
|
||||||
|
width: 100vw;
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
width: 400px;
|
||||||
|
margin: 0 16px;
|
||||||
|
overflow: auto;
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
}
|
||||||
|
@media only screen and (max-width: 800px) {
|
||||||
|
.root {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
margin: 16px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"demo-card": DemoCard;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,83 +0,0 @@
|
|||||||
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
|
||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
|
||||||
/* eslint-plugin-disable lit */
|
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
|
||||||
import { applyThemesOnElement } from "../../../src/common/dom/apply_themes_on_element";
|
|
||||||
import "../../../src/components/ha-formfield";
|
|
||||||
import "../../../src/components/ha-switch";
|
|
||||||
import "./demo-card";
|
|
||||||
|
|
||||||
class DemoCards extends PolymerElement {
|
|
||||||
static get template() {
|
|
||||||
return html`
|
|
||||||
<style>
|
|
||||||
#container {
|
|
||||||
min-height: calc(100vh - 128px);
|
|
||||||
background: var(--primary-background-color);
|
|
||||||
}
|
|
||||||
.cards {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
demo-card {
|
|
||||||
margin: 16px 16px 32px;
|
|
||||||
}
|
|
||||||
app-toolbar {
|
|
||||||
background-color: var(--light-primary-color);
|
|
||||||
}
|
|
||||||
.filters {
|
|
||||||
margin-left: 60px;
|
|
||||||
}
|
|
||||||
ha-formfield {
|
|
||||||
margin-right: 16px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<app-toolbar>
|
|
||||||
<div class="filters">
|
|
||||||
<ha-formfield label="Show config">
|
|
||||||
<ha-switch checked="[[_showConfig]]" on-change="_showConfigToggled">
|
|
||||||
</ha-switch>
|
|
||||||
</ha-formfield>
|
|
||||||
<ha-formfield label="Dark theme">
|
|
||||||
<ha-switch on-change="_darkThemeToggled"> </ha-switch>
|
|
||||||
</ha-formfield>
|
|
||||||
</div>
|
|
||||||
</app-toolbar>
|
|
||||||
<div id="container">
|
|
||||||
<div class="cards">
|
|
||||||
<template is="dom-repeat" items="[[configs]]">
|
|
||||||
<demo-card
|
|
||||||
config="[[item]]"
|
|
||||||
show-config="[[_showConfig]]"
|
|
||||||
hass="[[hass]]"
|
|
||||||
></demo-card>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get properties() {
|
|
||||||
return {
|
|
||||||
configs: Object,
|
|
||||||
hass: Object,
|
|
||||||
_showConfig: {
|
|
||||||
type: Boolean,
|
|
||||||
value: false,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
_showConfigToggled(ev) {
|
|
||||||
this._showConfig = ev.target.checked;
|
|
||||||
}
|
|
||||||
|
|
||||||
_darkThemeToggled(ev) {
|
|
||||||
applyThemesOnElement(this.$.container, { themes: {} }, "default", {
|
|
||||||
dark: ev.target.checked,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
customElements.define("demo-cards", DemoCards);
|
|
91
gallery/src/components/demo-cards.ts
Normal file
91
gallery/src/components/demo-cards.ts
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
||||||
|
import { html, css, LitElement } from "lit";
|
||||||
|
import { customElement, property, query, state } from "lit/decorators";
|
||||||
|
import { applyThemesOnElement } from "../../../src/common/dom/apply_themes_on_element";
|
||||||
|
import "../../../src/components/ha-formfield";
|
||||||
|
import "../../../src/components/ha-switch";
|
||||||
|
import { HomeAssistant } from "../../../src/types";
|
||||||
|
import "./demo-card";
|
||||||
|
import type { DemoCardConfig } from "./demo-card";
|
||||||
|
|
||||||
|
@customElement("demo-cards")
|
||||||
|
class DemoCards extends LitElement {
|
||||||
|
@property() public configs!: DemoCardConfig[];
|
||||||
|
|
||||||
|
@property() public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@state() private _showConfig = false;
|
||||||
|
|
||||||
|
@query("#container") private _container!: HTMLElement;
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
<app-toolbar>
|
||||||
|
<div class="filters">
|
||||||
|
<ha-formfield label="Show config">
|
||||||
|
<ha-switch
|
||||||
|
.checked=${this._showConfig}
|
||||||
|
@change=${this._showConfigToggled}
|
||||||
|
>
|
||||||
|
</ha-switch>
|
||||||
|
</ha-formfield>
|
||||||
|
<ha-formfield label="Dark theme">
|
||||||
|
<ha-switch @change=${this._darkThemeToggled}> </ha-switch>
|
||||||
|
</ha-formfield>
|
||||||
|
</div>
|
||||||
|
</app-toolbar>
|
||||||
|
<div id="container">
|
||||||
|
<div class="cards">
|
||||||
|
${this.configs.map(
|
||||||
|
(config) => html`
|
||||||
|
<demo-card
|
||||||
|
.config=${config}
|
||||||
|
.showConfig=${this._showConfig}
|
||||||
|
.hass=${this.hass}
|
||||||
|
></demo-card>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
_showConfigToggled(ev) {
|
||||||
|
this._showConfig = ev.target.checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
_darkThemeToggled(ev) {
|
||||||
|
applyThemesOnElement(this._container, { themes: {} } as any, "default", {
|
||||||
|
dark: ev.target.checked,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static styles = css`
|
||||||
|
.cards {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
demo-card {
|
||||||
|
margin: 16px 16px 32px;
|
||||||
|
}
|
||||||
|
app-toolbar {
|
||||||
|
background-color: var(--light-primary-color);
|
||||||
|
}
|
||||||
|
.filters {
|
||||||
|
margin-left: 60px;
|
||||||
|
}
|
||||||
|
ha-formfield {
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
#container {
|
||||||
|
background-color: var(--primary-background-color);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"demo-cards": DemoCards;
|
||||||
|
}
|
||||||
|
}
|
66
gallery/src/components/page-description.ts
Normal file
66
gallery/src/components/page-description.ts
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
import { html, css } from "lit";
|
||||||
|
import { customElement, property } from "lit/decorators";
|
||||||
|
import { until } from "lit/directives/until";
|
||||||
|
import { HaMarkdown } from "../../../src/components/ha-markdown";
|
||||||
|
import { PAGES } from "../../build/import-pages";
|
||||||
|
|
||||||
|
@customElement("page-description")
|
||||||
|
class PageDescription extends HaMarkdown {
|
||||||
|
@property() public page!: string;
|
||||||
|
|
||||||
|
render() {
|
||||||
|
if (!PAGES[this.page].description) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<div class="heading">
|
||||||
|
<div class="title">
|
||||||
|
${PAGES[this.page].metadata.title || this.page.split("/")[1]}
|
||||||
|
</div>
|
||||||
|
<div class="subtitle">${PAGES[this.page].metadata.subtitle}</div>
|
||||||
|
</div>
|
||||||
|
${until(
|
||||||
|
PAGES[this.page]
|
||||||
|
.description()
|
||||||
|
.then((content) => html`<div class="root">${content}</div>`),
|
||||||
|
""
|
||||||
|
)}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static styles = [
|
||||||
|
HaMarkdown.styles,
|
||||||
|
css`
|
||||||
|
.heading {
|
||||||
|
padding: 16px;
|
||||||
|
border-bottom: 1px solid var(--secondary-background-color);
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
font-size: 42px;
|
||||||
|
line-height: 56px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
}
|
||||||
|
.subtitle {
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
.root {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 16px auto;
|
||||||
|
}
|
||||||
|
.root > *:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
.root > *:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"page-description": PageDescription;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,10 +1,4 @@
|
|||||||
import { css, html, LitElement, TemplateResult } from "lit";
|
export const LONG_TEXT = `
|
||||||
import { customElement } from "lit/decorators";
|
|
||||||
import "../../../src/components/ha-card";
|
|
||||||
import "../../../src/components/ha-faded";
|
|
||||||
import "../../../src/components/ha-markdown";
|
|
||||||
|
|
||||||
const LONG_TEXT = `
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc laoreet velit ut elit volutpat, eget ultrices odio lacinia. In imperdiet malesuada est, nec sagittis metus ultricies quis. Sed nisl ex, convallis porttitor ante quis, hendrerit tristique justo. Mauris pharetra venenatis augue, eu maximus sem cursus in. Quisque sed consequat risus. Suspendisse facilisis ligula a odio consectetur condimentum. Curabitur vehicula elit nec augue mollis, et volutpat massa dictum.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc laoreet velit ut elit volutpat, eget ultrices odio lacinia. In imperdiet malesuada est, nec sagittis metus ultricies quis. Sed nisl ex, convallis porttitor ante quis, hendrerit tristique justo. Mauris pharetra venenatis augue, eu maximus sem cursus in. Quisque sed consequat risus. Suspendisse facilisis ligula a odio consectetur condimentum. Curabitur vehicula elit nec augue mollis, et volutpat massa dictum.
|
||||||
|
|
||||||
Nam pellentesque auctor rutrum. Suspendisse elit est, sodales vel diam nec, porttitor faucibus massa. Ut pretium ac orci eu pharetra. Praesent in nibh at magna viverra rutrum eu vitae tortor. Etiam eget sem ex. Fusce tristique odio nec lacus mattis, vitae tempor nunc malesuada. Maecenas faucibus magna vel libero maximus egestas. Vestibulum luctus semper velit, in lobortis risus tempus non. Curabitur bibendum ornare commodo. Quisque commodo neque sit amet tincidunt lacinia. Proin elementum ante velit, eu congue nulla semper quis. Pellentesque consequat vel nunc at scelerisque. Mauris sit amet venenatis diam, blandit viverra leo. Integer commodo laoreet orci.
|
Nam pellentesque auctor rutrum. Suspendisse elit est, sodales vel diam nec, porttitor faucibus massa. Ut pretium ac orci eu pharetra. Praesent in nibh at magna viverra rutrum eu vitae tortor. Etiam eget sem ex. Fusce tristique odio nec lacus mattis, vitae tempor nunc malesuada. Maecenas faucibus magna vel libero maximus egestas. Vestibulum luctus semper velit, in lobortis risus tempus non. Curabitur bibendum ornare commodo. Quisque commodo neque sit amet tincidunt lacinia. Proin elementum ante velit, eu congue nulla semper quis. Pellentesque consequat vel nunc at scelerisque. Mauris sit amet venenatis diam, blandit viverra leo. Integer commodo laoreet orci.
|
||||||
@@ -15,74 +9,3 @@ In vitae eros sollicitudin, iaculis ex eget, egestas orci. Etiam sed pretium lor
|
|||||||
|
|
||||||
Quisque posuere, velit sed porttitor dapibus, neque augue fringilla felis, eu luctus nisi nisl nec ipsum. Curabitur pellentesque ac lectus eget ultricies. Vestibulum est dolor, lacinia pharetra vulputate a, facilisis a magna. Nam vitae arcu nibh. Praesent finibus blandit ante, ac gravida ex mollis eget. Donec quam est, pulvinar vitae neque ut, bibendum aliquam erat. Nullam mollis arcu at sem tincidunt, in tristique lectus facilisis. Aenean ut lacus vel nisl finibus iaculis non a turpis. Integer eget ipsum ante. Donec nunc neque, vestibulum ac magna ac, posuere scelerisque dui. Pellentesque massa nibh, rhoncus id dolor quis, placerat posuere turpis. Donec aliquet augue nisi, eu finibus dui auctor et. Vestibulum eu varius lorem. Quisque lectus ante, malesuada pretium risus eget, interdum mattis enim.
|
Quisque posuere, velit sed porttitor dapibus, neque augue fringilla felis, eu luctus nisi nisl nec ipsum. Curabitur pellentesque ac lectus eget ultricies. Vestibulum est dolor, lacinia pharetra vulputate a, facilisis a magna. Nam vitae arcu nibh. Praesent finibus blandit ante, ac gravida ex mollis eget. Donec quam est, pulvinar vitae neque ut, bibendum aliquam erat. Nullam mollis arcu at sem tincidunt, in tristique lectus facilisis. Aenean ut lacus vel nisl finibus iaculis non a turpis. Integer eget ipsum ante. Donec nunc neque, vestibulum ac magna ac, posuere scelerisque dui. Pellentesque massa nibh, rhoncus id dolor quis, placerat posuere turpis. Donec aliquet augue nisi, eu finibus dui auctor et. Vestibulum eu varius lorem. Quisque lectus ante, malesuada pretium risus eget, interdum mattis enim.
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const SMALL_TEXT = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
|
|
||||||
|
|
||||||
@customElement("demo-ha-faded")
|
|
||||||
export class DemoHaFaded extends LitElement {
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`
|
|
||||||
<ha-card header="ha-faded demo">
|
|
||||||
<div class="card-content">
|
|
||||||
<h3>Long text directly as slotted content</h3>
|
|
||||||
<ha-faded>${LONG_TEXT}</ha-faded>
|
|
||||||
<h3>Long text with slotted element</h3>
|
|
||||||
<ha-faded><span>${LONG_TEXT}</span></ha-faded>
|
|
||||||
<h3>No text</h3>
|
|
||||||
<ha-faded><span></span></ha-faded>
|
|
||||||
<h3>Smal text</h3>
|
|
||||||
<ha-faded><span>${SMALL_TEXT}</span></ha-faded>
|
|
||||||
<h3>Long text in markdown</h3>
|
|
||||||
<ha-faded>
|
|
||||||
<ha-markdown .content=${LONG_TEXT}> </ha-markdown>
|
|
||||||
</ha-faded>
|
|
||||||
<h3>Missing 1px from hiding</h3>
|
|
||||||
<ha-faded faded-height="87">
|
|
||||||
<span>
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc
|
|
||||||
laoreet velit ut elit volutpat, eget ultrices odio lacinia. In
|
|
||||||
imperdiet malesuada est, nec sagittis metus ultricies quis. Sed
|
|
||||||
nisl ex, convallis porttitor ante quis, hendrerit tristique justo.
|
|
||||||
Mauris pharetra venenatis augue, eu maximus sem cursus in. Quisque
|
|
||||||
sed consequat risus. Suspendisse facilisis ligula a odio
|
|
||||||
consectetur condimentum. Curabitur vehicula elit nec augue mollis,
|
|
||||||
et volutpat massa dictum. Nam pellentesque auctor rutrum.
|
|
||||||
Suspendisse elit est, sodales vel diam nec, porttitor faucibus
|
|
||||||
massa. Ut pretium ac orci eu pharetra.
|
|
||||||
</span>
|
|
||||||
</ha-faded>
|
|
||||||
<h3>1px over hiding point</h3>
|
|
||||||
<ha-faded faded-height="85">
|
|
||||||
<span>
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc
|
|
||||||
laoreet velit ut elit volutpat, eget ultrices odio lacinia. In
|
|
||||||
imperdiet malesuada est, nec sagittis metus ultricies quis. Sed
|
|
||||||
nisl ex, convallis porttitor ante quis, hendrerit tristique justo.
|
|
||||||
Mauris pharetra venenatis augue, eu maximus sem cursus in. Quisque
|
|
||||||
sed consequat risus. Suspendisse facilisis ligula a odio
|
|
||||||
consectetur condimentum. Curabitur vehicula elit nec augue mollis,
|
|
||||||
et volutpat massa dictum. Nam pellentesque auctor rutrum.
|
|
||||||
Suspendisse elit est, sodales vel diam nec, porttitor faucibus
|
|
||||||
massa. Ut pretium ac orci eu pharetra.
|
|
||||||
</span>
|
|
||||||
</ha-faded>
|
|
||||||
</div>
|
|
||||||
</ha-card>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return css`
|
|
||||||
ha-card {
|
|
||||||
max-width: 600px;
|
|
||||||
margin: 24px auto;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-ha-faded": DemoHaFaded;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -119,7 +119,7 @@ export const basicTrace: DemoTrace = {
|
|||||||
params: {
|
params: {
|
||||||
domain: "input_boolean",
|
domain: "input_boolean",
|
||||||
service: "toggle",
|
service: "toggle",
|
||||||
service_data: {},
|
data: {},
|
||||||
target: {
|
target: {
|
||||||
entity_id: ["input_boolean.toggle_4"],
|
entity_id: ["input_boolean.toggle_4"],
|
||||||
},
|
},
|
||||||
@@ -164,7 +164,7 @@ export const basicTrace: DemoTrace = {
|
|||||||
params: {
|
params: {
|
||||||
domain: "input_boolean",
|
domain: "input_boolean",
|
||||||
service: "toggle",
|
service: "toggle",
|
||||||
service_data: {},
|
data: {},
|
||||||
target: {
|
target: {
|
||||||
entity_id: ["input_boolean.toggle_2"],
|
entity_id: ["input_boolean.toggle_2"],
|
||||||
},
|
},
|
||||||
@@ -182,7 +182,7 @@ export const basicTrace: DemoTrace = {
|
|||||||
params: {
|
params: {
|
||||||
domain: "input_boolean",
|
domain: "input_boolean",
|
||||||
service: "toggle",
|
service: "toggle",
|
||||||
service_data: {},
|
data: {},
|
||||||
target: {
|
target: {
|
||||||
entity_id: ["input_boolean.toggle_3"],
|
entity_id: ["input_boolean.toggle_3"],
|
||||||
},
|
},
|
||||||
@@ -200,7 +200,7 @@ export const basicTrace: DemoTrace = {
|
|||||||
params: {
|
params: {
|
||||||
domain: "input_boolean",
|
domain: "input_boolean",
|
||||||
service: "toggle",
|
service: "toggle",
|
||||||
service_data: {},
|
data: {},
|
||||||
target: {
|
target: {
|
||||||
entity_id: ["input_boolean.toggle_4"],
|
entity_id: ["input_boolean.toggle_4"],
|
||||||
},
|
},
|
||||||
@@ -298,11 +298,11 @@ export const basicTrace: DemoTrace = {
|
|||||||
source: "state of input_boolean.toggle_1",
|
source: "state of input_boolean.toggle_1",
|
||||||
entity_id: "automation.toggle_toggles",
|
entity_id: "automation.toggle_toggles",
|
||||||
context_id: "6cfcae368e7b3686fad6c59e83ae76c9",
|
context_id: "6cfcae368e7b3686fad6c59e83ae76c9",
|
||||||
when: "2021-03-25T04:36:51.240832+00:00",
|
when: 1616647011.240832,
|
||||||
domain: "automation",
|
domain: "automation",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
when: "2021-03-25T04:36:51.249828+00:00",
|
when: 1616647011.249828,
|
||||||
name: "Toggle 4",
|
name: "Toggle 4",
|
||||||
state: "on",
|
state: "on",
|
||||||
entity_id: "input_boolean.toggle_4",
|
entity_id: "input_boolean.toggle_4",
|
||||||
@@ -313,7 +313,7 @@ export const basicTrace: DemoTrace = {
|
|||||||
context_name: "Ensure Party mode",
|
context_name: "Ensure Party mode",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
when: "2021-03-25T04:36:51.258947+00:00",
|
when: 1616647011.258947,
|
||||||
name: "Toggle 2",
|
name: "Toggle 2",
|
||||||
state: "on",
|
state: "on",
|
||||||
entity_id: "input_boolean.toggle_2",
|
entity_id: "input_boolean.toggle_2",
|
||||||
@@ -324,7 +324,7 @@ export const basicTrace: DemoTrace = {
|
|||||||
context_name: "Ensure Party mode",
|
context_name: "Ensure Party mode",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
when: "2021-03-25T04:36:51.261806+00:00",
|
when: 1616647011.261806,
|
||||||
name: "Toggle 3",
|
name: "Toggle 3",
|
||||||
state: "off",
|
state: "off",
|
||||||
entity_id: "input_boolean.toggle_3",
|
entity_id: "input_boolean.toggle_3",
|
||||||
@@ -335,7 +335,7 @@ export const basicTrace: DemoTrace = {
|
|||||||
context_name: "Ensure Party mode",
|
context_name: "Ensure Party mode",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
when: "2021-03-25T04:36:51.265246+00:00",
|
when: 1616647011.265246,
|
||||||
name: "Toggle 4",
|
name: "Toggle 4",
|
||||||
state: "off",
|
state: "off",
|
||||||
entity_id: "input_boolean.toggle_4",
|
entity_id: "input_boolean.toggle_4",
|
||||||
|
@@ -185,11 +185,11 @@ export const motionLightTrace: DemoTrace = {
|
|||||||
"has been triggered by state of binary_sensor.pauluss_macbook_pro_camera_in_use",
|
"has been triggered by state of binary_sensor.pauluss_macbook_pro_camera_in_use",
|
||||||
source: "state of binary_sensor.pauluss_macbook_pro_camera_in_use",
|
source: "state of binary_sensor.pauluss_macbook_pro_camera_in_use",
|
||||||
entity_id: "automation.auto_elgato",
|
entity_id: "automation.auto_elgato",
|
||||||
when: "2021-03-14T06:07:01.768492+00:00",
|
when: 1615702021.768492,
|
||||||
domain: "automation",
|
domain: "automation",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
when: "2021-03-14T06:07:01.872187+00:00",
|
when: 1615702021.872187,
|
||||||
name: "Elgato Key Light Air",
|
name: "Elgato Key Light Air",
|
||||||
state: "on",
|
state: "on",
|
||||||
entity_id: "light.elgato_key_light_air",
|
entity_id: "light.elgato_key_light_air",
|
||||||
@@ -200,7 +200,7 @@ export const motionLightTrace: DemoTrace = {
|
|||||||
context_name: "Auto Elgato",
|
context_name: "Auto Elgato",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
when: "2021-03-14T06:07:53.284505+00:00",
|
when: 1615702073.284505,
|
||||||
name: "Elgato Key Light Air",
|
name: "Elgato Key Light Air",
|
||||||
state: "off",
|
state: "off",
|
||||||
entity_id: "light.elgato_key_light_air",
|
entity_id: "light.elgato_key_light_air",
|
||||||
|
@@ -1,96 +0,0 @@
|
|||||||
import { dump } from "js-yaml";
|
|
||||||
import { html, css, LitElement, TemplateResult } from "lit";
|
|
||||||
import { customElement, property } from "lit/decorators";
|
|
||||||
import "../../../src/components/ha-card";
|
|
||||||
import { describeAction } from "../../../src/data/script_i18n";
|
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
|
||||||
import { HomeAssistant } from "../../../src/types";
|
|
||||||
|
|
||||||
const actions = [
|
|
||||||
{ wait_template: "{{ true }}", alias: "Something with an alias" },
|
|
||||||
{ delay: "0:05" },
|
|
||||||
{ wait_template: "{{ true }}" },
|
|
||||||
{
|
|
||||||
condition: "template",
|
|
||||||
value_template: "{{ true }}",
|
|
||||||
},
|
|
||||||
{ event: "happy_event" },
|
|
||||||
{
|
|
||||||
device_id: "abcdefgh",
|
|
||||||
domain: "plex",
|
|
||||||
entity_id: "media_player.kitchen",
|
|
||||||
},
|
|
||||||
{ scene: "scene.kitchen_morning" },
|
|
||||||
{
|
|
||||||
wait_for_trigger: [
|
|
||||||
{
|
|
||||||
platform: "state",
|
|
||||||
entity_id: "input_boolean.toggle_1",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
variables: {
|
|
||||||
hello: "world",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
service: "input_boolean.toggle",
|
|
||||||
target: {
|
|
||||||
entity_id: "input_boolean.toggle_4",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
@customElement("demo-automation-describe-action")
|
|
||||||
export class DemoAutomationDescribeAction extends LitElement {
|
|
||||||
@property({ attribute: false }) hass!: HomeAssistant;
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
if (!this.hass) {
|
|
||||||
return html``;
|
|
||||||
}
|
|
||||||
return html`
|
|
||||||
<ha-card header="Actions">
|
|
||||||
${actions.map(
|
|
||||||
(conf) => html`
|
|
||||||
<div class="action">
|
|
||||||
<span>${describeAction(this.hass, conf as any)}</span>
|
|
||||||
<pre>${dump(conf)}</pre>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</ha-card>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected firstUpdated(changedProps) {
|
|
||||||
super.firstUpdated(changedProps);
|
|
||||||
const hass = provideHass(this);
|
|
||||||
hass.updateTranslations(null, "en");
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return css`
|
|
||||||
ha-card {
|
|
||||||
max-width: 600px;
|
|
||||||
margin: 24px auto;
|
|
||||||
}
|
|
||||||
.action {
|
|
||||||
padding: 16px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
span {
|
|
||||||
margin-right: 16px;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-automation-describe-action": DemoAutomationDescribeAction;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,60 +0,0 @@
|
|||||||
import { dump } from "js-yaml";
|
|
||||||
import { html, css, LitElement, TemplateResult } from "lit";
|
|
||||||
import { customElement } from "lit/decorators";
|
|
||||||
import "../../../src/components/ha-card";
|
|
||||||
import { describeCondition } from "../../../src/data/automation_i18n";
|
|
||||||
|
|
||||||
const conditions = [
|
|
||||||
{ condition: "and" },
|
|
||||||
{ condition: "not" },
|
|
||||||
{ condition: "or" },
|
|
||||||
{ condition: "state" },
|
|
||||||
{ condition: "numeric_state" },
|
|
||||||
{ condition: "sun", after: "sunset" },
|
|
||||||
{ condition: "sun", after: "sunrise" },
|
|
||||||
{ condition: "zone" },
|
|
||||||
{ condition: "time" },
|
|
||||||
{ condition: "template" },
|
|
||||||
];
|
|
||||||
|
|
||||||
@customElement("demo-automation-describe-condition")
|
|
||||||
export class DemoAutomationDescribeCondition extends LitElement {
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`
|
|
||||||
<ha-card header="Conditions">
|
|
||||||
${conditions.map(
|
|
||||||
(conf) => html`
|
|
||||||
<div class="condition">
|
|
||||||
<span>${describeCondition(conf as any)}</span>
|
|
||||||
<pre>${dump(conf)}</pre>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</ha-card>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return css`
|
|
||||||
ha-card {
|
|
||||||
max-width: 600px;
|
|
||||||
margin: 24px auto;
|
|
||||||
}
|
|
||||||
.condition {
|
|
||||||
padding: 16px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
span {
|
|
||||||
margin-right: 16px;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-automation-describe-condition": DemoAutomationDescribeCondition;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,63 +0,0 @@
|
|||||||
import { dump } from "js-yaml";
|
|
||||||
import { html, css, LitElement, TemplateResult } from "lit";
|
|
||||||
import { customElement } from "lit/decorators";
|
|
||||||
import "../../../src/components/ha-card";
|
|
||||||
import { describeTrigger } from "../../../src/data/automation_i18n";
|
|
||||||
|
|
||||||
const triggers = [
|
|
||||||
{ platform: "state" },
|
|
||||||
{ platform: "mqtt" },
|
|
||||||
{ platform: "geo_location" },
|
|
||||||
{ platform: "homeassistant" },
|
|
||||||
{ platform: "numeric_state" },
|
|
||||||
{ platform: "sun" },
|
|
||||||
{ platform: "time_pattern" },
|
|
||||||
{ platform: "webhook" },
|
|
||||||
{ platform: "zone" },
|
|
||||||
{ platform: "tag" },
|
|
||||||
{ platform: "time" },
|
|
||||||
{ platform: "template" },
|
|
||||||
{ platform: "event" },
|
|
||||||
];
|
|
||||||
|
|
||||||
@customElement("demo-automation-describe-trigger")
|
|
||||||
export class DemoAutomationDescribeTrigger extends LitElement {
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`
|
|
||||||
<ha-card header="Triggers">
|
|
||||||
${triggers.map(
|
|
||||||
(conf) => html`
|
|
||||||
<div class="trigger">
|
|
||||||
<span>${describeTrigger(conf as any)}</span>
|
|
||||||
<pre>${dump(conf)}</pre>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</ha-card>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return css`
|
|
||||||
ha-card {
|
|
||||||
max-width: 600px;
|
|
||||||
margin: 24px auto;
|
|
||||||
}
|
|
||||||
.trigger {
|
|
||||||
padding: 16px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
span {
|
|
||||||
margin-right: 16px;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-automation-describe-trigger": DemoAutomationDescribeTrigger;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,91 +0,0 @@
|
|||||||
/* eslint-disable lit/no-template-arrow */
|
|
||||||
import { LitElement, TemplateResult, html } from "lit";
|
|
||||||
import { customElement, state } from "lit/decorators";
|
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
|
||||||
import type { HomeAssistant } from "../../../src/types";
|
|
||||||
import "../components/demo-black-white-row";
|
|
||||||
import { mockEntityRegistry } from "../../../demo/src/stubs/entity_registry";
|
|
||||||
import { mockDeviceRegistry } from "../../../demo/src/stubs/device_registry";
|
|
||||||
import { mockAreaRegistry } from "../../../demo/src/stubs/area_registry";
|
|
||||||
import { mockHassioSupervisor } from "../../../demo/src/stubs/hassio_supervisor";
|
|
||||||
import "../../../src/panels/config/automation/action/ha-automation-action";
|
|
||||||
import { HaChooseAction } from "../../../src/panels/config/automation/action/types/ha-automation-action-choose";
|
|
||||||
import { HaDelayAction } from "../../../src/panels/config/automation/action/types/ha-automation-action-delay";
|
|
||||||
import { HaDeviceAction } from "../../../src/panels/config/automation/action/types/ha-automation-action-device_id";
|
|
||||||
import { HaEventAction } from "../../../src/panels/config/automation/action/types/ha-automation-action-event";
|
|
||||||
import { HaRepeatAction } from "../../../src/panels/config/automation/action/types/ha-automation-action-repeat";
|
|
||||||
import { HaSceneAction } from "../../../src/panels/config/automation/action/types/ha-automation-action-scene";
|
|
||||||
import { HaServiceAction } from "../../../src/panels/config/automation/action/types/ha-automation-action-service";
|
|
||||||
import { HaWaitForTriggerAction } from "../../../src/panels/config/automation/action/types/ha-automation-action-wait_for_trigger";
|
|
||||||
import { HaWaitAction } from "../../../src/panels/config/automation/action/types/ha-automation-action-wait_template";
|
|
||||||
import { Action } from "../../../src/data/script";
|
|
||||||
import { HaConditionAction } from "../../../src/panels/config/automation/action/types/ha-automation-action-condition";
|
|
||||||
|
|
||||||
const SCHEMAS: { name: string; actions: Action[] }[] = [
|
|
||||||
{ name: "Event", actions: [HaEventAction.defaultConfig] },
|
|
||||||
{ name: "Device", actions: [HaDeviceAction.defaultConfig] },
|
|
||||||
{ name: "Service", actions: [HaServiceAction.defaultConfig] },
|
|
||||||
{ name: "Condition", actions: [HaConditionAction.defaultConfig] },
|
|
||||||
{ name: "Delay", actions: [HaDelayAction.defaultConfig] },
|
|
||||||
{ name: "Scene", actions: [HaSceneAction.defaultConfig] },
|
|
||||||
{ name: "Wait", actions: [HaWaitAction.defaultConfig] },
|
|
||||||
{ name: "WaitForTrigger", actions: [HaWaitForTriggerAction.defaultConfig] },
|
|
||||||
{ name: "Repeat", actions: [HaRepeatAction.defaultConfig] },
|
|
||||||
{ name: "Choose", actions: [HaChooseAction.defaultConfig] },
|
|
||||||
{ name: "Variables", actions: [{ variables: { hello: "1" } }] },
|
|
||||||
];
|
|
||||||
|
|
||||||
@customElement("demo-automation-editor-action")
|
|
||||||
class DemoHaAutomationEditorAction extends LitElement {
|
|
||||||
@state() private hass!: HomeAssistant;
|
|
||||||
|
|
||||||
private data: any = SCHEMAS.map((info) => info.actions);
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
const hass = provideHass(this);
|
|
||||||
hass.updateTranslations(null, "en");
|
|
||||||
hass.updateTranslations("config", "en");
|
|
||||||
mockEntityRegistry(hass);
|
|
||||||
mockDeviceRegistry(hass);
|
|
||||||
mockAreaRegistry(hass);
|
|
||||||
mockHassioSupervisor(hass);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
const valueChanged = (ev) => {
|
|
||||||
const sampleIdx = ev.target.sampleIdx;
|
|
||||||
this.data[sampleIdx] = ev.detail.value;
|
|
||||||
this.requestUpdate();
|
|
||||||
};
|
|
||||||
return html`
|
|
||||||
${SCHEMAS.map(
|
|
||||||
(info, sampleIdx) => html`
|
|
||||||
<demo-black-white-row
|
|
||||||
.title=${info.name}
|
|
||||||
.value=${this.data[sampleIdx]}
|
|
||||||
>
|
|
||||||
${["light", "dark"].map(
|
|
||||||
(slot) =>
|
|
||||||
html`
|
|
||||||
<ha-automation-action
|
|
||||||
slot=${slot}
|
|
||||||
.hass=${this.hass}
|
|
||||||
.actions=${this.data[sampleIdx]}
|
|
||||||
.sampleIdx=${sampleIdx}
|
|
||||||
@value-changed=${valueChanged}
|
|
||||||
></ha-automation-action>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</demo-black-white-row>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-ha-automation-editor-action": DemoHaAutomationEditorAction;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,131 +0,0 @@
|
|||||||
/* eslint-disable lit/no-template-arrow */
|
|
||||||
import "@material/mwc-button";
|
|
||||||
import { LitElement, TemplateResult, css, html } from "lit";
|
|
||||||
import { customElement, state } from "lit/decorators";
|
|
||||||
import "../../../src/components/ha-selector/ha-selector";
|
|
||||||
import "../../../src/components/ha-settings-row";
|
|
||||||
import { provideHass } from "../../../src/fake_data/provide_hass";
|
|
||||||
import type { HomeAssistant } from "../../../src/types";
|
|
||||||
import "../components/demo-black-white-row";
|
|
||||||
import { BlueprintInput } from "../../../src/data/blueprint";
|
|
||||||
import { mockEntityRegistry } from "../../../demo/src/stubs/entity_registry";
|
|
||||||
import { mockDeviceRegistry } from "../../../demo/src/stubs/device_registry";
|
|
||||||
import { mockAreaRegistry } from "../../../demo/src/stubs/area_registry";
|
|
||||||
import { mockHassioSupervisor } from "../../../demo/src/stubs/hassio_supervisor";
|
|
||||||
|
|
||||||
const SCHEMAS: {
|
|
||||||
name: string;
|
|
||||||
input: Record<string, BlueprintInput | null>;
|
|
||||||
}[] = [
|
|
||||||
{
|
|
||||||
name: "One of each",
|
|
||||||
input: {
|
|
||||||
entity: { name: "Entity", selector: { entity: {} } },
|
|
||||||
device: { name: "Device", selector: { device: {} } },
|
|
||||||
addon: { name: "Addon", selector: { addon: {} } },
|
|
||||||
area: { name: "Area", selector: { area: {} } },
|
|
||||||
target: { name: "Target", selector: { target: {} } },
|
|
||||||
number_box: {
|
|
||||||
name: "Number Box",
|
|
||||||
selector: {
|
|
||||||
number: {
|
|
||||||
min: 0,
|
|
||||||
max: 10,
|
|
||||||
mode: "box",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
number_slider: {
|
|
||||||
name: "Number Slider",
|
|
||||||
selector: {
|
|
||||||
number: {
|
|
||||||
min: 0,
|
|
||||||
max: 10,
|
|
||||||
mode: "slider",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
boolean: { name: "Boolean", selector: { boolean: {} } },
|
|
||||||
time: { name: "Time", selector: { time: {} } },
|
|
||||||
action: { name: "Action", selector: { action: {} } },
|
|
||||||
text: { name: "Text", selector: { text: { multiline: false } } },
|
|
||||||
text_multiline: {
|
|
||||||
name: "Text multiline",
|
|
||||||
selector: { text: { multiline: true } },
|
|
||||||
},
|
|
||||||
object: { name: "Object", selector: { object: {} } },
|
|
||||||
select: {
|
|
||||||
name: "Select",
|
|
||||||
selector: { select: { options: ["Option 1", "Option 2"] } },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
@customElement("demo-ha-selector")
|
|
||||||
class DemoHaSelector extends LitElement {
|
|
||||||
@state() private hass!: HomeAssistant;
|
|
||||||
|
|
||||||
private data = SCHEMAS.map(() => ({}));
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
const hass = provideHass(this);
|
|
||||||
hass.updateTranslations(null, "en");
|
|
||||||
hass.updateTranslations("config", "en");
|
|
||||||
mockEntityRegistry(hass);
|
|
||||||
mockDeviceRegistry(hass);
|
|
||||||
mockAreaRegistry(hass);
|
|
||||||
mockHassioSupervisor(hass);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
|
||||||
return html`
|
|
||||||
${SCHEMAS.map((info, idx) => {
|
|
||||||
const data = this.data[idx];
|
|
||||||
const valueChanged = (ev) => {
|
|
||||||
this.data[idx] = {
|
|
||||||
...data,
|
|
||||||
[ev.target.key]: ev.detail.value,
|
|
||||||
};
|
|
||||||
this.requestUpdate();
|
|
||||||
};
|
|
||||||
return html`
|
|
||||||
<demo-black-white-row .title=${info.name} .value=${this.data[idx]}>
|
|
||||||
${["light", "dark"].map((slot) =>
|
|
||||||
Object.entries(info.input).map(
|
|
||||||
([key, value]) =>
|
|
||||||
html`
|
|
||||||
<ha-settings-row narrow slot=${slot}>
|
|
||||||
<span slot="heading">${value?.name || key}</span>
|
|
||||||
<span slot="description">${value?.description}</span>
|
|
||||||
<ha-selector
|
|
||||||
.hass=${this.hass}
|
|
||||||
.selector=${value!.selector}
|
|
||||||
.key=${key}
|
|
||||||
.value=${data[key] ?? value!.default}
|
|
||||||
@value-changed=${valueChanged}
|
|
||||||
></ha-selector>
|
|
||||||
</ha-settings-row>
|
|
||||||
`
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</demo-black-white-row>
|
|
||||||
`;
|
|
||||||
})}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static styles = css`
|
|
||||||
paper-input,
|
|
||||||
ha-selector {
|
|
||||||
width: 60;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"demo-ha-selector": DemoHaSelector;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,225 +0,0 @@
|
|||||||
import "@polymer/app-layout/app-header-layout/app-header-layout";
|
|
||||||
import "@polymer/app-layout/app-header/app-header";
|
|
||||||
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
|
||||||
import "@polymer/paper-item/paper-item";
|
|
||||||
import "@polymer/paper-item/paper-item-body";
|
|
||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
|
||||||
/* eslint-plugin-disable lit */
|
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
|
||||||
import "../../src/components/ha-card";
|
|
||||||
import "../../src/components/ha-icon";
|
|
||||||
import "../../src/components/ha-icon-button";
|
|
||||||
import "../../src/managers/notification-manager";
|
|
||||||
import "../../src/styles/polymer-ha-style";
|
|
||||||
// eslint-disable-next-line import/extensions
|
|
||||||
import { DEMOS } from "../build/import-demos";
|
|
||||||
|
|
||||||
class HaGallery extends PolymerElement {
|
|
||||||
static get template() {
|
|
||||||
return html`
|
|
||||||
<style include="iron-positioning ha-style">
|
|
||||||
:host {
|
|
||||||
-ms-user-select: initial;
|
|
||||||
-webkit-user-select: initial;
|
|
||||||
-moz-user-select: initial;
|
|
||||||
}
|
|
||||||
app-header-layout {
|
|
||||||
min-height: 100vh;
|
|
||||||
}
|
|
||||||
ha-icon-button.invisible {
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pickers {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: start;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pickers ha-card {
|
|
||||||
width: 400px;
|
|
||||||
display: block;
|
|
||||||
margin: 16px 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pickers ha-card:last-child {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.intro {
|
|
||||||
margin: -1em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
p a {
|
|
||||||
color: var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: var(--primary-text-color);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<app-header-layout>
|
|
||||||
<app-header slot="header" fixed>
|
|
||||||
<app-toolbar>
|
|
||||||
<ha-icon-button
|
|
||||||
on-click="_backTapped"
|
|
||||||
class$="[[_computeHeaderButtonClass(_demo)]]"
|
|
||||||
>
|
|
||||||
<ha-icon icon="hass:arrow-left"></ha-icon>
|
|
||||||
</ha-icon-button>
|
|
||||||
<div main-title>
|
|
||||||
[[_withDefault(_demo, "Home Assistant Gallery")]]
|
|
||||||
</div>
|
|
||||||
</app-toolbar>
|
|
||||||
</app-header>
|
|
||||||
|
|
||||||
<div class="content">
|
|
||||||
<div id="demo"></div>
|
|
||||||
<template is="dom-if" if="[[!_demo]]">
|
|
||||||
<div class="pickers">
|
|
||||||
<ha-card header="Lovelace Card Demos">
|
|
||||||
<div class="card-content intro">
|
|
||||||
<p>
|
|
||||||
Lovelace has many different cards. Each card allows the user
|
|
||||||
to tell a different story about what is going on in their
|
|
||||||
house. These cards are very customizable, as no household is
|
|
||||||
the same.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
This gallery helps our developers and designers to see all
|
|
||||||
the different states that each card can be in.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Check
|
|
||||||
<a href="https://www.home-assistant.io/lovelace"
|
|
||||||
>the official website</a
|
|
||||||
>
|
|
||||||
for instructions on how to get started with Lovelace.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<template is="dom-repeat" items="[[_lovelaceDemos]]">
|
|
||||||
<a href="#[[item]]">
|
|
||||||
<paper-item>
|
|
||||||
<paper-item-body>{{ item }}</paper-item-body>
|
|
||||||
<ha-icon icon="hass:chevron-right"></ha-icon>
|
|
||||||
</paper-item>
|
|
||||||
</a>
|
|
||||||
</template>
|
|
||||||
</ha-card>
|
|
||||||
|
|
||||||
<ha-card header="Other Demos">
|
|
||||||
<div class="card-content intro"></div>
|
|
||||||
<template is="dom-repeat" items="[[_restDemos]]">
|
|
||||||
<a href="#[[item]]">
|
|
||||||
<paper-item>
|
|
||||||
<paper-item-body>{{ item }}</paper-item-body>
|
|
||||||
<ha-icon icon="hass:chevron-right"></ha-icon>
|
|
||||||
</paper-item>
|
|
||||||
</a>
|
|
||||||
</template>
|
|
||||||
</ha-card>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</app-header-layout>
|
|
||||||
<notification-manager
|
|
||||||
hass="[[_fakeHass]]"
|
|
||||||
id="notifications"
|
|
||||||
></notification-manager>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
static get properties() {
|
|
||||||
return {
|
|
||||||
_fakeHass: {
|
|
||||||
type: Object,
|
|
||||||
// Just enough for computeRTL
|
|
||||||
value: {
|
|
||||||
language: "en",
|
|
||||||
translationMetadata: {
|
|
||||||
translations: {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
_demo: {
|
|
||||||
type: String,
|
|
||||||
value: document.location.hash.substr(1),
|
|
||||||
observer: "_demoChanged",
|
|
||||||
},
|
|
||||||
_demos: {
|
|
||||||
type: Array,
|
|
||||||
value: Object.keys(DEMOS),
|
|
||||||
},
|
|
||||||
_lovelaceDemos: {
|
|
||||||
type: Array,
|
|
||||||
computed: "_computeLovelace(_demos)",
|
|
||||||
},
|
|
||||||
_restDemos: {
|
|
||||||
type: Array,
|
|
||||||
computed: "_computeRest(_demos)",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
ready() {
|
|
||||||
super.ready();
|
|
||||||
|
|
||||||
this.addEventListener("show-notification", (ev) =>
|
|
||||||
this.$.notifications.showDialog({ message: ev.detail.message })
|
|
||||||
);
|
|
||||||
|
|
||||||
this.addEventListener("alert-dismissed-clicked", () =>
|
|
||||||
this.$.notifications.showDialog({ message: "Alert dismissed clicked" })
|
|
||||||
);
|
|
||||||
this.addEventListener("hass-more-info", (ev) => {
|
|
||||||
if (ev.detail.entityId) {
|
|
||||||
this.$.notifications.showDialog({
|
|
||||||
message: `Showing more info for ${ev.detail.entityId}`,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
window.addEventListener("hashchange", () => {
|
|
||||||
this._demo = document.location.hash.substr(1);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_withDefault(value, def) {
|
|
||||||
return value || def;
|
|
||||||
}
|
|
||||||
|
|
||||||
_demoChanged(demo) {
|
|
||||||
const root = this.$.demo;
|
|
||||||
|
|
||||||
while (root.lastChild) root.removeChild(root.lastChild);
|
|
||||||
|
|
||||||
if (demo) {
|
|
||||||
DEMOS[demo]();
|
|
||||||
const el = document.createElement(demo);
|
|
||||||
root.appendChild(el);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_computeHeaderButtonClass(demo) {
|
|
||||||
return demo ? "" : "invisible";
|
|
||||||
}
|
|
||||||
|
|
||||||
_backTapped() {
|
|
||||||
document.location.hash = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
_computeLovelace(demos) {
|
|
||||||
return demos.filter((demo) => demo.includes("hui"));
|
|
||||||
}
|
|
||||||
|
|
||||||
_computeRest(demos) {
|
|
||||||
return demos.filter((demo) => !demo.includes("hui"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
customElements.define("ha-gallery", HaGallery);
|
|
276
gallery/src/ha-gallery.ts
Normal file
276
gallery/src/ha-gallery.ts
Normal file
@@ -0,0 +1,276 @@
|
|||||||
|
import { mdiMenu } from "@mdi/js";
|
||||||
|
import "@material/mwc-drawer";
|
||||||
|
import "@material/mwc-top-app-bar-fixed";
|
||||||
|
import { html, css, LitElement, PropertyValues } from "lit";
|
||||||
|
import { customElement, property, query } from "lit/decorators";
|
||||||
|
import "../../src/components/ha-icon-button";
|
||||||
|
import "../../src/managers/notification-manager";
|
||||||
|
import { HaExpansionPanel } from "../../src/components/ha-expansion-panel";
|
||||||
|
import { haStyle } from "../../src/resources/styles";
|
||||||
|
import { PAGES, SIDEBAR } from "../build/import-pages";
|
||||||
|
import { dynamicElement } from "../../src/common/dom/dynamic-element-directive";
|
||||||
|
import "./components/page-description";
|
||||||
|
|
||||||
|
const GITHUB_DEMO_URL =
|
||||||
|
"https://github.com/home-assistant/frontend/blob/dev/gallery/src/pages/";
|
||||||
|
|
||||||
|
const FAKE_HASS = {
|
||||||
|
// Just enough for computeRTL for notification-manager
|
||||||
|
language: "en",
|
||||||
|
translationMetadata: {
|
||||||
|
translations: {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
@customElement("ha-gallery")
|
||||||
|
class HaGallery extends LitElement {
|
||||||
|
@property() private _page =
|
||||||
|
document.location.hash.substring(1) ||
|
||||||
|
`${SIDEBAR[0].category}/${SIDEBAR[0].pages![0]}`;
|
||||||
|
|
||||||
|
@query("notification-manager")
|
||||||
|
private _notifications!: HTMLElementTagNameMap["notification-manager"];
|
||||||
|
|
||||||
|
@query("mwc-drawer")
|
||||||
|
private _drawer!: HTMLElementTagNameMap["mwc-drawer"];
|
||||||
|
|
||||||
|
private _narrow = window.matchMedia("(max-width: 600px)").matches;
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const sidebar: unknown[] = [];
|
||||||
|
|
||||||
|
for (const group of SIDEBAR) {
|
||||||
|
const links: unknown[] = [];
|
||||||
|
|
||||||
|
for (const page of group.pages!) {
|
||||||
|
const key = `${group.category}/${page}`;
|
||||||
|
const active = this._page === key;
|
||||||
|
if (!(key in PAGES)) {
|
||||||
|
console.error("Undefined page referenced in sidebar.js:", key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const title = PAGES[key].metadata.title || page;
|
||||||
|
links.push(html`
|
||||||
|
<a ?active=${active} href=${`#${group.category}/${page}`}>${title}</a>
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
sidebar.push(
|
||||||
|
group.header
|
||||||
|
? html`
|
||||||
|
<ha-expansion-panel .header=${group.header}>
|
||||||
|
${links}
|
||||||
|
</ha-expansion-panel>
|
||||||
|
`
|
||||||
|
: links
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<mwc-drawer
|
||||||
|
hasHeader
|
||||||
|
.open=${!this._narrow}
|
||||||
|
.type=${this._narrow ? "modal" : "dismissible"}
|
||||||
|
>
|
||||||
|
<span slot="title">Home Assistant Design</span>
|
||||||
|
<!-- <span slot="subtitle">subtitle</span> -->
|
||||||
|
<div class="sidebar">${sidebar}</div>
|
||||||
|
<div slot="appContent">
|
||||||
|
<mwc-top-app-bar-fixed>
|
||||||
|
<ha-icon-button
|
||||||
|
slot="navigationIcon"
|
||||||
|
@click=${this._menuTapped}
|
||||||
|
.path=${mdiMenu}
|
||||||
|
></ha-icon-button>
|
||||||
|
|
||||||
|
<div slot="title">
|
||||||
|
${PAGES[this._page].metadata.title || this._page.split("/")[1]}
|
||||||
|
</div>
|
||||||
|
</mwc-top-app-bar-fixed>
|
||||||
|
<div class="content">
|
||||||
|
${PAGES[this._page].description
|
||||||
|
? html`
|
||||||
|
<page-description .page=${this._page}></page-description>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
${dynamicElement(`demo-${this._page.replace("/", "-")}`)}
|
||||||
|
</div>
|
||||||
|
<div class="page-footer">
|
||||||
|
<div class="header">Help us to improve our documentation</div>
|
||||||
|
<div class="secondary">
|
||||||
|
Suggest an edit to this page, or provide/view feedback for this
|
||||||
|
page.
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
${PAGES[this._page].description ||
|
||||||
|
Object.keys(PAGES[this._page].metadata).length > 0
|
||||||
|
? html`
|
||||||
|
<a
|
||||||
|
href=${`${GITHUB_DEMO_URL}${this._page}.markdown`}
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
Edit text
|
||||||
|
</a>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
${PAGES[this._page].demo
|
||||||
|
? html`
|
||||||
|
<a
|
||||||
|
href=${`${GITHUB_DEMO_URL}${this._page}.ts`}
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
Edit demo
|
||||||
|
</a>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</mwc-drawer>
|
||||||
|
<notification-manager
|
||||||
|
.hass=${FAKE_HASS}
|
||||||
|
id="notifications"
|
||||||
|
></notification-manager>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
firstUpdated(changedProps: PropertyValues) {
|
||||||
|
super.firstUpdated(changedProps);
|
||||||
|
|
||||||
|
this.addEventListener("show-notification", (ev) =>
|
||||||
|
this._notifications.showDialog({ message: ev.detail.message })
|
||||||
|
);
|
||||||
|
this.addEventListener("alert-dismissed-clicked", () =>
|
||||||
|
this._notifications.showDialog({ message: "Alert dismissed clicked" })
|
||||||
|
);
|
||||||
|
this.addEventListener("hass-more-info", (ev) => {
|
||||||
|
if (ev.detail.entityId) {
|
||||||
|
this._notifications.showDialog({
|
||||||
|
message: `Showing more info for ${ev.detail.entityId}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.location.hash = this._page;
|
||||||
|
|
||||||
|
window.addEventListener("hashchange", () => {
|
||||||
|
this._page = document.location.hash.substring(1);
|
||||||
|
if (this._narrow) {
|
||||||
|
this._drawer.open = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updated(changedProps: PropertyValues) {
|
||||||
|
super.updated(changedProps);
|
||||||
|
if (!changedProps.has("_page")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PAGES[this._page].demo) {
|
||||||
|
PAGES[this._page].demo();
|
||||||
|
}
|
||||||
|
|
||||||
|
const menuItem = this.shadowRoot!.querySelector(
|
||||||
|
`a[href="#${this._page}"]`
|
||||||
|
)!;
|
||||||
|
|
||||||
|
// Make sure section is expanded
|
||||||
|
if (menuItem.parentElement instanceof HaExpansionPanel) {
|
||||||
|
menuItem.parentElement.expanded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_menuTapped() {
|
||||||
|
this._drawer.open = !this._drawer.open;
|
||||||
|
}
|
||||||
|
|
||||||
|
static styles = [
|
||||||
|
haStyle,
|
||||||
|
css`
|
||||||
|
:host {
|
||||||
|
-ms-user-select: initial;
|
||||||
|
-webkit-user-select: initial;
|
||||||
|
-moz-user-select: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar {
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar a {
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
display: block;
|
||||||
|
padding: 12px;
|
||||||
|
text-decoration: none;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar a[active]::before {
|
||||||
|
border-radius: 12px;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 2px;
|
||||||
|
bottom: 0;
|
||||||
|
left: 2px;
|
||||||
|
pointer-events: none;
|
||||||
|
content: "";
|
||||||
|
transition: opacity 15ms linear;
|
||||||
|
will-change: opacity;
|
||||||
|
background-color: var(--sidebar-selected-icon-color);
|
||||||
|
opacity: 0.12;
|
||||||
|
}
|
||||||
|
|
||||||
|
div[slot="appContent"] {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 100vh;
|
||||||
|
background: var(--primary-background-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
page-description {
|
||||||
|
margin: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-footer {
|
||||||
|
text-align: center;
|
||||||
|
margin: 16px;
|
||||||
|
padding: 16px;
|
||||||
|
border-radius: 12px;
|
||||||
|
background-color: var(--primary-background-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-footer div {
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-footer .header {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 28px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-footer .secondary {
|
||||||
|
line-height: 23px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-footer a {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0 8px;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-gallery": HaGallery;
|
||||||
|
}
|
||||||
|
}
|
@@ -7,7 +7,7 @@
|
|||||||
content="width=device-width, initial-scale=1, shrink-to-fit=no"
|
content="width=device-width, initial-scale=1, shrink-to-fit=no"
|
||||||
/>
|
/>
|
||||||
<meta name="theme-color" content="#2157BC" />
|
<meta name="theme-color" content="#2157BC" />
|
||||||
<title>HAGallery</title>
|
<title>Home Assistant Design</title>
|
||||||
|
|
||||||
<script type="module" src="<%= latestGalleryJS %>"></script>
|
<script type="module" src="<%= latestGalleryJS %>"></script>
|
||||||
<style>
|
<style>
|
||||||
|
56
gallery/src/pages/Text/remove-delete-add-create.markdown
Normal file
56
gallery/src/pages/Text/remove-delete-add-create.markdown
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
---
|
||||||
|
title: When to use remove, delete, add and create
|
||||||
|
subtitle: The difference between remove/delete and add/create.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Remove vs Delete
|
||||||
|
Remove and Delete are quite similar, but can be frustrating if used inconsistently.
|
||||||
|
|
||||||
|
## Remove
|
||||||
|
Take away and set aside, but kept in existence.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
* Removing a user's permission
|
||||||
|
* Removing a user from a group
|
||||||
|
* Removing links between items
|
||||||
|
* Removing a widget
|
||||||
|
* Removing a link
|
||||||
|
* Removing an item from a cart
|
||||||
|
|
||||||
|
## Delete
|
||||||
|
Erase, rendered nonexistent or nonrecoverable.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
* Deleting a field
|
||||||
|
* Deleting a value in a field
|
||||||
|
* Deleting a task
|
||||||
|
* Deleting a group
|
||||||
|
* Deleting a permission
|
||||||
|
* Deleting a calendar event
|
||||||
|
|
||||||
|
# Add vs Create
|
||||||
|
In most cases, Create can be paired with Delete, and Add can be paired with Remove.
|
||||||
|
|
||||||
|
## Add
|
||||||
|
An already-exisiting item.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
* Adding a permission to a user
|
||||||
|
* Adding a user to a group
|
||||||
|
* Adding links between items
|
||||||
|
* Adding a widget
|
||||||
|
* Adding a link
|
||||||
|
* Adding an item to a cart
|
||||||
|
|
||||||
|
## Create
|
||||||
|
Something made from scratch.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
* Creating a new field
|
||||||
|
* Creating a new value in a field
|
||||||
|
* Creating a new task
|
||||||
|
* Creating a new group
|
||||||
|
* Creating a new permission
|
||||||
|
* Creating a new calendar event
|
||||||
|
|
||||||
|
Based on this is [UX magazine article](https://uxmag.com/articles/ui-copy-remove-vs-delete2-banner).
|
3
gallery/src/pages/automation/describe-action.markdown
Normal file
3
gallery/src/pages/automation/describe-action.markdown
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
title: Describe Action
|
||||||
|
---
|
199
gallery/src/pages/automation/describe-action.ts
Normal file
199
gallery/src/pages/automation/describe-action.ts
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
import { dump } from "js-yaml";
|
||||||
|
import { html, css, LitElement, TemplateResult } from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import "../../../../src/components/ha-card";
|
||||||
|
import "../../../../src/components/ha-yaml-editor";
|
||||||
|
import { Action } from "../../../../src/data/script";
|
||||||
|
import { describeAction } from "../../../../src/data/script_i18n";
|
||||||
|
import { getEntity } from "../../../../src/fake_data/entity";
|
||||||
|
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||||
|
import { HomeAssistant } from "../../../../src/types";
|
||||||
|
|
||||||
|
const ENTITIES = [
|
||||||
|
getEntity("scene", "kitchen_morning", "scening", {
|
||||||
|
friendly_name: "Kitchen Morning",
|
||||||
|
}),
|
||||||
|
getEntity("media_player", "kitchen", "playing", {
|
||||||
|
friendly_name: "Sonos Kitchen",
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
const ACTIONS = [
|
||||||
|
{ wait_template: "{{ true }}", alias: "Something with an alias" },
|
||||||
|
{ delay: "0:05" },
|
||||||
|
{ wait_template: "{{ true }}" },
|
||||||
|
{
|
||||||
|
condition: "template",
|
||||||
|
value_template: "{{ true }}",
|
||||||
|
},
|
||||||
|
{ event: "happy_event" },
|
||||||
|
{
|
||||||
|
device_id: "abcdefgh",
|
||||||
|
domain: "plex",
|
||||||
|
entity_id: "media_player.kitchen",
|
||||||
|
type: "turn_on",
|
||||||
|
},
|
||||||
|
{ scene: "scene.kitchen_morning" },
|
||||||
|
{
|
||||||
|
service: "scene.turn_on",
|
||||||
|
target: { entity_id: "scene.kitchen_morning" },
|
||||||
|
metadata: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
service: "media_player.play_media",
|
||||||
|
target: { entity_id: "media_player.kitchen" },
|
||||||
|
data: { media_content_id: "", media_content_type: "" },
|
||||||
|
metadata: { title: "Happy Song" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
wait_for_trigger: [
|
||||||
|
{
|
||||||
|
platform: "state",
|
||||||
|
entity_id: "input_boolean.toggle_1",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
variables: {
|
||||||
|
hello: "world",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
service: "input_boolean.toggle",
|
||||||
|
target: {
|
||||||
|
entity_id: "input_boolean.toggle_4",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parallel: [
|
||||||
|
{ scene: "scene.kitchen_morning" },
|
||||||
|
{
|
||||||
|
service: "media_player.play_media",
|
||||||
|
target: { entity_id: "media_player.living_room" },
|
||||||
|
data: { media_content_id: "", media_content_type: "" },
|
||||||
|
metadata: { title: "Happy Song" },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
stop: "No one is home!",
|
||||||
|
},
|
||||||
|
{ repeat: { count: 3, sequence: [{ delay: "00:00:01" }] } },
|
||||||
|
{
|
||||||
|
repeat: {
|
||||||
|
for_each: ["bread", "butter", "cheese"],
|
||||||
|
sequence: [{ delay: "00:00:01" }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
if: [{ condition: "state" }],
|
||||||
|
then: [{ delay: "00:00:01" }],
|
||||||
|
else: [{ delay: "00:00:05" }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
if: [{ condition: "state" }],
|
||||||
|
then: [{ delay: "00:00:01" }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
if: [{ condition: "state" }, { condition: "state" }],
|
||||||
|
then: [{ delay: "00:00:01" }],
|
||||||
|
else: [{ delay: "00:00:05" }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
choose: [
|
||||||
|
{
|
||||||
|
conditions: [{ condition: "state" }],
|
||||||
|
sequence: [{ delay: "00:00:01" }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conditions: [{ condition: "sun" }],
|
||||||
|
sequence: [{ delay: "00:00:05" }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: [{ delay: "00:00:03" }],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const initialAction: Action = {
|
||||||
|
service: "light.turn_on",
|
||||||
|
target: {
|
||||||
|
entity_id: "light.kitchen",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
@customElement("demo-automation-describe-action")
|
||||||
|
export class DemoAutomationDescribeAction extends LitElement {
|
||||||
|
@property({ attribute: false }) hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@state() _action = initialAction;
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this.hass) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
return html`
|
||||||
|
<ha-card header="Actions">
|
||||||
|
<div class="action">
|
||||||
|
<span>
|
||||||
|
${this._action
|
||||||
|
? describeAction(this.hass, this._action)
|
||||||
|
: "<invalid YAML>"}
|
||||||
|
</span>
|
||||||
|
<ha-yaml-editor
|
||||||
|
label="Action Config"
|
||||||
|
.defaultValue=${initialAction}
|
||||||
|
@value-changed=${this._dataChanged}
|
||||||
|
></ha-yaml-editor>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
${ACTIONS.map(
|
||||||
|
(conf) => html`
|
||||||
|
<div class="action">
|
||||||
|
<span>${describeAction(this.hass, conf as any)}</span>
|
||||||
|
<pre>${dump(conf)}</pre>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</ha-card>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected firstUpdated(changedProps) {
|
||||||
|
super.firstUpdated(changedProps);
|
||||||
|
const hass = provideHass(this);
|
||||||
|
hass.updateTranslations(null, "en");
|
||||||
|
hass.addEntities(ENTITIES);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _dataChanged(ev: CustomEvent): void {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this._action = ev.detail.isValid ? ev.detail.value : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return css`
|
||||||
|
ha-card {
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 24px auto;
|
||||||
|
}
|
||||||
|
.action {
|
||||||
|
padding: 16px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
ha-yaml-editor {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"demo-automation-describe-action": DemoAutomationDescribeAction;
|
||||||
|
}
|
||||||
|
}
|
3
gallery/src/pages/automation/describe-condition.markdown
Normal file
3
gallery/src/pages/automation/describe-condition.markdown
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
title: Describe Condition
|
||||||
|
---
|
126
gallery/src/pages/automation/describe-condition.ts
Normal file
126
gallery/src/pages/automation/describe-condition.ts
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
import { dump } from "js-yaml";
|
||||||
|
import { css, html, LitElement, TemplateResult } from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import "../../../../src/components/ha-card";
|
||||||
|
import "../../../../src/components/ha-yaml-editor";
|
||||||
|
import { Condition } from "../../../../src/data/automation";
|
||||||
|
import { describeCondition } from "../../../../src/data/automation_i18n";
|
||||||
|
import { getEntity } from "../../../../src/fake_data/entity";
|
||||||
|
import { provideHass } from "../../../../src/fake_data/provide_hass";
|
||||||
|
import { HomeAssistant } from "../../../../src/types";
|
||||||
|
|
||||||
|
const ENTITIES = [
|
||||||
|
getEntity("light", "kitchen", "on", {
|
||||||
|
friendly_name: "Kitchen Light",
|
||||||
|
}),
|
||||||
|
getEntity("device_tracker", "person", "home", {
|
||||||
|
friendly_name: "Person",
|
||||||
|
}),
|
||||||
|
getEntity("zone", "home", "", {
|
||||||
|
friendly_name: "Home",
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
const conditions = [
|
||||||
|
{ condition: "and" },
|
||||||
|
{ condition: "not" },
|
||||||
|
{ condition: "or" },
|
||||||
|
{ condition: "state", entity_id: "light.kitchen", state: "on" },
|
||||||
|
{
|
||||||
|
condition: "numeric_state",
|
||||||
|
entity_id: "light.kitchen",
|
||||||
|
attribute: "brightness",
|
||||||
|
below: 80,
|
||||||
|
above: 20,
|
||||||
|
},
|
||||||
|
{ condition: "sun", after: "sunset" },
|
||||||
|
{ condition: "sun", after: "sunrise", offset: "-01:00" },
|
||||||
|
{ condition: "zone", entity_id: "device_tracker.person", zone: "zone.home" },
|
||||||
|
{ condition: "trigger", id: "motion" },
|
||||||
|
{ condition: "time" },
|
||||||
|
{ condition: "template" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const initialCondition: Condition = {
|
||||||
|
condition: "state",
|
||||||
|
entity_id: "light.kitchen",
|
||||||
|
state: "on",
|
||||||
|
};
|
||||||
|
|
||||||
|
@customElement("demo-automation-describe-condition")
|
||||||
|
export class DemoAutomationDescribeCondition extends LitElement {
|
||||||
|
@property({ attribute: false }) hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@state() _condition = initialCondition;
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this.hass) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<ha-card header="Conditions">
|
||||||
|
<div class="condition">
|
||||||
|
<span>
|
||||||
|
${this._condition
|
||||||
|
? describeCondition(this._condition, this.hass)
|
||||||
|
: "<invalid YAML>"}
|
||||||
|
</span>
|
||||||
|
<ha-yaml-editor
|
||||||
|
label="Condition Config"
|
||||||
|
.defaultValue=${initialCondition}
|
||||||
|
@value-changed=${this._dataChanged}
|
||||||
|
></ha-yaml-editor>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
${conditions.map(
|
||||||
|
(conf) => html`
|
||||||
|
<div class="condition">
|
||||||
|
<span>${describeCondition(conf as any, this.hass)}</span>
|
||||||
|
<pre>${dump(conf)}</pre>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</ha-card>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected firstUpdated(changedProps) {
|
||||||
|
super.firstUpdated(changedProps);
|
||||||
|
const hass = provideHass(this);
|
||||||
|
hass.updateTranslations(null, "en");
|
||||||
|
hass.addEntities(ENTITIES);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _dataChanged(ev: CustomEvent): void {
|
||||||
|
ev.stopPropagation();
|
||||||
|
this._condition = ev.detail.isValid ? ev.detail.value : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return css`
|
||||||
|
ha-card {
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 24px auto;
|
||||||
|
}
|
||||||
|
.condition {
|
||||||
|
padding: 16px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
ha-yaml-editor {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"demo-automation-describe-condition": DemoAutomationDescribeCondition;
|
||||||
|
}
|
||||||
|
}
|
3
gallery/src/pages/automation/describe-trigger.markdown
Normal file
3
gallery/src/pages/automation/describe-trigger.markdown
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
title: Describe Trigger
|
||||||
|
---
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user