Compare commits

...
Author SHA1 Message Date
Bram Kragten 539472bd96 POC 2024-01-19 11:03:37 +01:00
Steve RepsherandGitHub 6234f7b7d2 Initialize boolean properties (#19445) 2024-01-18 16:39:33 +01:00
Paul BotteinandGitHub 04f6a01c3d Avoid thermostat card interaction on scroll on touch devices (#19423)
* Avoid thermostat card interaction on scroll on touch devices

* Fix background interaction on safari

* Fix interaction in Safari

* Make listeners private
2024-01-18 14:31:44 +01:00
Steve RepsherandGitHub 9bad3c8101 Lint for unknown tags and turn off unknow attribute check (#19439) 2024-01-18 14:30:59 +01:00
7398c6ab3e Automation nested drag and drop (#19338)
* Add nested drag and drop for actions

* Add nested drag and drop for triggers, conditions and options

* Update src/panels/config/automation/action/types/ha-automation-action-choose.ts

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

* Move object at the root level

* Add support for choose option

* Fix undefined container (e.g else action)

* Add common nested array move function

* Move item at root level for manual automation

* Fix array move

* Don't fallback on body

* migrate blueprint and script

* Add drag and drop to service control

* Use context for reorder mode

* Rename reorder mode functions

* Fix hide menu props

* Fix drag and drop for choose action

---------

Co-authored-by: Bram Kragten <[email protected]>
2024-01-18 14:26:17 +01:00
Steve RepsherandGitHub 4046534fa8 Compress static HTML/XML (#19437) 2024-01-17 17:58:32 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
8f43caee2e Update dependency @types/luxon to v3.4.1 (#19438)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-17 17:57:31 -05:00
karwostsandGitHub 83c5408f8f Minor form localizations (#19434)
* Minor form localizations

* missing imports
2024-01-17 14:40:58 -05:00
karwostsandGitHub 7d4284d409 Custom device_classes for Area Card sensors (#19421)
* Custom device_classes for Area Card sensors

* no sensor DOMAIN_ICONS
2024-01-17 13:22:08 +01:00
Steve RepsherandGitHub 58c4bf081b Fix boolean and nullable attribute bindings (#19432) 2024-01-17 12:45:21 +01:00
d1478567f0 Add title to grid card editor (#19429)
* Add title to grid card editor

* Update src/panels/lovelace/editor/config-elements/hui-grid-card-editor.ts

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

---------

Co-authored-by: Bram Kragten <[email protected]>
2024-01-17 12:43:25 +01:00
Paulus SchoutsenandGitHub d85c729fa5 Add a download button to history panel (#19428) 2024-01-17 11:47:45 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
c65fadbd8a Update dependency sortablejs to v1.15.2 (#19426)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-16 23:47:21 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
4326007022 Update dependency prettier to v3.2.2 (#19431)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-17 04:41:16 +00:00
Paulus Schoutsen 38b01e9335 Add a download button to history panel 2024-01-16 21:35:07 -05:00
karwostsandGitHub 22625a805d Don't show duplicates in statistics picker (#19422)
* Filter duplicates from ha-statistics-picker

* use repeat
2024-01-16 22:40:27 +01:00
karwostsandGitHub a06c9d0cc6 Localize show_password in auth form (#19300)
* Localize show_password in auth form

* changes from review
2024-01-16 22:39:35 +01:00
Paul BotteinandGitHub 490ed86e86 Add per domain style for tile card image (#19419) 2024-01-16 15:04:18 +01:00
Paul BotteinandGitHub df2514d79f Use new mdi oscillating icon (#19410) 2024-01-16 15:02:27 +01:00
Matthew GroveandGitHub 13a8b10f5c Fix incorrect padding on bottom of empty list (#19414) 2024-01-16 15:02:06 +01:00
Steve RepsherandGitHub bb4f09ad9a Fix missing imports (2 of 2) (#19417) 2024-01-16 15:01:34 +01:00
Bram KragtenandGitHub 1f2683dd56 Restrict adding todo list and calendars to admin users (#19408) 2024-01-16 10:44:28 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
0ba8babd87 Update dependency prettier to v3.2.1 (#19415)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-15 22:00:08 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
65d4d44f06 Update dependency @codemirror/autocomplete to v6.12.0 (#19412)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-15 16:52:48 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>Steve Repsher
6f8c366bad Update dependency prettier to v3.2.0 (#19411)
* Update dependency prettier to v3.2.0

* Reformat

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Steve Repsher <[email protected]>
2024-01-15 16:49:22 -05:00
3842e8e3a7 Wrap descriptions in automation list descriptions (#19367)
* Wrapped automation descriptions

* Fix

* Fixes

---------

Co-authored-by: Bram Kragten <[email protected]>
2024-01-15 14:59:46 +00:00
Steve RepsherandGitHub b881a2a88a Fix complex attribute and expressionless property bindings (#19348) 2024-01-15 15:52:48 +01:00
Steve RepsherandGitHub 70fcea0c2b Disable attributes for hass, stateObj, selector, and route properties (#19362)
* Disable attribute for hass properties

* Disable attribute for stateObj properties

* Disable attribute for selector properties

* Disable attribute for route properties

* Switch from Object type to no attribute for same properties
2024-01-15 15:52:10 +01:00
9f26bedf51 Custom device_classes for alert icons in Area Card (#19131)
* Custom device_classes for alerts in Area Card

* small refactor

* drop more-info feature

* Update src/panels/lovelace/editor/config-elements/hui-area-card-editor.ts

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

* localization and css updates

---------

Co-authored-by: Bram Kragten <[email protected]>
2024-01-15 15:51:19 +01:00
Simon LamonandGitHub 2053cf23c2 Replace some paper-items by list-item (#19314)
* system log card

* cloud login

* cloud account

* ha config voice assistants assistants

* ha config person

* ha-device-entities-card

* cloud login

* change --paper-item-icon-color into --state-icon-color

* Apply code review

* Revert "change --paper-item-icon-color into --state-icon-color"

This reverts commit b91ef0017e.

* Remove unneeded mwc-lists
2024-01-15 15:41:05 +01:00
Steve RepsherandGitHub b801441201 Fix property visibility mismatches (1 of 2) (#19376) 2024-01-15 15:40:03 +01:00
AlexandrErohinandGitHub 7209ed055a fix not showing base error bug (#19340) 2024-01-15 14:38:51 +00:00
Joakim PlateandGitHub 894205eff7 Display that entity is disabled in more info (#19378)
* Display that entity is disabled in more info

* Correct formatting
2024-01-15 15:37:59 +01:00
Steve RepsherandGitHub 64b0b64468 Cache Typescript runs for faster checks (#19381) 2024-01-15 15:36:26 +01:00
Steve RepsherandGitHub 920df03cc1 Fix missing imports (1 of 2) (#19363) 2024-01-15 15:34:46 +01:00
karwostsandGitHub 5a91f613ca Remove fire-dom-event from action struct (#19390) 2024-01-15 15:34:19 +01:00
karwostsandGitHub 61eaa07b25 Honor display_precision over duration-type format (#19396) 2024-01-15 15:33:00 +01:00
Cody CandGitHub 62f6766e1b Fix onboarding state exception following restore (#19389)
Fixes #19388
2024-01-15 15:31:37 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
f5994d2ae5 Update vaadinWebComponents monorepo to v24.3.3 (#19403)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-15 14:12:11 +01:00
Yosi LevyandGitHub 7e93367394 RTL stack card fix (#19394) 2024-01-15 13:55:11 +01:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
6256192c0c Bump actions/upload-artifact from 3.1.3 to 4.1.0 (#19401)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-15 09:20:26 +01:00
dependabot[bot]andGitHub 08fb3ced5f Bump actions/cache from 3.3.2 to 3.3.3 (#19400) 2024-01-15 07:56:19 +01:00
karwostsandGitHub 5aa5ce8b5e Fix blank_before_percent (#19397)
* Fix blank_before_percent

* types n stuff
2024-01-14 15:23:42 -05:00
Steve RepsherandGitHub 7c389a6cf0 Fix dependencies labeler (#19391) 2024-01-14 09:32:28 +01:00
renovate[bot]andGitHub f63ba0c20a Update dependency hls.js to v1.5.1 (#19387) 2024-01-13 22:36:10 -05:00
Simon LamonandGitHub 01e80108d7 Fix nightly builds (#19386) 2024-01-13 17:30:47 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
148c0c98d3 Update dependency hls.js to v1.5.0 (#19377)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-13 14:39:08 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
11a9a2f56b Update dependency @lit-labs/virtualizer to v2.0.12 (#19380)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-13 14:38:05 -05:00
Bram Kragten 6cdf1c1689 Bumped version to 20240112.0 2024-01-12 16:25:34 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2cfaa4f261 Update typescript-eslint monorepo to v6.18.1 (#19371)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-12 05:11:37 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
d3b0d03e70 Update dependency lit-analyzer to v2.0.3 (#19369)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-11 23:59:13 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
08b8978ee8 Update dependency ts-lit-plugin to v2.0.2 (#19370)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-11 23:57:25 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>Steve Repsher
d2019c2315 Update babel monorepo to v7.23.8 (#19368)
* Update babel monorepo to v7.23.8

* bump @babel/helpers

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Steve Repsher <[email protected]>
2024-01-11 23:52:37 -05:00
Bram KragtenandGitHub 02a7d0e797 Clean up local auth flow, preselect remember me (#19354) 2024-01-11 11:03:32 +01:00
Bram KragtenandGitHub 03751d2581 Load registries in core, wait them to be loaded before generating das… (#19356)
* load registries in core, wait them to be loaded before generating dashboard

* import

* improve

* Split out subscribe functions
2024-01-11 09:48:20 +01:00
Bram KragtenandGitHub b9069b25ad Assist devices: Move logic from column to data (#19359)
* Move logic from column to data

* Type
2024-01-11 09:48:10 +01:00
Paulus SchoutsenandGitHub a136fa687f Add page to list assist devices (#19301)
* Add page to list assist devices

* Translate title too
2024-01-10 15:22:59 +01:00
Bram Kragten de35e89c58 Update ha-config-logs.ts 2024-01-10 15:21:54 +01:00
Bram KragtenandGitHub 85beefec4c Fix logs, dont require advanced mode, allow provider in url and my (#19355)
* Fix logs, dont require advanced mode, allow provider in url and my

* Add params to my link with quick key `m`
2024-01-10 13:50:07 +01:00
renovate[bot]andGitHub 877c9b007b Update dependency open to v10.0.3 (#19351) 2024-01-10 07:33:15 -05:00
Steve RepsherandGitHub adb851a2b4 Fix unclosed HTML tags (#19343)
* Fix unclosed HTML tags

* Add missing import and remove unused class for debug tools

* Remove div from debug page
2024-01-10 10:53:03 +01:00
Steve RepsherandGitHub 6ab5116c34 Fix incompatible number property types (#19349) 2024-01-10 10:49:35 +01:00
Paul BotteinandGitHub a5630a4a7d Use switch for valve in entity row (#19342) 2024-01-09 16:15:33 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
e8c1a34f3b Update typescript-eslint monorepo to v6.18.0 (#19341)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-09 15:20:51 +01:00
Steve RepsherandGitHub 88abeada44 Remove Intl polyfill on connection and consistently resolve time zone (#19326) 2024-01-09 15:06:50 +01:00
Steve RepsherandGitHub 96a41704ea Fix incompatible boolean property types (#19337) 2024-01-09 15:02:15 +01:00
Steve RepsherandGitHub 8583c879f2 Fix invalid directive bindings (#19330) 2024-01-09 15:00:59 +01:00
Steve RepsherandGitHub 3edc77c978 Fix missing element tag definitions (#19329) 2024-01-09 15:00:30 +01:00
dependabot[bot]andGitHub 03a1c21f34 Bump follow-redirects from 1.15.3 to 1.15.4 (#19336) 2024-01-08 21:14:38 -05:00
renovate[bot]andGitHub 80b1a6297b Update dependency @types/luxon to v3.4.0 (#19333) 2024-01-08 20:57:22 -05:00
renovate[bot]andGitHub 056eb888f3 Update dependency @types/chromecast-caf-receiver to v6.0.13 (#19332) 2024-01-08 20:56:32 -05:00
Steve RepsherandGitHub d4ec608123 Fix invalid media queries in calendar and todo editors (#19295) 2024-01-08 15:45:24 +01:00
Steve RepsherandGitHub 2451cf77f9 Fix various missing component imports (#19296) 2024-01-08 15:43:53 +01:00
Simon LamonandGitHub 3b6b77c75b Localize time pattern trigger in automation editor (#19173) 2024-01-08 15:24:37 +01:00
Steve RepsherandGitHub e0f578c135 Start linting with lit-analyzer (#19302) 2024-01-08 14:26:25 +01:00
karwostsandGitHub ec2ae15e3f Cleanup else/default block when deleting all actions (#19298) 2024-01-08 14:10:23 +01:00
Steve RepsherandGitHub f5fc66f47e Better restrict applying dependencies label (#19319) 2024-01-08 14:08:21 +01:00
Steve RepsherandGitHub ae79df8c55 Allow TLA for legacy build and remove static Intl polyfills (#19207) 2024-01-08 14:07:08 +01:00
Paul BotteinandGitHub 104aef3dec Add ha-sortable component (#19294) 2024-01-08 14:02:41 +01:00
dependabot[bot]andGitHub 17e62c10d4 Bump home-assistant/wheels from 2023.10.5 to 2024.01.0 (#19321) 2024-01-08 08:17:13 +01:00
karwostsandGitHub 90965a4f4d Localize statistics datatable string (#19289) 2024-01-06 23:19:44 -05:00
renovate[bot]andGitHub 8960f5fef9 Update dependency @types/luxon to v3.3.8 (#19308) 2024-01-06 20:50:10 -05:00
Yosi LevyandGitHub 783a8242e1 Fix for RTL in Supervisor dashboards (#19290) 2024-01-05 14:56:15 +01:00
Simon LamonandGitHub 7a8f5c0cc9 Replace remaining paper inputs (#19292) 2024-01-05 14:31:58 +01:00
renovate[bot]andGitHub 53be012b34 Update CodeMirror (#19214) 2024-01-04 20:42:11 -05:00
renovate[bot]andGitHub be7b3a56f9 Update dependency core-js to v3.35.0 (#19215) 2024-01-04 20:36:13 -05:00
renovate[bot]andGitHub 554e5b7be5 Update typescript-eslint monorepo to v6.17.0 (#19286) 2024-01-04 19:48:57 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
249c89669e Update dependency systemjs to v6.14.3 (#19282)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-04 13:11:06 -05:00
Bram Kragten fe5431976d Bumped version to 20240104.0 2024-01-04 17:43:37 +01:00
Paul BotteinandGitHub 72dedc7596 Fix thermostat and humidifier card rendering when off (#19281)
* Fix thermostat and humidifier card rendering when off

* Fix action color
2024-01-04 16:18:16 +01:00
Bram KragtenandGitHub 8615b799c6 Fix due date when no time in certain timezones (#19280)
* Fix due date when no time in certain timezones

* Update dialog-todo-item-editor.ts
2024-01-04 14:24:33 +01:00
Bram KragtenandGitHub fd6cae48b7 Remove overflow hidden from profile (#19279) 2024-01-04 13:20:35 +01:00
Bram KragtenandGitHub ecadc06b45 fix valve entities row (#19278) 2024-01-04 11:52:38 +01:00
Franck NijhofandGitHub e5d31d85dd Update getStates to support valves (#19277) 2024-01-04 10:54:20 +01:00
Bram KragtenandGitHub e427ffca5f Fix turning valve on/off (#19269) 2024-01-03 21:27:30 -05:00
Bram KragtenandGitHub 4f05bd9e22 Fix circular progress size + fix bug in assist pipeline debug (#19268) 2024-01-03 21:21:42 -05:00
renovate[bot]andGitHub 0d8c0ac1a0 Update dependency marked to v11.1.1 (#19254) 2024-01-03 17:45:46 -05:00
karwostsandGitHub 3984702d3e Fix select view dialog (#19267)
* Fix select view dialog

* add import
2024-01-03 20:36:59 +01:00
Bram KragtenandGitHub 979085a9de Fix supervisor dev build (#19266) 2024-01-03 20:35:54 +01:00
Bram KragtenandGitHub 7a6fc573c2 Fix version bump script (#19264) 2024-01-03 14:19:30 +00:00
Bram Kragten 6929a9c603 Bumped version to 20240103.0 2024-01-03 14:59:45 +01:00
41bb677ebe Remove tile pointer/ripple/index when it has no action (#19137)
* Remove tile pointer/ripple/index when it has no action

* update

* Apply suggestions from code review

Co-authored-by: Paul Bottein <[email protected]>

---------

Co-authored-by: Paul Bottein <[email protected]>
2024-01-03 14:58:59 +01:00
Bram KragtenandGitHub 8368fb4408 Fix checking todo item that dont support due date (#19262)
* Fix checking todo item that dont support due date

* make cleaner

* Revert "make cleaner"

This reverts commit fa33b33614.

* Update dialog-todo-item-editor.ts

* do check in 1 place
2024-01-03 13:58:36 +00:00
Paul BotteinandGitHub acbb7e0453 Display edit button for climate fan mode feature (#19259) 2024-01-03 14:26:40 +01:00
Bram Kragten 6224cb6994 Bumped version to 20240103.1 2024-01-03 12:28:46 +01:00
Bram KragtenandGitHub 29fefa1d60 Revert conditional rendering of condition (#19257)
* Fix conditionally showing `triggered by`

* revert conditional rendering

* Update add-automation-element-dialog.ts

* Update add-automation-element-dialog.ts
2024-01-03 11:20:11 +00:00
Bram Kragten c7a98fa5a1 Bumped version to 20240103.0 2024-01-03 10:37:59 +01:00
Bram KragtenandGitHub 46565715c9 Calculate used domains on open of action dialog (#19255) 2024-01-03 10:37:30 +01:00
Simon LamonandGitHub 8a8b04ed00 Set default values for required and disabled for labeled slider (#19246)
Set default values
2024-01-02 20:00:19 +01:00
Bram KragtenandGitHub e721481757 Move notification services to main list (#19235) 2024-01-02 19:58:37 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2933d642ed Update dependency @bundle-stats/plugin-webpack-filter to v4.8.4 (#19230)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-02 13:55:44 -05:00
Bram Kragten 7d412a9913 Bumped version to 20240102.0 2024-01-02 18:49:31 +01:00
Bram KragtenandGitHub 5eaa6dafd9 Give todo and calendar edit static header (#19233) 2024-01-02 18:48:34 +01:00
Bram Kragten f994b378f1 Update add-automation-element-dialog.ts 2024-01-02 18:47:39 +01:00
JLoandGitHub 7d6dfaad15 New copy for device trigger in automation editor (#19232)
New copy for device trigger in automation editor: 
"Set of conditions provided by your device. Great way to start."
2024-01-02 17:39:55 +00:00
Josh McCartyandGitHub def2eadc24 Add missing device classes for entity-registry-settings-editor (#19231)
* Add connectivity device class for binary sensors

* Add update device class

* Separate connectivity and update
2024-01-02 17:35:08 +00:00
Bram KragtenandGitHub 53a25dde26 Change format of service description (#19229) 2024-01-02 18:31:18 +01:00
Bram KragtenandGitHub 6f7da16d1d Use brand icons in actions (#19227) 2024-01-02 18:11:34 +01:00
Bram KragtenandGitHub 5ac0360494 Remove references to "service call" from actions (#19226) 2024-01-02 16:08:26 +01:00
karwostsandGitHub 1b6def4875 Localize a device action string (#19203) 2024-01-02 14:07:34 +01:00
Bram KragtenandGitHub 52fcf64cfd Automation editor tweaks (#19225)
* Automation editor tweaks

* fix styling
2024-01-02 13:36:06 +01:00
JLoandGitHub c650e23432 Review on automation editor text (#19223)
- Added `.` to bloc descriptions
- Changed "Other" into "OTher triggers" "Other conditions" and "Other actions"
- Adapted a few descriptions
2024-01-02 11:08:05 +00:00
renovate[bot]andGitHub 428604d91d Update babel monorepo to v7.23.7 (#19220) 2024-01-01 20:15:34 -05:00
Bram Kragten d0c1481f76 Bumped version to 20240101.0 2024-01-01 13:58:47 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
6cc9a99b77 Update dependency terser-webpack-plugin to v5.3.10 (#19211)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-31 13:47:55 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
d25f49b694 Update dependency chai to v5 (#19208)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-31 13:46:23 -05:00
renovate[bot]andGitHub b92d25e28a Update Material Design Icons to v7.4.47 (#19192) 2023-12-30 21:08:13 -05:00
renovate[bot]andGitHub bf5c5bc46f Update dependency open to v10.0.2 (#19206) 2023-12-30 21:06:30 -05:00
renovate[bot]andGitHub e7cc842be4 Update dependency rollup-plugin-visualizer to v5.12.0 (#19204) 2023-12-30 21:05:23 -05:00
Bram KragtenandGitHub cb29d35949 Allow to clear due date (#19201) 2023-12-30 20:21:33 +01:00
Bram KragtenandGitHub fe18f70e51 Only make count field template (#19198) 2023-12-30 18:40:01 +01:00
Bram KragtenandGitHub ee57f26415 Sort domains correctly, scroll to top on back (#19197) 2023-12-30 18:39:21 +01:00
karwostsandGitHub 721ec8e559 Localize some strings in integration panel (#19200) 2023-12-30 18:37:50 +01:00
c584f83071 Fix display of variables tab when automation step not executed (#19186)
Co-authored-by: Bram Kragten <[email protected]>
2023-12-30 17:16:54 +00:00
Erik MontnemeryandGitHub 3c2fed5041 Improve message when an automation step was not executed (#19185)
* Improve message when an automation step was not executed

* Use step instead of node
2023-12-30 18:08:24 +01:00
Erik MontnemeryandGitHub 7e6d974438 Fix iteration index when displaying changed variables (#19184) 2023-12-30 14:08:01 +01:00
494 changed files with 6011 additions and 4697 deletions
+14 -8
View File
@@ -24,14 +24,20 @@ Design:
- src/fake_data/**
Dependencies:
- changed-files:
- any-glob-to-any-file:
- package.json
- renovate.json
- yarn.lock
- .yarn/**
- .yarnrc.yml
- .nvmrc
- any:
- changed-files:
# Match when only these files are changed (i.e. don't match PRs that happen to add or remove packages)
- any-glob-to-all-files:
- package.json
- renovate.json
- yarn.lock
- .yarn/**
- .yarnrc.yml
- .nvmrc
# Dependabot and Renovate branches always match (i.e. compatibility tweaks by members considered minor)
- head-branch:
- "^renovate/"
- "^dependabot/"
GitHub Actions:
- changed-files:
+6 -3
View File
@@ -37,17 +37,20 @@ jobs:
- name: Build resources
run: ./node_modules/.bin/gulp gen-icons-json build-translations build-locale-data gather-gallery-pages
- name: Setup lint cache
uses: actions/[email protected].2
uses: actions/[email protected].3
with:
path: |
node_modules/.cache/prettier
node_modules/.cache/eslint
node_modules/.cache/typescript
key: lint-${{ github.sha }}
restore-keys: lint-
- name: Run eslint
run: yarn run lint:eslint --quiet
- name: Run tsc
run: yarn run lint:types
- name: Run lit-analyzer
run: yarn run lint:lit --quiet
- name: Run prettier
run: yarn run lint:prettier
test:
@@ -86,7 +89,7 @@ jobs:
env:
IS_TEST: "true"
- name: Upload bundle stats
uses: actions/upload-artifact@v3.1.3
uses: actions/upload-artifact@v4.1.0
with:
name: frontend-bundle-stats
path: build/stats/*.json
@@ -110,7 +113,7 @@ jobs:
env:
IS_TEST: "true"
- name: Upload bundle stats
uses: actions/upload-artifact@v3.1.3
uses: actions/upload-artifact@v4.1.0
with:
name: supervisor-bundle-stats
path: build/stats/*.json
+3 -3
View File
@@ -42,7 +42,7 @@ jobs:
LOKALISE_TOKEN: ${{ secrets.LOKALISE_TOKEN }}
- name: Bump version
run: script/version_bump.cjs nightly
run: script/version_bump.js nightly
- name: Build nightly Python wheels
run: |
@@ -57,14 +57,14 @@ jobs:
run: tar -czvf translations.tar.gz translations
- name: Upload build artifacts
uses: actions/upload-artifact@v3.1.3
uses: actions/upload-artifact@v4.1.0
with:
name: wheels
path: dist/home_assistant_frontend*.whl
if-no-files-found: error
- name: Upload translations
uses: actions/upload-artifact@v3.1.3
uses: actions/upload-artifact@v4.1.0
with:
name: translations
path: translations.tar.gz
+1 -1
View File
@@ -74,7 +74,7 @@ jobs:
echo "home-assistant-frontend==$version" > ./requirements.txt
- name: Build wheels
uses: home-assistant/wheels@2023.10.5
uses: home-assistant/wheels@2024.01.0
with:
abi: cp311
tag: musllinux_1_2
+4 -1
View File
@@ -8,7 +8,10 @@ const zopfliOptions = { threshold: 150 };
const compressDist = (rootDir) =>
gulp
.src([`${rootDir}/**/*.{js,json,css,svg}`])
.src([
`${rootDir}/**/*.{js,json,css,svg,xml}`,
`${rootDir}/{authorize,onboarding}.html`,
])
.pipe(zopfli(zopfliOptions))
.pipe(gulp.dest(rootDir));
+1
View File
@@ -426,6 +426,7 @@ gulp.task(
"fetch-nightly-translations",
gulp.series("clean-translations", "ensure-translations-build-dir")
),
gulp.parallel("create-test-metadata", "create-test-translation"),
"build-master-translation",
"build-merged-translations",
"build-translation-fragment-supervisor",
+5 -11
View File
@@ -7,6 +7,9 @@ const TerserPlugin = require("terser-webpack-plugin");
const { WebpackManifestPlugin } = require("webpack-manifest-plugin");
const log = require("fancy-log");
const WebpackBar = require("webpackbar");
const {
TransformAsyncModulesPlugin,
} = require("transform-async-modules-webpack-plugin");
const paths = require("./paths.cjs");
const bundle = require("./bundle.cjs");
@@ -142,17 +145,6 @@ const createWebpackConfig = ({
),
path.resolve(paths.polymer_dir, "src/util/empty.js")
),
// See `src/resources/intl-polyfill-legacy.ts` for explanation
!latestBuild &&
new webpack.NormalModuleReplacementPlugin(
new RegExp(
path.resolve(paths.polymer_dir, "src/resources/intl-polyfill.ts")
),
path.resolve(
paths.polymer_dir,
"src/resources/intl-polyfill-legacy.ts"
)
),
!isProdBuild && new LogStartCompilePlugin(),
isProdBuild &&
new StatsWriterPlugin({
@@ -163,6 +155,8 @@ const createWebpackConfig = ({
stats: { assets: true, chunks: true, modules: true },
transform: (stats) => JSON.stringify(filterStats(stats)),
}),
!latestBuild &&
new TransformAsyncModulesPlugin({ browserslistEnv: "legacy" }),
].filter(Boolean),
resolve: {
extensions: [".ts", ".js", ".json"],
@@ -11,7 +11,7 @@ class DemoBlackWhiteRow extends LitElement {
@property() value!: any;
@property() disabled = false;
@property({ type: Boolean }) public disabled = false;
protected render(): TemplateResult {
return html`
+2 -2
View File
@@ -11,11 +11,11 @@ export interface DemoCardConfig {
@customElement("demo-card")
class DemoCard extends LitElement {
@property() public hass!: HomeAssistant;
@property({ attribute: false }) public hass!: HomeAssistant;
@property() public config!: DemoCardConfig;
@property() public showConfig = false;
@property({ type: Boolean }) public showConfig = false;
@state() private _size?: number;
+1 -1
View File
@@ -12,7 +12,7 @@ import "../ha-demo-options";
class DemoCards extends LitElement {
@property() public configs!: DemoCardConfig[];
@property() public hass!: HomeAssistant;
@property({ attribute: false }) public hass!: HomeAssistant;
@state() private _showConfig = false;
+2 -2
View File
@@ -8,11 +8,11 @@ import { HomeAssistant } from "../../../src/types";
@customElement("demo-more-info")
class DemoMoreInfo extends LitElement {
@property() public hass!: HomeAssistant;
@property({ attribute: false }) public hass!: HomeAssistant;
@property() public entityId!: string;
@property() public showConfig!: boolean;
@property({ type: Boolean }) public showConfig = false;
render() {
const state = this._getState(this.entityId, this.hass.states);
+1 -1
View File
@@ -9,7 +9,7 @@ import { HomeAssistant } from "../../../src/types";
@customElement("demo-more-infos")
class DemoMoreInfos extends LitElement {
@property() public hass!: HomeAssistant;
@property({ attribute: false }) public hass!: HomeAssistant;
@property() public entities!: [];
+6 -6
View File
@@ -1,14 +1,14 @@
import { mdiMenu } from "@mdi/js";
import "@material/mwc-drawer";
import "@material/mwc-top-app-bar-fixed";
import { html, css, LitElement, PropertyValues } from "lit";
import { customElement, property, query } from "lit/decorators";
import { mdiMenu } from "@mdi/js";
import { LitElement, PropertyValues, css, html } from "lit";
import { customElement, query, state } from "lit/decorators";
import { dynamicElement } from "../../src/common/dom/dynamic-element-directive";
import { HaExpansionPanel } from "../../src/components/ha-expansion-panel";
import "../../src/components/ha-icon-button";
import "../../src/managers/notification-manager";
import { HaExpansionPanel } from "../../src/components/ha-expansion-panel";
import { haStyle } from "../../src/resources/styles";
import { PAGES, SIDEBAR } from "../build/import-pages";
import { dynamicElement } from "../../src/common/dom/dynamic-element-directive";
import "./components/page-description";
const GITHUB_DEMO_URL =
@@ -24,7 +24,7 @@ const FAKE_HASS = {
@customElement("ha-gallery")
class HaGallery extends LitElement {
@property() private _page =
@state() private _page =
document.location.hash.substring(1) ||
`${SIDEBAR[0].category}/${SIDEBAR[0].pages![0]}`;
@@ -80,7 +80,7 @@ const SCHEMAS: { name: string; conditions: ConditionWithShorthand[] }[] = [
];
@customElement("demo-automation-editor-condition")
class DemoHaAutomationEditorCondition extends LitElement {
export class DemoAutomationEditorCondition extends LitElement {
@state() private hass!: HomeAssistant;
@state() private _disabled = false;
@@ -155,6 +155,6 @@ class DemoHaAutomationEditorCondition extends LitElement {
declare global {
interface HTMLElementTagNameMap {
"demo-ha-automation-editor-condition": DemoHaAutomationEditorCondition;
"demo-automation-editor-condition": DemoAutomationEditorCondition;
}
}
@@ -126,7 +126,7 @@ const SCHEMAS: { name: string; triggers: Trigger[] }[] = [
];
@customElement("demo-automation-editor-trigger")
class DemoHaAutomationEditorTrigger extends LitElement {
export class DemoAutomationEditorTrigger extends LitElement {
@state() private hass!: HomeAssistant;
@state() private _disabled = false;
@@ -201,6 +201,6 @@ class DemoHaAutomationEditorTrigger extends LitElement {
declare global {
interface HTMLElementTagNameMap {
"demo-ha-automation-editor-trigger": DemoHaAutomationEditorTrigger;
"demo-automation-editor-trigger": DemoAutomationEditorTrigger;
}
}
@@ -59,7 +59,7 @@ export class DemoHaBarButton extends LitElement {
<ha-control-button
class=${ifDefined(btn.class)}
label=${ifDefined(btn.label)}
disabled=${ifDefined(btn.disabled)}
?disabled=${btn.disabled}
>
<ha-svg-icon .path=${btn.icon || mdiLightbulb}></ha-svg-icon>
</ha-control-button>
@@ -135,7 +135,7 @@ export class DemoHaControlSelect extends LitElement {
class=${ifDefined(config.class)}
@value-changed=${this.handleValueChanged}
aria-labelledby=${id}
disabled=${ifDefined(config.disabled)}
?disabled=${config.disabled}
>
</ha-control-select>
</div>
@@ -156,7 +156,7 @@ export class DemoHaControlSelect extends LitElement {
class=${ifDefined(config.class)}
@value-changed=${this.handleValueChanged}
aria-labelledby=${id}
disabled=${ifDefined(config.disabled)}
?disabled=${config.disabled}
>
</ha-control-select>
`;
@@ -63,8 +63,8 @@ export class DemoHaControlSwitch extends LitElement {
.pathOn=${mdiLightbulb}
.pathOff=${mdiLightbulbOff}
aria-labelledby=${id}
disabled=${ifDefined(config.disabled)}
reversed=${ifDefined(config.reversed)}
?disabled=${config.disabled}
?reversed=${config.reversed}
>
</ha-control-switch>
</div>
@@ -86,8 +86,8 @@ export class DemoHaControlSwitch extends LitElement {
aria-label=${label}
.pathOn=${mdiGarageOpen}
.pathOff=${mdiGarage}
disabled=${ifDefined(config.disabled)}
reversed=${ifDefined(config.reversed)}
?disabled=${config.disabled}
?reversed=${config.reversed}
>
</ha-control-switch>
`;
@@ -3,6 +3,7 @@ import { css, html, LitElement, TemplateResult } from "lit";
import { customElement } from "lit/decorators";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-expansion-panel";
import "../../../../src/components/ha-icon-button";
import "../../../../src/components/ha-markdown";
import "../../components/demo-black-white-row";
import { LONG_TEXT } from "../../data/text";
@@ -1,19 +1,20 @@
import { html, css, LitElement } from "lit";
import "@material/mwc-list/mwc-list";
import { LitElement, css, html } from "lit";
import { customElement, state } from "lit/decorators";
import { formatDateTimeNumeric } from "../../../../src/common/datetime/format_date_time";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-control-select";
import { translationMetadata } from "../../../../src/resources/translations-metadata";
import { formatDateTimeNumeric } from "../../../../src/common/datetime/format_date_time";
import { timeOptions } from "../../data/date-options";
import { demoConfig } from "../../../../src/fake_data/demo_config";
import {
DateFormat,
FirstWeekday,
FrontendLocaleData,
NumberFormat,
TimeFormat,
DateFormat,
FirstWeekday,
TimeZone,
} from "../../../../src/data/translation";
import { demoConfig } from "../../../../src/fake_data/demo_config";
import { translationMetadata } from "../../../../src/resources/translations-metadata";
import { timeOptions } from "../../data/date-options";
@customElement("demo-date-time-date-time-numeric")
export class DemoDateTimeDateTimeNumeric extends LitElement {
@@ -1,19 +1,20 @@
import { html, css, LitElement } from "lit";
import "@material/mwc-list/mwc-list";
import { LitElement, css, html } from "lit";
import { customElement, state } from "lit/decorators";
import { formatDateTimeWithSeconds } from "../../../../src/common/datetime/format_date_time";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-control-select";
import { translationMetadata } from "../../../../src/resources/translations-metadata";
import { formatDateTimeWithSeconds } from "../../../../src/common/datetime/format_date_time";
import { timeOptions } from "../../data/date-options";
import { demoConfig } from "../../../../src/fake_data/demo_config";
import {
DateFormat,
FirstWeekday,
FrontendLocaleData,
NumberFormat,
TimeFormat,
DateFormat,
FirstWeekday,
TimeZone,
} from "../../../../src/data/translation";
import { demoConfig } from "../../../../src/fake_data/demo_config";
import { translationMetadata } from "../../../../src/resources/translations-metadata";
import { timeOptions } from "../../data/date-options";
@customElement("demo-date-time-date-time-seconds")
export class DemoDateTimeDateTimeSeconds extends LitElement {
@@ -1,19 +1,20 @@
import { html, css, LitElement } from "lit";
import "@material/mwc-list/mwc-list";
import { LitElement, css, html } from "lit";
import { customElement, state } from "lit/decorators";
import { formatShortDateTimeWithYear } from "../../../../src/common/datetime/format_date_time";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-control-select";
import { translationMetadata } from "../../../../src/resources/translations-metadata";
import { formatShortDateTimeWithYear } from "../../../../src/common/datetime/format_date_time";
import { timeOptions } from "../../data/date-options";
import { demoConfig } from "../../../../src/fake_data/demo_config";
import {
DateFormat,
FirstWeekday,
FrontendLocaleData,
NumberFormat,
TimeFormat,
DateFormat,
FirstWeekday,
TimeZone,
} from "../../../../src/data/translation";
import { demoConfig } from "../../../../src/fake_data/demo_config";
import { translationMetadata } from "../../../../src/resources/translations-metadata";
import { timeOptions } from "../../data/date-options";
@customElement("demo-date-time-date-time-short-year")
export class DemoDateTimeDateTimeShortYear extends LitElement {
@@ -1,19 +1,20 @@
import { html, css, LitElement } from "lit";
import "@material/mwc-list/mwc-list";
import { LitElement, css, html } from "lit";
import { customElement, state } from "lit/decorators";
import { formatShortDateTime } from "../../../../src/common/datetime/format_date_time";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-control-select";
import { translationMetadata } from "../../../../src/resources/translations-metadata";
import { formatShortDateTime } from "../../../../src/common/datetime/format_date_time";
import { timeOptions } from "../../data/date-options";
import { demoConfig } from "../../../../src/fake_data/demo_config";
import {
DateFormat,
FirstWeekday,
FrontendLocaleData,
NumberFormat,
TimeFormat,
DateFormat,
FirstWeekday,
TimeZone,
} from "../../../../src/data/translation";
import { demoConfig } from "../../../../src/fake_data/demo_config";
import { translationMetadata } from "../../../../src/resources/translations-metadata";
import { timeOptions } from "../../data/date-options";
@customElement("demo-date-time-date-time-short")
export class DemoDateTimeDateTimeShort extends LitElement {
+8 -7
View File
@@ -1,19 +1,20 @@
import { html, css, LitElement } from "lit";
import "@material/mwc-list/mwc-list";
import { LitElement, css, html } from "lit";
import { customElement, state } from "lit/decorators";
import { formatDateTime } from "../../../../src/common/datetime/format_date_time";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-control-select";
import { translationMetadata } from "../../../../src/resources/translations-metadata";
import { formatDateTime } from "../../../../src/common/datetime/format_date_time";
import { timeOptions } from "../../data/date-options";
import { demoConfig } from "../../../../src/fake_data/demo_config";
import {
DateFormat,
FirstWeekday,
FrontendLocaleData,
NumberFormat,
TimeFormat,
DateFormat,
FirstWeekday,
TimeZone,
} from "../../../../src/data/translation";
import { demoConfig } from "../../../../src/fake_data/demo_config";
import { translationMetadata } from "../../../../src/resources/translations-metadata";
import { timeOptions } from "../../data/date-options";
@customElement("demo-date-time-date-time")
export class DemoDateTimeDateTime extends LitElement {
+9 -7
View File
@@ -1,18 +1,20 @@
import { html, css, LitElement } from "lit";
import "@material/mwc-list/mwc-list";
import { LitElement, css, html } from "lit";
import { customElement, state } from "lit/decorators";
import "../../../../src/components/ha-card";
import { translationMetadata } from "../../../../src/resources/translations-metadata";
import { formatTimeWithSeconds } from "../../../../src/common/datetime/format_time";
import { timeOptions } from "../../data/date-options";
import { demoConfig } from "../../../../src/fake_data/demo_config";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-control-select";
import {
DateFormat,
FirstWeekday,
FrontendLocaleData,
NumberFormat,
TimeFormat,
DateFormat,
FirstWeekday,
TimeZone,
} from "../../../../src/data/translation";
import { demoConfig } from "../../../../src/fake_data/demo_config";
import { translationMetadata } from "../../../../src/resources/translations-metadata";
import { timeOptions } from "../../data/date-options";
@customElement("demo-date-time-time-seconds")
export class DemoDateTimeTimeSeconds extends LitElement {
+9 -7
View File
@@ -1,18 +1,20 @@
import { html, css, LitElement } from "lit";
import "@material/mwc-list/mwc-list";
import { LitElement, css, html } from "lit";
import { customElement, state } from "lit/decorators";
import "../../../../src/components/ha-card";
import { translationMetadata } from "../../../../src/resources/translations-metadata";
import { formatTimeWeekday } from "../../../../src/common/datetime/format_time";
import { timeOptions } from "../../data/date-options";
import { demoConfig } from "../../../../src/fake_data/demo_config";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-control-select";
import {
DateFormat,
FirstWeekday,
FrontendLocaleData,
NumberFormat,
TimeFormat,
DateFormat,
FirstWeekday,
TimeZone,
} from "../../../../src/data/translation";
import { demoConfig } from "../../../../src/fake_data/demo_config";
import { translationMetadata } from "../../../../src/resources/translations-metadata";
import { timeOptions } from "../../data/date-options";
@customElement("demo-date-time-time-weekday")
export class DemoDateTimeTimeWeekday extends LitElement {
+8 -7
View File
@@ -1,19 +1,20 @@
import { html, css, LitElement } from "lit";
import "@material/mwc-list/mwc-list";
import { LitElement, css, html } from "lit";
import { customElement, state } from "lit/decorators";
import { formatTime } from "../../../../src/common/datetime/format_time";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-control-select";
import { translationMetadata } from "../../../../src/resources/translations-metadata";
import { formatTime } from "../../../../src/common/datetime/format_time";
import { timeOptions } from "../../data/date-options";
import { demoConfig } from "../../../../src/fake_data/demo_config";
import {
DateFormat,
FirstWeekday,
FrontendLocaleData,
NumberFormat,
TimeFormat,
DateFormat,
FirstWeekday,
TimeZone,
} from "../../../../src/data/translation";
import { demoConfig } from "../../../../src/fake_data/demo_config";
import { translationMetadata } from "../../../../src/resources/translations-metadata";
import { timeOptions } from "../../data/date-options";
@customElement("demo-date-time-time")
export class DemoDateTimeTime extends LitElement {
@@ -55,7 +55,7 @@ const CONFIGS = [
];
@customElement("demo-lovelace-media-player-row")
class DemoHuiMediaPlayerRow extends LitElement {
export class DemoLovelaceMediaPlayerRow extends LitElement {
@query("#demos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
@@ -73,6 +73,6 @@ class DemoHuiMediaPlayerRow extends LitElement {
declare global {
interface HTMLElementTagNameMap {
"demo-lovelace-media-player-rows": DemoHuiMediaPlayerRow;
"demo-lovelace-media-player-row": DemoLovelaceMediaPlayerRow;
}
}
@@ -59,3 +59,9 @@ export class DemoUtilLongPress extends LitElement {
}
`;
}
declare global {
interface HTMLElementTagNameMap {
"demo-misc-util-long-press": DemoUtilLongPress;
}
}
+1 -1
View File
@@ -92,7 +92,7 @@ const ENTITIES = [
@customElement("demo-more-info-climate")
class DemoMoreInfoClimate extends LitElement {
@property() public hass!: MockHomeAssistant;
@property({ attribute: false }) public hass!: MockHomeAssistant;
@query("demo-more-infos") private _demoRoot!: HTMLElement;
+1 -1
View File
@@ -141,7 +141,7 @@ const ENTITIES = [
@customElement("demo-more-info-cover")
class DemoMoreInfoCover extends LitElement {
@property() public hass!: MockHomeAssistant;
@property({ attribute: false }) public hass!: MockHomeAssistant;
@query("demo-more-infos") private _demoRoot!: HTMLElement;
+1 -1
View File
@@ -29,7 +29,7 @@ const ENTITIES = [
@customElement("demo-more-info-humidifier")
class DemoMoreInfoHumidifier extends LitElement {
@property() public hass!: MockHomeAssistant;
@property({ attribute: false }) public hass!: MockHomeAssistant;
@query("demo-more-infos") private _demoRoot!: HTMLElement;
+1 -1
View File
@@ -32,7 +32,7 @@ const ENTITIES = [
@customElement("demo-more-info-input-number")
class DemoMoreInfoInputNumber extends LitElement {
@property() public hass!: MockHomeAssistant;
@property({ attribute: false }) public hass!: MockHomeAssistant;
@query("demo-more-infos") private _demoRoot!: HTMLElement;
+1 -1
View File
@@ -18,7 +18,7 @@ const ENTITIES = [
@customElement("demo-more-info-input-text")
class DemoMoreInfoInputText extends LitElement {
@property() public hass!: MockHomeAssistant;
@property({ attribute: false }) public hass!: MockHomeAssistant;
@query("demo-more-infos") private _demoRoot!: HTMLElement;
+1 -1
View File
@@ -140,7 +140,7 @@ const ENTITIES = [
@customElement("demo-more-info-light")
class DemoMoreInfoLight extends LitElement {
@property() public hass!: MockHomeAssistant;
@property({ attribute: false }) public hass!: MockHomeAssistant;
@query("demo-more-infos") private _demoRoot!: HTMLElement;
+1 -1
View File
@@ -21,7 +21,7 @@ const ENTITIES = [
@customElement("demo-more-info-lock")
class DemoMoreInfoLock extends LitElement {
@property() public hass!: MockHomeAssistant;
@property({ attribute: false }) public hass!: MockHomeAssistant;
@query("demo-more-infos") private _demoRoot!: HTMLElement;
+1 -1
View File
@@ -13,7 +13,7 @@ const ENTITIES = createMediaPlayerEntities();
@customElement("demo-more-info-media-player")
class DemoMoreInfoMediaPlayer extends LitElement {
@property() public hass!: MockHomeAssistant;
@property({ attribute: false }) public hass!: MockHomeAssistant;
@query("demo-more-infos") private _demoRoot!: HTMLElement;
+1 -1
View File
@@ -50,7 +50,7 @@ const ENTITIES = [
@customElement("demo-more-info-number")
class DemoMoreInfoNumber extends LitElement {
@property() public hass!: MockHomeAssistant;
@property({ attribute: false }) public hass!: MockHomeAssistant;
@query("demo-more-infos") private _demoRoot!: HTMLElement;
+1 -1
View File
@@ -21,7 +21,7 @@ const ENTITIES = [
@customElement("demo-more-info-scene")
class DemoMoreInfoScene extends LitElement {
@property() public hass!: MockHomeAssistant;
@property({ attribute: false }) public hass!: MockHomeAssistant;
@query("demo-more-infos") private _demoRoot!: HTMLElement;
+1 -1
View File
@@ -18,7 +18,7 @@ const ENTITIES = [
@customElement("demo-more-info-timer")
class DemoMoreInfoTimer extends LitElement {
@property() public hass!: MockHomeAssistant;
@property({ attribute: false }) public hass!: MockHomeAssistant;
@query("demo-more-infos") private _demoRoot!: HTMLElement;
+1 -1
View File
@@ -146,7 +146,7 @@ const ENTITIES = [
@customElement("demo-more-info-update")
class DemoMoreInfoUpdate extends LitElement {
@property() public hass!: MockHomeAssistant;
@property({ attribute: false }) public hass!: MockHomeAssistant;
@query("demo-more-infos") private _demoRoot!: HTMLElement;
+1 -1
View File
@@ -22,7 +22,7 @@ const ENTITIES = [
@customElement("demo-more-info-vacuum")
class DemoMoreInfoVacuum extends LitElement {
@property() public hass!: MockHomeAssistant;
@property({ attribute: false }) public hass!: MockHomeAssistant;
@query("demo-more-infos") private _demoRoot!: HTMLElement;
+1 -1
View File
@@ -42,7 +42,7 @@ const ENTITIES = [
@customElement("demo-more-info-water-heater")
class DemoMoreInfoWaterHeater extends LitElement {
@property() public hass!: MockHomeAssistant;
@property({ attribute: false }) public hass!: MockHomeAssistant;
@query("demo-more-infos") private _demoRoot!: HTMLElement;
@@ -140,3 +140,9 @@ export class HassioAddonRepositoryEl extends LitElement {
];
}
}
declare global {
interface HTMLElementTagNameMap {
"hassio-addon-repository": HassioAddonRepositoryEl;
}
}
+7 -1
View File
@@ -56,7 +56,7 @@ export class HassioAddonStore extends LitElement {
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ type: Boolean }) public narrow!: boolean;
@property({ type: Boolean }) public narrow = false;
@property({ attribute: false }) public route!: Route;
@@ -248,3 +248,9 @@ export class HassioAddonStore extends LitElement {
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"hassio-addon-store": HassioAddonStore;
}
}
@@ -65,9 +65,9 @@ class HassioAddonConfig extends LitElement {
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ type: Boolean }) private _configHasChanged = false;
@state() private _configHasChanged = false;
@property({ type: Boolean }) private _valid = true;
@state() private _valid = true;
@state() private _canShowSchema = false;
@@ -51,7 +51,7 @@ class HassioAddonDashboard extends LitElement {
| HassioAddonDetails
| StoreAddonDetails;
@property({ type: Boolean }) public narrow!: boolean;
@property({ type: Boolean }) public narrow = false;
@state() private _error?: string;
@@ -10,7 +10,7 @@ import "./hassio-addon-info";
@customElement("hassio-addon-info-tab")
class HassioAddonInfoDashboard extends LitElement {
@property({ type: Boolean }) public narrow!: boolean;
@property({ type: Boolean }) public narrow = false;
@property({ attribute: false }) public route!: Route;
@@ -99,7 +99,7 @@ const RATING_ICON = {
@customElement("hassio-addon-info")
class HassioAddonInfo extends LitElement {
@property({ type: Boolean }) public narrow!: boolean;
@property({ type: Boolean }) public narrow = false;
@property({ attribute: false }) public route!: Route;
+3 -3
View File
@@ -59,11 +59,11 @@ export class HassioBackups extends LitElement {
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ type: Object }) public route!: Route;
@property({ attribute: false }) public route!: Route;
@property({ type: Boolean }) public narrow!: boolean;
@property({ type: Boolean }) public narrow = false;
@property({ type: Boolean }) public isWide!: boolean;
@property({ type: Boolean }) public isWide = false;
@state() private _selectedBackups: string[] = [];
@@ -1,6 +1,4 @@
import { mdiFolder, mdiPuzzle } from "@mdi/js";
import "@polymer/paper-input/paper-input";
import type { PaperInputElement } from "@polymer/paper-input/paper-input";
import {
CSSResultGroup,
LitElement,
@@ -16,6 +14,7 @@ import { formatDateTime } from "../../../src/common/datetime/format_date_time";
import { LocalizeFunc } from "../../../src/common/translations/localize";
import "../../../src/components/ha-checkbox";
import "../../../src/components/ha-formfield";
import "../../../src/components/ha-textfield";
import "../../../src/components/ha-radio";
import type { HaRadio } from "../../../src/components/ha-radio";
import {
@@ -25,12 +24,9 @@ import {
} from "../../../src/data/hassio/backup";
import { Supervisor } from "../../../src/data/supervisor/supervisor";
import { mdiHomeAssistant } from "../../../src/resources/home-assistant-logo-svg";
import {
HomeAssistant,
TranslationDict,
ValueChangedEvent,
} from "../../../src/types";
import { HomeAssistant, TranslationDict } from "../../../src/types";
import "./supervisor-formfield-label";
import type { HaTextField } from "../../../src/components/ha-textfield";
type BackupOrRestoreKey = keyof TranslationDict["supervisor"]["backup"] &
keyof TranslationDict["ui"]["panel"]["page-onboarding"]["restore"];
@@ -100,7 +96,7 @@ export class SupervisorBackupContent extends LitElement {
@property() public confirmBackupPassword = "";
@query("paper-input, ha-radio, ha-checkbox", true) private _focusTarget;
@query("ha-textfield, ha-radio, ha-checkbox", true) private _focusTarget;
public willUpdate(changedProps) {
super.willUpdate(changedProps);
@@ -151,13 +147,13 @@ export class SupervisorBackupContent extends LitElement {
)
: this.backup.date}
</div>`
: html`<paper-input
: html`<ha-textfield
name="backupName"
.label=${this._localize("name")}
.value=${this.backupName}
@value-changed=${this._handleTextValueChanged}
@change=${this._handleTextValueChanged}
>
</paper-input>`}
</ha-textfield>`}
${!this.backup || this.backup.type === "full"
? html`<div class="sub-header">
${!this.backup
@@ -265,23 +261,23 @@ export class SupervisorBackupContent extends LitElement {
: ""}
${this.backupHasPassword
? html`
<paper-input
<ha-textfield
.label=${this._localize("password")}
type="password"
name="backupPassword"
.value=${this.backupPassword}
@value-changed=${this._handleTextValueChanged}
@change=${this._handleTextValueChanged}
>
</paper-input>
</ha-textfield>
${!this.backup
? html` <paper-input
? html`<ha-textfield
.label=${this._localize("confirm_password")}
type="password"
name="confirmBackupPassword"
.value=${this.confirmBackupPassword}
@value-changed=${this._handleTextValueChanged}
@change=${this._handleTextValueChanged}
>
</paper-input>`
</ha-textfield>`
: ""}
`
: ""}
@@ -429,9 +425,9 @@ export class SupervisorBackupContent extends LitElement {
this[input.name] = input.value;
}
private _handleTextValueChanged(ev: ValueChangedEvent<string>) {
const input = ev.currentTarget as PaperInputElement;
this[input.name!] = ev.detail.value;
private _handleTextValueChanged(ev: InputEvent) {
const input = ev.currentTarget as HaTextField;
this[input.name!] = input.value;
}
private _toggleHasPassword(): void {
+2 -1
View File
@@ -20,7 +20,7 @@ class HassioAddons extends LitElement {
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ type: Boolean }) public narrow!: boolean;
@property({ type: Boolean }) public narrow = false;
@state() private _filter?: string;
@@ -128,6 +128,7 @@ class HassioAddons extends LitElement {
ha-card {
cursor: pointer;
overflow: hidden;
direction: ltr;
}
.search {
position: sticky;
+3 -1
View File
@@ -21,7 +21,7 @@ class HassioDashboard extends LitElement {
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ type: Boolean }) public narrow!: boolean;
@property({ type: Boolean }) public narrow = false;
@property({ attribute: false }) public route!: Route;
@@ -133,6 +133,8 @@ class HassioDashboard extends LitElement {
position: fixed;
right: calc(16px + env(safe-area-inset-right));
bottom: calc(16px + env(safe-area-inset-bottom));
inset-inline-end: calc(16px + env(safe-area-inset-right));
inset-inline-start: initial;
z-index: 1;
}
`,
+6
View File
@@ -151,3 +151,9 @@ export class HassioUpdate extends LitElement {
];
}
}
declare global {
interface HTMLElementTagNameMap {
"hassio-update": HassioUpdate;
}
}
@@ -4,7 +4,6 @@ import "@material/mwc-list/mwc-list-item";
import "@material/mwc-tab";
import "@material/mwc-tab-bar";
import { mdiClose } from "@mdi/js";
import { PaperInputElement } from "@polymer/paper-input/paper-input";
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { cache } from "lit/directives/cache";
@@ -14,6 +13,7 @@ import "../../../../src/components/ha-circular-progress";
import "../../../../src/components/ha-dialog";
import "../../../../src/components/ha-expansion-panel";
import "../../../../src/components/ha-formfield";
import "../../../../src/components/ha-textfield";
import "../../../../src/components/ha-header-bar";
import "../../../../src/components/ha-icon-button";
import "../../../../src/components/ha-radio";
@@ -34,6 +34,7 @@ import { HassDialog } from "../../../../src/dialogs/make-dialog-manager";
import { haStyleDialog } from "../../../../src/resources/styles";
import type { HomeAssistant } from "../../../../src/types";
import { HassioNetworkDialogParams } from "./show-dialog-network";
import type { HaTextField } from "../../../../src/components/ha-textfield";
const IP_VERSIONS = ["ipv4", "ipv6"];
@@ -245,7 +246,7 @@ export class DialogHassioNetwork
${this._wifiConfiguration.auth === "wpa-psk" ||
this._wifiConfiguration.auth === "wep"
? html`
<paper-input
<ha-textfield
class="flex-auto"
type="password"
id="psk"
@@ -253,10 +254,9 @@ export class DialogHassioNetwork
"dialog.network.wifi_password"
)}
version="wifi"
@value-changed=${this
._handleInputValueChangedWifi}
@change=${this._handleInputValueChangedWifi}
>
</paper-input>
</ha-textfield>
`
: ""}
`
@@ -358,33 +358,33 @@ export class DialogHassioNetwork
</div>
${this._interface![version].method === "static"
? html`
<paper-input
<ha-textfield
class="flex-auto"
id="address"
.label=${this.supervisor.localize("dialog.network.ip_netmask")}
.version=${version}
.value=${this._toString(this._interface![version].address)}
@value-changed=${this._handleInputValueChanged}
@change=${this._handleInputValueChanged}
>
</paper-input>
<paper-input
</ha-textfield>
<ha-textfield
class="flex-auto"
id="gateway"
.label=${this.supervisor.localize("dialog.network.gateway")}
.version=${version}
.value=${this._interface![version].gateway}
@value-changed=${this._handleInputValueChanged}
@change=${this._handleInputValueChanged}
>
</paper-input>
<paper-input
</ha-textfield>
<ha-textfield
class="flex-auto"
id="nameservers"
.label=${this.supervisor.localize("dialog.network.dns_servers")}
.version=${version}
.value=${this._toString(this._interface![version].nameservers)}
@value-changed=${this._handleInputValueChanged}
@change=${this._handleInputValueChanged}
>
</paper-input>
</ha-textfield>
`
: ""}
</ha-expansion-panel>
@@ -517,11 +517,11 @@ export class DialogHassioNetwork
this.requestUpdate("_wifiConfiguration");
}
private _handleInputValueChanged(ev: CustomEvent): void {
const value: string | null | undefined = (ev.target as PaperInputElement)
.value;
private _handleInputValueChanged(ev: Event): void {
const source = ev.target as HaTextField;
const value = source.value;
const version = (ev.target as any).version as "ipv4" | "ipv6";
const id = (ev.target as PaperInputElement).id;
const id = source.id;
if (
!value ||
@@ -535,10 +535,10 @@ export class DialogHassioNetwork
this._interface[version]![id] = value;
}
private _handleInputValueChangedWifi(ev: CustomEvent): void {
const value: string | null | undefined = (ev.target as PaperInputElement)
.value;
const id = (ev.target as PaperInputElement).id;
private _handleInputValueChangedWifi(ev: Event): void {
const source = ev.target as HaTextField;
const value = source.value;
const id = source.id;
if (
!value ||
@@ -630,7 +630,7 @@ export class DialogHassioNetwork
--expansion-panel-summary-padding: 0 16px;
margin: 4px 0;
}
paper-input {
ha-textfield {
padding: 0 14px;
}
mwc-list-item {
@@ -157,11 +157,10 @@ class HassioRegistriesDialog extends LitElement {
}
public focus(): void {
this.updateComplete.then(
() =>
(
this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement
)?.focus()
this.updateComplete.then(() =>
(
this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement
)?.focus()
);
}
@@ -1,7 +1,5 @@
import "@material/mwc-button/mwc-button";
import { mdiDelete, mdiDeleteOff } from "@mdi/js";
import "@polymer/paper-input/paper-input";
import type { PaperInputElement } from "@polymer/paper-input/paper-input";
import "@polymer/paper-item/paper-item";
import "@polymer/paper-item/paper-item-body";
import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
@@ -27,12 +25,14 @@ import {
import { haStyle, haStyleDialog } from "../../../../src/resources/styles";
import type { HomeAssistant } from "../../../../src/types";
import { HassioRepositoryDialogParams } from "./show-dialog-repositories";
import type { HaTextField } from "../../../../src/components/ha-textfield";
import "../../../../src/components/ha-textfield";
@customElement("dialog-hassio-repositories")
class HassioRepositoriesDialog extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@query("#repository_input", true) private _optionInput?: PaperInputElement;
@query("#repository_input", true) private _optionInput?: HaTextField;
@state() private _repositories?: HassioAddonRepository[];
@@ -145,7 +145,7 @@ class HassioRepositoriesDialog extends LitElement {
)
: html`<paper-item> No repositories </paper-item>`}
<div class="layout horizontal bottom">
<paper-input
<ha-textfield
class="flex-auto"
id="repository_input"
.value=${this._dialogParams!.url || ""}
@@ -154,7 +154,7 @@ class HassioRepositoriesDialog extends LitElement {
)}
@keydown=${this._handleKeyAdd}
dialogInitialFocus
></paper-input>
></ha-textfield>
<mwc-button @click=${this._addRepository}>
${this._processing
? html`<ha-circular-progress
@@ -209,11 +209,10 @@ class HassioRepositoriesDialog extends LitElement {
}
public focus() {
this.updateComplete.then(
() =>
(
this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement
)?.focus()
this.updateComplete.then(() =>
(
this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement
)?.focus()
);
}
+1 -1
View File
@@ -21,7 +21,7 @@ export class HassioMain extends SupervisorBaseElement {
@property({ attribute: false }) public panel!: HassioPanelInfo;
@property({ type: Boolean }) public narrow!: boolean;
@property({ type: Boolean }) public narrow = false;
protected firstUpdated(changedProps: PropertyValues) {
super.firstUpdated(changedProps);
+1 -1
View File
@@ -16,7 +16,7 @@ class HassioPanelRouter extends HassRouterPage {
@property({ attribute: false }) public route!: Route;
@property({ type: Boolean }) public narrow!: boolean;
@property({ type: Boolean }) public narrow = false;
protected routerOptions: RouterOptions = {
beforeRender: (page: string) =>
+1 -1
View File
@@ -14,7 +14,7 @@ class HassioPanel extends LitElement {
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ type: Boolean }) public narrow!: boolean;
@property({ type: Boolean }) public narrow = false;
@property({ attribute: false }) public route!: Route;
+1 -1
View File
@@ -18,7 +18,7 @@ class HassioRouter extends HassRouterPage {
@property({ attribute: false }) public panel!: HassioPanelInfo;
@property({ type: Boolean }) public narrow!: boolean;
@property({ type: Boolean }) public narrow = false;
protected routerOptions: RouterOptions = {
// Hass.io has a page with tabs, so we route all non-matching routes to it.
+10
View File
@@ -29,6 +29,10 @@ import { ProvideHassLitMixin } from "../../src/mixins/provide-hass-lit-mixin";
import { urlSyncMixin } from "../../src/state/url-sync-mixin";
import { HomeAssistant, Route } from "../../src/types";
import { getTranslation } from "../../src/util/common-translation";
import {
computeRTLDirection,
setDirectionStyles,
} from "../../src/common/util/compute_rtl";
declare global {
interface HASSDomEvents {
@@ -95,6 +99,7 @@ export class SupervisorBaseElement extends urlSyncMixin(
if (changedProperties.has("_language") || !this.hasUpdated) {
this._initializeLocalize();
this._applyDirection(this.hass);
}
}
@@ -215,4 +220,9 @@ export class SupervisorBaseElement extends urlSyncMixin(
);
}
}
private _applyDirection(hass: HomeAssistant) {
const direction = computeRTLDirection(hass);
setDirectionStyles(direction, this);
}
}
+2 -1
View File
@@ -1,9 +1,10 @@
import "../../../src/components/ha-ansi-to-html";
import "@material/mwc-button";
import "@material/mwc-list/mwc-list-item";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../src/components/buttons/ha-progress-button";
import "../../../src/components/ha-alert";
import "../../../src/components/ha-ansi-to-html";
import "../../../src/components/ha-card";
import "../../../src/components/ha-select";
import { extractApiErrorMessage } from "../../../src/data/hassio/common";
+1 -1
View File
@@ -18,7 +18,7 @@ class HassioSystem extends LitElement {
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ type: Boolean }) public narrow!: boolean;
@property({ type: Boolean }) public narrow = false;
@property({ attribute: false }) public route!: Route;
@@ -94,7 +94,7 @@ class UpdateAvailableCard extends LitElement {
@property({ attribute: false }) public route!: Route;
@property({ type: Boolean }) public narrow!: boolean;
@property({ type: Boolean }) public narrow = false;
@property({ attribute: false }) public addonSlug?: string;
@@ -11,7 +11,7 @@ class UpdateAvailableDashboard extends LitElement {
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ type: Boolean }) public narrow!: boolean;
@property({ type: Boolean }) public narrow = false;
@property({ attribute: false }) public route!: Route;
+1
View File
@@ -2,6 +2,7 @@ export default {
"*.?(c|m){js,ts}": [
"eslint --cache --cache-strategy=content --cache-location=node_modules/.cache/eslint/.eslintcache --fix",
"prettier --cache --write",
"lit-analyzer",
],
"*.{json,css,md,markdown,html,y?aml}": "prettier --cache --write",
"translations/*/*.json": (files) =>
+36 -35
View File
@@ -13,8 +13,8 @@
"lint:prettier": "prettier . --cache --check",
"format:prettier": "prettier . --cache --write",
"lint:types": "tsc",
"lint:lit": "lit-analyzer \"**/src/**/*.ts\" --format markdown --outFile result.md",
"lint": "yarn run lint:eslint && yarn run lint:prettier && yarn run lint:types",
"lint:lit": "lit-analyzer \"{.,*}/src/**/*.ts\"",
"lint": "yarn run lint:eslint && yarn run lint:prettier && yarn run lint:types && yarn run lint:lit",
"format": "yarn run format:eslint && yarn run format:prettier",
"postinstall": "husky install",
"prepack": "pinst --disable",
@@ -25,15 +25,15 @@
"license": "Apache-2.0",
"type": "module",
"dependencies": {
"@babel/runtime": "7.23.6",
"@babel/runtime": "7.23.8",
"@braintree/sanitize-url": "7.0.0",
"@codemirror/autocomplete": "6.11.1",
"@codemirror/commands": "6.3.2",
"@codemirror/language": "6.9.3",
"@codemirror/autocomplete": "6.12.0",
"@codemirror/commands": "6.3.3",
"@codemirror/language": "6.10.0",
"@codemirror/legacy-modes": "6.3.3",
"@codemirror/search": "6.5.5",
"@codemirror/state": "6.3.3",
"@codemirror/view": "6.22.3",
"@codemirror/state": "6.4.0",
"@codemirror/view": "6.23.0",
"@egjs/hammerjs": "2.0.17",
"@formatjs/intl-datetimeformat": "6.12.0",
"@formatjs/intl-displaynames": "6.6.4",
@@ -53,7 +53,7 @@
"@lit-labs/context": "0.4.1",
"@lit-labs/motion": "1.0.6",
"@lit-labs/observers": "2.0.2",
"@lit-labs/virtualizer": "2.0.11",
"@lit-labs/virtualizer": "2.0.12",
"@lrnwebcomponents/simple-tooltip": "7.0.18",
"@material/chips": "=14.0.0-canary.53b3cad2f.0",
"@material/data-table": "=14.0.0-canary.53b3cad2f.0",
@@ -81,17 +81,16 @@
"@material/mwc-top-app-bar-fixed": "0.27.0",
"@material/top-app-bar": "=14.0.0-canary.53b3cad2f.0",
"@material/web": "=1.1.1",
"@mdi/js": "7.3.67",
"@mdi/svg": "7.3.67",
"@polymer/paper-input": "3.2.1",
"@mdi/js": "7.4.47",
"@mdi/svg": "7.4.47",
"@polymer/paper-item": "3.0.1",
"@polymer/paper-listbox": "3.0.1",
"@polymer/paper-tabs": "3.1.0",
"@polymer/paper-toast": "3.0.1",
"@polymer/polymer": "3.5.1",
"@thomasloven/round-slider": "0.6.0",
"@vaadin/combo-box": "24.3.2",
"@vaadin/vaadin-themable-mixin": "24.3.2",
"@vaadin/combo-box": "24.3.3",
"@vaadin/vaadin-themable-mixin": "24.3.3",
"@vibrant/color": "3.2.1-alpha.1",
"@vibrant/core": "3.2.1-alpha.1",
"@vibrant/quantizer-mmcq": "3.2.1-alpha.1",
@@ -101,7 +100,7 @@
"app-datepicker": "5.1.1",
"chart.js": "4.4.1",
"comlink": "4.4.1",
"core-js": "3.34.0",
"core-js": "3.35.0",
"cropperjs": "1.6.1",
"date-fns": "2.30.0",
"date-fns-tz": "2.0.0",
@@ -110,7 +109,8 @@
"element-internals-polyfill": "1.3.10",
"fuse.js": "7.0.0",
"google-timezones-json": "1.2.0",
"hls.js": "1.4.14",
"gridstack": "10.0.1",
"hls.js": "1.5.1",
"home-assistant-js-websocket": "9.1.0",
"idb-keyval": "6.2.1",
"intl-messageformat": "10.5.8",
@@ -119,7 +119,7 @@
"leaflet-draw": "1.0.4",
"lit": "2.8.0",
"luxon": "3.4.4",
"marked": "11.1.0",
"marked": "11.1.1",
"memoize-one": "6.0.0",
"node-vibrant": "3.2.1-alpha.1",
"proxy-polyfill": "0.3.2",
@@ -128,7 +128,7 @@
"qrcode": "1.5.3",
"roboto-fontface": "0.10.0",
"rrule": "2.8.1",
"sortablejs": "1.15.1",
"sortablejs": "1.15.2",
"stacktrace-js": "2.0.2",
"superstruct": "1.0.3",
"tinykeys": "2.1.0",
@@ -150,13 +150,13 @@
"xss": "1.0.14"
},
"devDependencies": {
"@babel/core": "7.23.6",
"@babel/core": "7.23.7",
"@babel/helper-define-polyfill-provider": "0.4.4",
"@babel/plugin-proposal-decorators": "7.23.6",
"@babel/plugin-transform-runtime": "7.23.6",
"@babel/preset-env": "7.23.6",
"@babel/plugin-proposal-decorators": "7.23.7",
"@babel/plugin-transform-runtime": "7.23.7",
"@babel/preset-env": "7.23.8",
"@babel/preset-typescript": "7.23.3",
"@bundle-stats/plugin-webpack-filter": "4.8.3",
"@bundle-stats/plugin-webpack-filter": "4.8.4",
"@koa/cors": "5.0.0",
"@lokalise/node-api": "12.1.0",
"@octokit/auth-oauth-device": "6.0.1",
@@ -169,14 +169,14 @@
"@rollup/plugin-node-resolve": "15.2.3",
"@rollup/plugin-replace": "5.0.5",
"@types/babel__plugin-transform-runtime": "7.9.5",
"@types/chromecast-caf-receiver": "6.0.12",
"@types/chromecast-caf-receiver": "6.0.13",
"@types/chromecast-caf-sender": "1.0.8",
"@types/glob": "8.1.0",
"@types/html-minifier-terser": "7.0.2",
"@types/js-yaml": "4.0.9",
"@types/leaflet": "1.9.8",
"@types/leaflet-draw": "1.0.11",
"@types/luxon": "3.3.7",
"@types/luxon": "3.4.1",
"@types/mocha": "10.0.6",
"@types/qrcode": "1.5.5",
"@types/serve-handler": "6.1.4",
@@ -184,13 +184,13 @@
"@types/tar": "6.1.10",
"@types/ua-parser-js": "0.7.39",
"@types/webspeechapi": "0.0.29",
"@typescript-eslint/eslint-plugin": "6.16.0",
"@typescript-eslint/parser": "6.16.0",
"@typescript-eslint/eslint-plugin": "6.18.1",
"@typescript-eslint/parser": "6.18.1",
"@web/dev-server": "0.1.38",
"@web/dev-server-rollup": "0.4.1",
"babel-loader": "9.1.3",
"babel-plugin-template-html-minifier": "4.1.0",
"chai": "4.3.10",
"chai": "5.0.0",
"del": "7.1.0",
"eslint": "8.56.0",
"eslint-config-airbnb-base": "15.0.0",
@@ -217,26 +217,27 @@
"instant-mocha": "1.5.2",
"jszip": "3.10.1",
"lint-staged": "15.2.0",
"lit-analyzer": "2.0.2",
"lit-analyzer": "2.0.3",
"lodash.template": "4.5.0",
"magic-string": "0.30.5",
"map-stream": "0.0.7",
"mocha": "10.2.0",
"object-hash": "3.0.0",
"open": "10.0.1",
"open": "10.0.3",
"pinst": "3.0.0",
"prettier": "3.1.1",
"prettier": "3.2.2",
"rollup": "2.79.1",
"rollup-plugin-string": "3.0.0",
"rollup-plugin-terser": "7.0.2",
"rollup-plugin-visualizer": "5.11.0",
"rollup-plugin-visualizer": "5.12.0",
"serve-handler": "6.1.5",
"sinon": "17.0.1",
"source-map-url": "0.4.1",
"systemjs": "6.14.2",
"systemjs": "6.14.3",
"tar": "6.2.0",
"terser-webpack-plugin": "5.3.9",
"ts-lit-plugin": "2.0.1",
"terser-webpack-plugin": "5.3.10",
"transform-async-modules-webpack-plugin": "1.0.2",
"ts-lit-plugin": "2.0.2",
"typescript": "5.3.3",
"vinyl-buffer": "1.0.1",
"vinyl-source-stream": "2.0.0",
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "home-assistant-frontend"
version = "20231228.0"
version = "20240112.0"
license = {text = "Apache-2.0"}
description = "The Home Assistant frontend"
readme = "README.md"
@@ -1,7 +1,10 @@
#!/usr/bin/env node
const fs = require("fs");
const util = require("util");
const exec = util.promisify(require("child_process").exec);
/* eslint-disable no-console */
import fs from "fs";
import util from "util";
import child_process from "child_process";
const exec = util.promisify(child_process.exec);
function patch(version) {
const parts = version.split(".");
@@ -18,7 +21,7 @@ function today() {
function auto(version) {
const todayVersion = today();
if (todayVersion !== version) {
if (todayVersion.split(".")[0] !== version.split(".")[0]) {
return todayVersion;
}
return patch(version);
@@ -44,7 +47,7 @@ async function main(args) {
commit = true;
} else {
method = args.length > 0 && methods[args[0]];
commit = args.length > 1 && args[1] == "--commit";
commit = args.length > 1 && args[1] === "--commit";
}
if (!method) {
+14 -22
View File
@@ -21,7 +21,6 @@ import {
DataEntryFlowStepForm,
} from "../data/data_entry_flow";
import "./ha-auth-form";
import { fireEvent } from "../common/dom/fire_event";
type State = "loading" | "error" | "step";
@@ -39,7 +38,9 @@ export class HaAuthFlow extends LitElement {
@property({ attribute: false }) public step?: DataEntryFlowStep;
@property({ type: Boolean }) private storeToken = false;
@property({ type: Boolean }) public initStoreToken = false;
@state() private _storeToken = false;
@state() private _state: State = "loading";
@@ -56,6 +57,10 @@ export class HaAuthFlow extends LitElement {
willUpdate(changedProps: PropertyValues) {
super.willUpdate(changedProps);
if (!this.hasUpdated) {
this._storeToken = this.initStoreToken;
}
if (!changedProps.has("step")) {
return;
}
@@ -155,11 +160,6 @@ export class HaAuthFlow extends LitElement {
}
private _renderForm() {
const showBack =
this.step?.type === "form" &&
this.authProvider?.users &&
!["select_mfa_module", "mfa"].includes(this.step.step_id);
switch (this._state) {
case "step":
if (this.step == null) {
@@ -168,12 +168,7 @@ export class HaAuthFlow extends LitElement {
return html`
${this._renderStep(this.step)}
<div class="action ${showBack ? "space-between" : ""}">
${showBack
? html`<mwc-button @click=${this._localFlow}>
${this.localize("ui.panel.page-authorize.form.previous")}
</mwc-button>`
: nothing}
<div class="action">
<mwc-button
raised
@click=${this._handleSubmit}
@@ -227,7 +222,8 @@ export class HaAuthFlow extends LitElement {
</h1>
${this._computeStepDescription(step)}
<ha-auth-form
.data=${this._stepData}
.localize=${this.localize}
.data=${this._stepData!}
.schema=${autocompleteLoginFields(step.data_schema)}
.error=${step.errors}
.disabled=${this._submitting}
@@ -246,7 +242,7 @@ export class HaAuthFlow extends LitElement {
)}
>
<ha-checkbox
.checked=${this.storeToken}
.checked=${this._storeToken}
@change=${this._storeTokenChanged}
></ha-checkbox>
</ha-formfield>
@@ -269,7 +265,7 @@ export class HaAuthFlow extends LitElement {
}
private _storeTokenChanged(e: CustomEvent<HTMLInputElement>) {
this.storeToken = (e.currentTarget as HTMLInputElement).checked;
this._storeToken = (e.currentTarget as HTMLInputElement).checked;
}
private async _providerChanged(newProvider?: AuthProvider) {
@@ -303,7 +299,7 @@ export class HaAuthFlow extends LitElement {
this.redirectUri!,
data.result,
this.oauth2State,
this.storeToken
this._storeToken
);
return;
}
@@ -385,7 +381,7 @@ export class HaAuthFlow extends LitElement {
this.redirectUri!,
newStep.result,
this.oauth2State,
this.storeToken
this._storeToken
);
return;
}
@@ -400,10 +396,6 @@ export class HaAuthFlow extends LitElement {
this._submitting = false;
}
}
private _localFlow() {
fireEvent(this, "default-login-flow", { value: false });
}
}
declare global {
+1 -1
View File
@@ -59,7 +59,7 @@ export class HaAuthFormString extends HaFormString {
html`<div style="width: 24px"></div>`
: this.schema.description?.suffix
}
.validationMessage=${this.schema.required ? "Required" : undefined}
.validationMessage=${this.schema.required ? this.localize?.("ui.panel.page-authorize.form.error_required") : undefined}
@input=${this._valueChanged}
@change=${this._valueChanged}
></ha-auth-textfield>
+13 -1
View File
@@ -1,11 +1,23 @@
/* eslint-disable lit/prefer-static-styles */
import { html } from "lit";
import { customElement } from "lit/decorators";
import { customElement, property } from "lit/decorators";
import { HaForm } from "../components/ha-form/ha-form";
import "./ha-auth-form-string";
import { LocalizeFunc } from "../common/translations/localize";
const localizeBaseKey = "ui.panel.page-authorize.form";
@customElement("ha-auth-form")
export class HaAuthForm extends HaForm {
@property({ attribute: false }) public localize?: LocalizeFunc;
protected getFormProperties(): Record<string, any> {
return {
localize: this.localize,
localizeBaseKey,
};
}
protected fieldElementName(type: string): string {
if (type === "string") {
return `ha-auth-form-${type}`;
+1 -1
View File
@@ -47,7 +47,7 @@ export class HaAuthTextField extends HaTextField {
// TODO: live() directive needs casting for lit-analyzer
// https://github.com/runem/lit-analyzer/pull/91/files
// TODO: lit-analyzer labels min/max as (number|string) instead of string
return html` <input
return html`<input
aria-labelledby=${ifDefined(ariaLabelledbyOrUndef)}
aria-controls=${ifDefined(ariaControlsOrUndef)}
aria-describedby=${ifDefined(ariaDescribedbyOrUndef)}
+27 -41
View File
@@ -13,7 +13,6 @@ import {
import { litLocalizeLiteMixin } from "../mixins/lit-localize-lite-mixin";
import { registerServiceWorker } from "../util/register-service-worker";
import "./ha-auth-flow";
import "./ha-local-auth-flow";
import("./ha-pick-auth-provider");
@@ -36,12 +35,12 @@ export class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
@state() private _authProviders?: AuthProvider[];
@state() private _preselectStoreToken = false;
@state() private _ownInstance = false;
@state() private _error?: string;
@state() private _forceDefaultLogin = false;
constructor() {
super();
const query = extractSearchParamsObject() as AuthUrlSearchParams;
@@ -84,8 +83,7 @@ export class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
display: block;
margin-top: 24px;
}
ha-auth-flow,
ha-local-auth-flow {
ha-auth-flow {
display: flex;
justify-content: center;
flex-direction: column;
@@ -176,44 +174,29 @@ export class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
</ha-alert>`
: nothing}
<div
class="card-content"
@default-login-flow=${this._handleDefaultLoginFlow}
>
<div class="card-content">
${!this._authProvider
? html`<p>
${this.localize("ui.panel.page-authorize.initializing")}
</p> `
: !this._forceDefaultLogin &&
this._authProvider!.users &&
this.clientId != null &&
this.redirectUri != null
? html`<ha-local-auth-flow
: html`<ha-auth-flow
.clientId=${this.clientId}
.redirectUri=${this.redirectUri}
.oauth2State=${this.oauth2State}
.authProvider=${this._authProvider}
.authProviders=${this._authProviders}
.localize=${this.localize}
.ownInstance=${this._ownInstance}
></ha-local-auth-flow>`
: html`<ha-auth-flow
.clientId=${this.clientId}
.redirectUri=${this.redirectUri}
.oauth2State=${this.oauth2State}
.authProvider=${this._authProvider}
.localize=${this.localize}
></ha-auth-flow>
${inactiveProviders!.length > 0
? html`
<ha-pick-auth-provider
.localize=${this.localize}
.clientId=${this.clientId}
.authProviders=${inactiveProviders}
@pick-auth-provider=${this._handleAuthProviderPick}
></ha-pick-auth-provider>
`
: ""}`}
.initStoreToken=${this._preselectStoreToken}
></ha-auth-flow>
${inactiveProviders!.length > 0
? html`
<ha-pick-auth-provider
.localize=${this.localize}
.clientId=${this.clientId}
.authProviders=${inactiveProviders!}
@pick-auth-provider=${this._handleAuthProviderPick}
></ha-pick-auth-provider>
`
: ""}`}
</div>
<div class="footer">
<ha-language-picker
@@ -319,13 +302,14 @@ export class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
return;
}
if (authProviders.length === 0) {
if (authProviders.providers.length === 0) {
this._error = "No auth providers returned. Unable to finish login.";
return;
}
this._authProviders = authProviders;
this._authProvider = authProviders[0];
this._authProviders = authProviders.providers;
this._authProvider = authProviders.providers[0];
this._preselectStoreToken = authProviders.preselect_remember_me;
} catch (err: any) {
this._error = "Unable to fetch auth providers.";
// eslint-disable-next-line
@@ -333,10 +317,6 @@ export class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
}
}
private _handleDefaultLoginFlow(ev) {
this._forceDefaultLogin = ev.detail.value;
}
private async _handleAuthProviderPick(ev) {
this._authProvider = ev.detail;
}
@@ -352,3 +332,9 @@ export class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
}
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-authorize": HaAuthorize;
}
}
-485
View File
@@ -1,485 +0,0 @@
/* eslint-disable lit/prefer-static-styles */
import "@material/mwc-button";
import { mdiEye, mdiEyeOff } from "@mdi/js";
import { html, LitElement, nothing, PropertyValues } from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../common/dom/fire_event";
import { LocalizeFunc } from "../common/translations/localize";
import "../components/ha-alert";
import "../components/ha-button";
import "../components/ha-icon-button";
import "../components/user/ha-person-badge";
import {
AuthProvider,
createLoginFlow,
deleteLoginFlow,
redirectWithAuthCode,
submitLoginFlow,
} from "../data/auth";
import { DataEntryFlowStep } from "../data/data_entry_flow";
import { BasePerson, listUserPersons } from "../data/person";
import "./ha-auth-textfield";
import type { HaAuthTextField } from "./ha-auth-textfield";
@customElement("ha-local-auth-flow")
export class HaLocalAuthFlow extends LitElement {
@property({ attribute: false }) public authProvider?: AuthProvider;
@property({ attribute: false }) public authProviders?: AuthProvider[];
@property() public clientId?: string;
@property() public redirectUri?: string;
@property() public oauth2State?: string;
@property({ type: Boolean }) public ownInstance = false;
@property() public localize!: LocalizeFunc;
@state() private _error?: string;
@state() private _step?: DataEntryFlowStep;
@state() private _submitting = false;
@state() private _persons?: Record<string, BasePerson>;
@state() private _selectedUser?: string;
@state() private _unmaskedPassword = false;
createRenderRoot() {
return this;
}
willUpdate(changedProps: PropertyValues) {
super.willUpdate(changedProps);
if (!this.hasUpdated) {
this._load();
}
}
protected render() {
if (!this.authProvider?.users || !this._persons) {
return nothing;
}
const userIds = Object.keys(this.authProvider.users).filter(
(userId) => userId in this._persons!
);
return html`
<style>
.content {
max-width: 560px;
}
.persons {
margin-top: 24px;
display: flex;
flex-wrap: wrap;
gap: 16px;
justify-content: center;
}
.persons.force-small {
max-width: 350px;
}
.person {
display: flex;
flex-direction: column;
align-items: center;
flex-shrink: 0;
text-align: center;
cursor: pointer;
width: 80px;
}
.person[role="button"] {
outline: none;
padding: 8px;
border-radius: 4px;
}
.person[role="button"]:focus-visible {
background: rgba(var(--rgb-primary-color), 0.1);
}
.person p {
margin-bottom: 0;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
width: 100%;
}
ha-person-badge {
width: 80px;
height: 80px;
--person-badge-font-size: 2em;
}
form {
width: 100%;
}
ha-auth-textfield {
display: block !important;
position: relative;
}
ha-auth-textfield ha-icon-button {
position: absolute;
top: 4px;
right: 4px;
z-index: 9;
}
.login-form {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
max-width: 336px;
margin-top: 24px;
}
.login-form .person {
cursor: default;
width: auto;
}
.login-form .person p {
font-size: 28px;
margin-top: 24px;
margin-bottom: 32px;
line-height: normal;
}
.login-form ha-person-badge {
width: 120px;
height: 120px;
--person-badge-font-size: 3em;
}
ha-list-item {
margin-top: 16px;
}
ha-button {
--mdc-typography-button-text-transform: none;
}
.forgot-password-container {
text-align: right;
padding: 8px 0 16px 0;
}
a.forgot-password {
color: var(--primary-color);
text-decoration: none;
font-size: 0.875rem;
}
button {
color: var(--primary-color);
background: none;
border: none;
padding: 8px;
font: inherit;
font-size: 0.875rem;
text-align: left;
cursor: pointer;
outline: none;
border-radius: 4px;
}
button:focus-visible {
background: rgba(var(--rgb-primary-color), 0.1);
}
</style>
${this._error
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
: nothing}
${this._step
? html`<ha-auth-flow
.clientId=${this.clientId}
.redirectUri=${this.redirectUri}
.oauth2State=${this.oauth2State}
.step=${this._step}
storeToken
.localize=${this.localize}
></ha-auth-flow>`
: this._selectedUser
? html`<div class="login-form">
<div class="person">
<ha-person-badge
.person=${this._persons[this._selectedUser]}
></ha-person-badge>
<p>${this._persons[this._selectedUser].name}</p>
</div>
<form>
<input
type="hidden"
name="username"
autocomplete="username"
readonly
.value=${this.authProvider.users[this._selectedUser]}
/>
<ha-auth-textfield
.type=${this._unmaskedPassword ? "text" : "password"}
autocomplete="current-password"
id="password"
name="password"
.label=${this.localize(
"ui.panel.page-authorize.form.providers.homeassistant.step.init.data.password"
)}
required
autoValidate
iconTrailing
validationMessage="Required"
>
<ha-icon-button
toggles
.label=${this.localize(
this._unmaskedPassword
? "ui.panel.page-authorize.form.hide_password"
: "ui.panel.page-authorize.form.show_password"
) ||
(this._unmaskedPassword
? "Hide password"
: "Show password")}
@click=${this._toggleUnmaskedPassword}
.path=${this._unmaskedPassword ? mdiEyeOff : mdiEye}
></ha-icon-button>
</ha-auth-textfield>
<div class="forgot-password-container">
<a
class="forgot-password"
href="https://www.home-assistant.io/docs/locked_out/#forgot-password"
target="_blank"
rel="noreferrer noopener"
>${this.localize(
"ui.panel.page-authorize.forgot_password"
)}</a
>
</div>
<div class="action space-between">
<mwc-button
@click=${this._restart}
.disabled=${this._submitting}
>
${this.localize("ui.panel.page-authorize.form.previous")}
</mwc-button>
<mwc-button
raised
@click=${this._handleSubmit}
.disabled=${this._submitting}
>
${this.localize("ui.panel.page-authorize.form.next")}
</mwc-button>
</div>
</form>
</div>`
: html`<h1>
${this.localize("ui.panel.page-authorize.welcome_home")}
</h1>
${this.localize("ui.panel.page-authorize.who_is_logging_in")}
<div
class="persons ${userIds.length < 10 && userIds.length % 4 === 1
? "force-small"
: ""}"
>
${userIds.map((userId) => {
const person = this._persons![userId];
return html`<div
class="person"
.userId=${userId}
@click=${this._personSelected}
@keyup=${this._handleKeyUp}
role="button"
tabindex="0"
>
<ha-person-badge .person=${person}></ha-person-badge>
<p>${person.name}</p>
</div>`;
})}
</div>
<div class="action">
<button @click=${this._otherLogin} tabindex="0">
${this.localize("ui.panel.page-authorize.other_options")}
</button>
</div>`}
`;
}
protected firstUpdated(changedProps: PropertyValues) {
super.firstUpdated(changedProps);
this.addEventListener("keypress", (ev) => {
if (ev.key === "Enter") {
this._handleSubmit(ev);
}
});
}
protected updated(changedProps: PropertyValues) {
if (changedProps.has("_selectedUser") && this._selectedUser) {
const passwordElement = this.renderRoot.querySelector(
"#password"
) as HaAuthTextField;
passwordElement.updateComplete.then(() => {
passwordElement.focus();
});
}
}
private async _load() {
try {
this._persons = await listUserPersons();
} catch {
this._persons = {};
this._error = "Failed to fetch persons";
}
}
private _restart() {
this._selectedUser = undefined;
this._error = undefined;
}
private _toggleUnmaskedPassword() {
this._unmaskedPassword = !this._unmaskedPassword;
}
private _handleKeyUp(ev: KeyboardEvent) {
if (ev.key === "Enter" || ev.key === " ") {
this._personSelected(ev);
}
}
private async _personSelected(ev) {
const userId = ev.currentTarget.userId;
if (
this.ownInstance &&
this.authProviders?.find((prv) => prv.type === "trusted_networks")
) {
try {
const flowResponse = await createLoginFlow(
this.clientId,
this.redirectUri,
["trusted_networks", null]
);
const data = await flowResponse.json();
if (data.type === "create_entry") {
redirectWithAuthCode(
this.redirectUri!,
data.result,
this.oauth2State,
true
);
return;
}
try {
if (!data.data_schema[0].options.find((opt) => opt[0] === userId)) {
throw new Error("User not available");
}
const postData = { user: userId, client_id: this.clientId };
const response = await submitLoginFlow(data.flow_id, postData);
if (response.ok) {
const result = await response.json();
if (result.type === "create_entry") {
redirectWithAuthCode(
this.redirectUri!,
result.result,
this.oauth2State,
true
);
return;
}
} else {
throw new Error("Invalid response");
}
} catch {
deleteLoginFlow(data.flow_id).catch((err) => {
// eslint-disable-next-line no-console
console.error("Error delete obsoleted auth flow", err);
});
}
} catch {
// Ignore
}
}
this._selectedUser = userId;
}
private async _handleSubmit(ev: Event) {
ev.preventDefault();
if (!this.authProvider?.users || !this._selectedUser) {
return;
}
this._error = undefined;
this._submitting = true;
const flowResponse = await createLoginFlow(
this.clientId,
this.redirectUri,
["homeassistant", null]
);
const data = await flowResponse.json();
const postData = {
username: this.authProvider.users[this._selectedUser],
password: (this.renderRoot.querySelector("#password") as HaAuthTextField)
.value,
client_id: this.clientId,
};
try {
const response = await submitLoginFlow(data.flow_id, postData);
const newStep = await response.json();
if (response.status === 403) {
this._error = newStep.message;
return;
}
if (newStep.type === "create_entry") {
redirectWithAuthCode(
this.redirectUri!,
newStep.result,
this.oauth2State,
true
);
return;
}
if (newStep.errors.base) {
this._error = this.localize(
`ui.panel.page-authorize.form.providers.homeassistant.error.${newStep.errors.base}`
);
throw new Error(this._error);
}
this._step = newStep;
} catch {
deleteLoginFlow(data.flow_id).catch((err) => {
// eslint-disable-next-line no-console
console.error("Error delete obsoleted auth flow", err);
});
if (!this._error) {
this._error = this.localize(
"ui.panel.page-authorize.form.unknown_error"
);
}
} finally {
this._submitting = false;
}
}
private _otherLogin() {
fireEvent(this, "default-login-flow", { value: true });
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-local-auth-flow": HaLocalAuthFlow;
}
interface HASSDomEvents {
"default-login-flow": { value: boolean };
}
}
+3
View File
@@ -8,6 +8,9 @@ import "../components/ha-list-item";
import { AuthProvider } from "../data/auth";
declare global {
interface HTMLElementTagNameMap {
"ha-pick-auth-provider": HaPickAuthProvider;
}
interface HASSDomEvents {
"pick-auth-provider": AuthProvider;
}
+6
View File
@@ -29,6 +29,7 @@ import {
mdiFlash,
mdiFlower,
mdiFormatListBulleted,
mdiFormatListCheckbox,
mdiFormTextbox,
mdiGauge,
mdiGoogleAssistant,
@@ -64,6 +65,7 @@ import {
mdiTransmissionTower,
mdiWater,
mdiWaterPercent,
mdiWeatherPartlyCloudy,
mdiWeatherPouring,
mdiWeatherRainy,
mdiWeatherWindy,
@@ -128,6 +130,7 @@ export const FIXED_DOMAIN_ICONS = {
updater: mdiCloudUpload,
vacuum: mdiRobotVacuum,
wake_word: mdiChatSleep,
weather: mdiWeatherPartlyCloudy,
zone: mdiMapMarkerRadius,
};
@@ -166,6 +169,7 @@ export const FIXED_DEVICE_CLASS_ICONS = {
precipitation_intensity: mdiWeatherPouring,
pressure: mdiGauge,
reactive_power: mdiFlash,
shopping_List: mdiFormatListCheckbox,
signal_strength: mdiWifi,
sound_pressure: mdiEarHearing,
speed: mdiSpeedometer,
@@ -250,6 +254,7 @@ export const DOMAINS_INPUT_ROW = [
"text",
"time",
"vacuum",
"valve",
];
/** States that we consider "off". */
@@ -268,6 +273,7 @@ export const DOMAINS_TOGGLE = new Set([
"group",
"automation",
"humidifier",
"valve",
]);
/** Domains that have a dynamic entity image / picture. */
+13 -12
View File
@@ -1,7 +1,8 @@
import { HassConfig } from "home-assistant-js-websocket";
import memoizeOne from "memoize-one";
import { FrontendLocaleData, DateFormat } from "../../data/translation";
import { DateFormat, FrontendLocaleData } from "../../data/translation";
import "../../resources/intl-polyfill";
import { resolveTimeZone } from "./resolve-time-zone";
// Tuesday, August 10
export const formatDateWeekdayDay = (
@@ -16,7 +17,7 @@ const formatDateWeekdayDayMem = memoizeOne(
weekday: "long",
month: "long",
day: "numeric",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
})
);
@@ -33,7 +34,7 @@ const formatDateMem = memoizeOne(
year: "numeric",
month: "long",
day: "numeric",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
})
);
@@ -50,7 +51,7 @@ const formatDateShortMem = memoizeOne(
year: "numeric",
month: "short",
day: "numeric",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
})
);
@@ -105,7 +106,7 @@ const formatDateNumericMem = memoizeOne(
year: "numeric",
month: "numeric",
day: "numeric",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
});
}
@@ -113,7 +114,7 @@ const formatDateNumericMem = memoizeOne(
year: "numeric",
month: "numeric",
day: "numeric",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
});
}
);
@@ -130,7 +131,7 @@ const formatDateVeryShortMem = memoizeOne(
new Intl.DateTimeFormat(locale.language, {
day: "numeric",
month: "short",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
})
);
@@ -146,7 +147,7 @@ const formatDateMonthYearMem = memoizeOne(
new Intl.DateTimeFormat(locale.language, {
month: "long",
year: "numeric",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
})
);
@@ -161,7 +162,7 @@ const formatDateMonthMem = memoizeOne(
(locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(locale.language, {
month: "long",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
})
);
@@ -176,7 +177,7 @@ const formatDateYearMem = memoizeOne(
(locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(locale.language, {
year: "numeric",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
})
);
@@ -191,7 +192,7 @@ const formatDateWeekdayMem = memoizeOne(
(locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(locale.language, {
weekday: "long",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
})
);
@@ -206,6 +207,6 @@ const formatDateWeekdayShortMem = memoizeOne(
(locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(locale.language, {
weekday: "short",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
})
);
+5 -4
View File
@@ -4,6 +4,7 @@ import { FrontendLocaleData } from "../../data/translation";
import "../../resources/intl-polyfill";
import { formatDateNumeric } from "./format_date";
import { formatTime } from "./format_time";
import { resolveTimeZone } from "./resolve-time-zone";
import { useAmPm } from "./use_am_pm";
// August 9, 2021, 8:23 AM
@@ -22,7 +23,7 @@ const formatDateTimeMem = memoizeOne(
hour: useAmPm(locale) ? "numeric" : "2-digit",
minute: "2-digit",
hourCycle: useAmPm(locale) ? "h12" : "h23",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
})
);
@@ -42,7 +43,7 @@ const formatShortDateTimeWithYearMem = memoizeOne(
hour: useAmPm(locale) ? "numeric" : "2-digit",
minute: "2-digit",
hourCycle: useAmPm(locale) ? "h12" : "h23",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
})
);
@@ -61,7 +62,7 @@ const formatShortDateTimeMem = memoizeOne(
hour: useAmPm(locale) ? "numeric" : "2-digit",
minute: "2-digit",
hourCycle: useAmPm(locale) ? "h12" : "h23",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
})
);
@@ -82,7 +83,7 @@ const formatDateTimeWithSecondsMem = memoizeOne(
minute: "2-digit",
second: "2-digit",
hourCycle: useAmPm(locale) ? "h12" : "h23",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
})
);
+5 -4
View File
@@ -2,6 +2,7 @@ import { HassConfig } from "home-assistant-js-websocket";
import memoizeOne from "memoize-one";
import { FrontendLocaleData } from "../../data/translation";
import "../../resources/intl-polyfill";
import { resolveTimeZone } from "./resolve-time-zone";
import { useAmPm } from "./use_am_pm";
// 9:15 PM || 21:15
@@ -17,7 +18,7 @@ const formatTimeMem = memoizeOne(
hour: "numeric",
minute: "2-digit",
hourCycle: useAmPm(locale) ? "h12" : "h23",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
})
);
@@ -35,7 +36,7 @@ const formatTimeWithSecondsMem = memoizeOne(
minute: "2-digit",
second: "2-digit",
hourCycle: useAmPm(locale) ? "h12" : "h23",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
})
);
@@ -53,7 +54,7 @@ const formatTimeWeekdayMem = memoizeOne(
hour: useAmPm(locale) ? "numeric" : "2-digit",
minute: "2-digit",
hourCycle: useAmPm(locale) ? "h12" : "h23",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
})
);
@@ -71,6 +72,6 @@ const formatTime24hMem = memoizeOne(
hour: "numeric",
minute: "2-digit",
hour12: false,
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
timeZone: resolveTimeZone(locale.time_zone, serverTimeZone),
})
);
+1
View File
@@ -1,4 +1,5 @@
import memoizeOne from "memoize-one";
import "../../resources/intl-polyfill";
export const localizeWeekdays = memoizeOne(
(language: string, short: boolean): string[] => {
+15
View File
@@ -0,0 +1,15 @@
import { TimeZone } from "../../data/translation";
// Browser time zone can be determined from Intl, with fallback to UTC for polyfill or no support.
// Alternatively, we could fallback to a fixed offset IANA zone (e.g. "Etc/GMT+5") using
// Date.prototype.getTimeOffset(), but IANA only has whole hour Etc zones, and problems
// might occur with relative time due to DST.
// Use optional chain instead of polyfill import since polyfill will always return UTC
export const LOCAL_TIME_ZONE =
Intl.DateTimeFormat?.().resolvedOptions?.().timeZone ?? "UTC";
// Pick time zone based on user profile option. Core zone is used when local cannot be determined.
export const resolveTimeZone = (option: TimeZone, serverTimeZone: string) =>
option === TimeZone.local && LOCAL_TIME_ZONE !== "UTC"
? LOCAL_TIME_ZONE
: serverTimeZone;
+3 -2
View File
@@ -79,7 +79,8 @@ export const computeStateDisplayFromEntityAttributes = (
if (
attributes.device_class === "duration" &&
attributes.unit_of_measurement &&
UNIT_TO_MILLISECOND_CONVERT[attributes.unit_of_measurement]
UNIT_TO_MILLISECOND_CONVERT[attributes.unit_of_measurement] &&
entity?.display_precision === undefined
) {
try {
return formatDuration(state, attributes.unit_of_measurement);
@@ -113,7 +114,7 @@ export const computeStateDisplayFromEntityAttributes = (
const unit = attributes.unit_of_measurement;
if (unit) {
return `${value}${blankBeforeUnit(unit)}${unit}`;
return `${value}${blankBeforeUnit(unit, locale)}${unit}`;
}
return value;
+1
View File
@@ -50,6 +50,7 @@ export const FIXED_DOMAIN_STATES = {
timer: ["active", "idle", "paused"],
update: ["on", "off"],
vacuum: ["cleaning", "docked", "error", "idle", "paused", "returning"],
valve: ["closed", "closing", "open", "opening"],
weather: [
"clear-night",
"cloudy",
@@ -4,7 +4,7 @@ import { FrontendLocaleData } from "../../data/translation";
export const blankBeforePercent = (
localeOptions: FrontendLocaleData
): string => {
switch (localeOptions?.language) {
switch (localeOptions.language) {
case "cz":
case "de":
case "fi":
+1 -1
View File
@@ -3,7 +3,7 @@ import { blankBeforePercent } from "./blank_before_percent";
export const blankBeforeUnit = (
unit: string,
localeOptions?: FrontendLocaleData
localeOptions: FrontendLocaleData | undefined
): string => {
if (unit === "°") {
return "";
+6 -4
View File
@@ -1,6 +1,8 @@
import { mainWindow } from "../dom/get_main_window";
export const extractSearchParamsObject = (): Record<string, string> => {
const query = {};
const searchParams = new URLSearchParams(location.search);
const searchParams = new URLSearchParams(mainWindow.location.search);
for (const [key, value] of searchParams.entries()) {
query[key] = value;
}
@@ -8,7 +10,7 @@ export const extractSearchParamsObject = (): Record<string, string> => {
};
export const extractSearchParam = (param: string): string | null => {
const urlParams = new URLSearchParams(window.location.search);
const urlParams = new URLSearchParams(mainWindow.location.search);
return urlParams.get(param);
};
@@ -21,7 +23,7 @@ export const createSearchParam = (params: Record<string, string>): string => {
};
export const addSearchParam = (params: Record<string, string>): string => {
const urlParams = new URLSearchParams(window.location.search);
const urlParams = new URLSearchParams(mainWindow.location.search);
Object.entries(params).forEach(([key, value]) => {
urlParams.set(key, value);
});
@@ -29,7 +31,7 @@ export const addSearchParam = (params: Record<string, string>): string => {
};
export const removeSearchParam = (param: string): string => {
const urlParams = new URLSearchParams(window.location.search);
const urlParams = new URLSearchParams(mainWindow.location.search);
urlParams.delete(param);
return urlParams.toString();
};
+53
View File
@@ -0,0 +1,53 @@
import { ItemPath } from "../../types";
function findNestedItem(
obj: any,
path: ItemPath,
createNonExistingPath?: boolean
): any {
return path.reduce((ac, p, index, array) => {
if (ac === undefined) return undefined;
if (!ac[p] && createNonExistingPath) {
const nextP = array[index + 1];
// Create object or array depending on next path
if (nextP === undefined || typeof nextP === "number") {
ac[p] = [];
} else {
ac[p] = {};
}
}
return ac[p];
}, obj);
}
export function nestedArrayMove<T>(
obj: T | T[],
oldIndex: number,
newIndex: number,
oldPath?: ItemPath,
newPath?: ItemPath
): T | T[] {
const newObj = Array.isArray(obj) ? [...obj] : { ...obj };
const from = oldPath ? findNestedItem(newObj, oldPath) : newObj;
const to = newPath ? findNestedItem(newObj, newPath, true) : newObj;
if (!Array.isArray(from) || !Array.isArray(to)) {
return obj;
}
const item = from.splice(oldIndex, 1)[0];
to.splice(newIndex, 0, item);
return newObj;
}
export function arrayMove<T = any>(
array: T[],
oldIndex: number,
newIndex: number
): T[] {
const newArray = [...array];
const [item] = newArray.splice(oldIndex, 1);
newArray.splice(newIndex, 0, item);
return newArray;
}
@@ -23,7 +23,7 @@ export class StateHistoryChartTimeline extends LitElement {
@property({ attribute: false }) public data: TimelineEntity[] = [];
@property() public narrow!: boolean;
@property({ type: Boolean }) public narrow = false;
@property() public names?: Record<string, string>;
+2 -2
View File
@@ -52,7 +52,7 @@ export class StateHistoryCharts extends LitElement {
@property({ attribute: false }) public historyData!: HistoryResult;
@property() public narrow!: boolean;
@property({ type: Boolean }) public narrow = false;
@property() public names?: Record<string, string>;
@@ -65,7 +65,7 @@ export class StateHistoryCharts extends LitElement {
@property({ type: Boolean, attribute: "up-to-now" }) public upToNow = false;
@property() public hoursToShow?: number;
@property({ type: Number }) public hoursToShow?: number;
@property({ type: Boolean }) public showNames = true;
+1 -1
View File
@@ -300,7 +300,7 @@ export class HaDataTable extends LitElement {
};
return html`
<div
aria-label=${column.label}
aria-label=${ifDefined(column.label)}
class="mdc-data-table__header-cell ${classMap(classes)}"
style=${column.width
? styleMap({
+2 -2
View File
@@ -88,9 +88,9 @@ export class HaDevicePicker extends LitElement {
@property() public entityFilter?: HaDevicePickerEntityFilterFunc;
@property({ type: Boolean }) public disabled?: boolean;
@property({ type: Boolean }) public disabled = false;
@property({ type: Boolean }) public required?: boolean;
@property({ type: Boolean }) public required = false;
@state() private _opened?: boolean;
+2 -2
View File
@@ -16,9 +16,9 @@ class HaDevicesPicker extends LitElement {
@property() public helper?: string;
@property({ type: Boolean }) public disabled?: boolean;
@property({ type: Boolean }) public disabled = false;
@property({ type: Boolean }) public required?: boolean;
@property({ type: Boolean }) public required = false;
/**
* Show entities from specific domains.
+2 -2
View File
@@ -14,9 +14,9 @@ class HaEntitiesPickerLight extends LitElement {
@property({ type: Array }) public value?: string[];
@property({ type: Boolean }) public disabled?: boolean;
@property({ type: Boolean }) public disabled = false;
@property({ type: Boolean }) public required?: boolean;
@property({ type: Boolean }) public required = false;
@property() public helper?: string;
+2 -2
View File
@@ -41,9 +41,9 @@ export class HaEntityPicker extends LitElement {
@property({ type: Boolean }) public autofocus = false;
@property({ type: Boolean }) public disabled?: boolean;
@property({ type: Boolean }) public disabled = false;
@property({ type: Boolean }) public required?: boolean;
@property({ type: Boolean }) public required = false;
@property({ type: Boolean, attribute: "allow-custom-entity" })
public allowCustomEntity;
+14 -6
View File
@@ -1,18 +1,18 @@
import { mdiFlash, mdiFlashOff } from "@mdi/js";
import { HassEntity } from "home-assistant-js-websocket";
import {
css,
CSSResultGroup,
html,
LitElement,
PropertyValues,
TemplateResult,
css,
html,
} from "lit";
import { property, state } from "lit/decorators";
import { customElement, property, state } from "lit/decorators";
import { STATES_OFF } from "../../common/const";
import { computeStateDomain } from "../../common/entity/compute_state_domain";
import { computeStateName } from "../../common/entity/compute_state_name";
import { isUnavailableState, UNAVAILABLE, UNKNOWN } from "../../data/entity";
import { UNAVAILABLE, UNKNOWN, isUnavailableState } from "../../data/entity";
import { forwardHaptic } from "../../data/haptics";
import { HomeAssistant } from "../../types";
import "../ha-formfield";
@@ -24,11 +24,12 @@ const isOn = (stateObj?: HassEntity) =>
!STATES_OFF.includes(stateObj.state) &&
!isUnavailableState(stateObj.state);
@customElement("ha-entity-toggle")
export class HaEntityToggle extends LitElement {
// hass is not a property so that we only re-render on stateObj changes
public hass?: HomeAssistant;
@property() public stateObj?: HassEntity;
@property({ attribute: false }) public stateObj?: HassEntity;
@property() public label?: string;
@@ -128,6 +129,9 @@ export class HaEntityToggle extends LitElement {
} else if (stateDomain === "cover") {
serviceDomain = "cover";
service = turnOn ? "open_cover" : "close_cover";
} else if (stateDomain === "valve") {
serviceDomain = "valve";
service = turnOn ? "open_valve" : "close_valve";
} else if (stateDomain === "group") {
serviceDomain = "homeassistant";
service = turnOn ? "turn_on" : "turn_off";
@@ -175,4 +179,8 @@ export class HaEntityToggle extends LitElement {
}
}
customElements.define("ha-entity-toggle", HaEntityToggle);
declare global {
interface HTMLElementTagNameMap {
"ha-entity-toggle": HaEntityToggle;
}
}
@@ -61,7 +61,7 @@ export class HaStateLabelBadge extends LitElement {
@property() public image?: string;
@property() public showName?: boolean;
@property({ type: Boolean }) public showName = false;
@state() private _timerTimeRemaining?: number;
+8 -4
View File
@@ -44,7 +44,7 @@ export class HaStatisticPicker extends LitElement {
@property({ type: Array }) public statisticIds?: StatisticsMetaData[];
@property({ type: Boolean }) public disabled?: boolean;
@property({ type: Boolean }) public disabled = false;
/**
* Show only statistics natively stored with these units of measurements.
@@ -129,7 +129,8 @@ export class HaStatisticPicker extends LitElement {
includeUnitClass?: string | string[],
includeDeviceClass?: string | string[],
entitiesOnly?: boolean,
excludeStatistics?: string[]
excludeStatistics?: string[],
value?: string
): StatisticItem[] => {
if (!statisticIds.length) {
return [
@@ -176,6 +177,7 @@ export class HaStatisticPicker extends LitElement {
statisticIds.forEach((meta) => {
if (
excludeStatistics &&
meta.statistic_id !== value &&
excludeStatistics.includes(meta.statistic_id)
) {
return;
@@ -258,7 +260,8 @@ export class HaStatisticPicker extends LitElement {
this.includeUnitClass,
this.includeDeviceClass,
this.entitiesOnly,
this.excludeStatistics
this.excludeStatistics,
this.value
);
} else {
this.updateComplete.then(() => {
@@ -268,7 +271,8 @@ export class HaStatisticPicker extends LitElement {
this.includeUnitClass,
this.includeDeviceClass,
this.entitiesOnly,
this.excludeStatistics
this.excludeStatistics,
this.value
);
});
}
@@ -1,5 +1,6 @@
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import { repeat } from "lit/directives/repeat";
import { fireEvent } from "../../common/dom/fire_event";
import type { ValueChangedEvent, HomeAssistant } from "../../types";
import "./ha-statistic-picker";
@@ -81,7 +82,9 @@ class HaStatisticsPicker extends LitElement {
: this.statisticTypes;
return html`
${this._currentStatistics.map(
${repeat(
this._currentStatistics,
(statisticId) => statisticId,
(statisticId) => html`
<div>
<ha-statistic-picker
@@ -94,6 +97,7 @@ class HaStatisticsPicker extends LitElement {
.statisticTypes=${includeStatisticTypesCurrent}
.statisticIds=${this.statisticIds}
.label=${this.pickedStatisticLabel}
.excludeStatistics=${this.value}
.allowCustomEntity=${this.allowCustomEntity}
@value-changed=${this._statisticChanged}
></ha-statistic-picker>
@@ -110,6 +114,7 @@ class HaStatisticsPicker extends LitElement {
.statisticTypes=${this.statisticTypes}
.statisticIds=${this.statisticIds}
.label=${this.pickStatisticLabel}
.excludeStatistics=${this.value}
.allowCustomEntity=${this.allowCustomEntity}
@value-changed=${this._addStatistic}
></ha-statistic-picker>

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