Compare commits

...
Author SHA1 Message Date
Zack 44a52075ec Remove entity_matches_only 2022-05-11 10:20:28 -05:00
Yosi LevyandGitHub c9c3be71cc Merge pull request #12620 from yosilevy/RTL-no-host-context
Replace host-context with css properties - after session with Bram
2022-05-11 16:30:21 +03:00
Bram Kragten f1b965dcc5 Update ha-fab.ts 2022-05-11 15:19:03 +02:00
Bram Kragten a08a23a93d Use FabBase 2022-05-11 14:25:43 +02:00
Bram Kragten 2040a49458 Update var name 2022-05-11 14:21:02 +02:00
Bram KragtenandGitHub df94f4f907 Merge branch 'dev' into RTL-no-host-context 2022-05-11 14:18:26 +02:00
Bram Kragten 96d375cb84 Use / 2022-05-11 14:16:44 +02:00
7a9c2f56c5 Rtl menu fix (#12561)
Co-authored-by: Bram Kragten <[email protected]>
2022-05-11 11:01:45 +02:00
J. Nick KostonandGitHub 5ec7193e5c Show script traces in logbook (#12643) 2022-05-10 23:32:09 +02:00
d89e4337f2 Hide Cloud URL - Add Copy Icon (#12655)
Co-authored-by: Bram Kragten <[email protected]>
2022-05-10 19:37:31 +00:00
Zack BarettandGitHub 2e192d5021 Update Translations to create helper (#12656) 2022-05-10 21:25:03 +02:00
Yosi Levy 7db28c0156 Update following review 2022-05-10 19:31:23 +03:00
f09c842981 Update src/state/translations-mixin.ts
Co-authored-by: Bram Kragten <[email protected]>
2022-05-10 18:25:28 +03:00
Yosi LevyandGitHub b295bbd706 RTL settings clickable list item fix (#12595) 2022-05-10 16:57:18 +02:00
Patrick ZAJDAandGitHub 8d3132fefc Add label for Fix issue column header in statistics developer tools (#12597)
Signed-off-by: Patrick ZAJDA <[email protected]>
2022-05-09 17:14:59 +02:00
00c5d3dbbb Add configuration panel for Application Credentials (#12344)
Co-authored-by: Zack Barett <[email protected]>
Co-authored-by: Zack <[email protected]>
2022-05-09 17:03:59 +02:00
Zack BarettandGitHub ca37aff47d Move YAML to first tab of Developer Tools (#12589) 2022-05-09 08:07:17 -05:00
Joakim SørensenandGitHub 9ed069ef6a Get full core logs from core (#12639) 2022-05-09 08:07:01 -05:00
Philip AllgaierandGitHub 6faa3eb848 Remove "Lovelace" from Github issue templates (#12614)
* Remove "Lovelace" from Github issue templates

* Changes from review
2022-05-09 09:47:39 +02:00
Yosi Levy 6c73ae5bf7 Replace host-context with css properties 2022-05-07 06:39:39 +03:00
Zack BarettandGitHub ce77ddf365 Revert #10991 (#12618) 2022-05-07 02:48:57 +00:00
Steve RepsherandGitHub cf05fbaa9d Fix enter key support for generic dialog box (#12600) 2022-05-06 13:32:44 +02:00
Joakim SørensenandGitHub 552c474feb Fix setting _externalAccess (#12584) 2022-05-04 08:17:09 -05:00
Bram Kragten a4f8e886bc Bumped version to 20220504.0 2022-05-04 13:14:25 +02:00
Bram KragtenandGitHub cc0c96b8b4 Make update notification better, add progress (#12581) 2022-05-04 11:09:54 +00:00
Philip AllgaierandGitHub 445f0e23fe System menu description tweaks (#12578) 2022-05-04 11:07:41 +00:00
Bram KragtenandGitHub 6f240297d1 Remove hassio config panel (#12580) 2022-05-04 10:20:41 +00:00
Paulus SchoutsenandGitHub 6da4981b70 Clone on duplicate (#12574) 2022-05-04 12:04:59 +02:00
Zack BarettandGitHub cfadf4d700 Fixes issue where the grid cards wouldnt be sized correctly (#12571) 2022-05-04 12:04:24 +02:00
Zack BarettandGitHub 7e60de0531 Add padding when no updates (#12575) 2022-05-04 11:59:24 +02:00
Zack BarettandGitHub aaef6d7b91 Fix Overlapping Media List items (#12569) 2022-05-03 23:10:40 +02:00
Zack BarettandGitHub 58c5ce2638 Bumped version to 20220503.0 (#12566) 2022-05-03 11:14:12 -07:00
Joakim SørensenandGitHub a9d01c7b55 Add missing outlined to supervisor panel (#12565) 2022-05-03 17:06:21 +00:00
Zack BarettandGitHub c5de8a4361 Add new system menu descriptions (#12564) 2022-05-03 16:44:43 +00:00
Bram KragtenandGitHub b53645ce92 Add disabled support to trace timeline and step details (#12555) 2022-05-03 09:50:33 -05:00
Bram KragtenandGitHub de34a5a597 Fix searching in hassio logs (#12560) 2022-05-03 07:30:01 -05:00
bd8e15bdd1 Add supervisor redirects to quickbar (#12557)
Co-authored-by: Bram Kragten <[email protected]>
2022-05-03 11:57:09 +00:00
Bram KragtenandGitHub 45c7e0eeeb Use outline for cards on config pages (#12558) 2022-05-03 06:44:55 -05:00
Zack BarettandGitHub a35a380ec7 Update Quickbar Section Logic to include all (#12553) 2022-05-03 13:25:46 +02:00
Bram KragtenandGitHub 02e67d1146 Use ha-tip for yaml move tip (#12559) 2022-05-03 11:22:48 +00:00
Zack BarettandGitHub a5411f7ac4 Search in Overflow on Mobile (#12552) 2022-05-03 13:17:47 +02:00
Zack BarettandGitHub e8da203fe1 Fix Webhook Overflow (#12551) 2022-05-03 13:17:02 +02:00
Joakim SørensenandGitHub 10aa0a8829 Add add-on logs to log selector (#12556) 2022-05-03 13:13:20 +02:00
Paulus Schoutsen 85a37e2d2f Bumped version to 20220502.0 2022-05-02 15:08:01 -07:00
Bram KragtenandGitHub ba8621fa2c Indicate things are disabled in trace graph (#12550)
* Indicate things are disabled in trace graph

* Update hat-script-graph.ts
2022-05-02 15:07:36 -07:00
Bram KragtenandGitHub 43e80f1a2e Add parallel action to trace timeline (#12549) 2022-05-02 15:07:01 -07:00
Bram KragtenandGitHub 3a305a44b6 Handle if in repeat (#12544) 2022-05-02 14:48:28 -07:00
Bram KragtenandGitHub e99143139e Fix script graph parallel (#12545) 2022-05-02 14:47:43 -07:00
Bram KragtenandGitHub f0c7232704 Add trace timeline for if (#12543) 2022-05-02 14:47:17 -07:00
Zack BarettandGitHub b2186592df Change name to Settings (#12548) 2022-05-02 23:29:06 +02:00
Bram KragtenandGitHub e51e3e79d5 Add repeat to trace timeline (#12547) 2022-05-02 17:16:32 +00:00
3b6b4d7664 Add descriptions for actions (#12541)
Co-authored-by: Paulus Schoutsen <[email protected]>
2022-05-02 15:06:55 +00:00
Zack BarettandGitHub 239e71b414 Fix some issues and feedback with About and system health (#12537) 2022-05-02 12:54:55 +02:00
Philip AllgaierandGitHub 080cad0ccd Prevent color temp selector mired exception (#12536) 2022-05-01 22:21:25 +00:00
Allen PorterandGitHub dd49fd2788 Make the "Aborted: Reauthentication successful" more user friendly (#12530)
Replace the "Aborted" in the title with the integration name to make the user error
messages more user friendly. The message itself ("Reauthentication successful" or "Missing configuraiton, etc) error
message is descriptive enought that we can replace the title with the integration
name and still preserve the meeting. The advance is that this doesn't confuse users
who are surprised by it saying "Aborted" when things were successful

https://github.com/home-assistant/core/issues/47135
2022-05-01 11:02:32 -05:00
Thomas LovénandGitHub a571fb5528 Handle condition shorthands in trace graphs (#12533) 2022-05-01 10:59:46 -05:00
Yosi LevyandGitHub 1369c1ae8c Calendar-card fix (#12532) 2022-05-01 10:59:12 -05:00
Joakim SørensenandGitHub f5864181af Add optional repository_url to supervisor_addon my link (#12524) 2022-04-30 16:53:43 -05:00
Joakim SørensenandGitHub a4a0d7cf19 Ignore modifier keys when forwarding events to quickbar (#12525) 2022-04-30 16:52:14 -05:00
Bram KragtenandGitHub 092dfd1e87 Change color of persons for real this time (#12527) 2022-04-30 14:31:43 -05:00
Zack BarettandGitHub a29ac33810 Bumped version to 20220429.0 (#12521) 2022-04-29 15:37:42 -07:00
Bram KragtenandGitHub 1421df2a5a Add if, parallel and stop action to trace graph (#12520) 2022-04-29 16:30:40 -05:00
Zack BarettandGitHub 591b8cc503 Move integrations to System Health (#12504) 2022-04-29 20:53:24 +02:00
Bram KragtenandGitHub 011467ece0 Add actions to design gallery (#12518)
* Add actions to design gallery

* Update describe-action.ts
2022-04-29 20:51:44 +02:00
Zack BarettandGitHub f52e8c3392 Restart Home ASsistant button - Make less red and less big (#12515) 2022-04-29 19:15:43 +02:00
Zack BarettandGitHub c8b87b65bd Fix for external url not logged into cloud (#12516) 2022-04-29 16:19:53 +00:00
Thomas LovénandGitHub 98cc82db44 Add condition shorthand to action types (#12514) 2022-04-29 15:40:03 +00:00
Zack BarettandGitHub f510e2a8e0 Only show Card Content if OS exist (#12513) 2022-04-29 16:49:47 +02:00
Franck NijhofandGitHub 3438912ba5 Support shorthand logical operators in script sequences (#12509) 2022-04-29 09:47:44 -05:00
Bruno MaiaandGitHub 671c8e387f Fix continue_on_timeout default on wait_template automation visual editor (#12511) 2022-04-29 14:37:35 +00:00
Yosi LevyandGitHub 0108ec65cf Media browser RTL fixes (#12506) 2022-04-29 09:27:06 -05:00
Philip AllgaierandGitHub 39f7034578 Fix incorrect 3-dot menu labels (config hardware & storage) (#12512) 2022-04-29 09:24:37 -05:00
Bram KragtenandGitHub bf8affaf2b Use media query for config menu mobile (#12510) 2022-04-29 07:41:27 -05:00
Yosi LevyandGitHub e16a61eb53 form-string password fix (#12507) 2022-04-29 11:50:19 +02:00
Zack BarettandGitHub cadbe45bab Fix Wrap menu and remove menu title (#12505) 2022-04-28 19:23:23 -07:00
Zack BarettandGitHub 51f971337d Bumped version to 20220428.0 (#12501) 2022-04-28 13:50:08 -07:00
Zack BarettandGitHub 1f3c23de29 Change Restart to be a button, update dialogs (#12499) 2022-04-28 13:43:00 -07:00
bdfb17d957 Add Board Names, Move All Hardware (#12484)
Co-authored-by: Joakim Sørensen <[email protected]>
Co-authored-by: Paulus Schoutsen <[email protected]>
2022-04-28 20:42:18 +00:00
Franck NijhofandGitHub 8c97aee1fe Add parallel automation/script action (#12491) 2022-04-28 15:09:03 -05:00
Bram KragtenandGitHub 38b4090daa Add support for enabling/disabling trigger/condition/action (#12493)
* Add support for enabling/disabling trigger/condition/action

* Add more visual indication of disabled

* review

* margin

* Dont make overflow transparent

* Change color of bar
2022-04-28 18:37:58 +02:00
b8c55f2f65 Evaluate condition shorthands in editors (#12473)
Co-authored-by: Paulus Schoutsen <[email protected]>
2022-04-28 08:36:17 -07:00
Bram KragtenandGitHub 7ca379e0a1 Hide and sort secondary device automations (#12496) 2022-04-28 08:53:56 -05:00
Bram KragtenandGitHub 1617a9dfed Address minor comments about config menu (#12492) 2022-04-28 08:44:01 -05:00
Franck NijhofandGitHub 2c9411c6c3 Add template editor to Markdown card editor (#12490) 2022-04-28 12:40:39 +02:00
Zack BarettandGitHub 67626d4a06 add my redirects for new config pages (#12481) 2022-04-28 12:39:35 +02:00
Yosi LevyandGitHub 8135611688 Media panel fix (#12485) 2022-04-28 05:16:18 +00:00
Zack BarettandGitHub 3ccbf6983e Move General Up in the system menu (#12483) 2022-04-27 22:08:21 -07:00
e4f91195d8 Fix Restarting Home Assistant (#12480)
* Fix Restarting Home ASsistant

* Update src/panels/config/core/ha-config-system-navigation.ts

Co-authored-by: Paulus Schoutsen <[email protected]>

* Update src/panels/developer-tools/yaml_configuration/developer-yaml-config.ts

Co-authored-by: Paulus Schoutsen <[email protected]>

* reviews

Co-authored-by: Paulus Schoutsen <[email protected]>
2022-04-27 15:55:04 -07:00
2751f8f33b Add some bottom padding to YAML conf dev tools page (#12477)
Co-authored-by: Zack Barett <[email protected]>
2022-04-27 22:18:25 +02:00
Philip AllgaierandGitHub 57f2df3b3e Visual tweaks to YAML validation results (#12479) 2022-04-27 19:57:41 +00:00
Zack BarettandGitHub 6822f0d067 Small config fixes (#12472) 2022-04-27 12:22:57 -07:00
Zack BarettandGitHub cfba957313 Fix YAML Config Invalid button (#12476) 2022-04-27 13:57:57 -05:00
Yosi LevyandGitHub 3149ffbf19 RTL fix for log buttons (#12474) 2022-04-27 12:26:19 -05:00
Philip AllgaierandGitHub 4cd8b76d7e Safeguard against non-existant area in device handling (#12475) 2022-04-27 12:25:13 -05:00
Joakim SørensenandGitHub 4b644d8bc5 Add supervisor redirects to m keyboard shortcut (#12466) 2022-04-27 13:36:47 +00:00
Joakim SørensenandGitHub 307cd5ad8c Use startsWith for m shortcut for partial match (#12464) 2022-04-27 08:10:38 -05:00
Joakim SørensenandGitHub ebc807a6a4 Add hass-quick-bar-trigger event to trigger quickbar from supervisor (#12467) 2022-04-27 08:08:45 -05:00
Philip AllgaierandGitHub 66adecdfc9 Make helper option button more user friendly (#12468) 2022-04-27 08:07:57 -05:00
Philip AllgaierandGitHub 2cc6432a0f Use correct label for update config menu (#12465) 2022-04-27 06:37:50 -05:00
Paulus Schoutsen a2c0c0474a Bumped version to 20220427.0 2022-04-26 22:13:16 -07:00
Zack BarettandGitHub 27884b9a54 Move Restart to Overflow and yaml config advanced (#12446)
* Move Restart to Overflow and yaml config advanced

* Move around YAML Config page

* Move to developer tools

* Make card actions

* Update Translations
2022-04-26 22:12:44 -07:00
Paulus SchoutsenandGitHub 293df61872 Add a tip for my shortcut (#12462) 2022-04-27 05:01:40 +00:00
Paulus SchoutsenandGitHub f82dada3e5 Fix icon alignment in nav list (#12463) 2022-04-26 21:58:26 -07:00
e5824c4794 Fix my link for config dashboard and profile (#12461)
* Fix my link for config dashboard and profile

* add server control redirect

Co-authored-by: Zack <[email protected]>
2022-04-27 04:58:18 +00:00
Paulus SchoutsenandGitHub 186550229c Tweak menu descriptions (#12460) 2022-04-27 04:53:42 +00:00
7877dd8e6b Move Zones Edit to General config + add general config page (#12452)
* Move Zones Edit to General config + add general

* Update src/translations/en.json

Co-authored-by: Paulus Schoutsen <[email protected]>

* add paper tooltip back for yaml

Co-authored-by: Paulus Schoutsen <[email protected]>
2022-04-26 21:53:29 -07:00
Zack BarettandGitHub b03abc249b Fix Updates Page Toast - Move to overflow (#12453) 2022-04-26 21:52:22 -07:00
Paulus SchoutsenandGitHub fda03918b9 Move the analytics link (#12459) 2022-04-27 04:40:01 +00:00
Zack BarettandGitHub 6747375a1b Move Provider Selection to Menu on top header (#12443) 2022-04-26 23:27:15 -05:00
Zack BarettandGitHub 53b6e31881 Update Configuration badge color to be accent color to match (#12455) 2022-04-26 21:12:09 -07:00
Zack BarettandGitHub fa004de2d1 Fix more info input number #12396 (#12456) 2022-04-26 21:11:54 -07:00
Zack BarettandGitHub 3605f7b70f Fix when creating new area in picker #11392 (#12457) 2022-04-26 21:11:38 -07:00
Zack BarettandGitHub 5348c54c91 Update the hint for key C (#12458) 2022-04-26 21:11:18 -07:00
Zack BarettandGitHub 684e4421bc Fix for backup overflow (#12454) 2022-04-26 21:10:35 -07:00
Zack BarettandGitHub 28f5611df5 Small edits on config menu (#12440) 2022-04-26 21:07:53 -07:00
Johann VanackereandGitHub 8da73d49d7 Terms based entities search (#10991) 2022-04-26 19:39:58 -05:00
Joakim SørensenandGitHub 049ddd5f84 Add "m" keyboard shortcut to get to the create my link page (#12451) 2022-04-27 00:11:09 +02:00
Bram KragtenandGitHub 8ae2d4e93a Fix integration page on mobile (#12447) 2022-04-26 14:38:59 -05:00
Philip AllgaierandGitHub 824bb9ba35 Add title to backups config page (#12442) 2022-04-26 21:04:32 +02:00
Philip AllgaierandGitHub d550b1a18e Fix content display for ha-network after #12438 (#12445)
* Fix content display for `ha-network` after #12438

* Add var default
2022-04-26 20:41:19 +02:00
Bram KragtenandGitHub dea6c0e761 Add header to supervisor backups page (#12444) 2022-04-26 17:53:32 +00:00
Philip AllgaierandGitHub 9caee357c0 Fix incorrect text if no backups are found (#12441) 2022-04-26 12:32:04 -05:00
Bram KragtenandGitHub 35d892c418 Set border radius in config to 8px (#12437) 2022-04-26 11:50:36 -05:00
Bram KragtenandGitHub 9572a2a46b Dont show tabs when less than 2 (#12439) 2022-04-26 15:39:50 +00:00
Bram KragtenandGitHub 8996361b26 Fix settings row width (#12438) 2022-04-26 15:17:00 +00:00
Joakim SørensenandGitHub 02ee731602 Add join/leave beta to updates panel (#12436) 2022-04-26 16:39:37 +02:00
Joakim SørensenandGitHub bb1e6bf35b Fix backup back path (#12435) 2022-04-26 15:29:56 +02:00
Joakim SørensenandGitHub c1b65285c1 Redirect hassio system my links to new locations (#12429) 2022-04-26 13:15:29 +02:00
Bram KragtenandGitHub 8b8d6e5fa3 Resources lovelace should just go back (#12432) 2022-04-26 11:12:14 +00:00
Joakim SørensenandGitHub c34fe184e8 Fix log syntax highlight when fetching logs from supervisor (#12430) 2022-04-26 06:09:39 -05:00
Joakim SørensenandGitHub 7363838f86 Move unsupported and unhealthy alerts (#12431) 2022-04-26 12:24:55 +02:00
Jaroslav HanslíkandGitHub 3081425ccd Typo in en.json (#12428) 2022-04-26 12:20:26 +02:00
Joakim SørensenandGitHub 95d494a54c Guard against non OS installation (#12427) 2022-04-26 12:18:43 +02:00
J. Nick KostonandGitHub 145e5d7bc6 Format sensors with state class duration (#12426) 2022-04-26 02:07:11 +00:00
Zack BarettandGitHub 876fd9e85a Bumped version to 20220425.0 (#12425) 2022-04-25 18:25:07 -05:00
Zack BarettandGitHub e8c30cabca Show usage stats in System Health (#12424) 2022-04-25 23:24:58 +00:00
Bram KragtenandGitHub 490f84a7b1 link to updates page (#12423) 2022-04-25 15:56:34 -05:00
Artem SorokinandGitHub ca28178b86 Fix title and description for menu step in options flow (#12420) 2022-04-25 20:26:05 +00:00
Zack BarettandGitHub 2fceb0aeee Allow for checking for updates (#12422) 2022-04-25 22:15:26 +02:00
Bram KragtenandGitHub 86f39d1d43 Add supervisor, OS version info to about page (#12421)
* Add supervisor, OS version info to about page

* description

* description
2022-04-25 22:14:32 +02:00
Zack BarettandGitHub 1faf60444d Move Data Disk Moving to Storage (#12416) 2022-04-25 20:49:44 +02:00
NetzwerkfehlerandGitHub e927091d21 Better gauge segment coloring (#11570) 2022-04-25 13:43:53 -05:00
Bram KragtenandGitHub cff2f856b3 Don't show tabs in supervisor (#12417) 2022-04-25 13:37:48 -05:00
Bram KragtenandGitHub a743e3bbba Show what updates are skipped (#12418) 2022-04-25 18:37:24 +00:00
Zack BarettandGitHub f8a52d250e Move System Health to a page (#12412) 2022-04-25 20:26:53 +02:00
Zack BarettandGitHub b70a523bdf Backup Page - Will load which is available (#12414) 2022-04-25 19:54:11 +02:00
Zack BarettandGitHub 8f2ed747e6 Configuration Menu Cleanup items (#12413) 2022-04-25 19:53:02 +02:00
Zack BarettandGitHub 5deccefb15 Allow Showing Skipped Updates on Updates Page (#12415) 2022-04-25 19:50:30 +02:00
Zack BarettandGitHub 3f04abfa9d Add Supervisor logs to core page (#12410) 2022-04-25 15:35:03 +00:00
Zack BarettandGitHub 8e55c83996 Add Hardware Page to Configuration System Menu (#12405) 2022-04-25 17:30:53 +02:00
Bram KragtenandGitHub dee59486ba Add supervisor hostname config (#12407) 2022-04-25 10:27:38 -05:00
Bram KragtenandGitHub 77ef509aea Fix zones (#12409) 2022-04-25 15:13:31 +00:00
Bram KragtenandGitHub bfa7bccfa6 Add supervisor network interface settings (#12403) 2022-04-25 16:21:03 +02:00
Thomas LovénandGitHub a8c365edc8 Fix broken cards being able to crash entire view (#11440) 2022-04-25 14:37:32 +02:00
Bram KragtenandGitHub 94953ddf6c Hide supervisor only config, fix backup config page (#12401) 2022-04-25 07:09:23 -05:00
Zack BarettandGitHub 6b67546daf Virtualize Media Player Grid (#11898) 2022-04-25 12:32:50 +02:00
Paulus SchoutsenandGitHub 3e188d1f87 Add shorthand condition to the gallery (#12400) 2022-04-25 10:00:28 +02:00
Zack BarettandGitHub f69eb15a90 Config Menu: Addressing Comments in #12377 (#12399) 2022-04-24 20:25:47 -07:00
Paulus Schoutsen dfe348187f Bumped version to 20220424.0 2022-04-24 15:26:42 -07:00
Zack BarettandGitHub 9706c56c5c Configuration Menu Updates 3 (#12377) 2022-04-24 15:26:01 -07:00
Raman GuptaandGitHub 3677c5be2c Update zwavejs controller model (#12390) 2022-04-24 14:55:31 -07:00
Zack BarettandGitHub bd339fa963 Fix Dashboard URLs (#12394) 2022-04-24 14:55:04 -07:00
Yosi LevyandGitHub 28f1b6bdf4 Force LTR on time & number inputs (#12393) 2022-04-23 19:48:17 -05:00
Zack BarettandGitHub c5aac3b81d Add Empty list item for None (#12356) 2022-04-23 10:11:44 -05:00
yangqianandGitHub 70836597e9 Show vacuum state in more-info dialog for StateVacuumEntity (#12391) 2022-04-23 06:32:59 +00:00
Allen PorterandGitHub 958a1de2fd Add calendar event end trigger to automation editor (#12389) 2022-04-23 00:19:23 -05:00
Allen PorterandGitHub 36d30266e3 Add automation editor for calendar trigger (#12343) 2022-04-22 16:53:45 -05:00
Yosi LevyandGitHub 558ab9761d RTL reading orders and alignments in system log (#12388) 2022-04-22 20:19:38 +00:00
269ef370e4 Accept new value when hitting ENTER to close a prompt dialog (#12360)
Co-authored-by: Zack Barett <[email protected]>
2022-04-22 14:23:34 -05:00
Kuba WolaninandGitHub ba2958ecd2 zwave_js: Add title tag to config box heading (#12387) 2022-04-22 13:17:42 -05:00
Yosi LevyandGitHub 3b8b6eb315 RTL fixes (#12367) 2022-04-22 10:27:49 -05:00
Mark LopezandGitHub 4f13db3178 Added ability to retry on initialization errors. (#12103) 2022-04-21 21:11:32 -05:00
Joakim SørensenandGitHub ee7aa54ab4 Add entity search tip to dev-tools set state (#12355) 2022-04-21 21:06:35 -05:00
Wesley VosandGitHub c305dd4cd5 Fix for monetary entities (#12378) 2022-04-21 21:01:09 -05:00
6865791596 Add jinja2 editor to template triggers/conditions (#12365)
Co-authored-by: Zack <[email protected]>
2022-04-22 01:42:28 +00:00
Franck NijhofandGitHub 2099259393 Use template selector in wait_template (#12366) 2022-04-21 20:32:25 -05:00
Zack BarettandGitHub 27ca45dc70 Bumped version to 20220420.0 (#12369) 2022-04-20 22:43:40 +00:00
Zack BarettandGitHub d290c11219 Config menu updates to get it ready for nightly (#12368) 2022-04-20 22:38:35 +00:00
cabe10ffdb Getting started on Configuration Changes (#12309)
Co-authored-by: Bram Kragten <[email protected]>
2022-04-20 16:57:51 -05:00
Franck NijhofandGitHub aa562c21a8 Add stop script/automation action (#12299) 2022-04-20 16:50:09 -05:00
22175a7271 Add if/else automation/script action (#12301)
Co-authored-by: Zack Barett <[email protected]>
2022-04-20 11:27:16 -05:00
Eric SternandGitHub 1e0647c0d1 Github no longer supports the (insecure) git protocol (#12359) 2022-04-20 13:52:12 +00:00
Simon VallièresandGitHub 58d94da8b3 Adding blueprint input description markdown/multi-line support (#12291) 2022-04-20 08:36:18 -05:00
Joakim SørensenandGitHub d97763a3e8 Add clear skipped to update more-info dialog (#12361) 2022-04-20 08:17:56 -05:00
Paulus SchoutsenandGitHub aa129aa123 Bump HAWS to 7.0.3 (#12358) 2022-04-19 12:50:18 -05:00
Franck NijhofandGitHub f648317206 Fix strict error handling in developer tools templates (#12352) 2022-04-19 07:28:07 -05:00
Raman GuptaandGitHub 0685fdf7c6 Add basic frontend support for siren (#12345) 2022-04-18 11:19:01 -05:00
Franck NijhofandGitHub 6fd4cda534 Add Template selector (#12348) 2022-04-18 11:17:44 -05:00
511368da13 Allow selecting multiple entities for state trigger (#12334)
Co-authored-by: Zack Barett <[email protected]>
2022-04-15 19:03:14 +00:00
J. Nick KostonandGitHub 76e1721c58 Quickly search for entities from the Overview Dashboard (#12324) 2022-04-15 13:54:57 -05:00
Yosi LevyandGitHub bad5a389b5 RTL calendar fix - arrows fix and views fix (#12314)
* RTL calendar fix - arrows fix and views fix

* Removed path attributes
2022-04-15 13:47:46 -05:00
Paulus SchoutsenandGitHub 85d1f49763 Allow tapping on the name on a picture entity card (#12332) 2022-04-15 08:55:22 -05:00
Paulus SchoutsenandGitHub 7723d47ac1 Split only on first comma in media browser (#12331) 2022-04-14 17:52:49 -05:00
J. Nick KostonandGitHub 30b130ca74 Use new mdi icons for smoke and co detection (#12323) 2022-04-14 15:42:54 -07:00
Joakim SørensenandGitHub a124ec0717 Always render title field (#12319) 2022-04-13 07:20:00 -05:00
Joakim SørensenandGitHub 323d98ecf7 Decode view path URL (#12310) 2022-04-12 06:52:17 -05:00
Paulus SchoutsenandGitHub 125a601ae3 Select default mode if none set (#12306) 2022-04-11 12:08:37 -05:00
Paulus SchoutsenandGitHub 3c549c6b31 Update cloud text (#12305) 2022-04-11 09:47:31 -07:00
Kuba WolaninandGitHub 9c1494c74d Fix endless loading screen in zwave-js config (#12295) 2022-04-11 16:56:03 +02:00
Philip AllgaierandGitHub e751abd775 Prevent empty brackets if no manufacturer during config entry creation (#12288) 2022-04-11 09:06:29 -05:00
Joakim SørensenandGitHub 714f2447b7 Use more text selector types for add-on configuration (#12303) 2022-04-11 16:01:30 +02:00
Franck NijhofandGitHub d900e40d04 Fix add-on security rating range (#12300) 2022-04-11 14:04:54 +02:00
Joakim SørensenandGitHub 8b82383790 Guard for partial translations (#12296) 2022-04-11 13:03:41 +02:00
Zack BarettandGitHub 5a2cc2646c Merge pull request #12252 from spacegaier/issue-12246 2022-04-07 16:40:08 -05:00
Philip Allgaier 16a0902989 Adjust import 2022-04-07 22:41:37 +02:00
Philip Allgaier 8f67aa38af Fix entity and device selector with multiple: true 2022-04-07 21:39:04 +02:00
Zack BarettandGitHub 34184cf2ab Merge pull request #12250 from spacegaier/issue-12248 2022-04-07 14:11:29 -05:00
Philip Allgaier 611cd2818e Exclude hidden entities from area card 2022-04-07 20:58:21 +02:00
Zack BarettandGitHub 0a4e8fd5d0 Merge pull request #12244 from home-assistant/lineup-badges 2022-04-07 13:19:48 -05:00
Ludeeus 11f0361f48 Lineup sidebar badges 2022-04-07 06:54:24 +00:00
Philip AllgaierandGitHub cfa048ea4e Only show "required" indicator if we have a selector label (#12241) 2022-04-06 22:11:12 +00:00
Joakim SørensenandGitHub bbca7b762b Use selectors for add-on network configuration (#12235)
* Use selectors for add-on network configuration

* Show container port as UOM if advanced user

* adjust
2022-04-06 22:21:06 +02:00
Erik MontnemeryandGitHub 1dba849567 Fix statistics chart for sum stat without state (#12238) 2022-04-06 20:54:11 +02:00
MariusandGitHub aff1ec10bf replace ToggleSwitch with new LightSwitch (#12218) 2022-04-06 16:26:34 +02:00
Joakim SørensenandGitHub 351ec08a71 Use selectors for add-on configurations (#12234) 2022-04-06 09:57:17 +02:00
Paulus Schoutsen a1a6a2cd30 Bumped version to 20220405.0 2022-04-05 15:49:13 -07:00
Joakim SørensenandGitHub 4e82c23b29 Fixes for flow help icon (#12224) 2022-04-05 15:47:24 -07:00
Paulus SchoutsenandGitHub 59595aabde Add helpers to all selectors (#12230) 2022-04-05 15:26:52 -05:00
Paulus SchoutsenandGitHub 358f91c2a9 Add statistic name to adjust dialog (#12229) 2022-04-05 17:25:23 +00:00
Joakim SørensenandGitHub e0e01e68b4 Use change instead of click when selecting home assistant in backup (#12226) 2022-04-05 10:48:45 -05:00
Paulus SchoutsenandGitHub 61dc4eaaea Throttle counting updates (#12223) 2022-04-05 09:55:01 +02:00
Paulus SchoutsenandGitHub 65c4d02452 Fix Safari dates (#12222) 2022-04-04 21:54:35 -07:00
Philip AllgaierandGitHub f78ce2c844 Sort "Switch as" domains and add separator (#12216) 2022-04-04 18:47:26 -05:00
Philip AllgaierandGitHub 4d1ab83b30 Hide "Show as" separator if there is nothing above/below it (#12219) 2022-04-04 18:44:21 -05:00
Zack BarettandGitHub fb4b40b828 Fix Entity Settings missing (#12221) 2022-04-04 22:49:11 +00:00
Philip AllgaierandGitHub db0c4ef941 Fix "Show as" in entity registry (#12215) 2022-04-04 14:16:03 -05:00
Philip AllgaierandGitHub c5b60b826b Enable <ha-form> overflow overriding via part (#12204) 2022-04-04 08:41:12 -05:00
Philip AllgaierandGitHub 718f0330a7 Fix button card behavior to toggle scenes (#12203) 2022-04-04 08:40:10 -05:00
Philip AllgaierandGitHub 89e31486c5 Ensure history entity picker wraps to next line on mobile (#12201) 2022-04-04 08:39:45 -05:00
Philip AllgaierandGitHub 717eec1860 Allow "none" again as secondary entity information (#12199) 2022-04-04 08:39:28 -05:00
Philip AllgaierandGitHub b6e51352e3 Fan more-info: Add margin to sections (#12202) 2022-04-04 08:38:53 -05:00
Joakim SørensenandGitHub 2ade728bc3 Make the progress bar not jump the dialog (#12212) 2022-04-04 08:20:37 +02:00
Joakim SørensenandGitHub 62f227da83 Use installed_version for update entities (#12194) 2022-04-01 19:28:39 +02:00
284 changed files with 9893 additions and 3738 deletions
+2 -2
View File
@@ -1,4 +1,4 @@
name: Report a bug with the UI, Frontend or Lovelace
name: Report a bug with the UI / Dashboards
description: Report an issue related to the Home Assistant frontend.
labels: bug
body:
@@ -9,7 +9,7 @@ body:
If you have a feature or enhancement request for the frontend, please [start an discussion][fr] instead of creating an issue.
**Please not not report issues for custom Lovelace cards.**
**Please not not report issues for custom cards.**
[fr]: https://github.com/home-assistant/frontend/discussions
[releases]: https://github.com/home-assistant/home-assistant/releases
+4 -4
View File
@@ -1,17 +1,17 @@
blank_issues_enabled: false
contact_links:
- name: Request a feature for the UI, Frontend or Lovelace
- name: Request a feature for the UI / Dashboards
url: https://github.com/home-assistant/frontend/discussions/category_choices
about: Request an new feature for the Home Assistant frontend.
- name: Report a bug that is NOT related to the UI, Frontend or Lovelace
- name: Report a bug that is NOT related to the UI / Dashboards
url: https://github.com/home-assistant/core/issues
about: This is the issue tracker for our frontend. Please report other issues with the backend repository.
about: This is the issue tracker for our frontend. Please report other issues in the backend ("core") repository.
- name: Report incorrect or missing information on our website
url: https://github.com/home-assistant/home-assistant.io/issues
about: Our documentation has its own issue tracker. Please report issues with the website there.
- name: I have a question or need support
url: https://www.home-assistant.io/help
about: We use GitHub for tracking bugs, check our website for resources on getting help.
about: We use GitHub for tracking bugs. Check our website for resources on getting help.
- name: I'm unsure where to go
url: https://www.home-assistant.io/join-chat
about: If you are unsure where to go, then joining our chat is recommended; Just ask!
+4 -2
View File
@@ -3,10 +3,10 @@ const webpack = require("webpack");
const path = require("path");
const TerserPlugin = require("terser-webpack-plugin");
const { WebpackManifestPlugin } = require("webpack-manifest-plugin");
const paths = require("./paths.js");
const bundle = require("./bundle.js");
const log = require("fancy-log");
const WebpackBar = require("webpackbar");
const paths = require("./paths.js");
const bundle = require("./bundle.js");
class LogStartCompilePlugin {
ignoredFirst = false;
@@ -138,6 +138,8 @@ const createWebpackConfig = ({
"lit/directives/cache$": "lit/directives/cache.js",
"lit/directives/repeat$": "lit/directives/repeat.js",
"lit/polyfill-support$": "lit/polyfill-support.js",
"@lit-labs/virtualizer/layouts/grid":
"@lit-labs/virtualizer/layouts/grid.js",
},
},
output: {
@@ -62,6 +62,45 @@ const ACTIONS = [
entity_id: "input_boolean.toggle_4",
},
},
{
parallel: [
{ scene: "scene.kitchen_morning" },
{
service: "media_player.play_media",
target: { entity_id: "media_player.living_room" },
data: { media_content_id: "", media_content_type: "" },
metadata: { title: "Happy Song" },
},
],
},
{
stop: "No one is home!",
},
{ repeat: { count: 3, sequence: [{ delay: "00:00:01" }] } },
{
repeat: {
for_each: ["bread", "butter", "cheese"],
sequence: [{ delay: "00:00:01" }],
},
},
{
if: [{ condition: "state" }],
then: [{ delay: "00:00:01" }],
else: [{ delay: "00:00:05" }],
},
{
choose: [
{
conditions: [{ condition: "state" }],
sequence: [{ delay: "00:00:01" }],
},
{
conditions: [{ condition: "sun" }],
sequence: [{ delay: "00:00:05" }],
},
],
default: [{ delay: "00:00:03" }],
},
];
@customElement("demo-automation-describe-action")
@@ -20,6 +20,10 @@ import { HaWaitForTriggerAction } from "../../../../src/panels/config/automation
import { HaWaitAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-wait_template";
import { Action } from "../../../../src/data/script";
import { HaConditionAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-condition";
import { HaParallelAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-parallel";
import { HaIfAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-if";
import { HaStopAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-stop";
import { HaPlayMediaAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-play_media";
const SCHEMAS: { name: string; actions: Action[] }[] = [
{ name: "Event", actions: [HaEventAction.defaultConfig] },
@@ -28,11 +32,15 @@ const SCHEMAS: { name: string; actions: Action[] }[] = [
{ name: "Condition", actions: [HaConditionAction.defaultConfig] },
{ name: "Delay", actions: [HaDelayAction.defaultConfig] },
{ name: "Scene", actions: [HaSceneAction.defaultConfig] },
{ name: "Play media", actions: [HaPlayMediaAction.defaultConfig] },
{ name: "Wait", actions: [HaWaitAction.defaultConfig] },
{ name: "WaitForTrigger", actions: [HaWaitForTriggerAction.defaultConfig] },
{ name: "Repeat", actions: [HaRepeatAction.defaultConfig] },
{ name: "If-Then", actions: [HaIfAction.defaultConfig] },
{ name: "Choose", actions: [HaChooseAction.defaultConfig] },
{ name: "Variables", actions: [{ variables: { hello: "1" } }] },
{ name: "Parallel", actions: [HaParallelAction.defaultConfig] },
{ name: "Stop", actions: [HaStopAction.defaultConfig] },
];
@customElement("demo-automation-editor-action")
@@ -86,6 +94,6 @@ class DemoHaAutomationEditorAction extends LitElement {
declare global {
interface HTMLElementTagNameMap {
"demo-ha-automation-editor-action": DemoHaAutomationEditorAction;
"demo-automation-editor-action": DemoHaAutomationEditorAction;
}
}
@@ -8,7 +8,7 @@ import { mockEntityRegistry } from "../../../../demo/src/stubs/entity_registry";
import { mockDeviceRegistry } from "../../../../demo/src/stubs/device_registry";
import { mockAreaRegistry } from "../../../../demo/src/stubs/area_registry";
import { mockHassioSupervisor } from "../../../../demo/src/stubs/hassio_supervisor";
import type { Condition } from "../../../../src/data/automation";
import type { ConditionWithShorthand } from "../../../../src/data/automation";
import "../../../../src/panels/config/automation/condition/ha-automation-condition";
import { HaDeviceCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-device";
import { HaLogicalCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-logical";
@@ -20,7 +20,7 @@ import { HaTimeCondition } from "../../../../src/panels/config/automation/condit
import { HaTriggerCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-trigger";
import { HaZoneCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-zone";
const SCHEMAS: { name: string; conditions: Condition[] }[] = [
const SCHEMAS: { name: string; conditions: ConditionWithShorthand[] }[] = [
{
name: "State",
conditions: [{ condition: "state", ...HaStateCondition.defaultConfig }],
@@ -69,6 +69,14 @@ const SCHEMAS: { name: string; conditions: Condition[] }[] = [
name: "Trigger",
conditions: [{ condition: "trigger", ...HaTriggerCondition.defaultConfig }],
},
{
name: "Shorthand",
conditions: [
{ and: HaLogicalCondition.defaultConfig.conditions },
{ or: HaLogicalCondition.defaultConfig.conditions },
{ not: HaLogicalCondition.defaultConfig.conditions },
],
},
];
@customElement("demo-automation-editor-condition")
+13 -7
View File
@@ -159,13 +159,19 @@ export class DemoHaAlert extends LitElement {
firstUpdated(changedProps) {
super.firstUpdated(changedProps);
applyThemesOnElement(this.shadowRoot!.querySelector(".dark"), {
default_theme: "default",
default_dark_theme: "default",
themes: {},
darkMode: true,
theme: "default",
});
applyThemesOnElement(
this.shadowRoot!.querySelector(".dark"),
{
default_theme: "default",
default_dark_theme: "default",
themes: {},
darkMode: true,
theme: "default",
},
undefined,
undefined,
true
);
}
static get styles() {
+13 -1
View File
@@ -170,6 +170,7 @@ const SCHEMAS: {
select: { options: ["Option 1", "Option 2"], mode: "list" },
},
},
template: { name: "Template", selector: { template: {} } },
select: {
name: "Select",
selector: {
@@ -261,6 +262,8 @@ class DemoHaSelector extends LitElement implements ProvideHassElement {
@state() private _required = false;
@state() private _helper = false;
@state() private _label = true;
private data = SCHEMAS.map(() => ({}));
@@ -418,6 +421,13 @@ class DemoHaSelector extends LitElement implements ProvideHassElement {
@change=${this._handleOptionChange}
></ha-switch>
</ha-formfield>
<ha-formfield label="Helper text">
<ha-switch
.name=${"helper"}
.checked=${this._helper}
@change=${this._handleOptionChange}
></ha-switch>
</ha-formfield>
</div>
${SCHEMAS.map((info, idx) => {
const data = this.data[idx];
@@ -446,6 +456,7 @@ class DemoHaSelector extends LitElement implements ProvideHassElement {
.disabled=${this._disabled}
.required=${this._required}
@value-changed=${valueChanged}
.helper=${this._helper ? "Helper text" : undefined}
></ha-selector>
</ha-settings-row>
`
@@ -466,7 +477,8 @@ class DemoHaSelector extends LitElement implements ProvideHassElement {
width: 60;
}
.options {
padding: 16px 48px;
max-width: 800px;
margin: 16px auto;
}
.options ha-formfield {
margin-right: 16px;
@@ -0,0 +1,3 @@
---
title: Tips
---
+73
View File
@@ -0,0 +1,73 @@
import { html, css, LitElement, TemplateResult } from "lit";
import { customElement } from "lit/decorators";
import "../../../../src/components/ha-tip";
import "../../../../src/components/ha-card";
import { applyThemesOnElement } from "../../../../src/common/dom/apply_themes_on_element";
const tips: (string | TemplateResult)[] = [
"Test tip",
"Bigger test tip, with some random text just to fill up as much space as possible without it looking like I'm really trying to to that",
html`<i>Tip</i> <b>with</b> <sub>HTML</sub>`,
];
@customElement("demo-components-ha-tip")
export class DemoHaTip extends LitElement {
protected render(): TemplateResult {
return html` ${["light", "dark"].map(
(mode) => html`
<div class=${mode}>
<ha-card header="ha-tip ${mode} demo">
<div class="card-content">
${tips.map((tip) => html`<ha-tip>${tip}</ha-tip>`)}
</div>
</ha-card>
</div>
`
)}`;
}
firstUpdated(changedProps) {
super.firstUpdated(changedProps);
applyThemesOnElement(
this.shadowRoot!.querySelector(".dark"),
{
default_theme: "default",
default_dark_theme: "default",
themes: {},
darkMode: true,
theme: "default",
},
undefined,
undefined,
true
);
}
static get styles() {
return css`
:host {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.dark,
.light {
display: block;
background-color: var(--primary-background-color);
padding: 0 50px;
}
ha-tip {
margin-bottom: 14px;
}
ha-card {
margin: 24px auto;
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"demo-components-ha-tip": DemoHaTip;
}
}
+10 -4
View File
@@ -18,7 +18,7 @@ import { LONG_TEXT } from "../../data/text";
const base_attributes = {
title: "Awesome",
current_version: "1.2.2",
installed_version: "1.2.2",
latest_version: "1.2.3",
release_url: "https://home-assistant.io",
supported_features: UPDATE_SUPPORT_INSTALL,
@@ -50,7 +50,7 @@ const ENTITIES = [
}),
getEntity("update", "update5", "off", {
...base_attributes,
current_version: "1.2.3",
installed_version: "1.2.3",
friendly_name: "No update",
}),
getEntity("update", "update6", "off", {
@@ -102,8 +102,8 @@ const ENTITIES = [
}),
getEntity("update", "update14", "off", {
...base_attributes,
current_version: null,
friendly_name: "Update without current_version",
installed_version: null,
friendly_name: "Update without installed_version",
}),
getEntity("update", "update15", "off", {
...base_attributes,
@@ -133,6 +133,12 @@ const ENTITIES = [
friendly_name: "Update with auto update",
auto_update: true,
}),
getEntity("update", "update20", "on", {
...base_attributes,
in_progress: true,
title: undefined,
friendly_name: "Installing without title",
}),
];
@customElement("demo-more-info-update")
@@ -68,6 +68,7 @@ class HassioAddonRepositoryEl extends LitElement {
${addons.map(
(addon) => html`
<ha-card
outlined
.addon=${addon}
class=${addon.available ? "" : "not_available"}
@click=${this._addonTapped}
@@ -50,6 +50,7 @@ class HassioAddonAudio extends LitElement {
protected render(): TemplateResult {
return html`
<ha-card
outlined
.header=${this.supervisor.localize("addon.configuration.audio.header")}
>
<div class="card-content">
@@ -39,7 +39,14 @@ import type { HomeAssistant } from "../../../../src/types";
import { suggestAddonRestart } from "../../dialogs/suggestAddonRestart";
import { hassioStyle } from "../../resources/hassio-style";
const SUPPORTED_UI_TYPES = ["string", "select", "boolean", "integer", "float"];
const SUPPORTED_UI_TYPES = [
"string",
"select",
"boolean",
"integer",
"float",
"schema",
];
const ADDON_YAML_SCHEMA = DEFAULT_SCHEMA.extend([
new Type("!secret", {
@@ -48,6 +55,8 @@ const ADDON_YAML_SCHEMA = DEFAULT_SCHEMA.extend([
}),
]);
const MASKED_FIELDS = ["password", "secret", "token"];
@customElement("hassio-addon-config")
class HassioAddonConfig extends LitElement {
@property({ attribute: false }) public addon!: HassioAddonDetails;
@@ -75,19 +84,66 @@ class HassioAddonConfig extends LitElement {
public computeLabel = (entry: HaFormSchema): string =>
this.addon.translations[this.hass.language]?.configuration?.[entry.name]
?.name ||
this.addon.translations.en?.configuration?.[entry.name].name ||
this.addon.translations.en?.configuration?.[entry.name]?.name ||
entry.name;
private _schema = memoizeOne((schema: HaFormSchema[]): HaFormSchema[] =>
// @ts-expect-error supervisor does not implement [string, string] for select.options[]
schema.map((entry) =>
entry.type === "select"
? {
...entry,
options: entry.options.map((option) => [option, option]),
}
: entry
)
public computeHelper = (entry: HaFormSchema): string =>
this.addon.translations[this.hass.language]?.configuration?.[entry.name]
?.description ||
this.addon.translations.en?.configuration?.[entry.name]?.description ||
"";
private _convertSchema = memoizeOne(
// Convert supervisor schema to selectors
(schema: Record<string, any>): HaFormSchema[] =>
schema.map((entry) =>
entry.type === "select"
? {
name: entry.name,
required: entry.required,
selector: { select: { options: entry.options } },
}
: entry.type === "string"
? entry.multiple
? {
name: entry.name,
required: entry.required,
selector: {
select: { options: [], multiple: true, custom_value: true },
},
}
: {
name: entry.name,
required: entry.required,
selector: {
text: {
type:
entry.format || MASKED_FIELDS.includes(entry.name)
? "password"
: "text",
},
},
}
: entry.type === "boolean"
? {
name: entry.name,
required: entry.required,
selector: { boolean: {} },
}
: entry.type === "schema"
? {
name: entry.name,
required: entry.required,
selector: { object: {} },
}
: entry.type === "float" || entry.type === "integer"
? {
name: entry.name,
required: entry.required,
selector: { number: { mode: "box" } },
}
: entry
)
);
private _filteredShchema = memoizeOne(
@@ -106,7 +162,7 @@ class HassioAddonConfig extends LitElement {
);
return html`
<h1>${this.addon.name}</h1>
<ha-card>
<ha-card outlined>
<div class="header">
<h2>
${this.supervisor.localize("addon.configuration.options.header")}
@@ -140,7 +196,8 @@ class HassioAddonConfig extends LitElement {
.data=${this._options!}
@value-changed=${this._configChanged}
.computeLabel=${this.computeLabel}
.schema=${this._schema(
.computeHelper=${this.computeHelper}
.schema=${this._convertSchema(
this._showOptional
? this.addon.schema!
: this._filteredShchema(
@@ -197,8 +254,9 @@ class HassioAddonConfig extends LitElement {
protected firstUpdated(changedProps) {
super.firstUpdated(changedProps);
this._canShowSchema = !this.addon.schema!.find(
// @ts-ignore
(entry) => !SUPPORTED_UI_TYPES.includes(entry.type) || entry.multiple
(entry) =>
// @ts-ignore
!SUPPORTED_UI_TYPES.includes(entry.type)
);
this._yamlMode = !this._canShowSchema;
}
@@ -1,4 +1,3 @@
import { PaperInputElement } from "@polymer/paper-input/paper-input";
import {
css,
CSSResultGroup,
@@ -8,10 +7,13 @@ import {
TemplateResult,
} from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../../../src/common/dom/fire_event";
import "../../../../src/components/buttons/ha-progress-button";
import "../../../../src/components/ha-alert";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-form/ha-form";
import type { HaFormSchema } from "../../../../src/components/ha-form/types";
import {
HassioAddonDetails,
HassioAddonSetOptionParams,
@@ -24,16 +26,6 @@ import { HomeAssistant } from "../../../../src/types";
import { suggestAddonRestart } from "../../dialogs/suggestAddonRestart";
import { hassioStyle } from "../../resources/hassio-style";
interface NetworkItem {
description: string;
container: string;
host: number | null;
}
interface NetworkItemInput extends PaperInputElement {
container: string;
}
@customElement("hassio-addon-network")
class HassioAddonNetwork extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -42,9 +34,13 @@ class HassioAddonNetwork extends LitElement {
@property({ attribute: false }) public addon!: HassioAddonDetails;
@state() private _showOptional = false;
@state() private _configHasChanged = false;
@state() private _error?: string;
@state() private _config?: NetworkItem[];
@state() private _config?: Record<string, any>;
public connectedCallback(): void {
super.connectedCallback();
@@ -56,59 +52,61 @@ class HassioAddonNetwork extends LitElement {
return html``;
}
const hasHiddenOptions = Object.keys(this._config).find(
(entry) => this._config![entry] === null
);
return html`
<ha-card
outlined
.header=${this.supervisor.localize(
"addon.configuration.network.header"
)}
>
<div class="card-content">
<p>
${this.supervisor.localize(
"addon.configuration.network.introduction"
)}
</p>
${this._error
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
: ""}
<table>
<tbody>
<tr>
<th>
${this.supervisor.localize(
"addon.configuration.network.container"
)}
</th>
<th>
${this.supervisor.localize(
"addon.configuration.network.host"
)}
</th>
<th>${this.supervisor.localize("common.description")}</th>
</tr>
${this._config!.map(
(item) => html`
<tr>
<td>${item.container}</td>
<td>
<paper-input
@value-changed=${this._configChanged}
placeholder=${this.supervisor.localize(
"addon.configuration.network.disabled"
)}
.value=${item.host ? String(item.host) : ""}
.container=${item.container}
no-label-float
></paper-input>
</td>
<td>${this._computeDescription(item)}</td>
</tr>
`
)}
</tbody>
</table>
<ha-form
.data=${this._config}
@value-changed=${this._configChanged}
.computeLabel=${this._computeLabel}
.computeHelper=${this._computeHelper}
.schema=${this._createSchema(
this._config,
this._showOptional,
this.hass.userData?.showAdvanced || false
)}
></ha-form>
</div>
${hasHiddenOptions
? html`<ha-formfield
class="show-optional"
.label=${this.supervisor.localize(
"addon.configuration.network.show_disabled"
)}
>
<ha-switch
@change=${this._toggleOptional}
.checked=${this._showOptional}
>
</ha-switch>
</ha-formfield>`
: ""}
<div class="card-actions">
<ha-progress-button class="warning" @click=${this._resetTapped}>
${this.supervisor.localize("common.reset_defaults")}
</ha-progress-button>
<ha-progress-button @click=${this._saveTapped}>
<ha-progress-button
@click=${this._saveTapped}
.disabled=${!this._configHasChanged}
>
${this.supervisor.localize("common.save")}
</ha-progress-button>
</div>
@@ -123,50 +121,60 @@ class HassioAddonNetwork extends LitElement {
}
}
private _computeDescription = (item: NetworkItem): string =>
this.addon.translations[this.hass.language]?.network?.[item.container]
?.description ||
this.addon.translations.en?.network?.[item.container]?.description ||
item.description;
private _createSchema = memoizeOne(
(
config: Record<string, number>,
showOptional: boolean,
advanced: boolean
): HaFormSchema[] =>
(showOptional
? Object.keys(config)
: Object.keys(config).filter((entry) => config[entry] !== null)
).map((entry) => ({
name: entry,
selector: {
number: {
mode: "box",
min: 0,
max: 65535,
unit_of_measurement: advanced ? entry : undefined,
},
},
}))
);
private _computeLabel = (_: HaFormSchema): string => "";
private _computeHelper = (item: HaFormSchema): string =>
this.addon.translations[this.hass.language]?.network?.[item.name] ||
this.addon.translations.en?.network?.[item.name] ||
this.addon.network_description?.[item.name] ||
item.name;
private _setNetworkConfig(): void {
const network = this.addon.network || {};
const description = this.addon.network_description || {};
const items: NetworkItem[] = Object.keys(network).map((key) => ({
container: key,
host: network[key],
description: description[key],
}));
this._config = items.sort((a, b) => (a.container > b.container ? 1 : -1));
this._config = this.addon.network || {};
}
private async _configChanged(ev: Event): Promise<void> {
const target = ev.target as NetworkItemInput;
this._config!.forEach((item) => {
if (
item.container === target.container &&
item.host !== parseInt(String(target.value), 10)
) {
item.host = target.value ? parseInt(String(target.value), 10) : null;
}
});
private async _configChanged(ev: CustomEvent): Promise<void> {
this._configHasChanged = true;
this._config! = ev.detail.value;
}
private async _resetTapped(ev: CustomEvent): Promise<void> {
const button = ev.currentTarget as any;
button.progress = true;
const data: HassioAddonSetOptionParams = {
network: null,
};
try {
await setHassioAddonOption(this.hass, this.addon.slug, data);
this._configHasChanged = false;
const eventdata = {
success: true,
response: undefined,
path: "option",
};
button.actionSuccess();
fireEvent(this, "hass-api-called", eventdata);
if (this.addon?.state === "started") {
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
@@ -177,19 +185,21 @@ class HassioAddonNetwork extends LitElement {
"error",
extractApiErrorMessage(err)
);
button.actionError();
}
}
button.progress = false;
private _toggleOptional() {
this._showOptional = !this._showOptional;
}
private async _saveTapped(ev: CustomEvent): Promise<void> {
const button = ev.currentTarget as any;
button.progress = true;
this._error = undefined;
const networkconfiguration = {};
this._config!.forEach((item) => {
networkconfiguration[item.container] = parseInt(String(item.host), 10);
Object.entries(this._config!).forEach(([key, value]) => {
networkconfiguration[key] = value ?? null;
});
const data: HassioAddonSetOptionParams = {
@@ -198,11 +208,13 @@ class HassioAddonNetwork extends LitElement {
try {
await setHassioAddonOption(this.hass, this.addon.slug, data);
this._configHasChanged = false;
const eventdata = {
success: true,
response: undefined,
path: "option",
};
button.actionSuccess();
fireEvent(this, "hass-api-called", eventdata);
if (this.addon?.state === "started") {
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
@@ -213,8 +225,8 @@ class HassioAddonNetwork extends LitElement {
"error",
extractApiErrorMessage(err)
);
button.actionError();
}
button.progress = false;
}
static get styles(): CSSResultGroup {
@@ -232,6 +244,9 @@ class HassioAddonNetwork extends LitElement {
display: flex;
justify-content: space-between;
}
.show-optional {
padding: 16px;
}
`,
];
}
@@ -38,7 +38,7 @@ class HassioAddonDocumentationDashboard extends LitElement {
}
return html`
<div class="content">
<ha-card>
<ha-card outlined>
${this._error
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
: ""}
@@ -17,7 +17,9 @@ import {
HassioAddonDetails,
} from "../../../src/data/hassio/addon";
import { extractApiErrorMessage } from "../../../src/data/hassio/common";
import { setSupervisorOption } from "../../../src/data/hassio/supervisor";
import { Supervisor } from "../../../src/data/supervisor/supervisor";
import { showConfirmationDialog } from "../../../src/dialogs/generic/show-dialog-box";
import "../../../src/layouts/hass-error-screen";
import "../../../src/layouts/hass-loading-screen";
import "../../../src/layouts/hass-tabs-subpage";
@@ -166,6 +168,42 @@ class HassioAddonDashboard extends LitElement {
protected async firstUpdated(): Promise<void> {
if (this.route.path === "") {
const requestedAddon = extractSearchParam("addon");
const requestedAddonRepository = extractSearchParam("repository_url");
if (
requestedAddonRepository &&
!this.supervisor.supervisor.addons_repositories.find(
(repo) => repo === requestedAddonRepository
)
) {
if (
!(await showConfirmationDialog(this, {
title: this.supervisor.localize("my.add_addon_repository_title"),
text: this.supervisor.localize(
"my.add_addon_repository_description",
{ addon: requestedAddon, repository: requestedAddonRepository }
),
confirmText: this.supervisor.localize("common.add"),
dismissText: this.supervisor.localize("common.cancel"),
}))
) {
this._error = this.supervisor.localize(
"my.error_repository_not_found"
);
return;
}
try {
await setSupervisorOption(this.hass, {
addons_repositories: [
...this.supervisor.supervisor.addons_repositories,
requestedAddonRepository,
],
});
} catch (err: any) {
this._error = extractApiErrorMessage(err);
}
}
if (requestedAddon) {
const addonsInfo = await fetchHassioAddonsInfo(this.hass);
const validAddon = addonsInfo.addons.some(
@@ -166,7 +166,7 @@ class HassioAddonInfo extends LitElement {
`
: ""}
<ha-card>
<ha-card outlined>
<div class="card-content">
<div class="addon-header">
${!this.narrow ? this.addon.name : ""}
@@ -649,7 +649,7 @@ class HassioAddonInfo extends LitElement {
${this.addon.long_description
? html`
<ha-card>
<ha-card outlined>
<div class="card-content">
<ha-markdown
.content=${this.addon.long_description}
@@ -2,6 +2,7 @@ import "@material/mwc-button";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../../src/components/ha-alert";
import "../../../../src/components/ha-ansi-to-html";
import "../../../../src/components/ha-card";
import {
fetchHassioAddonLogs,
@@ -11,7 +12,6 @@ import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
import { Supervisor } from "../../../../src/data/supervisor/supervisor";
import { haStyle } from "../../../../src/resources/styles";
import { HomeAssistant } from "../../../../src/types";
import "../../components/hassio-ansi-to-html";
import { hassioStyle } from "../../resources/hassio-style";
@customElement("hassio-addon-logs")
@@ -34,15 +34,15 @@ class HassioAddonLogs extends LitElement {
protected render(): TemplateResult {
return html`
<h1>${this.addon.name}</h1>
<ha-card>
<ha-card outlined>
${this._error
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
: ""}
<div class="card-content">
${this._content
? html`<hassio-ansi-to-html
? html`<ha-ansi-to-html
.content=${this._content}
></hassio-ansi-to-html>`
></ha-ansi-to-html>`
: ""}
</div>
<div class="card-actions">
+13 -3
View File
@@ -1,7 +1,7 @@
import "@material/mwc-button";
import { ActionDetail } from "@material/mwc-list";
import "@material/mwc-list/mwc-list-item";
import { mdiDelete, mdiDotsVertical, mdiPlus } from "@mdi/js";
import { mdiBackupRestore, mdiDelete, mdiDotsVertical, mdiPlus } from "@mdi/js";
import {
css,
CSSResultGroup,
@@ -166,7 +166,15 @@ export class HassioBackups extends LitElement {
}
return html`
<hass-tabs-subpage-data-table
.tabs=${supervisorTabs(this.hass)}
.tabs=${atLeastVersion(this.hass.config.version, 2022, 5)
? [
{
translationKey: "panel.backups",
path: `/hassio/backups`,
iconPath: mdiBackupRestore,
},
]
: supervisorTabs(this.hass)}
.hass=${this.hass}
.localizeFunc=${this.supervisor.localize}
.searchLabel=${this.supervisor.localize("search")}
@@ -182,7 +190,9 @@ export class HassioBackups extends LitElement {
selectable
hasFab
.mainPage=${!atLeastVersion(this.hass.config.version, 2021, 12)}
back-path="/config"
back-path=${atLeastVersion(this.hass.config.version, 2022, 5)
? "/config/system"
: "/config"}
supervisor
>
<ha-button-menu
@@ -180,7 +180,7 @@ export class SupervisorBackupContent extends LitElement {
>
<ha-checkbox
.checked=${this.homeAssistant}
@click=${this.toggleHomeAssistant}
@change=${this.toggleHomeAssistant}
>
</ha-checkbox>
</ha-formfield>
+6 -2
View File
@@ -26,7 +26,7 @@ class HassioAddons extends LitElement {
<div class="card-group">
${!this.supervisor.supervisor.addons?.length
? html`
<ha-card>
<ha-card outlined>
<div class="card-content">
<button class="link" @click=${this._openStore}>
${this.supervisor.localize("dashboard.no_addons")}
@@ -38,7 +38,11 @@ class HassioAddons extends LitElement {
.sort((a, b) => caseInsensitiveStringCompare(a.name, b.name))
.map(
(addon) => html`
<ha-card .addon=${addon} @click=${this._addonTapped}>
<ha-card
outlined
.addon=${addon}
@click=${this._addonTapped}
>
<div class="card-content">
<hassio-card-content
.hass=${this.hass}
+32
View File
@@ -10,6 +10,7 @@ import { HomeAssistant, Route } from "../../../src/types";
import { supervisorTabs } from "../hassio-tabs";
import "./hassio-addons";
import "./hassio-update";
import "../../../src/layouts/hass-subpage";
@customElement("hassio-dashboard")
class HassioDashboard extends LitElement {
@@ -22,6 +23,31 @@ class HassioDashboard extends LitElement {
@property({ attribute: false }) public route!: Route;
protected render(): TemplateResult {
if (atLeastVersion(this.hass.config.version, 2022, 5)) {
return html`<hass-subpage
.hass=${this.hass}
.narrow=${this.narrow}
.route=${this.route}
.header=${this.supervisor.localize("panel.addons")}
>
<hassio-addons
.hass=${this.hass}
.supervisor=${this.supervisor}
></hassio-addons>
<a href="/hassio/store">
<ha-fab
.label=${this.supervisor.localize("panel.store")}
extended
class="non-tabs"
>
<ha-svg-icon
slot="icon"
.path=${mdiStorePlus}
></ha-svg-icon> </ha-fab
></a>
</hass-subpage>`;
}
return html`
<hass-tabs-subpage
.hass=${this.hass}
@@ -74,6 +100,12 @@ class HassioDashboard extends LitElement {
.content {
margin: 0 auto;
}
ha-fab.non-tabs {
position: fixed;
right: calc(16px + env(safe-area-inset-right));
bottom: calc(16px + env(safe-area-inset-bottom));
z-index: 1;
}
`,
];
}
+1 -1
View File
@@ -85,7 +85,7 @@ export class HassioUpdate extends LitElement {
return html``;
}
return html`
<ha-card>
<ha-card outlined>
<div class="card-content">
<div class="icon">
<ha-svg-icon .path=${mdiHomeAssistant}></ha-svg-icon>
+13 -1
View File
@@ -3,8 +3,8 @@ import { customElement, property } from "lit/decorators";
import { atLeastVersion } from "../../src/common/config/version";
import { applyThemesOnElement } from "../../src/common/dom/apply_themes_on_element";
import { fireEvent } from "../../src/common/dom/fire_event";
import { isNavigationClick } from "../../src/common/dom/is-navigation-click";
import { mainWindow } from "../../src/common/dom/get_main_window";
import { isNavigationClick } from "../../src/common/dom/is-navigation-click";
import { navigate } from "../../src/common/navigate";
import { HassioPanelInfo } from "../../src/data/hassio/supervisor";
import { Supervisor } from "../../src/data/supervisor/supervisor";
@@ -73,6 +73,18 @@ export class HassioMain extends SupervisorBaseElement {
});
});
// Forward keydown events to the main window for quickbar access
document.body.addEventListener("keydown", (ev: KeyboardEvent) => {
if (ev.altKey || ev.ctrlKey || ev.shiftKey || ev.metaKey) {
// Ignore if modifier keys are pressed
return;
}
// @ts-ignore
fireEvent(mainWindow, "hass-quick-bar-trigger", ev, {
bubbles: false,
});
});
makeDialogManager(this, this.shadowRoot!);
}
+12 -1
View File
@@ -15,7 +15,7 @@ import {
} from "../../src/panels/my/ha-panel-my";
import { HomeAssistant, Route } from "../../src/types";
const REDIRECTS: Redirects = {
export const REDIRECTS: Redirects = {
supervisor: {
redirect: "/hassio/dashboard",
},
@@ -42,6 +42,9 @@ const REDIRECTS: Redirects = {
params: {
addon: "string",
},
optional_params: {
repository_url: "url",
},
},
supervisor_ingress: {
redirect: "/hassio/ingress",
@@ -124,6 +127,14 @@ class HassioMyRedirect extends LitElement {
}
resultParams[key] = params[key];
});
Object.entries(redirect.optional_params || {}).forEach(([key, type]) => {
if (params[key]) {
if (!this._checkParamType(type, params[key])) {
throw Error();
}
resultParams[key] = params[key];
}
});
return `?${createSearchParam(resultParams)}`;
}
+24 -21
View File
@@ -8,24 +8,27 @@ import { atLeastVersion } from "../../src/common/config/version";
import type { PageNavigation } from "../../src/layouts/hass-tabs-subpage";
import { HomeAssistant } from "../../src/types";
export const supervisorTabs = (hass: HomeAssistant): PageNavigation[] => [
{
translationKey: atLeastVersion(hass.config.version, 2021, 12)
? "panel.addons"
: "panel.dashboard",
path: `/hassio/dashboard`,
iconPath: atLeastVersion(hass.config.version, 2021, 12)
? mdiPuzzle
: mdiViewDashboard,
},
{
translationKey: "panel.backups",
path: `/hassio/backups`,
iconPath: mdiBackupRestore,
},
{
translationKey: "panel.system",
path: `/hassio/system`,
iconPath: mdiCogs,
},
];
export const supervisorTabs = (hass: HomeAssistant): PageNavigation[] =>
atLeastVersion(hass.config.version, 2022, 5)
? []
: [
{
translationKey: atLeastVersion(hass.config.version, 2021, 12)
? "panel.addons"
: "panel.dashboard",
path: `/hassio/dashboard`,
iconPath: atLeastVersion(hass.config.version, 2021, 12)
? mdiPuzzle
: mdiViewDashboard,
},
{
translationKey: "panel.backups",
path: `/hassio/backups`,
iconPath: mdiBackupRestore,
},
{
translationKey: "panel.system",
path: `/hassio/system`,
iconPath: mdiCogs,
},
];
+1 -1
View File
@@ -48,7 +48,7 @@ class HassioCoreInfo extends LitElement {
];
return html`
<ha-card header="Core">
<ha-card header="Core" outlined>
<div class="card-content">
<div>
<ha-settings-row>
+1 -1
View File
@@ -66,7 +66,7 @@ class HassioHostInfo extends LitElement {
},
];
return html`
<ha-card header="Host">
<ha-card header="Host" outlined>
<div class="card-content">
<div>
${this.supervisor.host.features.includes("hostname")
+5 -6
View File
@@ -23,6 +23,10 @@ import {
showAlertDialog,
showConfirmationDialog,
} from "../../../src/dialogs/generic/show-dialog-box";
import {
UNHEALTHY_REASON_URL,
UNSUPPORTED_REASON_URL,
} from "../../../src/panels/config/system-health/ha-config-system-health";
import { haStyle } from "../../../src/resources/styles";
import { HomeAssistant } from "../../../src/types";
import { bytesToString } from "../../../src/util/bytes-to-string";
@@ -30,11 +34,6 @@ import { documentationUrl } from "../../../src/util/documentation-url";
import "../components/supervisor-metric";
import { hassioStyle } from "../resources/hassio-style";
const UNSUPPORTED_REASON_URL = {};
const UNHEALTHY_REASON_URL = {
privileged: "/more-info/unsupported/privileged",
};
@customElement("hassio-supervisor-info")
class HassioSupervisorInfo extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -58,7 +57,7 @@ class HassioSupervisorInfo extends LitElement {
},
];
return html`
<ha-card header="Supervisor">
<ha-card header="Supervisor" outlined>
<div class="card-content">
<div>
<ha-settings-row>
+4 -4
View File
@@ -1,3 +1,4 @@
import "../../../src/components/ha-ansi-to-html";
import "@material/mwc-button";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
@@ -11,7 +12,6 @@ import { Supervisor } from "../../../src/data/supervisor/supervisor";
import "../../../src/layouts/hass-loading-screen";
import { haStyle } from "../../../src/resources/styles";
import { HomeAssistant } from "../../../src/types";
import "../components/hassio-ansi-to-html";
import { hassioStyle } from "../resources/hassio-style";
interface LogProvider {
@@ -65,7 +65,7 @@ class HassioSupervisorLog extends LitElement {
protected render(): TemplateResult | void {
return html`
<ha-card>
<ha-card outlined>
${this._error
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
: ""}
@@ -89,8 +89,8 @@ class HassioSupervisorLog extends LitElement {
<div class="card-content" id="content">
${this._content
? html`<hassio-ansi-to-html .content=${this._content}>
</hassio-ansi-to-html>`
? html`<ha-ansi-to-html .content=${this._content}>
</ha-ansi-to-html>`
: html`<hass-loading-screen no-toolbar></hass-loading-screen>`}
</div>
<div class="card-actions">
@@ -128,6 +128,7 @@ class UpdateAvailableCard extends LitElement {
return html`
<ha-card
outlined
.header=${this.supervisor.localize("update_available.update_name", {
name: this._name,
})}
+1 -1
View File
@@ -108,7 +108,7 @@
"fuse.js": "^6.0.0",
"google-timezones-json": "^1.0.2",
"hls.js": "^1.1.5",
"home-assistant-js-websocket": "^7.0.1",
"home-assistant-js-websocket": "^7.0.3",
"idb-keyval": "^5.1.3",
"intl-messageformat": "^9.9.1",
"js-yaml": "^4.1.0",
+1 -1
View File
@@ -15,7 +15,7 @@ if [ -z $(which hass) ]; then
echo "Installing Home Asstant core from dev."
python3 -m pip install --upgrade \
colorlog \
git+git://github.com/home-assistant/home-assistant.git@dev
git+https://github.com/home-assistant/home-assistant.git@dev
fi
if [ ! -d "${WD}/config" ]; then
+1 -1
View File
@@ -1,6 +1,6 @@
[metadata]
name = home-assistant-frontend
version = 20220401.0
version = 20220504.0
author = The Home Assistant Authors
author_email = [email protected]
license = Apache-2.0
+16
View File
@@ -0,0 +1,16 @@
import secondsToDuration from "./seconds_to_duration";
const DAY_IN_SECONDS = 86400;
const HOUR_IN_SECONDS = 3600;
const MINUTE_IN_SECONDS = 60;
export const UNIT_TO_SECOND_CONVERT = {
s: 1,
min: MINUTE_IN_SECONDS,
h: HOUR_IN_SECONDS,
d: DAY_IN_SECONDS,
};
export const formatDuration = (duration: string, units: string): string =>
secondsToDuration(parseFloat(duration) * UNIT_TO_SECOND_CONVERT[units]) ||
"0";
+1 -1
View File
@@ -12,7 +12,7 @@ export const isNavigationClick = (e: MouseEvent) => {
const anchor = e
.composedPath()
.filter((n) => (n as HTMLElement).tagName === "A")[0] as
.find((n) => (n as HTMLElement).tagName === "A") as
| HTMLAnchorElement
| undefined;
if (
+7 -2
View File
@@ -29,8 +29,11 @@ import {
mdiPowerPlug,
mdiPowerPlugOff,
mdiRadioboxBlank,
mdiSmoke,
mdiSnowflake,
mdiSmokeDetector,
mdiSmokeDetectorAlert,
mdiSmokeDetectorVariant,
mdiSmokeDetectorVariantAlert,
mdiSquare,
mdiSquareOutline,
mdiStop,
@@ -52,6 +55,8 @@ export const binarySensorIcon = (state?: string, stateObj?: HassEntity) => {
return is_off ? mdiBattery : mdiBatteryOutline;
case "battery_charging":
return is_off ? mdiBattery : mdiBatteryCharging;
case "carbon_monoxide":
return is_off ? mdiSmokeDetector : mdiSmokeDetectorAlert;
case "cold":
return is_off ? mdiThermometer : mdiSnowflake;
case "connectivity":
@@ -68,7 +73,7 @@ export const binarySensorIcon = (state?: string, stateObj?: HassEntity) => {
case "tamper":
return is_off ? mdiCheckCircle : mdiAlertCircle;
case "smoke":
return is_off ? mdiCheckCircle : mdiSmoke;
return is_off ? mdiSmokeDetectorVariant : mdiSmokeDetectorVariantAlert;
case "heat":
return is_off ? mdiThermometer : mdiFire;
case "light":
@@ -13,6 +13,7 @@ import { formatNumber, isNumericState } from "../number/format_number";
import { LocalizeFunc } from "../translations/localize";
import { computeStateDomain } from "./compute_state_domain";
import { supportsFeature } from "./supports-feature";
import { formatDuration, UNIT_TO_SECOND_CONVERT } from "../datetime/duration";
export const computeStateDisplay = (
localize: LocalizeFunc,
@@ -28,11 +29,27 @@ export const computeStateDisplay = (
// Entities with a `unit_of_measurement` or `state_class` are numeric values and should use `formatNumber`
if (isNumericState(stateObj)) {
// state is duration
if (
stateObj.attributes.device_class === "duration" &&
stateObj.attributes.unit_of_measurement &&
UNIT_TO_SECOND_CONVERT[stateObj.attributes.unit_of_measurement]
) {
try {
return formatDuration(
compareState,
stateObj.attributes.unit_of_measurement
);
} catch (_err) {
// fallback to default
}
}
if (stateObj.attributes.device_class === "monetary") {
try {
return formatNumber(compareState, locale, {
style: "currency",
currency: stateObj.attributes.unit_of_measurement,
minimumFractionDigits: 2,
});
} catch (_err) {
// fallback to default
+10 -9
View File
@@ -8,26 +8,25 @@ import {
mdiCalendar,
mdiCast,
mdiCastConnected,
mdiCheckCircleOutline,
mdiClock,
mdiCloseCircleOutline,
mdiGestureTapButton,
mdiLanConnect,
mdiLanDisconnect,
mdiLightSwitch,
mdiLock,
mdiLockAlert,
mdiLockClock,
mdiLockOpen,
mdiPackage,
mdiPackageDown,
mdiPackageUp,
mdiPowerPlug,
mdiPowerPlugOff,
mdiRestart,
mdiToggleSwitch,
mdiToggleSwitchOff,
mdiCheckCircleOutline,
mdiCloseCircleOutline,
mdiToggleSwitchVariant,
mdiToggleSwitchVariantOff,
mdiWeatherNight,
mdiPackage,
mdiPackageDown,
} from "@mdi/js";
import { HassEntity } from "home-assistant-js-websocket";
import { updateIsInstalling, UpdateEntity } from "../../data/update";
@@ -109,9 +108,11 @@ export const domainIcon = (
case "outlet":
return compareState === "on" ? mdiPowerPlug : mdiPowerPlugOff;
case "switch":
return compareState === "on" ? mdiToggleSwitch : mdiToggleSwitchOff;
return compareState === "on"
? mdiToggleSwitchVariant
: mdiToggleSwitchVariantOff;
default:
return mdiLightSwitch;
return mdiToggleSwitchVariant;
}
case "sensor": {
+1 -1
View File
@@ -1,4 +1,4 @@
export const promiseTimeout = (ms: number, promise: Promise<any>) => {
export const promiseTimeout = (ms: number, promise: Promise<any> | any) => {
const timeout = new Promise((_resolve, reject) => {
setTimeout(() => {
reject(`Timed out in ${ms} ms.`);
+18
View File
@@ -0,0 +1,18 @@
import { HomeAssistant } from "../../types";
export const subscribePollingCollection = (
hass: HomeAssistant,
updateData: (hass: HomeAssistant) => void,
interval: number
) => {
let timeout;
const fetchData = async () => {
try {
await updateData(hass);
} finally {
timeout = setTimeout(() => fetchData(), interval);
}
};
fetchData();
return () => clearTimeout(timeout);
};
+2 -2
View File
@@ -347,8 +347,8 @@ class StatisticsChart extends LitElement {
statTypes.forEach((type) => {
let val: number | null;
if (type === "sum") {
if (!initVal) {
initVal = val = stat.state;
if (initVal === null) {
initVal = val = stat.state || 0;
prevSum = stat.sum;
} else {
val = initVal + ((stat.sum || 0) - prevSum!);
+161 -159
View File
@@ -1,165 +1,167 @@
export const currencies = [
"AED",
"AFN",
"ALL",
"AMD",
"ANG",
"AOA",
"ARS",
"AUD",
"AWG",
"AZN",
"BAM",
"BBD",
"BDT",
"BGN",
"BHD",
"BIF",
"BMD",
"BND",
"BOB",
"BRL",
"BSD",
"BTN",
"BWP",
"BYN",
"BYR",
"BZD",
"CAD",
"CDF",
"CHF",
"CLP",
"CNY",
"COP",
"CRC",
"CUP",
"CVE",
"CZK",
"DJF",
"DKK",
"DOP",
"DZD",
"EGP",
"ERN",
"ETB",
"EUR",
"FJD",
"FKP",
"GBP",
"GEL",
"GHS",
"GIP",
"GMD",
"GNF",
"GTQ",
"GYD",
"HKD",
"HNL",
"HRK",
"HTG",
"HUF",
"IDR",
"ILS",
"INR",
"IQD",
"IRR",
"ISK",
"JMD",
"JOD",
"JPY",
"KES",
"KGS",
"KHR",
"KMF",
"KPW",
"KRW",
"KWD",
"KYD",
"KZT",
"LAK",
"LBP",
"LKR",
"LRD",
"LSL",
"LTL",
"LYD",
"MAD",
"MDL",
"MGA",
"MKD",
"MMK",
"MNT",
"MOP",
"MRO",
"MUR",
"MVR",
"MWK",
"MXN",
"MYR",
"MZN",
"NAD",
"NGN",
"NIO",
"NOK",
"NPR",
"NZD",
"OMR",
"PAB",
"PEN",
"PGK",
"PHP",
"PKR",
"PLN",
"PYG",
"QAR",
"RON",
"RSD",
"RUB",
"RWF",
"SAR",
"SBD",
"SCR",
"SDG",
"SEK",
"SGD",
"SHP",
"SLL",
"SOS",
"SRD",
"SSP",
"STD",
"SYP",
"SZL",
"THB",
"TJS",
"TMT",
"TND",
"TOP",
"TRY",
"TTD",
"TWD",
"TZS",
"UAH",
"UGX",
"USD",
"UYU",
"UZS",
"VEF",
"VND",
"VUV",
"WST",
"XAF",
"XCD",
"XOF",
"XPF",
"YER",
"ZAR",
"ZMK",
"ZWL",
];
export const createCurrencyListEl = () => {
const list = document.createElement("datalist");
list.id = "currencies";
for (const currency of [
"AED",
"AFN",
"ALL",
"AMD",
"ANG",
"AOA",
"ARS",
"AUD",
"AWG",
"AZN",
"BAM",
"BBD",
"BDT",
"BGN",
"BHD",
"BIF",
"BMD",
"BND",
"BOB",
"BRL",
"BSD",
"BTN",
"BWP",
"BYN",
"BYR",
"BZD",
"CAD",
"CDF",
"CHF",
"CLP",
"CNY",
"COP",
"CRC",
"CUP",
"CVE",
"CZK",
"DJF",
"DKK",
"DOP",
"DZD",
"EGP",
"ERN",
"ETB",
"EUR",
"FJD",
"FKP",
"GBP",
"GEL",
"GHS",
"GIP",
"GMD",
"GNF",
"GTQ",
"GYD",
"HKD",
"HNL",
"HRK",
"HTG",
"HUF",
"IDR",
"ILS",
"INR",
"IQD",
"IRR",
"ISK",
"JMD",
"JOD",
"JPY",
"KES",
"KGS",
"KHR",
"KMF",
"KPW",
"KRW",
"KWD",
"KYD",
"KZT",
"LAK",
"LBP",
"LKR",
"LRD",
"LSL",
"LTL",
"LYD",
"MAD",
"MDL",
"MGA",
"MKD",
"MMK",
"MNT",
"MOP",
"MRO",
"MUR",
"MVR",
"MWK",
"MXN",
"MYR",
"MZN",
"NAD",
"NGN",
"NIO",
"NOK",
"NPR",
"NZD",
"OMR",
"PAB",
"PEN",
"PGK",
"PHP",
"PKR",
"PLN",
"PYG",
"QAR",
"RON",
"RSD",
"RUB",
"RWF",
"SAR",
"SBD",
"SCR",
"SDG",
"SEK",
"SGD",
"SHP",
"SLL",
"SOS",
"SRD",
"SSP",
"STD",
"SYP",
"SZL",
"THB",
"TJS",
"TMT",
"TND",
"TOP",
"TRY",
"TTD",
"TWD",
"TZS",
"UAH",
"UGX",
"USD",
"UYU",
"UZS",
"VEF",
"VND",
"VUV",
"WST",
"XAF",
"XCD",
"XOF",
"XPF",
"YER",
"ZAR",
"ZMK",
"ZWL",
]) {
for (const currency of currencies) {
const option = document.createElement("option");
option.value = currency;
option.innerHTML = currency;
+2 -2
View File
@@ -269,8 +269,8 @@ export class HaDataTable extends LitElement {
@change=${this._handleHeaderRowCheckboxClick}
.indeterminate=${this._checkedRows.length &&
this._checkedRows.length !== this._checkableRowsCount}
.checked=${this._checkedRows.length ===
this._checkableRowsCount}
.checked=${this._checkedRows.length &&
this._checkedRows.length === this._checkableRowsCount}
>
</ha-checkbox>
</div>
@@ -5,6 +5,7 @@ import { fireEvent } from "../../common/dom/fire_event";
import {
DeviceAutomation,
deviceAutomationsEqual,
sortDeviceAutomations,
} from "../../data/device_automation";
import { HomeAssistant } from "../../types";
import "../ha-select";
@@ -127,7 +128,9 @@ export abstract class HaDeviceAutomationPicker<
private async _updateDeviceInfo() {
this._automations = this.deviceId
? await this._fetchDeviceAutomations(this.hass, this.deviceId)
? (await this._fetchDeviceAutomations(this.hass, this.deviceId)).sort(
sortDeviceAutomations
)
: // No device, clear the list of automations
[];
@@ -161,8 +164,9 @@ export abstract class HaDeviceAutomationPicker<
if (this.value && deviceAutomationsEqual(automation, this.value)) {
return;
}
fireEvent(this, "change");
fireEvent(this, "value-changed", { value: automation });
const value = { ...automation };
delete value.metadata;
fireEvent(this, "value-changed", { value });
}
static get styles(): CSSResultGroup {
+7 -3
View File
@@ -52,6 +52,8 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) {
@property() public value?: string;
@property() public helper?: string;
@property() public devices?: DeviceRegistryEntry[];
@property() public areas?: AreaRegistryEntry[];
@@ -196,9 +198,10 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) {
this.hass,
deviceEntityLookup[device.id]
),
area: device.area_id
? areaLookup[device.area_id].name
: this.hass.localize("ui.components.device-picker.no_area"),
area:
device.area_id && areaLookup[device.area_id]
? areaLookup[device.area_id].name
: this.hass.localize("ui.components.device-picker.no_area"),
}));
if (!outputDevices.length) {
return [
@@ -269,6 +272,7 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) {
? this.hass.localize("ui.components.device-picker.device")
: this.label}
.value=${this._value}
.helper=${this.helper}
.renderer=${rowRenderer}
.disabled=${this.disabled}
.required=${this.required}
@@ -4,6 +4,7 @@ import { fireEvent } from "../../common/dom/fire_event";
import { PolymerChangedEvent } from "../../polymer-types";
import { HomeAssistant } from "../../types";
import "./ha-device-picker";
import type { HaDevicePickerDeviceFilterFunc } from "./ha-device-picker";
@customElement("ha-devices-picker")
class HaDevicesPicker extends LitElement {
@@ -11,6 +12,10 @@ class HaDevicesPicker extends LitElement {
@property() public value?: string[];
@property() public helper?: string;
@property({ type: Boolean }) public disabled?: boolean;
@property({ type: Boolean }) public required?: boolean;
/**
@@ -37,6 +42,8 @@ class HaDevicesPicker extends LitElement {
@property({ attribute: "pick-device-label" }) public pickDeviceLabel?: string;
@property() public deviceFilter?: HaDevicePickerDeviceFilterFunc;
protected render(): TemplateResult {
if (!this.hass) {
return html``;
@@ -51,11 +58,13 @@ class HaDevicesPicker extends LitElement {
allow-custom-entity
.curValue=${entityId}
.hass=${this.hass}
.deviceFilter=${this.deviceFilter}
.includeDomains=${this.includeDomains}
.excludeDomains=${this.excludeDomains}
.includeDeviceClasses=${this.includeDeviceClasses}
.value=${entityId}
.label=${this.pickedDeviceLabel}
.disabled=${this.disabled}
@value-changed=${this._deviceChanged}
></ha-device-picker>
</div>
@@ -63,11 +72,15 @@ class HaDevicesPicker extends LitElement {
)}
<div>
<ha-device-picker
allow-custom-entity
.hass=${this.hass}
.helper=${this.helper}
.deviceFilter=${this.deviceFilter}
.includeDomains=${this.includeDomains}
.excludeDomains=${this.excludeDomains}
.includeDeviceClasses=${this.includeDeviceClasses}
.label=${this.pickDeviceLabel}
.disabled=${this.disabled}
.required=${this.required && !currentDevices.length}
@value-changed=${this._addDevice}
></ha-device-picker>
@@ -14,8 +14,12 @@ class HaEntitiesPickerLight extends LitElement {
@property({ type: Array }) public value?: string[];
@property({ type: Boolean }) public disabled?: boolean;
@property({ type: Boolean }) public required?: boolean;
@property() public helper?: string;
/**
* Show entities from specific domains.
* @type {string}
@@ -94,6 +98,7 @@ class HaEntitiesPickerLight extends LitElement {
.entityFilter=${this._entityFilter}
.value=${entityId}
.label=${this.pickedEntityLabel}
.disabled=${this.disabled}
@value-changed=${this._entityChanged}
></ha-entity-picker>
</div>
@@ -101,6 +106,7 @@ class HaEntitiesPickerLight extends LitElement {
)}
<div>
<ha-entity-picker
allow-custom-entity
.hass=${this.hass}
.includeDomains=${this.includeDomains}
.excludeDomains=${this.excludeDomains}
@@ -110,6 +116,8 @@ class HaEntitiesPickerLight extends LitElement {
.includeUnitOfMeasurement=${this.includeUnitOfMeasurement}
.entityFilter=${this._entityFilter}
.label=${this.pickEntityLabel}
.helper=${this.helper}
.disabled=${this.disabled}
.required=${this.required && !currentEntities.length}
@value-changed=${this._addEntity}
></ha-entity-picker>
@@ -28,6 +28,8 @@ class HaEntityAttributePicker extends LitElement {
@property() public value?: string;
@property() public helper?: string;
@property({ type: Boolean }) private _opened = false;
@query("ha-combo-box", true) private _comboBox!: HaComboBox;
@@ -64,6 +66,7 @@ class HaEntityAttributePicker extends LitElement {
)}
.disabled=${this.disabled || !this.entityId}
.required=${this.required}
.helper=${this.helper}
.allowCustomValue=${this.allowCustomValue}
item-value-path="value"
item-label-path="label"
@@ -48,6 +48,8 @@ export class HaEntityPicker extends LitElement {
@property() public value?: string;
@property() public helper?: string;
/**
* Show entities from specific domains.
* @type {Array}
@@ -304,6 +306,7 @@ export class HaEntityPicker extends LitElement {
.label=${this.label === undefined
? this.hass.localize("ui.components.entity.entity-picker.entity")
: this.label}
.helper=${this.helper}
.allowCustomValue=${this.allowCustomEntity}
.filteredItems=${this._states}
.renderer=${rowRenderer}
+3
View File
@@ -29,6 +29,8 @@ class HaAddonPicker extends LitElement {
@property() public value = "";
@property() public helper?: string;
@state() private _addons?: HassioAddonInfo[];
@property({ type: Boolean }) public disabled = false;
@@ -62,6 +64,7 @@ class HaAddonPicker extends LitElement {
.value=${this._value}
.required=${this.required}
.disabled=${this.disabled}
.helper=${this.helper}
.renderer=${rowRenderer}
.items=${this._addons}
item-value-path="slug"
+54 -54
View File
@@ -2,12 +2,12 @@ import "@polymer/paper-tooltip/paper-tooltip";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";
import { fireEvent } from "../common/dom/fire_event";
import { Analytics, AnalyticsPreferences } from "../data/analytics";
import type { Analytics, AnalyticsPreferences } from "../data/analytics";
import { haStyle } from "../resources/styles";
import { HomeAssistant } from "../types";
import "./ha-checkbox";
import type { HaCheckbox } from "./ha-checkbox";
import type { HomeAssistant } from "../types";
import "./ha-settings-row";
import "./ha-switch";
import type { HaSwitch } from "./ha-switch";
const ADDITIONAL_PREFERENCES = [
{
@@ -40,62 +40,62 @@ export class HaAnalytics extends LitElement {
return html`
<ha-settings-row>
<span slot="prefix">
<ha-checkbox
@change=${this._handleRowCheckboxClick}
.checked=${baseEnabled}
.preference=${"base"}
.disabled=${loading}
name="base"
>
</ha-checkbox>
</span>
<span slot="heading" data-for="base"> Basic analytics </span>
<span slot="description" data-for="base">
This includes information about your system.
</span>
<ha-switch
@change=${this._handleRowClick}
.checked=${baseEnabled}
.preference=${"base"}
.disabled=${loading}
name="base"
>
</ha-switch>
</ha-settings-row>
${ADDITIONAL_PREFERENCES.map(
(preference) =>
html`<ha-settings-row>
<span slot="prefix">
<ha-checkbox
@change=${this._handleRowCheckboxClick}
.checked=${this.analytics?.preferences[preference.key]}
.preference=${preference.key}
name=${preference.key}
>
</ha-checkbox>
${!baseEnabled
? html`<paper-tooltip animation-delay="0" position="right">
You need to enable basic analytics for this option to be
available
</paper-tooltip>`
: ""}
</span>
<span slot="heading" data-for=${preference.key}>
${preference.title}
</span>
<span slot="description" data-for=${preference.key}>
${preference.description}
</span>
</ha-settings-row>`
html`
<ha-settings-row>
<span slot="heading" data-for=${preference.key}>
${preference.title}
</span>
<span slot="description" data-for=${preference.key}>
${preference.description}
</span>
<span>
<ha-switch
@change=${this._handleRowClick}
.checked=${this.analytics?.preferences[preference.key]}
.preference=${preference.key}
name=${preference.key}
>
</ha-switch>
${!baseEnabled
? html`
<paper-tooltip animation-delay="0" position="right">
You need to enable basic analytics for this option to be
available
</paper-tooltip>
`
: ""}
</span>
</ha-settings-row>
`
)}
<ha-settings-row>
<span slot="prefix">
<ha-checkbox
@change=${this._handleRowCheckboxClick}
.checked=${this.analytics?.preferences.diagnostics}
.preference=${"diagnostics"}
.disabled=${loading}
name="diagnostics"
>
</ha-checkbox>
</span>
<span slot="heading" data-for="diagnostics"> Diagnostics </span>
<span slot="description" data-for="diagnostics">
Share crash reports when unexpected errors occur.
</span>
<ha-switch
@change=${this._handleRowClick}
.checked=${this.analytics?.preferences.diagnostics}
.preference=${"diagnostics"}
.disabled=${loading}
name="diagnostics"
>
</ha-switch>
</ha-settings-row>
`;
}
@@ -120,23 +120,23 @@ export class HaAnalytics extends LitElement {
});
}
private _handleRowCheckboxClick(ev: Event) {
const checkbox = ev.currentTarget as HaCheckbox;
const preference = (checkbox as any).preference;
private _handleRowClick(ev: Event) {
const target = ev.currentTarget as HaSwitch;
const preference = (target as any).preference;
const preferences = this.analytics ? { ...this.analytics.preferences } : {};
if (preferences[preference] === checkbox.checked) {
if (preferences[preference] === target.checked) {
return;
}
preferences[preference] = checkbox.checked;
preferences[preference] = target.checked;
if (
ADDITIONAL_PREFERENCES.some((entry) => entry.key === preference) &&
checkbox.checked
target.checked
) {
preferences.base = true;
} else if (preference === "base" && !checkbox.checked) {
} else if (preference === "base" && !target.checked) {
preferences.usage = false;
preferences.statistics = false;
}
@@ -10,8 +10,8 @@ interface State {
backgroundColor: null | string;
}
@customElement("hassio-ansi-to-html")
class HassioAnsiToHtml extends LitElement {
@customElement("ha-ansi-to-html")
class HaAnsiToHtml extends LitElement {
@property() public content!: string;
protected render(): TemplateResult | void {
@@ -241,6 +241,6 @@ class HassioAnsiToHtml extends LitElement {
declare global {
interface HTMLElementTagNameMap {
"hassio-ansi-to-html": HassioAnsiToHtml;
"ha-ansi-to-html": HaAnsiToHtml;
}
}
+4 -1
View File
@@ -49,6 +49,8 @@ export class HaAreaPicker extends SubscribeMixin(LitElement) {
@property() public value?: string;
@property() public helper?: string;
@property() public placeholder?: string;
@property({ type: Boolean, attribute: "no-add" })
@@ -312,6 +314,7 @@ export class HaAreaPicker extends SubscribeMixin(LitElement) {
return html`
<ha-combo-box
.hass=${this.hass}
.helper=${this.helper}
item-value-path="area_id"
item-id-path="area_id"
item-label-path="name"
@@ -406,7 +409,7 @@ export class HaAreaPicker extends SubscribeMixin(LitElement) {
name,
});
this._areas = [...this._areas!, area];
(this.comboBox as any).items = this._getAreas(
(this.comboBox as any).filteredItems = this._getAreas(
this._areas!,
this._devices!,
this._entities!,
+3
View File
@@ -15,6 +15,8 @@ export class HaAreasPicker extends SubscribeMixin(LitElement) {
@property() public value?: string[];
@property() public helper?: string;
@property() public placeholder?: string;
@property({ type: Boolean, attribute: "no-add" })
@@ -90,6 +92,7 @@ export class HaAreasPicker extends SubscribeMixin(LitElement) {
.noAdd=${this.noAdd}
.hass=${this.hass}
.label=${this.pickAreaLabel}
.helper=${this.helper}
.includeDomains=${this.includeDomains}
.excludeDomains=${this.excludeDomains}
.includeDeviceClasses=${this.includeDeviceClasses}
+6 -9
View File
@@ -5,6 +5,7 @@ import { fireEvent } from "../common/dom/fire_event";
import { stopPropagation } from "../common/dom/stop_propagation";
import "./ha-select";
import "./ha-textfield";
import "./ha-input-helper-text";
export interface TimeChangedEvent {
days?: number;
@@ -130,7 +131,7 @@ export class HaBaseTimeInput extends LitElement {
protected render(): TemplateResult {
return html`
${this.label
? html`<label>${this.label}${this.required ? "*" : ""}</label>`
? html`<label>${this.label}${this.required ? " *" : ""}</label>`
: ""}
<div class="time-input-wrap">
${this.enableDay
@@ -253,7 +254,9 @@ export class HaBaseTimeInput extends LitElement {
<mwc-list-item value="PM">PM</mwc-list-item>
</ha-select>`}
</div>
${this.helper ? html`<div class="helper">${this.helper}</div>` : ""}
${this.helper
? html`<ha-input-helper-text>${this.helper}</ha-input-helper-text>`
: ""}
`;
}
@@ -307,6 +310,7 @@ export class HaBaseTimeInput extends LitElement {
border-radius: var(--mdc-shape-small, 4px) var(--mdc-shape-small, 4px) 0 0;
overflow: hidden;
position: relative;
direction: ltr;
}
ha-textfield {
width: 40px;
@@ -350,13 +354,6 @@ export class HaBaseTimeInput extends LitElement {
color: var(--mdc-theme-text-primary-on-background, rgba(0, 0, 0, 0.87));
padding-left: 4px;
}
.helper {
color: var(--mdc-text-field-label-ink-color, rgba(0, 0, 0, 0.6));
font-size: 0.75rem;
padding-left: 16px;
padding-right: 16px;
}
`;
}
+15
View File
@@ -50,6 +50,21 @@ export class HaButtonMenu extends LitElement {
`;
}
protected firstUpdated(changedProps): void {
super.firstUpdated(changedProps);
if (document.dir === "rtl") {
this.updateComplete.then(() => {
this.querySelectorAll("mwc-list-item").forEach((item) => {
const style = document.createElement("style");
style.innerHTML =
"span.material-icons:first-of-type { margin-left: var(--mdc-list-item-graphic-margin, 32px) !important; margin-right: 0px !important;}";
item!.shadowRoot!.appendChild(style);
});
});
}
}
private _handleClick(): void {
if (this.disabled) {
return;
+13
View File
@@ -117,6 +117,19 @@ export class HaButtonToggleGroup extends LitElement {
--mdc-shape-small: 4px;
border-right-width: 1px;
}
:host([dir="rtl"]) ha-icon-button:first-child,
:host([dir="rtl"]) mwc-button:first-child {
border-radius: 0 4px 4px 0;
border-right-width: 1px;
--mdc-shape-small: 0 4px 4px 0;
--mdc-button-outline-width: 1px;
}
:host([dir="rtl"]) ha-icon-button:last-child,
:host([dir="rtl"]) mwc-button:last-child {
--mdc-shape-small: 4px 0 0 4px;
border-radius: 4px 0 0 4px;
}
`;
}
}
+82
View File
@@ -0,0 +1,82 @@
import { ListItemBase } from "@material/mwc-list/mwc-list-item-base";
import { styles } from "@material/mwc-list/mwc-list-item.css";
import { css, CSSResult, html } from "lit";
import { customElement, property, query } from "lit/decorators";
@customElement("ha-clickable-list-item")
export class HaClickableListItem extends ListItemBase {
@property() public href?: string;
@property({ type: Boolean }) public disableHref = false;
// property used only in css
@property({ type: Boolean, reflect: true }) public rtl = false;
@property({ type: Boolean, reflect: true }) public openNewTab = false;
@query("a") private _anchor!: HTMLAnchorElement;
public render() {
const r = super.render();
const href = this.href || "";
return html`${this.disableHref
? html`<a aria-role="option">${r}</a>`
: html`<a
aria-role="option"
target=${this.openNewTab ? "_blank" : ""}
href=${href}
>${r}</a
>`}`;
}
firstUpdated() {
super.firstUpdated();
this.addEventListener("keydown", (ev) => {
if (ev.key === "Enter" || ev.key === " ") {
this._anchor.click();
}
});
}
static get styles(): CSSResult[] {
return [
styles,
css`
:host {
padding-left: 0px;
padding-right: 0px;
}
:host([graphic="avatar"]:not([twoLine])),
:host([graphic="icon"]:not([twoLine])) {
height: 48px;
}
a {
width: 100%;
height: 100%;
display: flex;
align-items: center;
padding-left: var(--mdc-list-side-padding, 20px);
padding-right: var(--mdc-list-side-padding, 20px);
overflow: hidden;
}
:host-context([style*="direction: rtl;"])
span.material-icons:first-of-type {
margin-left: var(--mdc-list-item-graphic-margin, 16px) !important;
margin-right: 0px !important;
}
:host-context([style*="direction: rtl;"])
span.material-icons:last-of-type {
margin-left: 0px !important;
margin-right: auto !important;
}
`,
];
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-clickable-list-item": HaClickableListItem;
}
}
+16
View File
@@ -64,6 +64,8 @@ export class HaComboBox extends LitElement {
@property() public validationMessage?: string;
@property() public helper?: string;
@property({ attribute: "error-message" }) public errorMessage?: string;
@property({ type: Boolean }) public invalid?: boolean;
@@ -147,6 +149,8 @@ export class HaComboBox extends LitElement {
.suffix=${html`<div style="width: 28px;"></div>`}
.icon=${this.icon}
.invalid=${this.invalid}
.helper=${this.helper}
helperPersistent
>
<slot name="icon" slot="leadingIcon"></slot>
</ha-textfield>
@@ -246,6 +250,18 @@ export class HaComboBox extends LitElement {
top: -7px;
right: 36px;
}
:host-context([style*="direction: rtl;"]) .toggle-button {
left: 12px;
right: auto;
top: -10px;
}
:host-context([style*="direction: rtl;"]) .clear-button {
--mdc-icon-size: 20px;
top: -7px;
left: 36px;
right: auto;
}
`;
}
}
+4
View File
@@ -39,11 +39,15 @@ export class HaDateInput extends LitElement {
@property() public label?: string;
@property() public helper?: string;
render() {
return html`<ha-textfield
.label=${this.label}
.helper=${this.helper}
.disabled=${this.disabled}
iconTrailing
helperPersistent
@click=${this._openDialog}
.value=${this.value
? formatDateNumeric(new Date(this.value), this.locale)
+4
View File
@@ -98,6 +98,10 @@ export class HaDialog extends DialogBase {
margin-left: 40px;
margin-right: 0px;
}
:host-context([style*="direction: rtl;"]) .dialog-actions {
left: 0px !important;
right: auto !important;
}
`,
];
}
+15 -2
View File
@@ -1,12 +1,25 @@
import { Fab } from "@material/mwc-fab";
import { FabBase } from "@material/mwc-fab/mwc-fab-base";
import { styles } from "@material/mwc-fab/mwc-fab.css";
import { customElement } from "lit/decorators";
import { css } from "lit";
@customElement("ha-fab")
export class HaFab extends Fab {
export class HaFab extends FabBase {
protected firstUpdated(changedProperties) {
super.firstUpdated(changedProperties);
this.style.setProperty("--mdc-theme-secondary", "var(--primary-color)");
}
static override styles = [
styles,
css`
:host .mdc-fab--extended .mdc-fab__icon {
margin-inline-start: -8px;
margin-inline-end: 12px;
direction: var(--direction);
}
`,
];
}
declare global {
+14
View File
@@ -176,10 +176,24 @@ export class HaFileUpload extends LitElement {
.mdc-text-field__icon--leading {
margin-bottom: 12px;
}
:host-context([style*="direction: rtl;"])
.mdc-text-field__icon--leading {
margin-right: 0px;
}
.mdc-text-field--filled .mdc-floating-label--float-above {
transform: scale(0.75);
top: 8px;
}
:host-context([style*="direction: rtl;"]) .mdc-floating-label {
left: initial;
right: 16px;
}
:host-context([style*="direction: rtl;"])
.mdc-text-field--filled
.mdc-floating-label {
left: initial;
right: 48px;
}
.dragged:before {
position: var(--layout-fit_-_position);
top: var(--layout-fit_-_top);
+5
View File
@@ -132,6 +132,11 @@ export class HaFormString extends LitElement implements HaFormElement {
--mdc-icon-button-size: 24px;
color: var(--secondary-text-color);
}
:host-context([style*="direction: rtl;"]) ha-icon-button {
right: auto;
left: 12px;
}
`;
}
}
+1 -2
View File
@@ -77,7 +77,7 @@ export class HaForm extends LitElement implements HaFormElement {
protected render(): TemplateResult {
return html`
<div class="root">
<div class="root" part="root">
${this.error && this.error.base
? html`
<ha-alert alert-type="error">
@@ -173,7 +173,6 @@ export class HaForm extends LitElement implements HaFormElement {
}
static get styles(): CSSResultGroup {
// .root has overflow: auto to avoid margin collapse
return css`
.root {
margin-bottom: -24px;
+3
View File
@@ -31,6 +31,8 @@ export class HaIconPicker extends LitElement {
@property() public label?: string;
@property() public helper?: string;
@property() public placeholder?: string;
@property() public fallbackPath?: string;
@@ -57,6 +59,7 @@ export class HaIconPicker extends LitElement {
allow-custom-value
.filteredItems=${iconItems}
.label=${this.label}
.helper=${this.helper}
.disabled=${this.disabled}
.required=${this.required}
.placeholder=${this.placeholder}
+25
View File
@@ -0,0 +1,25 @@
import { css, html, LitElement, TemplateResult } from "lit";
import { customElement } from "lit/decorators";
@customElement("ha-input-helper-text")
class InputHelperText extends LitElement {
protected render(): TemplateResult {
return html`<slot></slot>`;
}
static styles = css`
:host {
display: block;
color: var(--mdc-text-field-label-ink-color, rgba(0, 0, 0, 0.6));
font-size: 0.75rem;
padding-left: 16px;
padding-right: 16px;
}
`;
}
declare global {
interface HTMLElementTagNameMap {
"ha-input-helper-text": InputHelperText;
}
}
+5 -1
View File
@@ -46,11 +46,14 @@ class HaLabeledSlider extends PolymerElement {
value="{{value}}"
></ha-slider>
</div>
<template is="dom-if" if="[[helper]]">
<ha-input-helper-text>[[helper]]</ha-input-helper-text>
</template>
`;
}
_getTitle() {
return `${this.caption}${this.required ? "*" : ""}`;
return `${this.caption}${this.caption && this.required ? " *" : ""}`;
}
static get properties() {
@@ -62,6 +65,7 @@ class HaLabeledSlider extends PolymerElement {
max: Number,
pin: Boolean,
step: Number,
helper: String,
extra: {
type: Boolean,
+3 -7
View File
@@ -3,7 +3,6 @@ import { UnsubscribeFunc } from "home-assistant-js-websocket";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../common/dom/fire_event";
import { computeDomain } from "../common/entity/compute_domain";
import { subscribeNotifications } from "../data/persistent_notification";
import { HomeAssistant } from "../types";
import "./ha-icon-button";
@@ -43,18 +42,15 @@ class HaMenuButton extends LitElement {
protected render(): TemplateResult {
const hasNotifications =
(this.narrow || this.hass.dockedSidebar === "always_hidden") &&
(this._hasNotifications ||
Object.keys(this.hass.states).some(
(entityId) => computeDomain(entityId) === "configurator"
));
this._hasNotifications &&
(this.narrow || this.hass.dockedSidebar === "always_hidden");
return html`
<ha-icon-button
.label=${this.hass.localize("ui.sidebar.sidebar_toggle")}
.path=${mdiMenu}
@click=${this._toggleMenu}
></ha-icon-button>
${hasNotifications ? html` <div class="dot"></div> ` : ""}
${hasNotifications ? html`<div class="dot"></div>` : ""}
`;
}
+79
View File
@@ -0,0 +1,79 @@
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { roundWithOneDecimal } from "../util/calculate";
import "./ha-bar";
import "./ha-settings-row";
@customElement("ha-metric")
class HaMetric extends LitElement {
@property({ type: Number }) public value!: number;
@property({ type: String }) public heading!: string;
@property({ type: String }) public tooltip?: string;
protected render(): TemplateResult {
const roundedValue = roundWithOneDecimal(this.value);
return html`
<ha-settings-row>
<span slot="heading"> ${this.heading} </span>
<div slot="description" .title=${this.tooltip ?? ""}>
<span class="value"> ${roundedValue} % </span>
<ha-bar
class=${classMap({
"target-warning": roundedValue > 50,
"target-critical": roundedValue > 85,
})}
.value=${this.value}
></ha-bar>
</div>
</ha-settings-row>
`;
}
static get styles(): CSSResultGroup {
return css`
ha-settings-row {
padding: 0;
height: 54px;
width: 100%;
}
ha-settings-row > div[slot="description"] {
white-space: normal;
color: var(--secondary-text-color);
display: flex;
justify-content: space-between;
}
ha-bar {
--ha-bar-primary-color: var(
--metric-bar-ok-color,
var(--success-color)
);
}
.target-warning {
--ha-bar-primary-color: var(
--metric-bar-warning-color,
var(--warning-color)
);
}
.target-critical {
--ha-bar-primary-color: var(
--metric-bar-critical-color,
var(--error-color)
);
}
.value {
width: 48px;
padding-right: 4px;
flex-shrink: 0;
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-metric": HaMetric;
}
}
+90
View File
@@ -0,0 +1,90 @@
import "@material/mwc-list/mwc-list";
import "@material/mwc-list/mwc-list-item";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";
import type { PageNavigation } from "../layouts/hass-tabs-subpage";
import type { HomeAssistant } from "../types";
import "./ha-clickable-list-item";
import "./ha-icon-next";
import "./ha-svg-icon";
@customElement("ha-navigation-list")
class HaNavigationList extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ type: Boolean }) public narrow!: boolean;
@property({ attribute: false }) public pages!: PageNavigation[];
@property({ type: Boolean }) public hasSecondary = false;
public render(): TemplateResult {
return html`
<mwc-list>
${this.pages.map(
(page) => html`
<ha-clickable-list-item
graphic="avatar"
.twoline=${this.hasSecondary}
.hasMeta=${!this.narrow}
@click=${this._entryClicked}
href=${page.path}
>
<div
slot="graphic"
class=${page.iconColor ? "icon-background" : ""}
.style="background-color: ${page.iconColor || "undefined"}"
>
<ha-svg-icon .path=${page.iconPath}></ha-svg-icon>
</div>
<span>${page.name}</span>
${this.hasSecondary
? html`<span slot="secondary">${page.description}</span>`
: ""}
${!this.narrow
? html`<ha-icon-next slot="meta"></ha-icon-next>`
: ""}
</ha-clickable-list-item>
`
)}
</mwc-list>
`;
}
private _entryClicked(ev) {
ev.currentTarget.blur();
}
static styles: CSSResultGroup = css`
:host {
--mdc-list-vertical-padding: 0;
}
ha-svg-icon,
ha-icon-next {
color: var(--secondary-text-color);
height: 24px;
width: 24px;
display: block;
}
ha-svg-icon {
padding: 8px;
}
.icon-background {
border-radius: 50%;
}
.icon-background ha-svg-icon {
color: #fff;
}
ha-clickable-list-item {
cursor: pointer;
font-size: var(--navigation-list-item-title-font-size);
padding: var(--navigation-list-item-padding) 0;
}
`;
}
declare global {
interface HTMLElementTagNameMap {
"ha-navigation-list": HaNavigationList;
}
}
+3
View File
@@ -163,6 +163,9 @@ export class HaNetwork extends LitElement {
ha-settings-row {
padding: 0;
--paper-time-input-justify-content: flex-end;
--settings-row-content-display: contents;
--settings-row-prefix-display: contents;
}
span[slot="heading"],
+4
View File
@@ -47,6 +47,10 @@ export class HaSelect extends SelectBase {
.mdc-select__anchor {
width: var(--ha-select-min-width, 200px);
}
:host-context([style*="direction: rtl;"]) .mdc-floating-label {
right: 16px !important;
left: initial !important;
}
`,
];
}
@@ -14,6 +14,8 @@ export class HaAddonSelector extends LitElement {
@property() public label?: string;
@property() public helper?: string;
@property({ type: Boolean }) public disabled = false;
@property({ type: Boolean }) public required = true;
@@ -23,6 +25,7 @@ export class HaAddonSelector extends LitElement {
.hass=${this.hass}
.value=${this.value}
.label=${this.label}
.helper=${this.helper}
.disabled=${this.disabled}
.required=${this.required}
allow-custom-entity
@@ -18,6 +18,8 @@ export class HaAreaSelector extends LitElement {
@property() public label?: string;
@property() public helper?: string;
@state() public _configEntries?: ConfigEntry[];
@property({ type: Boolean }) public disabled = false;
@@ -47,6 +49,7 @@ export class HaAreaSelector extends LitElement {
.hass=${this.hass}
.value=${this.value}
.label=${this.label}
.helper=${this.helper}
no-add
.deviceFilter=${this._filterDevices}
.entityFilter=${this._filterEntities}
@@ -66,6 +69,7 @@ export class HaAreaSelector extends LitElement {
<ha-areas-picker
.hass=${this.hass}
.value=${this.value}
.helper=${this.helper}
.pickAreaLabel=${this.label}
no-add
.deviceFilter=${this._filterDevices}
@@ -16,6 +16,8 @@ export class HaSelectorAttribute extends SubscribeMixin(LitElement) {
@property() public label?: string;
@property() public helper?: string;
@property({ type: Boolean }) public disabled = false;
@property({ type: Boolean }) public required = true;
@@ -32,6 +34,7 @@ export class HaSelectorAttribute extends SubscribeMixin(LitElement) {
this.context?.filter_entity}
.value=${this.value}
.label=${this.label}
.helper=${this.helper}
.disabled=${this.disabled}
.required=${this.required}
allow-custom-value
@@ -4,6 +4,7 @@ import { fireEvent } from "../../common/dom/fire_event";
import { HomeAssistant } from "../../types";
import "../ha-formfield";
import "../ha-switch";
import "../ha-input-helper-text";
@customElement("ha-selector-boolean")
export class HaBooleanSelector extends LitElement {
@@ -13,16 +14,23 @@ export class HaBooleanSelector extends LitElement {
@property() public label?: string;
@property() public helper?: string;
@property({ type: Boolean }) public disabled = false;
protected render() {
return html`<ha-formfield alignEnd spaceBetween .label=${this.label}>
<ha-switch
.checked=${this.value}
@change=${this._handleChange}
.disabled=${this.disabled}
></ha-switch>
</ha-formfield>`;
return html`
<ha-formfield alignEnd spaceBetween .label=${this.label}>
<ha-switch
.checked=${this.value}
@change=${this._handleChange}
.disabled=${this.disabled}
></ha-switch>
</ha-formfield>
${this.helper
? html`<ha-input-helper-text>${this.helper}</ha-input-helper-text>`
: ""}
`;
}
private _handleChange(ev) {
@@ -35,12 +43,10 @@ export class HaBooleanSelector extends LitElement {
static get styles(): CSSResultGroup {
return css`
:host {
height: 56px;
display: flex;
}
ha-formfield {
width: 100%;
display: flex;
height: 56px;
align-items: center;
--mdc-typography-body2-font-size: 1em;
}
`;
@@ -16,6 +16,8 @@ export class HaColorRGBSelector extends LitElement {
@property() public label?: string;
@property() public helper?: string;
@property({ type: Boolean, reflect: true }) public disabled = false;
@property({ type: Boolean }) public required = true;
@@ -24,9 +26,11 @@ export class HaColorRGBSelector extends LitElement {
return html`
<ha-textfield
type="color"
helperPersistent
.value=${this.value ? rgb2hex(this.value as any) : ""}
.label=${this.label || ""}
.required=${this.required}
.helper=${this.helper}
.disalbled=${this.disabled}
@change=${this._valueChanged}
></ha-textfield>
@@ -15,6 +15,8 @@ export class HaColorTempSelector extends LitElement {
@property() public label?: string;
@property() public helper?: string;
@property({ type: Boolean, reflect: true }) public disabled = false;
@property({ type: Boolean }) public required = true;
@@ -24,11 +26,12 @@ export class HaColorTempSelector extends LitElement {
<ha-labeled-slider
pin
icon="hass:thermometer"
.caption=${this.label}
.min=${this.selector.color_temp.min_mireds ?? 153}
.max=${this.selector.color_temp.max_mireds ?? 500}
.caption=${this.label || ""}
.min=${this.selector.color_temp?.min_mireds ?? 153}
.max=${this.selector.color_temp?.max_mireds ?? 500}
.value=${this.value}
.disabled=${this.disabled}
.helper=${this.helper}
.required=${this.required}
@change=${this._valueChanged}
></ha-labeled-slider>
@@ -14,6 +14,8 @@ export class HaDateSelector extends LitElement {
@property() public label?: string;
@property() public helper?: string;
@property({ type: Boolean, reflect: true }) public disabled = false;
@property({ type: Boolean }) public required = true;
@@ -26,6 +28,7 @@ export class HaDateSelector extends LitElement {
.disabled=${this.disabled}
.value=${this.value}
.required=${this.required}
.helper=${this.helper}
>
</ha-date-input>
`;
@@ -6,6 +6,7 @@ import type { HomeAssistant } from "../../types";
import "../ha-date-input";
import type { HaDateInput } from "../ha-date-input";
import "../ha-time-input";
import "../ha-input-helper-text";
import type { HaTimeInput } from "../ha-time-input";
@customElement("ha-selector-datetime")
@@ -18,6 +19,8 @@ export class HaDateTimeSelector extends LitElement {
@property() public label?: string;
@property() public helper?: string;
@property({ type: Boolean, reflect: true }) public disabled = false;
@property({ type: Boolean }) public required = true;
@@ -30,23 +33,28 @@ export class HaDateTimeSelector extends LitElement {
const values = this.value?.split(" ");
return html`
<ha-date-input
.label=${this.label}
.locale=${this.hass.locale}
.disabled=${this.disabled}
.required=${this.required}
.value=${values?.[0]}
@value-changed=${this._valueChanged}
>
</ha-date-input>
<ha-time-input
enable-second
.value=${values?.[1] || "0:00:00"}
.locale=${this.hass.locale}
.disabled=${this.disabled}
.required=${this.required}
@value-changed=${this._valueChanged}
></ha-time-input>
<div class="input">
<ha-date-input
.label=${this.label}
.locale=${this.hass.locale}
.disabled=${this.disabled}
.required=${this.required}
.value=${values?.[0]}
@value-changed=${this._valueChanged}
>
</ha-date-input>
<ha-time-input
enable-second
.value=${values?.[1] || "0:00:00"}
.locale=${this.hass.locale}
.disabled=${this.disabled}
.required=${this.required}
@value-changed=${this._valueChanged}
></ha-time-input>
</div>
${this.helper
? html`<ha-input-helper-text>${this.helper}</ha-input-helper-text>`
: ""}
`;
}
@@ -58,7 +66,7 @@ export class HaDateTimeSelector extends LitElement {
}
static styles = css`
:host {
.input {
display: flex;
align-items: center;
flex-direction: row;
@@ -17,6 +17,8 @@ export class HaDeviceSelector extends LitElement {
@property() public label?: string;
@property() public helper?: string;
@state() public _configEntries?: ConfigEntry[];
@property({ type: Boolean }) public disabled = false;
@@ -43,6 +45,7 @@ export class HaDeviceSelector extends LitElement {
.hass=${this.hass}
.value=${this.value}
.label=${this.label}
.helper=${this.helper}
.deviceFilter=${this._filterDevices}
.includeDeviceClasses=${this.selector.device.entity?.device_class
? [this.selector.device.entity.device_class]
@@ -62,12 +65,15 @@ export class HaDeviceSelector extends LitElement {
<ha-devices-picker
.hass=${this.hass}
.value=${this.value}
.helper=${this.helper}
.deviceFilter=${this._filterDevices}
.includeDeviceClasses=${this.selector.device.entity?.device_class
? [this.selector.device.entity.device_class]
: undefined}
.includeDomains=${this.selector.device.entity?.domain
? [this.selector.device.entity.domain]
: undefined}
.disabled=${this.disabled}
.required=${this.required}
></ha-devices-picker>
`;
@@ -23,6 +23,8 @@ export class HaEntitySelector extends LitElement {
@property() public label?: string;
@property() public helper?: string;
@property({ type: Boolean }) public disabled = false;
@property({ type: Boolean }) public required = true;
@@ -33,6 +35,7 @@ export class HaEntitySelector extends LitElement {
.hass=${this.hass}
.value=${this.value}
.label=${this.label}
.helper=${this.helper}
.includeEntities=${this.selector.entity.include_entities}
.excludeEntities=${this.selector.entity.exclude_entities}
.entityFilter=${this._filterEntities}
@@ -47,9 +50,11 @@ export class HaEntitySelector extends LitElement {
<ha-entities-picker
.hass=${this.hass}
.value=${this.value}
.entityFilter=${this._filterEntities}
.helper=${this.helper}
.includeEntities=${this.selector.entity.include_entities}
.excludeEntities=${this.selector.entity.exclude_entities}
.entityFilter=${this._filterEntities}
.disabled=${this.disabled}
.required=${this.required}
></ha-entities-picker>
`;
@@ -15,6 +15,8 @@ export class HaIconSelector extends LitElement {
@property() public label?: string;
@property() public helper?: string;
@property({ type: Boolean, reflect: true }) public disabled = false;
@property({ type: Boolean }) public required = true;
@@ -26,6 +28,7 @@ export class HaIconSelector extends LitElement {
.value=${this.value}
.required=${this.required}
.disabled=${this.disabled}
.helper=${this.helper}
.fallbackPath=${this.selector.icon.fallbackPath}
.placeholder=${this.selector.icon.placeholder}
@value-changed=${this._valueChanged}
@@ -1,4 +1,4 @@
import { html, LitElement } from "lit";
import { css, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../common/dom/fire_event";
@@ -20,6 +20,8 @@ export class HaLocationSelector extends LitElement {
@property() public label?: string;
@property() public helper?: string;
@property({ type: Boolean, reflect: true }) public disabled = false;
protected render() {
@@ -27,6 +29,7 @@ export class HaLocationSelector extends LitElement {
<ha-locations-editor
class="flex"
.hass=${this.hass}
.helper=${this.helper}
.locations=${this._location(this.selector, this.value)}
@location-updated=${this._locationChanged}
@radius-updated=${this._radiusChanged}
@@ -73,6 +76,13 @@ export class HaLocationSelector extends LitElement {
const radius = ev.detail.radius;
fireEvent(this, "value-changed", { value: { ...this.value, radius } });
}
static styles = css`
:host {
display: block;
height: 400px;
}
`;
}
declare global {
@@ -33,6 +33,8 @@ export class HaMediaSelector extends LitElement {
@property() public label?: string;
@property() public helper?: string;
@property({ type: Boolean, reflect: true }) public disabled = false;
@property({ type: Boolean, reflect: true }) public required = true;
@@ -86,6 +88,7 @@ export class HaMediaSelector extends LitElement {
.label=${this.label ||
this.hass.localize("ui.components.selectors.media.pick_media_player")}
.disabled=${this.disabled}
.helper=${this.helper}
.required=${this.required}
include-domains='["media_player"]'
allow-custom-entity
@@ -6,6 +6,7 @@ import { NumberSelector } from "../../data/selector";
import { HomeAssistant } from "../../types";
import "../ha-slider";
import "../ha-textfield";
import "../ha-input-helper-text";
@customElement("ha-selector-number")
export class HaNumberSelector extends LitElement {
@@ -26,8 +27,13 @@ export class HaNumberSelector extends LitElement {
@property({ type: Boolean }) public disabled = false;
protected render() {
return html`${this.selector.number.mode !== "box"
? html`${this.label}${this.required ? "*" : ""}<ha-slider
const isBox = this.selector.number.mode === "box";
return html`
${this.label ? html`${this.label}${this.required ? " *" : ""}` : ""}
<div class="input">
${!isBox
? html`<ha-slider
.min=${this.selector.number.min}
.max=${this.selector.number.max}
.value=${this._value}
@@ -39,28 +45,33 @@ export class HaNumberSelector extends LitElement {
@change=${this._handleSliderChange}
>
</ha-slider>`
: ""}
<ha-textfield
inputMode="numeric"
pattern="[0-9]+([\\.][0-9]+)?"
.label=${this.selector.number.mode !== "box" ? undefined : this.label}
.placeholder=${this.placeholder}
class=${classMap({ single: this.selector.number.mode === "box" })}
.min=${this.selector.number.min}
.max=${this.selector.number.max}
.value=${this.value ?? ""}
.step=${this.selector.number.step ?? 1}
helperPersistent
.helper=${isBox ? this.helper : undefined}
.disabled=${this.disabled}
.required=${this.required}
.suffix=${this.selector.number.unit_of_measurement}
type="number"
autoValidate
?no-spinner=${this.selector.number.mode !== "box"}
@input=${this._handleInputChange}
>
</ha-textfield>
</div>
${!isBox && this.helper
? html`<ha-input-helper-text>${this.helper}</ha-input-helper-text>`
: ""}
<ha-textfield
inputMode="numeric"
pattern="[0-9]+([\\.][0-9]+)?"
.label=${this.selector.number.mode !== "box" ? undefined : this.label}
.placeholder=${this.placeholder}
class=${classMap({ single: this.selector.number.mode === "box" })}
.min=${this.selector.number.min}
.max=${this.selector.number.max}
.value=${this.value ?? ""}
.step=${this.selector.number.step ?? 1}
helperPersistent
.helper=${this.helper}
.disabled=${this.disabled}
.required=${this.required}
.suffix=${this.selector.number.unit_of_measurement}
type="number"
autoValidate
?no-spinner=${this.selector.number.mode !== "box"}
@input=${this._handleInputChange}
>
</ha-textfield>`;
`;
}
private get _value() {
@@ -92,10 +103,11 @@ export class HaNumberSelector extends LitElement {
static get styles(): CSSResultGroup {
return css`
:host {
.input {
display: flex;
justify-content: space-between;
align-items: center;
direction: ltr;
}
ha-slider {
flex: 1;
@@ -3,6 +3,7 @@ import { customElement, property } from "lit/decorators";
import { fireEvent } from "../../common/dom/fire_event";
import { HomeAssistant } from "../../types";
import "../ha-yaml-editor";
import "../ha-input-helper-text";
@customElement("ha-selector-object")
export class HaObjectSelector extends LitElement {
@@ -12,6 +13,8 @@ export class HaObjectSelector extends LitElement {
@property() public label?: string;
@property() public helper?: string;
@property() public placeholder?: string;
@property({ type: Boolean }) public disabled = false;
@@ -20,13 +23,17 @@ export class HaObjectSelector extends LitElement {
protected render() {
return html`<ha-yaml-editor
.hass=${this.hass}
.readonly=${this.disabled}
.required=${this.required}
.placeholder=${this.placeholder}
.defaultValue=${this.value}
@value-changed=${this._handleChange}
></ha-yaml-editor>`;
.hass=${this.hass}
.readonly=${this.disabled}
.label=${this.label}
.required=${this.required}
.placeholder=${this.placeholder}
.defaultValue=${this.value}
@value-changed=${this._handleChange}
></ha-yaml-editor>
${this.helper
? html`<ha-input-helper-text>${this.helper}</ha-input-helper-text>`
: ""} `;
}
private _handleChange(ev) {
@@ -58,6 +58,7 @@ export class HaSelectSelector extends LitElement {
`
)}
</div>
${this._renderHelper()}
`;
}
@@ -76,6 +77,7 @@ export class HaSelectSelector extends LitElement {
`
)}
</div>
${this._renderHelper()}
`;
}
@@ -107,6 +109,7 @@ export class HaSelectSelector extends LitElement {
item-label-path="label"
.hass=${this.hass}
.label=${this.label}
.helper=${this.helper}
.disabled=${this.disabled}
.required=${this.required && !value.length}
.value=${this._filter}
@@ -131,6 +134,7 @@ export class HaSelectSelector extends LitElement {
item-label-path="label"
.hass=${this.hass}
.label=${this.label}
.helper=${this.helper}
.disabled=${this.disabled}
.required=${this.required}
.items=${options}
@@ -161,6 +165,12 @@ export class HaSelectSelector extends LitElement {
`;
}
private _renderHelper() {
return this.helper
? html`<ha-input-helper-text>${this.helper}</ha-input-helper-text>`
: "";
}
private get _mode(): "list" | "dropdown" {
return (
this.selector.select.mode ||
@@ -26,6 +26,8 @@ export class HaTargetSelector extends SubscribeMixin(LitElement) {
@property() public label?: string;
@property() public helper?: string;
@state() private _entityPlaformLookup?: Record<string, string>;
@state() private _configEntries?: ConfigEntry[];
@@ -64,6 +66,7 @@ export class HaTargetSelector extends SubscribeMixin(LitElement) {
return html`<ha-target-picker
.hass=${this.hass}
.value=${this.value}
.helper=${this.helper}
.deviceFilter=${this._filterDevices}
.entityRegFilter=${this._filterRegEntities}
.entityFilter=${this._filterEntities}
@@ -0,0 +1,56 @@
import { html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import { fireEvent } from "../../common/dom/fire_event";
import { HomeAssistant } from "../../types";
import "../ha-code-editor";
import "../ha-input-helper-text";
@customElement("ha-selector-template")
export class HaTemplateSelector extends LitElement {
@property() public hass!: HomeAssistant;
@property() public value?: string;
@property() public label?: string;
@property() public helper?: string;
@property({ type: Boolean }) public disabled = false;
@property({ type: Boolean }) public required = true;
protected render() {
return html`
${this.label
? html`<p>${this.label}${this.required ? " *" : ""}</p>`
: ""}
<ha-code-editor
mode="jinja2"
.hass=${this.hass}
.value=${this.value}
.readOnly=${this.disabled}
autofocus
autocomplete-entities
@value-changed=${this._handleChange}
dir="ltr"
></ha-code-editor>
${this.helper
? html`<ha-input-helper-text>${this.helper}</ha-input-helper-text>`
: ""}
`;
}
private _handleChange(ev) {
const value = ev.target.value;
if (this.value === value) {
return;
}
fireEvent(this, "value-changed", { value });
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-selector-template": HaTemplateSelector;
}
}
@@ -14,6 +14,8 @@ export class HaTimeSelector extends LitElement {
@property() public label?: string;
@property() public helper?: string;
@property({ type: Boolean }) public disabled = false;
@property({ type: Boolean }) public required = false;
@@ -25,6 +27,7 @@ export class HaTimeSelector extends LitElement {
.locale=${this.hass.locale}
.disabled=${this.disabled}
.required=${this.required}
.helper=${this.helper}
.label=${this.label}
enable-second
></ha-time-input>
@@ -18,6 +18,7 @@ import "./ha-selector-number";
import "./ha-selector-object";
import "./ha-selector-select";
import "./ha-selector-target";
import "./ha-selector-template";
import "./ha-selector-text";
import "./ha-selector-time";
import "./ha-selector-icon";
+1
View File
@@ -472,6 +472,7 @@ export class HaServiceControl extends LitElement {
ha-settings-row {
--paper-time-input-justify-content: flex-end;
--settings-row-content-width: 100%;
--settings-row-prefix-display: contents;
border-top: var(
--service-control-items-border-top,
1px solid var(--divider-color)
+2 -2
View File
@@ -47,7 +47,7 @@ export class HaSettingsRow extends LitElement {
display: contents;
}
:host(:not([narrow])) .content {
display: flex;
display: var(--settings-row-content-display, flex);
justify-content: flex-end;
flex: 1;
padding: 16px 0;
@@ -68,7 +68,7 @@ export class HaSettingsRow extends LitElement {
white-space: normal;
}
.prefix-wrap {
display: contents;
display: var(--settings-row-prefix-display);
}
:host([narrow]) .prefix-wrap {
display: flex;
+20 -16
View File
@@ -36,10 +36,9 @@ import memoizeOne from "memoize-one";
import { LocalStorage } from "../common/decorators/local-storage";
import { fireEvent } from "../common/dom/fire_event";
import { toggleAttribute } from "../common/dom/toggle_attribute";
import { computeDomain } from "../common/entity/compute_domain";
import { computeStateDomain } from "../common/entity/compute_state_domain";
import { stringCompare } from "../common/string/compare";
import { computeRTL } from "../common/util/compute_rtl";
import { throttle } from "../common/util/throttle";
import { ActionHandlerDetail } from "../data/lovelace";
import {
PersistentNotification,
@@ -294,11 +293,7 @@ class HaSidebar extends LitElement {
toggleAttribute(this, "rtl", computeRTL(this.hass));
}
this._updatesCount = Object.values(this.hass.states).filter(
(entity) =>
computeStateDomain(entity) === "update" &&
updateCanInstall(entity as UpdateEntity)
).length;
this._calculateCounts();
if (!SUPPORT_SCROLL_IF_NEEDED) {
return;
@@ -312,6 +307,21 @@ class HaSidebar extends LitElement {
}
}
private _calculateCounts = throttle(() => {
let updateCount = 0;
for (const entityId of Object.keys(this.hass.states)) {
if (
entityId.startsWith("update.") &&
updateCanInstall(this.hass.states[entityId] as UpdateEntity)
) {
updateCount++;
}
}
this._updatesCount = updateCount;
}, 5000);
private _renderHeader() {
return html`<div
class="menu"
@@ -519,14 +529,9 @@ class HaSidebar extends LitElement {
}
private _renderNotifications() {
let notificationCount = this._notifications
const notificationCount = this._notifications
? this._notifications.length
: 0;
for (const entityId in this.hass.states) {
if (computeDomain(entityId) === "configurator") {
notificationCount++;
}
}
return html`<div
class="notifications-container"
@@ -1034,6 +1039,8 @@ class HaSidebar extends LitElement {
.notification-badge,
.configuration-badge {
left: calc(var(--app-drawer-width) - 42px);
position: absolute;
min-width: 20px;
box-sizing: border-box;
border-radius: 50%;
@@ -1044,9 +1051,6 @@ class HaSidebar extends LitElement {
padding: 0px 6px;
color: var(--text-accent-color, var(--text-primary-color));
}
.configuration-badge {
background-color: var(--primary-color);
}
ha-svg-icon + .notification-badge,
ha-svg-icon + .configuration-badge {
position: absolute;
+12 -1
View File
@@ -43,6 +43,7 @@ import type { HaEntityPickerEntityFilterFunc } from "./entity/ha-entity-picker";
import "./ha-area-picker";
import "./ha-icon-button";
import "./ha-svg-icon";
import "./ha-input-helper-text";
@customElement("ha-target-picker")
export class HaTargetPicker extends SubscribeMixin(LitElement) {
@@ -52,6 +53,8 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
@property() public label?: string;
@property() public helper?: string;
/**
* Show only targets with entities from specific domains.
* @type {Array}
@@ -213,7 +216,11 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
</span>
</span>
</div>
</div>`;
</div>
${this.helper
? html`<ha-input-helper-text>${this.helper}</ha-input-helper-text>`
: ""} `;
}
private async _showPicker(ev) {
@@ -609,6 +616,10 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
opacity: var(--light-disabled-opacity);
pointer-events: none;
}
:host-context([style*="direction: rtl;"]) .mdc-chip__icon {
margin-right: -14px !important;
margin-left: 4px !important;
}
`;
}
}
+13
View File
@@ -91,6 +91,19 @@ export class HaTextField extends TextFieldBase {
.mdc-text-field {
overflow: var(--text-field-overflow);
}
:host-context([style*="direction: rtl;"]) .mdc-floating-label {
right: 10px !important;
left: initial !important;
}
:host-context([style*="direction: rtl;"])
.mdc-text-field--with-leading-icon.mdc-text-field--filled
.mdc-floating-label {
max-width: calc(100% - 48px);
right: 48px !important;
left: initial !important;
}
`,
];
}

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