Compare commits

..
Author SHA1 Message Date
J. Nick Koston ecba22d301 Merge branch 'dev' into persistent_notification_trigger 2023-06-22 01:44:19 +02:00
J. Nick Koston 72172cabc2 Migrate to using dismiss_all for persistent_notification 2023-06-22 01:41:49 +02:00
Bram KragtenandGitHub eb552530e2 Add support for image entity (#16877) 2023-06-21 17:46:40 +02:00
1fe5d66a68 Allow cards and tile features to provide a schema to create the editor (#16142)
Co-authored-by: Bram Kragten <[email protected]>
2023-06-21 17:22:33 +02:00
Bram KragtenandGitHub 7faa165558 Refactor Storage decorator (#16987) 2023-06-21 17:22:10 +02:00
karwostsandGitHub 752bc192cd Fix types selection for statistics-graph-card (#16988) 2023-06-21 15:10:00 +00:00
Paul BotteinandGitHub e9961b93f9 Add circular slider (#16981)
* WIP Create round slider

* Fix interaction on iOS

* Add dual and simple gauge

* Add events

* Rename events

* Use low and high

* Improve dual slider selection

* Add min and max

* Rename component

* Prevents setting a high value lower than low and vice versa

* Add keyboard support

* Fix typings

* Use html

* Update current indicator

* Improve doc

* Fix keyboard focus after mouse interaction

* Don't fallback to value
2023-06-21 15:01:45 +00:00
c0ffeeca7andGitHub bbdcc021d4 TTS and STT: standardize spelling (#16685) 2023-06-21 13:46:08 +02:00
3d6cfc4037 open option for lock (#14852)
Co-authored-by: Bram Kragten <[email protected]>
2023-06-21 09:59:28 +00:00
9b35c06eef Add persistent_notification trigger (#16967)
Co-authored-by: J. Nick Koston <[email protected]>
2023-06-21 11:55:55 +02:00
Joakim SørensenandGitHub b46c74fe76 Add haStyleScrollbar to hass-subpage (#16745) 2023-06-21 11:35:17 +02:00
Joakim SørensenandGitHub 5aa6ffe2e4 Map GitHub block quotes to our ha-alert component (#16757) 2023-06-21 11:35:02 +02:00
J. Nick Koston 4ffd31974c switch to schema 2023-06-21 10:38:57 +02:00
J. Nick Koston 1faef71dcb tweak 2023-06-21 10:25:53 +02:00
J. Nick Koston 1e5c35c158 Merge branch 'dev' into persistent_notification_trigger 2023-06-21 09:58:42 +02:00
J. Nick Koston 2e3ce4ae9e lint 2023-06-21 09:57:39 +02:00
karwostsandGitHub 07d37dd89f Handle multiple triggers in trigger condition UI (#16983) 2023-06-21 08:50:01 +02:00
Lasse Bang MikkelsenandGitHub 33d6ad1b0b Add copy-to-clipboard button for long-lived tokens (#16956) 2023-06-21 06:19:25 +00:00
Simon LamonandGitHub 386ed2167f Make automation editor card headers translateable (triggers partly) (#16969) 2023-06-21 08:12:04 +02:00
karwostsandGitHub 221f4f34a7 Use new automation dialog for new scripts (#16933) 2023-06-21 08:04:39 +02:00
karwostsandGitHub c63c717d9f Add 'Default' option to theme-picker (#16915) 2023-06-21 08:03:17 +02:00
Paul BotteinandGitHub 1cb1bcf274 Open assist from dashboard (#16829) 2023-06-21 08:02:09 +02:00
RoboMagus 30f2a49fbf Simplified update_types localizations 2023-06-20 17:53:33 +02:00
karwostsandGitHub 1cf24ffc8d Allow continue_on_error in the UI action editor (#16834) 2023-06-20 14:53:13 +00:00
Paul BotteinandGitHub 13b864e261 Use ha-icon-button-group in more info cover (#16911) 2023-06-20 16:45:45 +02:00
Paul BotteinandGitHub 7bc2ca3b65 Add more info lock (#15995)
* Add more info lock

* Use same height for pending state

* Fix attributes

* Add unlocking/locking to switch

* Improve code support
2023-06-20 15:25:26 +02:00
RoboMagus 101e9323a7 Review updates 2023-06-20 14:58:24 +02:00
Christoph Wen, B.ScandGitHub 922e95b895 Fix time and date-time 12h formats (#16692) (#16805)
* Fix time and date-time 12h formats  (#16692)

- am/pm check possible for other languages
- adjusted date format gallery page for consistency
- added gallery pages for date-time and time formats

* Fix typo in am/pm check (#16692)
2023-06-20 12:52:53 +02:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
baaa012101 Update octokit monorepo (#16979)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-20 12:07:01 +02:00
breakthestaticandGitHub 3888b1c48b Use fuzzy filter/sort for target pickers (#16912)
* Use fuzzy filter/sort for target pickers

* PR suggestions

* Restore missed sort
2023-06-20 12:03:55 +02:00
karwostsandGitHub 332af4003e History graph should start at requested time even if sensor is unavailable (#16850)
History graph should start at consistent time if sensor is unavailable
2023-06-20 12:00:33 +02:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
044a44e114 Update dependency @lit-labs/context to v0.3.3 (#16975)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-20 11:56:05 +02:00
c0ffeeca7andGitHub 13c932a8f8 Thread: Rename "My network" to "Preferred network" (#16980)
- All networks in my household are my networks. Otherwise they are my neighbor's.
- within my networks, this one is my preferred one (as opposed to other networks)
2023-06-20 10:43:28 +02:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
be1089302f Update dependency @octokit/rest to v19.0.12 (#16973)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-19 17:52:51 +00:00
Steve RepsherandGitHub 540df024d9 Upgrade to python 3.11 (#16948) 2023-06-19 19:50:45 +02:00
Bram KragtenandGitHub e7c8bd4c41 Bump Vaadin (#16971) 2023-06-19 13:48:54 -04:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>Bram Kragten
7c15a65bba Update dependency @lit-labs/virtualizer to v2.0.3 (#16761)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Bram Kragten <[email protected]>
2023-06-19 14:21:08 +00:00
karwostsandGitHub 5381a467e5 Fix blueprint script editor erroneously setting mode field (#16934) 2023-06-19 13:43:04 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>Bram Kragten
a96d3594ba Update dependency typescript to v5 (#15877)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Bram Kragten <[email protected]>
2023-06-19 13:03:48 +00:00
RoboMagus 4526a46a56 Add persistent_notification trigger 2023-06-19 15:02:53 +02:00
Steve RepsherandGitHub 1d0d4755d0 Update lit-analyzer and ts-lit-plugin to version 2 (#16954) 2023-06-19 14:30:16 +02:00
fa75b18a6b Add self-sufficiency gauge card (#15704)
Co-authored-by: Bram Kragten <[email protected]>
2023-06-19 13:59:20 +02:00
Joakim SørensenandGitHub cdd29c8bf7 Add help button to get documentation from mount dialog (#16932) 2023-06-19 11:54:47 +00:00
Paul BotteinandGitHub 215f5e341a Put color wheel at the root level for more info light (#16909) 2023-06-19 13:50:37 +02:00
Franck NijhofandGitHub 8abb58ae7d Add preheating HVAC action to climate (#16922) 2023-06-19 13:36:19 +02:00
karwostsandGitHub 40c8301df0 Allow templates in service template/object selector (#16925) 2023-06-19 13:33:28 +02:00
Simon LamonandGitHub 80f3d6aacb Change all occurrences to use Intl.ListFormat (#16897) 2023-06-19 12:52:28 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
41310007fe Bump dessant/lock-threads from 4.0.0 to 4.0.1 (#16962)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-19 09:39:22 +02:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
195b1eef02 Lock file maintenance (#16961)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-19 05:26:18 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>Steve Repsher
8e9b5ea66b Update dependency tsparticles-preset-links to v2.10.1 (#16802)
* Update dependency tsparticles-preset-links to v2.10.1

* Group future tsparticles updates

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Steve Repsher <[email protected]>
2023-06-19 05:10:21 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
827d89628d Update dependency tsparticles-engine to v2.10.1 (#16790)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-18 23:52:23 -04:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
cac341a938 Update dependency hls.js to v1.4.6 (#16960)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-18 23:31:13 -04:00
J. Nick KostonandGitHub 2b51228665 Fix notifications subscription leak when in narrow mode (#16953)
Fix persistent notifications subscription leak on mobile/narrow
2023-06-17 20:41:41 -04:00
renovate[bot]andGitHub 79c010eb7b Update dependency webpack to v5.87.0 (#16949) 2023-06-17 20:34:43 -04:00
renovate[bot]andGitHub 2a4356ce86 Update dependency tinykeys to v2.1.0 (#16951) 2023-06-17 20:33:36 -04:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
afdeb36258 Update vaadinWebComponents monorepo to v24.1.0 (#16844)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-17 14:56:35 -04:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>Steve Repsher
d4f4ee1e59 Update dependency tinykeys to v2 (#16873)
* Update dependency tinykeys to v2

* Switch to named import

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Steve Repsher <[email protected]>
2023-06-17 16:53:36 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
bcceef30bb Update dependency @octokit/auth-oauth-device to v5 (#16947)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-17 12:46:30 -04:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
356935fefc Update formatjs monorepo (#16945)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-17 15:28:29 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
49f59d7162 Update CodeMirror (#16942)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-17 11:17:37 -04:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
67e8357bb9 Update dependency sinon to v15.1.2 (#16940)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-17 11:15:05 -04:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
b8da712186 Update typescript-eslint monorepo to v5.59.11 (#16941)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-17 11:13:30 -04:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
a409f494a2 Update dependency @types/leaflet-draw to v1.0.7 (#16939)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-17 05:55:36 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
3b32825e2a Update dependency @octokit/plugin-retry to v5.0.3 (#16938)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-17 05:47:46 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>Steve Repsher
12b7b903bc Update dependency core-js to v3.31.0 (#16913)
* Update dependency core-js to v3.31.0

* Update babel setting

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Steve Repsher <[email protected]>
2023-06-17 05:40:10 +00:00
Joakim SørensenandGitHub 3be601a3b9 Add location to backups table (#16813) 2023-06-15 16:08:32 +02:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
d0641d64bd Update dependency eslint-plugin-lit-a11y to v3 (#16910)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-14 16:03:53 -04:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
3a64f64894 Update dependency @material/web to v1.0.0-pre.10 (#16841)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-14 18:08:19 +02:00
karwostsandGitHub 7182abfec5 Fix history chart when final sensor state is unavailable (#16852) 2023-06-14 17:45:57 +02:00
JakobDNSandGitHub 2076a083d3 en.json: Fix typo "recieved" -> "received" (#16903) 2023-06-14 16:18:02 +02:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
73317a48ee Update dependency rollup-plugin-visualizer to v5.9.2 (#16899)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-13 17:27:30 -04:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
b891c53994 Update dependency webpack-dev-server to v4.15.1 (#16900)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-13 17:26:26 -04:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
c1c18affbc Update dependency webpack to v5.86.0 (#16749)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-13 16:09:57 -04:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
3bea2cf7f9 Update dependency @rollup/plugin-commonjs to v25.0.1 (#16892)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-13 15:28:58 -04:00
Steve RepsherandGitHub fa1a6affa7 Use ES modules and dynamic import for Webpack latest builds (#16849) 2023-06-13 18:12:44 +02:00
Bram KragtenandGitHub 197638b282 Fix date demo in gallery (#16894) 2023-06-13 15:27:21 +00:00
karwostsandGitHub 6e3cf0975b Fix mqtt debug info dialog too big (#16893) 2023-06-13 17:22:45 +02:00
Paul BotteinandGitHub 9875cb2723 Only catch event inside color wheel (#16890) 2023-06-13 17:21:01 +02:00
Paul BotteinandGitHub f8ea7e0ef2 Make actions available as event (#16839) 2023-06-13 15:24:36 +02:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
c821f4296e Update dependency @octokit/auth-oauth-device to v4.0.5 (#16891)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-13 09:23:14 -04:00
5fc4e7a95d Introduce Intl.ListFormat (#16857)
Co-authored-by: Steve Repsher <[email protected]>
Co-authored-by: Bram Kragten <[email protected]>
2023-06-13 15:22:23 +02:00
Paul BotteinandGitHub 49fa7ec4ed Clear more info content when switching entity (#16846) 2023-06-13 12:20:02 +02:00
Bram KragtenandGitHub 780de42e4b Allow to show times in the UI in the timezone of the server (#16799) 2023-06-13 12:12:13 +02:00
Paul BotteinandGitHub f7722a270f Add safe zone to reach min and max temperature easily with temperature (#16880)
Add safe zone to reach min and max temperature easily with temperature picker
2023-06-13 11:55:52 +02:00
Paul BotteinandGitHub e3faa618bf Use esm module for hls.js (#16878) 2023-06-12 07:49:39 -04:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
655b630fa5 Bump actions/checkout from 3.5.2 to 3.5.3 (#16876)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-12 11:46:54 +02:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
983bba357a Update babel monorepo to v7.22.5 (#16872)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-11 17:42:06 -04:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
17a2560d94 Update dependency webpack-cli to v5.1.4 (#16862)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-11 13:28:12 -04:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
eaffed9ff8 Update dependency @octokit/plugin-retry to v5.0.2 (#16861)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-11 13:27:10 -04:00
Matthias AlphartandGitHub 273992c8e9 Consolidate dependency updates in release-drafter (#16856) 2023-06-10 16:39:43 +02:00
renovate[bot]andGitHub c77905bd22 Update dependency glob to v10.2.7 (#16851) 2023-06-09 20:45:14 -04:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
15132783d4 Update formatjs monorepo (#16843)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-09 10:49:59 -04:00
Paul BotteinandGitHub 2b6cf55638 Add paste to else automation action (#16840) 2023-06-09 16:38:01 +02:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
e4eaa52d53 Update dependency webpack-cli to v5.1.3 (#16809)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-09 09:04:55 -04:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
e1f73dac02 Update dependency hls.js to v1.4.5 (#16842)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-09 13:02:14 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
36de0e5c8c Update CodeMirror (#16820)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-09 08:55:19 -04:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
549e4e7fb3 Update typescript-eslint monorepo to v5.59.9 (#16832)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-09 08:48:34 -04:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
dd9c4e35bf Update dependency @octokit/plugin-retry to v5.0.1 (#16835)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-09 08:46:50 -04:00
Paul Bottein 8580d3f9bf Bumped version to 20230608.0 2023-06-08 15:08:18 +02:00
Bram KragtenandGitHub 6d29b764d3 Integration page fixes (#16822) 2023-06-08 14:11:52 +02:00
Joakim SørensenandGitHub 78cff3a921 Use menu_options instead of menu_issues for translation (#16823) 2023-06-08 11:13:12 +00:00
Paul BotteinandGitHub e3c312feaf Sort related entities by name (#16821) 2023-06-08 13:01:46 +02:00
Paul BotteinandGitHub 31e4166248 Make to full integration card header clickable (#16819) 2023-06-08 10:42:26 +02:00
Bram Kragten 0442e3e06e Bumped version to 20230607.0 2023-06-07 12:15:32 +02:00
english-raandGitHub 0a8252c16a Fixed issue where the cursor would not change to grabbing when a user… (#16808) 2023-06-07 09:44:54 +00:00
puddlyandGitHub 0a62d711f2 Allow the ZHA serial port path to wrap if it is too long (#16806)
Allow the serial port path to wrap if it is too long
2023-06-07 11:34:17 +02:00
karwostsandGitHub d7c3ff3e9d Fix cancel button in automation row alias rename dialog (#16810) 2023-06-07 11:27:50 +02:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2767f866f3 Update dependency @octokit/plugin-retry to v5 (#16803)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-06 19:53:57 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>Bram Kragten
040d5af0aa Update dependency eslint to v8.42.0 (#16789)
* Update dependency eslint to v8.42.0

* Update resize-observer.polyfill.ts

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Bram Kragten <[email protected]>
2023-06-06 19:44:54 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
06c6e312b0 Update workbox monorepo to v7 (major) (#16747)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-06 21:41:04 +02:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
841dffe563 Update Yarn to v3.6.0 (#16759)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-06 21:39:10 +02:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
a41e0d446f Update vaadinWebComponents monorepo to v24.0.8 (#16768)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-06 21:38:08 +02:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
9a0f24cd8b Update dependency @lrnwebcomponents/simple-tooltip to v7.0.2 (#16758)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-06 21:37:20 +02:00
puddlyandGitHub 2e531a9006 Add channel 26 to ZHA channel changing dialog dropdown (#16801)
Add 26 to list of valid ZHA network channels
2023-06-06 19:31:50 +00:00
karwostsandGitHub 76255f2efb Fix ha-devices-picker when changing or deleting devices (#16739) 2023-06-06 21:28:07 +02:00
karwostsandGitHub 19fc92419a Add miscellaneous UI elements for translation (#16797) 2023-06-06 16:37:58 +02:00
Bram Kragten e7c2625cf1 Bumped version to 20230606.0 2023-06-06 16:32:45 +02:00
Bram KragtenandGitHub c39fdcda6e Fix 403 on state-badge connect (#16795) 2023-06-06 13:42:45 +02:00
Paul BotteinandGitHub fd1381ab3b Update history chart when entity change in the more info dialog (#16794) 2023-06-06 11:14:11 +02:00
Paul BotteinandGitHub 7b8f4d1e72 Fix label for cover button mode (#16791) 2023-06-06 09:07:53 +02:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
b0a278df97 Update dependency @octokit/plugin-retry to v4.1.6 (#16788)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-06 01:25:59 -04:00
Bram KragtenandGitHub 93e31df106 Use integration_type as header for config entries (#16786) 2023-06-05 19:18:42 +02:00
Bram KragtenandGitHub 47fdae764f Improve display of disabled config entries (#16784) 2023-06-05 19:00:06 +02:00
Bram Kragten b8efc06caa Bumped version to 20230605.0 2023-06-05 18:22:38 +02:00
Bram KragtenandGitHub fcacdf6534 Add all devices and entities link to integration page (#16781) 2023-06-05 15:52:11 +00:00
Paul BotteinandGitHub 45d260f0ce Move add config entry button to card (#16783) 2023-06-05 15:49:05 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
d5f46a69b0 Update dependency @octokit/plugin-retry to v4.1.5 (#16782)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-05 17:45:44 +02:00
Bram KragtenandGitHub fe8eb333b9 Limit integration card to 1 action row (#16780) 2023-06-05 17:23:28 +02:00
677cd2de10 Fix integration card tooltip (#16779)
* Fix integration card tooltip

* Update src/panels/config/integrations/ha-integration-header.ts

Co-authored-by: Bram Kragten <[email protected]>

---------

Co-authored-by: Bram Kragten <[email protected]>
2023-06-05 14:13:27 +00:00
Bram KragtenandGitHub 1470eb484f Add more info controls for date/time/datetime (#16775)
* Add more info controls for date/time/datetime

* Discard changes to src/panels/lovelace/entity-rows/hui-date-entity-row.ts

* handle unavailable
2023-06-05 16:10:38 +02:00
Bram KragtenandGitHub 10ee8fda5b Improve protocol integration add device / integration (#16767) 2023-06-05 14:08:55 +00:00
Bram KragtenandGitHub e044ddcb57 Align+fix date time entity rows (#16774) 2023-06-05 13:55:15 +00:00
Bram KragtenandGitHub 29c564bb69 Fix maps card with location sources (#16778) 2023-06-05 15:53:57 +02:00
Bram KragtenandGitHub 1bf03f020e Fix closing notification drawer (#16769) 2023-06-05 14:26:51 +02:00
Bram KragtenandGitHub 6c684fd8ee Show number config entries when no devices/entities (#16766) 2023-06-05 14:17:03 +02:00
Simon LamonandGitHub ddaf403378 Fix dropdown selection in General Settings (#16754) 2023-06-05 11:57:20 +00:00
Paul BotteinandGitHub b337074758 Fix collapsed masonry view in safari (#16772) 2023-06-05 13:48:16 +02:00
Bram KragtenandGitHub a96eff4d25 Fix padding on thread config panel (#16770) 2023-06-05 13:06:54 +02:00
e6bdc3a15e Disable ZHA channel changing when multi-PAN is in use (#16731)
* Show baudrate and port in the ZHA network info

* Do not allow changing the Zigbee channel with the multiprotocol addon

* Include translations as well

* Update src/translations/en.json

---------

Co-authored-by: Bram Kragten <[email protected]>
2023-06-05 10:27:36 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
33e15eec22 Update dependency @lit-labs/context to v0.3.2 (#16760)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-05 09:50:00 +02:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
3c0afd6cde Update dependency lit to v2.7.5 (#16763)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-05 09:48:45 +02:00
Joakim SørensenandGitHub 31a3fa02d9 Allow for lazy loading images in markdown (#16746) 2023-06-05 09:46:38 +02:00
Paul BotteinandGitHub 71954f545c Fix white brightness effect on color wheel (#16738) 2023-06-05 09:39:53 +02:00
Paul BotteinandGitHub 9f3e8abe69 Don't show edit favorite colors button if the light doesn't support it (#16750) 2023-06-05 09:39:36 +02:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
21f983572c Update dependency @octokit/plugin-retry to v4.1.4 (#16762)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-05 01:20:24 -04:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
5667d71b02 Update dependency @rollup/plugin-node-resolve to v15.1.0 (#16741)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-02 23:40:50 -04:00
Bram KragtenandGitHub 0d0e5fdaaa Hide ignored entries (#16737) 2023-06-02 12:08:02 +02:00
karwostsandGitHub b1f5ff26d9 Fix device selector when picking devices with no entities (#16734) 2023-06-02 11:26:07 +02:00
renovate[bot]andGitHub 27451ca30e Update typescript-eslint monorepo to v5.59.8 (#16730) 2023-06-01 22:09:45 -04:00
Paul BotteinandGitHub 928b4e6f1e Add native color picker option (fix for firefox) (#16729) 2023-06-01 16:31:18 +00:00
Paul BotteinandGitHub b63a32109e Add native color picker option (#16726) 2023-06-01 18:06:26 +02:00
Bram Kragten efb0098eac Merge branch 'master' into dev 2023-06-01 18:04:54 +02:00
Bram Kragten a67b845812 Bumped version to 20230601.1 2023-06-01 18:01:55 +02:00
renovate[bot]andGitHub d29b7626f3 Update babel monorepo to v7.22.4 (#16724) 2023-06-01 17:13:30 +02:00
Paul BotteinandGitHub 47ac7062dc Increase size of color wheel cursor on mobile (#16723) 2023-06-01 16:36:32 +02:00
Paul BotteinandGitHub e7f5d927b1 Open right mode when editing favorite color (#16719)
* Open right mode when editing favorite color

* Add missing type
2023-06-01 16:35:24 +02:00
Paul BotteinandGitHub 6b06393559 Fix outlined button margin on iOS app (#16717) 2023-06-01 14:20:56 +02:00
Paul BotteinandGitHub efa02c309b Put button menu above toolbar in automation editor (#16716) 2023-06-01 13:35:23 +02:00
Bram KragtenandGitHub 9b2e77e781 Align integration card, limit height of logo (#16714) 2023-06-01 12:01:09 +02:00
Joakim SørensenandGitHub 24b4060c97 Add missing imports in backup dialogs (#16715) 2023-06-01 09:54:53 +00:00
Paul BotteinandGitHub 5e4c1ab4fc Share clipboard between automation and script (#16713) 2023-06-01 09:40:02 +00:00
Paul BotteinandGitHub 287e6dbb60 Fix define variables action (#16712) 2023-06-01 11:38:59 +02:00
Paul BotteinandGitHub 40c9292e16 Improve padding on integration logo (#16711) 2023-06-01 11:35:42 +02:00
Paul BotteinandGitHub d51dd00ec7 Add domain icon for time and datetime (#16710) 2023-06-01 09:07:18 +00:00
Paul BotteinandGitHub 0db50d13d3 Clean helper config entry fetching in settings (#16709) 2023-06-01 10:37:34 +02:00
9eb3618d97 20230601.0 (#16705)
* Fix fetching helper config entry (#16704)

* Fix fetching helper config entry

* willUpdate

* Bumped version to 20230601.0

---------

Co-authored-by: Bram Kragten <[email protected]>
2023-05-31 20:54:02 -04:00
Paulus Schoutsen 03eee9c7d5 Bumped version to 20230601.0 2023-05-31 20:49:41 -04:00
Bram KragtenandGitHub a49d59f4c6 Fix fetching helper config entry (#16704)
* Fix fetching helper config entry

* willUpdate
2023-06-01 00:58:03 +02:00
Bram KragtenandGitHub 990ade4294 20230531.0 (#16697) 2023-05-31 15:45:11 +02:00
Patrick ZAJDAandGitHub a4c57f09ad Set alt attribute to Assistant name in the exposed entities settings (#16698) 2023-05-31 13:36:16 +00:00
Bram Kragten c1fa6d6f8c Merge branch 'master' into dev 2023-05-31 15:20:23 +02:00
Bram Kragten 3bfcb808f5 Bumped version to 20230531.0 2023-05-31 15:17:21 +02:00
Paul BotteinandGitHub 9a30fe81c6 Use delete instead of remove for favorite colors (#16696) 2023-05-31 13:16:00 +00:00
Paul BotteinandGitHub c864edee72 Reset edit mode when closing more info dialog (#16695) 2023-05-31 13:11:10 +00:00
Bram KragtenandGitHub 36268d5048 fix error messages of addon mount picker (#16694) 2023-05-31 15:00:32 +02:00
5217d427e9 Support to|from null in UI for ha-automation-trigger-state (#15071)
Co-authored-by: Bram Kragten <[email protected]>
2023-05-31 12:28:16 +00:00
aea668e754 Minor UI bugfixes for selector-datetime and dialog-date-picker (#15759)
Co-authored-by: Bram Kragten <[email protected]>
2023-05-31 12:26:01 +00:00
Bram KragtenandGitHub 2219c9bbd3 Throttle replace state in restore scroll (#16693) 2023-05-31 12:18:48 +00:00
Bram KragtenandGitHub 9b896c63b6 Fix my link for config flow start (#16689) 2023-05-31 14:05:11 +02:00
Bram KragtenandGitHub 30af576ff5 Remove unused old code (#16691) 2023-05-31 12:04:45 +00:00
Bram KragtenandGitHub 585db6ab3f Close dialog when clicked on link (#16690) 2023-05-31 14:01:47 +02:00
karwostsandGitHub 046475e7ac Fix blueprint script editor defaults handling (#16196) 2023-05-31 12:58:22 +02:00
karwostsandGitHub 648383addd Fix ha-combo-box open direction (#16119) 2023-05-31 12:55:44 +02:00
Paul BotteinandGitHub 10018b4c32 Update default colors for more info light favorite colors (#16688)
Update default favorite color for more-info-light
2023-05-31 12:48:49 +02:00
Philip AllgaierandGitHub 872d3e4875 Make badge colors use the generic error/warning/success/info colors (#14728) 2023-05-31 12:44:48 +02:00
Bram KragtenandGitHub 881f5e5012 Fix energy compare (#16687) 2023-05-31 12:42:03 +02:00
Bram KragtenandGitHub 9797950f32 Use memoize in formatDateNumeric (#16686) 2023-05-31 12:36:52 +02:00
Bram KragtenandGitHub 25986f239e Blueprints: show error in alert dialog when clicked (#16684) 2023-05-31 12:35:38 +02:00
b586210ff1 Support zwave config parameters not on endpoint 0 (#16597)
Co-authored-by: Bram Kragten <[email protected]>
2023-05-31 12:11:26 +02:00
karwostsandGitHub 748925ede9 Localize time string in time trigger and condition (#16681) 2023-05-31 12:07:30 +02:00
Paul BotteinandGitHub a9f1c4a198 Add button bar for light modes (#16683)
* Add button bar for light modes

* Add disabled style

* Fix favorite colors display condition

* Fix color temp button
2023-05-31 11:48:22 +02:00
Bram KragtenandGitHub d914fb0cfc Revert "Use ES modules and dynamic import for Webpack latest builds (… (#16679)
Revert "Use ES modules and dynamic import for Webpack latest builds (#16620)"

This reverts commit 7b350e31dd.
2023-05-30 17:56:38 -04:00
Bram Kragten 5218e1352e async cleanup 2023-05-30 23:43:13 +02:00
Bram KragtenandGitHub eb0759a3b3 Fix integration translations (#16678) 2023-05-30 23:20:12 +02:00
Bram Kragten 88522ed155 change order 2023-05-30 22:59:34 +02:00
Bram KragtenandGitHub 64e7fc6591 Fix my link for integration (#16676) 2023-05-30 22:02:52 +02:00
Christoph Wen, B.ScandGitHub 2ad6253b72 Add setting to localize numeric dates independent from language (#15770) (#16489) 2023-05-30 19:39:27 +00:00
Bram KragtenandGitHub 7e5a85dbe7 Allow to change switch as x (#16671) 2023-05-30 21:32:06 +02:00
0771a780d9 Light more info enhancement (#16673)
Co-authored-by: Bram Kragten <[email protected]>
2023-05-30 18:41:12 +00:00
Steve RepsherandGitHub 7b350e31dd Use ES modules and dynamic import for Webpack latest builds (#16620) 2023-05-30 18:27:49 +00:00
70fbf68603 Overhaul Integrations page, add integration page (#16640)
Co-authored-by: Paul Bottein <[email protected]>
2023-05-30 20:09:26 +02:00
Bram KragtenandGitHub 2b4f199337 Tweak style of related items (#16672) 2023-05-30 16:12:41 +00:00
Bram KragtenandGitHub a70d7d8de3 Related blueprints (#16618) 2023-05-30 15:04:45 +02:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
e0c1f98803 Update babel monorepo to v7.22.3 (#16668)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-30 10:40:14 +00:00
Bram KragtenandGitHub 4b7a517d98 Fix async update localize (#16667) 2023-05-30 10:25:21 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>Steve RepsherBram Kragten
26d4839dfd Update dependency @types/chromecast-caf-receiver to v6 (#15724)
* Update dependency @types/chromecast-caf-receiver to v6

* Import cast namespace from receiver for receiver/media entry

* Use sender event types in manager and remove anonymous listeners

* Apply suggestions from code review

* prettier

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Steve Repsher <[email protected]>
Co-authored-by: Bram Kragten <[email protected]>
2023-05-30 09:30:04 +00:00
c358d724a7 update hidden_description to explain the behavior of the visible setting more clearly. (#16662)
Co-authored-by: Bram Kragten <[email protected]>
2023-05-30 09:27:22 +00:00
Allen PorterandGitHub 0ab7934c09 Add a vertical scrollbar for the calendar list (#16657) 2023-05-30 10:49:14 +02:00
Allen PorterandGitHub 6eac229901 Disable calendar selection when editing existing Calendar Events (#16656) 2023-05-30 10:48:34 +02:00
Joakim SørensenandGitHub 5006dfc138 Use __STATIC_PATH__ in more places so the supervisor panel can reach paths (#16665)
Use __STATIC_PATH__ in more places so the supervisor panel can reach paths
2023-05-30 10:45:58 +02:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
d9d38efd93 Update babel monorepo (#16658)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-30 00:40:11 -04:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
9fe3a500d5 Update workbox monorepo to v6.6.0 (#16659)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-30 00:29:12 -04:00
3df7c50690 Add frontend support for datetime platform (#14391)
Co-authored-by: Bram Kragten <[email protected]>
2023-05-29 23:32:57 +02:00
Bram KragtenandGitHub 38cf774a0d Use ESM version of hls.js (#16655) 2023-05-29 20:38:21 +02:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
98d22d38c3 Update vaadinWebComponents monorepo to v24.0.7 (#16653)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-29 16:30:29 +02:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
357dbb591b Update babel monorepo to v7.22.0 (#16654)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-29 16:29:54 +02:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
aa5df06bc3 Update dependency @lezer/highlight to v1.1.6 (#16652)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-29 16:28:24 +02:00
rtm516andGitHub 07a66b4bff Fix topbar overflowing card for add-on store (#16637) 2023-05-29 14:22:03 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
f466196fa8 Update dependency hls.js to v1.4.4 (#16651)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-29 16:10:15 +02:00
Marvin WichmannandGitHub 04ae0b34af Update WS commands for config entries (#16647) 2023-05-29 16:08:25 +02:00
Joakim SørensenandGitHub 6f48267dae Include share as mount usage option (#16636) 2023-05-29 11:43:12 +02:00
renovate[bot]andGitHub be1f5d99c8 Update dependency webpack to v5.84.1 (#16649) 2023-05-28 20:46:25 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
27b9b4dcc5 Update fullcalendar monorepo to v6.1.8 (#16644)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-28 13:48:53 -04:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
08b57d6168 Update dependency webpack to v5.84.0 (#16641)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-28 13:46:32 -04:00
renovate[bot]andGitHub 3e474daa32 Update dependency @lezer/highlight to v1.1.5 (#16638) 2023-05-27 13:11:42 -04:00
renovate[bot]andGitHub 48c1e8b56c Update dependency @codemirror/state to v6.2.1 (#16632) 2023-05-27 13:09:19 -04:00
karwostsandGitHub fd0c0a95ca Add a description for time condition (#16499) 2023-05-27 18:27:24 +02:00
Paul BotteinandGitHub 83570f2419 Add missing translations for effect and preset translation in more info (#16634) 2023-05-26 23:01:52 +02:00
Paul BotteinandGitHub 633c6cfc9b Use colored slider background for more info (#16633) 2023-05-26 17:45:57 +02:00
Paul BotteinandGitHub 54b4c9f347 Add favorite colors to more info light (#16592)
* Add default favorite colors

* Don't show favorite colors if no entity registry entry

* Move color picker in its own component

* Fix more info dialog width

* Make favorite color editable

* Don't include white mode as favorite

* Add label for favorite color button

* Add support for hs, rgbw and rgbww colors

* Adapt color wheel color according to white value

* Add translation

* Add keyboard control to color temp wheel

* Use bottom sheet style for edit favorite dialog

* Fix listener

* Edit color temp icon

* Disable favorite color when available

* Only admin can edit a color

* Refactor close action

* Clean css

* Use ha button

* Fix ha-border-radius for bottom sheet
2023-05-26 17:23:49 +02:00
85e7986b44 Always show "polling for updates" switch (#16629)
Co-authored-by: Bram Kragten <[email protected]>
2023-05-26 15:52:57 +02:00
Paul BotteinandGitHub da0cf9d950 Create outlined button component (#16631)
* Create outlined button component

* Fix css comment

* Don't use Md classes

* Simplify
2023-05-26 15:28:49 +02:00
Bram KragtenandGitHub ef51336770 Don't set name for entities that use device name already (#16613) 2023-05-26 14:54:49 +02:00
Bram Kragten bc81499e7c Bumped version to 20230503.3 2023-05-05 16:26:53 +02:00
Paul BotteinandBram Kragten c31378ad75 Fetch entries integration onboarding (#16424)
* Fetch loaded entries in integration onboarding

* Proper fix
2023-05-05 16:26:44 +02:00
Paul BotteinandBram Kragten 8ce8b63cfc Adapt unsupported microphone message (#16419) 2023-05-05 16:15:23 +02:00
Bram Kragten 11f77b09e6 Bumped version to 20230503.2 2023-05-04 15:46:34 +02:00
Bram Kragten ba7d7556a8 fix expose view for yaml config (#16408) 2023-05-04 15:42:14 +02:00
Bram Kragten 31da0d8678 Fix codemirror selection color (#16409) 2023-05-04 15:41:57 +02:00
Bram Kragten 9f195534b5 Fix entity areas in expose (#16402) 2023-05-04 15:41:40 +02:00
Bram KragtenandGitHub a293e7b91c 20230503.1 (#16399) 2023-05-03 16:15:27 +02:00
Bram KragtenandGitHub 1ea70f3191 20230503.0 (#16395) 2023-05-03 14:14:02 +02:00
Bram KragtenandGitHub 29aa762f7c 20230502.0 (#16382) 2023-05-02 22:01:32 +02:00
Bram KragtenandGitHub d0c7f65256 20230501.0 (#16364) 2023-05-01 19:55:38 +02:00
Paul BotteinandGitHub 71dd822978 20230428.0 (#16347) 2023-04-28 17:40:58 +02:00
Paul BotteinandGitHub c50aad8403 20230427.0 (#16338) 2023-04-27 17:31:29 +02:00
Bram KragtenandGitHub b7667d2cbf 20230426.0 (#16327) 2023-04-26 18:31:51 +02:00
394 changed files with 15727 additions and 7106 deletions
+6
View File
@@ -10,6 +10,12 @@ supports es6-module-dynamic-import
not Safari < 13
not iOS < 13
# Exclude KaiOS, QQ, and UC browsers due to lack of sufficient feature support data
# Babel ignores these automatically, but we need here for Webpack to output ESM with dynamic imports
not KaiOS > 0
not QQAndroid > 0
not UCAndroid > 0
# Exclude unsupported browsers
not dead
+1 -1
View File
@@ -1,5 +1,5 @@
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.148.1/containers/python-3/.devcontainer/base.Dockerfile
FROM mcr.microsoft.com/vscode/devcontainers/python:0-3.10
FROM mcr.microsoft.com/vscode/devcontainers/python:0-3.11
ENV \
DEBIAN_FRONTEND=noninteractive \
+5
View File
@@ -1,3 +1,8 @@
categories:
- title: 'Dependency updates'
collapse-after: 3
labels:
- 'dependencies'
template: |
## What's Changed
+2 -2
View File
@@ -21,7 +21,7 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps:
- name: Check out files from GitHub
uses: actions/[email protected].2
uses: actions/[email protected].3
with:
ref: dev
@@ -57,7 +57,7 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps:
- name: Check out files from GitHub
uses: actions/[email protected].2
uses: actions/[email protected].3
with:
ref: master
+4 -4
View File
@@ -24,7 +24,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
uses: actions/[email protected].2
uses: actions/[email protected].3
- name: Setup Node
uses: actions/[email protected]
with:
@@ -47,7 +47,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
uses: actions/[email protected].2
uses: actions/[email protected].3
- name: Setup Node
uses: actions/[email protected]
with:
@@ -65,7 +65,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
uses: actions/[email protected].2
uses: actions/[email protected].3
- name: Setup Node
uses: actions/[email protected]
with:
@@ -83,7 +83,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
uses: actions/[email protected].2
uses: actions/[email protected].3
- name: Setup Node
uses: actions/[email protected]
with:
+1 -1
View File
@@ -23,7 +23,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/[email protected].2
uses: actions/[email protected].3
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
+2 -2
View File
@@ -22,7 +22,7 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps:
- name: Check out files from GitHub
uses: actions/[email protected].2
uses: actions/[email protected].3
with:
ref: dev
@@ -58,7 +58,7 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps:
- name: Check out files from GitHub
uses: actions/[email protected].2
uses: actions/[email protected].3
with:
ref: master
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps:
- name: Check out files from GitHub
uses: actions/[email protected].2
uses: actions/[email protected].3
- name: Setup Node
uses: actions/[email protected]
+1 -1
View File
@@ -21,7 +21,7 @@ jobs:
if: github.repository == 'home-assistant/frontend' && contains(github.event.pull_request.labels.*.name, 'needs design preview')
steps:
- name: Check out files from GitHub
uses: actions/[email protected].2
uses: actions/[email protected].3
- name: Setup Node
uses: actions/[email protected]
+1 -1
View File
@@ -9,7 +9,7 @@ jobs:
lock:
runs-on: ubuntu-latest
steps:
- uses: dessant/[email protected].0
- uses: dessant/[email protected].1
with:
github-token: ${{ github.token }}
issue-lock-inactive-days: "30"
+2 -2
View File
@@ -6,7 +6,7 @@ on:
- cron: "0 1 * * *"
env:
PYTHON_VERSION: "3.10"
PYTHON_VERSION: "3.11"
NODE_OPTIONS: --max_old_space_size=6144
permissions:
@@ -20,7 +20,7 @@ jobs:
contents: write
steps:
- name: Checkout the repository
uses: actions/[email protected].2
uses: actions/[email protected].3
- name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@v4
+9
View File
@@ -5,8 +5,17 @@ on:
branches:
- dev
permissions:
contents: read
jobs:
update_release_draft:
permissions:
# write permission for contents is required to create a github release
contents: write
# write permission for pull-requests is required for autolabeler
# otherwise, read permission is required at least
pull-requests: read
runs-on: ubuntu-latest
steps:
- uses: release-drafter/release-drafter@v5
+3 -3
View File
@@ -6,7 +6,7 @@ on:
- published
env:
PYTHON_VERSION: "3.10"
PYTHON_VERSION: "3.11"
NODE_OPTIONS: --max_old_space_size=6144
# Set default workflow permissions
@@ -23,7 +23,7 @@ jobs:
contents: write # Required to upload release assets
steps:
- name: Checkout the repository
uses: actions/[email protected].2
uses: actions/[email protected].3
- name: Verify version
uses: home-assistant/actions/helpers/verify-version@master
@@ -76,7 +76,7 @@ jobs:
- name: Build wheels
uses: home-assistant/[email protected]
with:
abi: cp310
abi: cp311
tag: musllinux_1_2
arch: amd64
wheels-key: ${{ secrets.WHEELS_KEY }}
+1 -1
View File
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/[email protected].2
uses: actions/[email protected].3
- name: Upload Translations
run: |
@@ -0,0 +1,39 @@
diff --git a/modular/sortable.complete.esm.js b/modular/sortable.complete.esm.js
index 02e9f2d6bebeb430fe6e7c1cc3f9c3c9df051f14..bb8268b0844a1faa4108cc92c0be2a3dbaf23f83 100644
--- a/modular/sortable.complete.esm.js
+++ b/modular/sortable.complete.esm.js
@@ -1657,7 +1657,7 @@ Sortable.prototype =
target = parent; // store last element
}
/* jshint boss:true */
- while (parent = parent.parentNode);
+ while (parent = parent.parentNode || parent.getRootNode().host);
}
_unhideGhostForTarget();
diff --git a/modular/sortable.core.esm.js b/modular/sortable.core.esm.js
index b04c8b4634f7c6b4ef1aadbb48afe6564306dea9..39a107163c8c336ebd669b5ea8a936af87e1c1e7 100644
--- a/modular/sortable.core.esm.js
+++ b/modular/sortable.core.esm.js
@@ -1657,7 +1657,7 @@ Sortable.prototype =
target = parent; // store last element
}
/* jshint boss:true */
- while (parent = parent.parentNode);
+ while (parent = parent.parentNode || parent.getRootNode().host);
}
_unhideGhostForTarget();
diff --git a/modular/sortable.esm.js b/modular/sortable.esm.js
index 6ec7ed1bb557e21c2578200161e989c65d23150b..0a05475a22904472fac6c13f524c674da76584b0 100644
--- a/modular/sortable.esm.js
+++ b/modular/sortable.esm.js
@@ -1657,7 +1657,7 @@ Sortable.prototype =
target = parent; // store last element
}
/* jshint boss:true */
- while (parent = parent.parentNode);
+ while (parent = parent.parentNode || parent.getRootNode().host);
}
_unhideGhostForTarget();
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -8,4 +8,4 @@ plugins:
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
spec: "@yarnpkg/plugin-interactive-tools"
yarnPath: .yarn/releases/yarn-3.5.1.cjs
yarnPath: .yarn/releases/yarn-3.6.0.cjs
+3 -1
View File
@@ -77,6 +77,7 @@ module.exports.htmlMinifierOptions = {
module.exports.terserOptions = ({ latestBuild, isTestBuild }) => ({
safari10: !latestBuild,
ecma: latestBuild ? 2015 : 5,
module: latestBuild,
format: { comments: false },
sourceMap: !isTestBuild,
});
@@ -97,7 +98,7 @@ module.exports.babelOptions = ({ latestBuild, isProdBuild, isTestBuild }) => ({
"@babel/preset-env",
{
useBuiltIns: latestBuild ? false : "entry",
corejs: latestBuild ? false : { version: "3.30", proposals: true },
corejs: latestBuild ? false : { version: "3.31", proposals: true },
bugfixes: true,
},
],
@@ -259,6 +260,7 @@ module.exports.config = {
isHassioBuild: true,
defineOverlay: {
__SUPERVISOR__: true,
__STATIC_PATH__: `"${paths.hassio_publicPath}/static/"`,
},
};
},
+2 -1
View File
@@ -111,9 +111,10 @@ gulp.task("copy-translations-supervisor", async () => {
copyTranslations(staticDir);
});
gulp.task("copy-locale-data-supervisor", async () => {
gulp.task("copy-static-supervisor", async () => {
const staticDir = paths.hassio_output_static;
copyLocaleData(staticDir);
copyFonts(staticDir);
});
gulp.task("copy-static-app", async () => {
+2 -2
View File
@@ -21,7 +21,7 @@ gulp.task(
"build-supervisor-translations",
"copy-translations-supervisor",
"build-locale-data",
"copy-locale-data-supervisor",
"copy-static-supervisor",
env.useRollup() ? "rollup-watch-hassio" : "webpack-watch-hassio"
)
);
@@ -37,7 +37,7 @@ gulp.task(
"build-supervisor-translations",
"copy-translations-supervisor",
"build-locale-data",
"copy-locale-data-supervisor",
"copy-static-supervisor",
env.useRollup() ? "rollup-prod-hassio" : "webpack-prod-hassio",
"gen-pages-hassio-prod",
...// Don't compress running tests
+1
View File
@@ -17,6 +17,7 @@ const modules = {
"intl-datetimeformat": "DateTimeFormat",
"intl-numberformat": "NumberFormat",
"intl-displaynames": "DisplayNames",
"intl-listformat": "ListFormat",
};
gulp.task("create-locale-data", (done) => {
+12 -2
View File
@@ -41,7 +41,7 @@ const createWebpackConfig = ({
return {
name,
mode: isProdBuild ? "production" : "development",
target: ["web", latestBuild ? "es2017" : "es5"],
target: `browserslist:${latestBuild ? "modern" : "legacy"}`,
// For tests/CI, source maps are skipped to gain build speed
// For production, generate source maps for accurate stack traces without source code
// For development, generate "cheap" versions that can map to original line numbers
@@ -84,6 +84,13 @@ const createWebpackConfig = ({
],
moduleIds: isProdBuild && !isStatsBuild ? "deterministic" : "named",
chunkIds: isProdBuild && !isStatsBuild ? "deterministic" : "named",
splitChunks: {
// Disable splitting for web workers with ESM output
// Imports of external chunks are broken
chunks: latestBuild
? (chunk) => !chunk.canBeInitial() && !/^.+-worker$/.test(chunk.name)
: undefined,
},
},
plugins: [
!isStatsBuild && new WebpackBar({ fancy: !isProdBuild }),
@@ -160,9 +167,12 @@ const createWebpackConfig = ({
"lit/polyfill-support$": "lit/polyfill-support.js",
"@lit-labs/virtualizer/layouts/grid":
"@lit-labs/virtualizer/layouts/grid.js",
"@lit-labs/virtualizer/polyfills/resize-observer-polyfill/ResizeObserver":
"@lit-labs/virtualizer/polyfills/resize-observer-polyfill/ResizeObserver.js",
},
},
output: {
module: latestBuild,
filename: ({ chunk }) =>
!isProdBuild || isStatsBuild || dontHash.has(chunk.name)
? "[name].js"
@@ -196,7 +206,7 @@ const createWebpackConfig = ({
: undefined,
},
experiments: {
topLevelAwait: true,
outputModule: true,
},
};
};
+1 -1
View File
@@ -1,4 +1,4 @@
export {}; // for Babel to treat as a module
import { cast } from "chromecast-caf-receiver";
const castContext = cast.framework.CastReceiverContext.getInstance();
+2 -1
View File
@@ -1,2 +1,3 @@
/* eslint-disable no-undef */
import { cast } from "chromecast-caf-receiver";
export const castContext = cast.framework.CastReceiverContext.getInstance();
+1 -1
View File
@@ -1,4 +1,4 @@
/* eslint-disable no-undef */
import { cast } from "chromecast-caf-receiver";
import { CAST_NS } from "../../../src/cast/const";
import { HassMessage } from "../../../src/cast/receiver_messages";
import "../../../src/resources/custom-card-support";
+4
View File
@@ -45,6 +45,10 @@ export default [
header: "Users",
pages: ["user-types", "configuration-menu"],
},
{
category: "date-time",
header: "Date and Time",
},
{
category: "design.home-assistant.io",
header: "About",
+24
View File
@@ -0,0 +1,24 @@
import type { ControlSelectOption } from "../../../src/components/ha-control-select";
export const timeOptions: ControlSelectOption[] = [
{
value: "now",
label: "Now",
},
{
value: "00:15:30",
label: "12:15:30 AM",
},
{
value: "06:15:30",
label: "06:15:30 AM",
},
{
value: "12:15:30",
label: "12:15:30 PM",
},
{
value: "18:15:30",
label: "06:15:30 PM",
},
];
@@ -41,6 +41,7 @@ const triggers = [
{ platform: "sun", event: "sunset" },
{ platform: "time_pattern" },
{ platform: "webhook" },
{ platform: "persistent_notification" },
{
platform: "zone",
entity_id: "person.person",
@@ -19,6 +19,7 @@ import { HaTemplateTrigger } from "../../../../src/panels/config/automation/trig
import { HaTimeTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-time";
import { HaTimePatternTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-time_pattern";
import { HaWebhookTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-webhook";
import { HaPersistentNotificationTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-persistent_notification";
import { HaZoneTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-zone";
import { HaDeviceTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-device";
import { HaStateTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-state";
@@ -72,6 +73,16 @@ const SCHEMAS: { name: string; triggers: Trigger[] }[] = [
triggers: [{ platform: "webhook", ...HaWebhookTrigger.defaultConfig }],
},
{
name: "Persistent Notification",
triggers: [
{
platform: "persistent_notification",
...HaPersistentNotificationTrigger.defaultConfig,
},
],
},
{
name: "Zone",
triggers: [{ platform: "zone", ...HaZoneTrigger.defaultConfig }],
@@ -0,0 +1,3 @@
---
title: Control Circular Slider
---
@@ -0,0 +1,153 @@
import { css, html, LitElement, TemplateResult } from "lit";
import { customElement, state } from "lit/decorators";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-control-circular-slider";
import "../../../../src/components/ha-slider";
@customElement("demo-components-ha-control-circular-slider")
export class DemoHaCircularSlider extends LitElement {
@state()
private current = 22;
@state()
private value = 19;
@state()
private high = 25;
@state()
private changingValue?: number;
@state()
private changingHigh?: number;
private _valueChanged(ev) {
this.value = ev.detail.value;
}
private _valueChanging(ev) {
this.changingValue = ev.detail.value;
}
private _highChanged(ev) {
this.high = ev.detail.value;
}
private _highChanging(ev) {
this.changingHigh = ev.detail.value;
}
private _currentChanged(ev) {
this.current = ev.currentTarget.value;
}
protected render(): TemplateResult {
return html`
<ha-card>
<div class="card-content">
<p class="title"><b>Config</b></p>
<div class="field">
<p>Current</p>
<ha-slider
min="10"
max="30"
.value=${this.current}
@change=${this._currentChanged}
pin
></ha-slider>
<p>${this.current} °C</p>
</div>
</div>
</ha-card>
<ha-card>
<div class="card-content">
<p class="title"><b>Single</b></p>
<ha-control-circular-slider
@value-changed=${this._valueChanged}
@value-changing=${this._valueChanging}
.value=${this.value}
.current=${this.current}
step="1"
min="10"
max="30"
></ha-control-circular-slider>
<div>
Value: ${this.value} °C
<br />
Changing:
${this.changingValue != null ? `${this.changingValue} °C` : "-"}
</div>
</div>
</ha-card>
<ha-card>
<div class="card-content">
<p class="title"><b>Dual</b></p>
<ha-control-circular-slider
dual
@low-changed=${this._valueChanged}
@low-changing=${this._valueChanging}
@high-changed=${this._highChanged}
@high-changing=${this._highChanging}
.low=${this.value}
.high=${this.high}
.current=${this.current}
step="1"
min="10"
max="30"
></ha-control-circular-slider>
<div>
Low value: ${this.value} °C
<br />
Low changing:
${this.changingValue != null ? `${this.changingValue} °C` : "-"}
<br />
High value: ${this.high} °C
<br />
High changing:
${this.changingHigh != null ? `${this.changingHigh} °C` : "-"}
</div>
</div>
</ha-card>
`;
}
static get styles() {
return css`
ha-card {
max-width: 600px;
margin: 24px auto;
}
pre {
margin-top: 0;
margin-bottom: 8px;
}
p {
margin: 0;
}
p.title {
margin-bottom: 12px;
}
ha-control-circular-slider {
--control-circular-slider-color: #ff9800;
--control-circular-slider-background: #ff9800;
--control-circular-slider-background-opacity: 0.3;
}
ha-control-circular-slider[dual] {
--control-circular-slider-high-color: #2196f3;
--control-circular-slider-low-color: #ff9800;
--control-circular-slider-background: var(--disabled-color);
}
.field {
display: flex;
flex-direction: row;
align-items: center;
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"demo-components-ha-control-circular-slider": DemoHaCircularSlider;
}
}
@@ -0,0 +1,7 @@
---
title: Date-Time Format (Numeric)
---
This pages lists all supported languages with their available date-time formats.
Formatting function: `const formatDateTimeNumeric: (dateObj: Date, locale: FrontendLocaleData) => string`
@@ -0,0 +1,136 @@
import { html, css, LitElement } from "lit";
import { customElement, state } from "lit/decorators";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-control-select";
import { translationMetadata } from "../../../../src/resources/translations-metadata";
import { formatDateTimeNumeric } from "../../../../src/common/datetime/format_date_time";
import { timeOptions } from "../../data/date-options";
import { demoConfig } from "../../../../src/fake_data/demo_config";
import {
FrontendLocaleData,
NumberFormat,
TimeFormat,
DateFormat,
FirstWeekday,
TimeZone,
} from "../../../../src/data/translation";
@customElement("demo-date-time-date-time-numeric")
export class DemoDateTimeDateTimeNumeric extends LitElement {
@state() private selection?: string = "now";
@state() private date: Date = new Date();
handleValueChanged(e: CustomEvent) {
this.selection = e.detail.value as string;
this.date = new Date();
if (this.selection !== "now") {
const [hours, minutes, seconds] = this.selection.split(":").map(Number);
this.date.setHours(hours);
this.date.setMinutes(minutes);
this.date.setSeconds(seconds);
}
}
protected render() {
const defaultLocale: FrontendLocaleData = {
language: "en",
number_format: NumberFormat.language,
time_format: TimeFormat.language,
date_format: DateFormat.language,
first_weekday: FirstWeekday.language,
time_zone: TimeZone.local,
};
return html`
<ha-control-select
.value=${this.selection}
.options=${timeOptions}
@value-changed=${this.handleValueChanged}
>
</ha-control-select>
<mwc-list>
<div class="container header">
<div>Language</div>
<div class="center">Default (lang)</div>
<div class="center">12 Hours</div>
<div class="center">24 Hours</div>
</div>
${Object.entries(translationMetadata.translations)
.filter(([key, _]) => key !== "test")
.map(
([key, value]) => html`
<div class="container">
<div>${value.nativeName}</div>
<div class="center">
${formatDateTimeNumeric(
this.date,
{
...defaultLocale,
language: key,
time_format: TimeFormat.language,
},
demoConfig
)}
</div>
<div class="center">
${formatDateTimeNumeric(
this.date,
{
...defaultLocale,
language: key,
time_format: TimeFormat.am_pm,
},
demoConfig
)}
</div>
<div class="center">
${formatDateTimeNumeric(
this.date,
{
...defaultLocale,
language: key,
time_format: TimeFormat.twenty_four,
},
demoConfig
)}
</div>
</div>
`
)}
</mwc-list>
`;
}
static get styles() {
return css`
ha-control-select {
max-width: 800px;
margin: 12px auto;
}
.header {
font-weight: bold;
}
.center {
text-align: center;
}
.container {
max-width: 900px;
margin: 12px auto;
display: flex;
align-items: center;
justify-content: space-evenly;
}
.container > div {
flex-grow: 1;
width: 20%;
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"demo-date-time-date-time-numeric": DemoDateTimeDateTimeNumeric;
}
}
@@ -0,0 +1,7 @@
---
title: Date-Time Format (Seconds)
---
This pages lists all supported languages with their available date-time formats.
Formatting function: `const formatDateTimeWithSeconds: (dateObj: Date, locale: FrontendLocaleData) => string`
@@ -0,0 +1,136 @@
import { html, css, LitElement } from "lit";
import { customElement, state } from "lit/decorators";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-control-select";
import { translationMetadata } from "../../../../src/resources/translations-metadata";
import { formatDateTimeWithSeconds } from "../../../../src/common/datetime/format_date_time";
import { timeOptions } from "../../data/date-options";
import { demoConfig } from "../../../../src/fake_data/demo_config";
import {
FrontendLocaleData,
NumberFormat,
TimeFormat,
DateFormat,
FirstWeekday,
TimeZone,
} from "../../../../src/data/translation";
@customElement("demo-date-time-date-time-seconds")
export class DemoDateTimeDateTimeSeconds extends LitElement {
@state() private selection?: string = "now";
@state() private date: Date = new Date();
handleValueChanged(e: CustomEvent) {
this.selection = e.detail.value as string;
this.date = new Date();
if (this.selection !== "now") {
const [hours, minutes, seconds] = this.selection.split(":").map(Number);
this.date.setHours(hours);
this.date.setMinutes(minutes);
this.date.setSeconds(seconds);
}
}
protected render() {
const defaultLocale: FrontendLocaleData = {
language: "en",
number_format: NumberFormat.language,
time_format: TimeFormat.language,
date_format: DateFormat.language,
first_weekday: FirstWeekday.language,
time_zone: TimeZone.local,
};
return html`
<ha-control-select
.value=${this.selection}
.options=${timeOptions}
@value-changed=${this.handleValueChanged}
>
</ha-control-select>
<mwc-list>
<div class="container header">
<div>Language</div>
<div class="center">Default (lang)</div>
<div class="center">12 Hours</div>
<div class="center">24 Hours</div>
</div>
${Object.entries(translationMetadata.translations)
.filter(([key, _]) => key !== "test")
.map(
([key, value]) => html`
<div class="container">
<div>${value.nativeName}</div>
<div class="center">
${formatDateTimeWithSeconds(
this.date,
{
...defaultLocale,
language: key,
time_format: TimeFormat.language,
},
demoConfig
)}
</div>
<div class="center">
${formatDateTimeWithSeconds(
this.date,
{
...defaultLocale,
language: key,
time_format: TimeFormat.am_pm,
},
demoConfig
)}
</div>
<div class="center">
${formatDateTimeWithSeconds(
this.date,
{
...defaultLocale,
language: key,
time_format: TimeFormat.twenty_four,
},
demoConfig
)}
</div>
</div>
`
)}
</mwc-list>
`;
}
static get styles() {
return css`
ha-control-select {
max-width: 800px;
margin: 12px auto;
}
.header {
font-weight: bold;
}
.center {
text-align: center;
}
.container {
max-width: 900px;
margin: 12px auto;
display: flex;
align-items: center;
justify-content: space-evenly;
}
.container > div {
flex-grow: 1;
width: 20%;
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"demo-date-time-date-time-seconds": DemoDateTimeDateTimeSeconds;
}
}
@@ -0,0 +1,7 @@
---
title: Date-Time Format (Short w/ Year)
---
This pages lists all supported languages with their available date-time formats.
Formatting function: `const formatShortDateTimeWithYear: (dateObj: Date, locale: FrontendLocaleData) => string`
@@ -0,0 +1,136 @@
import { html, css, LitElement } from "lit";
import { customElement, state } from "lit/decorators";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-control-select";
import { translationMetadata } from "../../../../src/resources/translations-metadata";
import { formatShortDateTimeWithYear } from "../../../../src/common/datetime/format_date_time";
import { timeOptions } from "../../data/date-options";
import { demoConfig } from "../../../../src/fake_data/demo_config";
import {
FrontendLocaleData,
NumberFormat,
TimeFormat,
DateFormat,
FirstWeekday,
TimeZone,
} from "../../../../src/data/translation";
@customElement("demo-date-time-date-time-short-year")
export class DemoDateTimeDateTimeShortYear extends LitElement {
@state() private selection?: string = "now";
@state() private date: Date = new Date();
handleValueChanged(e: CustomEvent) {
this.selection = e.detail.value as string;
this.date = new Date();
if (this.selection !== "now") {
const [hours, minutes, seconds] = this.selection.split(":").map(Number);
this.date.setHours(hours);
this.date.setMinutes(minutes);
this.date.setSeconds(seconds);
}
}
protected render() {
const defaultLocale: FrontendLocaleData = {
language: "en",
number_format: NumberFormat.language,
time_format: TimeFormat.language,
date_format: DateFormat.language,
first_weekday: FirstWeekday.language,
time_zone: TimeZone.local,
};
return html`
<ha-control-select
.value=${this.selection}
.options=${timeOptions}
@value-changed=${this.handleValueChanged}
>
</ha-control-select>
<mwc-list>
<div class="container header">
<div>Language</div>
<div class="center">Default (lang)</div>
<div class="center">12 Hours</div>
<div class="center">24 Hours</div>
</div>
${Object.entries(translationMetadata.translations)
.filter(([key, _]) => key !== "test")
.map(
([key, value]) => html`
<div class="container">
<div>${value.nativeName}</div>
<div class="center">
${formatShortDateTimeWithYear(
this.date,
{
...defaultLocale,
language: key,
time_format: TimeFormat.language,
},
demoConfig
)}
</div>
<div class="center">
${formatShortDateTimeWithYear(
this.date,
{
...defaultLocale,
language: key,
time_format: TimeFormat.am_pm,
},
demoConfig
)}
</div>
<div class="center">
${formatShortDateTimeWithYear(
this.date,
{
...defaultLocale,
language: key,
time_format: TimeFormat.twenty_four,
},
demoConfig
)}
</div>
</div>
`
)}
</mwc-list>
`;
}
static get styles() {
return css`
ha-control-select {
max-width: 800px;
margin: 12px auto;
}
.header {
font-weight: bold;
}
.center {
text-align: center;
}
.container {
max-width: 900px;
margin: 12px auto;
display: flex;
align-items: center;
justify-content: space-evenly;
}
.container > div {
flex-grow: 1;
width: 20%;
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"demo-date-time-date-time-short-year": DemoDateTimeDateTimeShortYear;
}
}
@@ -0,0 +1,7 @@
---
title: Date-Time Format (Short)
---
This pages lists all supported languages with their available date-time formats.
Formatting function: `const formatShortDateTime: (dateObj: Date, locale: FrontendLocaleData) => string`
@@ -0,0 +1,136 @@
import { html, css, LitElement } from "lit";
import { customElement, state } from "lit/decorators";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-control-select";
import { translationMetadata } from "../../../../src/resources/translations-metadata";
import { formatShortDateTime } from "../../../../src/common/datetime/format_date_time";
import { timeOptions } from "../../data/date-options";
import { demoConfig } from "../../../../src/fake_data/demo_config";
import {
FrontendLocaleData,
NumberFormat,
TimeFormat,
DateFormat,
FirstWeekday,
TimeZone,
} from "../../../../src/data/translation";
@customElement("demo-date-time-date-time-short")
export class DemoDateTimeDateTimeShort extends LitElement {
@state() private selection?: string = "now";
@state() private date: Date = new Date();
handleValueChanged(e: CustomEvent) {
this.selection = e.detail.value as string;
this.date = new Date();
if (this.selection !== "now") {
const [hours, minutes, seconds] = this.selection.split(":").map(Number);
this.date.setHours(hours);
this.date.setMinutes(minutes);
this.date.setSeconds(seconds);
}
}
protected render() {
const defaultLocale: FrontendLocaleData = {
language: "en",
number_format: NumberFormat.language,
time_format: TimeFormat.language,
date_format: DateFormat.language,
first_weekday: FirstWeekday.language,
time_zone: TimeZone.local,
};
return html`
<ha-control-select
.value=${this.selection}
.options=${timeOptions}
@value-changed=${this.handleValueChanged}
>
</ha-control-select>
<mwc-list>
<div class="container header">
<div>Language</div>
<div class="center">Default (lang)</div>
<div class="center">12 Hours</div>
<div class="center">24 Hours</div>
</div>
${Object.entries(translationMetadata.translations)
.filter(([key, _]) => key !== "test")
.map(
([key, value]) => html`
<div class="container">
<div>${value.nativeName}</div>
<div class="center">
${formatShortDateTime(
this.date,
{
...defaultLocale,
language: key,
time_format: TimeFormat.language,
},
demoConfig
)}
</div>
<div class="center">
${formatShortDateTime(
this.date,
{
...defaultLocale,
language: key,
time_format: TimeFormat.am_pm,
},
demoConfig
)}
</div>
<div class="center">
${formatShortDateTime(
this.date,
{
...defaultLocale,
language: key,
time_format: TimeFormat.twenty_four,
},
demoConfig
)}
</div>
</div>
`
)}
</mwc-list>
`;
}
static get styles() {
return css`
ha-control-select {
max-width: 800px;
margin: 12px auto;
}
.header {
font-weight: bold;
}
.center {
text-align: center;
}
.container {
max-width: 900px;
margin: 12px auto;
display: flex;
align-items: center;
justify-content: space-evenly;
}
.container > div {
flex-grow: 1;
width: 20%;
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"demo-date-time-date-time-short": DemoDateTimeDateTimeShort;
}
}
@@ -0,0 +1,7 @@
---
title: Date-Time Format
---
This pages lists all supported languages with their available date-time formats.
Formatting function: `const formatDateTime: (dateObj: Date, locale: FrontendLocaleData) => string`
+136
View File
@@ -0,0 +1,136 @@
import { html, css, LitElement } from "lit";
import { customElement, state } from "lit/decorators";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-control-select";
import { translationMetadata } from "../../../../src/resources/translations-metadata";
import { formatDateTime } from "../../../../src/common/datetime/format_date_time";
import { timeOptions } from "../../data/date-options";
import { demoConfig } from "../../../../src/fake_data/demo_config";
import {
FrontendLocaleData,
NumberFormat,
TimeFormat,
DateFormat,
FirstWeekday,
TimeZone,
} from "../../../../src/data/translation";
@customElement("demo-date-time-date-time")
export class DemoDateTimeDateTime extends LitElement {
@state() private selection?: string = "now";
@state() private date: Date = new Date();
handleValueChanged(e: CustomEvent) {
this.selection = e.detail.value as string;
this.date = new Date();
if (this.selection !== "now") {
const [hours, minutes, seconds] = this.selection.split(":").map(Number);
this.date.setHours(hours);
this.date.setMinutes(minutes);
this.date.setSeconds(seconds);
}
}
protected render() {
const defaultLocale: FrontendLocaleData = {
language: "en",
number_format: NumberFormat.language,
time_format: TimeFormat.language,
date_format: DateFormat.language,
first_weekday: FirstWeekday.language,
time_zone: TimeZone.local,
};
return html`
<ha-control-select
.value=${this.selection}
.options=${timeOptions}
@value-changed=${this.handleValueChanged}
>
</ha-control-select>
<mwc-list>
<div class="container header">
<div>Language</div>
<div class="center">Default (lang)</div>
<div class="center">12 Hours</div>
<div class="center">24 Hours</div>
</div>
${Object.entries(translationMetadata.translations)
.filter(([key, _]) => key !== "test")
.map(
([key, value]) => html`
<div class="container">
<div>${value.nativeName}</div>
<div class="center">
${formatDateTime(
this.date,
{
...defaultLocale,
language: key,
time_format: TimeFormat.language,
},
demoConfig
)}
</div>
<div class="center">
${formatDateTime(
this.date,
{
...defaultLocale,
language: key,
time_format: TimeFormat.am_pm,
},
demoConfig
)}
</div>
<div class="center">
${formatDateTime(
this.date,
{
...defaultLocale,
language: key,
time_format: TimeFormat.twenty_four,
},
demoConfig
)}
</div>
</div>
`
)}
</mwc-list>
`;
}
static get styles() {
return css`
ha-control-select {
max-width: 800px;
margin: 12px auto;
}
.header {
font-weight: bold;
}
.center {
text-align: center;
}
.container {
max-width: 900px;
margin: 12px auto;
display: flex;
align-items: center;
justify-content: space-evenly;
}
.container > div {
flex-grow: 1;
width: 20%;
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"demo-date-time-date-time": DemoDateTimeDateTime;
}
}
@@ -0,0 +1,7 @@
---
title: Date Format (Numeric)
---
This pages lists all supported languages with their available (numeric) date formats.
Formatting function: `const formatDateNumeric: (dateObj: Date, locale: FrontendLocaleData) => string`
+123
View File
@@ -0,0 +1,123 @@
import "@material/mwc-list/mwc-list";
import { css, html, LitElement } from "lit";
import { customElement } from "lit/decorators";
import { formatDateNumeric } from "../../../../src/common/datetime/format_date";
import "../../../../src/components/ha-card";
import {
DateFormat,
FirstWeekday,
FrontendLocaleData,
NumberFormat,
TimeFormat,
TimeZone,
} from "../../../../src/data/translation";
import { demoConfig } from "../../../../src/fake_data/demo_config";
import { translationMetadata } from "../../../../src/resources/translations-metadata";
@customElement("demo-date-time-date")
export class DemoDateTimeDate extends LitElement {
protected render() {
const defaultLocale: FrontendLocaleData = {
language: "en",
number_format: NumberFormat.language,
time_format: TimeFormat.language,
date_format: DateFormat.language,
time_zone: TimeZone.local,
first_weekday: FirstWeekday.language,
};
const date = new Date();
return html`
<mwc-list>
<div class="container header">
<div>Language</div>
<div class="center">Default (lang)</div>
<div class="center">Day-Month-Year</div>
<div class="center">Month-Day-Year</div>
<div class="center">Year-Month-Day</div>
</div>
${Object.entries(translationMetadata.translations)
.filter(([key, _]) => key !== "test")
.map(
([key, value]) => html`
<div class="container">
<div>${value.nativeName}</div>
<div class="center">
${formatDateNumeric(
date,
{
...defaultLocale,
language: key,
date_format: DateFormat.language,
},
demoConfig
)}
</div>
<div class="center">
${formatDateNumeric(
date,
{
...defaultLocale,
language: key,
date_format: DateFormat.DMY,
},
demoConfig
)}
</div>
<div class="center">
${formatDateNumeric(
date,
{
...defaultLocale,
language: key,
date_format: DateFormat.MDY,
},
demoConfig
)}
</div>
<div class="center">
${formatDateNumeric(
date,
{
...defaultLocale,
language: key,
date_format: DateFormat.YMD,
},
demoConfig
)}
</div>
</div>
`
)}
</mwc-list>
`;
}
static get styles() {
return css`
.header {
font-weight: bold;
}
.center {
text-align: center;
}
.container {
max-width: 600px;
margin: 12px auto;
display: flex;
align-items: center;
justify-content: space-evenly;
}
.container > div {
flex-grow: 1;
width: 20%;
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"demo-date-time-date": DemoDateTimeDate;
}
}
@@ -0,0 +1,7 @@
---
title: Time Format (Seconds)
---
This pages lists all supported languages with their available time formats.
Formatting function: `const formatTimeWithSeconds: (dateObj: Date, locale: FrontendLocaleData) => string`
+135
View File
@@ -0,0 +1,135 @@
import { html, css, LitElement } from "lit";
import { customElement, state } from "lit/decorators";
import "../../../../src/components/ha-card";
import { translationMetadata } from "../../../../src/resources/translations-metadata";
import { formatTimeWithSeconds } from "../../../../src/common/datetime/format_time";
import { timeOptions } from "../../data/date-options";
import { demoConfig } from "../../../../src/fake_data/demo_config";
import {
FrontendLocaleData,
NumberFormat,
TimeFormat,
DateFormat,
FirstWeekday,
TimeZone,
} from "../../../../src/data/translation";
@customElement("demo-date-time-time-seconds")
export class DemoDateTimeTimeSeconds extends LitElement {
@state() private selection?: string = "now";
@state() private date: Date = new Date();
handleValueChanged(e: CustomEvent) {
this.selection = e.detail.value as string;
this.date = new Date();
if (this.selection !== "now") {
const [hours, minutes, seconds] = this.selection.split(":").map(Number);
this.date.setHours(hours);
this.date.setMinutes(minutes);
this.date.setSeconds(seconds);
}
}
protected render() {
const defaultLocale: FrontendLocaleData = {
language: "en",
number_format: NumberFormat.language,
time_format: TimeFormat.language,
date_format: DateFormat.language,
first_weekday: FirstWeekday.language,
time_zone: TimeZone.local,
};
return html`
<ha-control-select
.value=${this.selection}
.options=${timeOptions}
@value-changed=${this.handleValueChanged}
>
</ha-control-select>
<mwc-list>
<div class="container header">
<div>Language</div>
<div class="center">Default (lang)</div>
<div class="center">12 Hours</div>
<div class="center">24 Hours</div>
</div>
${Object.entries(translationMetadata.translations)
.filter(([key, _]) => key !== "test")
.map(
([key, value]) => html`
<div class="container">
<div>${value.nativeName}</div>
<div class="center">
${formatTimeWithSeconds(
this.date,
{
...defaultLocale,
language: key,
time_format: TimeFormat.language,
},
demoConfig
)}
</div>
<div class="center">
${formatTimeWithSeconds(
this.date,
{
...defaultLocale,
language: key,
time_format: TimeFormat.am_pm,
},
demoConfig
)}
</div>
<div class="center">
${formatTimeWithSeconds(
this.date,
{
...defaultLocale,
language: key,
time_format: TimeFormat.twenty_four,
},
demoConfig
)}
</div>
</div>
`
)}
</mwc-list>
`;
}
static get styles() {
return css`
ha-control-select {
max-width: 800px;
margin: 12px auto;
}
.header {
font-weight: bold;
}
.center {
text-align: center;
}
.container {
max-width: 600px;
margin: 12px auto;
display: flex;
align-items: center;
justify-content: space-evenly;
}
.container > div {
flex-grow: 1;
width: 20%;
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"demo-date-time-time-seconds": DemoDateTimeTimeSeconds;
}
}
@@ -0,0 +1,7 @@
---
title: Time Format (Weekday)
---
This pages lists all supported languages with their available time formats.
Formatting function: `const formatTimeWeekday: (dateObj: Date, locale: FrontendLocaleData) => string`
+135
View File
@@ -0,0 +1,135 @@
import { html, css, LitElement } from "lit";
import { customElement, state } from "lit/decorators";
import "../../../../src/components/ha-card";
import { translationMetadata } from "../../../../src/resources/translations-metadata";
import { formatTimeWeekday } from "../../../../src/common/datetime/format_time";
import { timeOptions } from "../../data/date-options";
import { demoConfig } from "../../../../src/fake_data/demo_config";
import {
FrontendLocaleData,
NumberFormat,
TimeFormat,
DateFormat,
FirstWeekday,
TimeZone,
} from "../../../../src/data/translation";
@customElement("demo-date-time-time-weekday")
export class DemoDateTimeTimeWeekday extends LitElement {
@state() private selection?: string = "now";
@state() private date: Date = new Date();
handleValueChanged(e: CustomEvent) {
this.selection = e.detail.value as string;
this.date = new Date();
if (this.selection !== "now") {
const [hours, minutes, seconds] = this.selection.split(":").map(Number);
this.date.setHours(hours);
this.date.setMinutes(minutes);
this.date.setSeconds(seconds);
}
}
protected render() {
const defaultLocale: FrontendLocaleData = {
language: "en",
number_format: NumberFormat.language,
time_format: TimeFormat.language,
date_format: DateFormat.language,
first_weekday: FirstWeekday.language,
time_zone: TimeZone.local,
};
return html`
<ha-control-select
.value=${this.selection}
.options=${timeOptions}
@value-changed=${this.handleValueChanged}
>
</ha-control-select>
<mwc-list>
<div class="container header">
<div>Language</div>
<div class="center">Default (lang)</div>
<div class="center">12 Hours</div>
<div class="center">24 Hours</div>
</div>
${Object.entries(translationMetadata.translations)
.filter(([key, _]) => key !== "test")
.map(
([key, value]) => html`
<div class="container">
<div>${value.nativeName}</div>
<div class="center">
${formatTimeWeekday(
this.date,
{
...defaultLocale,
language: key,
time_format: TimeFormat.language,
},
demoConfig
)}
</div>
<div class="center">
${formatTimeWeekday(
this.date,
{
...defaultLocale,
language: key,
time_format: TimeFormat.am_pm,
},
demoConfig
)}
</div>
<div class="center">
${formatTimeWeekday(
this.date,
{
...defaultLocale,
language: key,
time_format: TimeFormat.twenty_four,
},
demoConfig
)}
</div>
</div>
`
)}
</mwc-list>
`;
}
static get styles() {
return css`
ha-control-select {
max-width: 800px;
margin: 12px auto;
}
.header {
font-weight: bold;
}
.center {
text-align: center;
}
.container {
max-width: 800px;
margin: 12px auto;
display: flex;
align-items: center;
justify-content: space-evenly;
}
.container > div {
flex-grow: 1;
width: 20%;
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"demo-date-time-time-weekday": DemoDateTimeTimeWeekday;
}
}
@@ -0,0 +1,7 @@
---
title: Time Format
---
This pages lists all supported languages with their available time formats.
Formatting function: `const formatTime: (dateObj: Date, locale: FrontendLocaleData) => string`
+136
View File
@@ -0,0 +1,136 @@
import { html, css, LitElement } from "lit";
import { customElement, state } from "lit/decorators";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-control-select";
import { translationMetadata } from "../../../../src/resources/translations-metadata";
import { formatTime } from "../../../../src/common/datetime/format_time";
import { timeOptions } from "../../data/date-options";
import { demoConfig } from "../../../../src/fake_data/demo_config";
import {
FrontendLocaleData,
NumberFormat,
TimeFormat,
DateFormat,
FirstWeekday,
TimeZone,
} from "../../../../src/data/translation";
@customElement("demo-date-time-time")
export class DemoDateTimeTime extends LitElement {
@state() private selection?: string = "now";
@state() private date: Date = new Date();
handleValueChanged(e: CustomEvent) {
this.selection = e.detail.value as string;
this.date = new Date();
if (this.selection !== "now") {
const [hours, minutes, seconds] = this.selection.split(":").map(Number);
this.date.setHours(hours);
this.date.setMinutes(minutes);
this.date.setSeconds(seconds);
}
}
protected render() {
const defaultLocale: FrontendLocaleData = {
language: "en",
number_format: NumberFormat.language,
time_format: TimeFormat.language,
date_format: DateFormat.language,
first_weekday: FirstWeekday.language,
time_zone: TimeZone.local,
};
return html`
<ha-control-select
.value=${this.selection}
.options=${timeOptions}
@value-changed=${this.handleValueChanged}
>
</ha-control-select>
<mwc-list>
<div class="container header">
<div>Language</div>
<div class="center">Default (lang)</div>
<div class="center">12 Hours</div>
<div class="center">24 Hours</div>
</div>
${Object.entries(translationMetadata.translations)
.filter(([key, _]) => key !== "test")
.map(
([key, value]) => html`
<div class="container">
<div>${value.nativeName}</div>
<div class="center">
${formatTime(
this.date,
{
...defaultLocale,
language: key,
time_format: TimeFormat.language,
},
demoConfig
)}
</div>
<div class="center">
${formatTime(
this.date,
{
...defaultLocale,
language: key,
time_format: TimeFormat.am_pm,
},
demoConfig
)}
</div>
<div class="center">
${formatTime(
this.date,
{
...defaultLocale,
language: key,
time_format: TimeFormat.twenty_four,
},
demoConfig
)}
</div>
</div>
`
)}
</mwc-list>
`;
}
static get styles() {
return css`
ha-control-select {
max-width: 800px;
margin: 12px auto;
}
.header {
font-weight: bold;
}
.center {
text-align: center;
}
.container {
max-width: 600px;
margin: 12px auto;
display: flex;
align-items: center;
justify-content: space-evenly;
}
.container > div {
flex-grow: 1;
width: 20%;
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"demo-date-time-time": DemoDateTimeTime;
}
}
+10 -1
View File
@@ -9,7 +9,7 @@ const CONFIGS = [
heading: "markdown-it demo",
config: `
- type: markdown
content: >-
content: |
# h1 Heading 8-)
## h2 Heading
@@ -65,6 +65,15 @@ const CONFIGS = [
>> ...by using additional greater-than signs right next to each other...
> > > ...or with spaces between arrows.
> **Warning** Hey there
> This is a warning with a title
> **Note**
> This is a note
> **Note**
> This is a multiline note
> Lorem ipsum...
## Lists
+4
View File
@@ -135,6 +135,9 @@ const ENTITIES: HassEntity[] = [
createEntity("climate.fan_only", "fan_only"),
createEntity("climate.auto_idle", "auto", undefined, { hvac_action: "idle" }),
createEntity("climate.auto_off", "auto", undefined, { hvac_action: "off" }),
createEntity("climate.auto_preheating", "auto", undefined, {
hvac_action: "preheating",
}),
createEntity("climate.auto_heating", "auto", undefined, {
hvac_action: "heating",
}),
@@ -354,6 +357,7 @@ export class DemoEntityState extends LitElement {
hass.localize,
entry.stateObj,
hass.locale,
hass.config,
hass.entities
)}`,
},
@@ -130,6 +130,7 @@ export class HassioAddonRepositoryEl extends LitElement {
css`
ha-card {
cursor: pointer;
overflow: hidden;
}
.not_available {
opacity: 0.6;
@@ -44,7 +44,10 @@ class HassioAddonDocumentationDashboard extends LitElement {
: ""}
<div class="card-content">
${this._content
? html`<ha-markdown .content=${this._content}></ha-markdown>`
? html`<ha-markdown
.content=${this._content}
lazy-images
></ha-markdown>`
: html`<hass-loading-screen no-toolbar></hass-loading-screen>`}
</div>
</ha-card>
@@ -659,6 +659,7 @@ class HassioAddonInfo extends LitElement {
<div class="card-content">
<ha-markdown
.content=${this.addon.long_description}
lazy-images
></ha-markdown>
</div>
</ha-card>
+9
View File
@@ -136,6 +136,15 @@ export class HassioBackups extends LitElement {
sortable: true,
template: (entry: number) => Math.ceil(entry * 10) / 10 + " MB",
},
location: {
title: this.supervisor.localize("backup.location"),
width: "15%",
hidden: narrow,
filterable: true,
sortable: true,
template: (entry: string | null) =>
entry || this.supervisor.localize("backup.data_disk"),
},
date: {
title: this.supervisor.localize("backup.created"),
width: "15%",
@@ -1,5 +1,6 @@
import { mdiFolder, mdiHomeAssistant, mdiPuzzle } from "@mdi/js";
import { PaperInputElement } from "@polymer/paper-input/paper-input";
import "@polymer/paper-input/paper-input";
import type { PaperInputElement } from "@polymer/paper-input/paper-input";
import {
css,
CSSResultGroup,
@@ -142,7 +143,11 @@ export class SupervisorBackupContent extends LitElement {
: this._localize("partial_backup")}
(${Math.ceil(this.backup.size * 10) / 10 + " MB"})<br />
${this.hass
? formatDateTime(new Date(this.backup.date), this.hass.locale)
? formatDateTime(
new Date(this.backup.date),
this.hass.locale,
this.hass.config
)
: this.backup.date}
</div>`
: html`<paper-input
@@ -335,7 +340,9 @@ export class SupervisorBackupContent extends LitElement {
const data: any = {};
if (!this.backup) {
data.name = this.backupName || formatDate(new Date(), this.hass.locale);
data.name =
this.backupName ||
formatDate(new Date(), this.hass.locale, this.hass.config);
}
if (this.backupHasPassword) {
+1
View File
@@ -125,6 +125,7 @@ class HassioAddons extends LitElement {
css`
ha-card {
cursor: pointer;
overflow: hidden;
}
.search {
position: sticky;
@@ -7,6 +7,7 @@ import { atLeastVersion } from "../../../../src/common/config/version";
import { fireEvent } from "../../../../src/common/dom/fire_event";
import { stopPropagation } from "../../../../src/common/dom/stop_propagation";
import { slugify } from "../../../../src/common/string/slugify";
import "../../../../src/components/ha-dialog";
import "../../../../src/components/buttons/ha-progress-button";
import "../../../../src/components/ha-alert";
import "../../../../src/components/ha-button-menu";
+1 -5
View File
@@ -98,11 +98,7 @@ export class SupervisorBaseElement extends urlSyncMixin(
}
private async _initializeLocalize() {
const { language, data } = await getTranslation(
null,
this._language,
"/api/hassio/app/static/translations"
);
const { language, data } = await getTranslation(null, this._language);
this._updateSupervisor({
localize: await computeLocalize<SupervisorKeys>(
+68 -66
View File
@@ -25,33 +25,34 @@
"license": "Apache-2.0",
"type": "module",
"dependencies": {
"@babel/runtime": "7.21.5",
"@babel/runtime": "7.22.5",
"@braintree/sanitize-url": "6.0.2",
"@codemirror/autocomplete": "6.7.1",
"@codemirror/autocomplete": "6.8.0",
"@codemirror/commands": "6.2.4",
"@codemirror/language": "6.7.0",
"@codemirror/language": "6.8.0",
"@codemirror/legacy-modes": "6.3.2",
"@codemirror/search": "6.4.0",
"@codemirror/state": "6.2.0",
"@codemirror/view": "6.12.0",
"@codemirror/search": "6.5.0",
"@codemirror/state": "6.2.1",
"@codemirror/view": "6.13.2",
"@egjs/hammerjs": "2.0.17",
"@formatjs/intl-datetimeformat": "6.8.0",
"@formatjs/intl-displaynames": "6.3.2",
"@formatjs/intl-getcanonicallocales": "2.2.0",
"@formatjs/intl-locale": "3.3.0",
"@formatjs/intl-numberformat": "8.5.0",
"@formatjs/intl-pluralrules": "5.2.2",
"@formatjs/intl-relativetimeformat": "11.2.2",
"@fullcalendar/core": "6.1.7",
"@fullcalendar/daygrid": "6.1.7",
"@fullcalendar/interaction": "6.1.7",
"@fullcalendar/list": "6.1.7",
"@fullcalendar/timegrid": "6.1.7",
"@lezer/highlight": "1.1.4",
"@lit-labs/context": "0.3.1",
"@formatjs/intl-datetimeformat": "6.10.0",
"@formatjs/intl-displaynames": "6.5.0",
"@formatjs/intl-getcanonicallocales": "2.2.1",
"@formatjs/intl-listformat": "7.4.0",
"@formatjs/intl-locale": "3.3.2",
"@formatjs/intl-numberformat": "8.7.0",
"@formatjs/intl-pluralrules": "5.2.4",
"@formatjs/intl-relativetimeformat": "11.2.4",
"@fullcalendar/core": "6.1.8",
"@fullcalendar/daygrid": "6.1.8",
"@fullcalendar/interaction": "6.1.8",
"@fullcalendar/list": "6.1.8",
"@fullcalendar/timegrid": "6.1.8",
"@lezer/highlight": "1.1.6",
"@lit-labs/context": "0.3.3",
"@lit-labs/motion": "1.0.3",
"@lit-labs/virtualizer": "2.0.2",
"@lrnwebcomponents/simple-tooltip": "7.0.0",
"@lit-labs/virtualizer": "2.0.3",
"@lrnwebcomponents/simple-tooltip": "7.0.2",
"@material/chips": "=14.0.0-canary.53b3cad2f.0",
"@material/data-table": "=14.0.0-canary.53b3cad2f.0",
"@material/mwc-button": "0.27.0",
@@ -77,7 +78,7 @@
"@material/mwc-top-app-bar": "0.27.0",
"@material/mwc-top-app-bar-fixed": "0.27.0",
"@material/top-app-bar": "=14.0.0-canary.53b3cad2f.0",
"@material/web": "=1.0.0-pre.8",
"@material/web": "=1.0.0-pre.10",
"@mdi/js": "7.2.96",
"@mdi/svg": "7.2.96",
"@polymer/app-layout": "3.1.0",
@@ -92,8 +93,8 @@
"@polymer/paper-toast": "3.0.1",
"@polymer/polymer": "3.5.1",
"@thomasloven/round-slider": "0.6.0",
"@vaadin/combo-box": "24.0.6",
"@vaadin/vaadin-themable-mixin": "24.0.6",
"@vaadin/combo-box": "24.1.1",
"@vaadin/vaadin-themable-mixin": "24.1.1",
"@vibrant/color": "3.2.1-alpha.1",
"@vibrant/core": "3.2.1-alpha.1",
"@vibrant/quantizer-mmcq": "3.2.1-alpha.1",
@@ -103,7 +104,7 @@
"app-datepicker": "5.1.1",
"chart.js": "3.3.2",
"comlink": "4.4.1",
"core-js": "3.30.2",
"core-js": "3.31.0",
"cropperjs": "1.5.13",
"date-fns": "2.30.0",
"date-fns-tz": "2.0.0",
@@ -111,14 +112,14 @@
"deep-freeze": "0.0.1",
"fuse.js": "6.6.2",
"google-timezones-json": "1.1.0",
"hls.js": "1.4.3",
"hls.js": "1.4.6",
"home-assistant-js-websocket": "8.0.1",
"idb-keyval": "6.2.1",
"intl-messageformat": "10.3.5",
"intl-messageformat": "10.5.0",
"js-yaml": "4.1.0",
"leaflet": "1.9.4",
"leaflet-draw": "1.0.4",
"lit": "2.7.4",
"lit": "2.7.5",
"marked": "4.3.0",
"memoize-one": "6.0.0",
"node-vibrant": "3.2.1-alpha.1",
@@ -131,48 +132,48 @@
"rrule": "2.7.2",
"sortablejs": "1.15.0",
"superstruct": "1.0.3",
"tinykeys": "1.4.0",
"tsparticles-engine": "2.9.3",
"tsparticles-preset-links": "2.9.3",
"tinykeys": "2.1.0",
"tsparticles-engine": "2.10.1",
"tsparticles-preset-links": "2.10.1",
"unfetch": "5.0.0",
"vis-data": "7.1.6",
"vis-network": "9.1.6",
"vue": "2.7.14",
"vue2-daterange-picker": "0.6.8",
"weekstart": "2.0.0",
"workbox-cacheable-response": "6.5.4",
"workbox-core": "6.5.4",
"workbox-expiration": "6.5.4",
"workbox-precaching": "6.5.4",
"workbox-routing": "6.5.4",
"workbox-strategies": "6.5.4",
"workbox-cacheable-response": "7.0.0",
"workbox-core": "7.0.0",
"workbox-expiration": "7.0.0",
"workbox-precaching": "7.0.0",
"workbox-routing": "7.0.0",
"workbox-strategies": "7.0.0",
"xss": "1.0.14"
},
"devDependencies": {
"@babel/core": "7.21.8",
"@babel/plugin-proposal-decorators": "7.21.0",
"@babel/plugin-transform-runtime": "7.21.4",
"@babel/preset-env": "7.21.5",
"@babel/preset-typescript": "7.21.5",
"@babel/core": "7.22.5",
"@babel/plugin-proposal-decorators": "7.22.5",
"@babel/plugin-transform-runtime": "7.22.5",
"@babel/preset-env": "7.22.5",
"@babel/preset-typescript": "7.22.5",
"@koa/cors": "4.0.0",
"@octokit/auth-oauth-device": "4.0.4",
"@octokit/plugin-retry": "4.1.3",
"@octokit/rest": "19.0.11",
"@octokit/auth-oauth-device": "5.0.2",
"@octokit/plugin-retry": "5.0.4",
"@octokit/rest": "19.0.13",
"@open-wc/dev-server-hmr": "0.1.4",
"@rollup/plugin-babel": "6.0.3",
"@rollup/plugin-commonjs": "25.0.0",
"@rollup/plugin-commonjs": "25.0.1",
"@rollup/plugin-json": "6.0.0",
"@rollup/plugin-node-resolve": "15.0.2",
"@rollup/plugin-node-resolve": "15.1.0",
"@rollup/plugin-replace": "5.0.2",
"@types/babel__plugin-transform-runtime": "7.9.2",
"@types/chromecast-caf-receiver": "5.0.12",
"@types/chromecast-caf-receiver": "6.0.9",
"@types/chromecast-caf-sender": "1.0.5",
"@types/esprima": "4.0.3",
"@types/glob": "8.1.0",
"@types/html-minifier-terser": "7.0.0",
"@types/js-yaml": "4.0.5",
"@types/leaflet": "1.9.3",
"@types/leaflet-draw": "1.0.6",
"@types/leaflet-draw": "1.0.7",
"@types/marked": "4.3.1",
"@types/mocha": "10.0.1",
"@types/qrcode": "1.5.0",
@@ -180,15 +181,15 @@
"@types/sortablejs": "1.15.1",
"@types/tar": "6.1.5",
"@types/webspeechapi": "0.0.29",
"@typescript-eslint/eslint-plugin": "5.59.7",
"@typescript-eslint/parser": "5.59.7",
"@typescript-eslint/eslint-plugin": "5.59.11",
"@typescript-eslint/parser": "5.59.11",
"@web/dev-server": "0.1.38",
"@web/dev-server-rollup": "0.4.1",
"babel-loader": "9.1.2",
"babel-plugin-template-html-minifier": "4.1.0",
"chai": "4.3.7",
"del": "7.0.0",
"eslint": "8.41.0",
"eslint": "8.43.0",
"eslint-config-airbnb-base": "15.0.0",
"eslint-config-airbnb-typescript": "17.0.0",
"eslint-config-prettier": "8.8.0",
@@ -196,13 +197,13 @@
"eslint-plugin-disable": "2.0.3",
"eslint-plugin-import": "2.27.5",
"eslint-plugin-lit": "1.8.3",
"eslint-plugin-lit-a11y": "2.4.1",
"eslint-plugin-lit-a11y": "3.0.0",
"eslint-plugin-unused-imports": "2.0.0",
"eslint-plugin-wc": "1.5.0",
"esprima": "4.0.1",
"fancy-log": "2.0.0",
"fs-extra": "11.1.1",
"glob": "10.2.6",
"glob": "10.2.7",
"gulp": "4.0.2",
"gulp-flatmap": "1.0.2",
"gulp-json-transform": "0.4.8",
@@ -214,7 +215,7 @@
"instant-mocha": "1.5.1",
"jszip": "3.10.1",
"lint-staged": "13.2.2",
"lit-analyzer": "1.2.1",
"lit-analyzer": "2.0.0-pre.3",
"lodash.template": "4.5.0",
"magic-string": "0.30.0",
"map-stream": "0.0.7",
@@ -227,32 +228,33 @@
"rollup": "2.79.1",
"rollup-plugin-string": "3.0.0",
"rollup-plugin-terser": "7.0.2",
"rollup-plugin-visualizer": "5.9.0",
"rollup-plugin-visualizer": "5.9.2",
"serve-handler": "6.1.5",
"sinon": "15.1.0",
"sinon": "15.1.2",
"source-map-url": "0.4.1",
"systemjs": "6.14.1",
"tar": "6.1.15",
"terser-webpack-plugin": "5.3.9",
"ts-lit-plugin": "1.2.1",
"typescript": "4.9.5",
"ts-lit-plugin": "2.0.0-pre.1",
"typescript": "5.1.3",
"vinyl-buffer": "1.0.1",
"vinyl-source-stream": "2.0.0",
"webpack": "5.83.1",
"webpack-cli": "5.1.1",
"webpack-dev-server": "4.15.0",
"webpack": "5.87.0",
"webpack-cli": "5.1.4",
"webpack-dev-server": "4.15.1",
"webpack-manifest-plugin": "5.0.0",
"webpackbar": "5.0.2",
"workbox-build": "6.5.4"
"workbox-build": "7.0.0"
},
"_comment": "Polymer 3.2 contained a bug, fixed in https://github.com/Polymer/polymer/pull/5569, add as patch",
"resolutions": {
"@polymer/polymer": "patch:@polymer/[email protected]#./.yarn/patches/@polymer/polymer/pr-5569.patch",
"@material/mwc-button@^0.25.3": "^0.27.0"
"@material/mwc-button@^0.25.3": "^0.27.0",
"[email protected]": "patch:sortablejs@npm%3A1.15.0#./.yarn/patches/sortablejs-npm-1.15.0-f3a393abcc.patch"
},
"prettier": {
"trailingComma": "es5",
"arrowParens": "always"
},
"packageManager": "yarn@3.5.1"
"packageManager": "yarn@3.6.0"
}
+2 -2
View File
@@ -4,14 +4,14 @@ build-backend = "setuptools.build_meta"
[project]
name = "home-assistant-frontend"
version = "20230526.0"
version = "20230608.0"
license = {text = "Apache-2.0"}
description = "The Home Assistant frontend"
readme = "README.md"
authors = [
{name = "The Home Assistant Authors", email = "[email protected]"}
]
requires-python = ">=3.4.0"
requires-python = ">=3.10.0"
[project.urls]
"Homepage" = "https://github.com/home-assistant/frontend"
+8 -2
View File
@@ -19,14 +19,20 @@
},
"packageRules": [
{
"description": ["MDC packages are pinned to the same version as MWC"],
"description": "MDC packages are pinned to the same version as MWC",
"extends": ["monorepo:material-components-web"],
"enabled": false
},
{
"description": ["Vue is only used by date range which is only v2"],
"description": "Vue is only used by date range which is only v2",
"matchPackageNames": ["vue"],
"allowedVersions": "< 3"
},
{
"description": "Group tsparticles engine and presets",
"groupName": "tsparticles",
"matchPackageNames": ["tsparticles-engine"],
"matchPackagePrefixes": ["tsparticles-preset-"]
}
]
}
+2 -2
View File
@@ -8,9 +8,9 @@ cd "$(dirname "$0")/.."
# Install/upgrade node when inside devcontainer
if [[ -n "$DEVCONTAINER" ]]; then
nodeCurrent=$(nvm version default || echo "")
nodeCurrent=$(nvm version default || :)
nodeLatest=$(nvm version-remote "$(cat .nvmrc)")
if [[ -z "$nodeCurrent" ]]; then
if [[ -z "$nodeCurrent" || "$nodeCurrent" == "N/A" ]]; then
nvm install
elif [[ "$nodeCurrent" != "$nodeLatest" ]]; then
nvm install --reinstall-packages-from="$nodeCurrent" --default
+8 -11
View File
@@ -1,8 +1,5 @@
/* eslint-disable no-undef, no-console */
import {
CastStateEventData,
SessionStateEventData,
} from "chromecast-caf-receiver/cast.framework";
/* eslint-disable no-console */
import { Auth } from "home-assistant-js-websocket";
import { castApiAvailable } from "./cast_framework";
import { CAST_APP_ID, CAST_DEV, CAST_NS } from "./const";
@@ -48,11 +45,11 @@ export class CastManager {
});
context.addEventListener(
cast.framework.CastContextEventType.SESSION_STATE_CHANGED,
(ev) => this._sessionStateChanged(ev)
this._sessionStateChanged
);
context.addEventListener(
cast.framework.CastContextEventType.CAST_STATE_CHANGED,
(ev) => this._castStateChanged(ev)
this._castStateChanged
);
}
@@ -119,7 +116,7 @@ export class CastManager {
}
}
private _sessionStateChanged(ev: SessionStateEventData) {
private _sessionStateChanged = (ev: cast.framework.SessionStateEventData) => {
if (__DEV__) {
console.log("Cast session state changed", ev.sessionState);
}
@@ -140,14 +137,14 @@ export class CastManager {
this.status = undefined;
this._fireEvent("connection-changed");
}
}
};
private _castStateChanged(ev: CastStateEventData) {
private _castStateChanged = (ev: cast.framework.CastStateEventData) => {
if (__DEV__) {
console.log("Cast state changed", ev.castState);
}
this._fireEvent("state-changed");
}
};
private _attachMessageListener() {
const session = this.castSession;
+106
View File
@@ -0,0 +1,106 @@
import { clamp } from "../number/clamp";
const DEFAULT_MIN_KELVIN = 2700;
const DEFAULT_MAX_KELVIN = 6500;
export const temperature2rgb = (
temperature: number
): [number, number, number] => {
const value = temperature / 100;
return [
temperatureRed(value),
temperatureGreen(value),
temperatureBlue(value),
];
};
const temperatureRed = (temperature: number): number => {
if (temperature <= 66) {
return 255;
}
const red = 329.698727446 * (temperature - 60) ** -0.1332047592;
return clamp(red, 0, 255);
};
const temperatureGreen = (temperature: number): number => {
let green: number;
if (temperature <= 66) {
green = 99.4708025861 * Math.log(temperature) - 161.1195681661;
} else {
green = 288.1221695283 * (temperature - 60) ** -0.0755148492;
}
return clamp(green, 0, 255);
};
const temperatureBlue = (temperature: number): number => {
if (temperature >= 66) {
return 255;
}
if (temperature <= 19) {
return 0;
}
const blue = 138.5177312231 * Math.log(temperature - 10) - 305.0447927307;
return clamp(blue, 0, 255);
};
const matchMaxScale = (
inputColors: number[],
outputColors: number[]
): number[] => {
const maxIn: number = Math.max(...inputColors);
const maxOut: number = Math.max(...outputColors);
let factor: number;
if (maxOut === 0) {
factor = 0.0;
} else {
factor = maxIn / maxOut;
}
return outputColors.map((value) => Math.round(value * factor));
};
const mired2kelvin = (miredTemperature: number) =>
Math.floor(1000000 / miredTemperature);
const kelvin2mired = (kelvintTemperature: number) =>
Math.floor(1000000 / kelvintTemperature);
export const rgbww2rgb = (
rgbww: [number, number, number, number, number],
minKelvin?: number,
maxKelvin?: number
): [number, number, number] => {
const [r, g, b, cw, ww] = rgbww;
// Calculate color temperature of the white channels
const maxMireds: number = kelvin2mired(minKelvin ?? DEFAULT_MIN_KELVIN);
const minMireds: number = kelvin2mired(maxKelvin ?? DEFAULT_MAX_KELVIN);
const miredRange: number = maxMireds - minMireds;
let ctRatio: number;
try {
ctRatio = ww / (cw + ww);
} catch (_error) {
ctRatio = 0.5;
}
const colorTempMired = minMireds + ctRatio * miredRange;
const colorTempKelvin = colorTempMired ? mired2kelvin(colorTempMired) : 0;
const [wR, wG, wB] = temperature2rgb(colorTempKelvin);
const whiteLevel = Math.max(cw, ww) / 255;
// Add the white channels to the rgb channels.
const rgb = [
r + wR * whiteLevel,
g + wG * whiteLevel,
b + wB * whiteLevel,
] as [number, number, number];
// Match the output maximum value to the input. This ensures the
// output doesn't overflow.
return matchMaxScale([r, g, b, cw, ww], rgb) as [number, number, number];
};
export const rgbw2rgb = (
rgbw: [number, number, number, number]
): [number, number, number] => {
const [r, g, b, w] = rgbw;
const rgb = [r + w, g + w, b + w] as [number, number, number];
return matchMaxScale([r, g, b, w], rgb) as [number, number, number];
};
+5
View File
@@ -33,6 +33,7 @@ import {
mdiGoogleCirclesCommunities,
mdiHomeAssistant,
mdiHomeAutomation,
mdiImage,
mdiImageFilterFrames,
mdiLightbulb,
mdiLightningBolt,
@@ -83,12 +84,14 @@ export const FIXED_DOMAIN_ICONS = {
configurator: mdiCog,
conversation: mdiMicrophoneMessage,
counter: mdiCounter,
datetime: mdiCalendarClock,
date: mdiCalendar,
demo: mdiHomeAssistant,
google_assistant: mdiGoogleAssistant,
group: mdiGoogleCirclesCommunities,
homeassistant: mdiHomeAssistant,
homekit: mdiHomeAutomation,
image: mdiImage,
image_processing: mdiImageFilterFrames,
input_button: mdiGestureTapButton,
input_datetime: mdiCalendarClock,
@@ -112,6 +115,7 @@ export const FIXED_DOMAIN_ICONS = {
siren: mdiBullhorn,
stt: mdiMicrophoneMessage,
text: mdiFormTextbox,
time: mdiClock,
timer: mdiTimerOutline,
tts: mdiSpeakerMessage,
updater: mdiCloudUpload,
@@ -211,6 +215,7 @@ export const DOMAINS_INPUT_ROW = [
"button",
"cover",
"date",
"datetime",
"fan",
"group",
"humidifier",
+5 -3
View File
@@ -1,4 +1,5 @@
import { isSameDay, isSameYear } from "date-fns";
import { HassConfig } from "home-assistant-js-websocket";
import { FrontendLocaleData } from "../../data/translation";
import {
formatShortDateTime,
@@ -9,15 +10,16 @@ import { formatTime } from "./format_time";
export const absoluteTime = (
from: Date,
locale: FrontendLocaleData,
config: HassConfig,
to?: Date
): string => {
const _to = to ?? new Date();
if (isSameDay(from, _to)) {
return formatTime(from, locale);
return formatTime(from, locale, config);
}
if (isSameYear(from, _to)) {
return formatShortDateTime(from, locale);
return formatShortDateTime(from, locale, config);
}
return formatShortDateTimeWithYear(from, locale);
return formatShortDateTimeWithYear(from, locale, config);
};
+25
View File
@@ -0,0 +1,25 @@
import { utcToZonedTime, zonedTimeToUtc } from "date-fns-tz";
import { HassConfig } from "home-assistant-js-websocket";
import { FrontendLocaleData, TimeZone } from "../../data/translation";
const calcZonedDate = (
date: Date,
tz: string,
fn: (date: Date, options?: any) => Date,
options?
) => {
const inputZoned = utcToZonedTime(date, tz);
const fnZoned = fn(inputZoned, options);
return zonedTimeToUtc(fnZoned, tz);
};
export const calcDate = (
date: Date,
fn: (date: Date, options?: any) => Date,
locale: FrontendLocaleData,
config: HassConfig,
options?
) =>
locale.time_zone === TimeZone.server
? calcZonedDate(date, config.time_zone, fn, options)
: fn(date, options);
+118 -27
View File
@@ -1,103 +1,194 @@
import { HassConfig } from "home-assistant-js-websocket";
import memoizeOne from "memoize-one";
import { FrontendLocaleData } from "../../data/translation";
import { FrontendLocaleData, DateFormat } from "../../data/translation";
import "../../resources/intl-polyfill";
// Tuesday, August 10
export const formatDateWeekdayDay = (
dateObj: Date,
locale: FrontendLocaleData
) => formatDateWeekdayDayMem(locale).format(dateObj);
locale: FrontendLocaleData,
config: HassConfig
) => formatDateWeekdayDayMem(locale, config.time_zone).format(dateObj);
const formatDateWeekdayDayMem = memoizeOne(
(locale: FrontendLocaleData) =>
(locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(locale.language, {
weekday: "long",
month: "long",
day: "numeric",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
})
);
// August 10, 2021
export const formatDate = (dateObj: Date, locale: FrontendLocaleData) =>
formatDateMem(locale).format(dateObj);
export const formatDate = (
dateObj: Date,
locale: FrontendLocaleData,
config: HassConfig
) => formatDateMem(locale, config.time_zone).format(dateObj);
const formatDateMem = memoizeOne(
(locale: FrontendLocaleData) =>
(locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(locale.language, {
year: "numeric",
month: "long",
day: "numeric",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
})
);
// 10/08/2021
export const formatDateNumeric = (dateObj: Date, locale: FrontendLocaleData) =>
formatDateNumericMem(locale).format(dateObj);
export const formatDateNumeric = (
dateObj: Date,
locale: FrontendLocaleData,
config: HassConfig
) => {
const formatter = formatDateNumericMem(locale, config.time_zone);
if (
locale.date_format === DateFormat.language ||
locale.date_format === DateFormat.system
) {
return formatter.format(dateObj);
}
const parts = formatter.formatToParts(dateObj);
const literal = parts.find((value) => value.type === "literal")?.value;
const day = parts.find((value) => value.type === "day")?.value;
const month = parts.find((value) => value.type === "month")?.value;
const year = parts.find((value) => value.type === "year")?.value;
const lastPart = parts.at(parts.length - 1);
let lastLiteral = lastPart?.type === "literal" ? lastPart?.value : "";
if (locale.language === "bg" && locale.date_format === DateFormat.YMD) {
lastLiteral = "";
}
const formats = {
[DateFormat.DMY]: `${day}${literal}${month}${literal}${year}${lastLiteral}`,
[DateFormat.MDY]: `${month}${literal}${day}${literal}${year}${lastLiteral}`,
[DateFormat.YMD]: `${year}${literal}${month}${literal}${day}${lastLiteral}`,
};
return formats[locale.date_format];
};
const formatDateNumericMem = memoizeOne(
(locale: FrontendLocaleData) =>
new Intl.DateTimeFormat(locale.language, {
(locale: FrontendLocaleData, serverTimeZone: string) => {
const localeString =
locale.date_format === DateFormat.system ? undefined : locale.language;
if (
locale.date_format === DateFormat.language ||
locale.date_format === DateFormat.system
) {
return new Intl.DateTimeFormat(localeString, {
year: "numeric",
month: "numeric",
day: "numeric",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
});
}
return new Intl.DateTimeFormat(localeString, {
year: "numeric",
month: "numeric",
day: "numeric",
})
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
});
}
);
// Aug 10
export const formatDateShort = (dateObj: Date, locale: FrontendLocaleData) =>
formatDateShortMem(locale).format(dateObj);
export const formatDateShort = (
dateObj: Date,
locale: FrontendLocaleData,
config: HassConfig
) => formatDateShortMem(locale, config.time_zone).format(dateObj);
const formatDateShortMem = memoizeOne(
(locale: FrontendLocaleData) =>
(locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(locale.language, {
day: "numeric",
month: "short",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
})
);
// August 2021
export const formatDateMonthYear = (
dateObj: Date,
locale: FrontendLocaleData
) => formatDateMonthYearMem(locale).format(dateObj);
locale: FrontendLocaleData,
config: HassConfig
) => formatDateMonthYearMem(locale, config.time_zone).format(dateObj);
const formatDateMonthYearMem = memoizeOne(
(locale: FrontendLocaleData) =>
(locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(locale.language, {
month: "long",
year: "numeric",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
})
);
// August
export const formatDateMonth = (dateObj: Date, locale: FrontendLocaleData) =>
formatDateMonthMem(locale).format(dateObj);
export const formatDateMonth = (
dateObj: Date,
locale: FrontendLocaleData,
config: HassConfig
) => formatDateMonthMem(locale, config.time_zone).format(dateObj);
const formatDateMonthMem = memoizeOne(
(locale: FrontendLocaleData) =>
(locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(locale.language, {
month: "long",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
})
);
// 2021
export const formatDateYear = (dateObj: Date, locale: FrontendLocaleData) =>
formatDateYearMem(locale).format(dateObj);
export const formatDateYear = (
dateObj: Date,
locale: FrontendLocaleData,
config: HassConfig
) => formatDateYearMem(locale, config.time_zone).format(dateObj);
const formatDateYearMem = memoizeOne(
(locale: FrontendLocaleData) =>
(locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(locale.language, {
year: "numeric",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
})
);
// Monday
export const formatDateWeekday = (dateObj: Date, locale: FrontendLocaleData) =>
formatDateWeekdayMem(locale).format(dateObj);
export const formatDateWeekday = (
dateObj: Date,
locale: FrontendLocaleData,
config: HassConfig
) => formatDateWeekdayMem(locale, config.time_zone).format(dateObj);
const formatDateWeekdayMem = memoizeOne(
(locale: FrontendLocaleData) =>
(locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(locale.language, {
weekday: "long",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
})
);
// Mon
export const formatDateWeekdayShort = (
dateObj: Date,
locale: FrontendLocaleData,
config: HassConfig
) => formatDateWeekdayShortMem(locale, config.time_zone).format(dateObj);
const formatDateWeekdayShortMem = memoizeOne(
(locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(locale.language, {
weekday: "short",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
})
);
+65 -83
View File
@@ -1,117 +1,99 @@
import { HassConfig } from "home-assistant-js-websocket";
import memoizeOne from "memoize-one";
import { FrontendLocaleData } from "../../data/translation";
import "../../resources/intl-polyfill";
import { formatDateNumeric } from "./format_date";
import { formatTime } from "./format_time";
import { useAmPm } from "./use_am_pm";
// August 9, 2021, 8:23 AM
export const formatDateTime = (dateObj: Date, locale: FrontendLocaleData) =>
formatDateTimeMem(locale).format(dateObj);
export const formatDateTime = (
dateObj: Date,
locale: FrontendLocaleData,
config: HassConfig
) => formatDateTimeMem(locale, config.time_zone).format(dateObj);
const formatDateTimeMem = memoizeOne(
(locale: FrontendLocaleData) =>
new Intl.DateTimeFormat(
locale.language === "en" && !useAmPm(locale)
? "en-u-hc-h23"
: locale.language,
{
year: "numeric",
month: "long",
day: "numeric",
hour: useAmPm(locale) ? "numeric" : "2-digit",
minute: "2-digit",
hour12: useAmPm(locale),
}
)
(locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(locale.language, {
year: "numeric",
month: "long",
day: "numeric",
hour: useAmPm(locale) ? "numeric" : "2-digit",
minute: "2-digit",
hourCycle: useAmPm(locale) ? "h12" : "h23",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
})
);
// Aug 9, 2021, 8:23 AM
export const formatShortDateTimeWithYear = (
dateObj: Date,
locale: FrontendLocaleData
) => formatShortDateTimeWithYearMem(locale).format(dateObj);
locale: FrontendLocaleData,
config: HassConfig
) => formatShortDateTimeWithYearMem(locale, config.time_zone).format(dateObj);
const formatShortDateTimeWithYearMem = memoizeOne(
(locale: FrontendLocaleData) =>
new Intl.DateTimeFormat(
locale.language === "en" && !useAmPm(locale)
? "en-u-hc-h23"
: locale.language,
{
year: "numeric",
month: "short",
day: "numeric",
hour: useAmPm(locale) ? "numeric" : "2-digit",
minute: "2-digit",
hour12: useAmPm(locale),
}
)
(locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(locale.language, {
year: "numeric",
month: "short",
day: "numeric",
hour: useAmPm(locale) ? "numeric" : "2-digit",
minute: "2-digit",
hourCycle: useAmPm(locale) ? "h12" : "h23",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
})
);
// Aug 9, 8:23 AM
export const formatShortDateTime = (
dateObj: Date,
locale: FrontendLocaleData
) => formatShortDateTimeMem(locale).format(dateObj);
locale: FrontendLocaleData,
config: HassConfig
) => formatShortDateTimeMem(locale, config.time_zone).format(dateObj);
const formatShortDateTimeMem = memoizeOne(
(locale: FrontendLocaleData) =>
new Intl.DateTimeFormat(
locale.language === "en" && !useAmPm(locale)
? "en-u-hc-h23"
: locale.language,
{
month: "short",
day: "numeric",
hour: useAmPm(locale) ? "numeric" : "2-digit",
minute: "2-digit",
hour12: useAmPm(locale),
}
)
(locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(locale.language, {
month: "short",
day: "numeric",
hour: useAmPm(locale) ? "numeric" : "2-digit",
minute: "2-digit",
hourCycle: useAmPm(locale) ? "h12" : "h23",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
})
);
// August 9, 2021, 8:23:15 AM
export const formatDateTimeWithSeconds = (
dateObj: Date,
locale: FrontendLocaleData
) => formatDateTimeWithSecondsMem(locale).format(dateObj);
locale: FrontendLocaleData,
config: HassConfig
) => formatDateTimeWithSecondsMem(locale, config.time_zone).format(dateObj);
const formatDateTimeWithSecondsMem = memoizeOne(
(locale: FrontendLocaleData) =>
new Intl.DateTimeFormat(
locale.language === "en" && !useAmPm(locale)
? "en-u-hc-h23"
: locale.language,
{
year: "numeric",
month: "long",
day: "numeric",
hour: useAmPm(locale) ? "numeric" : "2-digit",
minute: "2-digit",
second: "2-digit",
hour12: useAmPm(locale),
}
)
(locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(locale.language, {
year: "numeric",
month: "long",
day: "numeric",
hour: useAmPm(locale) ? "numeric" : "2-digit",
minute: "2-digit",
second: "2-digit",
hourCycle: useAmPm(locale) ? "h12" : "h23",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
})
);
// 9/8/2021, 8:23 AM
export const formatDateTimeNumeric = (
dateObj: Date,
locale: FrontendLocaleData
) => formatDateTimeNumericMem(locale).format(dateObj);
const formatDateTimeNumericMem = memoizeOne(
(locale: FrontendLocaleData) =>
new Intl.DateTimeFormat(
locale.language === "en" && !useAmPm(locale)
? "en-u-hc-h23"
: locale.language,
{
year: "numeric",
month: "numeric",
day: "numeric",
hour: "numeric",
minute: "2-digit",
hour12: useAmPm(locale),
}
)
);
locale: FrontendLocaleData,
config: HassConfig
) =>
`${formatDateNumeric(dateObj, locale, config)}, ${formatTime(
dateObj,
locale,
config
)}`;
+44 -44
View File
@@ -1,76 +1,76 @@
import { HassConfig } from "home-assistant-js-websocket";
import memoizeOne from "memoize-one";
import { FrontendLocaleData } from "../../data/translation";
import "../../resources/intl-polyfill";
import { useAmPm } from "./use_am_pm";
// 9:15 PM || 21:15
export const formatTime = (dateObj: Date, locale: FrontendLocaleData) =>
formatTimeMem(locale).format(dateObj);
export const formatTime = (
dateObj: Date,
locale: FrontendLocaleData,
config: HassConfig
) => formatTimeMem(locale, config.time_zone).format(dateObj);
const formatTimeMem = memoizeOne(
(locale: FrontendLocaleData) =>
new Intl.DateTimeFormat(
locale.language === "en" && !useAmPm(locale)
? "en-u-hc-h23"
: locale.language,
{
hour: "numeric",
minute: "2-digit",
hour12: useAmPm(locale),
}
)
(locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(locale.language, {
hour: "numeric",
minute: "2-digit",
hourCycle: useAmPm(locale) ? "h12" : "h23",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
})
);
// 9:15:24 PM || 21:15:24
export const formatTimeWithSeconds = (
dateObj: Date,
locale: FrontendLocaleData
) => formatTimeWithSecondsMem(locale).format(dateObj);
locale: FrontendLocaleData,
config: HassConfig
) => formatTimeWithSecondsMem(locale, config.time_zone).format(dateObj);
const formatTimeWithSecondsMem = memoizeOne(
(locale: FrontendLocaleData) =>
new Intl.DateTimeFormat(
locale.language === "en" && !useAmPm(locale)
? "en-u-hc-h23"
: locale.language,
{
hour: useAmPm(locale) ? "numeric" : "2-digit",
minute: "2-digit",
second: "2-digit",
hour12: useAmPm(locale),
}
)
(locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(locale.language, {
hour: useAmPm(locale) ? "numeric" : "2-digit",
minute: "2-digit",
second: "2-digit",
hourCycle: useAmPm(locale) ? "h12" : "h23",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
})
);
// Tuesday 7:00 PM || Tuesday 19:00
export const formatTimeWeekday = (dateObj: Date, locale: FrontendLocaleData) =>
formatTimeWeekdayMem(locale).format(dateObj);
export const formatTimeWeekday = (
dateObj: Date,
locale: FrontendLocaleData,
config: HassConfig
) => formatTimeWeekdayMem(locale, config.time_zone).format(dateObj);
const formatTimeWeekdayMem = memoizeOne(
(locale: FrontendLocaleData) =>
new Intl.DateTimeFormat(
locale.language === "en" && !useAmPm(locale)
? "en-u-hc-h23"
: locale.language,
{
weekday: "long",
hour: useAmPm(locale) ? "numeric" : "2-digit",
minute: "2-digit",
hour12: useAmPm(locale),
}
)
(locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(locale.language, {
weekday: "long",
hour: useAmPm(locale) ? "numeric" : "2-digit",
minute: "2-digit",
hourCycle: useAmPm(locale) ? "h12" : "h23",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
})
);
// 21:15
export const formatTime24h = (dateObj: Date) =>
formatTime24hMem().format(dateObj);
export const formatTime24h = (
dateObj: Date,
locale: FrontendLocaleData,
config: HassConfig
) => formatTime24hMem(locale, config.time_zone).format(dateObj);
const formatTime24hMem = memoizeOne(
() =>
(locale: FrontendLocaleData, serverTimeZone: string) =>
// en-GB to fix Chrome 24:59 to 0:59 https://stackoverflow.com/a/60898146
new Intl.DateTimeFormat("en-GB", {
hour: "numeric",
minute: "2-digit",
hour12: false,
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
})
);
+4 -2
View File
@@ -8,8 +8,10 @@ export const useAmPm = memoizeOne((locale: FrontendLocaleData): boolean => {
) {
const testLanguage =
locale.time_format === TimeFormat.language ? locale.language : undefined;
const test = new Date().toLocaleString(testLanguage);
return test.includes("AM") || test.includes("PM");
const test = new Date("January 1, 2023 22:00:00").toLocaleString(
testLanguage
);
return test.includes("10");
}
return locale.time_format === TimeFormat.am_pm;
+20 -7
View File
@@ -1,5 +1,10 @@
import type { LitElement } from "lit";
import type { ClassElement } from "../../types";
import { throttle } from "../util/throttle";
const throttleReplaceState = throttle((value) => {
history.replaceState({ scrollPosition: value }, "");
}, 300);
export const restoreScroll =
(selector: string): any =>
@@ -9,10 +14,13 @@ export const restoreScroll =
key: element.key,
descriptor: {
set(this: LitElement, value: number) {
throttleReplaceState(value);
this[`__${String(element.key)}`] = value;
},
get(this: LitElement) {
return this[`__${String(element.key)}`];
return (
this[`__${String(element.key)}`] || history.state?.scrollPosition
);
},
enumerable: true,
configurable: true,
@@ -21,12 +29,17 @@ export const restoreScroll =
const connectedCallback = cls.prototype.connectedCallback;
cls.prototype.connectedCallback = function () {
connectedCallback.call(this);
if (this[element.key]) {
const target = this.renderRoot.querySelector(selector);
if (!target) {
return;
}
target.scrollTop = this[element.key];
const scrollPos = this[element.key];
if (scrollPos) {
this.updateComplete.then(() => {
const target = this.renderRoot.querySelector(selector);
if (!target) {
return;
}
setTimeout(() => {
target.scrollTop = scrollPos;
}, 0);
});
}
};
},
@@ -1,13 +1,15 @@
import { UnsubscribeFunc } from "home-assistant-js-websocket";
import { PropertyDeclaration, ReactiveElement } from "lit";
import { ReactiveElement } from "lit";
import { InternalPropertyDeclaration } from "lit/decorators";
import type { ClassElement } from "../../types";
type Callback = (oldValue: any, newValue: any) => void;
class Storage {
constructor(subscribe = true, storage = window.localStorage) {
class StorageClass {
constructor(storage = window.localStorage) {
this.storage = storage;
if (!subscribe) {
if (storage !== window.localStorage) {
// storage events only work for localStorage
return;
}
window.addEventListener("storage", (ev: StorageEvent) => {
@@ -77,6 +79,7 @@ class Storage {
}
public setValue(storageKey: string, value: any): any {
const oldValue = this._storage[storageKey];
this._storage[storageKey] = value;
try {
if (value === undefined) {
@@ -86,49 +89,68 @@ class Storage {
}
} catch (err: any) {
// Safari in private mode doesn't allow localstorage
} finally {
if (this._listeners[storageKey]) {
this._listeners[storageKey].forEach((listener) =>
listener(oldValue, value)
);
}
}
}
}
const subscribeStorage = new Storage();
const storages: Record<string, StorageClass> = {};
export const LocalStorage =
(
storageKey?: string,
property?: boolean,
subscribe = true,
storageType?: globalThis.Storage,
propertyOptions?: PropertyDeclaration
): any =>
export const storage =
(options: {
key?: string;
storage?: "localStorage" | "sessionStorage";
subscribe?: boolean;
state?: boolean;
stateOptions?: InternalPropertyDeclaration;
}): any =>
(clsElement: ClassElement) => {
const storage =
subscribe && !storageType
? subscribeStorage
: new Storage(subscribe, storageType);
const storageName = options.storage || "localStorage";
let storageInstance: StorageClass;
if (storageName && storageName in storages) {
storageInstance = storages[storageName];
} else {
storageInstance = new StorageClass(window[storageName]);
storages[storageName] = storageInstance;
}
const key = String(clsElement.key);
storageKey = storageKey || String(clsElement.key);
const storageKey = options.key || String(clsElement.key);
const initVal = clsElement.initializer
? clsElement.initializer()
: undefined;
storage.addFromStorage(storageKey);
storageInstance.addFromStorage(storageKey);
const subscribeChanges = (el: ReactiveElement): UnsubscribeFunc =>
storage.subscribeChanges(storageKey!, (oldValue) => {
el.requestUpdate(clsElement.key, oldValue);
});
const subscribeChanges =
options.subscribe !== false
? (el: ReactiveElement): UnsubscribeFunc =>
storageInstance.subscribeChanges(
storageKey!,
(oldValue, _newValue) => {
el.requestUpdate(clsElement.key, oldValue);
}
)
: undefined;
const getValue = (): any =>
storage.hasKey(storageKey!) ? storage.getValue(storageKey!) : initVal;
storageInstance.hasKey(storageKey!)
? storageInstance.getValue(storageKey!)
: initVal;
const setValue = (el: ReactiveElement, value: any) => {
let oldValue: unknown | undefined;
if (property) {
if (options.state) {
oldValue = getValue();
}
storage.setValue(storageKey!, value);
if (property) {
storageInstance.setValue(storageKey!, value);
if (options.state) {
el.requestUpdate(clsElement.key, oldValue);
}
};
@@ -148,22 +170,23 @@ export const LocalStorage =
configurable: true,
},
finisher(cls: typeof ReactiveElement) {
if (property && subscribe) {
if (options.state && options.subscribe) {
const connectedCallback = cls.prototype.connectedCallback;
const disconnectedCallback = cls.prototype.disconnectedCallback;
cls.prototype.connectedCallback = function () {
connectedCallback.call(this);
this[`__unbsubLocalStorage${key}`] = subscribeChanges(this);
this[`__unbsubLocalStorage${key}`] = subscribeChanges?.(this);
};
cls.prototype.disconnectedCallback = function () {
disconnectedCallback.call(this);
this[`__unbsubLocalStorage${key}`]();
this[`__unbsubLocalStorage${key}`]?.();
this[`__unbsubLocalStorage${key}`] = undefined;
};
}
if (property) {
if (options.state) {
cls.createProperty(clsElement.key, {
noAccessor: true,
...propertyOptions,
...options.stateOptions,
});
}
},
+4 -2
View File
@@ -1,4 +1,4 @@
export const isNavigationClick = (e: MouseEvent) => {
export const isNavigationClick = (e: MouseEvent, preventDefault = true) => {
// Taken from polymer/pwa-helpers. BSD-3 licensed
if (
e.defaultPrevented ||
@@ -40,6 +40,8 @@ export const isNavigationClick = (e: MouseEvent) => {
return undefined;
}
e.preventDefault();
if (preventDefault) {
e.preventDefault();
}
return href;
};
@@ -1,4 +1,4 @@
import { HassEntity } from "home-assistant-js-websocket";
import { HassConfig, HassEntity } from "home-assistant-js-websocket";
import { html, TemplateResult } from "lit";
import { until } from "lit/directives/until";
import { EntityRegistryDisplayEntry } from "../../data/entity_registry";
@@ -20,6 +20,7 @@ export const computeAttributeValueDisplay = (
localize: LocalizeFunc,
stateObj: HassEntity,
locale: FrontendLocaleData,
config: HassConfig,
entities: HomeAssistant["entities"],
attribute: string,
value?: any
@@ -59,14 +60,14 @@ export const computeAttributeValueDisplay = (
if (isTimestamp(attributeValue)) {
const date = new Date(attributeValue);
if (checkValidDate(date)) {
return formatDateTimeWithSeconds(date, locale);
return formatDateTimeWithSeconds(date, locale, config);
}
}
// Value was not a timestamp, so only do date formatting
const date = new Date(attributeValue);
if (checkValidDate(date)) {
return formatDate(date, locale);
return formatDate(date, locale, config);
}
}
}
@@ -92,6 +93,7 @@ export const computeAttributeValueDisplay = (
localize,
stateObj,
locale,
config,
entities,
attribute,
item
+50 -52
View File
@@ -1,7 +1,7 @@
import { HassEntity } from "home-assistant-js-websocket";
import { HassConfig, HassEntity } from "home-assistant-js-websocket";
import { UNAVAILABLE, UNKNOWN } from "../../data/entity";
import { EntityRegistryDisplayEntry } from "../../data/entity_registry";
import { FrontendLocaleData } from "../../data/translation";
import { FrontendLocaleData, TimeZone } from "../../data/translation";
import {
updateIsInstallingFromAttributes,
UPDATE_SUPPORT_PROGRESS,
@@ -28,12 +28,14 @@ export const computeStateDisplaySingleEntity = (
localize: LocalizeFunc,
stateObj: HassEntity,
locale: FrontendLocaleData,
config: HassConfig,
entity: EntityRegistryDisplayEntry | undefined,
state?: string
): string =>
computeStateDisplayFromEntityAttributes(
localize,
locale,
config,
entity,
stateObj.entity_id,
stateObj.attributes,
@@ -44,6 +46,7 @@ export const computeStateDisplay = (
localize: LocalizeFunc,
stateObj: HassEntity,
locale: FrontendLocaleData,
config: HassConfig,
entities: HomeAssistant["entities"],
state?: string
): string => {
@@ -54,6 +57,7 @@ export const computeStateDisplay = (
return computeStateDisplayFromEntityAttributes(
localize,
locale,
config,
entity,
stateObj.entity_id,
stateObj.attributes,
@@ -64,6 +68,7 @@ export const computeStateDisplay = (
export const computeStateDisplayFromEntityAttributes = (
localize: LocalizeFunc,
locale: FrontendLocaleData,
config: HassConfig,
entity: EntityRegistryDisplayEntry | undefined,
entityId: string,
attributes: any,
@@ -117,59 +122,50 @@ export const computeStateDisplayFromEntityAttributes = (
const domain = computeDomain(entityId);
if (domain === "datetime") {
const time = new Date(state);
return formatDateTime(time, locale, config);
}
if (["date", "input_datetime", "time"].includes(domain)) {
if (state !== undefined) {
// If trying to display an explicit state, need to parse the explicit state to `Date` then format.
// Attributes aren't available, we have to use `state`.
try {
const components = state.split(" ");
if (components.length === 2) {
// Date and time.
return formatDateTime(new Date(components.join("T")), locale);
}
if (components.length === 1) {
if (state.includes("-")) {
// Date only.
return formatDate(new Date(`${state}T00:00`), locale);
}
if (state.includes(":")) {
// Time only.
const now = new Date();
return formatTime(
new Date(`${now.toISOString().split("T")[0]}T${state}`),
locale
);
}
}
return state;
} catch (_e) {
// Formatting methods may throw error if date parsing doesn't go well,
// just return the state string in that case.
return state;
}
} else {
// If not trying to display an explicit state, create `Date` object from `stateObj`'s attributes then format.
let date: Date;
if (attributes.has_date && attributes.has_time) {
date = new Date(
attributes.year,
attributes.month - 1,
attributes.day,
attributes.hour,
attributes.minute
// If trying to display an explicit state, need to parse the explicit state to `Date` then format.
// Attributes aren't available, we have to use `state`.
// These are timezone agnostic, so we should NOT use the system timezone here.
try {
const components = state.split(" ");
if (components.length === 2) {
// Date and time.
return formatDateTime(
new Date(components.join("T")),
{ ...locale, time_zone: TimeZone.local },
config
);
return formatDateTime(date, locale);
}
if (attributes.has_date) {
date = new Date(attributes.year, attributes.month - 1, attributes.day);
return formatDate(date, locale);
}
if (attributes.has_time) {
date = new Date();
date.setHours(attributes.hour, attributes.minute);
return formatTime(date, locale);
if (components.length === 1) {
if (state.includes("-")) {
// Date only.
return formatDate(
new Date(`${state}T00:00`),
{ ...locale, time_zone: TimeZone.local },
config
);
}
if (state.includes(":")) {
// Time only.
const now = new Date();
return formatTime(
new Date(`${now.toISOString().split("T")[0]}T${state}`),
{ ...locale, time_zone: TimeZone.local },
config
);
}
}
return state;
} catch (_e) {
// Formatting methods may throw error if date parsing doesn't go well,
// just return the state string in that case.
return state;
}
}
@@ -195,11 +191,13 @@ export const computeStateDisplayFromEntityAttributes = (
// state is a timestamp
if (
["button", "input_button", "scene", "stt", "tts"].includes(domain) ||
["button", "image", "input_button", "scene", "stt", "tts"].includes(
domain
) ||
(domain === "sensor" && attributes.device_class === "timestamp")
) {
try {
return formatDateTime(new Date(state), locale);
return formatDateTime(new Date(state), locale, config);
} catch (_err) {
return state;
}
+9 -1
View File
@@ -102,7 +102,15 @@ const FIXED_DOMAIN_ATTRIBUTE_STATES = {
frontend_stream_type: ["hls", "web_rtc"],
},
climate: {
hvac_action: ["off", "idle", "heating", "cooling", "drying", "fan"],
hvac_action: [
"off",
"idle",
"preheating",
"heating",
"cooling",
"drying",
"fan",
],
},
cover: {
device_class: [
@@ -17,7 +17,7 @@ export const protocolIntegrationPicked = async (
element: HTMLElement,
hass: HomeAssistant,
domain: string,
options?: { brand?: string; domain?: string }
options?: { brand?: string; domain?: string; config_entry?: string }
) => {
if (options?.domain) {
const localize = await hass.loadBackendTranslation("title", options.domain);
@@ -32,11 +32,16 @@ export const protocolIntegrationPicked = async (
}
if (domain === "zwave_js") {
const entries = await getConfigEntries(hass, {
domain,
});
const entries = options?.config_entry
? undefined
: await getConfigEntries(hass, {
domain,
});
if (!isComponentLoaded(hass, "zwave_js") || !entries.length) {
if (
!isComponentLoaded(hass, "zwave_js") ||
(!options?.config_entry && !entries?.length)
) {
// If the component isn't loaded, ask them to load the integration first
showConfirmationDialog(element, {
title: hass.localize(
@@ -71,14 +76,19 @@ export const protocolIntegrationPicked = async (
}
showZWaveJSAddNodeDialog(element, {
entry_id: entries[0].entry_id,
entry_id: options?.config_entry || entries![0].entry_id,
});
} else if (domain === "zha") {
const entries = await getConfigEntries(hass, {
domain,
});
const entries = options?.config_entry
? undefined
: await getConfigEntries(hass, {
domain,
});
if (!isComponentLoaded(hass, "zha") || !entries.length) {
if (
!isComponentLoaded(hass, "zha") ||
(!options?.config_entry && !entries?.length)
) {
// If the component isn't loaded, ask them to load the integration first
showConfirmationDialog(element, {
title: hass.localize(
@@ -117,10 +127,15 @@ export const protocolIntegrationPicked = async (
navigate("/config/zha/add");
} else if (domain === "matter") {
const entries = await getConfigEntries(hass, {
domain,
});
if (!isComponentLoaded(hass, domain) || !entries.length) {
const entries = options?.config_entry
? undefined
: await getConfigEntries(hass, {
domain,
});
if (
!isComponentLoaded(hass, domain) ||
(!options?.config_entry && !entries?.length)
) {
// If the component isn't loaded, ask them to load the integration first
showConfirmationDialog(element, {
title: hass.localize(
+6 -4
View File
@@ -1,10 +1,12 @@
import { addDays, startOfWeek } from "date-fns";
import { HassConfig } from "home-assistant-js-websocket";
import memoizeOne from "memoize-one";
import { FrontendLocaleData } from "../../data/translation";
import { formatDateWeekday } from "../datetime/format_date";
export const dayNames = memoizeOne((locale: FrontendLocaleData): string[] =>
Array.from({ length: 7 }, (_, d) =>
formatDateWeekday(addDays(startOfWeek(new Date()), d), locale)
)
export const dayNames = memoizeOne(
(locale: FrontendLocaleData, config: HassConfig): string[] =>
Array.from({ length: 7 }, (_, d) =>
formatDateWeekday(addDays(startOfWeek(new Date()), d), locale, config)
)
);
+6 -4
View File
@@ -1,10 +1,12 @@
import { addMonths, startOfYear } from "date-fns";
import { HassConfig } from "home-assistant-js-websocket";
import memoizeOne from "memoize-one";
import { FrontendLocaleData } from "../../data/translation";
import { formatDateMonth } from "../datetime/format_date";
export const monthNames = memoizeOne((locale: FrontendLocaleData): string[] =>
Array.from({ length: 12 }, (_, m) =>
formatDateMonth(addMonths(startOfYear(new Date()), m), locale)
)
export const monthNames = memoizeOne(
(locale: FrontendLocaleData, config: HassConfig): string[] =>
Array.from({ length: 12 }, (_, m) =>
formatDateMonth(addMonths(startOfYear(new Date()), m), locale, config)
)
);
+70 -14
View File
@@ -80,33 +80,89 @@ _adapters._date.override({
format: function (time, fmt: keyof typeof FORMATS) {
switch (fmt) {
case "datetime":
return formatDateTime(new Date(time), this.options.locale);
return formatDateTime(
new Date(time),
this.options.locale,
this.options.config
);
case "datetimeseconds":
return formatDateTimeWithSeconds(new Date(time), this.options.locale);
return formatDateTimeWithSeconds(
new Date(time),
this.options.locale,
this.options.config
);
case "millisecond":
return formatTimeWithSeconds(new Date(time), this.options.locale);
return formatTimeWithSeconds(
new Date(time),
this.options.locale,
this.options.config
);
case "second":
return formatTimeWithSeconds(new Date(time), this.options.locale);
return formatTimeWithSeconds(
new Date(time),
this.options.locale,
this.options.config
);
case "minute":
return formatTime(new Date(time), this.options.locale);
return formatTime(
new Date(time),
this.options.locale,
this.options.config
);
case "hour":
return formatTime(new Date(time), this.options.locale);
return formatTime(
new Date(time),
this.options.locale,
this.options.config
);
case "weekday":
return formatDateWeekdayDay(new Date(time), this.options.locale);
return formatDateWeekdayDay(
new Date(time),
this.options.locale,
this.options.config
);
case "date":
return formatDate(new Date(time), this.options.locale);
return formatDate(
new Date(time),
this.options.locale,
this.options.config
);
case "day":
return formatDateShort(new Date(time), this.options.locale);
return formatDateShort(
new Date(time),
this.options.locale,
this.options.config
);
case "week":
return formatDate(new Date(time), this.options.locale);
return formatDate(
new Date(time),
this.options.locale,
this.options.config
);
case "month":
return formatDateMonth(new Date(time), this.options.locale);
return formatDateMonth(
new Date(time),
this.options.locale,
this.options.config
);
case "monthyear":
return formatDateMonthYear(new Date(time), this.options.locale);
return formatDateMonthYear(
new Date(time),
this.options.locale,
this.options.config
);
case "quarter":
return formatDate(new Date(time), this.options.locale);
return formatDate(
new Date(time),
this.options.locale,
this.options.config
);
case "year":
return formatDateYear(new Date(time), this.options.locale);
return formatDateYear(
new Date(time),
this.options.locale,
this.options.config
);
default:
return "";
}
@@ -30,6 +30,8 @@ class StateHistoryChartLine extends LitElement {
@property({ type: Boolean }) public showNames = true;
@property({ attribute: false }) public startTime!: Date;
@property({ attribute: false }) public endTime!: Date;
@property({ type: Number }) public paddingYAxis = 0;
@@ -57,7 +59,12 @@ class StateHistoryChartLine extends LitElement {
}
public willUpdate(changedProps: PropertyValues) {
if (!this.hasUpdated || changedProps.has("showNames")) {
if (
!this.hasUpdated ||
changedProps.has("showNames") ||
changedProps.has("startTime") ||
changedProps.has("endTime")
) {
this._chartOptions = {
parsing: false,
animation: false,
@@ -71,8 +78,10 @@ class StateHistoryChartLine extends LitElement {
adapters: {
date: {
locale: this.hass.locale,
config: this.hass.config,
},
},
suggestedMin: this.startTime,
suggestedMax: this.endTime,
ticks: {
maxRotation: 0,
@@ -145,6 +154,8 @@ class StateHistoryChartLine extends LitElement {
}
if (
changedProps.has("data") ||
changedProps.has("startTime") ||
changedProps.has("endTime") ||
this._chartTime <
new Date(this.endTime.getTime() - MIN_TIME_BETWEEN_UPDATES)
) {
@@ -375,6 +386,9 @@ class StateHistoryChartLine extends LitElement {
lastNullDate = date;
}
});
if (lastNullDate !== null) {
pushData(lastNullDate, [null]);
}
}
// Add an entry for final values
@@ -98,6 +98,7 @@ export class StateHistoryChartTimeline extends LitElement {
adapters: {
date: {
locale: this.hass.locale,
config: this.hass.config,
},
},
suggestedMin: this.startTime,
@@ -181,8 +182,16 @@ export class StateHistoryChartTimeline extends LitElement {
return [
d.label || "",
formatDateTimeWithSeconds(d.start, this.hass.locale),
formatDateTimeWithSeconds(d.end, this.hass.locale),
formatDateTimeWithSeconds(
d.start,
this.hass.locale,
this.hass.config
),
formatDateTimeWithSeconds(
d.end,
this.hass.locale,
this.hass.config
),
formattedDuration,
];
},
+23 -7
View File
@@ -52,8 +52,12 @@ export class StateHistoryCharts extends LitElement {
@property({ attribute: false }) public endTime?: Date;
@property({ attribute: false }) public startTime?: Date;
@property({ type: Boolean, attribute: "up-to-now" }) public upToNow = false;
@property() public hoursToShow?: number;
@property({ type: Boolean }) public showNames = true;
@property({ type: Boolean }) public isLoadingData = false;
@@ -95,13 +99,24 @@ export class StateHistoryCharts extends LitElement {
this._computedEndTime =
this.upToNow || !this.endTime || this.endTime > now ? now : this.endTime;
this._computedStartTime = new Date(
this.historyData.timeline.reduce(
(minTime, stateInfo) =>
Math.min(minTime, new Date(stateInfo.data[0].last_changed).getTime()),
new Date().getTime()
)
);
if (this.startTime) {
this._computedStartTime = this.startTime;
} else if (this.hoursToShow) {
this._computedStartTime = new Date(
new Date().getTime() - 60 * 60 * this.hoursToShow * 1000
);
} else {
this._computedStartTime = new Date(
this.historyData.timeline.reduce(
(minTime, stateInfo) =>
Math.min(
minTime,
new Date(stateInfo.data[0].last_changed).getTime()
),
new Date().getTime()
)
);
}
const combinedItems = this.historyData.timeline.length
? (this.virtualize
@@ -142,6 +157,7 @@ export class StateHistoryCharts extends LitElement {
.data=${item.data}
.identifier=${item.identifier}
.showNames=${this.showNames}
.startTime=${this._computedStartTime}
.endTime=${this._computedEndTime}
.paddingYAxis=${this._maxYWidth}
.names=${this.names}
+1
View File
@@ -146,6 +146,7 @@ class StatisticsChart extends LitElement {
adapters: {
date: {
locale: this.hass.locale,
config: this.hass.config,
},
},
ticks: {
+1 -1
View File
@@ -490,7 +490,7 @@ export class HaDataTable extends LitElement {
}
private _memFilterData = memoizeOne(
async (
(
data: DataTableRowData[],
columns: SortableColumnContainer,
filter: string
@@ -1,6 +1,6 @@
// To use comlink under ES5
import { expose } from "comlink";
import "proxy-polyfill";
import { expose } from "comlink";
import type {
ClonedDataTableColumnData,
DataTableRowData,
+19 -18
View File
@@ -1,5 +1,5 @@
import { Remote, wrap } from "comlink";
import type { Api } from "./sort_filter_worker";
import type { Api } from "./sort-filter-worker";
type FilterDataType = Api["filterData"];
type FilterDataParamTypes = Parameters<FilterDataType>;
@@ -9,27 +9,28 @@ type SortDataParamTypes = Parameters<SortDataType>;
let worker: Remote<Api> | undefined;
export const filterData = async (
const getWorker = () => {
if (!worker) {
worker = wrap(
new Worker(
/* webpackChunkName: "sort-filter-worker" */
new URL("./sort-filter-worker", import.meta.url)
)
);
}
return worker;
};
export const filterData = (
data: FilterDataParamTypes[0],
columns: FilterDataParamTypes[1],
filter: FilterDataParamTypes[2]
): Promise<ReturnType<FilterDataType>> => {
if (!worker) {
worker = wrap(new Worker(new URL("./sort_filter_worker", import.meta.url)));
}
return worker.filterData(data, columns, filter);
};
export const sortData = async (
): Promise<ReturnType<FilterDataType>> =>
getWorker().filterData(data, columns, filter);
export const sortData = (
data: SortDataParamTypes[0],
columns: SortDataParamTypes[1],
direction: SortDataParamTypes[2],
sortColumn: SortDataParamTypes[3]
): Promise<ReturnType<SortDataType>> => {
if (!worker) {
worker = wrap(new Worker(new URL("./sort_filter_worker", import.meta.url)));
}
return worker.sortData(data, columns, direction, sortColumn);
};
): Promise<ReturnType<SortDataType>> =>
getWorker().sortData(data, columns, direction, sortColumn);
+22 -2
View File
@@ -26,6 +26,10 @@ import { SubscribeMixin } from "../../mixins/subscribe-mixin";
import { ValueChangedEvent, HomeAssistant } from "../../types";
import "../ha-combo-box";
import type { HaComboBox } from "../ha-combo-box";
import {
fuzzyFilterSort,
ScorableTextItem,
} from "../../common/string/filter/sequence-matching";
interface Device {
name: string;
@@ -33,6 +37,8 @@ interface Device {
id: string;
}
type ScorableDevice = ScorableTextItem & Device;
export type HaDevicePickerDeviceFilterFunc = (
device: DeviceRegistryEntry
) => boolean;
@@ -119,13 +125,14 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) {
deviceFilter: this["deviceFilter"],
entityFilter: this["entityFilter"],
excludeDevices: this["excludeDevices"]
): Device[] => {
): ScorableDevice[] => {
if (!devices.length) {
return [
{
id: "no_devices",
area: "",
name: this.hass.localize("ui.components.device-picker.no_devices"),
strings: [],
},
];
}
@@ -235,6 +242,7 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) {
device.area_id && areaLookup[device.area_id]
? areaLookup[device.area_id].name
: this.hass.localize("ui.components.device-picker.no_area"),
strings: [device.name || ""],
}));
if (!outputDevices.length) {
return [
@@ -242,6 +250,7 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) {
id: "no_devices",
area: "",
name: this.hass.localize("ui.components.device-picker.no_match"),
strings: [],
},
];
}
@@ -284,7 +293,7 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) {
(this._init && changedProps.has("_opened") && this._opened)
) {
this._init = true;
(this.comboBox as any).items = this._getDevices(
const devices = this._getDevices(
this.devices!,
this.areas!,
this.entities!,
@@ -295,6 +304,8 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) {
this.entityFilter,
this.excludeDevices
);
this.comboBox.items = devices;
this.comboBox.filteredItems = devices;
}
}
@@ -314,6 +325,7 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) {
item-label-path="name"
@opened-changed=${this._openedChanged}
@value-changed=${this._deviceChanged}
@filter-changed=${this._filterChanged}
></ha-combo-box>
`;
}
@@ -322,6 +334,14 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) {
return this.value || "";
}
private _filterChanged(ev: CustomEvent): void {
const target = ev.target as HaComboBox;
const filterString = ev.detail.value.toLowerCase();
target.filteredItems = filterString.length
? fuzzyFilterSort<ScorableDevice>(filterString, target.items || [])
: target.items;
}
private _deviceChanged(ev: ValueChangedEvent<string>) {
ev.stopPropagation();
let newValue = ev.detail.value;
+2 -2
View File
@@ -111,10 +111,10 @@ class HaDevicesPicker extends LitElement {
event.stopPropagation();
const curValue = (event.currentTarget as any).curValue;
const newValue = event.detail.value;
if (newValue === curValue || newValue !== "") {
if (newValue === curValue) {
return;
}
if (newValue === "") {
if (newValue === undefined) {
this._updateDevices(
this._currentDevices.filter((dev) => dev !== curValue)
);
+29 -16
View File
@@ -7,15 +7,19 @@ import memoizeOne from "memoize-one";
import { fireEvent } from "../../common/dom/fire_event";
import { computeDomain } from "../../common/entity/compute_domain";
import { computeStateName } from "../../common/entity/compute_state_name";
import { caseInsensitiveStringCompare } from "../../common/string/compare";
import {
fuzzyFilterSort,
ScorableTextItem,
} from "../../common/string/filter/sequence-matching";
import { ValueChangedEvent, HomeAssistant } from "../../types";
import "../ha-combo-box";
import type { HaComboBox } from "../ha-combo-box";
import "../ha-icon-button";
import "../ha-svg-icon";
import "./state-badge";
import { caseInsensitiveStringCompare } from "../../common/string/compare";
interface HassEntityWithCachedName extends HassEntity {
interface HassEntityWithCachedName extends HassEntity, ScorableTextItem {
friendly_name: string;
}
@@ -159,6 +163,7 @@ export class HaEntityPicker extends LitElement {
),
icon: "mdi:magnify",
},
strings: [],
},
];
}
@@ -169,10 +174,14 @@ export class HaEntityPicker extends LitElement {
);
return entityIds
.map((key) => ({
...hass!.states[key],
friendly_name: computeStateName(hass!.states[key]) || key,
}))
.map((key) => {
const friendly_name = computeStateName(hass!.states[key]) || key;
return {
...hass!.states[key],
friendly_name,
strings: [key, friendly_name],
};
})
.sort((entityA, entityB) =>
caseInsensitiveStringCompare(
entityA.friendly_name,
@@ -201,10 +210,14 @@ export class HaEntityPicker extends LitElement {
}
states = entityIds
.map((key) => ({
...hass!.states[key],
friendly_name: computeStateName(hass!.states[key]) || key,
}))
.map((key) => {
const friendly_name = computeStateName(hass!.states[key]) || key;
return {
...hass!.states[key],
friendly_name,
strings: [key, friendly_name],
};
})
.sort((entityA, entityB) =>
caseInsensitiveStringCompare(
entityA.friendly_name,
@@ -260,6 +273,7 @@ export class HaEntityPicker extends LitElement {
),
icon: "mdi:magnify",
},
strings: [],
},
];
}
@@ -293,7 +307,7 @@ export class HaEntityPicker extends LitElement {
this.excludeEntities
);
if (this._initedStates) {
(this.comboBox as any).filteredItems = this._states;
this.comboBox.filteredItems = this._states;
}
this._initedStates = true;
}
@@ -340,12 +354,11 @@ export class HaEntityPicker extends LitElement {
}
private _filterChanged(ev: CustomEvent): void {
const target = ev.target as HaComboBox;
const filterString = ev.detail.value.toLowerCase();
(this.comboBox as any).filteredItems = this._states.filter(
(entityState) =>
entityState.entity_id.toLowerCase().includes(filterString) ||
computeStateName(entityState).toLowerCase().includes(filterString)
);
target.filteredItems = filterString.length
? fuzzyFilterSort<HassEntityWithCachedName>(filterString, this._states)
: this._states;
}
private _setValue(value: string) {
@@ -19,6 +19,8 @@ class HaEntityStatePicker extends LitElement {
@property() public attribute?: string;
@property() public extraOptions?: any[];
@property({ type: Boolean }) public autofocus = false;
@property({ type: Boolean }) public disabled = false;
@@ -43,10 +45,16 @@ class HaEntityStatePicker extends LitElement {
}
protected updated(changedProps: PropertyValues) {
if (changedProps.has("_opened") && this._opened) {
if (
(changedProps.has("_opened") && this._opened) ||
changedProps.has("entityId") ||
changedProps.has("attribute") ||
changedProps.has("extraOptions")
) {
const state = this.entityId ? this.hass.states[this.entityId] : undefined;
(this._comboBox as any).items =
this.entityId && state
(this._comboBox as any).items = [
...(this.extraOptions ?? []),
...(this.entityId && state
? getStates(state, this.attribute).map((key) => ({
value: key,
label: !this.attribute
@@ -54,6 +62,7 @@ class HaEntityStatePicker extends LitElement {
this.hass.localize,
state,
this.hass.locale,
this.hass.config,
this.hass.entities,
key
)
@@ -61,12 +70,14 @@ class HaEntityStatePicker extends LitElement {
this.hass.localize,
state,
this.hass.locale,
this.hass.config,
this.hass.entities,
this.attribute,
key
),
}))
: [];
: []),
];
}
}
@@ -192,6 +192,7 @@ export class HaStateLabelBadge extends LitElement {
this.hass!.localize,
entityState,
this.hass!.locale,
this.hass!.config,
this.hass!.entities
);
}
@@ -280,7 +281,7 @@ export class HaStateLabelBadge extends LitElement {
font-size: 70%;
}
ha-label-badge {
--ha-label-badge-color: var(--label-badge-red, #df4c1e);
--ha-label-badge-color: var(--label-badge-red);
}
ha-label-badge.has-unit_of_measurement {
--ha-label-badge-label-text-transform: none;
@@ -288,31 +289,31 @@ export class HaStateLabelBadge extends LitElement {
ha-label-badge.binary_sensor,
ha-label-badge.updater {
--ha-label-badge-color: var(--label-badge-blue, #039be5);
--ha-label-badge-color: var(--label-badge-blue);
}
.red {
--ha-label-badge-color: var(--label-badge-red, #df4c1e);
--ha-label-badge-color: var(--label-badge-red);
}
.blue {
--ha-label-badge-color: var(--label-badge-blue, #039be5);
--ha-label-badge-color: var(--label-badge-blue);
}
.green {
--ha-label-badge-color: var(--label-badge-green, #0da035);
--ha-label-badge-color: var(--label-badge-green);
}
.yellow {
--ha-label-badge-color: var(--label-badge-yellow, #f4b400);
--ha-label-badge-color: var(--label-badge-yellow);
}
.grey {
--ha-label-badge-color: var(--label-badge-grey, var(--paper-grey-500));
--ha-label-badge-color: var(--label-badge-grey);
}
.warning {
--ha-label-badge-color: var(--label-badge-yellow, #f4b400);
--ha-label-badge-color: var(--label-badge-yellow);
}
`;
}
+25
View File
@@ -38,6 +38,31 @@ export class StateBadge extends LitElement {
@state() private _iconStyle: { [name: string]: string | undefined } = {};
connectedCallback(): void {
super.connectedCallback();
if (
this.hasUpdated &&
this.overrideImage === undefined &&
(this.stateObj?.attributes.entity_picture ||
this.stateObj?.attributes.entity_picture_local)
) {
// Update image on connect, so we get new auth token
this.requestUpdate("stateObj");
}
}
disconnectedCallback() {
super.disconnectedCallback();
if (
this.overrideImage === undefined &&
(this.stateObj?.attributes.entity_picture ||
this.stateObj?.attributes.entity_picture_local)
) {
// Clear image on disconnect so we don't fetch with old auth when we reconnect
this.style.backgroundImage = "";
}
}
private get _stateColor() {
const domain = this.stateObj
? computeStateDomain(this.stateObj)
+5 -1
View File
@@ -64,7 +64,11 @@ class HaAbsoluteTime extends ReactiveElement {
if (!this.datetime) {
this.innerHTML = this.hass.localize("ui.components.absolute_time.never");
} else {
this.innerHTML = absoluteTime(new Date(this.datetime), this.hass.locale);
this.innerHTML = absoluteTime(
new Date(this.datetime),
this.hass.locale,
this.hass.config
);
}
}
}
+3 -3
View File
@@ -58,12 +58,12 @@ class HaAddonPicker extends LitElement {
}
protected render() {
if (!this._addons) {
return nothing;
}
if (this._error) {
return html`<ha-alert alert-type="error">${this._error}</ha-alert>`;
}
if (!this._addons) {
return nothing;
}
return html`
<ha-combo-box
.hass=${this.hass}
+16 -6
View File
@@ -7,6 +7,10 @@ import { classMap } from "lit/directives/class-map";
import memoizeOne from "memoize-one";
import { fireEvent } from "../common/dom/fire_event";
import { computeDomain } from "../common/entity/compute_domain";
import {
fuzzyFilterSort,
ScorableTextItem,
} from "../common/string/filter/sequence-matching";
import {
AreaRegistryEntry,
createAreaRegistryEntry,
@@ -28,6 +32,8 @@ import type { HaComboBox } from "./ha-combo-box";
import "./ha-icon-button";
import "./ha-svg-icon";
type ScorableAreaRegistryEntry = ScorableTextItem & AreaRegistryEntry;
const rowRenderer: ComboBoxLitRenderer<AreaRegistryEntry> = (
item
) => html`<mwc-list-item
@@ -306,9 +312,12 @@ export class HaAreaPicker extends LitElement {
this.entityFilter,
this.noAdd,
this.excludeAreas
);
(this.comboBox as any).items = areas;
(this.comboBox as any).filteredItems = areas;
).map((area) => ({
...area,
strings: [area.area_id, ...area.aliases, area.name],
}));
this.comboBox.items = areas;
this.comboBox.filteredItems = areas;
}
}
@@ -345,8 +354,9 @@ export class HaAreaPicker extends LitElement {
return;
}
const filteredItems = this.comboBox.items?.filter((item) =>
item.name.toLowerCase().includes(filter!.toLowerCase())
const filteredItems = fuzzyFilterSort<ScorableAreaRegistryEntry>(
filter,
this.comboBox?.items || []
);
if (!this.noAdd && filteredItems?.length === 0) {
this._suggestion = filter;
@@ -409,7 +419,7 @@ export class HaAreaPicker extends LitElement {
name,
});
const areas = [...Object.values(this.hass.areas), area];
(this.comboBox as any).filteredItems = this._getAreas(
this.comboBox.filteredItems = this._getAreas(
areas,
Object.values(this.hass.devices)!,
Object.values(this.hass.entities)!,
+1
View File
@@ -62,6 +62,7 @@ class HaAttributes extends LitElement {
this.hass.localize,
this.stateObj!,
this.hass.locale,
this.hass.config,
this.hass.entities,
attribute
)}
+3
View File
@@ -28,6 +28,7 @@ class HaClimateState extends LitElement {
this.hass.localize,
this.stateObj,
this.hass.locale,
this.hass.config,
this.hass.entities,
"preset_mode"
)}`
@@ -136,6 +137,7 @@ class HaClimateState extends LitElement {
this.hass.localize,
this.stateObj,
this.hass.locale,
this.hass.config,
this.hass.entities
);
@@ -144,6 +146,7 @@ class HaClimateState extends LitElement {
this.hass.localize,
this.stateObj,
this.hass.locale,
this.hass.config,
this.hass.entities,
"hvac_action"
)} (${stateString})`

Some files were not shown because too many files have changed in this diff Show More