Compare commits

...

563 Commits

Author SHA1 Message Date
Thomas Lovén e87accdfb4 Arrayify actions list 2021-01-27 10:43:58 +01:00
Thomas Lovén 4dcfe3031d Allow multiple tap/hold/doubletap actions. 2021-01-10 19:29:29 +01:00
Bram Kragten 1538fbb102 Bump material elements (#8093) 2021-01-07 10:09:03 +01:00
Philip Allgaier b9259b87eb Beautify ha-attribute <pre> (#8101) 2021-01-06 20:46:39 +01:00
David F. Mulcahey 30997dbc88 Add filtering and zoom to node to the ZHA network visualization (#7913) 2021-01-06 10:37:53 +01:00
Paulus Schoutsen 607eb6d130 Prefer target over environment (#8092) 2021-01-05 16:03:55 +01:00
Philip Allgaier f2e9b3577d Use proper styled confirmation dialog for handled actions (#8077) 2021-01-05 14:04:45 +01:00
Philip Allgaier cb2c6d8560 Convert gallery elements to LitElement (#8088) 2021-01-05 13:29:21 +01:00
dependabot[bot] bfe8346ced Bump ini from 1.3.5 to 1.3.7 (#7949)
Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.7.
- [Release notes](https://github.com/isaacs/ini/releases)
- [Commits](https://github.com/isaacs/ini/compare/v1.3.5...v1.3.7)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-05 11:47:56 +01:00
Siemon Geeroms 88da9bb91b Allow to show modal dialogs in iFrame panels (#7971) 2021-01-05 11:38:46 +01:00
Shane Qi 5e2ee1a16c Added Drag & Drop Reordering to Shopping List Card. (#7296) 2021-01-05 11:24:41 +01:00
Philip Allgaier 2fdc746392 Add support for "all" as entity ID in action "service" (#7954) 2021-01-05 11:02:47 +01:00
Philip Allgaier 1667973a66 Improve spacing in entity rows + secondary ellipsis (#8028) 2021-01-05 10:50:40 +01:00
Philip Allgaier 42f0101440 Add gallery demo for plant card (#7989) 2021-01-04 22:10:58 +01:00
Philip Allgaier 13b69bff1b Translate timestamp-display errors + tiny tweaks (#8086)
* Translate timestamp-display errors + tiny tweaks

* Adjust translation key
2021-01-04 20:55:43 +01:00
Philip Allgaier 2c2226dfd6 Slightly increase max attribute value width (#8085) 2021-01-04 19:51:30 +01:00
Philip Allgaier a3fdfe0e15 Add additional entities to gallery more-info-light (#7930) 2021-01-04 18:06:47 +01:00
Philip Allgaier a0de209a55 Aligned gallery more-info with hui-cards (#7931) 2021-01-04 18:05:30 +01:00
Philip Allgaier 0208b50ac7 Disable counter buttons if entity is unavailable (#8084) 2021-01-04 18:02:01 +01:00
Philip Allgaier 4a61779aba Ensure YAML editor gets updated during action change / deletion (#8024)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2021-01-04 15:01:25 +01:00
Philip Allgaier 05057ade05 Catch navigator.clipboard errors (#7942)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2021-01-04 14:04:54 +01:00
Abílio Costa 6fb206853c Switch header sizes for ZHA pairing status card (#8078)
Since the top title shows the result of the previous step ("Interview
Complete", "Configuration Complete", etc), while the second title shows
the current step ("Configuring", "Initializing", etc), having the top
title bigger would draw attention to it. So a user could see
"Configuration Complete" and assume pairing is done.

This change makes the second title bigger than the top one, so that the
user focus on the step that is in progress.
2021-01-04 14:03:12 +01:00
Charles Garwood fab68055bf OZW Panel: Don't show an empty wakeup card (#8064) 2021-01-04 10:57:25 +01:00
Philip Allgaier d5a77ef3cd Treat zero as String in number selector (#8070) 2021-01-04 10:53:40 +01:00
Philip Allgaier dcb2605de4 Add Bengali language (#8014) 2021-01-04 10:28:25 +01:00
Philip Allgaier e6d38f4539 Fix incorrect date selection ranges for history and logbook (#8045) 2021-01-04 10:04:14 +01:00
Philip Allgaier 293b56cfa6 Show actual error path/key in YAML card editor (#8076) 2021-01-04 09:58:07 +01:00
Philip Allgaier 775e93d54b Ensure consistent number display for gauge (#8080) 2021-01-04 09:24:51 +01:00
Philip Allgaier 7f840e75df Add EN fallback text for dismiss button (#8068) 2021-01-04 09:18:08 +01:00
Philip Allgaier 2113ea675e Prevent relative time text wrapping in more-info-sun (#8051) 2021-01-04 09:17:17 +01:00
Philip Allgaier 916a5c1a6b Make it clearer that we are looking for the YAML card config 2021-01-04 00:31:42 +01:00
HomeAssistant Azure f684531315 [ci skip] Translation update 2021-01-02 00:41:18 +00:00
HomeAssistant Azure fe8dda8996 [ci skip] Translation update 2020-12-31 00:32:48 +00:00
HomeAssistant Azure 4cd4b328c8 [ci skip] Translation update 2020-12-30 00:32:31 +00:00
Bram Kragten d844c89b94 Merge branch 'master' into dev 2020-12-29 23:12:14 +01:00
Bram Kragten 177ea2b85a Bumped version to 20201229.0 2020-12-29 23:09:00 +01:00
Marc Mueller 50c5c15f49 Update group reload string (#7938)
* Update group reload string

* Update src/translations/en.json

Co-authored-by: Philip Allgaier <philip.allgaier@gmx.de>

* Update rest reload string

Co-authored-by: Philip Allgaier <philip.allgaier@gmx.de>
2020-12-29 23:03:44 +01:00
Philip Allgaier 1810760dc7 Mark entity ID as optional for button card (#7967) 2020-12-29 23:02:47 +01:00
Joakim Sørensen 4635b92e3f Fix add-on stage icon rendering (#7981) 2020-12-29 22:59:07 +01:00
Jochen Mehlhorn 1c652626eb Fix typo in hassio-supervisor-info.ts (#7907)
Fix typo in "unhealthy state" warning
2020-12-29 22:58:29 +01:00
Philip Allgaier 2000cfb1db Correct tabs for customizations page (#7990) 2020-12-29 22:52:58 +01:00
Philip Allgaier f4d07828e7 Minor follow-up tweaks for PR 7947 (#7955) 2020-12-29 22:52:20 +01:00
Philip Allgaier 95b552671c Fix border radius for labeled slider (#7929) 2020-12-29 22:50:09 +01:00
Philip Allgaier ef3bc3efe1 Do not render "No Area" in device table to reduce clutter (#7986) 2020-12-29 22:46:47 +01:00
Philip Allgaier 371ad899f5 Handle sorting with "undefined" (move always to bottom) (#7985) 2020-12-29 22:45:39 +01:00
plafü 2c54158d84 Fixes typo: 'bring to live'>'bring to life' (#8000) 2020-12-29 22:44:21 +01:00
quthla 5d9e30bbdc Fix translation of home state (#8015) 2020-12-29 22:43:41 +01:00
Marc Randolph e477fd567d Button text is swapped on Lovelace raw YAML exit window (#8038)
Button text is swapped compared to the same thing elsewhere: https://github.com/home-assistant/frontend/blob/d23165d06ae57cddef2529481d1c4d857f3e20b6/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts#L311
2020-12-29 22:38:31 +01:00
Philip Allgaier 6a6c2937fe Ensure consistent spelling of "ID" (#8042) 2020-12-29 22:36:28 +01:00
HomeAssistant Azure 09e17c4da8 [ci skip] Translation update 2020-12-29 00:32:26 +00:00
HomeAssistant Azure fd00469d11 [ci skip] Translation update 2020-12-28 00:32:37 +00:00
HomeAssistant Azure cbbeb795f3 [ci skip] Translation update 2020-12-27 00:32:32 +00:00
HomeAssistant Azure bba40e0da8 [ci skip] Translation update 2020-12-25 00:32:32 +00:00
HomeAssistant Azure d23165d06a [ci skip] Translation update 2020-12-24 00:33:07 +00:00
HomeAssistant Azure 405fef6f03 [ci skip] Translation update 2020-12-23 00:32:49 +00:00
HomeAssistant Azure 588f217826 [ci skip] Translation update 2020-12-22 00:32:27 +00:00
HomeAssistant Azure 3d8b7cf80e [ci skip] Translation update 2020-12-21 00:32:26 +00:00
HomeAssistant Azure c0ef923ad3 [ci skip] Translation update 2020-12-20 00:32:26 +00:00
HomeAssistant Azure 3df44fc71e [ci skip] Translation update 2020-12-19 00:33:33 +00:00
HomeAssistant Azure c1965492d9 [ci skip] Translation update 2020-12-18 00:32:38 +00:00
HomeAssistant Azure 1f56ffde80 [ci skip] Translation update 2020-12-17 00:33:13 +00:00
Georgi Kirichkov f335fdc002 Fixes a typo in hassio-supervisor-info.ts (#7987)
An "a" was missing in installtion
2020-12-16 10:28:21 +01:00
HomeAssistant Azure 0c914b5ec8 [ci skip] Translation update 2020-12-16 00:32:25 +00:00
Philip Allgaier d767b06858 Fix spelling error (#7961)
Fixes https://github.com/home-assistant/frontend/issues/7958
2020-12-15 07:22:06 -06:00
Fabian Affolter d4e49f3944 Update entry (#7978) 2020-12-15 09:49:26 +01:00
HomeAssistant Azure 7dfc5b3faf [ci skip] Translation update 2020-12-15 00:32:22 +00:00
HomeAssistant Azure 8a88033ab9 [ci skip] Translation update 2020-12-14 00:32:42 +00:00
HomeAssistant Azure 7b06b38c94 [ci skip] Translation update 2020-12-13 00:32:43 +00:00
Bram Kragten 5409752817 20201212.0 (#7952)
* [ci skip] Translation update

* Add link to the community forums to find more blueprints (#7947)

* Add link to the community forums to find more blueprints

* Apply suggestions from code review

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>

* Fix `ha-relative-time` usage for tags and sun (#7944)

* Bumped version to 20201212.0

Co-authored-by: HomeAssistant Azure <hello@home-assistant.io>
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
Co-authored-by: Philip Allgaier <mail@spacegaier.de>
2020-12-12 20:57:28 +01:00
Bram Kragten 909f3a3005 Bumped version to 20201212.0 2020-12-12 20:48:44 +01:00
Philip Allgaier 4930532c7b Fix ha-relative-time usage for tags and sun (#7944) 2020-12-12 20:46:56 +01:00
Bram Kragten 8a42e65c6a Add link to the community forums to find more blueprints (#7947)
* Add link to the community forums to find more blueprints

* Apply suggestions from code review

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2020-12-12 20:38:10 +01:00
HomeAssistant Azure 5d4121a9b4 [ci skip] Translation update 2020-12-11 00:32:17 +00:00
Bram Kragten a70e6c49a1 Merge pull request #7940 from home-assistant/dev
20201210.0
2020-12-10 16:56:08 +01:00
Bram Kragten 3d83d5f4b5 Bumped version to 20201210.0 2020-12-10 15:57:13 +01:00
Philip Allgaier f9dece0743 Add copy YAML (automation & script) fallback without navigator.clipboard (#7900) 2020-12-10 15:55:57 +01:00
Bram Kragten ac0871d0e8 Use correct device name in target picker (#7939) 2020-12-10 15:12:33 +01:00
HomeAssistant Azure ffc19e591d [ci skip] Translation update 2020-12-10 00:32:24 +00:00
HomeAssistant Azure c53380ca3d [ci skip] Translation update 2020-12-09 00:32:38 +00:00
Bram Kragten 7c74a2026a Correct tabs helpers page (#7928)
Fixes https://github.com/home-assistant/frontend/issues/7926
2020-12-08 11:47:30 +01:00
HomeAssistant Azure adaed438d9 [ci skip] Translation update 2020-12-08 00:32:29 +00:00
uvjustin baf38305cb Remove use of named groups in regexp (#7921) 2020-12-07 15:18:27 +01:00
HomeAssistant Azure 8254712521 [ci skip] Translation update 2020-12-07 00:33:14 +00:00
HomeAssistant Azure 53214781e3 [ci skip] Translation update 2020-12-06 00:32:39 +00:00
HomeAssistant Azure 88cbbbdf65 [ci skip] Translation update 2020-12-05 00:33:30 +00:00
Bram Kragten c10dca9c7b Merge pull request #7910 from home-assistant/dev 2020-12-04 21:46:54 +01:00
Bram Kragten 7f2ebb4bde Bumped version to 20201204.0 2020-12-04 21:33:37 +01:00
Bram Kragten f1abb60e4a Add message when no matches for selectors, clear config when deleted (#7906) 2020-12-04 20:49:24 +01:00
Bram Kragten e014c7aff6 Entity is not required for button card (#7909)
Fixes https://github.com/home-assistant/frontend/issues/7908
2020-12-04 12:02:58 -06:00
Bram Kragten b79c03433e Don't update device picker while open (#7903) 2020-12-04 12:05:01 +01:00
HomeAssistant Azure 34eb4d974d [ci skip] Translation update 2020-12-04 00:32:26 +00:00
Zack Barett 3264be3c5e Move main function to events on hui-view for custom views to use (#7861) 2020-12-03 18:16:55 -06:00
Bram Kragten 655f4f75fb Change import blueprint fab icon (#7894) 2020-12-03 22:41:13 +01:00
Bram Kragten 4383f31696 Translation logic tweaks (#7901)
* Translation logic tweaks

* Comments
2020-12-03 22:29:52 +01:00
Paulus Schoutsen 99eb15d15e Improve blueprint translations (#7892) 2020-12-03 18:08:14 +01:00
Bram Kragten 2682c6e150 Merge pull request #7891 from home-assistant/dev 2020-12-03 17:22:08 +01:00
Bram Kragten 3a5d854e6d Bumped version to 20201203.0 2020-12-03 17:00:56 +01:00
Bram Kragten 1e90c6387c More BP tweaks (#7884) 2020-12-03 09:59:43 -06:00
Philip Allgaier 2cca25f4d0 Navigate back to area overview after area deletion (#7890) 2020-12-03 16:52:44 +01:00
Bram Kragten 565724d201 Fix translation race condition? (#7885) 2020-12-03 16:52:09 +01:00
Bram Kragten 3e4955becd UI tweaks for BP (#7883)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2020-12-03 14:18:17 +01:00
Philip Allgaier 7b560c727f Adjust text since entities can now be in areas too (#7880) 2020-12-03 14:05:16 +01:00
HomeAssistant Azure 35abd9dfdb [ci skip] Translation update 2020-12-03 00:32:38 +00:00
Bram Kragten b7ccf3e0e5 Merge pull request #7875 from home-assistant/dev 2020-12-02 19:51:36 +01:00
Bram Kragten 0d9ab8fdd0 Bumped version to 20201202.0 2020-12-02 19:31:43 +01:00
Bram Kragten 303f9290a8 Add more device disabled ui (#7874) 2020-12-02 19:31:06 +01:00
Bram Kragten e0c4dc08a1 Tooltip tweak target picker (#7870) 2020-12-02 11:21:51 -06:00
Bram Kragten 8c655883fe Add device disabled reason (#7873) 2020-12-02 18:20:29 +01:00
Bram Kragten ba90785115 Fix card picker cards (#7871) 2020-12-02 17:46:30 +01:00
Bram Kragten 7b392b626b Hardcode history card stub entity to sun.sun (#7760) 2020-12-02 10:16:46 -06:00
Zack Barett 8e4ceb7d48 Fix View Background Colors (#7823) 2020-12-02 17:08:18 +01:00
Philip Allgaier 2ab1c6e9a9 Make media player card work as square + add to gallery + icon pos tweaks (#7727) 2020-12-02 16:57:19 +01:00
Adam Ernst dbdced0971 Improve descriptions for Configuration entries (#7606) 2020-12-02 16:36:21 +01:00
Philip Allgaier 5e481880bd Allow empty entities array with entity-filter (#7854) 2020-12-02 16:34:59 +01:00
Kendell R faec063f34 Add --masonry-view-card-margin (#7395) 2020-12-02 16:22:20 +01:00
Zack Barett bbea38d227 Lovelace Card Editor: Preview Background (#7678) 2020-12-02 16:19:01 +01:00
Kendell R a0ef60de49 Make card picker border follow standards (#7162) 2020-12-02 16:14:46 +01:00
Philip Allgaier 3313572606 Improve password change card (#7756)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-12-02 16:00:49 +01:00
Philip Allgaier c4f850cb14 Cleanup created user if person creation is cancelled (#7865) 2020-12-02 15:45:24 +01:00
Erik Montnemery 3bdab738c6 Support disabling devices (#7715)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-12-02 15:40:35 +01:00
Philip Allgaier faaef31b9f Show proper error message if username already used (#7866) 2020-12-02 15:35:38 +01:00
Philip Allgaier ca7b8b8b4c Add option to deactivate a user (#7757) 2020-12-02 15:33:11 +01:00
Philip Allgaier 9ca84e0694 Ensure "false" is set as default for "continue_on_timeout" (#7862) 2020-12-02 15:22:17 +01:00
Philip Allgaier daaf2b1796 Ensure push notification description reacts to language change (#7856) 2020-12-02 12:11:47 +01:00
Bram Kragten 25f7cbea5a Add target selector (#7864)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2020-12-02 12:10:31 +01:00
Josh McCarty c485ea9d7b Add number formatting to counter entity state display (#7868) 2020-12-02 11:51:56 +01:00
HomeAssistant Azure 295390c8e9 [ci skip] Translation update 2020-12-02 00:32:30 +00:00
Bram Kragten 3ebf816ce2 Fix height of ha-icon-input (#7767) 2020-12-01 22:51:15 +01:00
HomeAssistant Azure 0e362b851b [ci skip] Translation update 2020-12-01 00:32:47 +00:00
David F. Mulcahey 8d7ba19a08 Add ZHA fab for adding device when filtered by ZHA (#7848) 2020-11-30 11:05:54 +01:00
Paulus Schoutsen 08f4aa9d10 Use balloons as default pic for header. (#7850) 2020-11-30 10:59:04 +01:00
HomeAssistant Azure 98175d5c72 [ci skip] Translation update 2020-11-30 00:32:50 +00:00
Ian Richardson 7d4cad90bc Show attribute value when 0 (#7842)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-11-29 22:37:13 +01:00
David F. Mulcahey 335354d962 Enhance ZHA device pairing feedback (#7843)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-11-29 22:33:46 +01:00
Bram Kragten fe31d15d27 Add UI for setting an area on entity level (#7837) 2020-11-29 22:00:51 +01:00
Marc Randolph 7ceb6eb50d Apply existing theme variables to unthemed items (#7844) 2020-11-29 16:13:55 +01:00
HomeAssistant Azure 4c4db46aa8 [ci skip] Translation update 2020-11-29 00:32:38 +00:00
Bram Kragten b5724ed343 Make fab blue (#7839) 2020-11-28 17:22:42 +01:00
HomeAssistant Azure cae94175fe [ci skip] Translation update 2020-11-28 00:32:35 +00:00
Kendell R 0494a9d410 Update skeleton height for compact header (#7827)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-11-27 19:23:41 +01:00
Philip Allgaier c261b5c1ce Display HA username + flags in user config (#7705) 2020-11-27 09:41:47 +01:00
HomeAssistant Azure c89e17ac00 [ci skip] Translation update 2020-11-27 00:32:35 +00:00
Bram Kragten 50e7410002 Merge pull request #7833 from home-assistant/dev 2020-11-27 00:16:56 +01:00
Bram Kragten c5b0ebf76d Update ha-config-dashboard.ts 2020-11-27 00:01:34 +01:00
Bram Kragten 1d08978d6c Merge branch 'master' into dev 2020-11-26 23:59:34 +01:00
Bram Kragten fc78b6c933 Bumped version to 20201126.0 2020-11-26 23:58:13 +01:00
Philip Allgaier 480a5718fc Remove unusable Polymer mixin from LitElement (vacuum entity row) (#7831) 2020-11-26 23:57:37 +01:00
David F. Mulcahey f093bd115c Add network visualization to the ZHA config panel (#7802)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-11-26 23:56:50 +01:00
David F. Mulcahey 8a86beff14 Remove unused ZHA translations and fix ZHA fab labels (#7832) 2020-11-26 23:56:22 +01:00
Philip Allgaier 6020890384 Add state-info ellipsis + fix height (#7740) 2020-11-26 23:54:30 +01:00
Philip Allgaier 124aa947e2 Show pointer cursor for input + scene entity rows (#7830) 2020-11-26 20:32:15 +01:00
Bram Kragten e1add14453 Add UI for new selectors (#7822) 2020-11-26 18:38:01 +01:00
Philip Allgaier e3293837a8 Blueprints: Added missing labels & tooltips, optimize input display + text tweaks (#7748) 2020-11-26 18:14:57 +01:00
HomeAssistant Azure 5cb2743780 [ci skip] Translation update 2020-11-26 00:32:25 +00:00
Joakim Sørensen 6f0c79ec25 Introduce supervisor object (#7800)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-11-25 18:22:05 +01:00
Paulus Schoutsen 7de7d1d926 Fix init page message color (#7780)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-11-25 15:22:22 +01:00
Bram Kragten 89175f8e85 Add description and device class (#7816)
https://github.com/home-assistant/core/pull/43321
2020-11-25 15:10:08 +01:00
Paulus Schoutsen fc48c59eb0 Clean up some types (#7801)
Co-authored-by: Zack Barett <arnett.zackary@gmail.com>
2020-11-25 12:31:51 +01:00
Paulus Schoutsen 51332bc7e7 Add frontend url (#7797) 2020-11-25 12:26:11 +01:00
Josh McCarty 7403405d12 Additional number formatting (#7763) 2020-11-25 11:37:58 +01:00
Paulus Schoutsen 1d13947e71 Use Record type (#7798) 2020-11-25 10:40:32 +01:00
HomeAssistant Azure f6cb1ffe20 [ci skip] Translation update 2020-11-25 00:32:19 +00:00
Paulus Schoutsen 6d92b5651a Bump @web/dev-server (#7792) 2020-11-24 12:04:22 +01:00
Bram Kragten 3ea5bb2a6c Fix filtering hidden columns entity table (#7786) 2020-11-24 12:03:06 +01:00
Joakim Sørensen 1d367eca69 Add ignored job_conditions to list of unsupported reasons (#7790) 2020-11-24 11:48:19 +01:00
HomeAssistant Azure d4bf3a2ec3 [ci skip] Translation update 2020-11-24 00:32:27 +00:00
Joakim Sørensen 0ef8881660 Add unhealthy dialog and SU restart button (#7781) 2020-11-23 17:24:26 +01:00
Joakim Sørensen d7d1121f7d Force enable interface if configured (#7785) 2020-11-23 17:22:23 +01:00
Joakim Sørensen 7f089c309f Change order and wording snapshot actions (#7677)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-11-23 17:08:10 +01:00
Philip Allgaier 4dcc0bb66c Reduce "wasted" screen space (#7655) 2020-11-23 13:44:47 +01:00
Paulus Schoutsen 0049be7feb Allow developing with @web/dev-server (#7782) 2020-11-23 13:05:18 +01:00
Paulus Schoutsen 39ff641be9 Close webpack compiler on prod build (#7779)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-11-23 12:48:21 +01:00
Paulus Schoutsen e2fed24995 Clean up node-vibrant (#7777) 2020-11-23 12:47:47 +01:00
Philip Allgaier c0aa353f83 Load missing component titles for ha-related-items (#7771) 2020-11-23 10:48:32 +01:00
Ian Richardson d8521be63d use correct condition for display of tilt controls (#7769)
Co-authored-by: Philip Allgaier <philip.allgaier@gmx.de>
2020-11-23 10:45:53 +01:00
Paulus Schoutsen 6d4569c89d Drop webpackChunkName (#7778) 2020-11-23 10:39:40 +01:00
Paulus Schoutsen cd07553b59 Upgrade Rollup babel plugin (#7773) 2020-11-23 10:21:45 +01:00
HomeAssistant Azure 641bfcc9f7 [ci skip] Translation update 2020-11-23 00:32:47 +00:00
HomeAssistant Azure 6c01371958 [ci skip] Translation update 2020-11-22 00:33:21 +00:00
Paulus Schoutsen 7b00260b1a Remove duplicate translation key (#7766) 2020-11-21 23:33:19 +01:00
Paulus Schoutsen 875142373e Remove unused files and automate translation fragments (#7764) 2020-11-21 22:44:44 +01:00
Philip Allgaier ba505b15ef Ensure new grid card options don't break editor (#7762) 2020-11-21 21:40:27 +01:00
Donnie 17d227b142 Stop appending 'Configuration' to the end of every config page in navigation commands. Fix spinner regression (#7753) 2020-11-21 08:31:40 -08:00
Philip Allgaier e7e192ffe3 Align gallery code + fix icon in entity-icon demo (#7754) 2020-11-21 14:28:25 +01:00
Philip Allgaier c53ec6e12d Ensure more consistent lovelace config errors (#7755) 2020-11-21 14:08:43 +01:00
Philip Allgaier aad6492a6a Show error if no entity specified for history card (#7752) 2020-11-21 13:50:56 +01:00
HomeAssistant Azure fd5b125c2d [ci skip] Translation update 2020-11-21 00:32:15 +00:00
Paulus Schoutsen 5acee76c70 Show validation errors in UI (#7725) 2020-11-20 15:37:56 +01:00
Ian Richardson 10916fa82a Convert ha-relative-time to TypeScript/LitElement (#7709)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-11-20 15:17:34 +01:00
Bram Kragten f69951a523 Fix automation editor (#7746) 2020-11-20 15:16:27 +01:00
Philip Allgaier 38ba85e89d Make gallery config visible in dark mode + fix config alignment (#7741) 2020-11-20 15:13:19 +01:00
Patrick Decat 97023921b8 Add missing "gate" cover device_class (#7744) 2020-11-20 15:10:25 +01:00
Bram Kragten f835810f0a Add entity and device selectors (#7735) 2020-11-20 13:26:03 +01:00
HomeAssistant Azure 46f5589530 [ci skip] Translation update 2020-11-20 00:32:27 +00:00
Thomas Lovén ff9840c8ef Use mwc-tabs in conditional card editor (#7716) 2020-11-19 23:06:06 +01:00
Philip Allgaier 0c197558a1 Close notification drawer when last entry is dismissed (#7724) 2020-11-19 22:53:21 +01:00
Joakim Sørensen c409ba149d Supervisor network changes (#7676) 2020-11-19 22:51:29 +01:00
Joakim Sørensen 0b896ddfb1 Check snapshot size before upload (#7733) 2020-11-19 22:49:29 +01:00
Philip Allgaier 45721eb4fe Adjust FAB for blueprint overview + align translations (#7730) 2020-11-19 22:48:34 +01:00
Bram Kragten 1289bd03b2 Remove conference banner (#7731) 2020-11-19 10:46:52 +01:00
HomeAssistant Azure c1ba8ba6b8 [ci skip] Translation update 2020-11-19 00:32:32 +00:00
Bram Kragten 4973d8f629 WIP initial Blueprint UI (#7695)
* WIP initial Blueprint UI

* Review comments

* localize
2020-11-18 12:19:59 +01:00
Philip Allgaier 3aff4c96c4 Add Georgian language (Kartuli) (#7721) 2020-11-18 10:39:35 +01:00
Paulus Schoutsen 4005bc8985 Clarify title 2020-11-18 08:46:42 +00:00
Paulus Schoutsen 62e9792c39 Add note about building the frontend 2020-11-18 08:44:45 +00:00
HomeAssistant Azure 33183cc595 [ci skip] Translation update 2020-11-18 00:32:28 +00:00
Josh McCarty 394d552856 Use ha-dialog for dialog-system-log-details, add close icon button (#7513) 2020-11-17 22:29:20 +01:00
Bram Kragten aa4f0929e0 Bumped version to 20201111.2 2020-11-17 22:24:30 +01:00
Thomas Lovén f99b9215e3 Fix date picker row alignment (#7704) 2020-11-17 22:23:21 +01:00
Paulus Schoutsen c51d621fee Allow dismissing (#7712) 2020-11-17 22:22:39 +01:00
Paulus Schoutsen 7499892bc2 Don't support safari 10 in minifaction for latest support (#7719) 2020-11-17 22:00:28 +01:00
Paulus Schoutsen cbddebeaa8 Allow dismissing (#7712) 2020-11-17 16:14:37 +01:00
Philip Allgaier bbe4c95109 Display entity ID for read-only entities (#7690) 2020-11-17 16:08:47 +01:00
Philip Allgaier 4c6f9f0dd8 Fix empty entity pickers for "Time" trigger and condition (#7689) 2020-11-17 15:51:18 +01:00
Philip Allgaier 90f7dba793 Use proper night time icon consistently for sun integration (#7681) 2020-11-17 15:48:54 +01:00
Philip Allgaier 7c492338a2 Improve gallery hui-gauge-card (#7682) 2020-11-17 15:46:33 +01:00
Philip Allgaier 530f494df8 Improve gallery hui-light-card (#7684) 2020-11-17 15:46:00 +01:00
Joakim Sørensen 8fd1f35c59 Move data_entry_flow_progressed event subscriber (#7700) 2020-11-17 15:12:45 +01:00
Joakim Sørensen af1518e924 Use stepid title if present for progress flow (#7710) 2020-11-17 14:33:13 +01:00
Thomas Lovén 473e381d75 Fix date picker row alignment (#7704) 2020-11-17 09:43:25 +01:00
Paulus Schoutsen 7d3acc747d Guard passing invalid tag to customElements.whenDefined (#7696) 2020-11-17 09:40:35 +01:00
HomeAssistant Azure bf7424a67c [ci skip] Translation update 2020-11-17 00:32:25 +00:00
Bram Kragten 3fb35871c7 Bumped version to 20201111.1 2020-11-16 22:02:28 +01:00
Donnie d6d20cd704 Quick Bar should only capitalize letters in Command Palette (#7671) 2020-11-16 22:02:02 +01:00
Bram Kragten 9cc6a6b885 Fix number format in state-card-display (#7703) 2020-11-16 22:01:48 +01:00
Philip Allgaier ee0be7b6d0 Add missing 1px to prevent slider pin cutoff (#7657) 2020-11-16 22:01:32 +01:00
Joakim Sørensen a856337eae Devcontainer (#7697)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2020-11-16 16:53:47 +01:00
Bram Kragten 6cf47ba4eb Fix number format in state-card-display (#7703) 2020-11-16 12:45:52 +01:00
Donnie 3b7a189708 Quick Bar should only capitalize letters in Command Palette (#7671) 2020-11-16 12:45:20 +01:00
Philip Allgaier 79c542b76a Add missing 1px to prevent slider pin cutoff (#7657) 2020-11-16 12:44:58 +01:00
Paulus Schoutsen e37b7bd73f Cleanup (#7702) 2020-11-16 11:43:25 +01:00
HomeAssistant Azure d6f3c34b33 [ci skip] Translation update 2020-11-16 00:32:42 +00:00
Paulus Schoutsen bc5cb46e7d Add missing outFiles 2020-11-15 15:37:43 +00:00
Paulus Schoutsen c7b747c4fa Add debug launch conf for VS Code (#7683) 2020-11-15 16:36:48 +01:00
HomeAssistant Azure d3c51d7acd [ci skip] Translation update 2020-11-15 00:32:20 +00:00
HomeAssistant Azure b6881d797c [ci skip] Translation update 2020-11-14 00:32:35 +00:00
Joakim Sørensen b9f802939c Add a github option when copying from system health (#7663)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-11-13 18:20:24 +01:00
HomeAssistant Azure 6558c2c065 [ci skip] Translation update 2020-11-13 00:32:24 +00:00
Ian Richardson 37a089c868 Convert ha-cover-controls to TypeScript/LitElement (#7521)
Co-authored-by: Zack Barett <zackbarett@hey.com>
2020-11-12 15:29:16 +01:00
Ian Richardson f68eff6bb3 Fix state-info icon color and convert to TypeScript/LitElement (#7664) 2020-11-12 15:06:45 +01:00
HomeAssistant Azure 88a525f1a7 [ci skip] Translation update 2020-11-12 00:32:16 +00:00
Bram Kragten 7e6153ba7d Merge pull request #7654 from home-assistant/dev 2020-11-11 15:40:04 +01:00
Bram Kragten 34fddd5940 Merge error 2020-11-11 15:27:33 +01:00
Bram Kragten 0e5d6fe8d8 Merge branch 'master' into dev 2020-11-11 15:26:26 +01:00
Bram Kragten e1342a0d9d Bumped version to 20201111.0 2020-11-11 15:17:21 +01:00
Joakim Sørensen 0cc2d3aaa7 Check for integration before loading logo (#7653) 2020-11-11 15:16:52 +01:00
Bram Kragten 67814505b3 Fix areas devices picker (#7652) 2020-11-11 14:59:26 +01:00
Bram Kragten bae29c6d62 Move last changed / last updated out of state table (#7649) 2020-11-11 14:42:27 +01:00
Bram Kragten a0e67d4c03 Fix fabs (#7650) 2020-11-11 14:13:40 +01:00
Bram Kragten 131bc5fbf7 Fix pin of labeled slider cutoff (#7651) 2020-11-11 14:12:49 +01:00
Bram Kragten 051218e29b Fix view height in edit mode (#7646) 2020-11-11 14:08:53 +01:00
Philip Allgaier 6ace8307d8 Always show "off" button if supported by player (#7389) 2020-11-11 14:00:53 +01:00
Bram Kragten e84bef44b7 Guard for undefined hass (#7647) 2020-11-11 13:55:45 +01:00
Bram Kragten 3186d762f2 Fix height of tabs subpage (#7648) 2020-11-11 13:10:07 +01:00
Bram Kragten c97a3b0a56 Fixes for logbook card (#7645) 2020-11-11 13:08:03 +01:00
Zack Barett 78f1bb3b91 Logbook Card (#6976) 2020-11-11 11:49:56 +01:00
Joakim Sørensen 67707fbc90 Don't block system_health if one value is null (#7644) 2020-11-11 11:49:10 +01:00
Donnie 2a57ffa615 Add navigation commands to quick bar commands (#7380)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-11-11 11:46:53 +01:00
Ryan Meek 216fce74f8 Header/sidebar sizing (#7470)
Co-authored-by: Zack Barett <zackbarett@hey.com>
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-11-11 10:47:06 +01:00
HomeAssistant Azure 6cd3e6652a [ci skip] Translation update 2020-11-11 00:33:03 +00:00
Paulus Schoutsen fe7d79cee6 Load system health translations from backend (#7643) 2020-11-10 23:44:59 +01:00
Nico Hirsch 2f4e7b388b Add dialog backdrop blur theme variable (#7635)
* Add dialog backdrop blur theme var

* Update src/components/ha-dialog.ts

Co-authored-by: Bram Kragten <mail@bramkragten.nl>

* Add backdrop-filter to iron-overlay-backdrop

* Revert change from opacity to rgba

* Add comment "for paper-dialog"

Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-11-10 18:01:33 +01:00
kg333 2e289cd152 Add fix to more-info for media players without play/pause state (#7608)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-11-10 18:00:44 +01:00
Sören Beye 21a3dcf06c Further brands-url cleanup (#7640) 2020-11-10 17:59:48 +01:00
Philip Allgaier 7f56add914 Show user friendly attribute names in picker (#7337)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-11-10 15:25:53 +01:00
Sören Beye 88701c6167 Refactor brands url to single location (#7613) 2020-11-10 15:25:06 +01:00
uvjustin e4ce6117a1 Get regular playlist url properly in ha-hls-player (#7417) 2020-11-10 14:41:14 +01:00
Josh McCarty cec2a61bdf Use ha-dialog for device-registry-details-dialog (#7500) 2020-11-10 12:22:32 +01:00
Philip Allgaier 8275ac5853 Ensure "next" and "prev" buttons always have ARIA label (#7588)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-11-10 11:39:09 +01:00
Philip Allgaier b7bcf97365 Minor visual QB command tweaks (#7590) 2020-11-10 11:38:44 +01:00
Nathan Orick fa28b480f1 Add button to duplicate script (#7511)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-11-10 10:16:42 +01:00
HomeAssistant Azure 4bb95b7396 [ci skip] Translation update 2020-11-10 00:32:22 +00:00
Philip Allgaier 5a9bd73e8b Use clearer dialog button texts + various translation improvements (#7584) 2020-11-09 23:41:22 +01:00
Thomas Lovén 4fe0276914 Replace date picker for entities card (#6899) 2020-11-09 23:27:21 +01:00
Kendell R 5e8bda55b4 Make PR template more discussion-friendly (#7622) 2020-11-09 23:05:44 +01:00
Joakim Sørensen d09c4898c1 Remove logs and fix dark theme during onboarding restore (#7579) 2020-11-09 22:50:16 +01:00
Joakim Sørensen 6ae67ed299 Add flow for "progress" step (#7592) 2020-11-09 22:45:37 +01:00
Zack Barett 32ff166a74 Entities Card: Add Header & Footer Editor (#6751) 2020-11-09 22:41:59 +01:00
Paulus Schoutsen 8feae04281 Add link to conference (#7636) 2020-11-09 22:41:05 +01:00
Erik Montnemery 129f9c147b Improve user experience when enabling a disabled entity (#7580) 2020-11-09 19:48:24 +01:00
Ian Richardson 6e336dd207 convert ha-cover-tilt-controls to TypeScript/LitElement (#7542) 2020-11-09 18:26:05 +01:00
Paulus Schoutsen 161561c48a Support system health streaming (#7593) 2020-11-09 16:11:01 +01:00
Franck Nijhof c162e84383 Replace lock bot with GitHub Action (#7633) 2020-11-09 12:49:42 +01:00
Franck Nijhof dc8d80a6e5 Replace stale bot with GitHub Action (#7634) 2020-11-09 12:46:19 +01:00
HomeAssistant Azure 293f67968c [ci skip] Translation update 2020-11-09 00:32:31 +00:00
HomeAssistant Azure 4dcf26236e [ci skip] Translation update 2020-11-08 00:32:28 +00:00
Philip Allgaier a0e8d69243 Add "www" to generated tag QR code (#7577)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-11-07 17:27:57 +01:00
Philip Allgaier 33cd9bf516 Ensure all <mwc-fab> set a label for ARIA (#7587) 2020-11-07 17:27:34 +01:00
HomeAssistant Azure 0132797f2f [ci skip] Translation update 2020-11-07 00:32:20 +00:00
Paulus Schoutsen 7e2db0aa4e Add ingress session validation (#7610) 2020-11-06 23:01:29 +01:00
HomeAssistant Azure cc1d50491b [ci skip] Translation update 2020-11-06 00:32:18 +00:00
Adam Ernst 461b86a04b Fix race condition in translation loading (#7597) 2020-11-05 18:47:09 +01:00
Ian Richardson 9a3a7c28f4 Use shopping list card in panel (#7519) 2020-11-05 16:17:42 +01:00
Philip Allgaier 1c9d0200ca Add "last_changed" and "last_updated" to dev tools state view (#7375) 2020-11-05 16:15:50 +01:00
Philip Allgaier 0037cd2e69 Make thingtalk dialogs translatable (#7574) 2020-11-05 16:15:16 +01:00
HomeAssistant Azure 028ae061da [ci skip] Translation update 2020-11-05 00:32:18 +00:00
HomeAssistant Azure 2e47763ecc [ci skip] Translation update 2020-11-04 00:32:29 +00:00
HomeAssistant Azure 924e4a45d0 [ci skip] Translation update 2020-11-03 00:32:27 +00:00
Bram Kragten 8361b9553b Fix polyfill check (#7575) 2020-11-02 22:06:49 +01:00
Zack Barett e52be20fba Grid Card: Fix Card Picker (#7562)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-11-02 10:47:24 +01:00
Bram Kragten da12233ade Add dark mode toggle to gallery cards (#7532) 2020-11-02 10:46:52 +01:00
HomeAssistant Azure 57500f6c97 [ci skip] Translation update 2020-11-02 00:32:22 +00:00
Ryan Meek 199e17d0b1 Use paper-tabs while in edit mode (#7563)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-11-01 22:04:52 +01:00
Ryan Meek 3b91343082 Dark mode header color (#7514)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-11-01 22:04:27 +01:00
HomeAssistant Azure 1753c9163c [ci skip] Translation update 2020-11-01 00:32:29 +00:00
HomeAssistant Azure 89e5953e89 [ci skip] Translation update 2020-10-31 00:33:15 +00:00
Ian Richardson 5bfd25c8c6 Convert ha-climate-state to TypeScript/LitElement (#7544)
Co-authored-by: Zack Barett <zackbarett@hey.com>
2020-10-30 17:04:13 -05:00
Zack Barett e555b24f50 Calendar: Adds an Update Size and Makes list view start today and adds in local for first day of week (#7541) 2020-10-30 17:03:02 -05:00
Josh McCarty 14db37459f Formats number state with selected language in compute_state_display (#7516) 2020-10-30 22:58:52 +01:00
Zack Barett 1d9779d47c Calendar Panel: Persist Calendars in Local Storage (#7540) 2020-10-30 11:28:19 -05:00
Rob McCann 3dedbc5457 Remove minification from translations to reduce build time by 1.5mins (#7552) 2020-10-30 15:36:52 +01:00
Zack Barett facb3266c6 Media Browser: Fix error handling (#7538) 2020-10-30 14:55:30 +01:00
Thomas Lovén 01fe5dd2f7 Make sure rebuilt cards show up in panel views (#7535) 2020-10-30 14:48:39 +01:00
dklemm 9b22b1e499 Resolve #7533 Broken styling on stack card titles (#7534) 2020-10-30 14:47:09 +01:00
Ian Richardson 4bc8818145 Remove ha-state-icon (#7545) 2020-10-30 14:45:51 +01:00
Paulus Schoutsen 48ef8c86c2 Add unavailable entity to gauge demo (#7530) 2020-10-30 14:30:27 +01:00
Zack Barett 89f359a52f Calendar: Fix background to match ha-card (#7539) 2020-10-30 14:28:51 +01:00
HomeAssistant Azure 13b8160d74 [ci skip] Translation update 2020-10-30 00:32:19 +00:00
Paulus Schoutsen f1c16d6674 Mock subscribe template (#7529) 2020-10-29 21:28:41 +01:00
Paulus Schoutsen 76a088e177 Only show header toggle for entities card if title (#7525) 2020-10-29 21:28:34 +01:00
Philip Allgaier 630d8c3bb6 Add last-updated to state info tooltip (#7445) 2020-10-29 20:08:44 +01:00
Bram Kragten 744efa30f2 Bumped version to 20201021.4 2020-10-29 18:33:22 +01:00
Erik Montnemery bf4a94dc48 Add MQTT as ignorable discovery flow (#7527) 2020-10-29 18:32:19 +01:00
Bram Kragten ce4ba2f6f1 Fix tooltip creating scrollbar history card (#7528) 2020-10-29 18:31:52 +01:00
Paulus Schoutsen 5b232b5d35 Fix glance card with header if parent does not set block (#7526) 2020-10-29 18:31:36 +01:00
Donnie 35151bbac7 Fix issue with toggles blocking dialog and dialog launching on mobile (#7506)
* Fix issue with some inputs blocking, or incorrectly allowing, keyboard shortcut activation

* Explicitly declare all input types that we can allow alphanumeric overrides

* Do not launch dialog in codemirror targets on mobile devices
2020-10-29 18:31:21 +01:00
Erik Montnemery f0e959319e Add MQTT as ignorable discovery flow (#7527) 2020-10-29 18:30:20 +01:00
Bram Kragten d0c4475724 Fix tooltip creating scrollbar history card (#7528) 2020-10-29 18:29:54 +01:00
Paulus Schoutsen 99935f1e59 Fix glance card with header if parent does not set block (#7526) 2020-10-29 18:29:20 +01:00
Paulus Schoutsen fbb43821ba Add grid card to the gallery (#7524) 2020-10-29 17:56:26 +01:00
Donnie c7f5c6c1d1 Fix issue with toggles blocking dialog and dialog launching on mobile (#7506)
* Fix issue with some inputs blocking, or incorrectly allowing, keyboard shortcut activation

* Explicitly declare all input types that we can allow alphanumeric overrides

* Do not launch dialog in codemirror targets on mobile devices
2020-10-29 09:18:47 -07:00
Paulus Schoutsen d26f1fa371 Fix grid card size when square (#7520) 2020-10-29 14:21:49 +01:00
Paulus Schoutsen c3718ff7dd Add Grid card (#7476) 2020-10-29 10:31:14 +01:00
HomeAssistant Azure d63493a859 [ci skip] Translation update 2020-10-29 00:32:17 +00:00
Josh McCarty a72183851a Use ha-dialog for dialog-area-registry-detail (#7508) 2020-10-28 16:00:39 +01:00
Nathan Orick 40b2387667 Allow pressing return to submit on area dialog (#7509) 2020-10-28 15:57:01 +01:00
HomeAssistant Azure d814aa36a7 [ci skip] Translation update 2020-10-28 00:32:29 +00:00
Philip Allgaier e37eebe4ad Get rid of the unwanted tooltip copying (final) (#7459) 2020-10-27 20:22:06 +01:00
Philip Allgaier 0baaaefdf8 Get rid of the unwanted tooltip copying (#7408) 2020-10-27 20:22:04 +01:00
Philip Allgaier 58a58906e7 Get rid of the unwanted tooltip copying (final) (#7459) 2020-10-27 20:20:15 +01:00
Bram Kragten bec0d9b00e Bumped version to 20201021.3 2020-10-27 20:18:52 +01:00
Donnie e6a4ab789b Add server restart/stop to quick bar command list (#7488) 2020-10-27 20:18:41 +01:00
Donnie 36c1d3230c Change Quick Bar shortcuts to "e" and "c" (#7496)
* Add toggle for disabling quick bar shortcuts

* Change shortcut from Ctrl+P and Ctrl+Shift+P to qe and qc (Quick Entity, Quick Command)

* Remove accidentally included code

* Use tinykeys for handling shortcuts

* Change shortcuts to e and c. And fix small typo.

* Change copy for toggle

* Rename hass property to be for generic shortcuts

* Minor tweaks to address review comments
2020-10-27 20:18:18 +01:00
Donnie 30466ec3fe Add toggle for disabling quick bar shortcuts (#7495)
* Add toggle for disabling quick bar shortcuts

* Remove accidentally included code

* Change copy for toggle

* Rename hass property to be for generic shortcuts
2020-10-27 20:17:53 +01:00
Thomas Lovén ce414a5ca9 Correctly replace rebuilt badges in view (#7487) 2020-10-27 20:17:34 +01:00
Ryan Meek e4e6edd573 Fix lovelace background color (#7478) 2020-10-27 20:17:18 +01:00
Erik Montnemery 79927f4dc9 Update translation for MQTT reload (#7475) 2020-10-27 20:17:02 +01:00
Ryan Meek 603b833757 fix edit mode mwc-button size (#7472) 2020-10-27 20:16:42 +01:00
Donnie ba99d1a10d Add server restart/stop to quick bar command list (#7488) 2020-10-27 20:14:25 +01:00
Donnie efe97e8f51 Refactor sidebar renders into methods (prep for mwc-list conversion) (#7453) 2020-10-27 20:12:30 +01:00
Donnie 5ec23bb7ab Change Quick Bar shortcuts to "e" and "c" (#7496)
* Add toggle for disabling quick bar shortcuts

* Change shortcut from Ctrl+P and Ctrl+Shift+P to qe and qc (Quick Entity, Quick Command)

* Remove accidentally included code

* Use tinykeys for handling shortcuts

* Change shortcuts to e and c. And fix small typo.

* Change copy for toggle

* Rename hass property to be for generic shortcuts

* Minor tweaks to address review comments
2020-10-27 10:34:51 -07:00
Donnie 9b4d01ab75 Add toggle for disabling quick bar shortcuts (#7495)
* Add toggle for disabling quick bar shortcuts

* Remove accidentally included code

* Change copy for toggle

* Rename hass property to be for generic shortcuts
2020-10-27 10:00:46 -07:00
Nathan Orick 40191a88d4 Allow edit card dialog to be made wider (#7492) 2020-10-27 15:59:32 +01:00
Josh McCarty a19477d179 Migrate ha-paper-dialog to ha-dialog in system options dialog (#7455) 2020-10-27 15:24:52 +01:00
Erik Montnemery bf98a78f3d Add custom device action to remove a Tasmota device (#7469) 2020-10-27 14:04:28 +01:00
Florian Gareis ba4c2fc1bd Replace prompt with showPromptDialog (#7460)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-10-27 14:04:01 +01:00
Charles Garwood b56e9ef028 Add cancel command button to ozw config panel (#7471) 2020-10-27 14:00:21 +01:00
Philip Allgaier dbbd34c520 Allow breaking of entity ID in history tooltip into multiple lines (#7482) 2020-10-27 11:14:47 +01:00
J. Nick Koston ccb69dbdfa Add icons for shade device class (#7493)
The blinds material icon looks more like a shade
then a blind but since its already being used
blind its still better than having it look like
a window.
2020-10-26 20:43:22 -05:00
HomeAssistant Azure 11e555ef6f [ci skip] Translation update 2020-10-27 00:32:18 +00:00
Thomas Lovén 61e17395c9 Correctly replace rebuilt badges in view (#7487) 2020-10-26 20:55:47 +01:00
Ryan Meek 733ce3b6b8 Fix lovelace background color (#7478) 2020-10-26 09:42:57 +01:00
Erik Montnemery 375f143199 Update translation for MQTT reload (#7475) 2020-10-26 09:41:43 +01:00
HomeAssistant Azure 2419f35eb9 [ci skip] Translation update 2020-10-26 00:32:40 +00:00
HomeAssistant Azure 21867c3576 [ci skip] Translation update 2020-10-25 00:32:37 +00:00
J. Nick Koston 28853b28bc Show cover attributes on the more-info card (#7458) 2020-10-24 08:26:18 -05:00
HomeAssistant Azure e2f27568a5 [ci skip] Translation update 2020-10-24 00:32:12 +00:00
Ryan Meek 98b2b796b0 fix edit mode mwc-button size (#7472) 2020-10-24 00:53:11 +02:00
Philip Allgaier b8f3fcf00b Allow discovered integration titles to line wrap (#7468) 2020-10-23 16:43:20 +02:00
Philip Allgaier d3fda9a821 Ensure attribute values are consistently right aligned (#7466) 2020-10-23 16:29:27 +02:00
HomeAssistant Azure 19e69dc13e [ci skip] Translation update 2020-10-23 00:32:22 +00:00
Bram Kragten 48543a2dad Bumped version to 20201021.2 2020-10-23 00:18:49 +02:00
Philip Allgaier b22f5ae5c2 Add outline color for dark buttons (#7444) 2020-10-23 00:18:26 +02:00
J. Nick Koston 2acb6a28fe Update template time listener phrasing for core changes (#7450) 2020-10-23 00:16:40 +02:00
Donnie 1064cdb79d Fix quick bar dark mode contrast, filter returning all items, no primary text (#7430)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-10-23 00:16:18 +02:00
Bram Kragten bd7cb1c877 Template dev tools: Print the type of the response and stringify objects (#7439) 2020-10-23 00:15:57 +02:00
Bram Kragten 6c314982dc Pass narrow to masonry view to calc columns (#7454) 2020-10-23 00:15:36 +02:00
Philip Allgaier d54710f113 Fix capitalization of state attributes (#7448) 2020-10-23 00:15:20 +02:00
J. Nick Koston 1346156ecd Avoid fetching logbook data instead in addition to not displaying it (#7427)
Co-authored-by: Zack Barett <zackbarett@hey.com>
2020-10-23 00:15:04 +02:00
Bram Kragten a2d9f9b417 Fix ES5 build, fix virtualizer polyfill (#7451) 2020-10-23 00:14:48 +02:00
Bram Kragten 3de78cca2d Fix quickbar debounce (#7426)
* Fix quicbar debounce

* Clear search property when dialog is closed

Co-authored-by: Donnie <donniekarnsinsb@hotmail.com>
2020-10-23 00:14:28 +02:00
J. Nick Koston 5fa7cd9fa9 Update template time listener phrasing for core changes (#7450) 2020-10-23 00:10:51 +02:00
Donnie a78c00fb41 Fix quick bar dark mode contrast, filter returning all items, no primary text (#7430)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-10-23 00:06:36 +02:00
Philip Allgaier edc2a03d1c Get rid of the unwanted tooltip copying (#7408) 2020-10-22 23:57:52 +02:00
Bram Kragten 174f8f5823 Template dev tools: Print the type of the response and stringify objects (#7439) 2020-10-22 23:51:33 +02:00
Bram Kragten 9fbc94e8d8 Pass narrow to masonry view to calc columns (#7454) 2020-10-22 23:29:26 +02:00
Philip Allgaier 6aff35196d Fix capitalization of state attributes (#7448) 2020-10-22 23:13:36 +02:00
J. Nick Koston eceed4ed74 Avoid fetching logbook data instead in addition to not displaying it (#7427)
Co-authored-by: Zack Barett <zackbarett@hey.com>
2020-10-22 22:47:19 +02:00
Bram Kragten 7428731eac Fix ES5 build, fix virtualizer polyfill (#7451) 2020-10-22 22:43:15 +02:00
Philip Allgaier 89b07ea0ae Add outline color for dark buttons (#7444) 2020-10-22 16:24:12 +02:00
Ian Richardson d16daf0fd9 Add last-updated as a secondaryinfo option to entity rows (#7433) 2020-10-22 12:37:51 +02:00
Bram Kragten 211ab4eea8 Fix quickbar debounce (#7426)
* Fix quicbar debounce

* Clear search property when dialog is closed

Co-authored-by: Donnie <donniekarnsinsb@hotmail.com>
2020-10-22 11:00:36 +02:00
HomeAssistant Azure dbd53f8d14 [ci skip] Translation update 2020-10-22 00:32:19 +00:00
Bram Kragten a27680b8c0 Merge pull request #7424 from home-assistant/dev 2020-10-21 23:43:52 +02:00
Bram Kragten 07fc9b98cc Bump webpack (#7423) 2020-10-21 23:39:05 +02:00
Bram Kragten 33582c0448 Bumped version to 20201021.1 2020-10-21 23:35:57 +02:00
Bram Kragten 73be0fef75 Merge pull request #7422 from home-assistant/dev
20201021.0
2020-10-21 19:21:45 +02:00
Bram Kragten 611202c905 Fix no focus on first item when switching mode (#7421) 2020-10-21 18:50:08 +02:00
Bram Kragten e553f35a68 Merge branch 'master' into dev 2020-10-21 18:41:18 +02:00
Bram Kragten 673649a603 Bumped version to 20201021.0 2020-10-21 18:36:59 +02:00
Bram Kragten c4ed743370 Fix mwc list items icon color (#7420) 2020-10-21 18:21:58 +02:00
Joakim Sørensen 682fa0d3eb Haos update button (#7419) 2020-10-21 10:30:41 -05:00
On Freund 30f34eee22 Add context to event trigger (#7182)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-10-21 17:26:45 +02:00
Bram Kragten eab76bf85b Fix position edit card dialog (#7418) 2020-10-21 15:26:08 +02:00
Donnie bcf405bf9d Fix Firefox quick bar issue by allowing Ctrl+P to toggle modes (#7413)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-10-21 14:19:16 +02:00
Ryan Meek 3c4b0d4a74 Compact header (#7369)
Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-10-21 14:18:33 +02:00
Zack Barett fb9bd0eb7d Fix prettier that keeps messing with merging dev (#7412) 2020-10-21 13:14:10 +02:00
Ian Richardson 7e2dc04123 Fix icon for unavailable buttons (#7416) 2020-10-21 13:12:28 +02:00
Bram Kragten 54ec37994c Improve performance of quick bar (#7359)
Co-authored-by: Donnie <donniekarnsinsb@hotmail.com>
2020-10-21 13:07:44 +02:00
Gilson Marquato Júnior 4a5935ee36 Add onClick listener to dismiss toast notification. (#7268) 2020-10-21 13:03:31 +02:00
Joakim Sørensen 01b9a07320 Change logic for the new version handling (#7405) 2020-10-21 12:40:06 +02:00
Zack Barett 0fcf0dcd18 Fix Yarn lock (#7411) 2020-10-20 19:37:26 -05:00
HomeAssistant Azure 80481f142a [ci skip] Translation update 2020-10-21 00:32:23 +00:00
Philip Allgaier 2be08ce7ab Light hui & more-info card fixes (#7397) 2020-10-20 23:52:10 +02:00
Bram Kragten 37eb5af3d4 Pass updated cards and badges to view element (#7407) 2020-10-20 23:51:15 +02:00
Philip Allgaier 8c8151be92 Add entity filter to history panel (#7401) 2020-10-20 23:02:59 +02:00
Philip Allgaier baf31d1c1e Fix alignments in integration card (#7404) 2020-10-20 22:59:20 +02:00
Donnie af2250835a Only admins can launch quick bar (#7388)
Co-authored-by: Zack Barett <zackbarett@hey.com>
2020-10-20 22:24:48 +02:00
Donnie 6f2a759ba3 Add scoring and sorting to sequence matcher (#7367)
* Replace sequence matcher with VS Code's score-based implementation

* Remove everything not related to fuzzyScore and matchSubstring

* Fix bug when filter length <= 3

* Add licensing and credit to Microsoft

* Remove unnecessary character codes

* Remove old sequence matcher, update tests, fix issue with not finding best score in list of words

* Remove unnecessary sequence precheck, refactor client api to remove array

* Fix issue with score sorting not implemented correctly and thus not actually sorting by score

* Update src/common/string/filter/sequence-matching.ts

Co-authored-by: Bram Kragten <mail@bramkragten.nl>

* Remove unnecessary string return from fuzzy matcher. Clean up code

* Remove globals from filter. Move sorting logic into matcher

* Update function description, make score property optional.

Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-10-20 09:01:16 -07:00
Jaroslav Hanslík 5065901196 Modified icons of binary sensors: gas, problem, safety, smoke (#7403) 2020-10-20 17:43:01 +02:00
Philip Allgaier 41b59e6e11 Bump round-slider to 0.5.2 (#7399) 2020-10-20 08:58:35 -05:00
onagurna 43afdaadc6 Fix syntax error (#7402) 2020-10-20 15:09:27 +02:00
Tomasz 83c5151792 bump node-vibrant to 3.1.6 (#7400) 2020-10-20 12:42:51 +02:00
HomeAssistant Azure 0880ab67c6 [ci skip] Translation update 2020-10-20 00:32:22 +00:00
Donnie c0b2143c7c Quick Bar dark mode, ignore leading white space (#7387) 2020-10-19 22:10:44 +02:00
Philip Allgaier c1de162c99 Visual alignment between PR 7364 & 7220 (#7396) 2020-10-19 22:09:15 +02:00
Philip Allgaier a7ef8aba68 Add dialog-box warning support (#7356) 2020-10-19 22:08:35 +02:00
Philip Allgaier 3ee4c11a99 Move error log <ha-card> + color in log entries (#7382) 2020-10-19 22:05:19 +02:00
Philip Allgaier 990ae10dc2 Detect Lovelace resource type based on file extension (#7354) 2020-10-19 22:03:59 +02:00
Philip Allgaier 52b2fd046b Improved automation & script menus + show errors in toast (#7371)
* Improved automation & script menus + show errors in toast

* Changes from review

* Re-added old error display

* Toast back to default duration + remove action
2020-10-19 19:55:36 +02:00
J. Nick Koston 9f41f80a91 Add support for displaying time listeners (#7220) 2020-10-19 19:43:04 +02:00
Joakim Sørensen eec4a91ad8 Fixes for snapshot upload during onboarding (#7390)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-10-19 15:24:25 +02:00
Joakim Sørensen 7c51001c3c Move valid so we don't cache an empty element for add-on config (#7394) 2020-10-19 15:23:13 +02:00
Daniel Martin Gonzalez a4ea4b1f5f Add Timer to Helpers (#7366) 2020-10-19 14:45:20 +02:00
Philip Allgaier 19fc37539e Fix alignment / padding of ha-switch (#7349) 2020-10-19 14:44:54 +02:00
Philip Allgaier ce7acb0feb Clean up general config page code (#7383) 2020-10-19 14:40:01 +02:00
Philip Allgaier 105b7678b8 Make error texts of device automation picker translatable (#7370) 2020-10-19 14:30:40 +02:00
Philip Allgaier b67575586e Add option to copy system info into clipboard (#7323) 2020-10-19 14:29:10 +02:00
Ing. Jaroslav Šafka 3dc6898673 Enable volume up/down for media player (#7376)
Always show volume up/down buttons in media player
if SUPPORT_VOLUME_BUTTONS is supported.
And slider if supported

Previous impl. shows slider or up/down buttons.
2020-10-19 11:16:20 +02:00
Philip Allgaier a73754c1b5 Use ha-card for dev tool "Services" + visual tweaks (#7364) 2020-10-19 11:15:12 +02:00
Charles Garwood 1ebf1c00d6 Initial OZW Node Config Panel (#7377) 2020-10-19 11:13:55 +02:00
HomeAssistant Azure 7dac7d757e [ci skip] Translation update 2020-10-19 00:32:45 +00:00
HomeAssistant Azure b1f3192b95 [ci skip] Translation update 2020-10-18 00:32:21 +00:00
Donnie 16984d18bb Refactor quick bar to use a common interface for future commands and easier sorting (#7368) 2020-10-17 15:48:48 -07:00
Philip Allgaier e603893d77 Fix navigation links for "script/edit" (#7363) 2020-10-17 17:28:05 -05:00
Bram Kragten a7998b30c6 Fix hls player (#7362) 2020-10-17 23:43:00 +02:00
Philip Allgaier 3277a4e8c3 Minor tweaks for when media player has no items (#7374) 2020-10-17 23:34:11 +02:00
Philip Allgaier 7e769d0e14 Make <ha-card> use <h1> for header (#7373)
Co-authored-by: Zack Barett <zackbarett@hey.com>
2020-10-17 23:22:56 +02:00
Philip Allgaier 713e0579f8 Entity registry settings: Remove "Override" string + use domain icon as fallback (#7320) 2020-10-17 22:46:34 +02:00
Philip Allgaier 6e130cc020 Properly wrap integration title / device names (#7355) 2020-10-17 22:28:40 +02:00
Villhellm eb036a12d9 add help button to tags config panel (#7278)
* add help button to tags config panel

* Update src/panels/config/tags/ha-config-tags.ts

Co-authored-by: Bram Kragten <mail@bramkragten.nl>

Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-10-17 22:21:03 +02:00
Joakim Sørensen 534d1f5055 Add dialog and links for unsupported supervisor installation (#7332) 2020-10-17 22:18:17 +02:00
Daniel Martin Gonzalez cbef909657 Add Counter to Helpers (#7346)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-10-17 22:15:37 +02:00
Philip Allgaier 874f3b32b3 Harmonize the font sizes on area and device page (#7357) 2020-10-17 22:10:52 +02:00
Bram Kragten 2fd017cf73 Fix more info group (#7345)
Co-authored-by: Zack Barett <arnett.zackary@gmail.com>
2020-10-17 22:05:04 +02:00
Bram Kragten 5740b018a7 Prevent old more info control to be created (#7324) 2020-10-17 22:04:44 +02:00
Tomasz 288bf6805a Sort persistent notifications ascending (#7195)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-10-17 22:03:33 +02:00
HomeAssistant Azure 02d37a369a [ci skip] Translation update 2020-10-17 00:32:29 +00:00
Philip Allgaier 1d316c3258 Remove query caching to get YAML editor toggle working again (#7365) 2020-10-16 23:27:00 +02:00
Joakim Sørensen a56ce62f1a Add docker registry management (#7269)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-10-16 17:25:23 +02:00
Zack Barett c268f42851 Entity Picker: undo fuzzy algorithm (#7360) 2020-10-16 09:45:58 -05:00
HomeAssistant Azure 7251e802ab [ci skip] Translation update 2020-10-16 00:32:27 +00:00
Matt 5b1a2d10c2 Add button that dismisses all notifications (#7223) 2020-10-15 16:22:47 -05:00
Charles Garwood 2dd7f292b1 Add product picture to ozw node dashboard (#7203) 2020-10-15 16:20:54 -05:00
Santobert 213c53e307 Add the options dark_mode_filter and dark_mode_image to the picture elements card (#7304) 2020-10-15 16:16:15 -05:00
Bram Kragten ce07dfd8ac Little clean up in data table (#7352) 2020-10-15 18:46:55 +02:00
Zack Barett c1dba462e8 Lovelace Cards: Update size calcs and add height fixes for horizontal stacks (#7177) 2020-10-15 17:46:29 +02:00
Philip Allgaier 47f0d74812 New "clickable" property for <ha-data-table> (#7351) 2020-10-15 15:57:05 +02:00
Ryan Meek ce80285f8d Header styling & paper-tabs improvements (#7238)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-10-15 15:08:53 +02:00
Philip Allgaier d2dd1a43dd Fix attribute picker suffix (#7348) 2020-10-15 14:56:10 +02:00
Zack Barett 12d73fe90d Add Friendly Name to the Entity Picker + FuzzySeq Algo (#7291) 2020-10-14 20:20:21 -05:00
HomeAssistant Azure c2741638b2 [ci skip] Translation update 2020-10-15 00:32:32 +00:00
Philip Allgaier 4a7fb3d509 Use attribute picker for sec. info in weather card editor (#7335) 2020-10-15 00:57:30 +02:00
Bram Kragten f6ff652ca4 Fix es5 build (#7319) 2020-10-14 22:20:39 +02:00
Donnie 6165cb0f83 Make enter key execute first filtered item in Quick Bar (#7288)
* Make enter key execute first filtered item in quick open dialog

* Add support for arrow up and down moving in and out of list

* Add support for typing letters even when arrowing around the list

* Address review comments and clean up the single-character keyboard event logic

* Address comments. Move activated index along with arrow keys

* Add loading spinner and remove memoization
2020-10-14 19:01:44 +02:00
Bram Kragten 1f361b7b10 Update entity picker (#7343) 2020-10-14 17:01:23 +02:00
Tomasz 5269ff978b New component: ha-expansion-panel (#6789)
Co-authored-by: Zack Barett <zackbarett@hey.com>
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-10-14 16:28:46 +02:00
Bram Kragten 55595493a9 Update config.yml 2020-10-14 13:57:48 +02:00
Bram Kragten ad3ff0aba7 Delete FEATURE_REQUEST.md 2020-10-14 12:04:24 +02:00
Bram Kragten ce48546cef Move feature requests to discussions 2020-10-14 12:04:07 +02:00
HomeAssistant Azure 35b3bc995e [ci skip] Translation update 2020-10-14 00:32:30 +00:00
Donnie 63f60019d1 Add friendly name to quick bar list and filter (#7306)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-10-13 17:26:12 -05:00
Philip Allgaier 0d741b6275 Add warning to badge preview in "Panel Mode" (#7331) 2020-10-13 13:49:02 +02:00
uvjustin 0df9080bbb Check if video el still exists before exoplayer resize in ha-hls-player (#7317)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-10-13 12:15:30 +02:00
Donnie ddcf89e6a2 Add tests for fuzzy sequence matcher (#7328) 2020-10-13 11:50:36 +02:00
Donnie 5de225d5d4 Fix: Quick Bar not launching on windows (#7293) 2020-10-13 11:23:18 +02:00
Donnie 5cddb482f1 Fix issue with enter key not executing selected item in quick bar list (#7283) 2020-10-13 11:16:46 +02:00
HomeAssistant Azure c000d724de [ci skip] Translation update 2020-10-13 00:32:16 +00:00
Philip Allgaier 504055f331 Add documentation link to "customize" dialog (#7321) 2020-10-12 22:09:34 +02:00
Philip Allgaier 7f6880f40e Show disabled entities for a config_entry by default + number of hidden entities (#7300)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-10-12 22:00:21 +02:00
Zack Barett 02e4e3c892 Weather Card: add icons instead of text (#7305)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-10-12 11:52:17 -05:00
Tobias Kündig 993d73c359 Added entity_id to history graph tooltip (#7310)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-10-12 14:12:54 +02:00
Philip Allgaier 97ca0b818e Capitalize first character of attributes (#7313) 2020-10-12 11:43:46 +02:00
Thomas Lovén 44166f76d4 Scriptomation yaml editor (#7273) 2020-10-12 11:26:16 +02:00
Nico Hirsch 557d6d37a1 Fix charts tooltip (#7216) 2020-10-12 11:12:20 +02:00
Paulus Schoutsen d3ad56a307 Update compatibility and fix polyfills for ES5 (#7298) 2020-10-12 10:48:33 +02:00
Mischa Gruber 0641022ec5 Use translations for alexa (#7301) 2020-10-12 10:28:11 +02:00
Zack Barett 80c7a8473a Fix Entity Toggle not working for Type Row (#7289) 2020-10-12 10:26:23 +02:00
Matt d9a954ca91 Close notification drawer after dismissing last notification (#7229)
* Close notification drawer after dismissing last

This change adds a listener to any changes of the notifications property once the drawer opens. After the last notification is dismissed, the notification drawer closes automatically, and the listener is removed.

* Use observer instead event for notification change

Using the observer pattern instead subscribing to change events for notification changes simplifies the implementation noticeably.
2020-10-12 10:25:04 +02:00
Donnie c219f64322 Rename 'quick open dialog' to 'quick bar' (#7286) 2020-10-12 10:18:18 +02:00
HomeAssistant Azure f7a9ecff21 [ci skip] Translation update 2020-10-12 00:32:48 +00:00
Jonas Bröms 2b3126ae04 hassio-addon-info.ts: Fix spelling (#7311) 2020-10-11 15:21:02 -05:00
Kyle Niewiada 934c227545 Sort profile refresh tokens by 'last used at' date (#4484) (#7199) 2020-10-11 01:17:05 -05:00
Villhellm cc0515c217 Add help link on automations picker and updated links for scripts and scenes (#7129)
Co-authored-by: Zack Barett <zackbarett@hey.com>
2020-10-11 01:14:22 -05:00
HomeAssistant Azure 55ba75f2bc [ci skip] Translation update 2020-10-11 00:32:41 +00:00
alex6480 c220228566 Add link to documentation for persons (#7205)
Co-authored-by: Zack Barett <zackbarett@hey.com>
2020-10-10 16:19:59 -05:00
Daniel Martin Gonzalez 26b476ab3c Weather card: Add wind speed direction (#7202)
Co-authored-by: Zack Barett <zackbarett@hey.com>
2020-10-10 16:19:40 -05:00
Paulus Schoutsen b8a67d530f Update translations 2020-10-10 16:41:36 +02:00
HomeAssistant Azure b08c96d2db [ci skip] Translation update 2020-10-10 00:32:54 +00:00
Philip Allgaier 4773c39a57 Ensure ha-dialog uses correct <a> color (#7255) 2020-10-09 11:29:47 +02:00
Ryan Meek 892843b290 Supervisor disk usage more info (#7247)
Co-authored-by: Joakim Sørensen <ludeeus@gmail.com>
2020-10-09 10:15:55 +02:00
HomeAssistant Azure 733244531e [ci skip] Translation update 2020-10-09 00:32:37 +00:00
Bram Kragten 66633273e2 Fix history chart fetching changes (#7235) 2020-10-08 16:41:25 +02:00
Spencer Williams 0405adcd16 Edit Person button in the Person "more info" dialog (fixes #4706) (#7208)
Co-authored-by: Zack Barett <zackbarett@hey.com>
2020-10-08 16:40:55 +02:00
Ian Richardson 426a7ac8dd Show moon phase icon in state-label-badge (#7194)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-10-08 16:37:51 +02:00
Thomas Lovén 3bf6205ff7 Display qr code in tag properties (#7092) 2020-10-08 16:37:17 +02:00
Thomas Lovén c7f4986e61 Put automation/script editor actions in a menu (#7250)
* Put automation/script editor actions in a menu

* Use disabled property instead of attribute
2020-10-08 16:37:01 +02:00
Gilson Marquato Júnior 0f0a3fdaf7 Add keyboard shortcut to save automation/scene/script (#7207) 2020-10-08 16:24:08 +02:00
Bram Kragten 7d6911b140 Replace mdc circular progress with mwc (#7248) 2020-10-08 16:17:20 +02:00
Jaroslav Hanslík b8777539d7 Fixed localization of relative time (#7256) 2020-10-08 15:53:59 +02:00
Bram Kragten b5b1849ab3 Bumped version to 20201001.2 2020-10-08 15:12:18 +02:00
Bram Kragten 0e10c81025 Fix cloud webhooks (#7261) 2020-10-08 15:12:05 +02:00
Joakim Sørensen 5fc0eaef1a Warn about slow snapshot downloads (#7265) 2020-10-08 15:06:42 +02:00
Paulus Schoutsen 113718c3c1 Do not show weather forecast in generated UI (#7251) 2020-10-08 13:29:13 +02:00
Ryan Meek 701bea6cae Fix tab focus issue in entity picker and password form. (#7252) 2020-10-08 13:24:58 +02:00
Donnie 8d516ed12a Add "quick open" style dialog for selecting entities and running reload commands (#7230)
Co-authored-by: Zack Barett <zackbarett@hey.com>
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2020-10-08 13:20:57 +02:00
Joakim Sørensen 667c5744f2 Fix ha-bar display issue on firefox (#7263) 2020-10-08 12:29:21 +02:00
Bram Kragten 80b7c840e2 Fix cloud webhooks (#7261) 2020-10-08 10:33:06 +02:00
HomeAssistant Azure 919c86796f [ci skip] Translation update 2020-10-08 00:32:28 +00:00
Bram Kragten c90c88ecbf Bump typescript (4) and babel (#7249) 2020-10-07 17:58:56 +02:00
Paulus Schoutsen d9ba0e2c46 Upgrade to Webpack 5 (#6200) 2020-10-07 10:54:42 +02:00
HomeAssistant Azure 45b2fc590b [ci skip] Translation update 2020-10-07 00:32:14 +00:00
Daniel 17ffdb0247 Update script editor panel tooltips (#7204) 2020-10-06 20:44:20 +02:00
J. Nick Koston c2fba15fc6 Avoid fetching logbook when there will never be entries (#7239) 2020-10-06 11:22:38 -05:00
Bram Kragten 5937be695f Bump Lit, use cache for query (#7245) 2020-10-06 15:55:55 +02:00
Tomasz a076fcde84 replace ha-icon_button and ha-icon in stack card editor (#7233) 2020-10-06 12:50:06 +02:00
Bram Kragten ede9931903 Only do 1 token update a time (#7236) 2020-10-06 10:55:12 +02:00
Paul Klingelhuber 722e01608c Fix flickering scrollbar when using progress-spinner (#7237) 2020-10-06 09:47:25 +02:00
HomeAssistant Azure af926370d6 [ci skip] Translation update 2020-10-06 00:32:53 +00:00
Tomasz 5971aee02e dot notation for path property of ha-svg-icon (#7197) 2020-10-05 19:51:14 +02:00
Bram Kragten cce7ad449a Set hass when creating card (#7187) 2020-10-05 16:04:25 +02:00
Bram Kragten d437dd5919 Bumped version to 20201001.1 2020-10-05 16:00:40 +02:00
Bram Kragten f1980730d2 Fix Apple not showing cards (#7232) 2020-10-05 16:00:27 +02:00
Zack Barett 47773e9cae Fix entities Card toggle (#7192) 2020-10-05 16:00:12 +02:00
Ryan Meek 60969b0916 Styling fixes for hui-masonry-view (#7226) 2020-10-05 15:59:53 +02:00
Zack Barett ecc7925d03 Warning Element: Fix Overflow in Entity Row (#7193) 2020-10-05 15:59:38 +02:00
Zack Barett 6d3010dcc7 Logbook: Fix for no state obj (#7191) 2020-10-05 15:59:19 +02:00
J. Nick Koston 0164bafbf1 Fix reversal in power icon (#7188) 2020-10-05 15:58:57 +02:00
Bram Kragten 3940606167 Fix Apple not showing cards (#7232) 2020-10-05 15:54:32 +02:00
David Beitey da9faccada Allow viewport scaling (zooming) of frontend (#7180)
The inclusion of the `user-scalable=no` value in the viewport meta tag
prevented viewport scaling, disabling the ability to zoom the webpage.
This most typically affects mobile devices, given the nature of the
`<meta name="viewport">` tag.

Removing the restriction allows a user to zoom in to see small and fine
detail in the UI -- such as zooming in on particular areas of a home
security camera streams or other images, inspecting detail in state and
other graphs, and so on.

For users with accessibility requirements, such as low vision
conditions, being able to zoom the frontend means they can enlarge UI
elements to suit them (MDN explains several accessibility concerns at
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta/name#Accessibility_concerns_with_viewport_scaling)

This change has no effect on users that choose not to use it (for
example, only those that engage zooming such as via pinch-to-zoom on
mobile devices will see the change) -- the frontend remains the same
otherwise.  Elements of the frontend that do use pinch-to-zoom (e.g. the
Map) continue to work as expected, with pinches on that screen area
being captured by the map.
2020-10-05 13:29:07 +02:00
Ryan Meek 7e708b3bf7 Use consistent title case for headers in Supervisor (#7227) 2020-10-05 12:05:57 +02:00
Ryan Meek 05630c9896 Use client_id if no client_name in delete dialog (#7228) 2020-10-05 10:24:23 +02:00
HomeAssistant Azure 369c56db73 [ci skip] Translation update 2020-10-05 00:32:49 +00:00
Ryan Meek 9873459169 Styling fixes for hui-masonry-view (#7226) 2020-10-04 15:15:14 -05:00
HomeAssistant Azure 7776b3766b [ci skip] Translation update 2020-10-04 00:32:25 +00:00
HomeAssistant Azure 29c9004654 [ci skip] Translation update 2020-10-03 00:32:26 +00:00
Zack Barett 601c909004 Warning Element: Fix Overflow in Entity Row (#7193) 2020-10-02 11:29:29 -05:00
Tomasz 72aa9a3b62 use ha-svg-icon in more-info-weather (#7196) 2020-10-02 15:12:54 +02:00
Bram Kragten 2ecf7bca97 Set hass when creating card (#7187) 2020-10-02 15:09:27 +02:00
Zack Barett cbdfaccdb2 Logbook: Fix for no state obj (#7191) 2020-10-02 14:57:42 +02:00
Zack Barett 93d1b9a2d5 Fix entities Card toggle (#7192) 2020-10-02 10:12:55 +02:00
HomeAssistant Azure bfb5ee794e [ci skip] Translation update 2020-10-02 00:32:24 +00:00
J. Nick Koston 9ae8bd238b Fix reversal in power icon (#7188) 2020-10-01 11:24:13 -05:00
721 changed files with 44547 additions and 13153 deletions
+13
View File
@@ -0,0 +1,13 @@
# 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.9
ENV \
DEBIAN_FRONTEND=noninteractive \
DEVCONTAINER=true \
PATH=$PATH:./node_modules/.bin
# Install nvm
COPY .nvmrc /tmp/.nvmrc
RUN \
su vscode -c \
"source /usr/local/share/nvm/nvm.sh && nvm install $(cat /tmp/.nvmrc) 2>&1"
+31
View File
@@ -0,0 +1,31 @@
{
"name": "Home Assistant Frontend",
"build": {
"dockerfile": "Dockerfile",
"context": ".."
},
"appPort": 8123,
"context": "..",
"postCreateCommand": "script/bootstrap",
"extensions": [
"github.vscode-pull-request-github",
"dbaeumer.vscode-eslint",
"ms-vscode.vscode-typescript-tslint-plugin",
"esbenp.prettier-vscode",
"bierner.lit-html",
"runem.lit-plugin",
"ms-python.vscode-pylance"
],
"settings": {
"terminal.integrated.shell.linux": "/bin/bash",
"files.eol": "\n",
"editor.tabSize": 2,
"editor.formatOnPaste": false,
"editor.formatOnSave": true,
"editor.formatOnType": true,
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"files.trimTrailingWhitespace": true
}
}
+5 -2
View File
@@ -75,13 +75,16 @@
"object-curly-newline": 0,
"default-case": 0,
"wc/no-self-class": 0,
"no-shadow": 0,
"@typescript-eslint/camelcase": 0,
"@typescript-eslint/ban-ts-ignore": 0,
"@typescript-eslint/ban-ts-comment": 0,
"@typescript-eslint/no-use-before-define": 0,
"@typescript-eslint/no-non-null-assertion": 0,
"@typescript-eslint/no-explicit-any": 0,
"@typescript-eslint/no-unused-vars": 0,
"@typescript-eslint/explicit-function-return-type": 0
"@typescript-eslint/explicit-function-return-type": 0,
"@typescript-eslint/explicit-module-boundary-types": 0,
"@typescript-eslint/no-shadow": ["error"]
},
"plugins": ["disable", "import", "lit", "prettier", "@typescript-eslint"],
"processor": "disable/disable"
+5 -5
View File
@@ -74,12 +74,12 @@ DO NOT DELETE ANY TEXT from this template! Otherwise, your issue may be closed w
```
## Problem-relevant configuration
## Problem-relevant frontend configuration
<!--
An example configuration that caused the problem for you. Fill this out even
if it seems unimportant to you. Please be sure to remove personal information
like passwords, private URLs and other credentials.
An example configuration that caused the problem for you, e.g. the YAML configuration
of the used cards. Fill this out even if it seems unimportant to you. Please be sure
to remove personal information like passwords, private URLs and other credentials.
-->
```yaml
@@ -89,7 +89,7 @@ DO NOT DELETE ANY TEXT from this template! Otherwise, your issue may be closed w
## Javascript errors shown in your browser console/inspector
<!--
If you come across any javascript or other error logs, e.g., in your browser
If you come across any Javascript or other error logs, e.g. in your browser
console/inspector please provide them.
-->
-26
View File
@@ -1,26 +0,0 @@
---
name: Request a feature for the UI, Frontend or Lovelace
about: Request an new feature for the Home Assistant frontend.
labels: feature request
---
<!--
DO NOT DELETE ANY TEXT from this template!
Otherwise, your request may be closed without comment.
-->
## The request
<!--
Describe to our maintainers, the feature you would like to be added.
Please be clear and concise and, if possible, provide a screenshot or mockup.
-->
## The alternatives
<!--
Are you currently using, or have you considered alternatives?
If so, could you please describe those?
-->
## Additional information
+3
View File
@@ -1,5 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Request a feature for the UI, Frontend or Lovelace
url: https://github.com/home-assistant/frontend/discussions/category_choices
about: Request an new feature for the Home Assistant frontend.
- name: Report a bug that is NOT related to the UI, Frontend or Lovelace
url: https://github.com/home-assistant/core/issues
about: This is the issue tracker for our frontend. Please report other issues with the backend repository.
+3 -3
View File
@@ -18,8 +18,8 @@
<!--
Describe the big picture of your changes here to communicate to the
maintainers why we should accept this pull request. If it fixes a bug
or resolves a feature request, be sure to link to that issue in the
additional information section.
or resolves a feature request, be sure to link to that issue or discussion
in the additional information section.
-->
## Type of change
@@ -56,7 +56,7 @@
-->
- This PR fixes or closes issue: fixes #
- This PR is related to issue:
- This PR is related to issue or discussion:
- Link to documentation pull request:
## Checklist
-27
View File
@@ -1,27 +0,0 @@
# Configuration for Lock Threads - https://github.com/dessant/lock-threads
# Number of days of inactivity before a closed issue or pull request is locked
daysUntilLock: 1
# Skip issues and pull requests created before a given timestamp. Timestamp must
# follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable
skipCreatedBefore: 2020-01-01
# Issues and pull requests with these labels will be ignored. Set to `[]` to disable
exemptLabels: []
# Label to add before locking, such as `outdated`. Set to `false` to disable
lockLabel: false
# Comment to post before locking. Set to `false` to disable
lockComment: false
# Assign `resolved` as the reason for locking. Set to `false` to disable
setLockReason: false
# Limit to only `issues` or `pulls`
only: pulls
# Optionally, specify configuration settings just for `issues` or `pulls`
issues:
daysUntilLock: 30
-56
View File
@@ -1,56 +0,0 @@
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 90
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
daysUntilClose: 7
# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
onlyLabels: []
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
exemptLabels:
- feature request
- Help wanted
- to do
# Set to true to ignore issues in a project (defaults to false)
exemptProjects: true
# Set to true to ignore issues in a milestone (defaults to false)
exemptMilestones: true
# Set to true to ignore issues with an assignee (defaults to false)
exemptAssignees: false
# Label to use when marking as stale
staleLabel: stale
# Comment to post when marking as stale. Set to `false` to disable
markComment: >
There hasn't been any activity on this issue recently. Due to the high number
of incoming GitHub notifications, we have to clean some of the old issues,
as many of them have already been resolved with the latest updates.
Please make sure to update to the latest Home Assistant version and check
if that solves the issue. Let us know if that works for you by adding a
comment 👍
This issue now has been marked as stale and will be closed if no further
activity occurs. Thank you for your contributions.
# Comment to post when removing the stale label.
# unmarkComment: >
# Your comment here.
# Comment to post when closing a stale Issue or Pull Request.
# closeComment: >
# Your comment here.
# Limit the number of actions per hour, from 1-30. Default is 30
limitPerRun: 30
# Limit to only `issues` or `pulls`
only: issues
+20
View File
@@ -0,0 +1,20 @@
name: Lock
# yamllint disable-line rule:truthy
on:
schedule:
- cron: "0 * * * *"
jobs:
lock:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v2.0.1
with:
github-token: ${{ github.token }}
issue-lock-inactive-days: "30"
issue-exclude-created-before: "2020-10-01T00:00:00Z"
issue-lock-reason: ""
pr-lock-inactive-days: "1"
pr-exclude-created-before: "2020-11-01T00:00:00Z"
pr-lock-reason: ""
+42
View File
@@ -0,0 +1,42 @@
name: Stale
# yamllint disable-line rule:truthy
on:
schedule:
- cron: "0 * * * *"
jobs:
stale:
runs-on: ubuntu-latest
steps:
- name: 90 days stale policy
uses: actions/stale@v3.0.13
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 90
days-before-close: 7
operations-per-run: 25
remove-stale-when-updated: true
stale-issue-label: "stale"
exempt-issue-labels: "no-stale,Help%20wanted,help-wanted,feature-request,feature%20request"
stale-issue-message: >
There hasn't been any activity on this issue recently. Due to the
high number of incoming GitHub notifications, we have to clean some
of the old issues, as many of them have already been resolved with
the latest updates.
Please make sure to update to the latest Home Assistant version and
check if that solves the issue. Let us know if that works for you by
adding a comment 👍
This issue has now been marked as stale and will be closed if no
further activity occurs. Thank you for your contributions.
stale-pr-label: "stale"
exempt-pr-labels: "no-stale"
stale-pr-message: >
There hasn't been any activity on this pull request recently. This
pull request has been automatically marked as stale because of that
and will be closed if no further activity occurs within 7 days.
Thank you for your contributions.
+5
View File
@@ -23,6 +23,8 @@ dist
# vscode
.vscode/*
!.vscode/extensions.json
!.vscode/launch.json
!.vscode/tasks.json
# Cast dev settings
src/cast/dev_const.ts
@@ -33,3 +35,6 @@ yarn-error.log
#asdf
.tool-versions
# Home Assistant config
/config
-6
View File
@@ -1,6 +0,0 @@
jshint:
enabled: false
eslint:
enabled: true
config_file: .eslintrc-hound.json
+44
View File
@@ -0,0 +1,44 @@
{
// https://github.com/microsoft/vscode-js-debug/blob/master/OPTIONS.md
"configurations": [
{
"name": "Debug Frontend",
"request": "launch",
"type": "pwa-chrome",
"url": "http://localhost:8123/",
"webRoot": "${workspaceFolder}/hass_frontend",
"disableNetworkCache": true,
"preLaunchTask": "Develop Frontend",
"outFiles": [
"${workspaceFolder}/hass_frontend/frontend_latest/*.js"
]
},
{
"name": "Debug Gallery",
"request": "launch",
"type": "pwa-chrome",
"url": "http://localhost:8100/",
"webRoot": "${workspaceFolder}/gallery/dist",
"disableNetworkCache": true,
"preLaunchTask": "Develop Gallery"
},
{
"name": "Debug Demo",
"request": "launch",
"type": "pwa-chrome",
"url": "http://localhost:8090/",
"webRoot": "${workspaceFolder}/demo/dist",
"disableNetworkCache": true,
"preLaunchTask": "Develop Demo"
},
{
"name": "Debug Cast",
"request": "launch",
"type": "pwa-chrome",
"url": "http://localhost:8080/",
"webRoot": "${workspaceFolder}/cast/dist",
"disableNetworkCache": true,
"preLaunchTask": "Develop Cast"
},
]
}
+208
View File
@@ -0,0 +1,208 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Develop Frontend",
"type": "gulp",
"task": "develop-app",
// Sync changes here to other tasks until issue resolved
// https://github.com/Microsoft/vscode/issues/61497
"problemMatcher": {
"owner": "ha-build",
"source": "ha-build",
"fileLocation": "absolute",
"severity": "error",
"pattern": [
{
"regexp": "(SyntaxError): (.+): (.+) \\((\\d+):(\\d+)\\)",
"severity": 1,
"file": 2,
"message": 3,
"line": 4,
"column": 5
}
],
"background": {
"activeOnStart": true,
"beginsPattern": "Changes detected. Starting compilation",
"endsPattern": "Build done @"
}
},
"isBackground": true,
"group": {
"kind": "build",
"isDefault": true
},
"runOptions": {
"instanceLimit": 1
}
},
{
"label": "Develop Supervisor panel",
"type": "gulp",
"task": "develop-hassio",
"problemMatcher": {
"owner": "ha-build",
"source": "ha-build",
"fileLocation": "absolute",
"severity": "error",
"pattern": [
{
"regexp": "(SyntaxError): (.+): (.+) \\((\\d+):(\\d+)\\)",
"severity": 1,
"file": 2,
"message": 3,
"line": 4,
"column": 5
}
],
"background": {
"activeOnStart": true,
"beginsPattern": "Changes detected. Starting compilation",
"endsPattern": "Build done @"
}
},
"isBackground": true,
"group": "build",
"runOptions": {
"instanceLimit": 1
}
},
{
"label": "Develop Gallery",
"type": "gulp",
"task": "develop-gallery",
"problemMatcher": {
"owner": "ha-build",
"source": "ha-build",
"fileLocation": "absolute",
"severity": "error",
"pattern": [
{
"regexp": "(SyntaxError): (.+): (.+) \\((\\d+):(\\d+)\\)",
"severity": 1,
"file": 2,
"message": 3,
"line": 4,
"column": 5
}
],
"background": {
"activeOnStart": true,
"beginsPattern": "Changes detected. Starting compilation",
"endsPattern": "Build done @"
}
},
"isBackground": true,
"group": "build",
"runOptions": {
"instanceLimit": 1
}
},
{
"label": "Develop Demo",
"type": "gulp",
"task": "develop-demo",
"problemMatcher": {
"owner": "ha-build",
"source": "ha-build",
"fileLocation": "absolute",
"severity": "error",
"pattern": [
{
"regexp": "(SyntaxError): (.+): (.+) \\((\\d+):(\\d+)\\)",
"severity": 1,
"file": 2,
"message": 3,
"line": 4,
"column": 5
}
],
"background": {
"activeOnStart": true,
"beginsPattern": "Changes detected. Starting compilation",
"endsPattern": "Build done @"
}
},
"isBackground": true,
"group": "build",
"runOptions": {
"instanceLimit": 1
}
},
{
"label": "Develop Cast",
"type": "gulp",
"task": "develop-cast",
"problemMatcher": {
"owner": "ha-build",
"source": "ha-build",
"fileLocation": "absolute",
"severity": "error",
"pattern": [
{
"regexp": "(SyntaxError): (.+): (.+) \\((\\d+):(\\d+)\\)",
"severity": 1,
"file": 2,
"message": 3,
"line": 4,
"column": 5
}
],
"background": {
"activeOnStart": true,
"beginsPattern": "Changes detected. Starting compilation",
"endsPattern": "Build done @"
}
},
"isBackground": true,
"group": "build",
"runOptions": {
"instanceLimit": 1
}
},
{
"label": "Run HA Core in devcontainer",
"type": "shell",
"command": "script/core",
"isBackground": true,
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [],
"runOptions": {
"instanceLimit": 1
}
},
{
"label": "Run HA Core for Supervisor in devcontainer",
"type": "shell",
"command": "HASSIO=${input:supervisorHost} HASSIO_TOKEN=${input:supervisorToken} script/core",
"isBackground": true,
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [],
"runOptions": {
"instanceLimit": 1
}
}
],
"inputs": [
{
"id": "supervisorHost",
"type": "promptString",
"description": "The IP of the Supervisor host running the Remote API proxy add-on"
},
{
"id": "supervisorToken",
"type": "promptString",
"description": "The token for the Remote API proxy add-on"
}
]
}
+2 -2
View File
@@ -14,7 +14,7 @@ This is the repository for the official [Home Assistant](https://home-assistant.
- Development: [Instructions](https://developers.home-assistant.io/docs/frontend/development/)
- Production build: `script/build_frontend`
- Gallery: `cd gallery && script/develop_gallery`
- Hass.io: [Instructions](https://developers.home-assistant.io/docs/en/hassio_hass.html)
- Supervisor: [Instructions](https://developers.home-assistant.io/docs/supervisor/developing)
## Frontend development
@@ -26,4 +26,4 @@ A complete guide can be found at the following [link](https://www.home-assistant
Home Assistant is open-source and Apache 2 licensed. Feel free to browse the repository, learn and reuse parts in your own projects.
We use [BrowserStack](https://www.browserstack.com) to test Home Assistant on a large variation of devices.
We use [BrowserStack](https://www.browserstack.com) to test Home Assistant on a large variety of devices.
+39
View File
@@ -0,0 +1,39 @@
# Bundling Home Assistant Frontend
The Home Assistant build pipeline contains various steps to prepare a build.
- Generating icon files to be included
- Generating translation files to be included
- Converting TypeScript, CSS and JSON files to JavaScript
- Bundling
- Minifying the files
- Generating the HTML entrypoint files
- Generating the service worker
- Compressing the files
## Converting files
Currently in Home Assistant we use a bundler to convert TypeScript, CSS and JSON files to JavaScript files that the browser understands.
We currently rely on Webpack but also have experimental Rollup support. Both of these programs bundle the converted files in both production and development.
For development, bundling is optional. We just want to get the right files in the browser.
Responsibilities of the converter during development:
- Convert TypeScript to JavaScript
- Convert CSS to JavaScript that sets the content as the default export
- Convert JSON to JavaScript that sets the content as the default export
- Make sure import, dynamic import and web worker references work
- Add extensions where missing
- Resolve absolute package imports
- Filter out specific imports/packages
- Replace constants with values
In production, the following responsibilities are added:
- Minify HTML
- Bundle multiple imports so that the browser can fetch less files
- Generate a second version that is ES5 compatible
Configuration for all these steps are specified in [bundle.js](bundle.js).
+12 -4
View File
@@ -44,7 +44,7 @@ module.exports.definedVars = ({ isProdBuild, latestBuild, defineOverlay }) => ({
});
module.exports.terserOptions = (latestBuild) => ({
safari10: true,
safari10: !latestBuild,
ecma: latestBuild ? undefined : 5,
output: { comments: false },
});
@@ -52,7 +52,13 @@ module.exports.terserOptions = (latestBuild) => ({
module.exports.babelOptions = ({ latestBuild }) => ({
babelrc: false,
presets: [
!latestBuild && [require("@babel/preset-env").default, { modules: false }],
!latestBuild && [
require("@babel/preset-env").default,
{
useBuiltIns: "entry",
corejs: "3.6",
},
],
require("@babel/preset-typescript").default,
].filter(Boolean),
plugins: [
@@ -62,7 +68,8 @@ module.exports.babelOptions = ({ latestBuild }) => ({
{ loose: true, useBuiltIns: true },
],
// Only support the syntax, Webpack will handle it.
"@babel/syntax-dynamic-import",
"@babel/plugin-syntax-import-meta",
"@babel/plugin-syntax-dynamic-import",
"@babel/plugin-proposal-optional-chaining",
"@babel/plugin-proposal-nullish-coalescing-operator",
[
@@ -110,7 +117,7 @@ BundleConfig {
*/
module.exports.config = {
app({ isProdBuild, latestBuild, isStatsBuild }) {
app({ isProdBuild, latestBuild, isStatsBuild, isWDS }) {
return {
entry: {
service_worker: "./src/entrypoints/service_worker.ts",
@@ -125,6 +132,7 @@ module.exports.config = {
isProdBuild,
latestBuild,
isStatsBuild,
isWDS,
};
},
+3
View File
@@ -6,6 +6,9 @@ module.exports = {
useRollup() {
return process.env.ROLLUP === "1";
},
useWDS() {
return process.env.WDS === "1";
},
isProdBuild() {
return (
process.env.NODE_ENV === "production" || module.exports.isStatsBuild()
+6 -1
View File
@@ -12,6 +12,7 @@ require("./webpack.js");
require("./service-worker.js");
require("./entry-html.js");
require("./rollup.js");
require("./wds.js");
gulp.task(
"develop-app",
@@ -28,7 +29,11 @@ gulp.task(
"build-translations"
),
"copy-static-app",
env.useRollup() ? "rollup-watch-app" : "webpack-watch-app"
env.useWDS()
? "wds-watch-app"
: env.useRollup()
? "rollup-watch-app"
: "webpack-watch-app"
)
);
+17 -3
View File
@@ -19,6 +19,7 @@ const renderTemplate = (pth, data = {}, pathFunc = templatePath) => {
return compiled({
...data,
useRollup: env.useRollup(),
useWDS: env.useWDS(),
renderTemplate,
});
};
@@ -90,10 +91,23 @@ gulp.task("gen-pages-prod", (done) => {
});
gulp.task("gen-index-app-dev", (done) => {
let latestAppJS, latestCoreJS, latestCustomPanelJS;
if (env.useWDS()) {
latestAppJS = "http://localhost:8000/src/entrypoints/app.ts";
latestCoreJS = "http://localhost:8000/src/entrypoints/core.ts";
latestCustomPanelJS =
"http://localhost:8000/src/entrypoints/custom-panel.ts";
} else {
latestAppJS = "/frontend_latest/app.js";
latestCoreJS = "/frontend_latest/core.js";
latestCustomPanelJS = "/frontend_latest/custom-panel.js";
}
const content = renderTemplate("index", {
latestAppJS: "/frontend_latest/app.js",
latestCoreJS: "/frontend_latest/core.js",
latestCustomPanelJS: "/frontend_latest/custom-panel.js",
latestAppJS,
latestCoreJS,
latestCustomPanelJS,
es5AppJS: "/frontend_es5/app.js",
es5CoreJS: "/frontend_es5/core.js",
+4 -17
View File
@@ -7,7 +7,6 @@ const gulp = require("gulp");
const fs = require("fs");
const foreach = require("gulp-foreach");
const merge = require("gulp-merge-json");
const minify = require("gulp-jsonminify");
const rename = require("gulp-rename");
const transform = require("gulp-json-transform");
const { mapFiles } = require("../util");
@@ -34,21 +33,10 @@ String.prototype.rsplit = function (sep, maxsplit) {
: split;
};
// Panel translations which should be split from the core translations. These
// should mirror the fragment definitions in polymer.json, so that we load
// additional resources at equivalent points.
const TRANSLATION_FRAGMENTS = [
"config",
"history",
"logbook",
"mailbox",
"profile",
"shopping-list",
"page-authorize",
"page-demo",
"page-onboarding",
"developer-tools",
];
// Panel translations which should be split from the core translations.
const TRANSLATION_FRAGMENTS = Object.keys(
require("../../src/translations/en.json").ui.panel
);
function recursiveFlatten(prefix, data) {
let output = {};
@@ -301,7 +289,6 @@ gulp.task("build-flattened-translations", function () {
return flatten(data);
})
)
.pipe(minify())
.pipe(
rename((filePath) => {
if (filePath.dirname === "core") {
+11
View File
@@ -0,0 +1,11 @@
// Tasks to run Rollup
const gulp = require("gulp");
const { startDevServer } = require("@web/dev-server");
gulp.task("wds-watch-app", () => {
startDevServer({
config: {
watch: true,
},
});
});
+60 -65
View File
@@ -18,6 +18,14 @@ const bothBuilds = (createConfigFunc, params) => [
createConfigFunc({ ...params, latestBuild: false }),
];
/**
* @param {{
* compiler: import("webpack").Compiler,
* contentBase: string,
* port: number,
* listenHost?: string
* }}
*/
const runDevServer = ({
compiler,
contentBase,
@@ -33,10 +41,13 @@ const runDevServer = ({
throw err;
}
// Server listening
log("[webpack-dev-server]", `http://localhost:${port}`);
log(
"[webpack-dev-server]",
`Project is running at http://localhost:${port}`
);
});
const handler = (done) => (err, stats) => {
const doneHandler = (done) => (err, stats) => {
if (err) {
log.error(err.stack || err);
if (err.details) {
@@ -45,22 +56,31 @@ const handler = (done) => (err, stats) => {
return;
}
log(`Build done @ ${new Date().toLocaleTimeString()}`);
if (stats.hasErrors() || stats.hasWarnings()) {
log.warn(stats.toString("minimal"));
console.log(stats.toString("minimal"));
}
log(`Build done @ ${new Date().toLocaleTimeString()}`);
if (done) {
done();
}
};
const prodBuild = (conf) =>
new Promise((resolve) => {
webpack(
conf,
// Resolve promise when done. Because we pass a callback, webpack closes itself
doneHandler(resolve)
);
});
gulp.task("webpack-watch-app", () => {
// we are not calling done, so this command will run forever
// This command will run forever because we don't close compiler
webpack(createAppConfig({ isProdBuild: false, latestBuild: true })).watch(
{ ignored: /build-translations/ },
handler()
doneHandler()
);
gulp.watch(
path.join(paths.translations_src, "en.json"),
@@ -68,15 +88,12 @@ gulp.task("webpack-watch-app", () => {
);
});
gulp.task(
"webpack-prod-app",
() =>
new Promise((resolve) =>
webpack(
bothBuilds(createAppConfig, { isProdBuild: true }),
handler(resolve)
)
)
gulp.task("webpack-prod-app", () =>
prodBuild(
bothBuilds(createAppConfig, {
isProdBuild: true,
})
)
);
gulp.task("webpack-dev-server-demo", () => {
@@ -87,17 +104,12 @@ gulp.task("webpack-dev-server-demo", () => {
});
});
gulp.task(
"webpack-prod-demo",
() =>
new Promise((resolve) =>
webpack(
bothBuilds(createDemoConfig, {
isProdBuild: true,
}),
handler(resolve)
)
)
gulp.task("webpack-prod-demo", () =>
prodBuild(
bothBuilds(createDemoConfig, {
isProdBuild: true,
})
)
);
gulp.task("webpack-dev-server-cast", () => {
@@ -110,41 +122,30 @@ gulp.task("webpack-dev-server-cast", () => {
});
});
gulp.task(
"webpack-prod-cast",
() =>
new Promise((resolve) =>
webpack(
bothBuilds(createCastConfig, {
isProdBuild: true,
}),
handler(resolve)
)
)
gulp.task("webpack-prod-cast", () =>
prodBuild(
bothBuilds(createCastConfig, {
isProdBuild: true,
})
)
);
gulp.task("webpack-watch-hassio", () => {
// we are not calling done, so this command will run forever
// This command will run forever because we don't close compiler
webpack(
createHassioConfig({
isProdBuild: false,
latestBuild: true,
})
).watch({}, handler());
).watch({}, doneHandler());
});
gulp.task(
"webpack-prod-hassio",
() =>
new Promise((resolve) =>
webpack(
bothBuilds(createHassioConfig, {
isProdBuild: true,
}),
handler(resolve)
)
)
gulp.task("webpack-prod-hassio", () =>
prodBuild(
bothBuilds(createHassioConfig, {
isProdBuild: true,
})
)
);
gulp.task("webpack-dev-server-gallery", () => {
@@ -156,17 +157,11 @@ gulp.task("webpack-dev-server-gallery", () => {
});
});
gulp.task(
"webpack-prod-gallery",
() =>
new Promise((resolve) =>
webpack(
createGalleryConfig({
isProdBuild: true,
latestBuild: true,
}),
handler(resolve)
)
)
gulp.task("webpack-prod-gallery", () =>
prodBuild(
createGalleryConfig({
isProdBuild: true,
latestBuild: true,
})
)
);
+1 -1
View File
@@ -1,4 +1,4 @@
var path = require("path");
const path = require("path");
module.exports = {
polymer_dir: path.resolve(__dirname, ".."),
@@ -1,5 +1,3 @@
const path = require("path");
module.exports = function (userOptions = {}) {
// Files need to be absolute paths.
// This only works if the file has no exports
+15 -10
View File
@@ -3,7 +3,7 @@ const path = require("path");
const commonjs = require("@rollup/plugin-commonjs");
const resolve = require("@rollup/plugin-node-resolve");
const json = require("@rollup/plugin-json");
const babel = require("rollup-plugin-babel");
const babel = require("@rollup/plugin-babel").babel;
const replace = require("@rollup/plugin-replace");
const visualizer = require("rollup-plugin-visualizer");
const { string } = require("rollup-plugin-string");
@@ -31,6 +31,7 @@ const createRollupConfig = ({
isStatsBuild,
publicPath,
dontHash,
isWDS,
}) => {
return {
/**
@@ -61,6 +62,7 @@ const createRollupConfig = ({
...bundle.babelOptions({ latestBuild }),
extensions,
exclude: bundle.babelExclude(),
babelHelpers: isWDS ? "inline" : "bundled",
}),
string({
// Import certain extensions as strings
@@ -69,19 +71,21 @@ const createRollupConfig = ({
replace(
bundle.definedVars({ isProdBuild, latestBuild, defineOverlay })
),
manifest({
publicPath,
}),
worker(),
dontHashPlugin({ dontHash }),
isProdBuild && terser(bundle.terserOptions(latestBuild)),
isStatsBuild &&
!isWDS &&
manifest({
publicPath,
}),
!isWDS && worker(),
!isWDS && dontHashPlugin({ dontHash }),
!isWDS && isProdBuild && terser(bundle.terserOptions(latestBuild)),
!isWDS &&
isStatsBuild &&
visualizer({
// https://github.com/btd/rollup-plugin-visualizer#options
open: true,
sourcemap: true,
}),
],
].filter(Boolean),
},
/**
* @type { import("rollup").OutputOptions }
@@ -108,12 +112,13 @@ const createRollupConfig = ({
};
};
const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild, isWDS }) => {
return createRollupConfig(
bundle.config.app({
isProdBuild,
latestBuild,
isStatsBuild,
isWDS,
})
);
};
+28 -6
View File
@@ -2,9 +2,23 @@ const webpack = require("webpack");
const path = require("path");
const TerserPlugin = require("terser-webpack-plugin");
const ManifestPlugin = require("webpack-manifest-plugin");
const WorkerPlugin = require("worker-plugin");
const paths = require("./paths.js");
const bundle = require("./bundle");
const log = require("fancy-log");
class LogStartCompilePlugin {
ignoredFirst = false;
apply(compiler) {
compiler.hooks.beforeCompile.tap("LogStartCompilePlugin", () => {
if (!this.ignoredFirst) {
this.ignoredFirst = true;
return;
}
log("Changes detected. Starting compilation");
});
}
}
const createWebpackConfig = ({
entry,
@@ -22,6 +36,7 @@ const createWebpackConfig = ({
const ignorePackages = bundle.ignorePackages({ latestBuild });
return {
mode: isProdBuild ? "production" : "development",
target: ["web", latestBuild ? "es2017" : "es5"],
devtool: isProdBuild
? "cheap-module-source-map"
: "eval-cheap-module-source-map",
@@ -30,7 +45,7 @@ const createWebpackConfig = ({
module: {
rules: [
{
test: /\.js$|\.ts$/,
test: /\.m?js$|\.ts$/,
exclude: bundle.babelExclude(),
use: {
loader: "babel-loader",
@@ -46,16 +61,13 @@ const createWebpackConfig = ({
optimization: {
minimizer: [
new TerserPlugin({
cache: true,
parallel: true,
extractComments: true,
sourceMap: true,
terserOptions: bundle.terserOptions(latestBuild),
}),
],
},
plugins: [
new WorkerPlugin(),
new ManifestPlugin({
// Only include the JS of entrypoints
filter: (file) => file.isInitial && !file.name.endsWith(".map"),
@@ -99,7 +111,17 @@ const createWebpackConfig = ({
new RegExp(bundle.emptyPackages({ latestBuild }).join("|")),
path.resolve(paths.polymer_dir, "src/util/empty.js")
),
],
// We need to change the import of the polyfill for EventTarget, so we replace the polyfill file with our customized one
new webpack.NormalModuleReplacementPlugin(
new RegExp(
require.resolve(
"lit-virtualizer/lib/uni-virtualizer/lib/polyfillLoaders/EventTarget.js"
)
),
path.resolve(paths.polymer_dir, "src/resources/EventTarget-ponyfill.js")
),
!isProdBuild && new LogStartCompilePlugin(),
].filter(Boolean),
resolve: {
extensions: [".ts", ".js", ".json"],
},
+2 -2
View File
@@ -30,7 +30,7 @@ class HcLayout extends LitElement {
<ha-card>
<div class="layout">
<img class="hero" src="/images/google-nest-hub.png" />
<div class="card-header">
<h1 class="card-header">
Home Assistant Cast${this.subtitle ? ` ${this.subtitle}` : ""}
${this.auth
? html`
@@ -44,7 +44,7 @@ class HcLayout extends LitElement {
</div>
`
: ""}
</div>
</h1>
<slot></slot>
</div>
</ha-card>
+1 -2
View File
@@ -49,7 +49,6 @@ class HcLovelace extends LitElement {
.hass=${this.hass}
.lovelace=${lovelace}
.index=${index}
columns="2"
></hui-view>
`;
}
@@ -67,7 +66,7 @@ class HcLovelace extends LitElement {
if (configBackground) {
(this.shadowRoot!.querySelector(
"hui-view, hui-panel-view"
"hui-view"
) as HTMLElement)!.style.setProperty(
"--lovelace-background",
configBackground
+4 -16
View File
@@ -3,22 +3,10 @@ import { Lovelace } from "../../../src/panels/lovelace/types";
import { DemoConfig } from "./types";
export const demoConfigs: Array<() => Promise<DemoConfig>> = [
() =>
import(/* webpackChunkName: "arsaboo" */ "./arsaboo").then(
(mod) => mod.demoArsaboo
),
() =>
import(/* webpackChunkName: "teachingbirds" */ "./teachingbirds").then(
(mod) => mod.demoTeachingbirds
),
() =>
import(/* webpackChunkName: "kernehed" */ "./kernehed").then(
(mod) => mod.demoKernehed
),
() =>
import(/* webpackChunkName: "jimpower" */ "./jimpower").then(
(mod) => mod.demoJimpower
),
() => import("./arsaboo").then((mod) => mod.demoArsaboo),
() => import("./teachingbirds").then((mod) => mod.demoTeachingbirds),
() => import("./kernehed").then((mod) => mod.demoKernehed),
() => import("./jimpower").then((mod) => mod.demoJimpower),
];
// eslint-disable-next-line import/no-mutable-exports
+160 -182
View File
@@ -7,205 +7,183 @@ export const demoLovelaceTeachingbirds: DemoConfig["lovelace"] = () => ({
cards: [
{ type: "custom:ha-demo-card" },
{
type: "grid",
columns: 4,
cards: [
{
cards: [
image: "/assets/teachingbirds/isa_square.jpg",
type: "picture-entity",
show_name: false,
tap_action: {
action: "more-info",
},
entity: "sensor.presence_isa",
},
{
image: "/assets/teachingbirds/Stefan_square.jpg",
type: "picture-entity",
show_name: false,
tap_action: {
action: "more-info",
},
entity: "sensor.presence_stefan",
},
{
image: "/assets/teachingbirds/background_square.png",
elements: [
{
image: "/assets/teachingbirds/isa_square.jpg",
type: "picture-entity",
show_name: false,
state_image: {
on: "/assets/teachingbirds/radiator_on.jpg",
off: "/assets/teachingbirds/radiator_off.jpg",
},
type: "image",
style: {
width: "100%",
top: "50%",
left: "50%",
},
tap_action: {
action: "more-info",
},
entity: "sensor.presence_isa",
entity: "switch.stefan_radiator_3",
},
{
image: "/assets/teachingbirds/Stefan_square.jpg",
type: "picture-entity",
show_name: false,
tap_action: {
action: "more-info",
style: {
top: "90%",
left: "50%",
},
entity: "sensor.presence_stefan",
},
{
image: "/assets/teachingbirds/background_square.png",
elements: [
{
state_image: {
on: "/assets/teachingbirds/radiator_on.jpg",
off: "/assets/teachingbirds/radiator_off.jpg",
},
type: "image",
style: {
width: "100%",
top: "50%",
left: "50%",
},
tap_action: {
action: "more-info",
},
entity: "switch.stefan_radiator_3",
},
{
style: {
top: "90%",
left: "50%",
},
type: "state-label",
entity: "sensor.temperature_stefan",
},
],
type: "picture-elements",
},
{
image: "/assets/teachingbirds/background_square.png",
elements: [
{
style: {
"--mdc-icon-size": "100%",
top: "50%",
left: "50%",
},
type: "icon",
tap_action: {
action: "navigate",
navigation_path: "/lovelace/home_info",
},
icon: "mdi:car",
},
],
type: "picture-elements",
},
],
type: "horizontal-stack",
},
{
cards: [
{
show_name: false,
type: "picture-entity",
name: "Alarm",
image: "/assets/teachingbirds/House_square.jpg",
entity: "alarm_control_panel.house",
},
{
name: "Roomba",
image: "/assets/teachingbirds/roomba_square.jpg",
show_name: false,
type: "picture-entity",
state_image: {
"Not Today": "/assets/teachingbirds/roomba_bw_square.jpg",
},
entity: "input_select.roomba_mode",
},
{
show_name: false,
type: "picture-entity",
state_image: {
Mail: "/assets/teachingbirds/mailbox_square.jpg",
"Package and mail":
"/assets/teachingbirds/mailbox_square.jpg",
Empty: "/assets/teachingbirds/mailbox_bw_square.jpg",
Package: "/assets/teachingbirds/mailbox_square.jpg",
},
entity: "sensor.mailbox",
},
{
show_name: false,
state_image: {
"Put out": "/assets/teachingbirds/trash_square.jpg",
"Take in": "/assets/teachingbirds/trash_square.jpg",
},
type: "picture-entity",
image: "/assets/teachingbirds/trash_bear_bw_square.jpg",
entity: "sensor.trash_status",
},
],
type: "horizontal-stack",
},
{
cards: [
{
state_image: {
Idle: "/assets/teachingbirds/washer_square.jpg",
Running: "/assets/teachingbirds/laundry_running_square.jpg",
Clean: "/assets/teachingbirds/laundry_clean_2_square.jpg",
},
entity: "input_select.washing_machine_status",
type: "picture-entity",
show_name: false,
name: "Washer",
},
{
state_image: {
Idle: "/assets/teachingbirds/dryer_square.jpg",
Running: "/assets/teachingbirds/clothes_drying_square.jpg",
Clean: "/assets/teachingbirds/folded_clothes_square.jpg",
},
entity: "input_select.dryer_status",
type: "picture-entity",
show_name: false,
name: "Dryer",
},
{
image: "/assets/teachingbirds/guests_square.jpg",
type: "picture-entity",
show_name: false,
tap_action: {
action: "toggle",
},
entity: "input_boolean.guest_mode",
},
{
image: "/assets/teachingbirds/cleaning_square.jpg",
type: "picture-entity",
show_name: false,
tap_action: {
action: "toggle",
},
entity: "input_boolean.cleaning_day",
},
],
type: "horizontal-stack",
},
],
type: "vertical-stack",
},
{
type: "vertical-stack",
cards: [
{
cards: [
{
graph: "line",
type: "sensor",
entity: "sensor.temperature_bedroom",
},
{
graph: "line",
type: "sensor",
name: "S's room",
type: "state-label",
entity: "sensor.temperature_stefan",
},
],
type: "horizontal-stack",
type: "picture-elements",
},
{
cards: [
image: "/assets/teachingbirds/background_square.png",
elements: [
{
graph: "line",
type: "sensor",
entity: "sensor.temperature_passage",
},
{
graph: "line",
type: "sensor",
name: "Laundry",
entity: "sensor.temperature_downstairs_bathroom",
style: {
"--mdc-icon-size": "100%",
top: "50%",
left: "50%",
},
type: "icon",
tap_action: {
action: "navigate",
navigation_path: "/lovelace/home_info",
},
icon: "mdi:car",
},
],
type: "horizontal-stack",
type: "picture-elements",
},
{
show_name: false,
type: "picture-entity",
name: "Alarm",
image: "/assets/teachingbirds/House_square.jpg",
entity: "alarm_control_panel.house",
},
{
name: "Roomba",
image: "/assets/teachingbirds/roomba_square.jpg",
show_name: false,
type: "picture-entity",
state_image: {
"Not Today": "/assets/teachingbirds/roomba_bw_square.jpg",
},
entity: "input_select.roomba_mode",
},
{
show_name: false,
type: "picture-entity",
state_image: {
Mail: "/assets/teachingbirds/mailbox_square.jpg",
"Package and mail": "/assets/teachingbirds/mailbox_square.jpg",
Empty: "/assets/teachingbirds/mailbox_bw_square.jpg",
Package: "/assets/teachingbirds/mailbox_square.jpg",
},
entity: "sensor.mailbox",
},
{
show_name: false,
state_image: {
"Put out": "/assets/teachingbirds/trash_square.jpg",
"Take in": "/assets/teachingbirds/trash_square.jpg",
},
type: "picture-entity",
image: "/assets/teachingbirds/trash_bear_bw_square.jpg",
entity: "sensor.trash_status",
},
{
state_image: {
Idle: "/assets/teachingbirds/washer_square.jpg",
Running: "/assets/teachingbirds/laundry_running_square.jpg",
Clean: "/assets/teachingbirds/laundry_clean_2_square.jpg",
},
entity: "input_select.washing_machine_status",
type: "picture-entity",
show_name: false,
name: "Washer",
},
{
state_image: {
Idle: "/assets/teachingbirds/dryer_square.jpg",
Running: "/assets/teachingbirds/clothes_drying_square.jpg",
Clean: "/assets/teachingbirds/folded_clothes_square.jpg",
},
entity: "input_select.dryer_status",
type: "picture-entity",
show_name: false,
name: "Dryer",
},
{
image: "/assets/teachingbirds/guests_square.jpg",
type: "picture-entity",
show_name: false,
tap_action: {
action: "toggle",
},
entity: "input_boolean.guest_mode",
},
{
image: "/assets/teachingbirds/cleaning_square.jpg",
type: "picture-entity",
show_name: false,
tap_action: {
action: "toggle",
},
entity: "input_boolean.cleaning_day",
},
],
},
{
type: "grid",
columns: 2,
cards: [
{
graph: "line",
type: "sensor",
entity: "sensor.temperature_bedroom",
},
{
graph: "line",
type: "sensor",
name: "S's room",
entity: "sensor.temperature_stefan",
},
{
graph: "line",
type: "sensor",
entity: "sensor.temperature_passage",
},
{
graph: "line",
type: "sensor",
name: "Laundry",
entity: "sensor.temperature_downstairs_bathroom",
},
],
},
+1 -1
View File
@@ -9,5 +9,5 @@ export interface DemoConfig {
authorUrl: string;
lovelace: (localize: LocalizeFunc) => LovelaceConfig;
entities: (localize: LocalizeFunc) => Entity[];
theme: () => { [key: string]: string } | null;
theme: () => Record<string, string> | null;
}
+1 -3
View File
@@ -7,7 +7,5 @@ import "./ha-demo";
/* polyfill for paper-dropdown */
setTimeout(() => {
import(
/* webpackChunkName: "polyfill-web-animations-next" */ "web-animations-js/web-animations-next-lite.min"
);
import("web-animations-js/web-animations-next-lite.min");
}, 1000);
+7
View File
@@ -6,4 +6,11 @@ export const mockTemplate = (hass: MockHomeAssistant) => {
body: { message: "Template dev tool does not work in the demo." },
})
);
hass.mockWS("render_template", (msg, onChange) => {
onChange!({
result: msg.template,
listeners: { all: false, domains: [], entities: [], time: false },
});
return () => {};
});
};
Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

+3 -2
View File
@@ -21,15 +21,16 @@ class DemoCard extends PolymerElement {
}
pre {
width: 400px;
margin: 16px;
margin: 0 16px;
overflow: auto;
color: var(--primary-text-color);
}
@media only screen and (max-width: 800px) {
.root {
flex-direction: column;
}
pre {
margin-left: 0;
margin: 16px 0;
}
}
</style>
+27 -8
View File
@@ -5,11 +5,16 @@ import { PolymerElement } from "@polymer/polymer/polymer-element";
import "../../../src/components/ha-switch";
import "../../../src/components/ha-formfield";
import "./demo-card";
import { applyThemesOnElement } from "../../../src/common/dom/apply_themes_on_element";
class DemoCards extends PolymerElement {
static get template() {
return html`
<style>
#container {
min-height: calc(100vh - 128px);
background: var(--primary-background-color);
}
.cards {
display: flex;
flex-wrap: wrap;
@@ -24,6 +29,9 @@ class DemoCards extends PolymerElement {
.filters {
margin-left: 60px;
}
ha-formfield {
margin-right: 16px;
}
</style>
<app-toolbar>
<div class="filters">
@@ -31,16 +39,21 @@ class DemoCards extends PolymerElement {
<ha-switch checked="[[_showConfig]]" on-change="_showConfigToggled">
</ha-switch>
</ha-formfield>
<ha-formfield label="Dark theme">
<ha-switch on-change="_darkThemeToggled"> </ha-switch>
</ha-formfield>
</div>
</app-toolbar>
<div class="cards">
<template is="dom-repeat" items="[[configs]]">
<demo-card
config="[[item]]"
show-config="[[_showConfig]]"
hass="[[hass]]"
></demo-card>
</template>
<div id="container">
<div class="cards">
<template is="dom-repeat" items="[[configs]]">
<demo-card
config="[[item]]"
show-config="[[_showConfig]]"
hass="[[hass]]"
></demo-card>
</template>
</div>
</div>
`;
}
@@ -59,6 +72,12 @@ class DemoCards extends PolymerElement {
_showConfigToggled(ev) {
this._showConfig = ev.target.checked;
}
_darkThemeToggled(ev) {
applyThemesOnElement(this.$.container, { themes: {} }, "default", {
dark: ev.target.checked,
});
}
}
customElements.define("demo-cards", DemoCards);
+31 -30
View File
@@ -3,60 +3,61 @@ import { html } from "@polymer/polymer/lib/utils/html-tag";
import { PolymerElement } from "@polymer/polymer/polymer-element";
import "../../../src/components/ha-card";
import "../../../src/state-summary/state-card-content";
import "./more-info-content";
import "../../../src/dialogs/more-info/more-info-content";
class DemoMoreInfo extends PolymerElement {
static get template() {
return html`
<style>
:host {
.root {
display: flex;
align-items: start;
}
#card {
max-width: 400px;
width: 100vw;
}
ha-card {
width: 333px;
width: 352px;
padding: 20px 24px;
}
state-card-content {
display: block;
padding: 16px;
margin-bottom: 16px;
}
more-info-content {
padding: 0 16px;
}
pre {
width: 400px;
margin: 16px;
margin: 0 16px;
overflow: auto;
color: var(--primary-text-color);
}
@media only screen and (max-width: 800px) {
:host {
.root {
flex-direction: column;
}
pre {
margin-left: 0;
margin: 16px 0;
}
}
</style>
<ha-card>
<state-card-content
state-obj="[[_stateObj]]"
hass="[[hass]]"
in-dialog
></state-card-content>
<div class="root">
<div id="card">
<ha-card>
<state-card-content
state-obj="[[_stateObj]]"
hass="[[hass]]"
in-dialog
></state-card-content>
<more-info-content
hass="[[hass]]"
state-obj="[[_stateObj]]"
></more-info-content>
</ha-card>
<template is="dom-if" if="[[showConfig]]">
<pre>[[_jsonEntity(_stateObj)]]</pre>
</template>
<more-info-content
hass="[[hass]]"
state-obj="[[_stateObj]]"
></more-info-content>
</ha-card>
</div>
<template is="dom-if" if="[[showConfig]]">
<pre>[[_jsonEntity(_stateObj)]]</pre>
</template>
</div>
`;
}
+36 -9
View File
@@ -3,12 +3,18 @@ import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import "../../../src/components/ha-switch";
import "../../../src/components/ha-formfield";
import "./demo-more-info";
import { applyThemesOnElement } from "../../../src/common/dom/apply_themes_on_element";
class DemoMoreInfos extends PolymerElement {
static get template() {
return html`
<style>
#container {
min-height: calc(100vh - 128px);
background: var(--primary-background-color);
}
.cards {
display: flex;
flex-wrap: wrap;
@@ -23,20 +29,31 @@ class DemoMoreInfos extends PolymerElement {
.filters {
margin-left: 60px;
}
ha-formfield {
margin-right: 16px;
}
</style>
<app-toolbar>
<div class="filters">
<ha-switch checked="{{_showConfig}}">Show entity</ha-switch>
<ha-formfield label="Show entities">
<ha-switch checked="[[_showConfig]]" on-change="_showConfigToggled">
</ha-switch>
</ha-formfield>
<ha-formfield label="Dark theme">
<ha-switch on-change="_darkThemeToggled"> </ha-switch>
</ha-formfield>
</div>
</app-toolbar>
<div class="cards">
<template is="dom-repeat" items="[[entities]]">
<demo-more-info
entity-id="[[item]]"
show-config="[[_showConfig]]"
hass="[[hass]]"
></demo-more-info>
</template>
<div id="container">
<div class="cards">
<template is="dom-repeat" items="[[entities]]">
<demo-more-info
entity-id="[[item]]"
show-config="[[_showConfig]]"
hass="[[hass]]"
></demo-more-info>
</template>
</div>
</div>
`;
}
@@ -51,6 +68,16 @@ class DemoMoreInfos extends PolymerElement {
},
};
}
_showConfigToggled(ev) {
this._showConfig = ev.target.checked;
}
_darkThemeToggled(ev) {
applyThemesOnElement(this.$.container, { themes: {} }, "default", {
dark: ev.target.checked,
});
}
}
customElements.define("demo-more-infos", DemoMoreInfos);
@@ -1,73 +0,0 @@
import { HassEntity } from "home-assistant-js-websocket";
import { property, PropertyValues, UpdatingElement } from "lit-element";
import dynamicContentUpdater from "../../../src/common/dom/dynamic_content_updater";
import { stateMoreInfoType } from "../../../src/dialogs/more-info/state_more_info_control";
import "../../../src/dialogs/more-info/controls/more-info-alarm_control_panel";
import "../../../src/dialogs/more-info/controls/more-info-automation";
import "../../../src/dialogs/more-info/controls/more-info-camera";
import "../../../src/dialogs/more-info/controls/more-info-climate";
import "../../../src/dialogs/more-info/controls/more-info-configurator";
import "../../../src/dialogs/more-info/controls/more-info-counter";
import "../../../src/dialogs/more-info/controls/more-info-cover";
import "../../../src/dialogs/more-info/controls/more-info-default";
import "../../../src/dialogs/more-info/controls/more-info-fan";
import "../../../src/dialogs/more-info/controls/more-info-group";
import "../../../src/dialogs/more-info/controls/more-info-humidifier";
import "../../../src/dialogs/more-info/controls/more-info-input_datetime";
import "../../../src/dialogs/more-info/controls/more-info-light";
import "../../../src/dialogs/more-info/controls/more-info-lock";
import "../../../src/dialogs/more-info/controls/more-info-media_player";
import "../../../src/dialogs/more-info/controls/more-info-person";
import "../../../src/dialogs/more-info/controls/more-info-script";
import "../../../src/dialogs/more-info/controls/more-info-sun";
import "../../../src/dialogs/more-info/controls/more-info-timer";
import "../../../src/dialogs/more-info/controls/more-info-vacuum";
import "../../../src/dialogs/more-info/controls/more-info-water_heater";
import "../../../src/dialogs/more-info/controls/more-info-weather";
import { HomeAssistant } from "../../../src/types";
class MoreInfoContent extends UpdatingElement {
@property({ attribute: false }) public hass?: HomeAssistant;
@property() public stateObj?: HassEntity;
private _detachedChild?: ChildNode;
protected firstUpdated(): void {
this.style.position = "relative";
this.style.display = "block";
}
// This is not a lit element, but an updating element, so we implement update
protected update(changedProps: PropertyValues): void {
super.update(changedProps);
const stateObj = this.stateObj;
const hass = this.hass;
if (!stateObj || !hass) {
if (this.lastChild) {
this._detachedChild = this.lastChild;
// Detach child to prevent it from doing work.
this.removeChild(this.lastChild);
}
return;
}
if (this._detachedChild) {
this.appendChild(this._detachedChild);
this._detachedChild = undefined;
}
const moreInfoType =
stateObj.attributes && "custom_ui_more_info" in stateObj.attributes
? stateObj.attributes.custom_ui_more_info
: "more-info-" + stateMoreInfoType(stateObj);
dynamicContentUpdater(this, moreInfoType.toUpperCase(), {
hass,
stateObj,
});
}
}
customElements.define("more-info-content", MoreInfoContent);
+90 -9
View File
@@ -6,6 +6,8 @@ export const createMediaPlayerEntities = () => [
media_content_type: "music",
media_title: "I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)",
media_artist: "Technohead",
// Pause + Seek + Volume Set + Volume Mute + Previous Track + Next Track + Play Media +
// Select Source + Stop + Clear + Play + Shuffle Set
supported_features: 64063,
entity_picture: "/images/album_cover_2.jpg",
media_duration: 300,
@@ -14,13 +16,16 @@ export const createMediaPlayerEntities = () => [
// 23 seconds in
new Date().getTime() - 23000
).toISOString(),
volume_level: 0.5,
}),
getEntity("media_player", "music_playing", "playing", {
friendly_name: "Playing The Music",
media_content_type: "music",
media_title: "I Wanna Be A Hippy (Flamman & Abraxas Radio Mix)",
media_artist: "Technohead",
supported_features: 64063,
// Pause + Seek + Volume Set + Volume Mute + Previous Track + Next Track + Play Media +
// Select Source + Stop + Clear + Play + Shuffle Set + Browse Media
supported_features: 195135,
entity_picture: "/images/album_cover.jpg",
media_duration: 300,
media_position: 0,
@@ -28,6 +33,7 @@ export const createMediaPlayerEntities = () => [
// 23 seconds in
new Date().getTime() - 23000
).toISOString(),
volume_level: 0.5,
}),
getEntity("media_player", "stream_playing", "playing", {
friendly_name: "Playing the Stream",
@@ -35,50 +41,125 @@ export const createMediaPlayerEntities = () => [
media_title: "Epic sax guy 10 hours",
app_name: "YouTube",
entity_picture: "/images/frenck.jpg",
supported_features: 33,
// Pause + Next Track + Play + Browse Media
supported_features: 147489,
}),
getEntity("media_player", "living_room", "playing", {
friendly_name: "Pause, No skip, tvshow",
getEntity("media_player", "stream_paused", "paused", {
friendly_name: "Paused the Stream",
media_content_type: "movie",
media_title: "Epic sax guy 10 hours",
app_name: "YouTube",
entity_picture: "/images/frenck.jpg",
// Pause + Next Track + Play
supported_features: 16417,
}),
getEntity("media_player", "stream_playing_previous", "playing", {
friendly_name: 'Playing the Stream (with "previous" support)',
media_content_type: "movie",
media_title: "Epic sax guy 10 hours",
app_name: "YouTube",
entity_picture: "/images/frenck.jpg",
// Pause + Previous Track + Play
supported_features: 16401,
}),
getEntity("media_player", "tv_playing", "playing", {
friendly_name: "Playing non-skip TV Show",
media_content_type: "tvshow",
media_title: "Chapter 1",
media_series_title: "House of Cards",
app_name: "Netflix",
entity_picture: "/images/netflix.jpg",
// Pause
supported_features: 1,
}),
getEntity("media_player", "sonos_idle", "idle", {
friendly_name: "Sonos Idle",
// Pause + Seek + Volume Set + Volume Mute + Previous Track + Next Track + Play Media +
// Select Source + Stop + Clear + Play + Shuffle Set
supported_features: 64063,
volume_level: 0.33,
is_volume_muted: true,
}),
getEntity("media_player", "theater", "off", {
getEntity("media_player", "idle_browse_media", "idle", {
friendly_name: "Idle waiting for Browse Media (e.g. Spotify)",
// Pause + Seek + Volume Set + Previous Track + Next Track + Play Media +
// Select Source + Play + Shuffle Set + Browse Media
supported_features: 182839,
volume_level: 0.79,
}),
getEntity("media_player", "theater_off", "off", {
friendly_name: "TV Off",
// On + Off + Play + Next + Pause
supported_features: 16801,
}),
getEntity("media_player", "theater_on", "on", {
friendly_name: "TV On",
// On + Off + Play + Next + Pause
supported_features: 16801,
}),
getEntity("media_player", "theater_off_static", "off", {
friendly_name: "TV Off (cannot be switched on)",
// Off + Next + Pause
supported_features: 289,
}),
getEntity("media_player", "theater_on_static", "on", {
friendly_name: "TV On (cannot be switched off)",
// On + Next + Pause
supported_features: 161,
}),
getEntity("media_player", "android_cast", "playing", {
friendly_name: "Casting App",
friendly_name: "Casting App (no supported features)",
media_title: "Android Screen Casting",
app_name: "Screen Mirroring",
// supported_features: 21437,
}),
getEntity("media_player", "image_display", "playing", {
friendly_name: "Digital Picture Frame",
media_content_type: "image",
media_title: "Famous Painting",
media_artist: "Famous Artist",
entity_picture: "/images/sunflowers.jpg",
// On + Off + Browse Media
supported_features: 131456,
}),
getEntity("media_player", "unavailable", "unavailable", {
friendly_name: "Player Unavailable",
// Pause + Volume Set + Volume Mute + Previous Track + Next Track +
// Play Media + Stop + Play
supported_features: 21437,
}),
getEntity("media_player", "unknown", "unknown", {
friendly_name: "Player Unknown",
// Pause + Volume Set + Volume Mute + Previous Track + Next Track +
// Play Media + Stop + Play
supported_features: 21437,
}),
getEntity("media_player", "playing", "playing", {
friendly_name: "Player Playing (no Pause support)",
// Volume Set + Volume Mute + Previous Track + Next Track +
// Play Media + Stop + Play
supported_features: 21436,
volume_level: 1,
}),
getEntity("media_player", "idle", "idle", {
friendly_name: "Player Idle",
// Pause + Volume Set + Volume Mute + Previous Track + Next Track +
// Play Media + Stop + Play
supported_features: 21437,
volume_level: 0,
}),
getEntity("media_player", "receiver_on", "on", {
source_list: ["AirPlay", "Blu-Ray", "TV", "USB", "iPod (USB)"],
volume_level: 0.63,
is_volume_muted: false,
source: "TV",
friendly_name: "Receiver",
friendly_name: "Receiver (selectable sources)",
// Volume Set + Volume Mute + On + Off + Select Source + Play + Sound Mode
supported_features: 84364,
}),
getEntity("media_player", "receiver_off", "off", {
source_list: ["AirPlay", "Blu-Ray", "TV", "USB", "iPod (USB)"],
friendly_name: "Receiver",
friendly_name: "Receiver (selectable sources)",
// Volume Set + Volume Mute + On + Off + Select Source + Play + Sound Mode
supported_features: 84364,
}),
];
+72
View File
@@ -0,0 +1,72 @@
import { getEntity } from "../../../src/fake_data/entity";
export const createPlantEntities = () => [
getEntity("plant", "lemon_tree", "ok", {
problem: "none",
sensors: {
moisture: "sensor.lemon_tree_moisture",
battery: "sensor.lemon_tree_battery",
temperature: "sensor.lemon_tree_temperature",
conductivity: "sensor.lemon_tree_conductivity",
brightness: "sensor.lemon_tree_brightness",
},
unit_of_measurement_dict: {
temperature: "°C",
moisture: "%",
brightness: "lx",
battery: "%",
conductivity: "μS/cm",
},
moisture: 54,
battery: 95,
temperature: 15.6,
conductivity: 1,
brightness: 12,
max_brightness: 20,
friendly_name: "Lemon Tree",
}),
getEntity("plant", "apple_tree", "ok", {
problem: "brightness",
sensors: {
moisture: "sensor.apple_tree_moisture",
battery: "sensor.apple_tree_battery",
temperature: "sensor.apple_tree_temperature",
conductivity: "sensor.apple_tree_conductivity",
brightness: "sensor.apple_tree_brightness",
},
unit_of_measurement_dict: {
temperature: "°C",
moisture: "%",
brightness: "lx",
battery: "%",
conductivity: "μS/cm",
},
moisture: 54,
battery: 2,
temperature: 15.6,
conductivity: 1,
brightness: 25,
max_brightness: 20,
friendly_name: "Apple Tree",
}),
getEntity("plant", "sunflowers", "ok", {
problem: "moisture, temperature, conductivity",
sensors: {
moisture: "sensor.sunflowers_moisture",
temperature: "sensor.sunflowers_temperature",
conductivity: "sensor.sunflowers_conductivity",
brightness: "sensor.sunflowers_brightness",
},
unit_of_measurement_dict: {
temperature: "°C",
moisture: "%",
brightness: "lx",
conductivity: "μS/cm",
},
moisture: 54,
temperature: 15.6,
conductivity: 1,
brightness: 25,
entity_picture: "/images/sunflowers.jpg",
}),
];
+30 -26
View File
@@ -1,6 +1,11 @@
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import {
html,
LitElement,
customElement,
PropertyValues,
query,
TemplateResult,
} from "lit-element";
import { getEntity } from "../../../src/fake_data/entity";
import { provideHass } from "../../../src/fake_data/provide_hass";
import "../components/demo-cards";
@@ -15,6 +20,10 @@ const ENTITIES = [
getEntity("alarm_control_panel", "unavailable", "unavailable", {
friendly_name: "Alarm",
}),
getEntity("alarm_control_panel", "alarm_code", "disarmed", {
friendly_name: "Alarm",
code_format: "number",
}),
];
const CONFIGS = [
@@ -30,7 +39,14 @@ const CONFIGS = [
config: `
- type: alarm-panel
entity: alarm_control_panel.alarm_armed
title: My Alarm
name: My Alarm
`,
},
{
heading: "Code Example",
config: `
- type: alarm-panel
entity: alarm_control_panel.alarm_code
`,
},
{
@@ -60,31 +76,19 @@ const CONFIGS = [
},
];
class DemoAlarmPanelEntity extends PolymerElement {
static get template() {
return html`
<demo-cards
id="demos"
hass="[[hass]]"
configs="[[_configs]]"
></demo-cards>
`;
@customElement("demo-hui-alarm-panel-card")
class DemoAlarmPanelEntity extends LitElement {
@query("#demos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
}
static get properties() {
return {
_configs: {
type: Object,
value: CONFIGS,
},
hass: Object,
};
}
public ready() {
super.ready();
const hass = provideHass(this.$.demos);
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
const hass = provideHass(this._demoRoot);
hass.updateTranslations(null, "en");
hass.updateTranslations("lovelace", "en");
hass.addEntities(ENTITIES);
}
}
+18 -25
View File
@@ -1,6 +1,11 @@
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import {
html,
LitElement,
customElement,
PropertyValues,
query,
TemplateResult,
} from "lit-element";
import { getEntity } from "../../../src/fake_data/entity";
import { provideHass } from "../../../src/fake_data/provide_hass";
import "../components/demo-cards";
@@ -53,31 +58,19 @@ const CONFIGS = [
},
];
class DemoConditional extends PolymerElement {
static get template() {
return html`
<demo-cards
id="demos"
hass="[[hass]]"
configs="[[_configs]]"
></demo-cards>
`;
@customElement("demo-hui-conditional-card")
class DemoConditional extends LitElement {
@query("#demos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
}
static get properties() {
return {
_configs: {
type: Object,
value: CONFIGS,
},
hass: Object,
};
}
public ready() {
super.ready();
const hass = provideHass(this.$.demos);
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
const hass = provideHass(this._demoRoot);
hass.updateTranslations(null, "en");
hass.updateTranslations("lovelace", "en");
hass.addEntities(ENTITIES);
}
}
+18 -18
View File
@@ -1,6 +1,11 @@
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import {
html,
LitElement,
customElement,
PropertyValues,
query,
TemplateResult,
} from "lit-element";
import { getEntity } from "../../../src/fake_data/entity";
import { provideHass } from "../../../src/fake_data/provide_hass";
import "../components/demo-cards";
@@ -217,24 +222,19 @@ const CONFIGS = [
},
];
class DemoEntities extends PolymerElement {
static get template() {
return html` <demo-cards id="demos" configs="[[_configs]]"></demo-cards> `;
@customElement("demo-hui-entities-card")
class DemoEntities extends LitElement {
@query("#demos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
}
static get properties() {
return {
_configs: {
type: Object,
value: CONFIGS,
},
};
}
public ready() {
super.ready();
const hass = provideHass(this.$.demos);
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
const hass = provideHass(this._demoRoot);
hass.updateTranslations(null, "en");
hass.updateTranslations("lovelace", "en");
hass.addEntities(ENTITIES);
}
}
@@ -1,6 +1,11 @@
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import {
html,
LitElement,
customElement,
PropertyValues,
query,
TemplateResult,
} from "lit-element";
import { getEntity } from "../../../src/fake_data/entity";
import { provideHass } from "../../../src/fake_data/provide_hass";
import "../components/demo-cards";
@@ -20,10 +25,10 @@ const CONFIGS = [
`,
},
{
heading: "With Name",
heading: "With Name (defined in card)",
config: `
- type: button
name: Bedroom
name: Custom Name
entity: light.bed_light
`,
},
@@ -32,7 +37,7 @@ const CONFIGS = [
config: `
- type: button
entity: light.bed_light
icon: mdi:hotel
icon: mdi:tools
`,
},
{
@@ -69,33 +74,21 @@ const CONFIGS = [
},
];
class DemoButtonEntity extends PolymerElement {
static get template() {
return html`
<demo-cards
id="demos"
hass="[[hass]]"
configs="[[_configs]]"
></demo-cards>
`;
@customElement("demo-hui-entity-button-card")
class DemoButtonEntity extends LitElement {
@query("#demos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
}
static get properties() {
return {
_configs: {
type: Object,
value: CONFIGS,
},
hass: Object,
};
}
public ready() {
super.ready();
const hass = provideHass(this.$.demos);
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
const hass = provideHass(this._demoRoot);
hass.updateTranslations(null, "en");
hass.updateTranslations("lovelace", "en");
hass.addEntities(ENTITIES);
}
}
customElements.define("demo-hui-button-card", DemoButtonEntity);
customElements.define("demo-hui-entity-button-card", DemoButtonEntity);
@@ -1,6 +1,11 @@
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import {
html,
LitElement,
customElement,
PropertyValues,
query,
TemplateResult,
} from "lit-element";
import { getEntity } from "../../../src/fake_data/entity";
import { provideHass } from "../../../src/fake_data/provide_hass";
import "../components/demo-cards";
@@ -89,26 +94,21 @@ const CONFIGS = [
},
];
class DemoFilter extends PolymerElement {
static get template() {
return html` <demo-cards id="demos" configs="[[_configs]]"></demo-cards> `;
@customElement("demo-hui-entity-filter-card")
class DemoEntityFilter extends LitElement {
@query("#demos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
}
static get properties() {
return {
_configs: {
type: Object,
value: CONFIGS,
},
};
}
public ready() {
super.ready();
const hass = provideHass(this.$.demos);
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
const hass = provideHass(this._demoRoot);
hass.updateTranslations(null, "en");
hass.updateTranslations("lovelace", "en");
hass.addEntities(ENTITIES);
}
}
customElements.define("demo-hui-entity-filter-card", DemoFilter);
customElements.define("demo-hui-entity-filter-card", DemoEntityFilter);
+60 -29
View File
@@ -1,13 +1,21 @@
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import {
html,
LitElement,
customElement,
PropertyValues,
query,
TemplateResult,
} from "lit-element";
import { getEntity } from "../../../src/fake_data/entity";
import { provideHass } from "../../../src/fake_data/provide_hass";
import "../components/demo-cards";
const ENTITIES = [
getEntity("sensor", "brightness", "12", {}),
getEntity("sensor", "brightness_medium", "53", {}),
getEntity("sensor", "brightness_high", "87", {}),
getEntity("plant", "bonsai", "ok", {}),
getEntity("sensor", "not_working", "unavailable", {}),
getEntity("sensor", "outside_humidity", "54", {
unit_of_measurement: "%",
}),
@@ -20,16 +28,10 @@ const CONFIGS = [
{
heading: "Basic example",
config: `
- type: gauge
entity: sensor.brightness
`,
},
{
heading: "With title",
config: `
- type: gauge
title: Humidity
entity: sensor.outside_humidity
name: Outside Humidity
`,
},
{
@@ -38,6 +40,7 @@ const CONFIGS = [
- type: gauge
entity: sensor.outside_temperature
unit_of_measurement: C
name: Outside Temperature
`,
},
{
@@ -45,19 +48,45 @@ const CONFIGS = [
config: `
- type: gauge
entity: sensor.brightness
name: Brightness Low
severity:
red: 32
red: 75
green: 0
yellow: 23
yellow: 50
`,
},
{
heading: "Setting Min and Max Values",
heading: "Setting Severity Levels",
config: `
- type: gauge
entity: sensor.brightness_medium
name: Brightness Medium
severity:
red: 75
green: 0
yellow: 50
`,
},
{
heading: "Setting Severity Levels",
config: `
- type: gauge
entity: sensor.brightness_high
name: Brightness High
severity:
red: 75
green: 0
yellow: 50
`,
},
{
heading: "Setting Min (0) and Max (15) Values",
config: `
- type: gauge
entity: sensor.brightness
name: Brightness
min: 0
max: 38
max: 15
`,
},
{
@@ -74,26 +103,28 @@ const CONFIGS = [
entity: plant.bonsai
`,
},
{
heading: "Unavailable entity",
config: `
- type: gauge
entity: sensor.not_working
`,
},
];
class DemoGaugeEntity extends PolymerElement {
static get template() {
return html` <demo-cards id="demos" configs="[[_configs]]"></demo-cards> `;
@customElement("demo-hui-gauge-card")
class DemoGaugeEntity extends LitElement {
@query("#demos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
}
static get properties() {
return {
_configs: {
type: Object,
value: CONFIGS,
},
};
}
public ready() {
super.ready();
const hass = provideHass(this.$.demos);
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
const hass = provideHass(this._demoRoot);
hass.updateTranslations(null, "en");
hass.updateTranslations("lovelace", "en");
hass.addEntities(ENTITIES);
}
}
+19 -19
View File
@@ -1,6 +1,11 @@
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import {
html,
LitElement,
customElement,
PropertyValues,
query,
TemplateResult,
} from "lit-element";
import { getEntity } from "../../../src/fake_data/entity";
import { provideHass } from "../../../src/fake_data/provide_hass";
import "../components/demo-cards";
@@ -218,26 +223,21 @@ const CONFIGS = [
},
];
class DemoPicEntity extends PolymerElement {
static get template() {
return html` <demo-cards id="demos" configs="[[_configs]]"></demo-cards> `;
@customElement("demo-hui-glance-card")
class DemoGlanceEntity extends LitElement {
@query("#demos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
}
static get properties() {
return {
_configs: {
type: Object,
value: CONFIGS,
},
};
}
public ready() {
super.ready();
const hass = provideHass(this.$.demos);
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
const hass = provideHass(this._demoRoot);
hass.updateTranslations(null, "en");
hass.updateTranslations("lovelace", "en");
hass.addEntities(ENTITIES);
}
}
customElements.define("demo-hui-glance-card", DemoPicEntity);
customElements.define("demo-hui-glance-card", DemoGlanceEntity);
+5 -15
View File
@@ -1,6 +1,4 @@
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import { html, LitElement, customElement, TemplateResult } from "lit-element";
import "../components/demo-cards";
const CONFIGS = [
@@ -37,18 +35,10 @@ const CONFIGS = [
},
];
class DemoIframe extends PolymerElement {
static get template() {
return html` <demo-cards configs="[[_configs]]"></demo-cards> `;
}
static get properties() {
return {
_configs: {
type: Object,
value: CONFIGS,
},
};
@customElement("demo-hui-iframe-card")
class DemoIframe extends LitElement {
protected render(): TemplateResult {
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
}
}
+37 -23
View File
@@ -1,6 +1,11 @@
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import {
html,
LitElement,
customElement,
PropertyValues,
query,
TemplateResult,
} from "lit-element";
import { getEntity } from "../../../src/fake_data/entity";
import { provideHass } from "../../../src/fake_data/provide_hass";
import "../components/demo-cards";
@@ -8,29 +13,43 @@ import "../components/demo-cards";
const ENTITIES = [
getEntity("light", "bed_light", "on", {
friendly_name: "Bed Light",
brightness: 130,
brightness: 255,
}),
getEntity("light", "dim", "off", {
getEntity("light", "dim_on", "on", {
friendly_name: "Dining Room",
supported_features: 1,
brightness: 100,
}),
getEntity("light", "dim_off", "off", {
friendly_name: "Dining Room",
supported_features: 1,
}),
getEntity("light", "unavailable", "unavailable", {
friendly_name: "Lost Light",
supported_features: 1,
}),
];
const CONFIGS = [
{
heading: "Basic example",
heading: "Switchable Light",
config: `
- type: light
entity: light.bed_light
`,
},
{
heading: "Dim",
heading: "Dimmable Light On",
config: `
- type: light
entity: light.dim
entity: light.dim_on
`,
},
{
heading: "Dimmable Light Off",
config: `
- type: light
entity: light.dim_off
`,
},
{
@@ -49,24 +68,19 @@ const CONFIGS = [
},
];
class DemoLightEntity extends PolymerElement {
static get template() {
return html` <demo-cards id="demos" configs="[[_configs]]"></demo-cards> `;
@customElement("demo-hui-light-card")
class DemoLightEntity extends LitElement {
@query("#demos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
}
static get properties() {
return {
_configs: {
type: Object,
value: CONFIGS,
},
};
}
public ready() {
super.ready();
const hass = provideHass(this.$.demos);
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
const hass = provideHass(this._demoRoot);
hass.updateTranslations(null, "en");
hass.updateTranslations("lovelace", "en");
hass.addEntities(ENTITIES);
}
}
+18 -25
View File
@@ -1,6 +1,11 @@
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import {
html,
LitElement,
customElement,
PropertyValues,
query,
TemplateResult,
} from "lit-element";
import { getEntity } from "../../../src/fake_data/entity";
import { provideHass } from "../../../src/fake_data/provide_hass";
import "../components/demo-cards";
@@ -161,31 +166,19 @@ const CONFIGS = [
},
];
class DemoMap extends PolymerElement {
static get template() {
return html`
<demo-cards
id="demos"
hass="[[hass]]"
configs="[[_configs]]"
></demo-cards>
`;
@customElement("demo-hui-map-card")
class DemoMap extends LitElement {
@query("#demos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
}
static get properties() {
return {
_configs: {
type: Object,
value: CONFIGS,
},
hass: Object,
};
}
public ready() {
super.ready();
const hass = provideHass(this.$.demos);
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
const hass = provideHass(this._demoRoot);
hass.updateTranslations(null, "en");
hass.updateTranslations("lovelace", "en");
hass.addEntities(ENTITIES);
}
}
+22 -13
View File
@@ -1,6 +1,13 @@
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import {
html,
LitElement,
customElement,
PropertyValues,
query,
TemplateResult,
} from "lit-element";
import { mockTemplate } from "../../../demo/src/stubs/template";
import { provideHass } from "../../../src/fake_data/provide_hass";
import "../components/demo-cards";
const CONFIGS = [
@@ -252,18 +259,20 @@ const CONFIGS = [
},
];
class DemoMarkdown extends PolymerElement {
static get template() {
return html` <demo-cards configs="[[_configs]]"></demo-cards> `;
@customElement("demo-hui-markdown-card")
class DemoMarkdown extends LitElement {
@query("#demos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
}
static get properties() {
return {
_configs: {
type: Object,
value: CONFIGS,
},
};
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
const hass = provideHass(this._demoRoot);
hass.updateTranslations(null, "en");
hass.updateTranslations("lovelace", "en");
mockTemplate(hass);
}
}
+101 -35
View File
@@ -1,46 +1,72 @@
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import {
html,
LitElement,
customElement,
PropertyValues,
query,
TemplateResult,
} from "lit-element";
import { provideHass } from "../../../src/fake_data/provide_hass";
import "../components/demo-cards";
import { createMediaPlayerEntities } from "../data/media_players";
const CONFIGS = [
{
heading: "Paused music",
heading: "Paused Music",
config: `
- type: media-control
entity: media_player.music_paused
`,
},
{
heading: "Playing music",
heading: "Playing Music",
config: `
- type: media-control
entity: media_player.music_playing
`,
},
{
heading: "Playing stream",
heading: "Playing Stream",
config: `
- type: media-control
entity: media_player.stream_playing
`,
},
{
heading: "Pause, No skip, tvshow",
heading: "Paused Stream",
config: `
- type: media-control
entity: media_player.living_room
entity: media_player.stream_paused
`,
},
{
heading: "Screen casting",
heading: 'Playing Stream (with "previous" support)',
config: `
- type: media-control
entity: media_player.stream_playing_previous
`,
},
{
heading: "Playing non-skip TV Show",
config: `
- type: media-control
entity: media_player.tv_playing
`,
},
{
heading: "Screen Casting",
config: `
- type: media-control
entity: media_player.android_cast
`,
},
{
heading: "Digital Picture Frame",
config: `
- type: media-control
entity: media_player.image_display
`,
},
{
heading: "Sonos Idle",
config: `
@@ -48,11 +74,53 @@ const CONFIGS = [
entity: media_player.sonos_idle
`,
},
{
heading: "Idle waiting for Browse Media",
config: `
- type: media-control
entity: media_player.idle_browse_media
`,
},
{
heading: "Player Off",
config: `
- type: media-control
entity: media_player.theater
entity: media_player.theater_off
`,
},
{
heading: "Player On",
config: `
- type: media-control
entity: media_player.theater_on
`,
},
{
heading: "Player Off (cannot be switched on)",
config: `
- type: media-control
entity: media_player.theater_off_static
`,
},
{
heading: "Player On (cannot be switched off)",
config: `
- type: media-control
entity: media_player.theater_on_static
`,
},
{
heading: "Player Idle",
config: `
- type: media-control
entity: media_player.idle
`,
},
{
heading: "Player Playing",
config: `
- type: media-control
entity: media_player.playing
`,
},
{
@@ -70,48 +138,46 @@ const CONFIGS = [
`,
},
{
heading: "Receiver On",
heading: "Receiver On (selectable sources)",
config: `
- type: media-control
entity: media_player.receiver_on
`,
},
{
heading: "Receiver Off",
heading: "Receiver Off (selectable sources)",
config: `
- type: media-control
entity: media_player.receiver_off
`,
},
{
heading: "Grid Full Size",
config: `
- type: grid
columns: 1
cards:
- type: media-control
entity: media_player.music_paused
`,
},
];
class DemoHuiMediControlCard extends PolymerElement {
static get template() {
return html`
<demo-cards
id="demos"
hass="[[hass]]"
configs="[[_configs]]"
></demo-cards>
`;
@customElement("demo-hui-media-control-card")
class DemoHuiMediaControlCard extends LitElement {
@query("#demos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
}
static get properties() {
return {
_configs: {
type: Object,
value: CONFIGS,
},
hass: Object,
};
}
public ready() {
super.ready();
const hass = provideHass(this.$.demos);
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
const hass = provideHass(this._demoRoot);
hass.updateTranslations(null, "en");
hass.updateTranslations("lovelace", "en");
hass.addEntities(createMediaPlayerEntities());
}
}
customElements.define("demo-hui-media-control-card", DemoHuiMediControlCard);
customElements.define("demo-hui-media-control-card", DemoHuiMediaControlCard);
+48 -33
View File
@@ -1,6 +1,11 @@
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import {
html,
LitElement,
customElement,
PropertyValues,
query,
TemplateResult,
} from "lit-element";
import { provideHass } from "../../../src/fake_data/provide_hass";
import "../components/demo-cards";
import { createMediaPlayerEntities } from "../data/media_players";
@@ -12,54 +17,64 @@ const CONFIGS = [
- type: entities
entities:
- entity: media_player.music_paused
name: Paused music
name: Paused Music
- entity: media_player.music_playing
name: Playing music
name: Playing Music
- entity: media_player.stream_playing
name: Paused, no play
- entity: media_player.living_room
name: Pause, No skip, tvshow
name: Playing Stream
- entity: media_player.stream_paused
name: Paused Stream
- entity: media_player.stream_playing_previous
name: Playing Stream (with "previous" support)
- entity: media_player.tv_playing
name: Playing non-skip TV Show
- entity: media_player.android_cast
name: Screen casting
- entity: media_player.image_display
name: Digital Picture Frame
- entity: media_player.sonos_idle
name: Chromcast Idle
- entity: media_player.theater
name: Sonos Idle
- entity: media_player.idle_browse_media
name: Idle waiting for Browse Media
- entity: media_player.theater_off
name: Player Off
- entity: media_player.theater_on
name: Player On
- entity: media_player.theater_off_static
name: Player Off (cannot be switched on)
- entity: media_player.theater_on_static
name: Player On (cannot be switched off)
- entity: media_player.idle
name: Player Idle
- entity: media_player.playing
name: Player Playing
- entity: media_player.unavailable
name: Player Unavailable
- entity: media_player.unknown
name: Player Unknown
- entity: media_player.receiver_on
name: Receiver On (selectable sources)
- entity: media_player.receiver_off
name: Receiver Off (selectable sources)
`,
},
];
class DemoHuiMediaPlayerRows extends PolymerElement {
static get template() {
return html`
<demo-cards
id="demos"
hass="[[hass]]"
configs="[[_configs]]"
></demo-cards>
`;
@customElement("demo-hui-media-player-row")
class DemoHuiMediaPlayerRow extends LitElement {
@query("#demos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
}
static get properties() {
return {
_configs: {
type: Object,
value: CONFIGS,
},
hass: Object,
};
}
public ready() {
super.ready();
const hass = provideHass(this.$.demos);
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
const hass = provideHass(this._demoRoot);
hass.updateTranslations(null, "en");
hass.updateTranslations("lovelace", "en");
hass.addEntities(createMediaPlayerEntities());
}
}
customElements.define("demo-hui-media-player-rows", DemoHuiMediaPlayerRows);
customElements.define("demo-hui-media-player-row", DemoHuiMediaPlayerRow);
@@ -1,6 +1,11 @@
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import {
html,
LitElement,
customElement,
PropertyValues,
query,
TemplateResult,
} from "lit-element";
import { getEntity } from "../../../src/fake_data/entity";
import { provideHass } from "../../../src/fake_data/provide_hass";
import "../components/demo-cards";
@@ -125,26 +130,21 @@ const CONFIGS = [
},
];
class DemoPicElements extends PolymerElement {
static get template() {
return html` <demo-cards id="demos" configs="[[_configs]]"></demo-cards> `;
@customElement("demo-hui-picture-elements-card")
class DemoPictureElements extends LitElement {
@query("#demos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
}
static get properties() {
return {
_configs: {
type: Object,
value: CONFIGS,
},
};
}
public ready() {
super.ready();
const hass = provideHass(this.$.demos);
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
const hass = provideHass(this._demoRoot);
hass.updateTranslations(null, "en");
hass.updateTranslations("lovelace", "en");
hass.addEntities(ENTITIES);
}
}
customElements.define("demo-hui-picture-elements-card", DemoPicElements);
customElements.define("demo-hui-picture-elements-card", DemoPictureElements);
@@ -1,6 +1,11 @@
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import {
html,
LitElement,
customElement,
PropertyValues,
query,
TemplateResult,
} from "lit-element";
import { getEntity } from "../../../src/fake_data/entity";
import { provideHass } from "../../../src/fake_data/provide_hass";
import "../components/demo-cards";
@@ -80,26 +85,21 @@ const CONFIGS = [
},
];
class DemoPicEntity extends PolymerElement {
static get template() {
return html` <demo-cards id="demos" configs="[[_configs]]"></demo-cards> `;
@customElement("demo-hui-picture-entity-card")
class DemoPictureEntity extends LitElement {
@query("#demos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
}
static get properties() {
return {
_configs: {
type: Object,
value: CONFIGS,
},
};
}
public ready() {
super.ready();
const hass = provideHass(this.$.demos);
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
const hass = provideHass(this._demoRoot);
hass.updateTranslations(null, "en");
hass.updateTranslations("lovelace", "en");
hass.addEntities(ENTITIES);
}
}
customElements.define("demo-hui-picture-entity-card", DemoPicEntity);
customElements.define("demo-hui-picture-entity-card", DemoPictureEntity);
@@ -1,6 +1,11 @@
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import {
html,
LitElement,
customElement,
PropertyValues,
query,
TemplateResult,
} from "lit-element";
import { getEntity } from "../../../src/fake_data/entity";
import { provideHass } from "../../../src/fake_data/provide_hass";
import "../components/demo-cards";
@@ -121,26 +126,21 @@ const CONFIGS = [
},
];
class DemoPicGlance extends PolymerElement {
static get template() {
return html` <demo-cards id="demos" configs="[[_configs]]"></demo-cards> `;
@customElement("demo-hui-picture-glance-card")
class DemoPictureGlance extends LitElement {
@query("#demos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
}
static get properties() {
return {
_configs: {
type: Object,
value: CONFIGS,
},
};
}
public ready() {
super.ready();
const hass = provideHass(this.$.demos);
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
const hass = provideHass(this._demoRoot);
hass.updateTranslations(null, "en");
hass.updateTranslations("lovelace", "en");
hass.addEntities(ENTITIES);
}
}
customElements.define("demo-hui-picture-glance-card", DemoPicGlance);
customElements.define("demo-hui-picture-glance-card", DemoPictureGlance);
+55
View File
@@ -0,0 +1,55 @@
import {
html,
LitElement,
customElement,
PropertyValues,
query,
TemplateResult,
} from "lit-element";
import { provideHass } from "../../../src/fake_data/provide_hass";
import "../components/demo-cards";
import { createPlantEntities } from "../data/plants";
const CONFIGS = [
{
heading: "Basic example",
config: `
- type: plant-status
entity: plant.lemon_tree
`,
},
{
heading: "Problem (too bright) + low battery",
config: `
- type: plant-status
entity: plant.apple_tree
`,
},
{
heading: "With picture + multiple problems",
config: `
- type: plant-status
entity: plant.sunflowers
name: Sunflowers Name Overwrite
`,
},
];
@customElement("demo-hui-plant-card")
export class DemoPlantEntity extends LitElement {
@query("#demos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
}
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
const hass = provideHass(this._demoRoot);
hass.updateTranslations(null, "en");
hass.updateTranslations("lovelace", "en");
hass.addEntities(createPlantEntities());
}
}
customElements.define("demo-hui-plant-card", DemoPlantEntity);
@@ -1,6 +1,11 @@
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import {
html,
LitElement,
customElement,
PropertyValues,
query,
TemplateResult,
} from "lit-element";
import { provideHass } from "../../../src/fake_data/provide_hass";
import "../components/demo-cards";
@@ -20,24 +25,19 @@ const CONFIGS = [
},
];
class DemoShoppingListEntity extends PolymerElement {
static get template() {
return html` <demo-cards id="demos" configs="[[_configs]]"></demo-cards> `;
@customElement("demo-hui-shopping-list-card")
class DemoShoppingListEntity extends LitElement {
@query("#demos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
}
static get properties() {
return {
_configs: {
type: Object,
value: CONFIGS,
},
};
}
public ready() {
super.ready();
const hass = provideHass(this.$.demos);
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
const hass = provideHass(this._demoRoot);
hass.updateTranslations(null, "en");
hass.updateTranslations("lovelace", "en");
hass.mockAPI("shopping_list", () => [
{ name: "list", id: 1, complete: false },
+60 -18
View File
@@ -1,6 +1,12 @@
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import {
html,
LitElement,
customElement,
PropertyValues,
query,
TemplateResult,
} from "lit-element";
import { mockHistory } from "../../../demo/src/stubs/history";
import { getEntity } from "../../../src/fake_data/entity";
import { provideHass } from "../../../src/fake_data/provide_hass";
import "../components/demo-cards";
@@ -36,6 +42,10 @@ const ENTITIES = [
battery: 71,
friendly_name: "Home Boy",
}),
getEntity("sensor", "illumination", "23", {
friendly_name: "Illumination",
unit_of_measurement: "lx",
}),
];
const CONFIGS = [
@@ -89,27 +99,59 @@ const CONFIGS = [
entity: light.bed_light
`,
},
{
heading: "Default Grid",
config: `
- type: grid
cards:
- type: entity
entity: light.kitchen_lights
- type: entity
entity: light.bed_light
- type: entity
entity: device_tracker.demo_paulus
- type: sensor
entity: sensor.illumination
graph: line
- type: entity
entity: device_tracker.demo_anne_therese
`,
},
{
heading: "Non-square Grid with 2 columns",
config: `
- type: grid
columns: 2
square: false
cards:
- type: entity
entity: light.kitchen_lights
- type: entity
entity: light.bed_light
- type: entity
entity: device_tracker.demo_paulus
- type: sensor
entity: sensor.illumination
graph: line
`,
},
];
class DemoStack extends PolymerElement {
static get template() {
return html` <demo-cards id="demos" configs="[[_configs]]"></demo-cards> `;
@customElement("demo-hui-stack-card")
class DemoStack extends LitElement {
@query("#demos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
}
static get properties() {
return {
_configs: {
type: Object,
value: CONFIGS,
},
};
}
public ready() {
super.ready();
const hass = provideHass(this.$.demos);
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
const hass = provideHass(this._demoRoot);
hass.updateTranslations(null, "en");
hass.updateTranslations("lovelace", "en");
hass.addEntities(ENTITIES);
mockHistory(hass);
}
}
+18 -18
View File
@@ -1,6 +1,11 @@
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import {
html,
LitElement,
customElement,
PropertyValues,
query,
TemplateResult,
} from "lit-element";
import { getEntity } from "../../../src/fake_data/entity";
import { provideHass } from "../../../src/fake_data/provide_hass";
import "../components/demo-cards";
@@ -74,24 +79,19 @@ const CONFIGS = [
},
];
class DemoThermostatEntity extends PolymerElement {
static get template() {
return html` <demo-cards id="demos" configs="[[_configs]]"></demo-cards> `;
@customElement("demo-hui-thermostat-card")
class DemoThermostatEntity extends LitElement {
@query("#demos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
return html`<demo-cards id="demos" .configs=${CONFIGS}></demo-cards>`;
}
static get properties() {
return {
_configs: {
type: Object,
value: CONFIGS,
},
};
}
public ready() {
super.ready();
const hass = provideHass(this.$.demos);
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
const hass = provideHass(this._demoRoot);
hass.updateTranslations(null, "en");
hass.updateTranslations("lovelace", "en");
hass.addEntities(ENTITIES);
}
}
+58 -23
View File
@@ -1,12 +1,29 @@
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import {
html,
LitElement,
customElement,
property,
PropertyValues,
query,
TemplateResult,
} from "lit-element";
import "../../../src/components/ha-card";
import { SUPPORT_BRIGHTNESS } from "../../../src/data/light";
import {
SUPPORT_BRIGHTNESS,
SUPPORT_COLOR_TEMP,
SUPPORT_EFFECT,
SUPPORT_FLASH,
SUPPORT_COLOR,
SUPPORT_TRANSITION,
SUPPORT_WHITE_VALUE,
} from "../../../src/data/light";
import { getEntity } from "../../../src/fake_data/entity";
import { provideHass } from "../../../src/fake_data/provide_hass";
import {
provideHass,
MockHomeAssistant,
} from "../../../src/fake_data/provide_hass";
import "../components/demo-more-infos";
import "../components/more-info-content";
import "../../../src/dialogs/more-info/more-info-content";
const ENTITIES = [
getEntity("light", "bed_light", "on", {
@@ -14,33 +31,51 @@ const ENTITIES = [
}),
getEntity("light", "kitchen_light", "on", {
friendly_name: "Brightness Light",
brightness: 80,
brightness: 200,
supported_features: SUPPORT_BRIGHTNESS,
}),
getEntity("light", "color_temperature_light", "on", {
friendly_name: "White Color Temperature Light",
brightness: 128,
color_temp: 75,
min_mireds: 30,
max_mireds: 150,
supported_features: SUPPORT_BRIGHTNESS + SUPPORT_COLOR_TEMP,
}),
getEntity("light", "color_effectslight", "on", {
friendly_name: "Color Effets Light",
brightness: 255,
hs_color: [30, 100],
white_value: 36,
supported_features:
SUPPORT_BRIGHTNESS +
SUPPORT_EFFECT +
SUPPORT_FLASH +
SUPPORT_COLOR +
SUPPORT_TRANSITION +
SUPPORT_WHITE_VALUE,
effect_list: ["random", "colorloop"],
}),
];
class DemoMoreInfoLight extends PolymerElement {
static get template() {
@customElement("demo-more-info-light")
class DemoMoreInfoLight extends LitElement {
@property() public hass!: MockHomeAssistant;
@query("demo-more-infos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
return html`
<demo-more-infos
hass="[[hass]]"
entities="[[_entities]]"
.hass=${this.hass}
.entities=${ENTITIES.map((ent) => ent.entityId)}
></demo-more-infos>
`;
}
static get properties() {
return {
_entities: {
type: Array,
value: ENTITIES.map((ent) => ent.entityId),
},
};
}
public ready() {
super.ready();
const hass = provideHass(this);
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
const hass = provideHass(this._demoRoot);
hass.updateTranslations(null, "en");
hass.addEntities(ENTITIES);
}
+3 -4
View File
@@ -1,9 +1,10 @@
import "@material/mwc-button";
import { html, LitElement, TemplateResult } from "lit-element";
import { customElement, html, LitElement, TemplateResult } from "lit-element";
import "../../../src/components/ha-card";
import { ActionHandlerEvent } from "../../../src/data/lovelace";
import { actionHandler } from "../../../src/panels/lovelace/common/directives/action-handler-directive";
@customElement("demo-util-long-press")
export class DemoUtilLongPress extends LitElement {
protected render(): TemplateResult {
return html`
@@ -20,7 +21,7 @@ export class DemoUtilLongPress extends LitElement {
<textarea></textarea>
<div>(try pressing and scrolling too!)</div>
<div>Try pressing and scrolling too!</div>
</ha-card>
`
)}
@@ -62,5 +63,3 @@ export class DemoUtilLongPress extends LitElement {
`;
}
}
customElements.define("demo-util-long-press", DemoUtilLongPress);
+70 -60
View File
@@ -14,54 +14,51 @@ import "../../src/styles/polymer-ha-style";
// eslint-disable-next-line import/extensions
import { DEMOS } from "../build/import-demos";
const fixPath = (path) => path.substr(2, path.length - 5);
class HaGallery extends PolymerElement {
static get template() {
return html`
<style include="iron-positioning ha-style">
:host {
-ms-user-select: initial;
-webkit-user-select: initial;
-moz-user-select: initial;
}
app-header-layout {
min-height: 100vh;
}
ha-icon-button.invisible {
visibility: hidden;
}
:host {
-ms-user-select: initial;
-webkit-user-select: initial;
-moz-user-select: initial;
}
app-header-layout {
min-height: 100vh;
}
ha-icon-button.invisible {
visibility: hidden;
}
.pickers {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: start;
}
.pickers {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: start;
}
.pickers ha-card {
width: 400px;
display: block;
margin: 16px 8px;
}
.pickers ha-card {
width: 400px;
display: block;
margin: 16px 8px;
}
.pickers ha-card:last-child {
margin-bottom: 16px;
}
.pickers ha-card:last-child {
margin-bottom: 16px;
}
.intro {
margin: -1em 0;
}
.intro {
margin: -1em 0;
}
p a {
color: var(--primary-color);
}
a {
color: var(--primary-text-color);
text-decoration: none;
}
p a {
color: var(--primary-color);
}
a {
color: var(--primary-text-color);
text-decoration: none;
}
</style>
<app-header-layout>
@@ -70,32 +67,42 @@ class HaGallery extends PolymerElement {
<ha-icon-button
icon="hass:arrow-left"
on-click="_backTapped"
class$='[[_computeHeaderButtonClass(_demo)]]'
class$="[[_computeHeaderButtonClass(_demo)]]"
></ha-icon-button>
<div main-title>[[_withDefault(_demo, "Home Assistant Gallery")]]</div>
<div main-title>
[[_withDefault(_demo, "Home Assistant Gallery")]]
</div>
</app-toolbar>
</app-header>
<div class='content'>
<div id='demo'></div>
<template is='dom-if' if='[[!_demo]]'>
<div class='pickers'>
<ha-card header="Lovelace card demos">
<div class='card-content intro'>
<div class="content">
<div id="demo"></div>
<template is="dom-if" if="[[!_demo]]">
<div class="pickers">
<ha-card header="Lovelace Card Demos">
<div class="card-content intro">
<p>
Lovelace has many different cards. Each card allows the user to tell a different story about what is going on in their house. These cards are very customizable, as no household is the same.
Lovelace has many different cards. Each card allows the user
to tell a different story about what is going on in their
house. These cards are very customizable, as no household is
the same.
</p>
<p>
This gallery helps our developers and designers to see all the different states that each card can be in.
This gallery helps our developers and designers to see all
the different states that each card can be in.
</p>
<p>
Check <a href='https://www.home-assistant.io/lovelace'>the official website</a> for instructions on how to get started with Lovelace.</a>.
Check
<a href="https://www.home-assistant.io/lovelace"
>the official website</a
>
for instructions on how to get started with Lovelace.
</p>
</div>
<template is='dom-repeat' items='[[_lovelaceDemos]]'>
<a href='#[[item]]'>
<template is="dom-repeat" items="[[_lovelaceDemos]]">
<a href="#[[item]]">
<paper-item>
<paper-item-body>{{ item }}</paper-item-body>
<ha-icon icon="hass:chevron-right"></ha-icon>
@@ -104,14 +111,14 @@ class HaGallery extends PolymerElement {
</template>
</ha-card>
<ha-card header="More Info demos">
<div class='card-content intro'>
<ha-card header="More Info Demos">
<div class="card-content intro">
<p>
More info screens show up when an entity is clicked.
</p>
</div>
<template is='dom-repeat' items='[[_moreInfoDemos]]'>
<a href='#[[item]]'>
<template is="dom-repeat" items="[[_moreInfoDemos]]">
<a href="#[[item]]">
<paper-item>
<paper-item-body>{{ item }}</paper-item-body>
<ha-icon icon="hass:chevron-right"></ha-icon>
@@ -120,14 +127,14 @@ class HaGallery extends PolymerElement {
</template>
</ha-card>
<ha-card header="Util demos">
<div class='card-content intro'>
<ha-card header="Util Demos">
<div class="card-content intro">
<p>
Test pages for our utility functions.
</p>
</div>
<template is='dom-repeat' items='[[_utilDemos]]'>
<a href='#[[item]]'>
<template is="dom-repeat" items="[[_utilDemos]]">
<a href="#[[item]]">
<paper-item>
<paper-item-body>{{ item }}</paper-item-body>
<ha-icon icon="hass:chevron-right"></ha-icon>
@@ -139,7 +146,10 @@ class HaGallery extends PolymerElement {
</template>
</div>
</app-header-layout>
<notification-manager hass=[[_fakeHass]] id='notifications'></notification-manager>
<notification-manager
hass="[[_fakeHass]]"
id="notifications"
></notification-manager>
`;
}
@@ -23,9 +23,9 @@ import { hassioStyle } from "../resources/hassio-style";
class HassioAddonRepositoryEl extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property() public repo!: HassioAddonRepository;
@property({ attribute: false }) public repo!: HassioAddonRepository;
@property() public addons!: HassioAddonInfo[];
@property({ attribute: false }) public addons!: HassioAddonInfo[];
@property() public filter!: string;
@@ -78,18 +78,18 @@ class HassioAddonRepositoryEl extends LitElement {
.title=${addon.name}
.description=${addon.description}
.available=${addon.available}
.icon=${addon.installed && addon.installed !== addon.version
.icon=${addon.installed && addon.update_available
? mdiArrowUpBoldCircle
: mdiPuzzle}
.iconTitle=${addon.installed
? addon.installed !== addon.version
? addon.update_available
? "New version available"
: "Add-on is installed"
: addon.available
? "Add-on is not installed"
: "Add-on is not available on your system"}
.iconClass=${addon.installed
? addon.installed !== addon.version
? addon.update_available
? "update"
: "installed"
: !addon.available
@@ -104,7 +104,7 @@ class HassioAddonRepositoryEl extends LitElement {
: undefined}
.showTopbar=${addon.installed || !addon.available}
.topbarClass=${addon.installed
? addon.installed !== addon.version
? addon.update_available
? "update"
: "installed"
: !addon.available
+17 -2
View File
@@ -11,6 +11,7 @@ import {
PropertyValues,
} from "lit-element";
import { html, TemplateResult } from "lit-html";
import { atLeastVersion } from "../../../src/common/config/version";
import "../../../src/common/search/search-input";
import "../../../src/components/ha-button-menu";
import "../../../src/components/ha-svg-icon";
@@ -24,6 +25,7 @@ import { extractApiErrorMessage } from "../../../src/data/hassio/common";
import "../../../src/layouts/hass-loading-screen";
import "../../../src/layouts/hass-tabs-subpage";
import { HomeAssistant, Route } from "../../../src/types";
import { showRegistriesDialog } from "../dialogs/registries/show-dialog-registries";
import { showRepositoriesDialog } from "../dialogs/repositories/show-dialog-repositories";
import { supervisorTabs } from "../hassio-tabs";
import "./hassio-addon-repository";
@@ -98,14 +100,14 @@ class HassioAddonStore extends LitElement {
main-page
.tabs=${supervisorTabs}
>
<span slot="header">Add-on store</span>
<span slot="header">Add-on Store</span>
<ha-button-menu
corner="BOTTOM_START"
slot="toolbar-icon"
@action=${this._handleAction}
>
<mwc-icon-button slot="trigger" alt="menu">
<ha-svg-icon path=${mdiDotsVertical}></ha-svg-icon>
<ha-svg-icon .path=${mdiDotsVertical}></ha-svg-icon>
</mwc-icon-button>
<mwc-list-item>
Repositories
@@ -113,6 +115,12 @@ class HassioAddonStore extends LitElement {
<mwc-list-item>
Reload
</mwc-list-item>
${this.hass.userData?.showAdvanced &&
atLeastVersion(this.hass.config.version, 0, 117)
? html`<mwc-list-item>
Registries
</mwc-list-item>`
: ""}
</ha-button-menu>
${repos.length === 0
? html`<hass-loading-screen no-toolbar></hass-loading-screen>`
@@ -157,6 +165,9 @@ class HassioAddonStore extends LitElement {
case 1:
this.refreshData();
break;
case 2:
this._manageRegistries();
break;
}
}
@@ -173,6 +184,10 @@ class HassioAddonStore extends LitElement {
});
}
private async _manageRegistries() {
showRegistriesDialog(this);
}
private async _loadData() {
try {
const addonsInfo = await fetchHassioAddonsInfo(this.hass);
@@ -39,13 +39,11 @@ class HassioAddonConfig extends LitElement {
@property({ type: Boolean }) private _configHasChanged = false;
@query("ha-yaml-editor") private _editor!: HaYamlEditor;
@property({ type: Boolean }) private _valid = true;
@query("ha-yaml-editor", true) private _editor!: HaYamlEditor;
protected render(): TemplateResult {
const editor = this._editor;
// If editor not rendered, don't show the error.
const valid = editor ? editor.isValid : true;
return html`
<h1>${this.addon.name}</h1>
<ha-card header="Configuration">
@@ -54,7 +52,7 @@ class HassioAddonConfig extends LitElement {
@value-changed=${this._configChanged}
></ha-yaml-editor>
${this._error ? html` <div class="errors">${this._error}</div> ` : ""}
${valid ? "" : html` <div class="errors">Invalid YAML</div> `}
${this._valid ? "" : html` <div class="errors">Invalid YAML</div> `}
</div>
<div class="card-actions">
<ha-progress-button class="warning" @click=${this._resetTapped}>
@@ -62,7 +60,7 @@ class HassioAddonConfig extends LitElement {
</ha-progress-button>
<ha-progress-button
@click=${this._saveTapped}
.disabled=${!this._configHasChanged || !valid}
.disabled=${!this._configHasChanged || !this._valid}
>
Save
</ha-progress-button>
@@ -78,9 +76,9 @@ class HassioAddonConfig extends LitElement {
}
}
private _configChanged(): void {
private _configChanged(ev): void {
this._configHasChanged = true;
this.requestUpdate();
this._valid = ev.detail.isValid;
}
private async _resetTapped(ev: CustomEvent): Promise<void> {
+16 -25
View File
@@ -69,7 +69,7 @@ const STAGE_ICON = {
const PERMIS_DESC = {
stage: {
title: "Add-on Stage",
description: `Add-ons can have one of three stages:\n\n<ha-svg-icon path='${STAGE_ICON.stable}'></ha-svg-icon> **Stable**: These are add-ons ready to be used in production.\n\n<ha-svg-icon path='${STAGE_ICON.experimental}'></ha-svg-icon> **Experimental**: These may contain bugs, and may be unfinished.\n\n<ha-svg-icon path='${STAGE_ICON.deprecated}'></ha-svg-icon> **Deprecated**: These add-ons will no longer receive any updates.`,
description: `Add-ons can have one of three stages:\n\n<ha-svg-icon path="${STAGE_ICON.stable}"></ha-svg-icon> **Stable**: These are add-ons ready to be used in production.\n\n<ha-svg-icon path="${STAGE_ICON.experimental}"></ha-svg-icon> **Experimental**: These may contain bugs, and may be unfinished.\n\n<ha-svg-icon path="${STAGE_ICON.deprecated}"></ha-svg-icon> **Deprecated**: These add-ons will no longer receive any updates.`,
},
rating: {
title: "Add-on Security Rating",
@@ -135,7 +135,7 @@ class HassioAddonInfo extends LitElement {
protected render(): TemplateResult {
return html`
${this._computeUpdateAvailable
${this.addon.update_available
? html`
<ha-card header="Update available! 🎉">
<div class="card-content">
@@ -178,7 +178,7 @@ class HassioAddonInfo extends LitElement {
${!this.addon.protected
? html`
<ha-card class="warning">
<div class="card-header">Warning: Protection mode is disabled!</div>
<h1 class="card-header">Warning: Protection mode is disabled!</h1>
<div class="card-content">
Protection mode on this add-on is disabled! This gives the add-on full access to the entire system, which adds security risks, and could damage your system when used incorrectly. Only disable the protection mode if you know, need AND trust the source of this add-on.
</div>
@@ -202,14 +202,14 @@ class HassioAddonInfo extends LitElement {
<ha-svg-icon
title="Add-on is running"
class="running"
path=${mdiCircle}
.path=${mdiCircle}
></ha-svg-icon>
`
: html`
<ha-svg-icon
title="Add-on is stopped"
class="stopped"
path=${mdiCircle}
.path=${mdiCircle}
></ha-svg-icon>
`}
`
@@ -283,7 +283,7 @@ class HassioAddonInfo extends LitElement {
label="host"
description=""
>
<ha-svg-icon path=${mdiNetwork}></ha-svg-icon>
<ha-svg-icon .path=${mdiNetwork}></ha-svg-icon>
</ha-label-badge>
`
: ""}
@@ -295,7 +295,7 @@ class HassioAddonInfo extends LitElement {
label="hardware"
description=""
>
<ha-svg-icon path=${mdiChip}></ha-svg-icon>
<ha-svg-icon .path=${mdiChip}></ha-svg-icon>
</ha-label-badge>
`
: ""}
@@ -307,7 +307,7 @@ class HassioAddonInfo extends LitElement {
label="hass"
description=""
>
<ha-svg-icon path=${mdiHomeAssistant}></ha-svg-icon>
<ha-svg-icon .path=${mdiHomeAssistant}></ha-svg-icon>
</ha-label-badge>
`
: ""}
@@ -319,7 +319,7 @@ class HassioAddonInfo extends LitElement {
label="hassio"
.description=${this.addon.hassio_role}
>
<ha-svg-icon path=${mdiHomeAssistant}></ha-svg-icon>
<ha-svg-icon .path=${mdiHomeAssistant}></ha-svg-icon>
</ha-label-badge>
`
: ""}
@@ -331,7 +331,7 @@ class HassioAddonInfo extends LitElement {
label="docker"
description=""
>
<ha-svg-icon path=${mdiDocker}></ha-svg-icon>
<ha-svg-icon .path=${mdiDocker}></ha-svg-icon>
</ha-label-badge>
`
: ""}
@@ -343,7 +343,7 @@ class HassioAddonInfo extends LitElement {
label="host pid"
description=""
>
<ha-svg-icon path=${mdiPound}></ha-svg-icon>
<ha-svg-icon .path=${mdiPound}></ha-svg-icon>
</ha-label-badge>
`
: ""}
@@ -356,7 +356,7 @@ class HassioAddonInfo extends LitElement {
label="apparmor"
description=""
>
<ha-svg-icon path=${mdiShield}></ha-svg-icon>
<ha-svg-icon .path=${mdiShield}></ha-svg-icon>
</ha-label-badge>
`
: ""}
@@ -368,7 +368,7 @@ class HassioAddonInfo extends LitElement {
label="auth"
description=""
>
<ha-svg-icon path=${mdiKey}></ha-svg-icon>
<ha-svg-icon .path=${mdiKey}></ha-svg-icon>
</ha-label-badge>
`
: ""}
@@ -381,7 +381,7 @@ class HassioAddonInfo extends LitElement {
description=""
>
<ha-svg-icon
path=${mdiCursorDefaultClickOutline}
.path=${mdiCursorDefaultClickOutline}
></ha-svg-icon>
</ha-label-badge>
`
@@ -609,15 +609,6 @@ class HassioAddonInfo extends LitElement {
return this.addon?.state === "started";
}
private get _computeUpdateAvailable(): boolean | "" {
return (
this.addon &&
!this.addon.detached &&
this.addon.version &&
this.addon.version !== this.addon.version_latest
);
}
private get _pathWebui(): string | null {
return (
this.addon.webui &&
@@ -798,10 +789,10 @@ class HassioAddonInfo extends LitElement {
);
if (!validate.data.valid) {
await showConfirmationDialog(this, {
title: "Failed to start addon - configruation validation faled!",
title: "Failed to start addon - configuration validation failed!",
text: validate.data.message.split(" Got ")[0],
confirm: () => this._openConfiguration(),
confirmText: "Go to configruation",
confirmText: "Go to configuration",
dismissText: "Cancel",
});
button.progress = false;
+1 -1
View File
@@ -50,7 +50,7 @@ class HassioCardContent extends LitElement {
`
: html`
<ha-svg-icon
class=${this.iconClass}
class=${this.iconClass!}
.path=${this.icon}
.title=${this.iconTitle}
></ha-svg-icon>
@@ -1,4 +1,3 @@
import "../../../src/components/ha-file-upload";
import "@material/mwc-icon-button/mwc-icon-button";
import { mdiFolderUpload } from "@mdi/js";
import "@polymer/iron-input/iron-input";
@@ -12,13 +11,15 @@ import {
} from "lit-element";
import { fireEvent } from "../../../src/common/dom/fire_event";
import "../../../src/components/ha-circular-progress";
import "../../../src/components/ha-file-upload";
import "../../../src/components/ha-svg-icon";
import { extractApiErrorMessage } from "../../../src/data/hassio/common";
import {
HassioSnapshot,
uploadSnapshot,
} from "../../../src/data/hassio/snapshot";
import { HomeAssistant } from "../../../src/types";
import { showAlertDialog } from "../../../src/dialogs/generic/show-dialog-box";
import { HomeAssistant } from "../../../src/types";
declare global {
interface HASSDomEvents {
@@ -26,6 +27,8 @@ declare global {
}
}
const MAX_FILE_SIZE = 1 * 1024 * 1024 * 1024; // 1GB
@customElement("hassio-upload-snapshot")
export class HassioUploadSnapshot extends LitElement {
public hass!: HomeAssistant;
@@ -50,6 +53,20 @@ export class HassioUploadSnapshot extends LitElement {
private async _uploadFile(ev) {
const file = ev.detail.files[0];
if (file.size > MAX_FILE_SIZE) {
showAlertDialog(this, {
title: "Snapshot file is too big",
text: html`The maximum allowed filesize is 1GB.<br />
<a
href="https://www.home-assistant.io/hassio/haos_common_tasks/#restoring-a-snapshot-on-a-new-install"
target="_blank"
>Have a look here on how to restore it.</a
>`,
confirmText: "ok",
});
return;
}
if (!["application/x-tar"].includes(file.type)) {
showAlertDialog(this, {
title: "Unsupported file format",
@@ -65,7 +82,7 @@ export class HassioUploadSnapshot extends LitElement {
} catch (err) {
showAlertDialog(this, {
title: "Upload failed",
text: err.toString(),
text: extractApiErrorMessage(err),
confirmText: "ok",
});
} finally {
+9 -10
View File
@@ -12,7 +12,7 @@ import { atLeastVersion } from "../../../src/common/config/version";
import { navigate } from "../../../src/common/navigate";
import { compare } from "../../../src/common/string/compare";
import "../../../src/components/ha-card";
import { HassioAddonInfo } from "../../../src/data/hassio/addon";
import { Supervisor } from "../../../src/data/supervisor/supervisor";
import { haStyle } from "../../../src/resources/styles";
import { HomeAssistant } from "../../../src/types";
import "../components/hassio-card-content";
@@ -22,14 +22,14 @@ import { hassioStyle } from "../resources/hassio-style";
class HassioAddons extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public addons?: HassioAddonInfo[];
@property({ attribute: false }) public supervisor!: Supervisor;
protected render(): TemplateResult {
return html`
<div class="content">
<h1>Add-ons</h1>
<div class="card-group">
${!this.addons?.length
${!this.supervisor.supervisor.addons?.length
? html`
<ha-card>
<div class="card-content">
@@ -41,7 +41,7 @@ class HassioAddons extends LitElement {
</div>
</ha-card>
`
: this.addons
: this.supervisor.supervisor.addons
.sort((a, b) => compare(a.name, b.name))
.map(
(addon) => html`
@@ -52,22 +52,21 @@ class HassioAddons extends LitElement {
.title=${addon.name}
.description=${addon.description}
available
.showTopbar=${addon.installed !== addon.version}
.showTopbar=${addon.update_available}
topbarClass="update"
.icon=${addon.installed !== addon.version
.icon=${addon.update_available!
? mdiArrowUpBoldCircle
: mdiPuzzle}
.iconTitle=${addon.state !== "started"
? "Add-on is stopped"
: addon.installed !== addon.version
: addon.update_available!
? "New version available"
: "Add-on is running"}
.iconClass=${addon.installed &&
addon.installed !== addon.version
.iconClass=${addon.update_available
? addon.state === "started"
? "update"
: "update stopped"
: addon.installed && addon.state === "started"
: addon.state === "started"
? "running"
: "stopped"}
.iconImage=${atLeastVersion(
+5 -15
View File
@@ -7,11 +7,7 @@ import {
property,
TemplateResult,
} from "lit-element";
import { HassioHassOSInfo } from "../../../src/data/hassio/host";
import {
HassioHomeAssistantInfo,
HassioSupervisorInfo,
} from "../../../src/data/hassio/supervisor";
import { Supervisor } from "../../../src/data/supervisor/supervisor";
import "../../../src/layouts/hass-tabs-subpage";
import { haStyle } from "../../../src/resources/styles";
import { HomeAssistant, Route } from "../../../src/types";
@@ -23,16 +19,12 @@ import "./hassio-update";
class HassioDashboard extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ type: Boolean }) public narrow!: boolean;
@property({ attribute: false }) public route!: Route;
@property({ attribute: false }) public supervisorInfo!: HassioSupervisorInfo;
@property({ attribute: false }) public hassInfo!: HassioHomeAssistantInfo;
@property({ attribute: false }) public hassOsInfo!: HassioHassOSInfo;
protected render(): TemplateResult {
return html`
<hass-tabs-subpage
@@ -47,13 +39,11 @@ class HassioDashboard extends LitElement {
<div class="content">
<hassio-update
.hass=${this.hass}
.hassInfo=${this.hassInfo}
.supervisorInfo=${this.supervisorInfo}
.hassOsInfo=${this.hassOsInfo}
.supervisor=${this.supervisor}
></hassio-update>
<hassio-addons
.hass=${this.hass}
.addons=${this.supervisorInfo.addons}
.supervisor=${this.supervisor}
></hassio-addons>
</div>
</hass-tabs-subpage>
+29 -51
View File
@@ -5,11 +5,11 @@ import {
CSSResult,
customElement,
html,
internalProperty,
LitElement,
property,
TemplateResult,
} from "lit-element";
import memoizeOne from "memoize-one";
import "../../../src/components/buttons/ha-progress-button";
import "../../../src/components/ha-card";
import "../../../src/components/ha-svg-icon";
@@ -23,6 +23,7 @@ import {
HassioHomeAssistantInfo,
HassioSupervisorInfo,
} from "../../../src/data/hassio/supervisor";
import { Supervisor } from "../../../src/data/supervisor/supervisor";
import {
showAlertDialog,
showConfirmationDialog,
@@ -35,39 +36,26 @@ import { hassioStyle } from "../resources/hassio-style";
export class HassioUpdate extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public hassInfo: HassioHomeAssistantInfo;
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ attribute: false }) public hassOsInfo?: HassioHassOSInfo;
@property() public supervisorInfo: HassioSupervisorInfo;
@internalProperty() private _error?: string;
private _pendingUpdates = memoizeOne((supervisor: Supervisor): number => {
return Object.keys(supervisor).filter(
(value) => supervisor[value].update_available
).length;
});
protected render(): TemplateResult {
const updatesAvailable: number = [
this.hassInfo,
this.supervisorInfo,
this.hassOsInfo,
].filter((value) => {
return (
!!value &&
(value.version_latest
? value.version !== value.version_latest
: value.version_latest
? value.version !== value.version_latest
: false)
);
}).length;
if (!this.supervisor) {
return html``;
}
const updatesAvailable = this._pendingUpdates(this.supervisor);
if (!updatesAvailable) {
return html``;
}
return html`
<div class="content">
${this._error
? html` <div class="error">Error: ${this._error}</div> `
: ""}
<h1>
${updatesAvailable > 1
? "Updates Available 🎉"
@@ -76,28 +64,24 @@ export class HassioUpdate extends LitElement {
<div class="card-group">
${this._renderUpdateCard(
"Home Assistant Core",
this.hassInfo.version,
this.hassInfo.version_latest,
this.supervisor.core,
"hassio/homeassistant/update",
`https://${
this.hassInfo.version_latest.includes("b") ? "rc" : "www"
}.home-assistant.io/latest-release-notes/`,
mdiHomeAssistant
this.supervisor.core.version_latest.includes("b") ? "rc" : "www"
}.home-assistant.io/latest-release-notes/`
)}
${this._renderUpdateCard(
"Supervisor",
this.supervisorInfo.version,
this.supervisorInfo.version_latest,
this.supervisor.supervisor,
"hassio/supervisor/update",
`https://github.com//home-assistant/hassio/releases/tag/${this.supervisorInfo.version_latest}`
`https://github.com//home-assistant/hassio/releases/tag/${this.supervisor.supervisor.version_latest}`
)}
${this.hassOsInfo
${this.supervisor.host.features.includes("hassos")
? this._renderUpdateCard(
"Operating System",
this.hassOsInfo.version,
this.hassOsInfo.version_latest,
this.supervisor.os,
"hassio/os/update",
`https://github.com//home-assistant/hassos/releases/tag/${this.hassOsInfo.version_latest}`
`https://github.com//home-assistant/hassos/releases/tag/${this.supervisor.os.version_latest}`
)
: ""}
</div>
@@ -107,28 +91,22 @@ export class HassioUpdate extends LitElement {
private _renderUpdateCard(
name: string,
curVersion: string,
lastVersion: string,
object: HassioHomeAssistantInfo | HassioSupervisorInfo | HassioHassOSInfo,
apiPath: string,
releaseNotesUrl: string,
icon?: string
releaseNotesUrl: string
): TemplateResult {
if (!lastVersion || lastVersion === curVersion) {
if (!object.update_available) {
return html``;
}
return html`
<ha-card>
<div class="card-content">
${icon
? html`
<div class="icon">
<ha-svg-icon .path=${icon}></ha-svg-icon>
</div>
`
: ""}
<div class="update-heading">${name} ${lastVersion}</div>
<div class="icon">
<ha-svg-icon .path=${mdiHomeAssistant}></ha-svg-icon>
</div>
<div class="update-heading">${name} ${object.version_latest}</div>
<div class="warning">
You are currently running version ${curVersion}
You are currently running version ${object.version}
</div>
</div>
<div class="card-actions">
@@ -138,7 +116,7 @@ export class HassioUpdate extends LitElement {
<ha-progress-button
.apiPath=${apiPath}
.name=${name}
.version=${lastVersion}
.version=${object.version_latest}
@click=${this._confirmUpdate}
>
Update
@@ -11,10 +11,7 @@ export const showHassioMarkdownDialog = (
): void => {
fireEvent(element, "show-dialog", {
dialogTag: "dialog-hassio-markdown",
dialogImport: () =>
import(
/* webpackChunkName: "dialog-hassio-markdown" */ "./dialog-hassio-markdown"
),
dialogImport: () => import("./dialog-hassio-markdown"),
dialogParams,
});
};
@@ -1,5 +1,7 @@
import "@material/mwc-button/mwc-button";
import "@material/mwc-icon-button";
import "@material/mwc-list/mwc-list";
import "@material/mwc-list/mwc-list-item";
import "@material/mwc-tab";
import "@material/mwc-tab-bar";
import { mdiClose } from "@mdi/js";
@@ -16,18 +18,22 @@ import {
} from "lit-element";
import { cache } from "lit-html/directives/cache";
import { fireEvent } from "../../../../src/common/dom/fire_event";
import "../../../../src/components/ha-chips";
import "../../../../src/components/ha-circular-progress";
import "../../../../src/components/ha-dialog";
import "../../../../src/components/ha-expansion-panel";
import "../../../../src/components/ha-formfield";
import "../../../../src/components/ha-header-bar";
import "../../../../src/components/ha-radio";
import type { HaRadio } from "../../../../src/components/ha-radio";
import "../../../../src/components/ha-related-items";
import "../../../../src/components/ha-svg-icon";
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
import {
AccessPoints,
accesspointScan,
NetworkInterface,
updateNetworkInterface,
WifiConfiguration,
} from "../../../../src/data/hassio/network";
import {
showAlertDialog,
@@ -38,53 +44,51 @@ import { haStyleDialog } from "../../../../src/resources/styles";
import type { HomeAssistant } from "../../../../src/types";
import { HassioNetworkDialogParams } from "./show-dialog-network";
const IP_VERSIONS = ["ipv4", "ipv6"];
@customElement("dialog-hassio-network")
export class DialogHassioNetwork extends LitElement implements HassDialog {
export class DialogHassioNetwork extends LitElement
implements HassDialog<HassioNetworkDialogParams> {
@property({ attribute: false }) public hass!: HomeAssistant;
@internalProperty() private _prosessing = false;
@internalProperty() private _params?: HassioNetworkDialogParams;
@internalProperty() private _network!: {
interface: string;
data: NetworkInterface;
}[];
@internalProperty() private _accessPoints?: AccessPoints;
@internalProperty() private _curTabIndex = 0;
@internalProperty() private _device?: {
interface: string;
data: NetworkInterface;
};
@internalProperty() private _dirty = false;
@internalProperty() private _interface?: NetworkInterface;
@internalProperty() private _interfaces!: NetworkInterface[];
@internalProperty() private _params?: HassioNetworkDialogParams;
@internalProperty() private _processing = false;
@internalProperty() private _scanning = false;
@internalProperty() private _wifiConfiguration?: WifiConfiguration;
public async showDialog(params: HassioNetworkDialogParams): Promise<void> {
this._params = params;
this._dirty = false;
this._curTabIndex = 0;
this._network = Object.keys(params.network?.interfaces)
.map((device) => ({
interface: device,
data: params.network.interfaces[device],
}))
.sort((a, b) => {
return a.data.primary > b.data.primary ? -1 : 1;
});
this._device = this._network[this._curTabIndex];
this._device.data.nameservers = String(this._device.data.nameservers);
this._interfaces = params.network.interfaces.sort((a, b) => {
return a.primary > b.primary ? -1 : 1;
});
this._interface = { ...this._interfaces[this._curTabIndex] };
await this.updateComplete;
}
public closeDialog(): void {
this._params = undefined;
this._prosessing = false;
this._processing = false;
fireEvent(this, "dialog-closed", { dialog: this.localName });
}
protected render(): TemplateResult {
if (!this._params || !this._network) {
if (!this._params || !this._interface) {
return html``;
}
@@ -106,11 +110,11 @@ export class DialogHassioNetwork extends LitElement implements HassDialog {
<ha-svg-icon .path=${mdiClose}></ha-svg-icon>
</mwc-icon-button>
</ha-header-bar>
${this._network.length > 1
${this._interfaces.length > 1
? html` <mwc-tab-bar
.activeIndex=${this._curTabIndex}
@MDCTabBar:activated=${this._handleTabActivated}
>${this._network.map(
>${this._interfaces.map(
(device) =>
html`<mwc-tab
.id=${device.interface}
@@ -128,81 +132,302 @@ export class DialogHassioNetwork extends LitElement implements HassDialog {
private _renderTab() {
return html` <div class="form container">
<ha-formfield label="DHCP">
<ha-radio
@change=${this._handleRadioValueChanged}
value="dhcp"
name="method"
?checked=${this._device!.data.method === "dhcp"}
>
</ha-radio>
</ha-formfield>
<ha-formfield label="Static">
<ha-radio
@change=${this._handleRadioValueChanged}
value="static"
name="method"
?checked=${this._device!.data.method === "static"}
>
</ha-radio>
</ha-formfield>
${this._device!.data.method !== "dhcp"
? html` <paper-input
class="flex-auto"
id="ip_address"
label="IP address/Netmask"
.value="${this._device!.data.ip_address}"
@value-changed=${this._handleInputValueChanged}
></paper-input>
<paper-input
class="flex-auto"
id="gateway"
label="Gateway address"
.value="${this._device!.data.gateway}"
@value-changed=${this._handleInputValueChanged}
></paper-input>
<paper-input
class="flex-auto"
id="nameservers"
label="DNS servers"
.value="${this._device!.data.nameservers as string}"
@value-changed=${this._handleInputValueChanged}
></paper-input>
NB!: If you are changing IP or gateway addresses, you might lose
the connection.`
${IP_VERSIONS.map((version) =>
this._interface![version] ? this._renderIPConfiguration(version) : ""
)}
${this._interface?.type === "wireless"
? html`
<ha-expansion-panel header="Wi-Fi" outlined>
${this._interface?.wifi?.ssid
? html`<p>Connected to: ${this._interface?.wifi?.ssid}</p>`
: ""}
<mwc-button
class="scan"
@click=${this._scanForAP}
.disabled=${this._scanning}
>
${this._scanning
? html`<ha-circular-progress active size="small">
</ha-circular-progress>`
: "Scan for accesspoints"}
</mwc-button>
${this._accessPoints &&
this._accessPoints.accesspoints &&
this._accessPoints.accesspoints.length !== 0
? html`
<mwc-list>
${this._accessPoints.accesspoints
.filter((ap) => ap.ssid)
.map(
(ap) =>
html`
<mwc-list-item
twoline
@click=${this._selectAP}
.activated=${ap.ssid ===
this._wifiConfiguration?.ssid}
.ap=${ap}
>
<span>${ap.ssid}</span>
<span slot="secondary">
${ap.mac} - Strength: ${ap.signal}
</span>
</mwc-list-item>
`
)}
</mwc-list>
`
: ""}
${this._wifiConfiguration
? html`
<div class="radio-row">
<ha-formfield label="open">
<ha-radio
@change=${this._handleRadioValueChangedAp}
.ap=${this._wifiConfiguration}
value="open"
name="auth"
.checked=${this._wifiConfiguration.auth ===
undefined ||
this._wifiConfiguration.auth === "open"}
>
</ha-radio>
</ha-formfield>
<ha-formfield label="wep">
<ha-radio
@change=${this._handleRadioValueChangedAp}
.ap=${this._wifiConfiguration}
value="wep"
name="auth"
.checked=${this._wifiConfiguration.auth === "wep"}
>
</ha-radio>
</ha-formfield>
<ha-formfield label="wpa-psk">
<ha-radio
@change=${this._handleRadioValueChangedAp}
.ap=${this._wifiConfiguration}
value="wpa-psk"
name="auth"
.checked=${this._wifiConfiguration.auth ===
"wpa-psk"}
>
</ha-radio>
</ha-formfield>
</div>
${this._wifiConfiguration.auth === "wpa-psk" ||
this._wifiConfiguration.auth === "wep"
? html`
<paper-input
class="flex-auto"
type="password"
id="psk"
label="Password"
version="wifi"
@value-changed=${this
._handleInputValueChangedWifi}
>
</paper-input>
`
: ""}
`
: ""}
</ha-expansion-panel>
`
: ""}
${this._dirty
? html`<div class="warning">
If you are changing the Wi-Fi, IP or gateway addresses, you might
lose the connection!
</div>`
: ""}
</div>
<div class="buttons">
<mwc-button label="close" @click=${this.closeDialog}> </mwc-button>
<mwc-button @click=${this._updateNetwork} ?disabled=${!this._dirty}>
${this._prosessing
? html`<ha-circular-progress active></ha-circular-progress>`
: "Update"}
<mwc-button @click=${this._updateNetwork} .disabled=${!this._dirty}>
${this._processing
? html`<ha-circular-progress active size="small">
</ha-circular-progress>`
: "Save"}
</mwc-button>
</div>`;
}
private async _updateNetwork() {
this._prosessing = true;
let options: Partial<NetworkInterface> = {
method: this._device!.data.method,
};
if (options.method !== "dhcp") {
options = {
...options,
address: this._device!.data.ip_address,
gateway: this._device!.data.gateway,
dns: String(this._device!.data.nameservers).split(","),
};
private _selectAP(event) {
this._wifiConfiguration = event.currentTarget.ap;
this._dirty = true;
}
private async _scanForAP() {
if (!this._interface) {
return;
}
this._scanning = true;
try {
await updateNetworkInterface(this.hass, this._device!.interface, options);
this._accessPoints = await accesspointScan(
this.hass,
this._interface.interface
);
} catch (err) {
showAlertDialog(this, {
title: "Failed to scan for accesspoints",
text: extractApiErrorMessage(err),
});
} finally {
this._scanning = false;
}
}
private _renderIPConfiguration(version: string) {
return html`
<ha-expansion-panel
.header=${`IPv${version.charAt(version.length - 1)}`}
outlined
>
<div class="radio-row">
<ha-formfield label="DHCP">
<ha-radio
@change=${this._handleRadioValueChanged}
.version=${version}
value="auto"
name="${version}method"
.checked=${this._interface![version]?.method === "auto"}
>
</ha-radio>
</ha-formfield>
<ha-formfield label="Static">
<ha-radio
@change=${this._handleRadioValueChanged}
.version=${version}
value="static"
name="${version}method"
.checked=${this._interface![version]?.method === "static"}
>
</ha-radio>
</ha-formfield>
<ha-formfield label="Disabled" class="warning">
<ha-radio
@change=${this._handleRadioValueChanged}
.version=${version}
value="disabled"
name="${version}method"
.checked=${this._interface![version]?.method === "disabled"}
>
</ha-radio>
</ha-formfield>
</div>
${this._interface![version].method === "static"
? html`
<paper-input
class="flex-auto"
id="address"
label="IP address/Netmask"
.version=${version}
.value=${this._toString(this._interface![version].address)}
@value-changed=${this._handleInputValueChanged}
>
</paper-input>
<paper-input
class="flex-auto"
id="gateway"
label="Gateway address"
.version=${version}
.value=${this._interface![version].gateway}
@value-changed=${this._handleInputValueChanged}
>
</paper-input>
<paper-input
class="flex-auto"
id="nameservers"
label="DNS servers"
.version=${version}
.value=${this._toString(this._interface![version].nameservers)}
@value-changed=${this._handleInputValueChanged}
>
</paper-input>
`
: ""}
</ha-expansion-panel>
`;
}
_toArray(data: string | string[]): string[] {
if (Array.isArray(data)) {
if (data && typeof data[0] === "string") {
data = data[0];
}
}
if (!data) {
return [];
}
if (typeof data === "string") {
return data.replace(/ /g, "").split(",");
}
return data;
}
_toString(data: string | string[]): string {
if (!data) {
return "";
}
if (Array.isArray(data)) {
return data.join(", ");
}
return data;
}
private async _updateNetwork() {
this._processing = true;
let interfaceOptions: Partial<NetworkInterface> = {};
IP_VERSIONS.forEach((version) => {
interfaceOptions[version] = {
method: this._interface![version]?.method || "auto",
};
if (this._interface![version]?.method === "static") {
interfaceOptions[version] = {
...interfaceOptions[version],
address: this._toArray(this._interface![version]?.address),
gateway: this._interface![version]?.gateway,
nameservers: this._toArray(this._interface![version]?.nameservers),
};
}
});
if (this._wifiConfiguration) {
interfaceOptions = {
...interfaceOptions,
wifi: {
ssid: this._wifiConfiguration.ssid,
mode: this._wifiConfiguration.mode,
auth: this._wifiConfiguration.auth || "open",
},
};
if (interfaceOptions.wifi!.auth !== "open") {
interfaceOptions.wifi = {
...interfaceOptions.wifi,
psk: this._wifiConfiguration.psk,
};
}
}
interfaceOptions.enabled =
this._wifiConfiguration !== undefined ||
interfaceOptions.ipv4?.method !== "disabled" ||
interfaceOptions.ipv6?.method !== "disabled";
try {
await updateNetworkInterface(
this.hass,
this._interface!.interface,
interfaceOptions
);
} catch (err) {
showAlertDialog(this, {
title: "Failed to change network settings",
text: extractApiErrorMessage(err),
});
this._prosessing = false;
this._processing = false;
return;
}
this._params?.loadData();
@@ -218,40 +443,73 @@ export class DialogHassioNetwork extends LitElement implements HassDialog {
dismissText: "no",
});
if (!confirm) {
this.requestUpdate("_device");
this.requestUpdate("_interface");
return;
}
}
this._curTabIndex = ev.detail.index;
this._device = this._network[ev.detail.index];
this._device.data.nameservers = String(this._device.data.nameservers);
this._interface = { ...this._interfaces[ev.detail.index] };
}
private _handleRadioValueChanged(ev: CustomEvent): void {
const value = (ev.target as HaRadio).value as "dhcp" | "static";
const value = (ev.target as any).value as "disabled" | "auto" | "static";
const version = (ev.target as any).version as "ipv4" | "ipv6";
if (!value || !this._device || this._device!.data.method === value) {
if (
!value ||
!this._interface ||
this._interface[version]!.method === value
) {
return;
}
this._dirty = true;
this._device!.data.method = value;
this.requestUpdate("_device");
this._interface[version]!.method = value;
this.requestUpdate("_interface");
}
private _handleRadioValueChangedAp(ev: CustomEvent): void {
const value = ((ev.target as any).value as string) as
| "open"
| "wep"
| "wpa-psk";
this._wifiConfiguration!.auth = value;
this._dirty = true;
this.requestUpdate("_wifiConfiguration");
}
private _handleInputValueChanged(ev: CustomEvent): void {
const value: string | null | undefined = (ev.target as PaperInputElement)
.value;
const version = (ev.target as any).version as "ipv4" | "ipv6";
const id = (ev.target as PaperInputElement).id;
if (!value || !this._device || this._device.data[id] === value) {
if (
!value ||
!this._interface ||
this._toString(this._interface[version]![id]) === this._toString(value)
) {
return;
}
this._dirty = true;
this._interface[version]![id] = value;
}
this._device.data[id] = value;
private _handleInputValueChangedWifi(ev: CustomEvent): void {
const value: string | null | undefined = (ev.target as PaperInputElement)
.value;
const id = (ev.target as PaperInputElement).id;
if (
!value ||
!this._wifiConfiguration ||
this._wifiConfiguration![id] === value
) {
return;
}
this._dirty = true;
this._wifiConfiguration![id] = value;
}
static get styles(): CSSResult[] {
@@ -298,12 +556,16 @@ export class DialogHassioNetwork extends LitElement implements HassDialog {
--mdc-theme-primary: var(--error-color);
}
mwc-button.scan {
margin-left: 8px;
}
:host([rtl]) app-toolbar {
direction: rtl;
text-align: right;
}
.container {
padding: 20px 24px;
padding: 0 8px 4px;
}
.form {
margin-bottom: 53px;
@@ -321,6 +583,24 @@ export class DialogHassioNetwork extends LitElement implements HassDialog {
padding-bottom: max(env(safe-area-inset-bottom), 8px);
background-color: var(--mdc-theme-surface, #fff);
}
.warning {
color: var(--error-color);
--primary-color: var(--error-color);
}
div.warning {
margin: 12px 4px -12px;
}
ha-expansion-panel {
--expansion-panel-summary-padding: 0 16px;
margin: 4px 0;
}
paper-input {
padding: 0 14px;
}
mwc-list-item {
--mdc-list-side-padding: 10px;
}
`,
];
}
@@ -13,10 +13,7 @@ export const showNetworkDialog = (
): void => {
fireEvent(element, "show-dialog", {
dialogTag: "dialog-hassio-network",
dialogImport: () =>
import(
/* webpackChunkName: "dialog-hassio-network" */ "./dialog-hassio-network"
),
dialogImport: () => import("./dialog-hassio-network"),
dialogParams,
});
};
@@ -0,0 +1,245 @@
import "@material/mwc-button/mwc-button";
import "@material/mwc-icon-button/mwc-icon-button";
import "@material/mwc-list/mwc-list-item";
import { mdiDelete } from "@mdi/js";
import { PaperInputElement } from "@polymer/paper-input/paper-input";
import {
css,
CSSResult,
customElement,
html,
internalProperty,
LitElement,
property,
TemplateResult,
} from "lit-element";
import "../../../../src/components/ha-circular-progress";
import { createCloseHeading } from "../../../../src/components/ha-dialog";
import "../../../../src/components/ha-svg-icon";
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
import {
addHassioDockerRegistry,
fetchHassioDockerRegistries,
removeHassioDockerRegistry,
} from "../../../../src/data/hassio/docker";
import { showAlertDialog } from "../../../../src/dialogs/generic/show-dialog-box";
import { haStyle, haStyleDialog } from "../../../../src/resources/styles";
import type { HomeAssistant } from "../../../../src/types";
@customElement("dialog-hassio-registries")
class HassioRegistriesDialog extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) private _registries?: {
registry: string;
username: string;
}[];
@internalProperty() private _registry?: string;
@internalProperty() private _username?: string;
@internalProperty() private _password?: string;
@internalProperty() private _opened = false;
@internalProperty() private _addingRegistry = false;
protected render(): TemplateResult {
return html`
<ha-dialog
.open=${this._opened}
@closing=${this.closeDialog}
scrimClickAction
escapeKeyAction
.heading=${createCloseHeading(
this.hass,
this._addingRegistry
? "Add New Docker Registry"
: "Manage Docker Registries"
)}
>
<div class="form">
${this._addingRegistry
? html`
<paper-input
@value-changed=${this._inputChanged}
class="flex-auto"
name="registry"
label="Registry"
required
auto-validate
></paper-input>
<paper-input
@value-changed=${this._inputChanged}
class="flex-auto"
name="username"
label="Username"
required
auto-validate
></paper-input>
<paper-input
@value-changed=${this._inputChanged}
class="flex-auto"
name="password"
label="Password"
type="password"
required
auto-validate
></paper-input>
<mwc-button
?disabled=${Boolean(
!this._registry || !this._username || !this._password
)}
@click=${this._addNewRegistry}
>
Add registry
</mwc-button>
`
: html`${this._registries?.length
? this._registries.map((entry) => {
return html`
<mwc-list-item class="option" hasMeta twoline>
<span>${entry.registry}</span>
<span slot="secondary"
>Username: ${entry.username}</span
>
<mwc-icon-button
.entry=${entry}
title="Remove"
slot="meta"
@click=${this._removeRegistry}
>
<ha-svg-icon .path=${mdiDelete}></ha-svg-icon>
</mwc-icon-button>
</mwc-list-item>
`;
})
: html`
<mwc-list-item>
<span>No registries configured</span>
</mwc-list-item>
`}
<mwc-button @click=${this._addRegistry}>
Add new registry
</mwc-button> `}
</div>
</ha-dialog>
`;
}
private _inputChanged(ev: Event) {
const target = ev.currentTarget as PaperInputElement;
this[`_${target.name}`] = target.value;
}
public async showDialog(_dialogParams: any): Promise<void> {
this._opened = true;
await this._loadRegistries();
await this.updateComplete;
}
public closeDialog(): void {
this._addingRegistry = false;
this._opened = false;
}
public focus(): void {
this.updateComplete.then(() =>
(this.shadowRoot?.querySelector(
"[dialogInitialFocus]"
) as HTMLElement)?.focus()
);
}
private async _loadRegistries(): Promise<void> {
const registries = await fetchHassioDockerRegistries(this.hass);
this._registries = Object.keys(registries!.registries).map((key) => ({
registry: key,
username: registries.registries[key].username,
}));
}
private _addRegistry(): void {
this._addingRegistry = true;
}
private async _addNewRegistry(): Promise<void> {
const data = {};
data[this._registry!] = {
username: this._username,
password: this._password,
};
try {
await addHassioDockerRegistry(this.hass, data);
await this._loadRegistries();
this._addingRegistry = false;
} catch (err) {
showAlertDialog(this, {
title: "Failed to add registry",
text: extractApiErrorMessage(err),
});
}
}
private async _removeRegistry(ev: Event): Promise<void> {
const entry = (ev.currentTarget as any).entry;
try {
await removeHassioDockerRegistry(this.hass, entry.registry);
await this._loadRegistries();
} catch (err) {
showAlertDialog(this, {
title: "Failed to remove registry",
text: extractApiErrorMessage(err),
});
}
}
static get styles(): CSSResult[] {
return [
haStyle,
haStyleDialog,
css`
ha-dialog.button-left {
--justify-action-buttons: flex-start;
}
paper-icon-item {
cursor: pointer;
}
.form {
color: var(--primary-text-color);
}
.option {
border: 1px solid var(--divider-color);
border-radius: 4px;
margin-top: 4px;
}
mwc-button {
margin-left: 8px;
}
mwc-icon-button {
color: var(--error-color);
margin: -10px;
}
mwc-list-item {
cursor: default;
}
mwc-list-item span[slot="secondary"] {
color: var(--secondary-text-color);
}
ha-paper-dropdown-menu {
display: block;
}
`,
];
}
}
declare global {
interface HTMLElementTagNameMap {
"dialog-hassio-registries": HassioRegistriesDialog;
}
}
@@ -0,0 +1,10 @@
import { fireEvent } from "../../../../src/common/dom/fire_event";
import "./dialog-hassio-registries";
export const showRegistriesDialog = (element: HTMLElement): void => {
fireEvent(element, "show-dialog", {
dialogTag: "dialog-hassio-registries",
dialogImport: () => import("./dialog-hassio-registries"),
dialogParams: {},
});
};
@@ -39,7 +39,7 @@ class HassioRepositoriesDialog extends LitElement {
@property({ attribute: false })
private _dialogParams?: HassioRepositoryDialogParams;
@query("#repository_input") private _optionInput?: PaperInputElement;
@query("#repository_input", true) private _optionInput?: PaperInputElement;
@internalProperty() private _opened = false;
@@ -91,7 +91,7 @@ class HassioRepositoriesDialog extends LitElement {
title="Remove"
@click=${this._removeRepository}
>
<ha-svg-icon path=${mdiDelete}></ha-svg-icon>
<ha-svg-icon .path=${mdiDelete}></ha-svg-icon>
</mwc-icon-button>
</paper-item>
`;
@@ -13,10 +13,7 @@ export const showRepositoriesDialog = (
): void => {
fireEvent(element, "show-dialog", {
dialogTag: "dialog-hassio-repositories",
dialogImport: () =>
import(
/* webpackChunkName: "dialog-hassio-repositories" */ "./dialog-hassio-repositories"
),
dialogImport: () => import("./dialog-hassio-repositories"),
dialogParams,
});
};
@@ -19,7 +19,7 @@ import { HassioSnapshotUploadDialogParams } from "./show-dialog-snapshot-upload"
@customElement("dialog-hassio-snapshot-upload")
export class DialogHassioSnapshotUpload extends LitElement
implements HassDialog {
implements HassDialog<HassioSnapshotUploadDialogParams> {
@property({ attribute: false }) public hass!: HomeAssistant;
@internalProperty() private _params?: HassioSnapshotUploadDialogParams;
@@ -1,6 +1,7 @@
import "@material/mwc-button";
import { mdiClose, mdiDelete, mdiDownload, mdiHistory } from "@mdi/js";
import { PaperCheckboxElement } from "@polymer/paper-checkbox/paper-checkbox";
import "@polymer/paper-checkbox/paper-checkbox";
import type { PaperCheckboxElement } from "@polymer/paper-checkbox/paper-checkbox";
import "@polymer/paper-input/paper-input";
import {
css,
@@ -108,7 +109,7 @@ class HassioSnapshotDialog extends LitElement {
return html``;
}
return html`
<ha-dialog open stacked @closing=${this._closeDialog} .heading=${true}>
<ha-dialog open @closing=${this._closeDialog} .heading=${true}>
<div slot="heading">
<ha-header-bar>
<span slot="title">
@@ -190,44 +191,37 @@ class HassioSnapshotDialog extends LitElement {
: ""}
${this._error ? html` <p class="error">Error: ${this._error}</p> ` : ""}
<div>Actions:</div>
${!this._onboarding
? html`<mwc-button
@click=${this._downloadClicked}
slot="primaryAction"
>
<ha-svg-icon path=${mdiDownload} class="icon"></ha-svg-icon>
Download Snapshot
</mwc-button>`
: ""}
<mwc-button
@click=${this._partialRestoreClicked}
slot="secondaryAction"
>
<ha-svg-icon path=${mdiHistory} class="icon"></ha-svg-icon>
Restore Selected
</mwc-button>
${this._snapshot.type === "full"
? html`
<mwc-button
@click=${this._fullRestoreClicked}
slot="secondaryAction"
>
<ha-svg-icon path=${mdiHistory} class="icon"></ha-svg-icon>
Wipe &amp; restore
</mwc-button>
`
: ""}
${!this._onboarding
? html`<mwc-button
@click=${this._deleteClicked}
slot="secondaryAction"
>
<ha-svg-icon path=${mdiDelete} class="icon warning"></ha-svg-icon>
<span class="warning">Delete Snapshot</span>
</mwc-button>`
: ""}
<div class="button-row" slot="primaryAction">
<mwc-button @click=${this._partialRestoreClicked}>
<ha-svg-icon .path=${mdiHistory} class="icon"></ha-svg-icon>
Restore Selected
</mwc-button>
${!this._onboarding
? html`
<mwc-button @click=${this._deleteClicked}>
<ha-svg-icon .path=${mdiDelete} class="icon warning">
</ha-svg-icon>
<span class="warning">Delete Snapshot</span>
</mwc-button>
`
: ""}
</div>
<div class="button-row" slot="secondaryAction">
${this._snapshot.type === "full"
? html`
<mwc-button @click=${this._fullRestoreClicked}>
<ha-svg-icon .path=${mdiHistory} class="icon"></ha-svg-icon>
Restore Everything
</mwc-button>
`
: ""}
${!this._onboarding
? html`<mwc-button @click=${this._downloadClicked}>
<ha-svg-icon .path=${mdiDownload} class="icon"></ha-svg-icon>
Download Snapshot
</mwc-button>`
: ""}
</div>
</ha-dialog>
`;
}
@@ -241,6 +235,14 @@ class HassioSnapshotDialog extends LitElement {
display: block;
margin: 4px;
}
mwc-button ha-svg-icon {
margin-right: 4px;
}
.button-row {
display: grid;
gap: 8px;
margin-right: 8px;
}
.details {
color: var(--secondary-text-color);
}
@@ -248,10 +250,6 @@ class HassioSnapshotDialog extends LitElement {
.error {
color: var(--error-color);
}
.buttons {
display: flex;
flex-direction: column;
}
.buttons li {
list-style-type: none;
}
@@ -440,6 +438,19 @@ class HassioSnapshotDialog extends LitElement {
return;
}
if (window.location.href.includes("ui.nabu.casa")) {
const confirm = await showConfirmationDialog(this, {
title: "Potential slow download",
text:
"Downloading snapshots over the Nabu Casa URL will take some time, it is recomended to use your local URL instead, do you want to continue?",
confirmText: "continue",
dismissText: "cancel",
});
if (!confirm) {
return;
}
}
const name = this._computeName.replace(/[^a-z0-9]+/gi, "_");
const a = document.createElement("a");
a.href = signedPath.path;
@@ -12,10 +12,7 @@ export const showHassioSnapshotDialog = (
): void => {
fireEvent(element, "show-dialog", {
dialogTag: "dialog-hassio-snapshot",
dialogImport: () =>
import(
/* webpackChunkName: "dialog-hassio-snapshot" */ "./dialog-hassio-snapshot"
),
dialogImport: () => import("./dialog-hassio-snapshot"),
dialogParams,
});
};
@@ -13,10 +13,7 @@ export const showSnapshotUploadDialog = (
): void => {
fireEvent(element, "show-dialog", {
dialogTag: "dialog-hassio-snapshot-upload",
dialogImport: () =>
import(
/* webpackChunkName: "dialog-hassio-snapshot-upload" */ "./dialog-hassio-snapshot-upload"
),
dialogImport: () => import("./dialog-hassio-snapshot-upload"),
dialogParams,
});
};
+10 -13
View File
@@ -1,29 +1,22 @@
import {
html,
PropertyValues,
customElement,
LitElement,
property,
} from "lit-element";
import { html, PropertyValues, customElement, property } from "lit-element";
import "./hassio-router";
import { urlSyncMixin } from "../../src/state/url-sync-mixin";
import { ProvideHassLitMixin } from "../../src/mixins/provide-hass-lit-mixin";
import { HomeAssistant, Route } from "../../src/types";
import { HassioPanelInfo } from "../../src/data/hassio/supervisor";
import { applyThemesOnElement } from "../../src/common/dom/apply_themes_on_element";
import { fireEvent } from "../../src/common/dom/fire_event";
import { makeDialogManager } from "../../src/dialogs/make-dialog-manager";
import { atLeastVersion } from "../../src/common/config/version";
import { SupervisorBaseElement } from "./supervisor-base-element";
@customElement("hassio-main")
export class HassioMain extends urlSyncMixin(ProvideHassLitMixin(LitElement)) {
export class HassioMain extends SupervisorBaseElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property() public panel!: HassioPanelInfo;
@property({ attribute: false }) public panel!: HassioPanelInfo;
@property() public narrow!: boolean;
@property({ type: Boolean }) public narrow!: boolean;
@property() public route?: Route;
@property({ attribute: false }) public route?: Route;
protected firstUpdated(changedProps: PropertyValues) {
super.firstUpdated(changedProps);
@@ -77,9 +70,13 @@ export class HassioMain extends urlSyncMixin(ProvideHassLitMixin(LitElement)) {
}
protected render() {
if (!this.supervisor || !this.hass) {
return html``;
}
return html`
<hassio-router
.hass=${this.hass}
.supervisor=${this.supervisor}
.route=${this.route}
.panel=${this.panel}
.narrow=${this.narrow}
+4 -21
View File
@@ -1,10 +1,5 @@
import { customElement, property } from "lit-element";
import { HassioHassOSInfo, HassioHostInfo } from "../../src/data/hassio/host";
import {
HassioHomeAssistantInfo,
HassioSupervisorInfo,
HassioInfo,
} from "../../src/data/hassio/supervisor";
import { Supervisor } from "../../src/data/supervisor/supervisor";
import {
HassRouterPage,
RouterOptions,
@@ -21,20 +16,12 @@ import "./system/hassio-system";
class HassioPanelRouter extends HassRouterPage {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ attribute: false }) public route!: Route;
@property({ type: Boolean }) public narrow!: boolean;
@property({ attribute: false }) public supervisorInfo: HassioSupervisorInfo;
@property({ attribute: false }) public hassioInfo!: HassioInfo;
@property({ attribute: false }) public hostInfo: HassioHostInfo;
@property({ attribute: false }) public hassInfo: HassioHomeAssistantInfo;
@property({ attribute: false }) public hassOsInfo!: HassioHassOSInfo;
protected routerOptions: RouterOptions = {
routes: {
dashboard: {
@@ -54,13 +41,9 @@ class HassioPanelRouter extends HassRouterPage {
protected updatePageEl(el) {
el.hass = this.hass;
el.supervisor = this.supervisor;
el.route = this.route;
el.narrow = this.narrow;
el.supervisorInfo = this.supervisorInfo;
el.hassioInfo = this.hassioInfo;
el.hostInfo = this.hostInfo;
el.hassInfo = this.hassInfo;
el.hassOsInfo = this.hassOsInfo;
}
}
+7 -27
View File
@@ -1,18 +1,13 @@
import {
css,
CSSResult,
customElement,
html,
LitElement,
property,
TemplateResult,
css,
CSSResult,
} from "lit-element";
import { HassioHassOSInfo, HassioHostInfo } from "../../src/data/hassio/host";
import {
HassioHomeAssistantInfo,
HassioSupervisorInfo,
HassioInfo,
} from "../../src/data/hassio/supervisor";
import { Supervisor } from "../../src/data/supervisor/supervisor";
import { HomeAssistant, Route } from "../../src/types";
import "./hassio-panel-router";
@@ -20,34 +15,19 @@ import "./hassio-panel-router";
class HassioPanel extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ type: Boolean }) public narrow!: boolean;
@property({ attribute: false }) public route!: Route;
@property({ attribute: false }) public supervisorInfo!: HassioSupervisorInfo;
@property({ attribute: false }) public hassioInfo!: HassioInfo;
@property({ attribute: false }) public hostInfo!: HassioHostInfo;
@property({ attribute: false }) public hassInfo!: HassioHomeAssistantInfo;
@property({ attribute: false }) public hassOsInfo!: HassioHassOSInfo;
protected render(): TemplateResult {
if (!this.supervisorInfo) {
return html``;
}
return html`
<hassio-panel-router
.route=${this.route}
.hass=${this.hass}
.supervisor=${this.supervisor}
.route=${this.route}
.narrow=${this.narrow}
.supervisorInfo=${this.supervisorInfo}
.hassioInfo=${this.hassioInfo}
.hostInfo=${this.hostInfo}
.hassInfo=${this.hassInfo}
.hassOsInfo=${this.hassOsInfo}
></hassio-panel-router>
`;
}
+10 -84
View File
@@ -1,24 +1,6 @@
import {
customElement,
property,
internalProperty,
PropertyValues,
} from "lit-element";
import {
fetchHassioHassOsInfo,
fetchHassioHostInfo,
HassioHassOSInfo,
HassioHostInfo,
} from "../../src/data/hassio/host";
import {
fetchHassioHomeAssistantInfo,
fetchHassioSupervisorInfo,
fetchHassioInfo,
HassioHomeAssistantInfo,
HassioInfo,
HassioPanelInfo,
HassioSupervisorInfo,
} from "../../src/data/hassio/supervisor";
import { customElement, property } from "lit-element";
import { HassioPanelInfo } from "../../src/data/hassio/supervisor";
import { Supervisor } from "../../src/data/supervisor/supervisor";
import {
HassRouterPage,
RouterOptions,
@@ -32,9 +14,11 @@ import "./hassio-panel";
class HassioRouter extends HassRouterPage {
@property({ attribute: false }) public hass!: HomeAssistant;
@property() public panel!: HassioPanelInfo;
@property({ attribute: false }) public supervisor!: Supervisor;
@property() public narrow!: boolean;
@property({ attribute: false }) public panel!: HassioPanelInfo;
@property({ type: Boolean }) public narrow!: boolean;
protected routerOptions: RouterOptions = {
// Hass.io has a page with tabs, so we route all non-matching routes to it.
@@ -51,47 +35,22 @@ class HassioRouter extends HassRouterPage {
system: "dashboard",
addon: {
tag: "hassio-addon-dashboard",
load: () =>
import(
/* webpackChunkName: "hassio-addon-dashboard" */ "./addon-view/hassio-addon-dashboard"
),
load: () => import("./addon-view/hassio-addon-dashboard"),
},
ingress: {
tag: "hassio-ingress-view",
load: () =>
import(
/* webpackChunkName: "hassio-ingress-view" */ "./ingress-view/hassio-ingress-view"
),
load: () => import("./ingress-view/hassio-ingress-view"),
},
},
};
@internalProperty() private _supervisorInfo: HassioSupervisorInfo;
@internalProperty() private _hostInfo: HassioHostInfo;
@internalProperty() private _hassioInfo?: HassioInfo;
@internalProperty() private _hassOsInfo?: HassioHassOSInfo;
@internalProperty() private _hassInfo: HassioHomeAssistantInfo;
protected firstUpdated(changedProps: PropertyValues) {
super.firstUpdated(changedProps);
this.addEventListener("hass-api-called", (ev) => this._apiCalled(ev));
}
protected updatePageEl(el) {
// the tabs page does its own routing so needs full route.
const route = el.nodeName === "HASSIO-PANEL" ? this.route : this.routeTail;
el.hass = this.hass;
el.supervisor = this.supervisor;
el.narrow = this.narrow;
el.supervisorInfo = this._supervisorInfo;
el.hassioInfo = this._hassioInfo;
el.hostInfo = this._hostInfo;
el.hassInfo = this._hassInfo;
el.hassOsInfo = this._hassOsInfo;
el.route = route;
if (el.localName === "hassio-ingress-view") {
@@ -102,45 +61,12 @@ class HassioRouter extends HassRouterPage {
private async _fetchData() {
if (this.panel.config && this.panel.config.ingress) {
this._redirectIngress(this.panel.config.ingress);
return;
}
const [supervisorInfo, hostInfo, hassInfo, hassioInfo] = await Promise.all([
fetchHassioSupervisorInfo(this.hass),
fetchHassioHostInfo(this.hass),
fetchHassioHomeAssistantInfo(this.hass),
fetchHassioInfo(this.hass),
]);
this._supervisorInfo = supervisorInfo;
this._hassioInfo = hassioInfo;
this._hostInfo = hostInfo;
this._hassInfo = hassInfo;
if (this._hostInfo.features && this._hostInfo.features.includes("hassos")) {
this._hassOsInfo = await fetchHassioHassOsInfo(this.hass);
}
}
private _redirectIngress(addonSlug: string) {
this.route = { prefix: "/hassio", path: `/ingress/${addonSlug}` };
}
private _apiCalled(ev) {
if (!ev.detail.success) {
return;
}
let tries = 1;
const tryUpdate = () => {
this._fetchData().catch(() => {
tries += 1;
setTimeout(tryUpdate, Math.min(tries, 5) * 1000);
});
};
tryUpdate();
}
}
declare global {
+1 -1
View File
@@ -8,7 +8,7 @@ export const supervisorTabs: PageNavigation[] = [
iconPath: mdiViewDashboard,
},
{
name: "Add-on store",
name: "Add-on Store",
path: `/hassio/store`,
iconPath: mdiStore,
},
+34 -7
View File
@@ -13,7 +13,10 @@ import {
fetchHassioAddonInfo,
HassioAddonDetails,
} from "../../../src/data/hassio/addon";
import { createHassioSession } from "../../../src/data/hassio/supervisor";
import {
createHassioSession,
validateHassioSession,
} from "../../../src/data/hassio/ingress";
import "../../../src/layouts/hass-loading-screen";
import "../../../src/layouts/hass-subpage";
import { HomeAssistant, Route } from "../../../src/types";
@@ -35,6 +38,17 @@ class HassioIngressView extends LitElement {
@property({ type: Boolean })
public narrow = false;
private _sessionKeepAlive?: number;
public disconnectedCallback() {
super.disconnectedCallback();
if (this._sessionKeepAlive) {
clearInterval(this._sessionKeepAlive);
this._sessionKeepAlive = undefined;
}
}
protected render(): TemplateResult {
if (!this._addon) {
return html` <hass-loading-screen></hass-loading-screen> `;
@@ -44,6 +58,7 @@ class HassioIngressView extends LitElement {
if (!this.ingressPanel) {
return html`<hass-subpage
.hass=${this.hass}
.header=${this._addon.name}
.narrow=${this.narrow}
>
@@ -57,7 +72,7 @@ class HassioIngressView extends LitElement {
aria-label=${this.hass.localize("ui.sidebar.sidebar_toggle")}
@click=${this._toggleMenu}
>
<ha-svg-icon path=${mdiMenu}></ha-svg-icon>
<ha-svg-icon .path=${mdiMenu}></ha-svg-icon>
</mwc-icon-button>
<div class="main-title">${this._addon.name}</div>
</div>
@@ -83,10 +98,7 @@ class HassioIngressView extends LitElement {
}
private async _fetchData(addonSlug: string) {
const createSessionPromise = createHassioSession(this.hass).then(
() => true,
() => false
);
const createSessionPromise = createHassioSession(this.hass);
let addon;
@@ -119,7 +131,11 @@ class HassioIngressView extends LitElement {
return;
}
if (!(await createSessionPromise)) {
let session;
try {
session = await createSessionPromise;
} catch (err) {
await showAlertDialog(this, {
text: "Unable to create an Ingress session",
title: addon.name,
@@ -128,6 +144,17 @@ class HassioIngressView extends LitElement {
return;
}
if (this._sessionKeepAlive) {
clearInterval(this._sessionKeepAlive);
}
this._sessionKeepAlive = window.setInterval(async () => {
try {
await validateHassioSession(this.hass, session);
} catch (err) {
session = await createHassioSession(this.hass);
}
}, 60000);
this._addon = addon;
}
+6 -8
View File
@@ -26,7 +26,6 @@ import {
TemplateResult,
} from "lit-element";
import { atLeastVersion } from "../../../src/common/config/version";
import { fireEvent } from "../../../src/common/dom/fire_event";
import "../../../src/components/buttons/ha-progress-button";
import "../../../src/components/ha-button-menu";
import "../../../src/components/ha-card";
@@ -41,7 +40,7 @@ import {
HassioSnapshot,
reloadHassioSnapshots,
} from "../../../src/data/hassio/snapshot";
import { HassioSupervisorInfo } from "../../../src/data/hassio/supervisor";
import { Supervisor } from "../../../src/data/supervisor/supervisor";
import "../../../src/layouts/hass-tabs-subpage";
import { PolymerChangedEvent } from "../../../src/polymer-types";
import { haStyle } from "../../../src/resources/styles";
@@ -67,7 +66,7 @@ class HassioSnapshots extends LitElement {
@property({ attribute: false }) public route!: Route;
@property({ attribute: false }) public supervisorInfo!: HassioSupervisorInfo;
@property({ attribute: false }) public supervisor!: Supervisor;
@internalProperty() private _snapshotName = "";
@@ -117,7 +116,7 @@ class HassioSnapshots extends LitElement {
@action=${this._handleAction}
>
<mwc-icon-button slot="trigger" alt="menu">
<ha-svg-icon path=${mdiDotsVertical}></ha-svg-icon>
<ha-svg-icon .path=${mdiDotsVertical}></ha-svg-icon>
</mwc-icon-button>
<mwc-list-item>
Reload
@@ -131,7 +130,7 @@ class HassioSnapshots extends LitElement {
<div class="content">
<h1>
Create snapshot
Create Snapshot
</h1>
<p class="description">
Snapshots allow you to easily backup and restore all data of your
@@ -219,7 +218,7 @@ class HassioSnapshots extends LitElement {
</ha-card>
</div>
<h1>Available snapshots</h1>
<h1>Available Snapshots</h1>
<div class="card-group">
${this._snapshots === undefined
? undefined
@@ -266,7 +265,7 @@ class HassioSnapshots extends LitElement {
protected updated(changedProps: PropertyValues) {
if (changedProps.has("supervisorInfo")) {
this._addonList = this.supervisorInfo.addons
this._addonList = this.supervisor.supervisor.addons
.map((addon) => ({
slug: addon.slug,
name: addon.name,
@@ -372,7 +371,6 @@ class HassioSnapshots extends LitElement {
await createHassioPartialSnapshot(this.hass, data);
}
this._updateSnapshots();
fireEvent(this, "hass-api-called", { success: true, response: null });
} catch (err) {
this._error = extractApiErrorMessage(err);
}
+69
View File
@@ -0,0 +1,69 @@
import { LitElement, property, PropertyValues } from "lit-element";
import {
fetchHassioHassOsInfo,
fetchHassioHostInfo,
} from "../../src/data/hassio/host";
import { fetchNetworkInfo } from "../../src/data/hassio/network";
import { fetchHassioResolution } from "../../src/data/hassio/resolution";
import {
fetchHassioHomeAssistantInfo,
fetchHassioInfo,
fetchHassioSupervisorInfo,
} from "../../src/data/hassio/supervisor";
import { Supervisor } from "../../src/data/supervisor/supervisor";
import { ProvideHassLitMixin } from "../../src/mixins/provide-hass-lit-mixin";
import { urlSyncMixin } from "../../src/state/url-sync-mixin";
declare global {
interface HASSDomEvents {
"supervisor-update": Partial<Supervisor>;
}
}
export class SupervisorBaseElement extends urlSyncMixin(
ProvideHassLitMixin(LitElement)
) {
@property({ attribute: false }) public supervisor?: Supervisor;
protected _updateSupervisor(obj: Partial<Supervisor>): void {
this.supervisor = { ...this.supervisor!, ...obj };
}
protected firstUpdated(changedProps: PropertyValues): void {
super.firstUpdated(changedProps);
this._initSupervisor();
this.addEventListener("supervisor-update", (ev) =>
this._updateSupervisor(ev.detail)
);
}
private async _initSupervisor(): Promise<void> {
const [
supervisor,
host,
core,
info,
os,
network,
resolution,
] = await Promise.all([
fetchHassioSupervisorInfo(this.hass),
fetchHassioHostInfo(this.hass),
fetchHassioHomeAssistantInfo(this.hass),
fetchHassioInfo(this.hass),
fetchHassioHassOsInfo(this.hass),
fetchNetworkInfo(this.hass),
fetchHassioResolution(this.hass),
]);
this.supervisor = {
supervisor,
host,
core,
info,
os,
network,
resolution,
};
}
}
+31 -39
View File
@@ -8,12 +8,12 @@ import {
CSSResult,
customElement,
html,
internalProperty,
LitElement,
property,
TemplateResult,
} from "lit-element";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../../src/common/dom/fire_event";
import "../../../src/components/buttons/ha-progress-button";
import "../../../src/components/ha-button-menu";
import "../../../src/components/ha-card";
@@ -27,8 +27,6 @@ import {
changeHostOptions,
configSyncOS,
fetchHassioHostInfo,
HassioHassOSInfo,
HassioHostInfo as HassioHostInfoType,
rebootHost,
shutdownHost,
updateOS,
@@ -37,7 +35,7 @@ import {
fetchNetworkInfo,
NetworkInfo,
} from "../../../src/data/hassio/network";
import { HassioInfo } from "../../../src/data/hassio/supervisor";
import { Supervisor } from "../../../src/data/supervisor/supervisor";
import {
showAlertDialog,
showConfirmationDialog,
@@ -53,28 +51,22 @@ import { hassioStyle } from "../resources/hassio-style";
class HassioHostInfo extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property() public hostInfo!: HassioHostInfoType;
@property({ attribute: false }) public hassioInfo!: HassioInfo;
@property({ attribute: false }) public hassOsInfo!: HassioHassOSInfo;
@internalProperty() public _networkInfo?: NetworkInfo;
@property({ attribute: false }) public supervisor!: Supervisor;
protected render(): TemplateResult | void {
const primaryIpAddress = this.hostInfo.features.includes("network")
? this._primaryIpAddress(this._networkInfo!)
const primaryIpAddress = this.supervisor.host.features.includes("network")
? this._primaryIpAddress(this.supervisor.network!)
: "";
return html`
<ha-card header="Host System">
<div class="card-content">
${this.hostInfo.features.includes("hostname")
${this.supervisor.host.features.includes("hostname")
? html`<ha-settings-row>
<span slot="heading">
Hostname
</span>
<span slot="description">
${this.hostInfo.hostname}
${this.supervisor.host.hostname}
</span>
<mwc-button
title="Change the hostname"
@@ -84,10 +76,10 @@ class HassioHostInfo extends LitElement {
</mwc-button>
</ha-settings-row>`
: ""}
${this.hostInfo.features.includes("network")
${this.supervisor.host.features.includes("network")
? html` <ha-settings-row>
<span slot="heading">
IP address
IP Address
</span>
<span slot="description">
${primaryIpAddress}
@@ -103,13 +95,12 @@ class HassioHostInfo extends LitElement {
<ha-settings-row>
<span slot="heading">
Operating system
Operating System
</span>
<span slot="description">
${this.hostInfo.operating_system}
${this.supervisor.host.operating_system}
</span>
${this.hostInfo.version !== this.hostInfo.version_latest &&
this.hostInfo.features.includes("hassos")
${this.supervisor.os.update_available
? html`
<ha-progress-button
title="Update the host OS"
@@ -120,29 +111,29 @@ class HassioHostInfo extends LitElement {
`
: ""}
</ha-settings-row>
${!this.hostInfo.features.includes("hassos")
${!this.supervisor.host.features.includes("hassos")
? html`<ha-settings-row>
<span slot="heading">
Docker version
</span>
<span slot="description">
${this.hassioInfo.docker}
${this.supervisor.info.docker}
</span>
</ha-settings-row>`
: ""}
${this.hostInfo.deployment
${this.supervisor.host.deployment
? html`<ha-settings-row>
<span slot="heading">
Deployment
</span>
<span slot="description">
${this.hostInfo.deployment}
${this.supervisor.host.deployment}
</span>
</ha-settings-row>`
: ""}
</div>
<div class="card-actions">
${this.hostInfo.features.includes("reboot")
${this.supervisor.host.features.includes("reboot")
? html`
<ha-progress-button
title="Reboot the host OS"
@@ -153,7 +144,7 @@ class HassioHostInfo extends LitElement {
</ha-progress-button>
`
: ""}
${this.hostInfo.features.includes("shutdown")
${this.supervisor.host.features.includes("shutdown")
? html`
<ha-progress-button
title="Shutdown the host OS"
@@ -175,7 +166,7 @@ class HassioHostInfo extends LitElement {
<mwc-list-item title="Show a list of hardware">
Hardware
</mwc-list-item>
${this.hostInfo.features.includes("hassos")
${this.supervisor.host.features.includes("hassos")
? html`<mwc-list-item
title="Load HassOS configs or updates from USB"
>
@@ -193,12 +184,10 @@ class HassioHostInfo extends LitElement {
}
private _primaryIpAddress = memoizeOne((network_info: NetworkInfo) => {
if (!network_info) {
if (!network_info || !network_info.interfaces) {
return "";
}
return Object.keys(network_info?.interfaces)
.map((device) => network_info.interfaces[device])
.find((device) => device.primary)?.ip_address;
return network_info.interfaces.find((a) => a.primary)?.ipv4?.address![0];
});
private async _handleMenuAction(ev: CustomEvent<ActionDetail>) {
@@ -221,7 +210,7 @@ class HassioHostInfo extends LitElement {
});
} catch (err) {
showAlertDialog(this, {
title: "Failed to get Hardware list",
title: "Failed to get hardware list",
text: extractApiErrorMessage(err),
});
}
@@ -316,15 +305,15 @@ class HassioHostInfo extends LitElement {
private async _changeNetworkClicked(): Promise<void> {
showNetworkDialog(this, {
network: this._networkInfo!,
network: this.supervisor.network!,
loadData: () => this._loadData(),
});
}
private async _changeHostnameClicked(): Promise<void> {
const curHostname: string = this.hostInfo.hostname;
const curHostname: string = this.supervisor.host.hostname;
const hostname = await showPromptDialog(this, {
title: "Change hostname",
title: "Change Hostname",
inputLabel: "Please enter a new hostname:",
inputType: "string",
defaultValue: curHostname,
@@ -333,7 +322,8 @@ class HassioHostInfo extends LitElement {
if (hostname && hostname !== curHostname) {
try {
await changeHostOptions(this.hass, { hostname });
this.hostInfo = await fetchHassioHostInfo(this.hass);
const host = await fetchHassioHostInfo(this.hass);
fireEvent(this, "supervisor-update", { host });
} catch (err) {
showAlertDialog(this, {
title: "Setting hostname failed",
@@ -346,7 +336,8 @@ class HassioHostInfo extends LitElement {
private async _importFromUSB(): Promise<void> {
try {
await configSyncOS(this.hass);
this.hostInfo = await fetchHassioHostInfo(this.hass);
const host = await fetchHassioHostInfo(this.hass);
fireEvent(this, "supervisor-update", { host });
} catch (err) {
showAlertDialog(this, {
title: "Failed to import from USB",
@@ -356,7 +347,8 @@ class HassioHostInfo extends LitElement {
}
private async _loadData(): Promise<void> {
this._networkInfo = await fetchNetworkInfo(this.hass);
const network = await fetchNetworkInfo(this.hass);
fireEvent(this, "supervisor-update", { network });
}
static get styles(): CSSResult[] {
+185 -40
View File
@@ -7,35 +7,85 @@ import {
property,
TemplateResult,
} from "lit-element";
import { fireEvent } from "../../../src/common/dom/fire_event";
import "../../../src/components/buttons/ha-progress-button";
import "../../../src/components/ha-card";
import "../../../src/components/ha-settings-row";
import "../../../src/components/ha-switch";
import { HassioHostInfo as HassioHostInfoType } from "../../../src/data/hassio/host";
import { extractApiErrorMessage } from "../../../src/data/hassio/common";
import {
HassioSupervisorInfo as HassioSupervisorInfoType,
fetchHassioSupervisorInfo,
reloadSupervisor,
restartSupervisor,
setSupervisorOption,
SupervisorOptions,
updateSupervisor,
fetchHassioSupervisorInfo,
} from "../../../src/data/hassio/supervisor";
import { Supervisor } from "../../../src/data/supervisor/supervisor";
import {
showAlertDialog,
showConfirmationDialog,
} from "../../../src/dialogs/generic/show-dialog-box";
import { haStyle } from "../../../src/resources/styles";
import { HomeAssistant } from "../../../src/types";
import { documentationUrl } from "../../../src/util/documentation-url";
import { hassioStyle } from "../resources/hassio-style";
import { extractApiErrorMessage } from "../../../src/data/hassio/common";
const UNSUPPORTED_REASON = {
container: {
title: "Containers known to cause issues",
url: "/more-info/unsupported/container",
},
dbus: { title: "DBUS", url: "/more-info/unsupported/dbus" },
docker_configuration: {
title: "Docker Configuration",
url: "/more-info/unsupported/docker_configuration",
},
docker_version: {
title: "Docker Version",
url: "/more-info/unsupported/docker_version",
},
job_conditions: {
title: "Ignored job conditions",
url: "/more-info/unsupported/job_conditions",
},
lxc: { title: "LXC", url: "/more-info/unsupported/lxc" },
network_manager: {
title: "Network Manager",
url: "/more-info/unsupported/network_manager",
},
os: { title: "Operating System", url: "/more-info/unsupported/os" },
privileged: {
title: "Supervisor is not privileged",
url: "/more-info/unsupported/privileged",
},
systemd: { title: "Systemd", url: "/more-info/unsupported/systemd" },
};
const UNHEALTHY_REASON = {
privileged: {
title: "Supervisor is not privileged",
url: "/more-info/unsupported/privileged",
},
supervisor: {
title: "Supervisor was not able to update",
url: "/more-info/unhealthy/supervisor",
},
setup: {
title: "Setup of the Supervisor failed",
url: "/more-info/unhealthy/setup",
},
docker: {
title: "The Docker environment is not working properly",
url: "/more-info/unhealthy/docker",
},
};
@customElement("hassio-supervisor-info")
class HassioSupervisorInfo extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property() public supervisorInfo!: HassioSupervisorInfoType;
@property() public hostInfo!: HassioHostInfoType;
@property({ attribute: false }) public supervisor!: Supervisor;
protected render(): TemplateResult | void {
return html`
@@ -46,17 +96,17 @@ class HassioSupervisorInfo extends LitElement {
Version
</span>
<span slot="description">
${this.supervisorInfo.version}
${this.supervisor.supervisor.version}
</span>
</ha-settings-row>
<ha-settings-row>
<span slot="heading">
Newest version
Newest Version
</span>
<span slot="description">
${this.supervisorInfo.version_latest}
${this.supervisor.supervisor.version_latest}
</span>
${this.supervisorInfo.version !== this.supervisorInfo.version_latest
${this.supervisor.supervisor.update_available
? html`
<ha-progress-button
title="Update the supervisor"
@@ -72,9 +122,9 @@ class HassioSupervisorInfo extends LitElement {
Channel
</span>
<span slot="description">
${this.supervisorInfo.channel}
${this.supervisor.supervisor.channel}
</span>
${this.supervisorInfo.channel === "beta"
${this.supervisor.supervisor.channel === "beta"
? html`
<ha-progress-button
@click=${this._toggleBeta}
@@ -83,7 +133,7 @@ class HassioSupervisorInfo extends LitElement {
Leave beta channel
</ha-progress-button>
`
: this.supervisorInfo.channel === "stable"
: this.supervisor.supervisor.channel === "stable"
? html`
<ha-progress-button
@click=${this._toggleBeta}
@@ -95,10 +145,10 @@ class HassioSupervisorInfo extends LitElement {
: ""}
</ha-settings-row>
${this.supervisorInfo?.supported
${this.supervisor.supervisor.supported
? html` <ha-settings-row three-line>
<span slot="heading">
Share diagnostics
Share Diagnostics
</span>
<div slot="description" class="diagnostics-description">
Share crash reports and diagnostic information.
@@ -112,33 +162,47 @@ class HassioSupervisorInfo extends LitElement {
</div>
<ha-switch
haptic
.checked=${this.supervisorInfo.diagnostics}
.checked=${this.supervisor.supervisor.diagnostics}
@change=${this._toggleDiagnostics}
></ha-switch>
</ha-settings-row>`
: html`<div class="error">
You are running an unsupported installation.
<a
href="https://github.com/home-assistant/architecture/blob/master/adr/${this.hostInfo.features.includes(
"hassos"
)
? "0015-home-assistant-os.md"
: "0014-home-assistant-supervised.md"}"
target="_blank"
rel="noreferrer"
<button
class="link"
title="Learn more about how you can make your system compliant"
@click=${this._unsupportedDialog}
>
Learn More
</a>
Learn more
</button>
</div>`}
${!this.supervisor.supervisor.healthy
? html`<div class="error">
Your installation is running in an unhealthy state.
<button
class="link"
title="Learn more about why your system is marked as unhealthy"
@click=${this._unhealthyDialog}
>
Learn more
</button>
</div>`
: ""}
</div>
<div class="card-actions">
<ha-progress-button
@click=${this._supervisorReload}
title="Reload parts of the supervisor."
title="Reload parts of the Supervisor"
>
Reload
</ha-progress-button>
<ha-progress-button
class="warning"
@click=${this._supervisorRestart}
title="Restart the Supervisor"
>
Restart
</ha-progress-button>
</div>
</ha-card>
`;
@@ -148,7 +212,7 @@ class HassioSupervisorInfo extends LitElement {
const button = ev.currentTarget as any;
button.progress = true;
if (this.supervisorInfo.channel === "stable") {
if (this.supervisor.supervisor.channel === "stable") {
const confirmed = await showConfirmationDialog(this, {
title: "WARNING",
text: html` Beta releases are for testers and early adopters and can
@@ -177,18 +241,19 @@ class HassioSupervisorInfo extends LitElement {
try {
const data: Partial<SupervisorOptions> = {
channel: this.supervisorInfo.channel === "stable" ? "beta" : "stable",
channel:
this.supervisor.supervisor.channel === "stable" ? "beta" : "stable",
};
await setSupervisorOption(this.hass, data);
await reloadSupervisor(this.hass);
this.supervisorInfo = await fetchHassioSupervisorInfo(this.hass);
await this._reloadSupervisor();
} catch (err) {
showAlertDialog(this, {
title: "Failed to set supervisor option",
text: extractApiErrorMessage(err),
});
} finally {
button.progress = false;
}
button.progress = false;
}
private async _supervisorReload(ev: CustomEvent): Promise<void> {
@@ -196,15 +261,37 @@ class HassioSupervisorInfo extends LitElement {
button.progress = true;
try {
await reloadSupervisor(this.hass);
this.supervisorInfo = await fetchHassioSupervisorInfo(this.hass);
await this._reloadSupervisor();
} catch (err) {
showAlertDialog(this, {
title: "Failed to reload the supervisor",
text: extractApiErrorMessage(err),
});
} finally {
button.progress = false;
}
}
private async _reloadSupervisor(): Promise<void> {
await reloadSupervisor(this.hass);
const supervisor = await fetchHassioSupervisorInfo(this.hass);
fireEvent(this, "supervisor-update", { supervisor });
}
private async _supervisorRestart(ev: CustomEvent): Promise<void> {
const button = ev.currentTarget as any;
button.progress = true;
try {
await restartSupervisor(this.hass);
} catch (err) {
showAlertDialog(this, {
title: "Failed to restart the supervisor",
text: extractApiErrorMessage(err),
});
} finally {
button.progress = false;
}
button.progress = false;
}
private async _supervisorUpdate(ev: CustomEvent): Promise<void> {
@@ -212,8 +299,8 @@ class HassioSupervisorInfo extends LitElement {
button.progress = true;
const confirmed = await showConfirmationDialog(this, {
title: "Update supervisor",
text: `Are you sure you want to update supervisor to version ${this.supervisorInfo.version_latest}?`,
title: "Update Supervisor",
text: `Are you sure you want to update supervisor to version ${this.supervisor.supervisor.version_latest}?`,
confirmText: "update",
dismissText: "cancel",
});
@@ -230,8 +317,9 @@ class HassioSupervisorInfo extends LitElement {
title: "Failed to update the supervisor",
text: extractApiErrorMessage(err),
});
} finally {
button.progress = false;
}
button.progress = false;
}
private async _diagnosticsInformationDialog(): Promise<void> {
@@ -249,10 +337,67 @@ class HassioSupervisorInfo extends LitElement {
});
}
private async _unsupportedDialog(): Promise<void> {
await showAlertDialog(this, {
title: "You are running an unsupported installation",
text: html`Below is a list of issues found with your installation, click
on the links to learn how you can resolve the issues. <br /><br />
<ul>
${this.supervisor.resolution.unsupported.map(
(issue) => html`
<li>
${UNSUPPORTED_REASON[issue]
? html`<a
href="${documentationUrl(
this.hass,
UNSUPPORTED_REASON[issue].url
)}"
target="_blank"
rel="noreferrer"
>
${UNSUPPORTED_REASON[issue].title}
</a>`
: issue}
</li>
`
)}
</ul>`,
});
}
private async _unhealthyDialog(): Promise<void> {
await showAlertDialog(this, {
title: "Your installation is unhealthy",
text: html`Running an unhealthy installation will cause issues. Below is a
list of issues found with your installation, click on the links to learn
how you can resolve the issues. <br /><br />
<ul>
${this.supervisor.resolution.unhealthy.map(
(issue) => html`
<li>
${UNHEALTHY_REASON[issue]
? html`<a
href="${documentationUrl(
this.hass,
UNHEALTHY_REASON[issue].url
)}"
target="_blank"
rel="noreferrer"
>
${UNHEALTHY_REASON[issue].title}
</a>`
: issue}
</li>
`
)}
</ul>`,
});
}
private async _toggleDiagnostics(): Promise<void> {
try {
const data: SupervisorOptions = {
diagnostics: !this.supervisorInfo?.diagnostics,
diagnostics: !this.supervisor.supervisor?.diagnostics,
};
await setSupervisorOption(this.hass, data);
} catch (err) {
+1 -1
View File
@@ -76,7 +76,7 @@ class HassioSupervisorLog extends LitElement {
${this.hass.userData?.showAdvanced
? html`
<paper-dropdown-menu
label="Log provider"
label="Log Provider"
@iron-select=${this._setLogProvider}
>
<paper-listbox
+29 -12
View File
@@ -19,8 +19,10 @@ import "../../../src/components/ha-card";
import "../../../src/components/ha-settings-row";
import { fetchHassioStats, HassioStats } from "../../../src/data/hassio/common";
import { HassioHostInfo } from "../../../src/data/hassio/host";
import { Supervisor } from "../../../src/data/supervisor/supervisor";
import { haStyle } from "../../../src/resources/styles";
import { HomeAssistant } from "../../../src/types";
import { bytesToString } from "../../../src/util/bytes-to-string";
import {
getValueInPercentage,
roundWithOneDecimal,
@@ -31,42 +33,52 @@ import { hassioStyle } from "../resources/hassio-style";
class HassioSystemMetrics extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property() public hostInfo!: HassioHostInfo;
@property({ attribute: false }) public supervisor!: Supervisor;
@internalProperty() private _supervisorMetrics?: HassioStats;
@internalProperty() private _coreMetrics?: HassioStats;
protected render(): TemplateResult | void {
const usedSpace = this._getUsedSpace(this.hostInfo);
const metrics = [
{
description: "Core CPU usage",
description: "Core CPU Usage",
value: this._coreMetrics?.cpu_percent,
},
{
description: "Core RAM usage",
description: "Core RAM Usage",
value: this._coreMetrics?.memory_percent,
tooltip: `${bytesToString(
this._coreMetrics?.memory_usage
)}/${bytesToString(this._coreMetrics?.memory_limit)}`,
},
{
description: "Supervisor CPU usage",
description: "Supervisor CPU Usage",
value: this._supervisorMetrics?.cpu_percent,
},
{
description: "Supervisor RAM usage",
description: "Supervisor RAM Usage",
value: this._supervisorMetrics?.memory_percent,
tooltip: `${bytesToString(
this._supervisorMetrics?.memory_usage
)}/${bytesToString(this._supervisorMetrics?.memory_limit)}`,
},
{
description: "Used space",
value: usedSpace,
description: "Used Space",
value: this._getUsedSpace(this.supervisor.host),
tooltip: `${this.supervisor.host.disk_used} GB/${this.supervisor.host.disk_total} GB`,
},
];
return html`
<ha-card header="System metrics">
<ha-card header="System Metrics">
<div class="card-content">
${metrics.map((metric) =>
this._renderMetric(metric.description, metric.value ?? 0)
this._renderMetric(
metric.description,
metric.value ?? 0,
metric.tooltip
)
)}
</div>
</ha-card>
@@ -77,13 +89,17 @@ class HassioSystemMetrics extends LitElement {
this._loadData();
}
private _renderMetric(description: string, value: number): TemplateResult {
private _renderMetric(
description: string,
value: number,
tooltip?: string
): TemplateResult {
const roundedValue = roundWithOneDecimal(value);
return html`<ha-settings-row>
<span slot="heading">
${description}
</span>
<div slot="description">
<div slot="description" title="${tooltip ?? ""}">
<span class="value">
${roundedValue}%
</span>
@@ -155,6 +171,7 @@ class HassioSystemMetrics extends LitElement {
}
.value {
width: 42px;
padding-right: 4px;
}
`,
];
+6 -22
View File
@@ -7,14 +7,7 @@ import {
property,
TemplateResult,
} from "lit-element";
import {
HassioHassOSInfo,
HassioHostInfo,
} from "../../../src/data/hassio/host";
import {
HassioInfo,
HassioSupervisorInfo,
} from "../../../src/data/hassio/supervisor";
import { Supervisor } from "../../../src/data/supervisor/supervisor";
import "../../../src/layouts/hass-tabs-subpage";
import { haStyle } from "../../../src/resources/styles";
import { HomeAssistant, Route } from "../../../src/types";
@@ -29,18 +22,12 @@ import "./hassio-system-metrics";
class HassioSystem extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ type: Boolean }) public narrow!: boolean;
@property({ attribute: false }) public route!: Route;
@property() public supervisorInfo!: HassioSupervisorInfo;
@property({ attribute: false }) public hassioInfo!: HassioInfo;
@property() public hostInfo!: HassioHostInfo;
@property({ attribute: false }) public hassOsInfo!: HassioHassOSInfo;
protected render(): TemplateResult | void {
return html`
<hass-tabs-subpage
@@ -56,18 +43,15 @@ class HassioSystem extends LitElement {
<div class="card-group">
<hassio-supervisor-info
.hass=${this.hass}
.hostInfo=${this.hostInfo}
.supervisorInfo=${this.supervisorInfo}
.supervisor=${this.supervisor}
></hassio-supervisor-info>
<hassio-host-info
.hass=${this.hass}
.hassioInfo=${this.hassioInfo}
.hostInfo=${this.hostInfo}
.hassOsInfo=${this.hassOsInfo}
.supervisor=${this.supervisor}
></hassio-host-info>
<hassio-system-metrics
.hass=${this.hass}
.hostInfo=${this.hostInfo}
.supervisor=${this.supervisor}
></hassio-system-metrics>
</div>
<hassio-supervisor-log .hass=${this.hass}></hassio-supervisor-log>
+59 -52
View File
@@ -22,28 +22,29 @@
"author": "Paulus Schoutsen <Paulus@PaulusSchoutsen.nl> (http://paulusschoutsen.nl)",
"license": "Apache-2.0",
"dependencies": {
"@formatjs/intl-pluralrules": "^1.5.8",
"@formatjs/intl-getcanonicallocales": "^1.4.6",
"@formatjs/intl-pluralrules": "^3.4.10",
"@fullcalendar/common": "5.1.0",
"@fullcalendar/core": "5.1.0",
"@fullcalendar/daygrid": "5.1.0",
"@fullcalendar/interaction": "5.1.0",
"@fullcalendar/list": "5.1.0",
"@material/chips": "=8.0.0-canary.096a7a066.0",
"@material/circular-progress": "=8.0.0-canary.a78ceb112.0",
"@material/mwc-button": "^0.18.0",
"@material/mwc-checkbox": "^0.18.0",
"@material/mwc-dialog": "^0.18.0",
"@material/mwc-fab": "^0.18.0",
"@material/mwc-formfield": "^0.18.0",
"@material/mwc-icon-button": "^0.18.0",
"@material/mwc-list": "^0.18.0",
"@material/mwc-menu": "^0.18.0",
"@material/mwc-radio": "^0.18.0",
"@material/mwc-ripple": "^0.18.0",
"@material/mwc-switch": "^0.18.0",
"@material/mwc-tab": "^0.18.0",
"@material/mwc-tab-bar": "^0.18.0",
"@material/top-app-bar": "=8.0.0-canary.096a7a066.0",
"@material/chips": "=9.0.0-canary.1c156d69d.0",
"@material/mwc-button": "^0.20.0",
"@material/mwc-checkbox": "^0.20.0",
"@material/mwc-circular-progress": "^0.20.0",
"@material/mwc-dialog": "^0.20.0",
"@material/mwc-fab": "^0.20.0",
"@material/mwc-formfield": "^0.20.0",
"@material/mwc-icon-button": "^0.20.0",
"@material/mwc-list": "^0.20.0",
"@material/mwc-menu": "^0.20.0",
"@material/mwc-radio": "^0.20.0",
"@material/mwc-ripple": "^0.20.0",
"@material/mwc-switch": "^0.20.0",
"@material/mwc-tab": "^0.20.0",
"@material/mwc-tab-bar": "^0.20.0",
"@material/top-app-bar": "=9.0.0-canary.1c156d69d.0",
"@mdi/js": "5.6.55",
"@mdi/svg": "5.6.55",
"@polymer/app-layout": "^3.0.2",
@@ -77,22 +78,24 @@
"@polymer/paper-toast": "^3.0.1",
"@polymer/paper-tooltip": "^3.0.1",
"@polymer/polymer": "3.1.0",
"@thomasloven/round-slider": "0.5.0",
"@thomasloven/round-slider": "0.5.2",
"@types/chromecast-caf-sender": "^1.0.3",
"@types/sortablejs": "^1.10.6",
"@vaadin/vaadin-combo-box": "^5.0.10",
"@vaadin/vaadin-date-picker": "^4.0.7",
"@vibrant/color": "^3.2.1-alpha.1",
"@vibrant/core": "^3.2.1-alpha.1",
"@vibrant/quantizer-mmcq": "^3.2.1-alpha.1",
"@vue/web-component-wrapper": "^1.2.0",
"@webcomponents/webcomponentsjs": "^2.2.7",
"chart.js": "~2.8.0",
"chartjs-chart-timeline": "^0.3.0",
"codemirror": "^5.49.0",
"comlink": "^4.3.0",
"cpx": "^1.5.0",
"core-js": "^3.6.5",
"cropperjs": "^1.5.7",
"deep-clone-simple": "^1.1.1",
"deep-freeze": "^0.0.1",
"es6-object-assign": "^1.1.0",
"fecha": "^4.2.0",
"fuse.js": "^6.0.0",
"google-timezones-json": "^1.0.2",
@@ -103,21 +106,25 @@
"js-yaml": "^3.13.1",
"leaflet": "^1.4.0",
"leaflet-draw": "^1.0.4",
"lit-element": "^2.3.1",
"lit-html": "^1.2.1",
"lit-element": "^2.4.0",
"lit-html": "^1.3.0",
"lit-virtualizer": "^0.4.2",
"marked": "^1.1.1",
"mdn-polyfills": "^5.16.0",
"memoize-one": "^5.0.2",
"node-vibrant": "^3.1.5",
"node-vibrant": "3.2.1-alpha.1",
"proxy-polyfill": "^0.3.1",
"punycode": "^2.1.1",
"qrcode": "^1.4.4",
"regenerator-runtime": "^0.13.2",
"resize-observer-polyfill": "^1.5.1",
"roboto-fontface": "^0.10.0",
"sortablejs": "^1.10.2",
"superstruct": "^0.10.12",
"tinykeys": "^1.1.1",
"unfetch": "^4.1.0",
"vis-data": "^7.1.1",
"vis-network": "^8.5.4",
"vue": "^2.6.11",
"vue2-daterange-picker": "^0.5.1",
"web-animations-js": "^2.3.2",
@@ -128,16 +135,20 @@
"xss": "^1.0.6"
},
"devDependencies": {
"@babel/core": "^7.9.0",
"@babel/plugin-external-helpers": "^7.8.3",
"@babel/plugin-proposal-class-properties": "^7.8.3",
"@babel/plugin-proposal-decorators": "^7.8.3",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3",
"@babel/plugin-proposal-object-rest-spread": "^7.9.5",
"@babel/plugin-proposal-optional-chaining": "^7.9.0",
"@babel/core": "^7.11.6",
"@babel/plugin-external-helpers": "^7.10.4",
"@babel/plugin-proposal-class-properties": "^7.10.4",
"@babel/plugin-proposal-decorators": "^7.10.5",
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.4",
"@babel/plugin-proposal-object-rest-spread": "^7.11.0",
"@babel/plugin-proposal-optional-chaining": "^7.11.0",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/preset-env": "^7.9.5",
"@babel/preset-typescript": "^7.9.0",
"@babel/plugin-syntax-import-meta": "^7.10.4",
"@babel/preset-env": "^7.11.5",
"@babel/preset-typescript": "^7.10.4",
"@koa/cors": "^3.1.0",
"@open-wc/dev-server-hmr": "^0.0.2",
"@rollup/plugin-babel": "^5.2.1",
"@rollup/plugin-commonjs": "^11.1.0",
"@rollup/plugin-json": "^4.0.3",
"@rollup/plugin-node-resolve": "^7.1.3",
@@ -154,10 +165,13 @@
"@types/mocha": "^7.0.2",
"@types/resize-observer-browser": "^0.1.3",
"@types/webspeechapi": "^0.0.29",
"@typescript-eslint/eslint-plugin": "^2.28.0",
"@typescript-eslint/parser": "^2.28.0",
"@typescript-eslint/eslint-plugin": "^4.4.0",
"@typescript-eslint/parser": "^4.4.0",
"@web/dev-server": "^0.0.24",
"@web/dev-server-rollup": "^0.2.11",
"babel-loader": "^8.1.0",
"chai": "^4.2.0",
"cpx": "^1.5.0",
"del": "^4.0.0",
"eslint": "^6.8.0",
"eslint-config-airbnb-typescript": "^7.2.1",
@@ -173,14 +187,13 @@
"gulp": "^4.0.0",
"gulp-foreach": "^0.1.0",
"gulp-json-transform": "^0.4.6",
"gulp-jsonminify": "^1.1.0",
"gulp-merge-json": "^1.3.1",
"gulp-rename": "^2.0.0",
"gulp-zopfli-green": "^3.0.1",
"html-minifier": "^4.0.0",
"husky": "^1.3.1",
"lint-staged": "^8.1.5",
"lit-analyzer": "^1.2.0",
"lit-analyzer": "^1.2.1",
"lodash.template": "^4.5.0",
"magic-string": "^0.25.7",
"map-stream": "^0.0.7",
@@ -192,7 +205,6 @@
"raw-loader": "^2.0.0",
"require-dir": "^1.2.0",
"rollup": "^2.8.2",
"rollup-plugin-babel": "^4.4.0",
"rollup-plugin-string": "^3.0.0",
"rollup-plugin-terser": "^5.3.0",
"rollup-plugin-visualizer": "^4.0.4",
@@ -200,30 +212,25 @@
"sinon": "^7.3.1",
"source-map-url": "^0.4.0",
"systemjs": "^6.3.2",
"terser-webpack-plugin": "^3.0.6",
"ts-lit-plugin": "^1.2.0",
"terser-webpack-plugin": "^5.0.0",
"ts-lit-plugin": "^1.2.1",
"ts-mocha": "^7.0.0",
"typescript": "^3.8.3",
"typescript": "^4.0.3",
"vinyl-buffer": "^1.0.1",
"vinyl-source-stream": "^2.0.0",
"webpack": "^4.40.2",
"webpack-cli": "^3.3.9",
"webpack-dev-server": "^3.10.3",
"webpack-manifest-plugin": "^2.0.4",
"workbox-build": "^5.1.3",
"worker-plugin": "^4.0.3"
"webpack": "5.1.3",
"webpack-cli": "4.1.0",
"webpack-dev-server": "^3.11.0",
"webpack-manifest-plugin": "3.0.0-rc.0",
"workbox-build": "^5.1.3"
},
"_comment": "Polymer fixed to 3.1 because 3.2 throws on logbook page",
"_comment_2": "Fix in https://github.com/Polymer/polymer/pull/5569",
"resolutions": {
"@webcomponents/webcomponentsjs": "^2.2.10",
"@polymer/polymer": "3.1.0",
"lit-html": "1.2.1",
"lit-element": "2.3.1",
"@material/animation": "8.0.0-canary.096a7a066.0",
"@material/base": "8.0.0-canary.096a7a066.0",
"@material/feature-targeting": "8.0.0-canary.096a7a066.0",
"@material/theme": "8.0.0-canary.096a7a066.0"
"lit-html": "1.3.0",
"lit-element": "2.4.0"
},
"main": "src/home-assistant.js",
"husky": {

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