mirror of
https://github.com/home-assistant/frontend.git
synced 2026-10-29 09:04:22 +00:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5868059ac0 | ||
|
|
fe90b0339d | ||
|
|
3b5ba802f6 | ||
|
|
b0c6e7f564 | ||
|
|
658a23724e | ||
|
|
f859183628 | ||
|
|
53dc14f413 |
No files matched your search
+3
-3
@@ -78,8 +78,8 @@
|
||||
"@mdi/svg": "7.4.47",
|
||||
"@replit/codemirror-indentation-markers": "6.5.3",
|
||||
"@swc/helpers": "0.5.23",
|
||||
"@tsparticles/engine": "4.4.0",
|
||||
"@tsparticles/preset-links": "4.4.0",
|
||||
"@tsparticles/engine": "4.5.0",
|
||||
"@tsparticles/preset-links": "4.5.0",
|
||||
"@versatiles/style": "7.0.1",
|
||||
"@vibrant/color": "4.0.4",
|
||||
"@vvo/tzdb": "6.201.1",
|
||||
@@ -154,7 +154,7 @@
|
||||
"@playwright/test": "1.64.1",
|
||||
"@rsdoctor/rspack-plugin": "1.6.5",
|
||||
"@rspack/core": "2.2.9",
|
||||
"@rspack/dev-server": "2.2.1",
|
||||
"@rspack/dev-server": "2.2.2",
|
||||
"@types/babel__plugin-transform-runtime": "7.9.5",
|
||||
"@types/chromecast-caf-receiver": "7.0.1",
|
||||
"@types/chromecast-caf-sender": "1.0.11",
|
||||
|
||||
Generated
+112
-112
@@ -295,11 +295,11 @@ importers:
|
||||
specifier: 0.5.23
|
||||
version: 0.5.23
|
||||
'@tsparticles/engine':
|
||||
specifier: 4.4.0
|
||||
version: 4.4.0
|
||||
specifier: 4.5.0
|
||||
version: 4.5.0
|
||||
'@tsparticles/preset-links':
|
||||
specifier: 4.4.0
|
||||
version: 4.4.0
|
||||
specifier: 4.5.0
|
||||
version: 4.5.0
|
||||
'@versatiles/style':
|
||||
specifier: 7.0.1
|
||||
version: 7.0.1([email protected])
|
||||
@@ -518,8 +518,8 @@ importers:
|
||||
specifier: 2.2.9
|
||||
version: 2.2.9(@swc/[email protected])
|
||||
'@rspack/dev-server':
|
||||
specifier: 2.2.1
|
||||
version: 2.2.1(@rspack/[email protected](@swc/[email protected]))
|
||||
specifier: 2.2.2
|
||||
version: 2.2.2(@rspack/[email protected](@swc/[email protected]))
|
||||
'@types/babel__plugin-transform-runtime':
|
||||
specifier: 7.9.5
|
||||
version: 7.9.5
|
||||
@@ -2990,8 +2990,8 @@ packages:
|
||||
'@swc/helpers':
|
||||
optional: true
|
||||
|
||||
'@rspack/[email protected].3':
|
||||
resolution: {integrity: sha512-GxnGj9jy76G3eCPyZei81fwKLAMLZaPEEqFz1/QDYquhwi/qYZX5fekFJ1XVpuwxGEK9KSX3hxZylfwrs4cmLA==}
|
||||
'@rspack/[email protected].6':
|
||||
resolution: {integrity: sha512-Rcx7dlDZQ9ddUJGuutFvnSeAKl+ZOc1fnC3htibs8yew3zMD9VgvSUe4MAwEn94Gb390l5heA+s/j5KhoSG5MQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
peerDependencies:
|
||||
'@rspack/core': ^2.0.0
|
||||
@@ -2999,8 +2999,8 @@ packages:
|
||||
'@rspack/core':
|
||||
optional: true
|
||||
|
||||
'@rspack/[email protected].1':
|
||||
resolution: {integrity: sha512-Il8HbYGK3rH5rM0XmUOsOGZVw69BKRpBZ61P28Fy8ry35CtfniDBWtbo/rvJtIT/sK0qwijmNrhF498ltsV+uA==}
|
||||
'@rspack/[email protected].2':
|
||||
resolution: {integrity: sha512-pK4V9YJW8dkfjy6WYJ2T6DrPkcIn2yjA1HiaU146141j8UCxHok5lsplyqudLzerOhvwqMrNFmnsuXLnFbfn4Q==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
peerDependencies:
|
||||
'@rspack/core': ^2.0.0
|
||||
@@ -3156,85 +3156,85 @@ packages:
|
||||
resolution: {integrity: sha512-/67zpWDBLV+oYAEL682s1ktXL0HgqX76f6gaVGkGnVZlBbm1zd0v4Bz8MFF2GGhoX9rvfq3KSQHubFHwa6w6/Q==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
'@tsparticles/animation-utils@4.4.0':
|
||||
resolution: {integrity: sha512-yl4iE9SSuJ2n8B096t/vn4bWN+wWIkDm11OfTsIM3/64bJLB/5T92n6iOm/XLC3r6g8M8XuDi6ntTnpOcwsGxg==}
|
||||
'@tsparticles/animation-utils@4.5.0':
|
||||
resolution: {integrity: sha512-jIcPbhaA7X9gIEzUOsw63Vn7558ZLRbPeAodfzvIEo+VYhmnKOCrnf7e91THZ2XoFYjRQkkOt94uJfT8bma1TQ==}
|
||||
peerDependencies:
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/engine': 4.5.0
|
||||
|
||||
'@tsparticles/basic@4.4.0':
|
||||
resolution: {integrity: sha512-lTbKBPzab0alPy+4Wm/xehrVpT1FrpEMaQcTU2eTV0c0G++5/kOINEWkC7GL7/cHovycukxB+tOMYVT54bSprA==}
|
||||
'@tsparticles/basic@4.5.0':
|
||||
resolution: {integrity: sha512-4yZucXSWNeHh5NXjJ1is4aiq1Fi8hW5gBTrlWbIm7JcqBjUxNkYCqdLKvOCR/5bnToqjtezBJWlArwBdbzuU6w==}
|
||||
|
||||
'@tsparticles/canvas-utils@4.4.0':
|
||||
resolution: {integrity: sha512-3zVr95OZ05BExgVYNT8WPqA/wFp83TiEJo66rZCZ/nZd1Ny8UCYLMKBcbUPBvGS2GB87UMK8+ygleZnlFhGTtw==}
|
||||
'@tsparticles/canvas-utils@4.5.0':
|
||||
resolution: {integrity: sha512-Yu/lxI9DzJvcvXSLlqEc7j/1B9f3A/Wa2yK6R+fn3ysDmf4CUVdjOiwa5Y65LlvvSpZMfBLbPoIgkwnCSbYaow==}
|
||||
peerDependencies:
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/engine': 4.5.0
|
||||
|
||||
'@tsparticles/engine@4.4.0':
|
||||
resolution: {integrity: sha512-zUDykZ7qBqHYMXr6NveXg51kBlvfaQKMmWkMJ8nT7fC4dXdNayb1+TxOfAoqH9/U/u0Eyr0YE+72ai/ymS0uww==}
|
||||
'@tsparticles/engine@4.5.0':
|
||||
resolution: {integrity: sha512-ClhG2dxDU7HUAqCHGQZLgyIQRJFhuuCFCnNowSB9znuoNrxSeln4UKVBbRRv/994Eoi5OHuHuGaK9iw6ZeT21g==}
|
||||
|
||||
'@tsparticles/interaction-particles-links@4.4.0':
|
||||
resolution: {integrity: sha512-n2OkzB8BjQkzFrtiVq8O42/Tf+/Psng+K71MhJDI+czkwLo3PdmG51MCsy2w9ywCvGwWci2nwxMQ1qZL7nPONg==}
|
||||
'@tsparticles/interaction-particles-links@4.5.0':
|
||||
resolution: {integrity: sha512-L6F7eJdFVn3JsulaKrIwnl52rE9EazfMrNIUpa829PRoi/30BPOmRP469EKjdv3mntiwjUXgWFx8NDj+iQkJgw==}
|
||||
peerDependencies:
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/plugin-interactivity': 4.4.0
|
||||
'@tsparticles/engine': 4.5.0
|
||||
'@tsparticles/plugin-interactivity': 4.5.0
|
||||
|
||||
'@tsparticles/plugin-blend@4.4.0':
|
||||
resolution: {integrity: sha512-X/SG2WIasgHqA+fLZFu6MMv3z5VY5uX4VIfKjXz1qxZjEjn0w4kzZrbtZBxXxRKdrm8Dg8Qu2mmBokNZ8Bny3g==}
|
||||
'@tsparticles/plugin-blend@4.5.0':
|
||||
resolution: {integrity: sha512-iTy4OajUDyDHyYVh2NaUZjKwzrjFfiGLiWl1I04dli417Ecmwfq/pU6leX/SIARVAqdvaeZOwFg4YmIN+zvv6w==}
|
||||
peerDependencies:
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/engine': 4.5.0
|
||||
|
||||
'@tsparticles/plugin-hex-color@4.4.0':
|
||||
resolution: {integrity: sha512-sbRW6fi/YOS/hvFi6GCQiKI2zMCrmydrhlzqWyw2UUyg4Rr3FviQbIC2VRZrMc30Cm6kSkR3SovXIFDpZzO94Q==}
|
||||
'@tsparticles/plugin-hex-color@4.5.0':
|
||||
resolution: {integrity: sha512-yO3Rw27rR4ZpJo8IuBp0br1GXaju7iUl4u8zVD8WNcig7bbgoZqzhFhofgQYY9UPLVLyG1dnn8aODsk5Rq0X2g==}
|
||||
peerDependencies:
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/engine': 4.5.0
|
||||
|
||||
'@tsparticles/plugin-hsl-color@4.4.0':
|
||||
resolution: {integrity: sha512-nw/7cGoU99y8veeYD7yA7ygNyrGr461V9xx+ed+jrj0LyXQbLF3d/r78ovMseoHxm4SWa9pmtoQxS3fBHIgecw==}
|
||||
'@tsparticles/plugin-hsl-color@4.5.0':
|
||||
resolution: {integrity: sha512-6AyFRVVXyHb4NrytzwKoCIUhSD/ZXIIr1av2z7cNgaLJCZ00qrur/G7FJhK1XUBNR4DV6/hYhP9ohSfrEhdZ+Q==}
|
||||
peerDependencies:
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/engine': 4.5.0
|
||||
|
||||
'@tsparticles/plugin-interactivity@4.4.0':
|
||||
resolution: {integrity: sha512-jquoxlT4ra1Mc4glVlIfPubmchyIq5IZ25RdnvAop1uuc+6tu4N1zq5SSeyRO8MhJ94xevsNe6ozjmqvZ9CzKA==}
|
||||
'@tsparticles/plugin-interactivity@4.5.0':
|
||||
resolution: {integrity: sha512-Ydxd29SRldhjbvf5IIhu5NIfCAW2LdqSk6aN60zJb6AupV+wxztJ4/e4JL1t0ymj9992iQSVD9nQql4yzbdOwA==}
|
||||
peerDependencies:
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/engine': 4.5.0
|
||||
|
||||
'@tsparticles/plugin-move@4.4.0':
|
||||
resolution: {integrity: sha512-o05YP6bWxljbxmsQoqbay8sn4GtHIiTQZhZmcIyxJw/q+oSCNKHWALElSAqa1H7Dp/7ltnmd4rH4pgbQtHnfEw==}
|
||||
'@tsparticles/plugin-move@4.5.0':
|
||||
resolution: {integrity: sha512-0lkYVygqc30SqBiuviI900fBKPHkJJyuZVpUBSolGSTz7J1P49PXKqy1az6f+ub42SZxFcGOChtQ5vwpZSh0Gg==}
|
||||
peerDependencies:
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/engine': 4.5.0
|
||||
|
||||
'@tsparticles/plugin-rgb-color@4.4.0':
|
||||
resolution: {integrity: sha512-s7YlsrcjndVLiOgKNPQaPcEQmmZeZqHec0lpSbt8BgR2pQmjFvCMSzHDA/aaqZ6JX8iVqvj+bT8uqT5XQDq70Q==}
|
||||
'@tsparticles/plugin-rgb-color@4.5.0':
|
||||
resolution: {integrity: sha512-DBhtOO82K2kLaFginNEGfgfKoSXycj0eJzCHp2kSQ0HjKkpwINdK2nFh2QXfsYfjP1fQbLaIu3CuJG/VmjkDvw==}
|
||||
peerDependencies:
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/engine': 4.5.0
|
||||
|
||||
'@tsparticles/preset-links@4.4.0':
|
||||
resolution: {integrity: sha512-skdPsg/3AgBFtv0vrn20KrPGbIa0AdZw812Avg86BW7NqVGeX3JLyowZbFRQTPU13CcUo9YXCeJccoZv6FovOw==}
|
||||
'@tsparticles/preset-links@4.5.0':
|
||||
resolution: {integrity: sha512-Itwr6ECwf3ORiroUvLAwwg8O66IT3tQ2CFdml6A0u3ze1kfBmL9JT/u9UYG4QFICT0qjE86pkXpFRv8NwWLkBw==}
|
||||
|
||||
'@tsparticles/shape-circle@4.4.0':
|
||||
resolution: {integrity: sha512-pCdCenLohHwaeeuMCw9bh1icGB+CKwBYx67L5dTBw6aig7LRvL+Kd1PKClJTgXkx8Mb1Xb7KLNmSYgh/ABRtEQ==}
|
||||
'@tsparticles/shape-circle@4.5.0':
|
||||
resolution: {integrity: sha512-6fyvghJFvUMokKIQU6p7KKwcX3pTnp6gizj/occVTnar8AxxOlXNjK1J019etwnqdLbSWU/E7Qdt7y4zCTPD1A==}
|
||||
peerDependencies:
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/engine': 4.5.0
|
||||
|
||||
'@tsparticles/updater-opacity@4.4.0':
|
||||
resolution: {integrity: sha512-StQAExNqeOHANRAMXHdaKKEBD1DrRwBZ3TQF6DPtERtoElj8BvMlPHq38W0TSzfvR0lFP91p2Pzo5txVzVJ3Gg==}
|
||||
'@tsparticles/updater-opacity@4.5.0':
|
||||
resolution: {integrity: sha512-808wb6KUe1wYzth/hJBMzcLDsApmES4FHOavoulyQmSJdWfiNED4LjoX2MNJg4ry56wtg9IXS7qa8XaqdekQYA==}
|
||||
peerDependencies:
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/engine': 4.5.0
|
||||
|
||||
'@tsparticles/updater-out-modes@4.4.0':
|
||||
resolution: {integrity: sha512-IzHaYhOVI6mBFqub1ivd/5UMkvn5Pb/j9xS8edT7XeSNYqO3UeomLJci0KE6Xsm+4K/kBLGbCRW5+Tf+kV4E0g==}
|
||||
'@tsparticles/updater-out-modes@4.5.0':
|
||||
resolution: {integrity: sha512-fOzj/2nUtwPK7A+1WN+EnQZtLPBI8++hxkgOHr+RIEGo2d9K4qOgoIxI1zpa6WHt9fSXCk4rWsjENpc++pB+JQ==}
|
||||
peerDependencies:
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/engine': 4.5.0
|
||||
|
||||
'@tsparticles/updater-paint@4.4.0':
|
||||
resolution: {integrity: sha512-v7liuaT9BwHsd1hCfJF2d93M2gD3lSfsfIfKjPihAYo73hS43Wq7Cf1F0yjEiR3yXryRGH1QmYYdhonKAvyDKw==}
|
||||
'@tsparticles/updater-paint@4.5.0':
|
||||
resolution: {integrity: sha512-BJK3De1UZW01uyIk5AJVW4ex2ejEfoU5Vqw512Ox/kGipx3qXsaROTbh/9+NbqMtRyDtYuDc5PgGWIWTyYb7TQ==}
|
||||
peerDependencies:
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/engine': 4.5.0
|
||||
|
||||
'@tsparticles/updater-size@4.4.0':
|
||||
resolution: {integrity: sha512-Qq8QjC0MMjlaHjtpWUROSqe14eKVphq92n0VR4/d4WY+pnSG1U1VJzF43Kyfb4IyV06b29F0TUROIG7Ivqk36g==}
|
||||
'@tsparticles/updater-size@4.5.0':
|
||||
resolution: {integrity: sha512-42AZGbnWUmIL7giRaerPauYHaX2Agx482+8dq3hBYvvc0vM4Pks/fhpaKtTCAGG4CJb3fvaiyRrF7T75CQVAdQ==}
|
||||
peerDependencies:
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/engine': 4.5.0
|
||||
|
||||
'@tufjs/[email protected]':
|
||||
resolution: {integrity: sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==}
|
||||
@@ -10675,14 +10675,14 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@swc/helpers': 0.5.23
|
||||
|
||||
'@rspack/[email protected].3(@rspack/[email protected](@swc/[email protected]))':
|
||||
'@rspack/[email protected].6(@rspack/[email protected](@swc/[email protected]))':
|
||||
optionalDependencies:
|
||||
'@rspack/core': 2.2.9(@swc/[email protected])
|
||||
|
||||
'@rspack/[email protected].1(@rspack/[email protected](@swc/[email protected]))':
|
||||
'@rspack/[email protected].2(@rspack/[email protected](@swc/[email protected]))':
|
||||
dependencies:
|
||||
'@rspack/core': 2.2.9(@swc/[email protected])
|
||||
'@rspack/dev-middleware': 2.0.3(@rspack/[email protected](@swc/[email protected]))
|
||||
'@rspack/dev-middleware': 2.0.6(@rspack/[email protected](@swc/[email protected]))
|
||||
|
||||
'@rspack/[email protected]': {}
|
||||
|
||||
@@ -10844,88 +10844,88 @@ snapshots:
|
||||
magic-string: 0.30.21
|
||||
string.prototype.matchall: 4.0.12
|
||||
|
||||
'@tsparticles/animation-utils@4.4.0(@tsparticles/engine@4.4.0)':
|
||||
'@tsparticles/animation-utils@4.5.0(@tsparticles/engine@4.5.0)':
|
||||
dependencies:
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/engine': 4.5.0
|
||||
|
||||
'@tsparticles/basic@4.4.0':
|
||||
'@tsparticles/basic@4.5.0':
|
||||
dependencies:
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/plugin-blend': 4.4.0(@tsparticles/engine@4.4.0)
|
||||
'@tsparticles/plugin-hex-color': 4.4.0(@tsparticles/engine@4.4.0)
|
||||
'@tsparticles/plugin-hsl-color': 4.4.0(@tsparticles/engine@4.4.0)
|
||||
'@tsparticles/plugin-move': 4.4.0(@tsparticles/engine@4.4.0)
|
||||
'@tsparticles/plugin-rgb-color': 4.4.0(@tsparticles/engine@4.4.0)
|
||||
'@tsparticles/shape-circle': 4.4.0(@tsparticles/engine@4.4.0)
|
||||
'@tsparticles/updater-opacity': 4.4.0(@tsparticles/engine@4.4.0)
|
||||
'@tsparticles/updater-out-modes': 4.4.0(@tsparticles/engine@4.4.0)
|
||||
'@tsparticles/updater-paint': 4.4.0(@tsparticles/engine@4.4.0)
|
||||
'@tsparticles/updater-size': 4.4.0(@tsparticles/engine@4.4.0)
|
||||
'@tsparticles/engine': 4.5.0
|
||||
'@tsparticles/plugin-blend': 4.5.0(@tsparticles/engine@4.5.0)
|
||||
'@tsparticles/plugin-hex-color': 4.5.0(@tsparticles/engine@4.5.0)
|
||||
'@tsparticles/plugin-hsl-color': 4.5.0(@tsparticles/engine@4.5.0)
|
||||
'@tsparticles/plugin-move': 4.5.0(@tsparticles/engine@4.5.0)
|
||||
'@tsparticles/plugin-rgb-color': 4.5.0(@tsparticles/engine@4.5.0)
|
||||
'@tsparticles/shape-circle': 4.5.0(@tsparticles/engine@4.5.0)
|
||||
'@tsparticles/updater-opacity': 4.5.0(@tsparticles/engine@4.5.0)
|
||||
'@tsparticles/updater-out-modes': 4.5.0(@tsparticles/engine@4.5.0)
|
||||
'@tsparticles/updater-paint': 4.5.0(@tsparticles/engine@4.5.0)
|
||||
'@tsparticles/updater-size': 4.5.0(@tsparticles/engine@4.5.0)
|
||||
|
||||
'@tsparticles/canvas-utils@4.4.0(@tsparticles/engine@4.4.0)':
|
||||
'@tsparticles/canvas-utils@4.5.0(@tsparticles/engine@4.5.0)':
|
||||
dependencies:
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/engine': 4.5.0
|
||||
|
||||
'@tsparticles/engine@4.4.0': {}
|
||||
'@tsparticles/engine@4.5.0': {}
|
||||
|
||||
'@tsparticles/interaction-particles-links@4.4.0(@tsparticles/engine@4.4.0)(@tsparticles/plugin-interactivity@4.4.0(@tsparticles/engine@4.4.0))':
|
||||
'@tsparticles/interaction-particles-links@4.5.0(@tsparticles/engine@4.5.0)(@tsparticles/plugin-interactivity@4.5.0(@tsparticles/engine@4.5.0))':
|
||||
dependencies:
|
||||
'@tsparticles/canvas-utils': 4.4.0(@tsparticles/engine@4.4.0)
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/plugin-interactivity': 4.4.0(@tsparticles/engine@4.4.0)
|
||||
'@tsparticles/canvas-utils': 4.5.0(@tsparticles/engine@4.5.0)
|
||||
'@tsparticles/engine': 4.5.0
|
||||
'@tsparticles/plugin-interactivity': 4.5.0(@tsparticles/engine@4.5.0)
|
||||
|
||||
'@tsparticles/plugin-blend@4.4.0(@tsparticles/engine@4.4.0)':
|
||||
'@tsparticles/plugin-blend@4.5.0(@tsparticles/engine@4.5.0)':
|
||||
dependencies:
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/engine': 4.5.0
|
||||
|
||||
'@tsparticles/plugin-hex-color@4.4.0(@tsparticles/engine@4.4.0)':
|
||||
'@tsparticles/plugin-hex-color@4.5.0(@tsparticles/engine@4.5.0)':
|
||||
dependencies:
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/engine': 4.5.0
|
||||
|
||||
'@tsparticles/plugin-hsl-color@4.4.0(@tsparticles/engine@4.4.0)':
|
||||
'@tsparticles/plugin-hsl-color@4.5.0(@tsparticles/engine@4.5.0)':
|
||||
dependencies:
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/engine': 4.5.0
|
||||
|
||||
'@tsparticles/plugin-interactivity@4.4.0(@tsparticles/engine@4.4.0)':
|
||||
'@tsparticles/plugin-interactivity@4.5.0(@tsparticles/engine@4.5.0)':
|
||||
dependencies:
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/engine': 4.5.0
|
||||
|
||||
'@tsparticles/plugin-move@4.4.0(@tsparticles/engine@4.4.0)':
|
||||
'@tsparticles/plugin-move@4.5.0(@tsparticles/engine@4.5.0)':
|
||||
dependencies:
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/engine': 4.5.0
|
||||
|
||||
'@tsparticles/plugin-rgb-color@4.4.0(@tsparticles/engine@4.4.0)':
|
||||
'@tsparticles/plugin-rgb-color@4.5.0(@tsparticles/engine@4.5.0)':
|
||||
dependencies:
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/engine': 4.5.0
|
||||
|
||||
'@tsparticles/preset-links@4.4.0':
|
||||
'@tsparticles/preset-links@4.5.0':
|
||||
dependencies:
|
||||
'@tsparticles/basic': 4.4.0
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/interaction-particles-links': 4.4.0(@tsparticles/engine@4.4.0)(@tsparticles/plugin-interactivity@4.4.0(@tsparticles/engine@4.4.0))
|
||||
'@tsparticles/plugin-interactivity': 4.4.0(@tsparticles/engine@4.4.0)
|
||||
'@tsparticles/basic': 4.5.0
|
||||
'@tsparticles/engine': 4.5.0
|
||||
'@tsparticles/interaction-particles-links': 4.5.0(@tsparticles/engine@4.5.0)(@tsparticles/plugin-interactivity@4.5.0(@tsparticles/engine@4.5.0))
|
||||
'@tsparticles/plugin-interactivity': 4.5.0(@tsparticles/engine@4.5.0)
|
||||
|
||||
'@tsparticles/shape-circle@4.4.0(@tsparticles/engine@4.4.0)':
|
||||
'@tsparticles/shape-circle@4.5.0(@tsparticles/engine@4.5.0)':
|
||||
dependencies:
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/engine': 4.5.0
|
||||
|
||||
'@tsparticles/updater-opacity@4.4.0(@tsparticles/engine@4.4.0)':
|
||||
'@tsparticles/updater-opacity@4.5.0(@tsparticles/engine@4.5.0)':
|
||||
dependencies:
|
||||
'@tsparticles/animation-utils': 4.4.0(@tsparticles/engine@4.4.0)
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/animation-utils': 4.5.0(@tsparticles/engine@4.5.0)
|
||||
'@tsparticles/engine': 4.5.0
|
||||
|
||||
'@tsparticles/updater-out-modes@4.4.0(@tsparticles/engine@4.4.0)':
|
||||
'@tsparticles/updater-out-modes@4.5.0(@tsparticles/engine@4.5.0)':
|
||||
dependencies:
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/engine': 4.5.0
|
||||
|
||||
'@tsparticles/updater-paint@4.4.0(@tsparticles/engine@4.4.0)':
|
||||
'@tsparticles/updater-paint@4.5.0(@tsparticles/engine@4.5.0)':
|
||||
dependencies:
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/engine': 4.5.0
|
||||
|
||||
'@tsparticles/updater-size@4.4.0(@tsparticles/engine@4.4.0)':
|
||||
'@tsparticles/updater-size@4.5.0(@tsparticles/engine@4.5.0)':
|
||||
dependencies:
|
||||
'@tsparticles/animation-utils': 4.4.0(@tsparticles/engine@4.4.0)
|
||||
'@tsparticles/engine': 4.4.0
|
||||
'@tsparticles/animation-utils': 4.5.0(@tsparticles/engine@4.5.0)
|
||||
'@tsparticles/engine': 4.5.0
|
||||
|
||||
'@tufjs/[email protected]': {}
|
||||
|
||||
|
||||
@@ -26,10 +26,7 @@ import "./ha-sortable";
|
||||
|
||||
type ClockDatePartSection = "weekday" | "day" | "month" | "year" | "separator";
|
||||
|
||||
type ClockDateSeparatorPart = Extract<
|
||||
ClockCardDatePart,
|
||||
"separator-dash" | "separator-slash" | "separator-dot" | "separator-new-line"
|
||||
>;
|
||||
type ClockDateSeparatorPart = Extract<ClockCardDatePart, `separator-${string}`>;
|
||||
|
||||
const CLOCK_DATE_PART_SECTION_ORDER: readonly ClockDatePartSection[] = [
|
||||
"day",
|
||||
@@ -43,6 +40,7 @@ const CLOCK_DATE_SEPARATOR_VALUES: Record<ClockDateSeparatorPart, string> = {
|
||||
"separator-dash": "-",
|
||||
"separator-slash": "/",
|
||||
"separator-dot": ".",
|
||||
"separator-comma": ",",
|
||||
"separator-new-line": "",
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,24 @@
|
||||
import { html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import type { ContextType } from "@lit/context";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { consume } from "../../common/decorators/consume";
|
||||
import { resolveTimeZone } from "../../common/datetime/resolve-time-zone";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { configContext, internationalizationContext } from "../../data/context";
|
||||
import type { UiClockDateFormatSelector } from "../../data/selector";
|
||||
import {
|
||||
CLOCK_CARD_DATE_PRESETS,
|
||||
formatClockCardDatePreset,
|
||||
getClockCardDatePresetParts,
|
||||
isClockCardDatePreset,
|
||||
} from "../../panels/lovelace/cards/clock/clock-date-format";
|
||||
import type { ClockCardDatePreset } from "../../panels/lovelace/cards/types";
|
||||
import "../ha-clock-date-format-picker";
|
||||
import "../ha-select";
|
||||
import type { HaSelectOption, HaSelectSelectEvent } from "../ha-select";
|
||||
|
||||
type ClockDateFormatMode = ClockCardDatePreset | "custom";
|
||||
|
||||
@customElement("ha-selector-ui_clock_date_format")
|
||||
export class HaSelectorUiClockDateFormat extends LitElement {
|
||||
@@ -17,17 +34,125 @@ export class HaSelectorUiClockDateFormat extends LitElement {
|
||||
|
||||
@property({ type: Boolean }) public required = true;
|
||||
|
||||
@state()
|
||||
@consume({ context: internationalizationContext, subscribe: true })
|
||||
private _i18n!: ContextType<typeof internationalizationContext>;
|
||||
|
||||
@state()
|
||||
@consume({ context: configContext, subscribe: true })
|
||||
private _hassConfig!: ContextType<typeof configContext>;
|
||||
|
||||
// Keeps custom mode open while its parts list is still empty.
|
||||
@state() private _custom = false;
|
||||
|
||||
private get _mode(): ClockDateFormatMode | undefined {
|
||||
if (isClockCardDatePreset(this.value)) {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
if ((Array.isArray(this.value) && this.value.length) || this._custom) {
|
||||
return "custom";
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private _options = memoizeOne(
|
||||
(
|
||||
i18n: ContextType<typeof internationalizationContext>,
|
||||
serverTimeZone: string
|
||||
): HaSelectOption[] => {
|
||||
const now = new Date();
|
||||
const timeZone = resolveTimeZone(i18n.locale.time_zone, serverTimeZone);
|
||||
|
||||
return [
|
||||
...CLOCK_CARD_DATE_PRESETS.map((preset) => ({
|
||||
value: preset,
|
||||
label: i18n.localize(
|
||||
`ui.panel.lovelace.editor.card.clock.date.presets.${preset}`
|
||||
),
|
||||
secondary: formatClockCardDatePreset(
|
||||
now,
|
||||
preset,
|
||||
i18n.locale.language,
|
||||
timeZone
|
||||
),
|
||||
})),
|
||||
{
|
||||
value: "custom",
|
||||
label: i18n.localize(
|
||||
"ui.panel.lovelace.editor.card.clock.date.presets.custom"
|
||||
),
|
||||
},
|
||||
];
|
||||
}
|
||||
);
|
||||
|
||||
protected render() {
|
||||
const mode = this._mode;
|
||||
|
||||
return html`
|
||||
<ha-clock-date-format-picker
|
||||
.value=${this.value}
|
||||
<ha-select
|
||||
.label=${this.label}
|
||||
.helper=${this.helper}
|
||||
.value=${mode}
|
||||
.options=${this._options(this._i18n, this._hassConfig.config.time_zone)}
|
||||
.disabled=${this.disabled}
|
||||
.required=${this.required}
|
||||
></ha-clock-date-format-picker>
|
||||
.clearable=${!this.required}
|
||||
@selected=${this._modeSelected}
|
||||
></ha-select>
|
||||
${
|
||||
mode === "custom"
|
||||
? html`
|
||||
<ha-clock-date-format-picker
|
||||
.value=${this.value}
|
||||
.helper=${this.helper}
|
||||
.disabled=${this.disabled}
|
||||
.required=${this.required}
|
||||
></ha-clock-date-format-picker>
|
||||
`
|
||||
: nothing
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
private _modeSelected(
|
||||
ev: HaSelectSelectEvent<ClockDateFormatMode, true>
|
||||
): void {
|
||||
ev.stopPropagation();
|
||||
const mode = ev.detail.value;
|
||||
const currentValue = this.value;
|
||||
|
||||
this._custom = mode === "custom";
|
||||
|
||||
if (mode === "custom") {
|
||||
if (isClockCardDatePreset(currentValue)) {
|
||||
fireEvent(this, "value-changed", {
|
||||
value: getClockCardDatePresetParts(
|
||||
currentValue,
|
||||
this._i18n.locale.language
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
fireEvent(this, "value-changed", { value: mode });
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--ha-space-2);
|
||||
}
|
||||
|
||||
ha-select {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
||||
@@ -98,8 +98,9 @@ export class HaUnitOfMeasurementSelector extends LitElement {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.required && units.length === 1 && units[0] !== null) {
|
||||
// Preselect the only allowed unit
|
||||
if (units.length === 1 && units[0] !== null) {
|
||||
// Preselect the only allowed unit; "no unit" is not allowed either, so
|
||||
// this also applies to an optional field
|
||||
fireEvent(this, "value-changed", { value: units[0] });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
mdiShareVariant,
|
||||
} from "@mdi/js";
|
||||
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
|
||||
import { LitElement, html } from "lit";
|
||||
import { LitElement, html, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { DataTableSettingsController } from "../../../common/controllers/data-table-settings-controller";
|
||||
@@ -27,6 +27,7 @@ import { extractSearchParam } from "../../../common/url/search-params";
|
||||
import { hasRejectedItems } from "../../../common/util/promise-all-settled-results";
|
||||
import type {
|
||||
DataTableColumnContainer,
|
||||
DataTableColumnData,
|
||||
RowClickedEvent,
|
||||
SelectionChangedEvent,
|
||||
} from "../../../components/data-table/ha-data-table";
|
||||
@@ -191,30 +192,16 @@ class HaBlueprintOverview extends LitElement {
|
||||
|
||||
private _columns = memoizeOne(
|
||||
(
|
||||
localize: LocalizeFunc
|
||||
): DataTableColumnContainer<BlueprintMetaDataPath> => ({
|
||||
name: {
|
||||
title: localize("ui.panel.config.blueprint.overview.headers.name"),
|
||||
main: true,
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
direction: "asc",
|
||||
flex: 2,
|
||||
},
|
||||
translated_type: {
|
||||
title: localize("ui.panel.config.blueprint.overview.headers.type"),
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
groupable: true,
|
||||
urlName: "type",
|
||||
},
|
||||
path: {
|
||||
localize: LocalizeFunc,
|
||||
narrow: boolean
|
||||
): DataTableColumnContainer<BlueprintMetaDataPath> => {
|
||||
const path: DataTableColumnData<BlueprintMetaDataPath> = {
|
||||
title: localize("ui.panel.config.blueprint.overview.headers.file_name"),
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
flex: 2,
|
||||
},
|
||||
usage_count: {
|
||||
};
|
||||
const usageCount: DataTableColumnData<BlueprintMetaDataPath> = {
|
||||
title: localize(
|
||||
"ui.panel.config.blueprint.overview.headers.usage_count"
|
||||
),
|
||||
@@ -225,6 +212,14 @@ class HaBlueprintOverview extends LitElement {
|
||||
maxWidth: "90px",
|
||||
template: (blueprint) => {
|
||||
const count = blueprint.usageCount ?? 0;
|
||||
if (narrow) {
|
||||
if (blueprint.error) {
|
||||
return nothing;
|
||||
}
|
||||
return localize("ui.panel.config.blueprint.overview.used_count", {
|
||||
count,
|
||||
});
|
||||
}
|
||||
return html`
|
||||
<ha-assist-chip
|
||||
filled
|
||||
@@ -243,78 +238,98 @@ class HaBlueprintOverview extends LitElement {
|
||||
></ha-assist-chip>
|
||||
`;
|
||||
},
|
||||
},
|
||||
fullpath: {
|
||||
title: "fullpath",
|
||||
hidden: true,
|
||||
},
|
||||
actions: {
|
||||
lastFixed: true,
|
||||
title: "",
|
||||
label: this.hass.localize("ui.panel.config.generic.headers.actions"),
|
||||
type: "overflow-menu",
|
||||
showNarrow: true,
|
||||
template: (blueprint) =>
|
||||
blueprint.error
|
||||
? html`<ha-svg-icon
|
||||
style="color: var(--error-color); display: block; margin-inline-end: 12px; margin-inline-start: auto;"
|
||||
.path=${mdiAlertCircle}
|
||||
></ha-svg-icon>`
|
||||
: html`
|
||||
<ha-icon-overflow-menu
|
||||
narrow
|
||||
.items=${[
|
||||
{
|
||||
path: mdiPlus,
|
||||
label: this.hass.localize(
|
||||
`ui.panel.config.blueprint.overview.create_${blueprint.type}`
|
||||
),
|
||||
action: () => this._createNew(blueprint),
|
||||
},
|
||||
{
|
||||
path: mdiEye,
|
||||
label: this.hass.localize(
|
||||
`ui.panel.config.blueprint.overview.view_${blueprint.domain}`
|
||||
),
|
||||
action: () => this._showUsed(blueprint),
|
||||
},
|
||||
{
|
||||
path: mdiShareVariant,
|
||||
disabled: !blueprint.source_url,
|
||||
label: this.hass.localize(
|
||||
blueprint.source_url
|
||||
? "ui.panel.config.blueprint.overview.share_blueprint"
|
||||
: "ui.panel.config.blueprint.overview.share_blueprint_no_url"
|
||||
),
|
||||
action: () => this._share(blueprint),
|
||||
},
|
||||
{
|
||||
path: mdiDownload,
|
||||
disabled: !blueprint.source_url,
|
||||
label: this.hass.localize(
|
||||
blueprint.source_url
|
||||
? "ui.panel.config.blueprint.overview.re_import_blueprint"
|
||||
: "ui.panel.config.blueprint.overview.re_import_blueprint_no_url"
|
||||
),
|
||||
action: () => this._reImport(blueprint),
|
||||
},
|
||||
{
|
||||
divider: true,
|
||||
},
|
||||
{
|
||||
label: this.hass.localize(
|
||||
"ui.panel.config.blueprint.overview.delete_blueprint"
|
||||
),
|
||||
path: mdiDelete,
|
||||
action: () => this._delete(blueprint),
|
||||
warning: true,
|
||||
},
|
||||
]}
|
||||
>
|
||||
</ha-icon-overflow-menu>
|
||||
`,
|
||||
},
|
||||
})
|
||||
};
|
||||
return {
|
||||
name: {
|
||||
title: localize("ui.panel.config.blueprint.overview.headers.name"),
|
||||
main: true,
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
direction: "asc",
|
||||
flex: 2,
|
||||
},
|
||||
translated_type: {
|
||||
title: localize("ui.panel.config.blueprint.overview.headers.type"),
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
groupable: true,
|
||||
urlName: "type",
|
||||
},
|
||||
...(narrow
|
||||
? { usage_count: usageCount, path }
|
||||
: { path, usage_count: usageCount }),
|
||||
fullpath: {
|
||||
title: "fullpath",
|
||||
hidden: true,
|
||||
},
|
||||
actions: {
|
||||
lastFixed: true,
|
||||
title: "",
|
||||
label: this.hass.localize("ui.panel.config.generic.headers.actions"),
|
||||
type: "overflow-menu",
|
||||
showNarrow: true,
|
||||
template: (blueprint) =>
|
||||
blueprint.error
|
||||
? html`<ha-svg-icon
|
||||
style="color: var(--error-color); display: block; margin-inline-end: 12px; margin-inline-start: auto;"
|
||||
.path=${mdiAlertCircle}
|
||||
></ha-svg-icon>`
|
||||
: html`
|
||||
<ha-icon-overflow-menu
|
||||
narrow
|
||||
.items=${[
|
||||
{
|
||||
path: mdiPlus,
|
||||
label: this.hass.localize(
|
||||
`ui.panel.config.blueprint.overview.create_${blueprint.type}`
|
||||
),
|
||||
action: () => this._createNew(blueprint),
|
||||
},
|
||||
{
|
||||
path: mdiEye,
|
||||
label: this.hass.localize(
|
||||
`ui.panel.config.blueprint.overview.view_${blueprint.domain}`
|
||||
),
|
||||
action: () => this._showUsed(blueprint),
|
||||
},
|
||||
{
|
||||
path: mdiShareVariant,
|
||||
disabled: !blueprint.source_url,
|
||||
label: this.hass.localize(
|
||||
blueprint.source_url
|
||||
? "ui.panel.config.blueprint.overview.share_blueprint"
|
||||
: "ui.panel.config.blueprint.overview.share_blueprint_no_url"
|
||||
),
|
||||
action: () => this._share(blueprint),
|
||||
},
|
||||
{
|
||||
path: mdiDownload,
|
||||
disabled: !blueprint.source_url,
|
||||
label: this.hass.localize(
|
||||
blueprint.source_url
|
||||
? "ui.panel.config.blueprint.overview.re_import_blueprint"
|
||||
: "ui.panel.config.blueprint.overview.re_import_blueprint_no_url"
|
||||
),
|
||||
action: () => this._reImport(blueprint),
|
||||
},
|
||||
{
|
||||
divider: true,
|
||||
},
|
||||
{
|
||||
label: this.hass.localize(
|
||||
"ui.panel.config.blueprint.overview.delete_blueprint"
|
||||
),
|
||||
path: mdiDelete,
|
||||
action: () => this._delete(blueprint),
|
||||
warning: true,
|
||||
},
|
||||
]}
|
||||
>
|
||||
</ha-icon-overflow-menu>
|
||||
`,
|
||||
},
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
public connectedCallback() {
|
||||
@@ -373,7 +388,7 @@ class HaBlueprintOverview extends LitElement {
|
||||
back-path="/config"
|
||||
.route=${this.route}
|
||||
.tabs=${configSections.automations}
|
||||
.columns=${this._columns(this.hass.localize)}
|
||||
.columns=${this._columns(this.hass.localize, this.narrow)}
|
||||
.data=${this._processedBlueprints(
|
||||
this.blueprints,
|
||||
this.hass.localize,
|
||||
|
||||
@@ -1,21 +1,58 @@
|
||||
import { resolveTimeZone } from "../../../../common/datetime/resolve-time-zone";
|
||||
import type { FrontendLocaleData } from "../../../../data/translation";
|
||||
import type { ClockCardConfig, ClockCardDatePart } from "../types";
|
||||
|
||||
type ClockCardSeparatorPart = Extract<
|
||||
import type {
|
||||
ClockCardConfig,
|
||||
ClockCardDatePart,
|
||||
"separator-dash" | "separator-slash" | "separator-dot" | "separator-new-line"
|
||||
>;
|
||||
ClockCardDatePreset,
|
||||
} from "../types";
|
||||
|
||||
type ClockCardSeparatorPart = Extract<ClockCardDatePart, `separator-${string}`>;
|
||||
|
||||
type ClockCardValuePart = Exclude<ClockCardDatePart, ClockCardSeparatorPart>;
|
||||
|
||||
/**
|
||||
* Normalized date configuration used by clock card renderers.
|
||||
* Normalized date configuration used by clock card renderers. A preset wins
|
||||
* over parts.
|
||||
*/
|
||||
interface ClockCardDateConfig {
|
||||
parts: ClockCardDatePart[];
|
||||
preset?: ClockCardDatePreset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Date presets offered before the custom parts editor. `short` to `full`
|
||||
* follow the locale's standard date styles, `iso` is ISO 8601 (YYYY-MM-DD).
|
||||
*/
|
||||
export const CLOCK_CARD_DATE_PRESETS: readonly ClockCardDatePreset[] = [
|
||||
"short",
|
||||
"medium",
|
||||
"long",
|
||||
"full",
|
||||
"iso",
|
||||
];
|
||||
|
||||
const ISO_DATE_OPTIONS: Intl.DateTimeFormatOptions = {
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
};
|
||||
|
||||
const DATE_PRESET_OPTIONS: Record<
|
||||
ClockCardDatePreset,
|
||||
Intl.DateTimeFormatOptions
|
||||
> = {
|
||||
short: { dateStyle: "short" },
|
||||
medium: { dateStyle: "medium" },
|
||||
long: { dateStyle: "long" },
|
||||
full: { dateStyle: "full" },
|
||||
iso: ISO_DATE_OPTIONS,
|
||||
};
|
||||
|
||||
export const isClockCardDatePreset = (
|
||||
value: unknown
|
||||
): value is ClockCardDatePreset =>
|
||||
CLOCK_CARD_DATE_PRESETS.some((preset) => preset === value);
|
||||
|
||||
/**
|
||||
* Resolves the locale and time zone for a clock card from the user's locale,
|
||||
* the server time zone and the card's configuration. Applies the optional
|
||||
@@ -54,6 +91,7 @@ export const CLOCK_CARD_DATE_PARTS: readonly ClockCardDatePart[] = [
|
||||
"separator-dash",
|
||||
"separator-slash",
|
||||
"separator-dot",
|
||||
"separator-comma",
|
||||
"separator-new-line",
|
||||
];
|
||||
|
||||
@@ -77,6 +115,8 @@ const DATE_SEPARATORS: Record<ClockCardSeparatorPart, string> = {
|
||||
"separator-dash": "-",
|
||||
"separator-slash": "/",
|
||||
"separator-dot": ".",
|
||||
// A comma always reads with a space after it, as in "Thursday, 29 October".
|
||||
"separator-comma": ", ",
|
||||
"separator-new-line": "\n",
|
||||
};
|
||||
|
||||
@@ -84,6 +124,7 @@ const DATE_SEPARATOR_PARTS = new Set<ClockCardSeparatorPart>([
|
||||
"separator-dash",
|
||||
"separator-slash",
|
||||
"separator-dot",
|
||||
"separator-comma",
|
||||
"separator-new-line",
|
||||
]);
|
||||
|
||||
@@ -163,7 +204,7 @@ const applyDatePartOption = (
|
||||
* Sanitizes configured date tokens while preserving their literal order.
|
||||
*/
|
||||
const normalizeDateParts = (
|
||||
parts: ClockCardConfig["date_format"]
|
||||
parts: ClockCardDatePart[] | undefined
|
||||
): ClockCardDatePart[] =>
|
||||
parts?.filter((part): part is ClockCardDatePart =>
|
||||
isClockCardDatePart(part)
|
||||
@@ -174,19 +215,31 @@ const normalizeDateParts = (
|
||||
*/
|
||||
export const getClockCardDateConfig = (
|
||||
config?: Pick<ClockCardConfig, "date_format">
|
||||
): ClockCardDateConfig => ({
|
||||
parts: normalizeDateParts(config?.date_format),
|
||||
});
|
||||
): ClockCardDateConfig => {
|
||||
const dateFormat = config?.date_format;
|
||||
|
||||
if (isClockCardDatePreset(dateFormat)) {
|
||||
return { parts: [], preset: dateFormat };
|
||||
}
|
||||
|
||||
return {
|
||||
parts: normalizeDateParts(Array.isArray(dateFormat) ? dateFormat : []),
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks whether the clock configuration resolves to any visible date output.
|
||||
*/
|
||||
export const hasClockCardDate = (
|
||||
config?: Pick<ClockCardConfig, "date_format">
|
||||
): boolean => getClockCardDateConfig(config).parts.length > 0;
|
||||
): boolean => {
|
||||
const dateConfig = getClockCardDateConfig(config);
|
||||
|
||||
return !!dateConfig.preset || dateConfig.parts.length > 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts normalized date tokens into Intl.DateTimeFormat options.
|
||||
* Converts a normalized date config into Intl.DateTimeFormat options.
|
||||
*
|
||||
* Separator tokens are ignored. If multiple tokens target the same Intl field,
|
||||
* the last one wins.
|
||||
@@ -194,6 +247,10 @@ export const hasClockCardDate = (
|
||||
export const getClockCardDateTimeFormatOptions = (
|
||||
dateConfig: ClockCardDateConfig
|
||||
): Intl.DateTimeFormatOptions => {
|
||||
if (dateConfig.preset) {
|
||||
return { ...DATE_PRESET_OPTIONS[dateConfig.preset] };
|
||||
}
|
||||
|
||||
const options: Intl.DateTimeFormatOptions = {};
|
||||
|
||||
dateConfig.parts.forEach((part) => {
|
||||
@@ -203,6 +260,147 @@ export const getClockCardDateTimeFormatOptions = (
|
||||
return options;
|
||||
};
|
||||
|
||||
const DATE_PRESET_FORMATTERS = new Map<string, Intl.DateTimeFormat>();
|
||||
|
||||
const getDatePresetFormatter = (
|
||||
preset: ClockCardDatePreset,
|
||||
language: string,
|
||||
timeZone?: string
|
||||
): Intl.DateTimeFormat => {
|
||||
const cacheKey = `${language}|${timeZone || ""}|${preset}`;
|
||||
const cached = DATE_PRESET_FORMATTERS.get(cacheKey);
|
||||
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
// ISO 8601 is fixed: Gregorian calendar and Latin digits in any language.
|
||||
const isIso = preset === "iso";
|
||||
|
||||
const options: Intl.DateTimeFormatOptions = isIso
|
||||
? { ...ISO_DATE_OPTIONS, calendar: "iso8601", numberingSystem: "latn" }
|
||||
: { ...DATE_PRESET_OPTIONS[preset] };
|
||||
|
||||
if (timeZone) {
|
||||
options.timeZone = timeZone;
|
||||
}
|
||||
|
||||
const formatter = new Intl.DateTimeFormat(isIso ? "en" : language, options);
|
||||
|
||||
DATE_PRESET_FORMATTERS.set(cacheKey, formatter);
|
||||
|
||||
return formatter;
|
||||
};
|
||||
|
||||
/**
|
||||
* Formats a date with one of the presets.
|
||||
*/
|
||||
export const formatClockCardDatePreset = (
|
||||
date: Date,
|
||||
preset: ClockCardDatePreset,
|
||||
language: string,
|
||||
timeZone?: string
|
||||
): string => {
|
||||
const formatter = getDatePresetFormatter(preset, language, timeZone);
|
||||
|
||||
if (preset !== "iso") {
|
||||
return formatter.format(date);
|
||||
}
|
||||
|
||||
const values: Partial<Record<Intl.DateTimeFormatPartTypes, string>> = {};
|
||||
|
||||
formatter.formatToParts(date).forEach(({ type, value }) => {
|
||||
values[type] = value;
|
||||
});
|
||||
|
||||
return `${values.year}-${values.month}-${values.day}`;
|
||||
};
|
||||
|
||||
const PRESET_REFERENCE_DATE = new Date(Date.UTC(2026, 0, 5, 12));
|
||||
|
||||
const INLINE_SEPARATOR_PARTS = [
|
||||
"separator-dash",
|
||||
"separator-slash",
|
||||
"separator-dot",
|
||||
"separator-comma",
|
||||
] as const satisfies readonly ClockCardSeparatorPart[];
|
||||
|
||||
/**
|
||||
* Approximates a preset as custom date parts in the given language, so
|
||||
* switching from a preset to custom starts from what the user already sees.
|
||||
* Literal text the parts can't express, such as commas, is dropped.
|
||||
*/
|
||||
export const getClockCardDatePresetParts = (
|
||||
preset: ClockCardDatePreset,
|
||||
language: string
|
||||
): ClockCardDatePart[] => {
|
||||
if (preset === "iso") {
|
||||
return [
|
||||
"year-numeric",
|
||||
"separator-dash",
|
||||
"month-2-digit",
|
||||
"separator-dash",
|
||||
"day-2-digit",
|
||||
];
|
||||
}
|
||||
|
||||
const formatUtc = (part: ClockCardValuePart) =>
|
||||
formatDatePart(part, PRESET_REFERENCE_DATE, language, "UTC");
|
||||
|
||||
const parts: ClockCardDatePart[] = [];
|
||||
|
||||
getDatePresetFormatter(preset, language, "UTC")
|
||||
.formatToParts(PRESET_REFERENCE_DATE)
|
||||
.forEach(({ type, value }) => {
|
||||
switch (type) {
|
||||
case "weekday":
|
||||
parts.push(
|
||||
value === formatUtc("weekday-long")
|
||||
? "weekday-long"
|
||||
: "weekday-short"
|
||||
);
|
||||
break;
|
||||
case "day":
|
||||
parts.push(
|
||||
value === formatUtc("day-2-digit") ? "day-2-digit" : "day-numeric"
|
||||
);
|
||||
break;
|
||||
case "month":
|
||||
parts.push(
|
||||
(
|
||||
[
|
||||
"month-2-digit",
|
||||
"month-numeric",
|
||||
"month-long",
|
||||
"month-short",
|
||||
] as const
|
||||
).find((part) => value === formatUtc(part)) ?? "month-short"
|
||||
);
|
||||
break;
|
||||
case "year":
|
||||
parts.push(
|
||||
value === formatUtc("year-2-digit")
|
||||
? "year-2-digit"
|
||||
: "year-numeric"
|
||||
);
|
||||
break;
|
||||
case "literal": {
|
||||
const separator = INLINE_SEPARATOR_PARTS.find(
|
||||
(part) => value.trim() === DATE_SEPARATORS[part].trim()
|
||||
);
|
||||
|
||||
if (separator) {
|
||||
parts.push(separator);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return parts;
|
||||
};
|
||||
|
||||
/**
|
||||
* Builds the final date string from literal date tokens.
|
||||
*
|
||||
@@ -216,6 +414,15 @@ export const formatClockCardDate = (
|
||||
language: string,
|
||||
timeZone?: string
|
||||
): string => {
|
||||
if (dateConfig.preset) {
|
||||
return formatClockCardDatePreset(
|
||||
date,
|
||||
dateConfig.preset,
|
||||
language,
|
||||
timeZone
|
||||
);
|
||||
}
|
||||
|
||||
let result = "";
|
||||
let previousRenderedPartWasValue = false;
|
||||
|
||||
|
||||
@@ -230,6 +230,8 @@ export class HuiClockCardAnalog extends LitElement {
|
||||
const dateConfig = getClockCardDateConfig(config);
|
||||
const showDate = hasClockCardDate(config);
|
||||
const isLongDate =
|
||||
dateConfig.preset === "long" ||
|
||||
dateConfig.preset === "full" ||
|
||||
dateConfig.parts.includes("month-long") ||
|
||||
dateConfig.parts.includes("weekday-long");
|
||||
|
||||
|
||||
@@ -62,14 +62,14 @@ export const computeDateText = (
|
||||
config: HassConfig,
|
||||
cardConfig: DateCardConfig
|
||||
): string => {
|
||||
const { parts } = getClockCardDateConfig(cardConfig);
|
||||
const dateConfig = getClockCardDateConfig(cardConfig);
|
||||
const timeZone = computeResolvedTimeZone(locale, config, cardConfig);
|
||||
|
||||
if (!parts.length) {
|
||||
if (!dateConfig.preset && !dateConfig.parts.length) {
|
||||
return formatDefaultDate(dateObj, locale.language, timeZone);
|
||||
}
|
||||
|
||||
return formatClockCardDate(dateObj, { parts }, locale.language, timeZone);
|
||||
return formatClockCardDate(dateObj, dateConfig, locale.language, timeZone);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -310,11 +310,11 @@ class HuiEntitiesCard extends LitElement implements LovelaceCard {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#states > div:first-child > hui-section-row::part(divider) {
|
||||
#states:first-child > div:first-child > hui-section-row::part(divider) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#states > div:first-child > hui-section-row::part(label) {
|
||||
#states:first-child > div:first-child > hui-section-row::part(label) {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -472,7 +472,7 @@ export interface ClockCardConfig extends LovelaceCardConfig {
|
||||
time_format?: TimeFormat;
|
||||
time_zone?: string;
|
||||
no_background?: boolean;
|
||||
date_format?: ClockCardDatePart[];
|
||||
date_format?: ClockCardDateFormat;
|
||||
// Analog clock options
|
||||
border?: boolean;
|
||||
ticks?: "none" | "quarter" | "hour" | "minute";
|
||||
@@ -493,13 +493,21 @@ export type ClockCardDatePart =
|
||||
| "separator-dash"
|
||||
| "separator-slash"
|
||||
| "separator-dot"
|
||||
| "separator-comma"
|
||||
| "separator-new-line";
|
||||
|
||||
export type ClockCardDatePreset = "short" | "medium" | "long" | "full" | "iso";
|
||||
|
||||
/**
|
||||
* A preset name, or a custom list of date parts in display order.
|
||||
*/
|
||||
export type ClockCardDateFormat = ClockCardDatePreset | ClockCardDatePart[];
|
||||
|
||||
export interface DateCardConfig extends LovelaceCardConfig {
|
||||
type: "date";
|
||||
title?: string;
|
||||
date_size?: "small" | "medium" | "large";
|
||||
date_format?: ClockCardDatePart[];
|
||||
date_format?: ClockCardDateFormat;
|
||||
time_zone?: string;
|
||||
no_background?: boolean;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
object,
|
||||
optional,
|
||||
string,
|
||||
union,
|
||||
} from "superstruct";
|
||||
import { consumeLocalize } from "../../../../common/decorators/consume-context-entry";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
@@ -28,6 +29,7 @@ import { TimeFormat } from "../../../../data/translation";
|
||||
import { getTimezoneOptions } from "../../../../components/ha-timezone-picker";
|
||||
import {
|
||||
CLOCK_CARD_DATE_PARTS,
|
||||
CLOCK_CARD_DATE_PRESETS,
|
||||
getClockCardDateConfig,
|
||||
} from "../../cards/clock/clock-date-format";
|
||||
|
||||
@@ -41,7 +43,12 @@ const cardConfigStruct = assign(
|
||||
time_zone: optional(enums(getTimezoneOptions().map((option) => option.id))),
|
||||
show_seconds: optional(boolean()),
|
||||
no_background: optional(boolean()),
|
||||
date_format: optional(defaulted(array(enums(CLOCK_CARD_DATE_PARTS)), [])),
|
||||
date_format: optional(
|
||||
union([
|
||||
enums(CLOCK_CARD_DATE_PRESETS),
|
||||
array(enums(CLOCK_CARD_DATE_PARTS)),
|
||||
])
|
||||
),
|
||||
// Analog clock options
|
||||
border: optional(defaulted(boolean(), false)),
|
||||
ticks: optional(
|
||||
|
||||
@@ -6,11 +6,11 @@ import {
|
||||
assert,
|
||||
assign,
|
||||
boolean,
|
||||
defaulted,
|
||||
enums,
|
||||
object,
|
||||
optional,
|
||||
string,
|
||||
union,
|
||||
} from "superstruct";
|
||||
import { consumeLocalize } from "../../../../common/decorators/consume-context-entry";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
@@ -22,7 +22,10 @@ import type {
|
||||
import type { ValueChangedEvent } from "../../../../types";
|
||||
import type { LocalizeFunc } from "../../../../common/translations/localize";
|
||||
import type { DateCardConfig } from "../../cards/types";
|
||||
import { CLOCK_CARD_DATE_PARTS } from "../../cards/clock/clock-date-format";
|
||||
import {
|
||||
CLOCK_CARD_DATE_PARTS,
|
||||
CLOCK_CARD_DATE_PRESETS,
|
||||
} from "../../cards/clock/clock-date-format";
|
||||
import type { LovelaceCardEditor } from "../../types";
|
||||
import { baseLovelaceCardConfig } from "../structs/base-card-struct";
|
||||
import { getTimezoneOptions } from "../../../../components/ha-timezone-picker";
|
||||
@@ -32,7 +35,12 @@ const cardConfigStruct = assign(
|
||||
object({
|
||||
title: optional(string()),
|
||||
date_size: optional(enums(["small", "medium", "large"] as const)),
|
||||
date_format: optional(defaulted(array(enums(CLOCK_CARD_DATE_PARTS)), [])),
|
||||
date_format: optional(
|
||||
union([
|
||||
enums(CLOCK_CARD_DATE_PRESETS),
|
||||
array(enums(CLOCK_CARD_DATE_PARTS)),
|
||||
])
|
||||
),
|
||||
time_zone: optional(enums(getTimezoneOptions().map((option) => option.id))),
|
||||
no_background: optional(boolean()),
|
||||
})
|
||||
|
||||
@@ -92,16 +92,22 @@ export const filterUnavailableBatteryEntities = (
|
||||
return states[entityId]?.state === "unavailable";
|
||||
});
|
||||
|
||||
const computeBatteryTileCard = (
|
||||
const computeMaintenanceTileCard = (
|
||||
states: HomeAssistant["states"],
|
||||
entities: HomeAssistant["entities"],
|
||||
entityId: string
|
||||
): TileCardConfig => {
|
||||
const entity = entities[entityId];
|
||||
const deviceId = entity?.device_id;
|
||||
const deviceId = entities[entityId]?.device_id;
|
||||
if (!deviceId) {
|
||||
return { type: "tile", entity: entityId, name: { type: "entity" } };
|
||||
}
|
||||
const isProblem = states[entityId]?.attributes?.device_class === "problem";
|
||||
return {
|
||||
type: "tile",
|
||||
entity: entityId,
|
||||
name: { type: deviceId ? "device" : "entity" },
|
||||
name: isProblem
|
||||
? [{ type: "device" }, { type: "entity" }]
|
||||
: { type: "device" },
|
||||
};
|
||||
};
|
||||
|
||||
@@ -130,7 +136,9 @@ const processAreasForBattery = (
|
||||
const areaCards: LovelaceCardConfig[] = [];
|
||||
|
||||
for (const entityId of areaBatteryEntities) {
|
||||
areaCards.push(computeBatteryTileCard(hass.entities, entityId));
|
||||
areaCards.push(
|
||||
computeMaintenanceTileCard(hass.states, hass.entities, entityId)
|
||||
);
|
||||
}
|
||||
|
||||
if (areaCards.length > 0) {
|
||||
@@ -170,7 +178,9 @@ const processUnassignedEntities = (
|
||||
const cards: LovelaceCardConfig[] = [];
|
||||
|
||||
for (const entityId of unassignedEntities) {
|
||||
cards.push(computeBatteryTileCard(hass.entities, entityId));
|
||||
cards.push(
|
||||
computeMaintenanceTileCard(hass.states, hass.entities, entityId)
|
||||
);
|
||||
}
|
||||
|
||||
return cards;
|
||||
|
||||
@@ -6720,6 +6720,7 @@
|
||||
"script": "scripts"
|
||||
},
|
||||
"error": "{path} could not be loaded",
|
||||
"used_count": "{count, plural,\n =0 {Not in use}\n one {Used once}\n other {Used {count} times}\n}",
|
||||
"blueprint_in_use_title": "This blueprint is in use and cannot be deleted",
|
||||
"blueprint_in_use_text": "Please remove all below {type} that use this blueprint before deleting it. {list}",
|
||||
"blueprint_in_use_view_automation": "View automations",
|
||||
@@ -11386,6 +11387,14 @@
|
||||
"date": {
|
||||
"label": "Date",
|
||||
"description": "Select and order the date parts. Add a separator to control punctuation.",
|
||||
"presets": {
|
||||
"short": "Short",
|
||||
"medium": "Medium",
|
||||
"long": "Long",
|
||||
"full": "Full",
|
||||
"iso": "ISO 8601",
|
||||
"custom": "Custom"
|
||||
},
|
||||
"sections": {
|
||||
"weekday": "Weekday",
|
||||
"day": "Day",
|
||||
@@ -11407,6 +11416,7 @@
|
||||
"separator-dash": "Dash",
|
||||
"separator-slash": "Slash",
|
||||
"separator-dot": "Dot",
|
||||
"separator-comma": "Comma",
|
||||
"separator-new-line": "New line"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
import { assert, describe, it } from "vitest";
|
||||
import type { ClockCardDatePart } from "../../../../src/panels/lovelace/cards/types";
|
||||
import type {
|
||||
ClockCardDatePart,
|
||||
ClockCardDatePreset,
|
||||
} from "../../../../src/panels/lovelace/cards/types";
|
||||
import {
|
||||
formatClockCardDate,
|
||||
formatClockCardDatePreset,
|
||||
getClockCardDateConfig,
|
||||
getClockCardDatePresetParts,
|
||||
getClockCardDateTimeFormatOptions,
|
||||
hasClockCardDate,
|
||||
} from "../../../../src/panels/lovelace/cards/clock/clock-date-format";
|
||||
@@ -258,4 +263,85 @@ describe("clock-date-format", () => {
|
||||
|
||||
assert.equal(result, "11 2024");
|
||||
});
|
||||
|
||||
it("reads a preset date format", () => {
|
||||
assert.deepEqual(getClockCardDateConfig({ date_format: "long" }), {
|
||||
parts: [],
|
||||
preset: "long",
|
||||
});
|
||||
assert.equal(hasClockCardDate({ date_format: "short" }), true);
|
||||
assert.deepEqual(
|
||||
getClockCardDateTimeFormatOptions({ parts: [], preset: "full" }),
|
||||
{ dateStyle: "full" }
|
||||
);
|
||||
});
|
||||
|
||||
it("formats presets with the locale's date styles", () => {
|
||||
const format = (preset: ClockCardDatePreset, language = "en-GB") =>
|
||||
formatClockCardDate(date, { parts: [], preset }, language, "UTC");
|
||||
|
||||
assert.equal(format("short"), "08/11/2024");
|
||||
assert.equal(format("medium"), "8 Nov 2024");
|
||||
assert.equal(format("long"), "8 November 2024");
|
||||
assert.equal(format("short", "en-US"), "11/8/24");
|
||||
});
|
||||
|
||||
it("formats the ISO preset the same in every language", () => {
|
||||
const format = (language: string, timeZone: string) =>
|
||||
formatClockCardDatePreset(date, "iso", language, timeZone);
|
||||
|
||||
assert.equal(format("en-US", "UTC"), "2024-11-08");
|
||||
assert.equal(format("ar-EG", "UTC"), "2024-11-08");
|
||||
assert.equal(format("en", "Pacific/Kiritimati"), "2024-11-09");
|
||||
});
|
||||
|
||||
it("converts presets into matching custom parts", () => {
|
||||
assert.deepEqual(getClockCardDatePresetParts("short", "en-GB"), [
|
||||
"day-2-digit",
|
||||
"separator-slash",
|
||||
"month-2-digit",
|
||||
"separator-slash",
|
||||
"year-numeric",
|
||||
]);
|
||||
assert.deepEqual(getClockCardDatePresetParts("full", "en-US"), [
|
||||
"weekday-long",
|
||||
"separator-comma",
|
||||
"month-long",
|
||||
"day-numeric",
|
||||
"separator-comma",
|
||||
"year-numeric",
|
||||
]);
|
||||
assert.deepEqual(getClockCardDatePresetParts("short", "de"), [
|
||||
"day-2-digit",
|
||||
"separator-dot",
|
||||
"month-2-digit",
|
||||
"separator-dot",
|
||||
"year-2-digit",
|
||||
]);
|
||||
|
||||
(["en-GB", "en-US"] as const).forEach((language) => {
|
||||
(["short", "medium", "long", "full", "iso"] as const).forEach(
|
||||
(preset) => {
|
||||
const parts = getClockCardDatePresetParts(preset, language);
|
||||
assert.equal(
|
||||
formatClockCardDate(date, { parts }, language, "UTC"),
|
||||
formatClockCardDate(date, { parts: [], preset }, language, "UTC")
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("renders a comma separator with a following space", () => {
|
||||
const result = formatClockCardDate(
|
||||
date,
|
||||
{
|
||||
parts: ["weekday-long", "separator-comma", "month-long", "day-numeric"],
|
||||
},
|
||||
"en",
|
||||
"UTC"
|
||||
);
|
||||
|
||||
assert.equal(result, "Friday, November 8");
|
||||
});
|
||||
});
|
||||
@@ -2,8 +2,13 @@ import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
filterLowBatteryEntities,
|
||||
filterProblemEntities,
|
||||
MaintenanceViewStrategy,
|
||||
} from "../../../../src/panels/maintenance/strategies/maintenance-view-strategy";
|
||||
import { mockEntity } from "../../../common/entity/context/context-mock";
|
||||
import {
|
||||
mockDevice,
|
||||
mockEntity,
|
||||
} from "../../../common/entity/context/context-mock";
|
||||
import type { LovelaceSectionConfig } from "../../../../src/data/lovelace/config/section";
|
||||
import { createMockEntityState, createMockHass } from "../../../fixtures/hass";
|
||||
|
||||
describe("filterLowBatteryEntities", () => {
|
||||
@@ -209,3 +214,70 @@ describe("filterProblemEntities", () => {
|
||||
).toEqual(["binary_sensor.has_problem"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("MaintenanceViewStrategy.generate", () => {
|
||||
it("names problem tiles after the device and the entity", async () => {
|
||||
const hass = createMockHass(
|
||||
{
|
||||
"sensor.microwave_battery": createMockEntityState(
|
||||
"sensor.microwave_battery",
|
||||
"80",
|
||||
{ device_class: "battery" }
|
||||
),
|
||||
"binary_sensor.microwave_overheating": createMockEntityState(
|
||||
"binary_sensor.microwave_overheating",
|
||||
"off",
|
||||
{ device_class: "problem" }
|
||||
),
|
||||
"binary_sensor.standalone_problem": createMockEntityState(
|
||||
"binary_sensor.standalone_problem",
|
||||
"off",
|
||||
{ device_class: "problem" }
|
||||
),
|
||||
},
|
||||
{
|
||||
devices: {
|
||||
microwave: mockDevice({ id: "microwave", name: "Microwave" }),
|
||||
},
|
||||
entities: {
|
||||
"sensor.microwave_battery": mockEntity({
|
||||
entity_id: "sensor.microwave_battery",
|
||||
device_id: "microwave",
|
||||
}),
|
||||
"binary_sensor.microwave_overheating": mockEntity({
|
||||
entity_id: "binary_sensor.microwave_overheating",
|
||||
device_id: "microwave",
|
||||
}),
|
||||
"binary_sensor.standalone_problem": mockEntity({
|
||||
entity_id: "binary_sensor.standalone_problem",
|
||||
}),
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const view = await MaintenanceViewStrategy.generate(
|
||||
{ type: "maintenance" },
|
||||
hass
|
||||
);
|
||||
|
||||
const section = view.sections?.[0] as LovelaceSectionConfig;
|
||||
|
||||
expect(section.cards?.slice(1)).toEqual([
|
||||
{
|
||||
type: "tile",
|
||||
entity: "sensor.microwave_battery",
|
||||
name: { type: "device" },
|
||||
},
|
||||
{
|
||||
type: "tile",
|
||||
entity: "binary_sensor.microwave_overheating",
|
||||
name: [{ type: "device" }, { type: "entity" }],
|
||||
},
|
||||
{
|
||||
type: "tile",
|
||||
entity: "binary_sensor.standalone_problem",
|
||||
name: { type: "entity" },
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user