Compare commits

...

288 Commits

Author SHA1 Message Date
Bram Kragten
f0341f28ab Merge branch 'rc' 2025-05-07 13:14:55 +02:00
Paul Bottein
603663e0cc Fix badge overlay in scrolling mode (#25352)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2025-05-07 13:14:21 +02:00
Bram Kragten
80dddc9eef Only enable drag scroll controller when needed (#25351) 2025-05-07 13:14:20 +02:00
Bram Kragten
8494d0542e Bumped version to 20250507.0 2025-05-07 10:45:48 +02:00
Wendelin
467a5bef0b Fix data-table search clear button alignment (#25348) 2025-05-07 10:45:19 +02:00
Petar Petrov
24736e36ff Set <=0 chart values to null so they render as gaps on a log graph (#25347) 2025-05-07 10:45:18 +02:00
Paulus Schoutsen
604c00d772 Update network browser descriptions (#25345) 2025-05-07 10:45:17 +02:00
Bram Kragten
12bbba1bff fix height of stats graph card in section (#25344) 2025-05-07 10:45:16 +02:00
Bram Kragten
e3221ad4ee Merge branch 'rc' 2025-05-06 20:46:09 +02:00
Bram Kragten
7d3a7fa1db Bumped version to 20250506.0 2025-05-06 20:45:47 +02:00
Paul Bottein
5e67bf1fa7 Fix outlined icon button style (#25340) 2025-05-06 20:45:16 +02:00
Paul Bottein
7147c7578d Use right theme variable for dashboard tab color in edit mode (#25339) 2025-05-06 20:45:16 +02:00
Paul Bottein
90710fedf2 Simplify entity combo-box code (#25338) 2025-05-06 20:45:15 +02:00
Paul Bottein
9629159ef1 Use middle dot 00B7 as separator (#25336) 2025-05-06 20:45:14 +02:00
Paul Bottein
bfac6e1516 Add covers to overview view for area strategy (#25334) 2025-05-06 20:45:13 +02:00
Wendelin
7c288d1769 Fix sidebar item text width (#25332)
* Fix sidebar item text width to utilize full available space

* Update src/components/ha-sidebar.ts

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

---------

Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2025-05-06 20:45:12 +02:00
Paul Bottein
39119eeb2a Align side bar title with items (#25330) 2025-05-06 20:45:11 +02:00
Wendelin
9c16ce3342 Fix flow form padding end (#25328)
* Fix flow form padding end

* Use more end padding if docs are present
2025-05-06 20:45:10 +02:00
Paulus Schoutsen
3595fab5cb Show voice ID in TTS media browser (#25324)
* Show voice ID in TTS media browser

* Apply suggestions from code review

Co-authored-by: Paul Bottein <paul.bottein@gmail.com>

* Add copy button

* Now copy correct clipboard icon

* Improve styling

* GAP

---------

Co-authored-by: Paul Bottein <paul.bottein@gmail.com>
2025-05-06 20:45:09 +02:00
Wendelin
78b2d17f10 Add custom retention info to backup locations (#25318)
* Add retention messages to backup locations

* Fix mobile

* Use join
2025-05-06 20:45:09 +02:00
Paul Bottein
7b8b8f9d0b 20250502.1 (#25323) 2025-05-05 20:14:29 +02:00
Paul Bottein
b7f866faff Bumped version to 20250502.1 2025-05-05 20:12:59 +02:00
Paulus Schoutsen
37671fd613 Populate integration domain My link (#25322)
* Populate integration domain My link

* break out of loop

* Actually just return from function

* Consolidate code
2025-05-05 20:12:06 +02:00
Paulus Schoutsen
92905c1433 Clean up network browser nav (#25321)
* Clean up network browser nav

* Add ha-md-list
2025-05-05 20:12:05 +02:00
Paulus Schoutsen
cb7251cb5e Reorder my links (#25319) 2025-05-05 20:12:04 +02:00
Paul Bottein
44485c0de4 Do not display no areas in entity pickers (#25317) 2025-05-05 20:12:03 +02:00
Paul Bottein
1191a09576 Use new entity naming in card entity picker (#25316) 2025-05-05 20:12:03 +02:00
karwosts
c178488aac Add energy hourly calculations to CSV report (#25315) 2025-05-05 20:12:02 +02:00
Wendelin
9f6463eec0 Fix zwave add device LR/mesh icons (#25313)
Fix zwave LR/mesh icons
2025-05-05 20:12:01 +02:00
Wendelin
70fef59401 Fix options and repair flow success (#25312) 2025-05-05 20:12:00 +02:00
Wendelin
3e053e07c6 Fix selected entity overflow (#25311) 2025-05-05 20:11:59 +02:00
Wendelin
376cac6002 Fix select entity change (#25310) 2025-05-05 20:11:58 +02:00
Paul Bottein
5cd68301ed Fix pasting yaml in automation code editor (#25309)
Fix pasting yaml in code editor
2025-05-05 20:11:57 +02:00
Wendelin
3121721ac7 Revert "Use md-select for entity-row and state-card" (#25308)
Revert "Use md-select for entity-row and state-card (#25307)"

This reverts commit 3c9dce20e2.
2025-05-05 20:11:56 +02:00
Wendelin
868daf692d Use md-select for entity-row and state-card (#25307) 2025-05-05 20:11:56 +02:00
Wendelin
75e9ac9e73 Fix flow-form header (#25305) 2025-05-05 20:11:55 +02:00
Paulus Schoutsen
f6e36f2038 Add profile security link to My Home Assistant (#25303) 2025-05-05 20:11:54 +02:00
Bram Kragten
55770f3e02 Fix display of disabled items in traces (#25293) 2025-05-05 20:11:53 +02:00
Bram Kragten
cfc7f91f03 Fix select entity row opening more info on select (#25292) 2025-05-05 20:11:52 +02:00
Jan-Philipp Benecke
74488c0b96 Use new entity picker style in quick bar (#25265)
* Use new entity picker style in quick bar

* Cleanup

* Add missing no area

* Process code review
2025-05-05 20:11:51 +02:00
Bram Kragten
1154d1769d Bumped version to 20250502.0 2025-05-02 21:34:23 +03:00
Bram Kragten
a820cd4576 Fix decorators with properties (#25282)
* Fix decorators with properties

* Green build

---------

Co-authored-by: Simon Lamon <32477463+silamon@users.noreply.github.com>
2025-05-02 21:33:56 +03:00
Bram Kragten
678a8a85cb Fix alignment of ha-labeled-slider (#25279) 2025-05-02 21:33:55 +03:00
karwosts
358e450e60 Fix disabled language picker (#25278) 2025-05-02 21:33:54 +03:00
Jan-Philipp Benecke
32acef8fad Add save shortcut to shortcuts dialog (#25271) 2025-05-02 21:33:53 +03:00
J. Nick Koston
fae619085c Add my links for the Bluetooth monitors (#25270)
The plan is to link these in the Bluetooth docs for help debugging
2025-05-02 21:33:52 +03:00
Paulus Schoutsen
5d89563aa5 Import missing components on init page (#25269) 2025-05-02 21:33:52 +03:00
Bram Kragten
d7dd11ba7f Improve error handling in automation i18n (#25266) 2025-05-02 21:33:51 +03:00
Jan-Philipp Benecke
4624cc609f Always show backup location retention settings (#25261)
Always show backup location retention settings
2025-05-02 21:33:50 +03:00
karwosts
f24b6a4cb1 Fix typo in energy calculation (#25259)
* New energy calculation

* more tests and stricter tests. change priority order

* more test and fix error
2025-05-02 21:33:49 +03:00
Jan-Philipp Benecke
2b06742bb9 Hide the tab when view is a subview (#25256) 2025-05-02 21:33:48 +03:00
Jan-Philipp Benecke
9e5b7462af Add ? as shortcut for shortcuts dialog (#25253)
Bind shortcuts dialog to `?` key
2025-05-02 21:33:47 +03:00
J. Nick Koston
a544ff4c8a Improve message when no discovery data is found (#25252)
* Improve message when no discovery data is found

It was pointed out its a bit confusing when a device has not been
discovered yet for the discovery/network browser panels as we
only said there was no data. Give the user a better hint
as to why there is no data.

* Improve message when no discovery data is found

It was pointed out its a bit confusing when a device has not been
discovered yet for the discovery/network browser panels as we
only said there was no data. Give the user a better hint
as to why there is no data.

* Improve message when no discovery data is found

It was pointed out its a bit confusing when a device has not been
discovered yet for the discovery/network browser panels as we
only said there was no data. Give the user a better hint
as to why there is no data.

* Improve message when no discovery data is found

It was pointed out its a bit confusing when a device has not been
discovered yet for the discovery/network browser panels as we
only said there was no data. Give the user a better hint
as to why there is no data.
2025-05-02 21:33:46 +03:00
J. Nick Koston
b81d2013dc Fix formatting of mac address fields in device info (#25251)
Previous change lost the `:` seperator, and unexpectedly MAC became
title case instead of MAC when dhcp is loaded.
2025-05-02 21:33:45 +03:00
J. Nick Koston
9b7e2886b6 Better explain when DHCP discovery data will be available (#25250)
It was pointed out that users likely may not know what DHCP is
and wonder why the data is not available yet.
2025-05-02 21:33:44 +03:00
karwosts
69eaf178ca New energy calculation formula (#25242)
* New energy calculation

* more tests and stricter tests. change priority order
2025-05-02 21:33:44 +03:00
Yosi Levy
1a14511fa6 Various RTL fixes (#25231) 2025-05-02 21:33:43 +03:00
Paul Bottein
e517175f68 20250430.2 (#25246) 2025-04-30 17:52:11 +02:00
Paul Bottein
ee9cbf7370 Bumped version to 20250430.2 2025-04-30 17:50:44 +02:00
Bram Kragten
efd7b380a9 Handle errrors/wrong values on paste (#25245) 2025-04-30 17:49:56 +02:00
Paul Bottein
46cc254f77 Use code font family variable in combo-box (#25243) 2025-04-30 17:49:55 +02:00
Paul Bottein
d996ba818f 20250430.1 (#25244) 2025-04-30 16:10:12 +02:00
Paul Bottein
e5f41ceb3e Bumped version to 20250430.1 2025-04-30 16:08:42 +02:00
Bram Kragten
2e4ce71d06 Improve trigger condition check on paste (#25241) 2025-04-30 16:08:03 +02:00
Bram Kragten
50e39de974 Allow pasting more script config (#25240)
* Allow pasting more script config

* Update manual-script-editor.ts
2025-04-30 16:08:02 +02:00
Bram Kragten
1ba941282c Allow pasting more automation config formats (#25239) 2025-04-30 16:08:01 +02:00
J. Nick Koston
b656ddc1f0 Add DHCP Browser entry point to network (#25235)
* Add DHCP Browser entry point to network

* lint
2025-04-30 16:08:00 +02:00
Paul Bottein
a699149388 20250430.0 (#25237) 2025-04-30 13:10:20 +02:00
Paul Bottein
0aeb8fa75c Merge branch 'rc' into dev 2025-04-30 12:53:10 +02:00
Paul Bottein
456a44fdfd Bumped version to 20250430.0 2025-04-30 12:35:26 +02:00
Paul Bottein
53a0b311de Use list item for statistic picker (#25228)
* Use list item for statistic picker

* Use item interface

* Fix icon
2025-04-30 11:40:56 +03:00
Petar Petrov
ded5ade0f2 Grouping options for hui-energy-sankey-card (#25207)
* Grouping options for hui-energy-sankey-card

* use getEntityContext for area/floor

* Update rspack monorepo to v1.3.7 (#25206)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Update vaadinWebComponents monorepo to v24.7.4 (#25204)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Add typography styles (#25171)

* Add typoghrapy styles

* Split styles

* Fix duplicated html

* remove unused paper vars

* Fix vars

* Add vars autocompletion extension

* Fix css syntax highlighting

* History tooltip RTL fix (#24917)

* History tooltip RTL fix

* Fix background color

* Render todo items with no state, change look of read only items (#24529)

* Render todo items with no state, change look of read only items

Co-authored-by: Erik Montnemery <erik@montnemery.com>
Co-authored-by: Wendelin <12148533+wendevlin@users.noreply.github.com>
Co-authored-by: Wendelin <w@pe8.at>

* Themeable badge icon size and badge font size (#25185)

Co-authored-by: Wendelin <12148533+wendevlin@users.noreply.github.com>

* Add context to config update entries (#25208)

* Add context to config update entries

* Add no area

* import fix

* import fix

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Wendelin <12148533+wendevlin@users.noreply.github.com>
Co-authored-by: Yosi Levy <37745463+yosilevy@users.noreply.github.com>
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
Co-authored-by: Erik Montnemery <erik@montnemery.com>
Co-authored-by: Wendelin <w@pe8.at>
Co-authored-by: emufan <emufan@users.noreply.github.com>
2025-04-30 11:00:51 +03:00
J. Nick Koston
5d2d6dcd6c Make name a top level field for the SSDP panel (#25232)
* Make name a top level field for the SSDP panel

* Make name a top level field for the SSDP panel
2025-04-30 09:39:01 +02:00
karwosts
92353ebed5 Centralize energy usage calculations (#25197)
* Centralize energy usage calculations

* addl tests

* test organization

* Update src/data/energy.ts

Co-authored-by: Petar Petrov <MindFreeze@users.noreply.github.com>

* Centralize more equations

---------

Co-authored-by: Petar Petrov <MindFreeze@users.noreply.github.com>
2025-04-30 06:57:26 +03:00
J. Nick Koston
bc582db7fc Add initial SSDP discovery panel (#25217)
* Add initial SSDP discovery panel
2025-04-29 21:46:56 +02:00
Jan-Philipp Benecke
ab415188ba Allow pasting YAML in automation/script editor directly (#24838)
* Allow pasting YAML in automation/script editor directly

* Highlight pasted items

* Change highlighting

* Also reset in script editor

* Show dialog when pasting to changed automation/script

* Add shortcuts to shortcuts dialog

* Use translated shortcut

* Change timeout and clear on save

* Fix imports

* Process code review

* Move paste logic to manual-*-editor
2025-04-29 18:28:07 +02:00
Wendelin
29c11978b3 Rename font-weight-semibold to medium (#25224) 2025-04-29 16:50:30 +02:00
Paul Bottein
574f9e8936 Add message when no entities found in the entity picker (#25222) 2025-04-29 12:34:09 +00:00
Wendelin
fddc00bfab Change --ha-font-weight-bold (#25221)
* Use font-weight vars in roboto

* Revert roboto usage of vars
2025-04-29 14:24:06 +02:00
Paul Bottein
ff5cbb0613 Revert "Add message in picker when no entities found"
This reverts commit 498d933c06.
2025-04-29 14:22:26 +02:00
Paul Bottein
498d933c06 Add message in picker when no entities found 2025-04-29 14:14:38 +02:00
Paul Bottein
f9fbb254bf Use list item for entity picker (#25176)
Co-authored-by: Wendelin <12148533+wendevlin@users.noreply.github.com>
Co-authored-by: Wendelin <w@pe8.at>
2025-04-29 13:30:32 +02:00
Paul Bottein
536602580d Remove duplicated context files (#25212) 2025-04-29 11:51:05 +02:00
Wendelin
c111bf1062 Add ha-badge docs to gallery (#25218) 2025-04-29 11:37:56 +02:00
Simon Lamon
0242fbc6f8 Guard against unknown entities in automation compare functions (#25213)
Guard against unknown entities
2025-04-29 08:24:49 +03:00
Wendelin
f65a0ef4f7 Add context to config update entries (#25208)
* Add context to config update entries

* Add no area
2025-04-28 18:43:10 +02:00
emufan
92521d4565 Themeable badge icon size and badge font size (#25185)
Co-authored-by: Wendelin <12148533+wendevlin@users.noreply.github.com>
2025-04-28 14:20:05 +00:00
Bram Kragten
66dbafb5f5 Render todo items with no state, change look of read only items (#24529)
* Render todo items with no state, change look of read only items

Co-authored-by: Erik Montnemery <erik@montnemery.com>
Co-authored-by: Wendelin <12148533+wendevlin@users.noreply.github.com>
Co-authored-by: Wendelin <w@pe8.at>
2025-04-28 16:06:02 +02:00
Yosi Levy
7c46d2d2f4 History tooltip RTL fix (#24917)
* History tooltip RTL fix

* Fix background color
2025-04-28 16:30:26 +03:00
Wendelin
ca642d46cc Add typography styles (#25171)
* Add typoghrapy styles

* Split styles

* Fix duplicated html

* remove unused paper vars

* Fix vars

* Add vars autocompletion extension

* Fix css syntax highlighting
2025-04-28 16:04:47 +03:00
renovate[bot]
9a52185e13 Update vaadinWebComponents monorepo to v24.7.4 (#25204)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-28 14:54:24 +03:00
renovate[bot]
39a73774b0 Update rspack monorepo to v1.3.7 (#25206)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-28 14:53:45 +03:00
Wendelin
b25b170539 Update ha cloud backup info translation (#25203)
* Update ha cloud backup info translation

* Update src/translations/en.json
2025-04-28 12:15:18 +02:00
Bram Kragten
6442606fc5 Wait for backup integration when doing a restore (#25188)
Co-authored-by: Wendelin <w@pe8.at>
2025-04-28 07:51:58 +00:00
Wendelin
1b79869c87 Backup retention by location (#25144) 2025-04-28 09:24:34 +02:00
Bram Kragten
672fbc6007 Fix storage decorator timing (#25199) 2025-04-28 08:46:13 +03:00
renovate[bot]
e1899836bf Update dependency marked to v15.0.11 (#25202)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-28 08:28:34 +03:00
Said Tahsin Dane
e90967d200 Scripts - Fix the run button to check if the script has fields (#25156)
* Fix the run button to check if the script has fields

* Used a more straightforward function to check fields instead of an async call
2025-04-27 16:17:55 +00:00
renovate[bot]
631bfe46ba Update dependency @codemirror/view to v6.36.6 (#25194)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-27 19:06:56 +03:00
Bram Kragten
a5762f07ac Rename entity ids when updating device name during config flow (#25186)
* Rename entity ids when updating device name during config flow

* simplify
2025-04-27 19:06:26 +03:00
renovate[bot]
bf7422e4c5 Update rspack monorepo to v1.3.6 (#25193)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-27 08:26:19 +02:00
renovate[bot]
45994e7989 Update dependency marked to v15.0.10 (#25191)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-27 08:21:50 +02:00
Simon Lamon
995e3f10ad Replace remaining mwc-tabs (#25179)
* Remaining mwc-tabs

* Apply suggestions from code review

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

---------

Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2025-04-26 20:12:03 +00:00
karwosts
6464c2b602 Share energy sum calculation across all cards (#25184) 2025-04-26 20:58:33 +03:00
renovate[bot]
8901c1fb31 Update dependency glob to v11.0.2 (#25183)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-26 19:38:54 +03:00
Simon Lamon
1f5f18f7e7 Align add-view button in edit dashboard (#25181)
Align button
2025-04-26 19:29:02 +03:00
Simon Lamon
51ca3e277c Fix wrong label selected when filtering labels (#25180)
Fix filtered labels
2025-04-26 19:27:15 +03:00
J. Nick Koston
ee495a432f Add initial zeroconf panel (#25151)
* Add initial zeroconf panel
2025-04-26 12:14:47 +02:00
Bram Kragten
d75ea3bb8d Replace mwc-tab -> sl-tab (#25166)
* Replace mwc-tab -> sl-tab
2025-04-25 17:05:04 +00:00
Paulus Schoutsen
40fbeaae1c render voice names for Cloud voices (#25164) 2025-04-25 09:43:04 -04:00
renovate[bot]
dc2c6cee21 Update dependency @codemirror/legacy-modes to v6.5.1 (#25177)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-25 13:24:29 +00:00
Petar Petrov
3b0cd9e3ae Improve handling of batteries in sankey chart (#25175) 2025-04-25 14:18:40 +02:00
ildar170975
834ece8547 Fix height & scroll in hui-dialog-create-card (#25042)
* set min/max height & fix margin for "search" field

* remove restoring height & width

* added scrollTo(top)

* compare _filter with _prevFilter

* use changedProps
2025-04-25 14:24:27 +03:00
Bram Kragten
b7aa296be7 remove wait for person in onboarding user (#25173) 2025-04-25 14:18:53 +03:00
Petar Petrov
0cab6c9e2e Use refactored Z-Wave reconfigure flow (#25174) 2025-04-25 11:18:22 +00:00
Bram Kragten
94c8665528 Improve sidebar styling (#25172) 2025-04-25 14:16:07 +03:00
Simon Lamon
c7ca654926 Clean up polymer paper item CSS variables (#24896)
Co-authored-by: Wendelin <12148533+wendevlin@users.noreply.github.com>
2025-04-25 13:08:54 +02:00
Bram Kragten
488599905b Always use target ES2021 (#25170) 2025-04-25 09:04:05 +00:00
Bram Kragten
221e1d9ed8 Allow to change device names during config flow (#25142)
* Allow to change device names during config flow

* Update zha-device-card.ts

---------

Co-authored-by: Simon Lamon <32477463+silamon@users.noreply.github.com>
2025-04-25 10:04:00 +03:00
Bram Kragten
0229f67751 Replace clickable list item (#25165) 2025-04-25 10:01:19 +03:00
Bram Kragten
3a0c367f76 Add a drag-scroll controller (#25159)
* Add a drag-scroll controller

* simplify and fix
2025-04-25 08:51:35 +03:00
renovate[bot]
af0854e480 Update dependency marked to v15.0.9 (#25168)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-25 06:18:46 +02:00
Simon Lamon
14f4120926 Fix menu not opening options (#25162) 2025-04-24 20:20:11 +02:00
renovate[bot]
e2bd464001 Update dependency typescript-eslint to v8.31.0 (#25161)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-24 20:09:48 +02:00
renovate[bot]
eb9f81d9a1 Update dependency eslint to v9.25.1 (#25160)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-24 19:32:07 +02:00
Johannes Hager
078209d154 Add Option to wrap or scroll section header badges (#24709) 2025-04-24 15:04:09 +00:00
Wendelin
7a617600ad Add unit tests and docs for common/context (#25158) 2025-04-24 16:57:29 +02:00
Wendelin
ae74e3496c Add typography tokens (#25084) 2025-04-24 16:52:03 +02:00
Petar Petrov
c0f304ad40 Use numeric prefix for IPv6 mask (#25130) 2025-04-24 16:45:37 +02:00
renovate[bot]
c794a2734b Update dependency @lit/context to v1.1.5 (#25157)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-24 12:21:10 +00:00
Bram Kragten
e156dd36f4 Use SWC for typescript, update to Lit 3, migrate decorators (#25150)
Co-authored-by: Wendelin <w@pe8.at>
2025-04-24 14:10:35 +02:00
Wendelin
c40bf8f3cd Add prevent restart when backup is ongoing (#25010)
* Add prevent restart when backup is ongoing

* Fix types

* Add error handling

* Improve review issues
2025-04-24 13:45:42 +03:00
renovate[bot]
93485d8b57 Update vitest monorepo to v3.1.2 (#25155)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-24 13:10:44 +03:00
Paul Bottein
ce5cdaa496 Add badges section on the areas strategy editor (#25154) 2025-04-24 12:36:54 +03:00
Wendelin
dcbaa31c96 Add system-managed addon info (#25132)
* Add system managed addon info dialog

* Add system managed alert

* Fix translation

* Update hassio/src/addon-view/info/hassio-addon-info.ts

Co-authored-by: Petar Petrov <MindFreeze@users.noreply.github.com>

---------

Co-authored-by: Petar Petrov <MindFreeze@users.noreply.github.com>
2025-04-24 11:12:34 +03:00
Wendelin
71b2e5f827 Improve onboarding styling (#25147) 2025-04-24 10:54:43 +03:00
Wendelin
d58590b534 Add automation loading indicator (#25146) 2025-04-24 08:01:25 +02:00
Wendelin
b2044e88b6 Improve landingpage translation loading (#25148) 2025-04-24 08:33:14 +03:00
Paul Bottein
94b5ed97c6 Refactor multi term fuse search to reuse it (#25143)
* Refactor multi term fuse search to re-use

* Do not create filter when not open

* Update fuse options

* Use fuse options
2025-04-24 08:31:02 +03:00
Zhephyr
11b8f6210f Extend usage of Data Entry Flow forms description_placeholders to field labels (#25115) 2025-04-23 12:46:15 +03:00
Paul Bottein
8e778cfc32 Use new entity naming in statistic picker (#25137) 2025-04-23 08:37:03 +03:00
karwosts
4c6a5ed2e3 convert-color: color names should be case insensitive (#25140)
convert-color: colornames should be case insensitive
2025-04-23 08:14:53 +03:00
Simon Lamon
48c90267df Fix stuck onboarding when no devices are discovered (#25106)
* Broken onboarding

* Introduce a boolean var and return previous code

* Remove import
2025-04-23 08:14:03 +03:00
Simon Lamon
fcab356639 Change netlify actions (#24815)
* Netlify fix

* Fix missing \

* Prettier

* PR review

* npx

* npx
2025-04-22 13:22:03 +02:00
Paul Bottein
a70a0d4b4a Fix event propagation in generic entity row (#25134) 2025-04-22 13:15:20 +02:00
Simon Lamon
5a34560381 Delete entity/device to Remove entity/device in scene editor (#25116)
Delete entity/device to Remove entity/device
2025-04-22 08:57:47 +03:00
renovate[bot]
f71245893a Update dependency eslint to v9.25.0 (#25126) 2025-04-21 21:06:12 +02:00
renovate[bot]
1e7bfd59f2 Update dependency @lokalise/node-api to v14.4.0 (#25123)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-21 20:43:27 +02:00
J. Nick Koston
1c15116052 Add initial DHCP discovery panel (#25086) 2025-04-21 08:09:58 -10:00
Simon Lamon
3647722824 Camera view options translated (#25119)
* Camera view options translated

* Swap around changes

* Clean up

* Clean up
2025-04-21 14:21:32 +03:00
Simon Lamon
713dd68089 Sensor card: Graph types options translated (#25118)
* Sensor card: Graph types options translated

* Clean up
2025-04-21 14:18:41 +03:00
karwosts
53dd0cbaa8 Fix some min/mean/max issues with statistics line charts (#25107)
* Fix some min/mean/max issues with statistics line charts

* minor simplification
2025-04-21 14:09:07 +03:00
Simon Lamon
6bf8faa96a Translation for number of occurrences (#25117)
* Translation for number of occurrences

* Update src/translations/en.json
2025-04-21 11:47:43 +03:00
dependabot[bot]
09a17131ab Bump softprops/action-gh-release from 2.2.1 to 2.2.2 (#25120)
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.2.1 to 2.2.2.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/v2.2.1...v2.2.2)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 2.2.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-21 11:46:14 +03:00
renovate[bot]
7f20b2d6d2 Update dependency @rsdoctor/rspack-plugin to v1.0.2 (#25112)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-20 12:29:35 +02:00
renovate[bot]
fa05cd0c90 Update dependency eslint-plugin-lit to v2.1.1 (#25110)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-19 17:33:34 +02:00
renovate[bot]
0b7fc330b3 Update dependency element-internals-polyfill to v3.0.2 (#25109)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-19 17:32:33 +02:00
Simon Lamon
6aa78794a7 Area strategy: Translate no entities in this area (#25101)
No entities in this area
2025-04-19 12:32:02 +02:00
renovate[bot]
3f17548582 Lock file maintenance (#25108)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-19 09:23:46 +02:00
renovate[bot]
0cee3c2882 Update rspack monorepo to v1.3.5 (#25104)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-18 14:56:02 +02:00
renovate[bot]
5753b3e166 Update dependency typescript-eslint to v8.30.1 (#25103)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-18 07:55:50 +02:00
Paul Bottein
7b78d821f9 Fix spinner in quick bar (#25097) 2025-04-17 20:23:59 +02:00
renovate[bot]
9a4469588c Update dependency typescript-eslint to v8.30.0 (#25099)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-17 17:57:40 +00:00
renovate[bot]
f9eadf08fd Update vaadinWebComponents monorepo to v24.7.3 (#25087)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-17 19:47:50 +02:00
dependabot[bot]
c630176fcf Bump http-proxy-middleware from 2.0.7 to 2.0.9 (#25092)
Bumps [http-proxy-middleware](https://github.com/chimurai/http-proxy-middleware) from 2.0.7 to 2.0.9.
- [Release notes](https://github.com/chimurai/http-proxy-middleware/releases)
- [Changelog](https://github.com/chimurai/http-proxy-middleware/blob/v2.0.9/CHANGELOG.md)
- [Commits](https://github.com/chimurai/http-proxy-middleware/compare/v2.0.7...v2.0.9)

---
updated-dependencies:
- dependency-name: http-proxy-middleware
  dependency-version: 2.0.9
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-17 19:46:20 +02:00
Paul Bottein
0389fbba52 Use ha-combox-box-list-item in all combo box components (#25096) 2025-04-17 17:13:19 +02:00
Paul Bottein
d56c7c41e2 Update entity naming in entity picker (#24971) 2025-04-17 16:43:47 +02:00
Paul Bottein
e74cac697e Add fit mode support to picture glance card and picture entity card (#25005)
Co-authored-by: karwosts <karwosts@gmail.com>
2025-04-17 13:36:34 +00:00
renovate[bot]
77216e8e76 Update Yarn to v4.9.1 (#25089)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-17 15:28:28 +02:00
Bram Kragten
02a8924f63 Fix max height of video in more info (#25091) 2025-04-17 15:27:57 +02:00
Petar Petrov
9fc28e5abb ZwaveJS controller migration flow (#25003)
* ZwaveJS migration flow

* Show exact progress in options flow

* progress fix

* Apply suggestions from code review

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

* remove unused string

* import fix

* fix selectedDomain

* entryId -> handler

* Update src/translations/en.json

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

---------

Co-authored-by: Bram Kragten <mail@bramkragten.nl>
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2025-04-17 13:32:33 +02:00
Wendelin
933fb1327a Implement new Z-Wave add device flow (#24667)
Co-authored-by: Petar Petrov <MindFreeze@users.noreply.github.com>
2025-04-17 13:12:04 +02:00
Petar Petrov
c73a9fccb8 Add support for exact % progress reports in options flow (#25082)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2025-04-17 09:42:52 +02:00
Wendelin
38c11e738e Improve ha cloud info buttons (#25079) 2025-04-16 17:42:51 +02:00
renovate[bot]
93c5632ee0 Update dependency jsdom to v26.1.0 (#25081)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-16 13:50:29 +03:00
Wendelin
5459eaff30 Fix and improve remove z-wave node (#25078)
* Fix and improve remove zwave node

* Improve error

* Fix lint
2025-04-16 13:48:26 +03:00
Wendelin
b02f1037fb Translate "Unnamed view" (#25080)
Add unnamed view translation
2025-04-16 11:01:13 +03:00
Paul Bottein
3d130b790c Create covers section in area strategy dashboard (#25073)
* Move cover domain and garage, door, window binary sensor to opening section in area strategy

* Rename to cover and add input boolean and select
2025-04-15 23:10:40 +02:00
renovate[bot]
e23d2392d8 Update dependency @lokalise/node-api to v14.3.0 (#25077)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-15 21:51:24 +02:00
Bram Kragten
d5a6e16bf8 Fix safe area inset in sidebar (#25074) 2025-04-15 15:32:57 +02:00
ildar170975
91a5497c60 fix ha-textfield (max-width, text-overflow, padding) (#25043)
* fix max-width, text-overflow, padding

* simmetrical padding
2025-04-15 15:41:08 +03:00
Paul Bottein
65dae09a49 Avoid generic entity row with control to open more info (#25068) 2025-04-15 13:12:49 +02:00
Wendelin
7e0f293d1f Add cloud info to backup locations (#25065)
* Add cloud info to backup agents

* Add ha cloud translation
2025-04-15 12:01:04 +02:00
0xEF
2682011ae6 Add padding back to weather forecast card for non-masonry layout (#25035) 2025-04-15 09:31:41 +00:00
Paul Bottein
1bba103a3d Fix theme variables for ha-tabs (#25066) 2025-04-15 11:08:41 +02:00
renovate[bot]
e425375d55 Update dependency lint-staged to v15.5.1 (#25057)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-14 21:05:13 +02:00
Bram Kragten
a2689eee63 Add suffix to addon copies setting (#25055) 2025-04-14 13:52:35 +00:00
Bram Kragten
74741c5d69 Don't use advanced mode in hardware dialog (#25051) 2025-04-14 15:14:44 +02:00
Bram Kragten
53426d647a Remove advanced mode from scenes editor (#25054) 2025-04-14 12:41:24 +00:00
Bram Kragten
f6e4f4c0d6 Remove advanced mode from dashboard creation (#25053) 2025-04-14 12:35:45 +00:00
Bram Kragten
2f086f4d00 Use expandable instead of advanced mode toggle (#25052) 2025-04-14 14:35:30 +02:00
ildar170975
cd91e8c07c Use codemirror in dialog-import-blueprint (#25034)
* use codemirror

* hass not needed for codemirror

* fix uom for css var
2025-04-14 10:28:28 +03:00
dependabot[bot]
b3a5ea2893 Bump actions/setup-node from 4.3.0 to 4.4.0 (#25047)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4.3.0 to 4.4.0.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v4.3.0...v4.4.0)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: 4.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-14 09:23:24 +03:00
ildar170975
98ae0295b4 Do not show tips for shortcuts on a client with a touch screen (#25020)
* check isTouch

* check isTouch

* check isTouch

* restored lost line

* isTouch -> isMobileClient

* isTouch -> isMobileClient

* isTouch -> isMobileClient

* Create is_mobile.ts
2025-04-14 09:22:33 +03:00
ildar170975
43bb9d3401 codemirror: set cursor color to "--primary-color", set indent marker color to "--divider-color" (#25045)
* set cursor color to "--primary-color"

* indent markers' color
2025-04-14 09:15:29 +03:00
J. Nick Koston
8ad4385d67 Link the device info BLE address to the Advertisement Monitor (#25044)
* Link the device info BLE address to the Advertisement Monitor

* Link the device info BLE address to the Advertisement Monitor

* preen
2025-04-14 09:13:27 +03:00
renovate[bot]
8fb7c1594a Update dependency eslint-config-prettier to v10.1.2 (#25036)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-14 09:10:19 +03:00
ildar170975
4fca09f9ae If entity has "entity_picture" - allow using a CSS theme var for border-radius (#24248)
* added CSS theme var for border-radius

* prettier

* moved "50%" out of "styles"

* small refactoring

* lint

* lint

* lint

* revert to this.style.borderRadius

* prettier

* adding classes

* fixed styles + setting a class

* clean-up

* remove old classes in render()

* "!important" not needed

* using map
2025-04-14 09:09:52 +03:00
ildar170975
6793753755 more-info-camera: disable "download_snapshot" if idle (#25027)
* disable download_snapshot if idle

* prettier
2025-04-13 09:02:36 +02:00
ildar170975
f4e3fdb98e ha-map-card: fit_zones tiny fix (#25031)
fit_zones fix
2025-04-13 08:57:53 +02:00
karwosts
63f4cc456c No particles when prefers-reduced-motion (#25029) 2025-04-13 08:56:02 +02:00
renovate[bot]
33735abfb0 Update octokit monorepo (#25032)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-13 08:42:27 +02:00
renovate[bot]
22b59b247e Update Yarn to v4.9.0 (#25025)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-12 18:13:27 +02:00
karwosts
6d7a40368c Support more templates in action visual editor (#25015)
* Support more templates in action visual editor

* Make selector sticky

* typing
2025-04-12 15:03:44 +03:00
renovate[bot]
fbeb457c25 Update rspack monorepo to v1.3.4 (#25021)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-12 08:52:32 +02:00
dependabot[bot]
4a6834f0d9 Bump vite from 6.2.5 to 6.2.6 (#25014)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.2.5 to 6.2.6.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v6.2.6/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.2.6/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 6.2.6
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-11 18:19:46 +03:00
Bram Kragten
add417a166 Wait for backup integration to setup before subscribing (#25012) 2025-04-11 16:50:23 +02:00
Pierre
ae4f43496e Add reconnection information when an instance is already connected (#25013) 2025-04-11 16:08:02 +02:00
renovate[bot]
4ce792e5bf Update rspack monorepo to v1.3.3 (#25007)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-11 16:20:55 +03:00
Bram Kragten
b9433b96dc Wait for person before creating user in onboarding (#25011) 2025-04-11 16:19:22 +03:00
Wendelin
1dfd937c94 Add automatic backup toggle to OS update (#24995) 2025-04-11 15:10:43 +02:00
Bram Kragten
6a333a4774 Bumped version to 20250411.0 2025-04-11 14:45:42 +02:00
Paul Bottein
7742ccf631 Only ask to refresh dashboard if necessary (#24993) 2025-04-11 14:45:07 +02:00
Paul Bottein
20f2a8d53e Fix refresh strategy config on HA start-up (#24984) 2025-04-11 14:45:07 +02:00
Bram Kragten
ec9fbe7d77 fix dropdown behind datatable (#24981) 2025-04-11 14:45:06 +02:00
Wendelin
6fa226d30a Fix submit spinner in config-flow-form (#24969) 2025-04-11 14:45:04 +02:00
Bram Kragten
b76a723fd9 fix voice wizard bugs (#24950) 2025-04-11 14:44:09 +02:00
Paul Bottein
5237cc72b7 Restore default hold action for some cards (#24947) 2025-04-11 14:42:20 +02:00
Jan-Philipp Benecke
63d2718f67 Import missing ha-tip in quick bar dialog (#24929) 2025-04-11 14:42:19 +02:00
Paul Bottein
14e0666c3a Only ask to refresh dashboard if necessary (#24993) 2025-04-11 14:41:12 +02:00
Bram Kragten
929a0b9cd4 Wait for cloud and backup in onboarding (#24997) 2025-04-11 13:43:45 +02:00
Bram Kragten
0541270695 Also show hardware integration if it has options (#25006)
also show hardware integration if it has options
2025-04-11 11:39:54 +02:00
Paul Bottein
20d357fb13 Add tests for get duplicates function (#24994) 2025-04-11 08:47:42 +02:00
renovate[bot]
6658c10b94 Update dependency typescript-eslint to v8.29.1 (#25000)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-11 06:41:13 +02:00
karwosts
c2ce02652b Fix automation action row describing template targets (#25002) 2025-04-11 06:40:20 +02:00
Bram Kragten
634db1944f Fix dragging in tab bar (#24998) 2025-04-10 19:12:29 +02:00
Bram Kragten
21b3177f95 Replace paper item in sidebar (#24883)
* replace paper item in sidebar

* make items same height as before

* remove polymer refs

* fix user badge

* replace removed styles (and remove unused)
2025-04-10 18:32:38 +02:00
renovate[bot]
7383e3247b Update dependency marked to v15.0.8 (#24996)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-10 16:12:09 +00:00
karwosts
b33e4bf305 Render low carbon gauge when only solar consumption (#24992)
* Render low carbon gauge when only solar consumption

* no null check
2025-04-10 18:01:49 +02:00
Bram Kragten
9d9522cade Use subscription for config flows in progress (#24985) 2025-04-10 16:59:20 +02:00
Bram Kragten
430e47c0fc Replace paper tabs by shoelace tabs (#24909) 2025-04-10 14:20:24 +00:00
Paul Bottein
a6c9702ab2 Update entity naming in entities config page (#24966)
Co-authored-by: Wendelin <12148533+wendevlin@users.noreply.github.com>
2025-04-10 12:43:08 +00:00
Wendelin
e3122e8e4d Supervisor backup update config (#24990) 2025-04-10 11:55:20 +02:00
Paul Bottein
c8e46bd239 Fix refresh strategy config on HA start-up (#24984) 2025-04-10 11:04:43 +03:00
Bram Kragten
4fd87a1d7c Hide hardware integrations without entities (#24986) 2025-04-10 08:12:21 +03:00
karwosts
80151ff759 Fix now-7d history to include today (#24989) 2025-04-10 08:10:04 +03:00
Paul Bottein
5f187c1bb3 Fix data-table group by unknown column (#24987) 2025-04-09 15:51:02 +00:00
Stefan Agner
ddc04dd48a Allow to copy IP address of Matter devices to clipboard (#24983)
Often when debugging it is actually helpful to copy the IP address
for further investigation. This PR changes the list to allow
interaction and copies the IP address when clicked on a list item.
2025-04-09 17:44:13 +02:00
Jan-Philipp Benecke
228acf1fae Add shortcuts item to command quick bar (#24952)
* Add shortcuts item to command quick bar

* Remove
2025-04-09 16:46:08 +02:00
Bram Kragten
74acd7ec38 fix dropdown behind datatable (#24981) 2025-04-09 16:16:47 +02:00
Paul Bottein
9bc867d0dc Restore no grouping from local storage from datatable (#24979)
* Restore no grouping from localstorage

* Fix collapse/expand button
2025-04-09 14:15:27 +00:00
Bram Kragten
590df8dd1a Restore media browser to browser when entity is not in state machine (#24982)
restore media browser to browser when entity is not in state machine
2025-04-09 15:49:16 +02:00
Wendelin
ccee57f4a5 Improve background settings and fix save button (#24978) 2025-04-09 13:04:07 +03:00
Bram Kragten
1e26f155a7 Bumped version to 20250404.0 2025-04-04 15:10:56 +02:00
Simon Lamon
27e13017c3 Show the correct area icon in entity breadcrumb (#24913) 2025-04-04 15:10:37 +02:00
Paul Bottein
88f1dc9c16 Add missing translations for areas strategy (#24905) 2025-04-04 15:10:36 +02:00
Paul Bottein
825e707a80 Refresh dashboard strategy when registries changed (#24902)
* Refresh dashboard strategy when registries changed

* Display toast before refreshing dashboard

* Apply suggestions
2025-04-04 15:10:35 +02:00
Bram Kragten
0bcaa104e7 Bumped version to 20250401.0 2025-04-01 17:30:31 +02:00
Bram Kragten
6b3f807129 Developer tools action fixes (#24876) 2025-04-01 17:30:16 +02:00
Paul Bottein
c464d344db Add ellipsis for more info breadcrumb (#24882) 2025-04-01 17:29:14 +02:00
karwosts
69f0a4a728 Fix condition rendering in trace choose node (#24878) 2025-04-01 17:29:13 +02:00
Bram Kragten
2ba8f9f99d Bumped version to 20250331.0 2025-03-31 20:43:31 +02:00
Bram Kragten
7e06bbc467 Fix add zwave device my link (#24871) 2025-03-31 20:42:38 +02:00
Paul Bottein
6017d82c21 Handle date range shift during daylight saving time days (#24868) 2025-03-31 20:42:37 +02:00
Bram Kragten
40c200a172 fix spinner in tts try dialog (#24867) 2025-03-31 20:42:36 +02:00
Bram Kragten
a2f70f682f Take lang into account when search existing pipeline (#24866)
* Take lang into account when search existing pipeline

* Simplify logic
2025-03-31 20:42:36 +02:00
Paul Bottein
c42a899b52 Force clock card to display time LTR (#24865) 2025-03-31 20:42:35 +02:00
Paul Bottein
706f43e99e Add interactions for weather card editor (#24864) 2025-03-31 20:42:34 +02:00
karwosts
f5496c21e8 Bar charts start from 0 (#24854) 2025-03-31 20:42:33 +02:00
Paul Bottein
34dce5b279 Only use button for breadcrumb for admin users (#24836) 2025-03-31 20:42:32 +02:00
Bram Kragten
a4f07423ec Name local pipeline based on local or full choice (#24835) 2025-03-31 20:42:31 +02:00
Bram Kragten
9e32c24f3c Update lang support text in voice wizard (#24834) 2025-03-31 20:42:30 +02:00
Paul Bottein
b281d095cd Remove add-on word in satellite wizard translations for state (#24832) 2025-03-31 20:42:29 +02:00
Paul Bottein
fe7e8e17ae More info breadcrumb clickable (#24830)
* Make more info breadcrum clickable

* css adjustements
2025-03-28 15:37:27 +01:00
Eloy Rodriguez
2161357226 Add title and time zone to clock card (#24818)
* Add title and time zone to clock card

* Small changes to the spacing and text sizing of the clock card

* Update translations to use dropdown labels from profile configuration

* Use similar approach as #24819 for setting automatic time zone

* Update hui-clock-card.ts

---------

Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2025-03-28 15:37:02 +01:00
Darren Griffin
e8e65a4293 Fix default time_format option. Fixes #24798 (#24819)
* Fix default time_format option. Fixes #24798

* Update en.json

* Update src/translations/en.json

---------

Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2025-03-28 15:36:29 +01:00
Bram Kragten
724adab2d6 Bumped version to 20250328.0 2025-03-28 15:02:51 +01:00
Bram Kragten
345ad6c9c5 Update voice-assistant-setup-step-local.ts 2025-03-28 15:02:37 +01:00
Bram Kragten
a88d066d7e Update text voice wizard install addons step (#24829) 2025-03-28 15:02:15 +01:00
Paulus Schoutsen
a8e5c8482b Hide backup from default dashboard (#24828) 2025-03-28 15:02:14 +01:00
Paulus Schoutsen
d5ff8ab1e1 Do not play pre-announce sound when testing voice on satellite (#24827) 2025-03-28 15:02:13 +01:00
Bram Kragten
e765cc10fb Fix voice flow (#24825)
* Fix voice flow

* Apply suggestions from code review

---------

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2025-03-28 15:02:12 +01:00
Paul Bottein
916dec101f Add hold and double tap action in the UI for every card that supports it. (#24824)
* Add double tap action to button card UI editor

* Add double tap action to light card UI editor

* Add hold action and double tap action to gauge card UI editor

* Add hold action and double tap action to picture glance card UI editor

* Add hold action and double tap action to picture card UI editor

* Add hold action and double tap action to entity card UI editor

* Add hold action and double tap action to elements
2025-03-28 15:02:11 +01:00
Paul Bottein
909fc119b7 Add scroll restoration when using back navigation in dashboard (#24822)
Add scroll restoration when using back navigation with subviews
2025-03-28 15:02:10 +01:00
puddly
8751dc46f4 Show hardware integrations in the integration list (#24820)
Show hardware integrations in the frontend
2025-03-28 15:02:09 +01:00
Paul Bottein
118c25d25f Bumped version to 20250327.1 2025-03-27 19:12:22 +01:00
Paul Bottein
ae5427a75e Fix dashboard strategy (#24808) 2025-03-27 19:12:03 +01:00
Paul Bottein
3b6e267fb5 Fallback to state name when the entry doesn't have name (#24805) 2025-03-27 19:12:02 +01:00
Bram Kragten
1770a51303 Bumped version to 20250327.0 2025-03-27 16:46:17 +01:00
Paul Bottein
534df3d378 Add loading state to area strategy (#24803) 2025-03-27 16:44:15 +01:00
Paul Bottein
23229b3e3b Set the max number of columns to 3 for area dashboard (#24802)
* Set the max number of columns to 4 for area dashboard

* Set it to 3
2025-03-27 16:44:14 +01:00
karwosts
94ee99160b Energy device settings fixes (#24801) 2025-03-27 16:44:13 +01:00
Paul Bottein
b009d71e8f Fix take control of the dashboard (#24800) 2025-03-27 16:44:12 +01:00
Bram Kragten
2ab8209622 Align behavior of template selector with text selector (#24796) 2025-03-27 16:44:11 +01:00
Paul Bottein
ed2940edc3 Revert "Restore scroll position when using back navigation in dashboard" (#24795)
Revert "Restore scroll position when using back navigation in dashboard (#24777)"

This reverts commit 9cfcd21a93.
2025-03-27 16:44:11 +01:00
Paul Bottein
e2b9a06242 Fix more info for disabled entities (#24789) 2025-03-27 16:44:10 +01:00
Paul Bottein
a7acee0438 Remove fixed height in ha tile info (#24787)
Remove unused height in ha tile info
2025-03-27 16:44:09 +01:00
Bram Kragten
1208af510c Fix typo in Arithmetic (#24786)
Fix type in Arithmetic
2025-03-27 16:44:08 +01:00
606 changed files with 18403 additions and 10258 deletions

View File

@@ -21,7 +21,8 @@
"esbenp.prettier-vscode",
"runem.lit-plugin",
"github.vscode-pull-request-github",
"eamodio.gitlens"
"eamodio.gitlens",
"yeion7.styled-global-variables-autocomplete"
],
"settings": {
"files.eol": "\n",

View File

@@ -26,7 +26,7 @@ jobs:
ref: dev
- name: Setup Node
uses: actions/setup-node@v4.3.0
uses: actions/setup-node@v4.4.0
with:
node-version-file: ".nvmrc"
cache: yarn
@@ -41,9 +41,8 @@ jobs:
- name: Deploy to Netlify
id: deploy
uses: netlify/actions/cli@master
with:
args: deploy --dir=cast/dist --alias dev
run: |
npx -y netlify-cli deploy --dir=cast/dist --alias dev
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_CAST_SITE_ID }}
@@ -62,7 +61,7 @@ jobs:
ref: master
- name: Setup Node
uses: actions/setup-node@v4.3.0
uses: actions/setup-node@v4.4.0
with:
node-version-file: ".nvmrc"
cache: yarn
@@ -77,9 +76,8 @@ jobs:
- name: Deploy to Netlify
id: deploy
uses: netlify/actions/cli@master
with:
args: deploy --dir=cast/dist --prod
run: |
npx -y netlify-cli deploy --dir=cast/dist --prod
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_CAST_SITE_ID }}

View File

@@ -26,7 +26,7 @@ jobs:
- name: Check out files from GitHub
uses: actions/checkout@v4.2.2
- name: Setup Node
uses: actions/setup-node@v4.3.0
uses: actions/setup-node@v4.4.0
with:
node-version-file: ".nvmrc"
cache: yarn
@@ -60,7 +60,7 @@ jobs:
- name: Check out files from GitHub
uses: actions/checkout@v4.2.2
- name: Setup Node
uses: actions/setup-node@v4.3.0
uses: actions/setup-node@v4.4.0
with:
node-version-file: ".nvmrc"
cache: yarn
@@ -78,7 +78,7 @@ jobs:
- name: Check out files from GitHub
uses: actions/checkout@v4.2.2
- name: Setup Node
uses: actions/setup-node@v4.3.0
uses: actions/setup-node@v4.4.0
with:
node-version-file: ".nvmrc"
cache: yarn
@@ -102,7 +102,7 @@ jobs:
- name: Check out files from GitHub
uses: actions/checkout@v4.2.2
- name: Setup Node
uses: actions/setup-node@v4.3.0
uses: actions/setup-node@v4.4.0
with:
node-version-file: ".nvmrc"
cache: yarn

View File

@@ -27,7 +27,7 @@ jobs:
ref: dev
- name: Setup Node
uses: actions/setup-node@v4.3.0
uses: actions/setup-node@v4.4.0
with:
node-version-file: ".nvmrc"
cache: yarn
@@ -42,9 +42,8 @@ jobs:
- name: Deploy to Netlify
id: deploy
uses: netlify/actions/cli@master
with:
args: deploy --dir=demo/dist --prod
run: |
npx -y netlify-cli deploy --dir=demo/dist --prod
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_DEMO_DEV_SITE_ID }}
@@ -63,7 +62,7 @@ jobs:
ref: master
- name: Setup Node
uses: actions/setup-node@v4.3.0
uses: actions/setup-node@v4.4.0
with:
node-version-file: ".nvmrc"
cache: yarn
@@ -78,9 +77,8 @@ jobs:
- name: Deploy to Netlify
id: deploy
uses: netlify/actions/cli@master
with:
args: deploy --dir=demo/dist --prod
run: |
npx -y netlify-cli deploy --dir=demo/dist --prod
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_DEMO_SITE_ID }}

View File

@@ -19,7 +19,7 @@ jobs:
uses: actions/checkout@v4.2.2
- name: Setup Node
uses: actions/setup-node@v4.3.0
uses: actions/setup-node@v4.4.0
with:
node-version-file: ".nvmrc"
cache: yarn
@@ -34,9 +34,8 @@ jobs:
- name: Deploy to Netlify
id: deploy
uses: netlify/actions/cli@master
with:
args: deploy --dir=gallery/dist --prod
run: |
npx -y netlify-cli deploy --dir=gallery/dist --prod
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_GALLERY_SITE_ID }}

View File

@@ -24,7 +24,7 @@ jobs:
uses: actions/checkout@v4.2.2
- name: Setup Node
uses: actions/setup-node@v4.3.0
uses: actions/setup-node@v4.4.0
with:
node-version-file: ".nvmrc"
cache: yarn
@@ -39,13 +39,14 @@ jobs:
- name: Deploy preview to Netlify
id: deploy
uses: netlify/actions/cli@master
with:
args: deploy --dir=gallery/dist --alias "deploy-preview-${{ github.event.number }}"
run: |
npx -y netlify-cli deploy --dir=gallery/dist --alias "deploy-preview-${{ github.event.number }}" \
--json > deploy_output.json
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_GALLERY_SITE_ID }}
- name: Generate summary
run: |
echo "${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}" >> "$GITHUB_STEP_SUMMARY"
NETLIFY_LIVE_URL=$(jq -r '.deploy_url' deploy_output.json)
echo "$NETLIFY_LIVE_URL" >> "$GITHUB_STEP_SUMMARY"

View File

@@ -28,7 +28,7 @@ jobs:
python-version: ${{ env.PYTHON_VERSION }}
- name: Setup Node
uses: actions/setup-node@v4.3.0
uses: actions/setup-node@v4.4.0
with:
node-version-file: ".nvmrc"
cache: yarn

View File

@@ -34,7 +34,7 @@ jobs:
uses: home-assistant/actions/helpers/verify-version@master
- name: Setup Node
uses: actions/setup-node@v4.3.0
uses: actions/setup-node@v4.4.0
with:
node-version-file: ".nvmrc"
cache: yarn
@@ -55,7 +55,7 @@ jobs:
script/release
- name: Upload release assets
uses: softprops/action-gh-release@v2.2.1
uses: softprops/action-gh-release@v2.2.2
with:
files: |
dist/*.whl
@@ -92,7 +92,7 @@ jobs:
- name: Checkout the repository
uses: actions/checkout@v4.2.2
- name: Setup Node
uses: actions/setup-node@v4.3.0
uses: actions/setup-node@v4.4.0
with:
node-version-file: ".nvmrc"
cache: yarn
@@ -107,7 +107,7 @@ jobs:
- name: Tar folder
run: tar -czf landing-page/home_assistant_frontend_landingpage-${{ github.event.release.tag_name }}.tar.gz -C landing-page/dist .
- name: Upload release asset
uses: softprops/action-gh-release@v2.2.1
uses: softprops/action-gh-release@v2.2.2
with:
files: landing-page/home_assistant_frontend_landingpage-${{ github.event.release.tag_name }}.tar.gz
@@ -121,7 +121,7 @@ jobs:
- name: Checkout the repository
uses: actions/checkout@v4.2.2
- name: Setup Node
uses: actions/setup-node@v4.3.0
uses: actions/setup-node@v4.4.0
with:
node-version-file: ".nvmrc"
cache: yarn
@@ -136,6 +136,6 @@ jobs:
- name: Tar folder
run: tar -czf hassio/home_assistant_frontend_supervisor-${{ github.event.release.tag_name }}.tar.gz -C hassio/build .
- name: Upload release asset
uses: softprops/action-gh-release@v2.2.1
uses: softprops/action-gh-release@v2.2.2
with:
files: hassio/home_assistant_frontend_supervisor-${{ github.event.release.tag_name }}.tar.gz

View File

@@ -5,6 +5,7 @@
"runem.lit-plugin",
"github.vscode-pull-request-github",
"eamodio.gitlens",
"vitest.explorer"
"vitest.explorer",
"yeion7.styled-global-variables-autocomplete"
]
}

View File

@@ -0,0 +1,22 @@
diff --git a/mwc-formfield-base.js b/mwc-formfield-base.js
index 7b763326d7d51835ad52646bfbc80fe21989abd3..f2baa8224e6d03df1fdb0b9fd03f5c6d77fc8747 100644
--- a/mwc-formfield-base.js
+++ b/mwc-formfield-base.js
@@ -9,7 +9,7 @@ import { BaseElement } from '@material/mwc-base/base-element.js';
import { FormElement } from '@material/mwc-base/form-element.js';
import { observer } from '@material/mwc-base/observer.js';
import { html } from 'lit';
-import { property, query, queryAssignedNodes } from 'lit/decorators.js';
+import { property, query, queryAssignedElements } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
export class FormfieldBase extends BaseElement {
constructor() {
@@ -96,7 +96,7 @@ __decorate([
query('.mdc-form-field')
], FormfieldBase.prototype, "mdcRoot", void 0);
__decorate([
- queryAssignedNodes('', true, '*')
+ queryAssignedElements({ slot: "", flatten: true, selector: "*" })
], FormfieldBase.prototype, "slottedInputs", void 0);
__decorate([
query('label')

View File

@@ -0,0 +1,26 @@
diff --git a/mwc-list-base.js b/mwc-list-base.js
index 1ba95b6a01dcecea4d85b5cbbbcc3dfb04c40d5f..dced13fdb7929c490d6661b1bbe7e9f96dcd2285 100644
--- a/mwc-list-base.js
+++ b/mwc-list-base.js
@@ -11,7 +11,7 @@ import { BaseElement } from '@material/mwc-base/base-element.js';
import { observer } from '@material/mwc-base/observer.js';
import { deepActiveElementPath, doesElementContainFocus, isNodeElement } from '@material/mwc-base/utils.js';
import { html } from 'lit';
-import { property, query, queryAssignedNodes } from 'lit/decorators.js';
+import { property, query, queryAssignedElements } from 'lit/decorators.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import MDCListFoundation, { isIndexSet } from './mwc-list-foundation.js';
export { createSetFromIndex, isEventMulti, isIndexSet } from './mwc-list-foundation.js';
@@ -425,10 +425,10 @@ __decorate([
query('.mdc-deprecated-list')
], ListBase.prototype, "mdcRoot", void 0);
__decorate([
- queryAssignedNodes('', true, '*')
+ queryAssignedElements({ flatten: true, selector: "*" })
], ListBase.prototype, "assignedElements", void 0);
__decorate([
- queryAssignedNodes('', true, '[tabindex="0"]')
+ queryAssignedElements({ flatten: true, selector: '[tabindex="0"]' })
], ListBase.prototype, "tabbableElements", void 0);
__decorate([
property({ type: Boolean }),

View File

@@ -1,34 +0,0 @@
diff --git a/lib/legacy/class.js b/lib/legacy/class.js
index aee2511be1cd9bf900ee552bc98190c1631c57c0..f2f499d68bf52034cac9c28307c99e8ce6b8417d 100644
--- a/lib/legacy/class.js
+++ b/lib/legacy/class.js
@@ -304,17 +304,23 @@ function GenerateClassFromInfo(info, Base, behaviors) {
// only proceed if the generated class' prototype has not been registered.
const generatedProto = PolymerGenerated.prototype;
if (!generatedProto.hasOwnProperty(JSCompiler_renameProperty('__hasRegisterFinished', generatedProto))) {
- generatedProto.__hasRegisterFinished = true;
+ // make sure legacy lifecycle is called on the *element*'s prototype
+ // and not the generated class prototype; if the element has been
+ // extended, these are *not* the same.
+ const proto = Object.getPrototypeOf(this);
+ // Only set flag when generated prototype itself is registered,
+ // as this element may be extended from, and needs to run `registered`
+ // on all behaviors on the subclass as well.
+ if (proto === generatedProto) {
+ generatedProto.__hasRegisterFinished = true;
+ }
// ensure superclass is registered first.
super._registered();
// copy properties onto the generated class lazily if we're optimizing,
- if (legacyOptimizations) {
+ if (legacyOptimizations && !Object.hasOwnProperty(generatedProto, '__hasCopiedProperties')) {
+ generatedProto.__hasCopiedProperties = true;
copyPropertiesToProto(generatedProto);
}
- // make sure legacy lifecycle is called on the *element*'s prototype
- // and not the generated class prototype; if the element has been
- // extended, these are *not* the same.
- const proto = Object.getPrototypeOf(this);
let list = lifecycle.beforeRegister;
if (list) {
for (let i=0; i < list.length; i++) {

File diff suppressed because one or more lines are too long

948
.yarn/releases/yarn-4.9.1.cjs vendored Executable file

File diff suppressed because one or more lines are too long

View File

@@ -6,4 +6,4 @@ enableGlobalCache: false
nodeLinker: node-modules
yarnPath: .yarn/releases/yarn-4.8.1.cjs
yarnPath: .yarn/releases/yarn-4.9.1.cjs

View File

@@ -2,7 +2,7 @@ import defineProvider from "@babel/helper-define-polyfill-provider";
import { join } from "node:path";
import paths from "../paths.cjs";
const POLYFILL_DIR = join(paths.polymer_dir, "src/resources/polyfills");
const POLYFILL_DIR = join(paths.root_dir, "src/resources/polyfills");
// List of polyfill keys with supported browser targets for the functionality
const polyfillSupport = {

View File

@@ -20,22 +20,16 @@ module.exports.ignorePackages = () => [];
// Files from NPM packages that we should replace with empty file
module.exports.emptyPackages = ({ isHassioBuild }) =>
[
// Contains all color definitions for all material color sets.
// We don't use it
require.resolve("@polymer/paper-styles/color.js"),
require.resolve("@polymer/paper-styles/default-theme.js"),
// Loads stuff from a CDN
require.resolve("@polymer/font-roboto/roboto.js"),
require.resolve("@vaadin/vaadin-material-styles/typography.js"),
require.resolve("@vaadin/vaadin-material-styles/font-icons.js"),
// Icons in supervisor conflict with icons in HA so we don't load.
isHassioBuild &&
require.resolve(
path.resolve(paths.polymer_dir, "src/components/ha-icon.ts")
path.resolve(paths.root_dir, "src/components/ha-icon.ts")
),
isHassioBuild &&
require.resolve(
path.resolve(paths.polymer_dir, "src/components/ha-icon-picker.ts")
path.resolve(paths.root_dir, "src/components/ha-icon-picker.ts")
),
].filter(Boolean);
@@ -50,7 +44,8 @@ module.exports.definedVars = ({ isProdBuild, latestBuild, defineOverlay }) => ({
__HASS_URL__: `\`${
"HASS_URL" in process.env
? process.env.HASS_URL
: "${location.protocol}//${location.host}"
: // eslint-disable-next-line no-template-curly-in-string
"${location.protocol}//${location.host}"
}\``,
"process.env.NODE_ENV": JSON.stringify(
isProdBuild ? "production" : "development"
@@ -78,6 +73,19 @@ module.exports.terserOptions = ({ latestBuild, isTestBuild }) => ({
sourceMap: !isTestBuild,
});
/** @type {import('@rspack/core').SwcLoaderOptions} */
module.exports.swcOptions = () => ({
jsc: {
loose: true,
externalHelpers: true,
target: "ES2021",
parser: {
syntax: "typescript",
decorators: true,
},
},
});
module.exports.babelOptions = ({
latestBuild,
isProdBuild,
@@ -102,7 +110,6 @@ module.exports.babelOptions = ({
shippedProposals: true,
},
],
"@babel/preset-typescript",
],
plugins: [
[
@@ -139,12 +146,6 @@ module.exports.babelOptions = ({
"@babel/plugin-transform-runtime",
{ version: dependencies["@babel/runtime"] },
],
// Transpile decorators (still in TC39 process)
// Modern browsers support class fields and private methods, but transform is required with the older decorator version dictated by Lit
[
"@babel/plugin-proposal-decorators",
{ version: "2018-09", decoratorsBeforeExport: true },
],
"@babel/plugin-transform-class-properties",
"@babel/plugin-transform-private-methods",
].filter(Boolean),
@@ -164,7 +165,7 @@ module.exports.babelOptions = ({
],
],
exclude: [
path.join(paths.polymer_dir, "src/resources/polyfills"),
path.join(paths.root_dir, "src/resources/polyfills"),
...[
"@formatjs/(?:ecma402-abstract|intl-\\w+)",
"@lit-labs/virtualizer/polyfills",
@@ -182,6 +183,7 @@ module.exports.babelOptions = ({
include: /\/node_modules\//,
exclude: [
"element-internals-polyfill",
"@shoelace-style",
"@?lit(?:-labs|-element|-html)?",
].map((p) => new RegExp(`/node_modules/${p}/`)),
},

View File

@@ -21,7 +21,7 @@ module.exports = {
},
version() {
const version = fs
.readFileSync(path.resolve(paths.polymer_dir, "pyproject.toml"), "utf8")
.readFileSync(path.resolve(paths.root_dir, "pyproject.toml"), "utf8")
.match(/version\W+=\W"(\d{8}\.\d(?:\.dev)?)"/);
if (!version) {
throw Error("Version not found");

View File

@@ -169,14 +169,14 @@ const APP_PAGE_ENTRIES = {
gulp.task(
"gen-pages-app-dev",
genPagesDevTask(APP_PAGE_ENTRIES, paths.polymer_dir, paths.app_output_root)
genPagesDevTask(APP_PAGE_ENTRIES, paths.root_dir, paths.app_output_root)
);
gulp.task(
"gen-pages-app-prod",
genPagesProdTask(
APP_PAGE_ENTRIES,
paths.polymer_dir,
paths.root_dir,
paths.app_output_root,
paths.app_output_latest,
paths.app_output_es5

View File

@@ -6,8 +6,8 @@ import path from "path";
import paths from "../paths.cjs";
const npmPath = (...parts) =>
path.resolve(paths.polymer_dir, "node_modules", ...parts);
const polyPath = (...parts) => path.resolve(paths.polymer_dir, ...parts);
path.resolve(paths.root_dir, "node_modules", ...parts);
const polyPath = (...parts) => path.resolve(paths.root_dir, ...parts);
const copyFileDir = (fromFile, toDir) =>
fs.copySync(fromFile, path.join(toDir, path.basename(fromFile)));

View File

@@ -4,7 +4,7 @@ import gulp from "gulp";
import { join, resolve } from "node:path";
import paths from "../paths.cjs";
const formatjsDir = join(paths.polymer_dir, "node_modules", "@formatjs");
const formatjsDir = join(paths.root_dir, "node_modules", "@formatjs");
const outDir = join(paths.build_dir, "locale-data");
const INTL_POLYFILLS = {

View File

@@ -16,6 +16,7 @@ const detailsClose = "</details>\n";
const dummyAPI = {
version: babelVersion,
// eslint-disable-next-line @typescript-eslint/no-empty-function
assertVersion: () => {},
caller: (callback) =>
callback({

View File

@@ -1,7 +1,7 @@
const path = require("path");
module.exports = {
polymer_dir: path.resolve(__dirname, ".."),
root_dir: path.resolve(__dirname, ".."),
build_dir: path.resolve(__dirname, "../build"),
app_output_root: path.resolve(__dirname, "../hass_frontend"),

View File

@@ -65,19 +65,26 @@ const createRspackConfig = ({
rules: [
{
test: /\.m?js$|\.ts$/,
use: (info) => ({
loader: "babel-loader",
options: {
...bundle.babelOptions({
latestBuild,
isProdBuild,
isTestBuild,
sw: info.issuerLayer === "sw",
}),
cacheDirectory: !isProdBuild,
cacheCompression: false,
exclude: /node_modules[\\/]core-js/,
use: (info) => [
{
loader: "babel-loader",
options: {
...bundle.babelOptions({
latestBuild,
isProdBuild,
isTestBuild,
sw: info.issuerLayer === "sw",
}),
cacheDirectory: !isProdBuild,
cacheCompression: false,
},
},
}),
{
loader: "builtin:swc-loader",
options: bundle.swcOptions(),
},
],
resolve: {
fullySpecified: false,
},
@@ -136,7 +143,8 @@ const createRspackConfig = ({
// calling define.amd will call require("!!webpack amd options")
resource.startsWith("!!webpack") ||
// loaded by webpack dev server but doesn't exist.
resource === "webpack/hot"
resource === "webpack/hot" ||
resource.startsWith("@swc/helpers")
) {
return false;
}
@@ -161,7 +169,7 @@ const createRspackConfig = ({
}),
new rspack.NormalModuleReplacementPlugin(
new RegExp(bundle.emptyPackages({ isHassioBuild }).join("|")),
path.resolve(paths.polymer_dir, "src/util/empty.js")
path.resolve(paths.root_dir, "src/util/empty.js")
),
!isProdBuild && new LogStartCompilePlugin(),
isProdBuild &&

View File

@@ -1,3 +1,3 @@
import "./layout/hc-connect";
import("../../../src/resources/ha-style");
import("../../../src/resources/append-ha-style");

View File

@@ -1,5 +1,5 @@
import "@material/mwc-button/mwc-button";
import "@material/mwc-list/mwc-list";
import type { ActionDetail } from "@material/mwc-list/mwc-list";
import { mdiCast, mdiCastConnected, mdiViewDashboard } from "@mdi/js";
import type { Auth, Connection } from "home-assistant-js-websocket";
@@ -19,6 +19,8 @@ import {
import { atLeastVersion } from "../../../../src/common/config/version";
import { toggleAttribute } from "../../../../src/common/dom/toggle_attribute";
import "../../../../src/components/ha-icon";
import "../../../../src/components/ha-list";
import "../../../../src/components/ha-list-item";
import "../../../../src/components/ha-svg-icon";
import {
getLegacyLovelaceCollection,
@@ -29,7 +31,6 @@ import type { LovelaceViewConfig } from "../../../../src/data/lovelace/config/vi
import "../../../../src/layouts/hass-loading-screen";
import { generateDefaultViewConfig } from "../../../../src/panels/lovelace/common/generate-lovelace-config";
import "./hc-layout";
import "../../../../src/components/ha-list-item";
@customElement("hc-cast")
class HcCast extends LitElement {
@@ -85,7 +86,7 @@ class HcCast extends LitElement {
`
: html`
<div class="section-header">PICK A VIEW</div>
<mwc-list @action=${this._handlePickView} activatable>
<ha-list @action=${this._handlePickView} activatable>
${(
this.lovelaceViews ?? [
generateDefaultViewConfig({}, {}, {}, {}, () => ""),
@@ -113,7 +114,7 @@ class HcCast extends LitElement {
></ha-svg-icon>`}
</ha-list-item>
`
)}</mwc-list
)}</ha-list
>
`}

View File

@@ -109,7 +109,7 @@ export class HcMain extends HassElement {
protected firstUpdated(changedProps) {
super.firstUpdated(changedProps);
import("./hc-lovelace");
import("../../../../src/resources/ha-style");
import("../../../../src/resources/append-ha-style");
window.addEventListener("location-changed", () => {
const panelPath = `/${this._urlPath || "lovelace"}/`;

View File

@@ -1,37 +1,28 @@
export const demoThemeJimpower = () => ({
"text-primary-color": "var(--primary-text-color)",
"paper-item-icon-color": "var(--primary-text-color)",
"primary-color": "#5294E2",
"label-badge-red": "var(--accent-color)",
"paper-tabs-selection-bar-color": "green",
"light-primary-color": "var(--accent-color)",
"primary-background-color": "#383C45",
"primary-text-color": "#FFFFFF",
"paper-item-selected_-_background-color": "#434954",
"secondary-background-color": "#383C45",
"disabled-text-color": "#7F848E",
"paper-item-icon_-_color": "green",
"paper-grey-200": "#414A59",
"label-badge-background-color": "#2E333A",
"paper-card-header-color": "var(--accent-color)",
"sidebar-icon-color": "var(--paper-item-icon-color)",
"paper-listbox-background-color": "#2E333A",
"sidebar-icon-color": "var(--state-icon-color)",
"table-row-background-color": "#353840",
"paper-grey-50": "var(--primary-text-color)",
"switch-checked-color": "var(--accent-color)",
"paper-dialog-background-color": "#434954",
"secondary-text-color": "#5294E2",
"error-color": "#E45E65",
"divider-color": "rgba(0, 0, 0, .12)",
"success-color": "#39E949",
"switch-unchecked-button-color": "var(--disabled-text-color)",
"label-badge-border-color": "green",
"paper-listbox-color": "var(--primary-color)",
"card-background-color": "#434954",
"label-badge-text-color": "var(--primary-text-color)",
"switch-unchecked-track-color": "var(--disabled-text-color)",
"dark-primary-color": "var(--accent-color)",
"paper-item-icon-active-color": "#F9C536",
"accent-color": "#E45E65",
"table-row-alternative-background-color": "#3E424B",
});

View File

@@ -1,38 +1,29 @@
// https://community.home-assistant.io/t/slate-a-new-dark-theme/86410
export const demoThemeKernehed = () => ({
"text-primary-color": "var(--primary-text-color)",
"paper-item-icon-color": "var(--primary-text-color)",
"primary-color": "#2980b9",
"label-badge-red": "var(--accent-color)",
"paper-tabs-selection-bar-color": "green",
"primary-text-color": "#FFFFFF",
"light-primary-color": "var(--accent-color)",
"primary-background-color": "#222222",
"sidebar-icon-color": "#777777",
"paper-item-selected_-_background-color": "#292929",
"secondary-background-color": "#222222",
"disabled-text-color": "#777777",
"paper-item-icon_-_color": "green",
"paper-grey-200": "#222222",
"label-badge-background-color": "#222222",
"paper-card-header-color": "var(--accent-color)",
"paper-listbox-background-color": "#141414",
"table-row-background-color": "#292929",
"paper-grey-50": "var(--primary-text-color)",
"switch-checked-color": "var(--accent-color)",
"paper-dialog-background-color": "#292929",
"secondary-text-color": "#b58e31",
"error-color": "#b58e31",
"divider-color": "rgba(0, 0, 0, .12)",
"success-color": "#2980b9",
"switch-unchecked-button-color": "var(--disabled-text-color)",
"label-badge-border-color": "green",
"paper-listbox-color": "#777777",
"card-background-color": "#292929",
"label-badge-text-color": "var(--primary-text-color)",
"switch-unchecked-track-color": "var(--disabled-text-color)",
"dark-primary-color": "var(--accent-color)",
"paper-item-icon-active-color": "#b58e31",
"accent-color": "#2980b9",
"table-row-alternative-background-color": "#292929",
});

View File

@@ -1,26 +1,18 @@
export const demoThemeTeachingbirds = () => ({
"paper-card-header-color": "var(--paper-item-icon-color)",
"paper-listbox-background-color": "#202020",
"paper-grey-50": "var(--primary-text-color)",
"paper-item-icon-color": "#d3d3d3",
"divider-color": "rgba(255, 255, 255, 0.12)",
"primary-color": "#389638",
"light-primary-color": "#6f956f",
"label-badge-red": "var(--primary-color)",
"paper-listbox-color": "#FFFFFF",
"paper-toggle-button-checked-bar-color": "var(--light-primary-color)",
"switch-unchecked-track-color": "var(--primary-text-color)",
"card-background-color": "#4e4e4e",
"label-badge-text-color": "var(--text-primary-color)",
"primary-background-color": "#303030",
"sidebar-icon-color": "var(--paper-item-icon-color)",
"sidebar-icon-color": "#d3d3d3",
"secondary-background-color": "#2b2b2b",
"paper-item-icon-active-color": "#d8bf50",
"switch-checked-color": "var(--primary-color)",
"secondary-text-color": "#389638",
"disabled-text-color": "#545454",
"paper-item-icon_-_color": "var(--primary-text-color)",
"paper-grey-200": "#191919",
"primary-text-color": "#cfcfcf",
"label-badge-background-color": "var(--secondary-background-color)",
});

View File

@@ -73,7 +73,7 @@ class CastDemoRow extends LitElement implements LovelaceRow {
}
ha-svg-icon {
padding: 8px;
color: var(--paper-item-icon-color);
color: var(--state-icon-color);
}
.flex {
flex: 1;

View File

@@ -1,4 +1,4 @@
import "./util/is_frontpage";
import "./ha-demo";
import("../../src/resources/ha-style");
import("../../src/resources/append-ha-style");

View File

@@ -2,26 +2,36 @@ import type { TodoItem } from "../../../src/data/todo";
import { TodoItemStatus } from "../../../src/data/todo";
import type { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
export const mockTodo = (hass: MockHomeAssistant) => {
hass.mockWS("todo/item/list", () => ({
items: [
{
uid: "12",
summary: "Milk",
status: TodoItemStatus.NeedsAction,
},
{
uid: "13",
summary: "Eggs",
status: TodoItemStatus.NeedsAction,
},
{
uid: "14",
summary: "Oranges",
status: TodoItemStatus.Completed,
},
] as TodoItem[],
}));
// eslint-disable-next-line @typescript-eslint/no-empty-function
hass.mockWS("todo/item/subscribe", (_msg, _hass) => () => {});
const items = {
items: [
{
uid: "12",
summary: "Milk",
status: TodoItemStatus.NeedsAction,
},
{
uid: "13",
summary: "Eggs",
status: TodoItemStatus.NeedsAction,
},
{
uid: "14",
summary: "Oranges",
status: TodoItemStatus.Completed,
},
{
uid: "15",
summary: "Beer",
},
] as TodoItem[],
};
export const mockTodo = (hass: MockHomeAssistant) => {
hass.mockWS("todo/item/list", () => items);
hass.mockWS("todo/item/move", () => undefined);
hass.mockWS("todo/item/subscribe", (_msg, _hass, onChange) => {
onChange!(items);
// eslint-disable-next-line @typescript-eslint/no-empty-function
return () => {};
});
};

View File

@@ -42,7 +42,6 @@ export default tseslint.config(
__VERSION__: false,
__STATIC_PATH__: false,
__SUPERVISOR__: false,
Polymer: true,
},
parser: tseslint.parser,

View File

@@ -1,5 +1,5 @@
import "./ha-gallery";
import("../../src/resources/ha-style");
import("../../src/resources/append-ha-style");
document.body.appendChild(document.createElement("ha-gallery"));

View File

@@ -1,29 +1,30 @@
import type { TemplateResult } from "lit";
import { LitElement, html, css } from "lit";
import { LitElement, css, html } from "lit";
import { customElement, state } from "lit/decorators";
import "../../../../src/components/ha-formfield";
import { provideHass } from "../../../../src/fake_data/provide_hass";
import type { HomeAssistant } from "../../../../src/types";
import "../../components/demo-black-white-row";
import { mockEntityRegistry } from "../../../../demo/src/stubs/entity_registry";
import { mockDeviceRegistry } from "../../../../demo/src/stubs/device_registry";
import { mockAreaRegistry } from "../../../../demo/src/stubs/area_registry";
import { mockDeviceRegistry } from "../../../../demo/src/stubs/device_registry";
import { mockEntityRegistry } from "../../../../demo/src/stubs/entity_registry";
import { mockHassioSupervisor } from "../../../../demo/src/stubs/hassio_supervisor";
import type { Action } from "../../../../src/data/script";
import "../../../../src/panels/config/automation/action/ha-automation-action";
import { HaChooseAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-choose";
import { HaConditionAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-condition";
import { HaDelayAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-delay";
import { HaDeviceAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-device_id";
import { HaEventAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-event";
import { HaIfAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-if";
import { HaParallelAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-parallel";
import { HaPlayMediaAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-play_media";
import { HaRepeatAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-repeat";
import { HaSequenceAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-sequence";
import { HaServiceAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-service";
import { HaStopAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-stop";
import { HaWaitForTriggerAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-wait_for_trigger";
import { HaWaitAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-wait_template";
import type { Action } from "../../../../src/data/script";
import { HaConditionAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-condition";
import { HaSequenceAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-sequence";
import { HaParallelAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-parallel";
import { HaIfAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-if";
import { HaStopAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-stop";
import { HaPlayMediaAction } from "../../../../src/panels/config/automation/action/types/ha-automation-action-play_media";
const SCHEMAS: { name: string; actions: Action[] }[] = [
{ name: "Event", actions: [HaEventAction.defaultConfig] },

View File

@@ -1,26 +1,27 @@
import type { TemplateResult } from "lit";
import { LitElement, html, css } from "lit";
import { LitElement, css, html } from "lit";
import { customElement, state } from "lit/decorators";
import { provideHass } from "../../../../src/fake_data/provide_hass";
import type { HomeAssistant } from "../../../../src/types";
import "../../components/demo-black-white-row";
import { mockEntityRegistry } from "../../../../demo/src/stubs/entity_registry";
import { mockDeviceRegistry } from "../../../../demo/src/stubs/device_registry";
import { mockAreaRegistry } from "../../../../demo/src/stubs/area_registry";
import { mockDeviceRegistry } from "../../../../demo/src/stubs/device_registry";
import { mockEntityRegistry } from "../../../../demo/src/stubs/entity_registry";
import { mockHassioSupervisor } from "../../../../demo/src/stubs/hassio_supervisor";
import "../../../../src/components/ha-formfield";
import type { ConditionWithShorthand } from "../../../../src/data/automation";
import { provideHass } from "../../../../src/fake_data/provide_hass";
import "../../../../src/panels/config/automation/condition/ha-automation-condition";
import { HaAndCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-and";
import { HaDeviceCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-device";
import { HaNotCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-not";
import HaNumericStateCondition from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-numeric_state";
import { HaOrCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-or";
import { HaStateCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-state";
import { HaSunCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-sun";
import { HaTemplateCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-template";
import { HaTimeCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-time";
import { HaTriggerCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-trigger";
import { HaZoneCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-zone";
import { HaAndCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-and";
import { HaOrCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-or";
import { HaNotCondition } from "../../../../src/panels/config/automation/condition/types/ha-automation-condition-not";
import type { HomeAssistant } from "../../../../src/types";
import "../../components/demo-black-white-row";
const SCHEMAS: { name: string; conditions: ConditionWithShorthand[] }[] = [
{

View File

@@ -1,35 +1,36 @@
import type { TemplateResult } from "lit";
import { LitElement, html, css } from "lit";
import { LitElement, css, html } from "lit";
import { customElement, state } from "lit/decorators";
import { provideHass } from "../../../../src/fake_data/provide_hass";
import type { HomeAssistant } from "../../../../src/types";
import "../../components/demo-black-white-row";
import { mockEntityRegistry } from "../../../../demo/src/stubs/entity_registry";
import { mockDeviceRegistry } from "../../../../demo/src/stubs/device_registry";
import { mockAreaRegistry } from "../../../../demo/src/stubs/area_registry";
import { mockHassioSupervisor } from "../../../../demo/src/stubs/hassio_supervisor";
import { mockConfig } from "../../../../demo/src/stubs/config";
import { mockTags } from "../../../../demo/src/stubs/tags";
import { mockAuth } from "../../../../demo/src/stubs/auth";
import { mockConfig } from "../../../../demo/src/stubs/config";
import { mockDeviceRegistry } from "../../../../demo/src/stubs/device_registry";
import { mockEntityRegistry } from "../../../../demo/src/stubs/entity_registry";
import { mockHassioSupervisor } from "../../../../demo/src/stubs/hassio_supervisor";
import { mockTags } from "../../../../demo/src/stubs/tags";
import "../../../../src/components/ha-formfield";
import type { Trigger } from "../../../../src/data/automation";
import { HaGeolocationTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-geo_location";
import { provideHass } from "../../../../src/fake_data/provide_hass";
import "../../../../src/panels/config/automation/trigger/ha-automation-trigger";
import { HaConversationTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-conversation";
import { HaDeviceTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-device";
import { HaEventTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-event";
import { HaGeolocationTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-geo_location";
import { HaHassTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-homeassistant";
import { HaTriggerList } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-list";
import { HaMQTTTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-mqtt";
import { HaNumericStateTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-numeric_state";
import { HaPersistentNotificationTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-persistent_notification";
import { HaStateTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-state";
import { HaSunTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-sun";
import { HaTagTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-tag";
import { HaTemplateTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-template";
import { HaTimeTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-time";
import { HaTimePatternTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-time_pattern";
import { HaWebhookTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-webhook";
import { HaPersistentNotificationTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-persistent_notification";
import { HaZoneTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-zone";
import { HaDeviceTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-device";
import { HaStateTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-state";
import { HaMQTTTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-mqtt";
import "../../../../src/panels/config/automation/trigger/ha-automation-trigger";
import { HaConversationTrigger } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-conversation";
import { HaTriggerList } from "../../../../src/panels/config/automation/trigger/types/ha-automation-trigger-list";
import type { HomeAssistant } from "../../../../src/types";
import "../../components/demo-black-white-row";
const SCHEMAS: { name: string; triggers: Trigger[] }[] = [
{

View File

@@ -0,0 +1,65 @@
---
title: Badge
subtitle: Lovelace dashboard badge
---
<style>
.wrapper {
display: flex;
gap: 24px;
}
</style>
# Badge `<ha-badge>`
The badge component is a small component that displays a number or status information. It is used in the lovelace dashboard on the top.
## Implementation
### Example Usage
<div class="wrapper">
<ha-badge>
simple badge
</ha-badge>
<ha-badge label="Info">
With a label
</ha-badge>
<ha-badge type="button">
Type button
</ha-badge>
</div>
```html
<ha-badge> simple badge </ha-badge>
<ha-badge label="Info"> With a label </ha-badge>
<ha-badge type="button"> Type button </ha-badge>
```
### API
**Slots**
- default slot is the content of the badge
- no default
- `icon` set the icon of the badge
- no default
**Properties/Attributes**
| Name | Type | Default | Description |
| -------- | ----------------------- | ----------- | ------------------------------------------------------------ |
| type | `"badge"` or `"button"` | `"badge"` | If it's button it shows a ripple effect |
| label | string | `undefined` | Text label for the badge, only visible if `iconOnly = false` |
| iconOnly | boolean | `false` | Only show label |
**CSS Custom Properties**
- `--ha-badge-size` (default `36px`)
- `--ha-badge-border-radius` (default `calc(var(--ha-badge-size, 36px) / 2)`)
- `--ha-badge-font-size` (default `var(--ha-font-size-s)`)
- `--ha-badge-icon-size` (default `18px`)

View File

@@ -0,0 +1,129 @@
import { mdiButtonCursor, mdiHome } from "@mdi/js";
import type { TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
import { customElement } from "lit/decorators";
import { applyThemesOnElement } from "../../../../src/common/dom/apply_themes_on_element";
import "../../../../src/components/ha-badge";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-svg-icon";
import { mdiHomeAssistant } from "../../../../src/resources/home-assistant-logo-svg";
const badges: {
type?: "badge" | "button";
label?: string;
iconOnly?: boolean;
slot?: TemplateResult;
iconSlot?: TemplateResult;
}[] = [
{
slot: html`<span>Badge</span>`,
},
{
type: "badge",
label: "Badge",
iconSlot: html`<ha-svg-icon slot="icon" .path=${mdiHome}></ha-svg-icon>`,
slot: html`<span>Badge</span>`,
},
{
type: "button",
label: "Button",
iconSlot: html`<ha-svg-icon
slot="icon"
.path=${mdiButtonCursor}
></ha-svg-icon>`,
slot: html`<span>Button</span>`,
},
{
type: "button",
label: "Label only",
iconSlot: html`<ha-svg-icon
slot="icon"
.path=${mdiButtonCursor}
></ha-svg-icon>`,
},
{
type: "button",
label: "Label",
slot: html`<span>Button no label</span>`,
},
{
label: "Icon only",
iconOnly: true,
iconSlot: html`<ha-svg-icon
slot="icon"
.path=${mdiHomeAssistant}
></ha-svg-icon>`,
},
];
@customElement("demo-components-ha-badge")
export class DemoHaBadge extends LitElement {
protected render(): TemplateResult {
return html`
${["light", "dark"].map(
(mode) => html`
<div class=${mode}>
<ha-card header="ha-badge ${mode} demo">
<div class="card-content">
${badges.map(
(badge) => html`
<ha-badge
.type=${badge.type || undefined}
.label=${badge.label}
.iconOnly=${badge.iconOnly || false}
>
${badge.iconSlot} ${badge.slot}
</ha-badge>
`
)}
</div>
</ha-card>
</div>
`
)}
`;
}
firstUpdated(changedProps) {
super.firstUpdated(changedProps);
applyThemesOnElement(
this.shadowRoot!.querySelector(".dark"),
{
default_theme: "default",
default_dark_theme: "default",
themes: {},
darkMode: true,
theme: "default",
},
undefined,
undefined,
true
);
}
static styles = css`
:host {
display: flex;
justify-content: center;
}
.dark,
.light {
display: block;
background-color: var(--primary-background-color);
padding: 0 50px;
}
ha-card {
margin: 24px auto;
}
.card-content {
display: flex;
gap: 24px;
}
`;
}
declare global {
interface HTMLElementTagNameMap {
"demo-components-ha-badge": DemoHaBadge;
}
}

View File

@@ -6,22 +6,23 @@ import { mockAreaRegistry } from "../../../../demo/src/stubs/area_registry";
import { mockConfigEntries } from "../../../../demo/src/stubs/config_entries";
import { mockDeviceRegistry } from "../../../../demo/src/stubs/device_registry";
import { mockEntityRegistry } from "../../../../demo/src/stubs/entity_registry";
import { mockFloorRegistry } from "../../../../demo/src/stubs/floor_registry";
import { mockHassioSupervisor } from "../../../../demo/src/stubs/hassio_supervisor";
import { mockLabelRegistry } from "../../../../demo/src/stubs/label_registry";
import "../../../../src/components/ha-formfield";
import "../../../../src/components/ha-selector/ha-selector";
import "../../../../src/components/ha-settings-row";
import type { AreaRegistryEntry } from "../../../../src/data/area_registry";
import type { BlueprintInput } from "../../../../src/data/blueprint";
import type { DeviceRegistryEntry } from "../../../../src/data/device_registry";
import type { FloorRegistryEntry } from "../../../../src/data/floor_registry";
import type { LabelRegistryEntry } from "../../../../src/data/label_registry";
import { showDialog } from "../../../../src/dialogs/make-dialog-manager";
import { getEntity } from "../../../../src/fake_data/entity";
import { provideHass } from "../../../../src/fake_data/provide_hass";
import type { ProvideHassElement } from "../../../../src/mixins/provide-hass-lit-mixin";
import type { HomeAssistant } from "../../../../src/types";
import "../../components/demo-black-white-row";
import type { FloorRegistryEntry } from "../../../../src/data/floor_registry";
import type { LabelRegistryEntry } from "../../../../src/data/label_registry";
import { mockFloorRegistry } from "../../../../demo/src/stubs/floor_registry";
import { mockLabelRegistry } from "../../../../demo/src/stubs/label_registry";
import type { DeviceRegistryEntry } from "../../../../src/data/device_registry";
const ENTITIES = [
getEntity("alarm_control_panel", "alarm", "disarmed", {
@@ -643,9 +644,6 @@ class DemoHaSelector extends LitElement implements ProvideHassElement {
}
static styles = css`
ha-settings-row {
--paper-item-body-two-line-min-height: 0;
}
.options {
max-width: 800px;
margin: 16px auto;

View File

@@ -18,7 +18,7 @@ Tooltips use `display: contents` so they won't interfere with how elements are p
## Documentation
This element is based on sholace `sl-tooltip` it only sets some css tokens and has a custom show/hide animation.
This element is based on shoelace `sl-tooltip` it only sets some css tokens and has a custom show/hide animation.
<a href="https://shoelace.style/components/tooltip" target="_blank" rel="noopener noreferrer">Shoelace documentation</a>
@@ -28,3 +28,7 @@ In your theme settings use this without the prefixed `--`.
- `--ha-tooltip-border-radius` (Default: 4px)
- `--ha-tooltip-arrow-size` (Default: 8px)
- `--sl-tooltip-font-family` (Default: `var(--ha-font-family-body)`)
- `--ha-tooltip-font-size` (Default: `var(--ha-font-size-s)`)
- `--sl-tooltip-font-weight` (Default: `var(--ha-font-weight-normal)`)
- `--sl-tooltip-line-height` (Default: `var(--ha-line-height-condensed)`)

View File

@@ -1,9 +1,9 @@
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 "../../../../src/components/ha-list";
import type { FrontendLocaleData } from "../../../../src/data/translation";
import {
DateFormat,
@@ -49,7 +49,7 @@ export class DemoDateTimeDateTimeNumeric extends LitElement {
@value-changed=${this.handleValueChanged}
>
</ha-control-select>
<mwc-list>
<ha-list>
<div class="container header">
<div>Language</div>
<div class="center">Default (lang)</div>
@@ -96,7 +96,7 @@ export class DemoDateTimeDateTimeNumeric extends LitElement {
</div>
`
)}
</mwc-list>
</ha-list>
`;
}

View File

@@ -1,9 +1,9 @@
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 "../../../../src/components/ha-list";
import type { FrontendLocaleData } from "../../../../src/data/translation";
import {
DateFormat,
@@ -49,7 +49,7 @@ export class DemoDateTimeDateTimeSeconds extends LitElement {
@value-changed=${this.handleValueChanged}
>
</ha-control-select>
<mwc-list>
<ha-list>
<div class="container header">
<div>Language</div>
<div class="center">Default (lang)</div>
@@ -96,7 +96,7 @@ export class DemoDateTimeDateTimeSeconds extends LitElement {
</div>
`
)}
</mwc-list>
</ha-list>
`;
}

View File

@@ -1,9 +1,9 @@
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 "../../../../src/components/ha-list";
import type { FrontendLocaleData } from "../../../../src/data/translation";
import {
DateFormat,
@@ -49,7 +49,7 @@ export class DemoDateTimeDateTimeShortYear extends LitElement {
@value-changed=${this.handleValueChanged}
>
</ha-control-select>
<mwc-list>
<ha-list>
<div class="container header">
<div>Language</div>
<div class="center">Default (lang)</div>
@@ -96,7 +96,7 @@ export class DemoDateTimeDateTimeShortYear extends LitElement {
</div>
`
)}
</mwc-list>
</ha-list>
`;
}

View File

@@ -1,9 +1,9 @@
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 "../../../../src/components/ha-list";
import type { FrontendLocaleData } from "../../../../src/data/translation";
import {
DateFormat,
@@ -49,7 +49,7 @@ export class DemoDateTimeDateTimeShort extends LitElement {
@value-changed=${this.handleValueChanged}
>
</ha-control-select>
<mwc-list>
<ha-list>
<div class="container header">
<div>Language</div>
<div class="center">Default (lang)</div>
@@ -96,7 +96,7 @@ export class DemoDateTimeDateTimeShort extends LitElement {
</div>
`
)}
</mwc-list>
</ha-list>
`;
}

View File

@@ -1,9 +1,9 @@
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 "../../../../src/components/ha-list";
import type { FrontendLocaleData } from "../../../../src/data/translation";
import {
DateFormat,
@@ -49,7 +49,7 @@ export class DemoDateTimeDateTime extends LitElement {
@value-changed=${this.handleValueChanged}
>
</ha-control-select>
<mwc-list>
<ha-list>
<div class="container header">
<div>Language</div>
<div class="center">Default (lang)</div>
@@ -96,7 +96,7 @@ export class DemoDateTimeDateTime extends LitElement {
</div>
`
)}
</mwc-list>
</ha-list>
`;
}

View File

@@ -1,8 +1,8 @@
import "@material/mwc-list/mwc-list";
import { css, html, LitElement } from "lit";
import { customElement } from "lit/decorators";
import { formatDateNumeric } from "../../../../src/common/datetime/format_date";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-list";
import type { FrontendLocaleData } from "../../../../src/data/translation";
import {
DateFormat,
@@ -27,7 +27,7 @@ export class DemoDateTimeDate extends LitElement {
};
const date = new Date();
return html`
<mwc-list>
<ha-list>
<div class="container header">
<div>Language</div>
<div class="center">Default (lang)</div>
@@ -86,7 +86,7 @@ export class DemoDateTimeDate extends LitElement {
</div>
`
)}
</mwc-list>
</ha-list>
`;
}

View File

@@ -1,9 +1,9 @@
import "@material/mwc-list/mwc-list";
import { LitElement, css, html } from "lit";
import { customElement, state } from "lit/decorators";
import { formatTimeWithSeconds } from "../../../../src/common/datetime/format_time";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-control-select";
import "../../../../src/components/ha-list";
import type { FrontendLocaleData } from "../../../../src/data/translation";
import {
DateFormat,
@@ -49,7 +49,7 @@ export class DemoDateTimeTimeSeconds extends LitElement {
@value-changed=${this.handleValueChanged}
>
</ha-control-select>
<mwc-list>
<ha-list>
<div class="container header">
<div>Language</div>
<div class="center">Default (lang)</div>
@@ -96,7 +96,7 @@ export class DemoDateTimeTimeSeconds extends LitElement {
</div>
`
)}
</mwc-list>
</ha-list>
`;
}

View File

@@ -1,9 +1,9 @@
import "@material/mwc-list/mwc-list";
import { LitElement, css, html } from "lit";
import { customElement, state } from "lit/decorators";
import { formatTimeWeekday } from "../../../../src/common/datetime/format_time";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-control-select";
import "../../../../src/components/ha-list";
import type { FrontendLocaleData } from "../../../../src/data/translation";
import {
DateFormat,
@@ -49,7 +49,7 @@ export class DemoDateTimeTimeWeekday extends LitElement {
@value-changed=${this.handleValueChanged}
>
</ha-control-select>
<mwc-list>
<ha-list>
<div class="container header">
<div>Language</div>
<div class="center">Default (lang)</div>
@@ -96,7 +96,7 @@ export class DemoDateTimeTimeWeekday extends LitElement {
</div>
`
)}
</mwc-list>
</ha-list>
`;
}

View File

@@ -1,9 +1,9 @@
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 "../../../../src/components/ha-list";
import type { FrontendLocaleData } from "../../../../src/data/translation";
import {
DateFormat,
@@ -49,7 +49,7 @@ export class DemoDateTimeTime extends LitElement {
@value-changed=${this.handleValueChanged}
>
</ha-control-select>
<mwc-list>
<ha-list>
<div class="container header">
<div>Language</div>
<div class="center">Default (lang)</div>
@@ -96,7 +96,7 @@ export class DemoDateTimeTime extends LitElement {
</div>
`
)}
</mwc-list>
</ha-list>
`;
}

View File

@@ -1,11 +1,11 @@
import type { PropertyValues, TemplateResult } from "lit";
import { html, LitElement } from "lit";
import { customElement, query } from "lit/decorators";
import { mockIcons } from "../../../../demo/src/stubs/icons";
import { mockTodo } from "../../../../demo/src/stubs/todo";
import { getEntity } from "../../../../src/fake_data/entity";
import { provideHass } from "../../../../src/fake_data/provide_hass";
import "../../components/demo-cards";
import { getEntity } from "../../../../src/fake_data/entity";
import { mockTodo } from "../../../../demo/src/stubs/todo";
import { mockIcons } from "../../../../demo/src/stubs/icons";
const ENTITIES = [
getEntity("todo", "shopping_list", "2", {

View File

@@ -1,5 +1,5 @@
import type { ActionDetail } from "@material/mwc-list/mwc-list-foundation";
import "@material/mwc-list/mwc-list-item";
import { mdiDotsVertical } from "@mdi/js";
import type { PropertyValues, TemplateResult } from "lit";
import { css, html, LitElement, nothing } from "lit";
@@ -11,6 +11,7 @@ import { navigate } from "../../../src/common/navigate";
import { extractSearchParam } from "../../../src/common/url/search-params";
import "../../../src/components/ha-button-menu";
import "../../../src/components/ha-icon-button";
import "../../../src/components/ha-list-item";
import "../../../src/components/search-input";
import type { HassioAddonRepository } from "../../../src/data/hassio/addon";
import { reloadHassioAddons } from "../../../src/data/hassio/addon";
@@ -89,17 +90,17 @@ export class HassioAddonStore extends LitElement {
.path=${mdiDotsVertical}
slot="trigger"
></ha-icon-button>
<mwc-list-item>
<ha-list-item>
${this.supervisor.localize("store.check_updates")}
</mwc-list-item>
<mwc-list-item>
</ha-list-item>
<ha-list-item>
${this.supervisor.localize("store.repositories")}
</mwc-list-item>
</ha-list-item>
${this.hass.userData?.showAdvanced &&
atLeastVersion(this.hass.config.version, 0, 117)
? html`<mwc-list-item>
? html`<ha-list-item>
${this.supervisor.localize("store.registries")}
</mwc-list-item>`
</ha-list-item>`
: ""}
</ha-button-menu>
${repos.length === 0

View File

@@ -1,12 +1,11 @@
import "@material/mwc-button";
import "@material/mwc-list/mwc-list-item";
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { stopPropagation } from "../../../../src/common/dom/stop_propagation";
import "../../../../src/components/buttons/ha-progress-button";
import "../../../../src/components/ha-alert";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-list-item";
import "../../../../src/components/ha-select";
import type {
HassioAddonDetails,
@@ -29,6 +28,8 @@ class HassioAddonAudio extends LitElement {
@property({ attribute: false }) public addon!: HassioAddonDetails;
@property({ type: Boolean }) public disabled = false;
@state() private _error?: string;
@state() private _inputDevices?: HassioHardwareAudioDevice[];
@@ -48,7 +49,7 @@ class HassioAddonAudio extends LitElement {
<div class="card-content">
${this._error
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
: ""}
: nothing}
${this._inputDevices &&
html`<ha-select
.label=${this.supervisor.localize(
@@ -59,12 +60,13 @@ class HassioAddonAudio extends LitElement {
fixedMenuPosition
naturalMenuWidth
.value=${this._selectedInput!}
.disabled=${this.disabled}
>
${this._inputDevices.map(
(item) => html`
<mwc-list-item .value=${item.device || ""}>
<ha-list-item .value=${item.device || ""}>
${item.name}
</mwc-list-item>
</ha-list-item>
`
)}
</ha-select>`}
@@ -78,18 +80,22 @@ class HassioAddonAudio extends LitElement {
fixedMenuPosition
naturalMenuWidth
.value=${this._selectedOutput!}
.disabled=${this.disabled}
>
${this._outputDevices.map(
(item) => html`
<mwc-list-item .value=${item.device || ""}
>${item.name}</mwc-list-item
<ha-list-item .value=${item.device || ""}
>${item.name}</ha-list-item
>
`
)}
</ha-select>`}
</div>
<div class="card-actions">
<ha-progress-button @click=${this._saveSettings}>
<ha-progress-button
.disabled=${this.disabled}
@click=${this._saveSettings}
>
${this.supervisor.localize("common.save")}
</ha-progress-button>
</div>
@@ -171,6 +177,10 @@ class HassioAddonAudio extends LitElement {
}
private async _saveSettings(ev: CustomEvent): Promise<void> {
if (this.disabled) {
return;
}
const button = ev.currentTarget as any;
button.progress = true;

View File

@@ -1,5 +1,5 @@
import type { CSSResultGroup, TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import "../../../../src/components/ha-spinner";
import type { HassioAddonDetails } from "../../../../src/data/hassio/addon";
@@ -7,6 +7,7 @@ import type { Supervisor } from "../../../../src/data/supervisor/supervisor";
import { haStyle } from "../../../../src/resources/styles";
import type { HomeAssistant } from "../../../../src/types";
import { hassioStyle } from "../../resources/hassio-style";
import "../info/hassio-addon-system-managed";
import "./hassio-addon-audio";
import "./hassio-addon-config";
import "./hassio-addon-network";
@@ -19,6 +20,11 @@ class HassioAddonConfigDashboard extends LitElement {
@property({ attribute: false }) public addon?: HassioAddonDetails;
@property({ type: Boolean }) public narrow = false;
@property({ type: Boolean, attribute: "control-enabled" })
public controlEnabled = false;
protected render(): TemplateResult {
if (!this.addon) {
return html`<ha-spinner></ha-spinner>`;
@@ -29,6 +35,16 @@ class HassioAddonConfigDashboard extends LitElement {
return html`
<div class="content">
${this.addon.system_managed &&
(hasConfiguration || this.addon.network || this.addon.audio)
? html`
<hassio-addon-system-managed
.supervisor=${this.supervisor}
.narrow=${this.narrow}
.hideButton=${this.controlEnabled}
></hassio-addon-system-managed>
`
: nothing}
${hasConfiguration || this.addon.network || this.addon.audio
? html`
${hasConfiguration
@@ -37,27 +53,33 @@ class HassioAddonConfigDashboard extends LitElement {
.hass=${this.hass}
.addon=${this.addon}
.supervisor=${this.supervisor}
.disabled=${this.addon.system_managed &&
!this.controlEnabled}
></hassio-addon-config>
`
: ""}
: nothing}
${this.addon.network
? html`
<hassio-addon-network
.hass=${this.hass}
.addon=${this.addon}
.supervisor=${this.supervisor}
.disabled=${this.addon.system_managed &&
!this.controlEnabled}
></hassio-addon-network>
`
: ""}
: nothing}
${this.addon.audio
? html`
<hassio-addon-audio
.hass=${this.hass}
.addon=${this.addon}
.supervisor=${this.supervisor}
.disabled=${this.addon.system_managed &&
!this.controlEnabled}
></hassio-addon-audio>
`
: ""}
: nothing}
`
: this.supervisor.localize("addon.configuration.no_configuration")}
</div>

View File

@@ -1,6 +1,4 @@
import "@material/mwc-button";
import type { ActionDetail } from "@material/mwc-list";
import "@material/mwc-list/mwc-list-item";
import { mdiDotsVertical } from "@mdi/js";
import { DEFAULT_SCHEMA, Type } from "js-yaml";
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
@@ -16,6 +14,7 @@ import "../../../../src/components/ha-form/ha-form";
import type { HaFormSchema } from "../../../../src/components/ha-form/types";
import "../../../../src/components/ha-formfield";
import "../../../../src/components/ha-icon-button";
import "../../../../src/components/ha-list-item";
import "../../../../src/components/ha-switch";
import "../../../../src/components/ha-yaml-editor";
import type { HaYamlEditor } from "../../../../src/components/ha-yaml-editor";
@@ -61,6 +60,8 @@ class HassioAddonConfig extends LitElement {
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ type: Boolean }) public disabled = false;
@state() private _configHasChanged = false;
@state() private _valid = true;
@@ -176,7 +177,7 @@ class HassioAddonConfig extends LitElement {
.path=${mdiDotsVertical}
slot="trigger"
></ha-icon-button>
<mwc-list-item .disabled=${!this._canShowSchema}>
<ha-list-item .disabled=${!this._canShowSchema || this.disabled}>
${this._yamlMode
? this.supervisor.localize(
"addon.configuration.options.edit_in_ui"
@@ -184,10 +185,13 @@ class HassioAddonConfig extends LitElement {
: this.supervisor.localize(
"addon.configuration.options.edit_in_yaml"
)}
</mwc-list-item>
<mwc-list-item class="warning">
</ha-list-item>
<ha-list-item
class=${!this.disabled ? "warning" : ""}
.disabled=${this.disabled}
>
${this.supervisor.localize("common.reset_defaults")}
</mwc-list-item>
</ha-list-item>
</ha-button-menu>
</div>
</div>
@@ -195,6 +199,7 @@ class HassioAddonConfig extends LitElement {
<div class="card-content">
${showForm
? html`<ha-form
.disabled=${this.disabled}
.data=${this._options!}
@value-changed=${this._configChanged}
.computeLabel=${this.computeLabel}
@@ -208,7 +213,7 @@ class HassioAddonConfig extends LitElement {
)
)}
></ha-form>`
: html` <ha-yaml-editor
: html`<ha-yaml-editor
@value-changed=${this._configChanged}
.yamlSchema=${ADDON_YAML_SCHEMA}
></ha-yaml-editor>`}
@@ -244,7 +249,9 @@ class HassioAddonConfig extends LitElement {
<div class="card-actions right">
<ha-progress-button
@click=${this._saveTapped}
.disabled=${!this._configHasChanged || !this._valid}
.disabled=${this.disabled ||
!this._configHasChanged ||
!this._valid}
>
${this.supervisor.localize("common.save")}
</ha-progress-button>
@@ -346,6 +353,10 @@ class HassioAddonConfig extends LitElement {
}
private async _saveTapped(ev: CustomEvent): Promise<void> {
if (this.disabled || !this._configHasChanged || !this._valid) {
return;
}
const button = ev.currentTarget as any;
const options: Record<string, unknown> = this._yamlMode
? this._editor?.value
@@ -407,7 +418,7 @@ class HassioAddonConfig extends LitElement {
z-index: 3;
--mdc-theme-text-primary-on-background: var(--primary-text-color);
}
mwc-list-item[disabled] {
ha-list-item[disabled] {
--mdc-theme-text-primary-on-background: var(--disabled-text-color);
}
.header {

View File

@@ -6,6 +6,7 @@ import { fireEvent } from "../../../../src/common/dom/fire_event";
import "../../../../src/components/buttons/ha-progress-button";
import "../../../../src/components/ha-alert";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-formfield";
import "../../../../src/components/ha-form/ha-form";
import type { HaFormSchema } from "../../../../src/components/ha-form/types";
import type {
@@ -28,6 +29,8 @@ class HassioAddonNetwork extends LitElement {
@property({ attribute: false }) public addon!: HassioAddonDetails;
@property({ type: Boolean }) public disabled = false;
@state() private _showOptional = false;
@state() private _configHasChanged = false;
@@ -65,9 +68,10 @@ class HassioAddonNetwork extends LitElement {
</p>
${this._error
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
: ""}
: nothing}
<ha-form
.disabled=${this.disabled}
.data=${this._config}
@value-changed=${this._configChanged}
.computeLabel=${this._computeLabel}
@@ -92,14 +96,18 @@ class HassioAddonNetwork extends LitElement {
>
</ha-switch>
</ha-formfield>`
: ""}
: nothing}
<div class="card-actions">
<ha-progress-button class="warning" @click=${this._resetTapped}>
<ha-progress-button
class="warning"
.disabled=${this.disabled}
@click=${this._resetTapped}
>
${this.supervisor.localize("common.reset_defaults")}
</ha-progress-button>
<ha-progress-button
@click=${this._saveTapped}
.disabled=${!this._configHasChanged}
.disabled=${!this._configHasChanged || this.disabled}
>
${this.supervisor.localize("common.save")}
</ha-progress-button>
@@ -155,6 +163,10 @@ class HassioAddonNetwork extends LitElement {
}
private async _resetTapped(ev: CustomEvent): Promise<void> {
if (this.disabled) {
return;
}
const button = ev.currentTarget as any;
const data: HassioAddonSetOptionParams = {
network: null,
@@ -186,6 +198,10 @@ class HassioAddonNetwork extends LitElement {
}
private async _saveTapped(ev: CustomEvent): Promise<void> {
if (!this._configHasChanged || this.disabled) {
return;
}
const button = ev.currentTarget as any;
this._error = undefined;

View File

@@ -52,6 +52,9 @@ class HassioAddonDashboard extends LitElement {
@property({ type: Boolean }) public narrow = false;
@state()
private _controlEnabled = false;
@state() private _error?: string;
private _backPath = new URLSearchParams(window.parent.location.search).get(
@@ -134,11 +137,17 @@ class HassioAddonDashboard extends LitElement {
.hass=${this.hass}
.supervisor=${this.supervisor}
.addon=${this.addon}
.controlEnabled=${this._controlEnabled}
@system-managed-take-control=${this._enableControl}
></hassio-addon-router>
</hass-tabs-subpage>
`;
}
private _enableControl() {
this._controlEnabled = true;
}
static get styles(): CSSResultGroup {
return [
haStyle,

View File

@@ -23,6 +23,9 @@ class HassioAddonRouter extends HassRouterPage {
| HassioAddonDetails
| StoreAddonDetails;
@property({ type: Boolean, attribute: "control-enabled" })
public controlEnabled = false;
protected routerOptions: RouterOptions = {
defaultPage: "info",
showLoading: true,
@@ -48,6 +51,7 @@ class HassioAddonRouter extends HassRouterPage {
el.supervisor = this.supervisor;
el.addon = this.addon;
el.narrow = this.narrow;
el.controlEnabled = this.controlEnabled;
}
}

View File

@@ -21,6 +21,9 @@ class HassioAddonInfoDashboard extends LitElement {
@property({ attribute: false }) public addon?: HassioAddonDetails;
@property({ type: Boolean, attribute: "control-enabled" })
public controlEnabled = false;
protected render(): TemplateResult {
if (!this.addon) {
return html`<ha-spinner></ha-spinner>`;
@@ -34,6 +37,7 @@ class HassioAddonInfoDashboard extends LitElement {
.hass=${this.hass}
.supervisor=${this.supervisor}
.addon=${this.addon}
.controlEnabled=${this.controlEnabled}
></hassio-addon-info>
</div>
`;

View File

@@ -1,8 +1,6 @@
import "@material/mwc-button";
import {
mdiCheckCircle,
mdiChip,
mdiPlayCircle,
mdiCircleOffOutline,
mdiCursorDefaultClickOutline,
mdiDocker,
@@ -19,27 +17,30 @@ import {
mdiNumeric6,
mdiNumeric7,
mdiNumeric8,
mdiPlayCircle,
mdiPound,
mdiShield,
} from "@mdi/js";
import type { CSSResultGroup, TemplateResult } from "lit";
import { LitElement, css, html } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import memoizeOne from "memoize-one";
import { atLeastVersion } from "../../../../src/common/config/version";
import { fireEvent } from "../../../../src/common/dom/fire_event";
import { navigate } from "../../../../src/common/navigate";
import { capitalizeFirstLetter } from "../../../../src/common/string/capitalize-first-letter";
import "../../../../src/components/buttons/ha-progress-button";
import "../../../../src/components/ha-alert";
import "../../../../src/components/ha-card";
import "../../../../src/components/chips/ha-chip-set";
import "../../../../src/components/chips/ha-assist-chip";
import "../../../../src/components/chips/ha-chip-set";
import "../../../../src/components/ha-alert";
import "../../../../src/components/ha-button";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-formfield";
import "../../../../src/components/ha-markdown";
import "../../../../src/components/ha-settings-row";
import "../../../../src/components/ha-svg-icon";
import "../../../../src/components/ha-switch";
import "../../../../src/components/ha-formfield";
import type { HaSwitch } from "../../../../src/components/ha-switch";
import type {
AddonCapability,
@@ -81,10 +82,11 @@ import { bytesToString } from "../../../../src/util/bytes-to-string";
import "../../components/hassio-card-content";
import "../../components/supervisor-metric";
import { showHassioMarkdownDialog } from "../../dialogs/markdown/show-dialog-hassio-markdown";
import { showSystemManagedDialog } from "../../dialogs/system-managed/show-dialog-system-managed";
import { hassioStyle } from "../../resources/hassio-style";
import "../../update-available/update-available-card";
import { addonArchIsSupported, extractChangelog } from "../../util/addon";
import { capitalizeFirstLetter } from "../../../../src/common/string/capitalize-first-letter";
import "./hassio-addon-system-managed";
const STAGE_ICON = {
stable: mdiCheckCircle,
@@ -117,6 +119,9 @@ class HassioAddonInfo extends LitElement {
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ type: Boolean, attribute: "control-enabled" })
public controlEnabled = false;
@state() private _metrics?: HassioStats;
@state() private _error?: string;
@@ -155,6 +160,9 @@ class HassioAddonInfo extends LitElement {
)}`,
},
];
const systemManaged = this._isSystemManaged(this.addon);
return html`
${this.addon.update_available
? html`
@@ -166,7 +174,7 @@ class HassioAddonInfo extends LitElement {
@update-complete=${this._updateComplete}
></update-available-card>
`
: ""}
: nothing}
${"protected" in this.addon && !this.addon.protected
? html`
<ha-alert
@@ -178,22 +186,31 @@ class HassioAddonInfo extends LitElement {
${this.supervisor.localize(
"addon.dashboard.protection_mode.content"
)}
<mwc-button
<ha-button
slot="action"
.label=${this.supervisor.localize(
"addon.dashboard.protection_mode.enable"
)}
@click=${this._protectionToggled}
>
</mwc-button>
</ha-button>
</ha-alert>
`
: ""}
: nothing}
${systemManaged
? html`
<hassio-addon-system-managed
.supervisor=${this.supervisor}
.narrow=${this.narrow}
.hideButton=${this.controlEnabled}
></hassio-addon-system-managed>
`
: nothing}
<ha-card outlined>
<div class="card-content">
<div class="addon-header">
${!this.narrow ? this.addon.name : ""}
${!this.narrow ? this.addon.name : nothing}
<div class="addon-version light-color">
${this.addon.version
? html`
@@ -266,7 +283,7 @@ class HassioAddonInfo extends LitElement {
</ha-svg-icon>
</ha-assist-chip>
`
: ""}
: nothing}
<ha-assist-chip
filled
@@ -301,7 +318,7 @@ class HassioAddonInfo extends LitElement {
<ha-svg-icon slot="icon" .path=${mdiNetwork}> </ha-svg-icon>
</ha-assist-chip>
`
: ""}
: nothing}
${this.addon.full_access
? html`
<ha-assist-chip
@@ -317,7 +334,7 @@ class HassioAddonInfo extends LitElement {
<ha-svg-icon slot="icon" .path=${mdiChip}></ha-svg-icon>
</ha-assist-chip>
`
: ""}
: nothing}
${this.addon.homeassistant_api
? html`
<ha-assist-chip
@@ -336,7 +353,7 @@ class HassioAddonInfo extends LitElement {
></ha-svg-icon>
</ha-assist-chip>
`
: ""}
: nothing}
${this._computeHassioApi
? html`
<ha-assist-chip
@@ -355,7 +372,7 @@ class HassioAddonInfo extends LitElement {
></ha-svg-icon>
</ha-assist-chip>
`
: ""}
: nothing}
${this.addon.docker_api
? html`
<ha-assist-chip
@@ -371,7 +388,7 @@ class HassioAddonInfo extends LitElement {
<ha-svg-icon slot="icon" .path=${mdiDocker}></ha-svg-icon>
</ha-assist-chip>
`
: ""}
: nothing}
${this.addon.host_pid
? html`
<ha-assist-chip
@@ -387,7 +404,7 @@ class HassioAddonInfo extends LitElement {
<ha-svg-icon slot="icon" .path=${mdiPound}></ha-svg-icon>
</ha-assist-chip>
`
: ""}
: nothing}
${this.addon.apparmor !== "default"
? html`
<ha-assist-chip
@@ -404,7 +421,7 @@ class HassioAddonInfo extends LitElement {
<ha-svg-icon slot="icon" .path=${mdiShield}></ha-svg-icon>
</ha-assist-chip>
`
: ""}
: nothing}
${this.addon.auth_api
? html`
<ha-assist-chip
@@ -420,7 +437,7 @@ class HassioAddonInfo extends LitElement {
<ha-svg-icon slot="icon" .path=${mdiKey}></ha-svg-icon>
</ha-assist-chip>
`
: ""}
: nothing}
${this.addon.ingress
? html`
<ha-assist-chip
@@ -439,7 +456,7 @@ class HassioAddonInfo extends LitElement {
></ha-svg-icon>
</ha-assist-chip>
`
: ""}
: nothing}
${this.addon.signed
? html`
<ha-assist-chip
@@ -455,7 +472,24 @@ class HassioAddonInfo extends LitElement {
<ha-svg-icon slot="icon" .path=${mdiLinkLock}></ha-svg-icon>
</ha-assist-chip>
`
: ""}
: nothing}
${systemManaged
? html`
<ha-assist-chip
filled
@click=${this._showSystemManagedDialog}
id="system_managed"
.label=${capitalizeFirstLetter(
this.supervisor.localize("addon.system_managed.badge")
)}
>
<ha-svg-icon
slot="icon"
.path=${mdiHomeAssistant}
></ha-svg-icon>
</ha-assist-chip>
`
: nothing}
</ha-chip-set>
<div class="description light-color">
@@ -479,7 +513,7 @@ class HassioAddonInfo extends LitElement {
src="/api/hassio/addons/${this.addon.slug}/logo"
/>
`
: ""}
: nothing}
${this.addon.version
? html`
<div
@@ -500,6 +534,7 @@ class HassioAddonInfo extends LitElement {
)}
</span>
<ha-switch
.disabled=${systemManaged && !this.controlEnabled}
@change=${this._startOnBootToggled}
.checked=${this.addon.boot === "auto"}
haptic
@@ -520,13 +555,15 @@ class HassioAddonInfo extends LitElement {
)}
</span>
<ha-switch
.disabled=${systemManaged &&
!this.controlEnabled}
@change=${this._watchdogToggled}
.checked=${this.addon.watchdog}
.checked=${this.addon.watchdog || false}
haptic
></ha-switch>
</ha-settings-row>
`
: ""}
: nothing}
${this.addon.auto_update ||
this.hass.userData?.showAdvanced
? html`
@@ -542,13 +579,15 @@ class HassioAddonInfo extends LitElement {
)}
</span>
<ha-switch
.disabled=${systemManaged &&
!this.controlEnabled}
@change=${this._autoUpdateToggled}
.checked=${this.addon.auto_update}
haptic
></ha-switch>
</ha-settings-row>
`
: ""}
: nothing}
${!this._computeCannotIngressSidebar && this.addon.ingress
? html`
<ha-settings-row ?three-line=${this.narrow}>
@@ -563,13 +602,15 @@ class HassioAddonInfo extends LitElement {
)}
</span>
<ha-switch
.disabled=${systemManaged &&
!this.controlEnabled}
@change=${this._panelToggled}
.checked=${this.addon.ingress_panel}
haptic
></ha-switch>
</ha-settings-row>
`
: ""}
: nothing}
${this._computeUsesProtectedOptions
? html`
<ha-settings-row ?three-line=${this.narrow}>
@@ -584,16 +625,18 @@ class HassioAddonInfo extends LitElement {
)}
</span>
<ha-switch
.disabled=${systemManaged &&
!this.controlEnabled}
@change=${this._protectionToggled}
.checked=${this.addon.protected}
haptic
></ha-switch>
</ha-settings-row>
`
: ""}
: nothing}
</div>
`
: ""}
: nothing}
</div>
<div>
${this.addon.version && this.addon.state === "started"
@@ -612,12 +655,12 @@ class HassioAddonInfo extends LitElement {
></supervisor-metric>
`
)}`
: ""}
: nothing}
</div>
</div>
${this._error
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
: ""}
: nothing}
${!this.addon.version && addonStoreInfo && !this.addon.available
? !addonArchIsSupported(
this.supervisor.info.supported_arch,
@@ -641,7 +684,7 @@ class HassioAddonInfo extends LitElement {
)}
</ha-alert>
`
: ""}
: nothing}
</div>
<div class="card-actions">
<div>
@@ -651,6 +694,7 @@ class HassioAddonInfo extends LitElement {
<ha-progress-button
class="warning"
@click=${this._stopClicked}
.disabled=${systemManaged && !this.controlEnabled}
>
${this.supervisor.localize("addon.dashboard.stop")}
</ha-progress-button>
@@ -688,26 +732,27 @@ class HassioAddonInfo extends LitElement {
target="_blank"
rel="noopener"
>
<mwc-button>
<ha-button>
${this.supervisor.localize(
"addon.dashboard.open_web_ui"
)}
</mwc-button>
</ha-button>
</a>
`
: ""}
: nothing}
${this._computeShowIngressUI
? html`
<mwc-button @click=${this._openIngress}>
<ha-button @click=${this._openIngress}>
${this.supervisor.localize(
"addon.dashboard.open_web_ui"
)}
</mwc-button>
</ha-button>
`
: ""}
: nothing}
<ha-progress-button
class="warning"
@click=${this._uninstallClicked}
.disabled=${systemManaged && !this.controlEnabled}
>
${this.supervisor.localize("addon.dashboard.uninstall")}
</ha-progress-button>
@@ -720,8 +765,8 @@ class HassioAddonInfo extends LitElement {
${this.supervisor.localize("addon.dashboard.rebuild")}
</ha-progress-button>
`
: ""}`
: ""}
: nothing}`
: nothing}
</div>
</div>
</ha-card>
@@ -737,7 +782,7 @@ class HassioAddonInfo extends LitElement {
</div>
</ha-card>
`
: ""}
: nothing}
`;
}
@@ -822,6 +867,13 @@ class HassioAddonInfo extends LitElement {
});
}
private _showSystemManagedDialog() {
showSystemManagedDialog(this, {
addon: this.addon as HassioAddonDetails,
supervisor: this.supervisor,
});
}
private get _computeIsRunning(): boolean {
return (this.addon as HassioAddonDetails)?.state === "started";
}
@@ -1014,6 +1066,10 @@ class HassioAddonInfo extends LitElement {
}
private async _stopClicked(ev: CustomEvent): Promise<void> {
if (this._isSystemManaged(this.addon) && !this.controlEnabled) {
return;
}
const button = ev.currentTarget as any;
button.progress = true;
@@ -1125,6 +1181,10 @@ class HassioAddonInfo extends LitElement {
}
private async _uninstallClicked(ev: CustomEvent): Promise<void> {
if (this._isSystemManaged(this.addon) && !this.controlEnabled) {
return;
}
const button = ev.currentTarget as any;
button.progress = true;
let removeData = false;
@@ -1179,6 +1239,11 @@ class HassioAddonInfo extends LitElement {
button.progress = false;
}
private _isSystemManaged = memoizeOne(
(addon: HassioAddonDetails | StoreAddonDetails) =>
"system_managed" in addon && addon.system_managed
);
static get styles(): CSSResultGroup {
return [
haStyle,
@@ -1201,7 +1266,7 @@ class HassioAddonInfo extends LitElement {
ha-card.warning .card-content {
color: white;
}
ha-card.warning mwc-button {
ha-card.warning ha-button {
--mdc-theme-primary: white !important;
}
.warning {
@@ -1246,7 +1311,7 @@ class HassioAddonInfo extends LitElement {
ha-svg-icon.stopped {
color: var(--error-color);
}
protection-enable mwc-button {
protection-enable ha-button {
--mdc-theme-primary: white;
}
.description a {
@@ -1328,7 +1393,7 @@ class HassioAddonInfo extends LitElement {
align-self: end;
}
ha-alert mwc-button {
ha-alert ha-button {
--mdc-theme-primary: var(--primary-text-color);
}

View File

@@ -0,0 +1,60 @@
import "@material/mwc-button";
import type { TemplateResult } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import { fireEvent } from "../../../../src/common/dom/fire_event";
import "../../../../src/components/ha-alert";
import "../../../../src/components/ha-button";
import type { Supervisor } from "../../../../src/data/supervisor/supervisor";
@customElement("hassio-addon-system-managed")
class HassioAddonSystemManaged extends LitElement {
@property({ type: Boolean }) public narrow = false;
@property({ attribute: false }) public supervisor!: Supervisor;
@property({ type: Boolean, attribute: "hide-button" }) public hideButton =
false;
protected render(): TemplateResult {
return html`
<ha-alert
alert-type="warning"
.title=${this.supervisor.localize("addon.system_managed.title")}
.narrow=${this.narrow}
>
${this.supervisor.localize("addon.system_managed.description")}
${!this.hideButton
? html`
<ha-button slot="action" @click=${this._takeControl}>
${this.supervisor.localize("addon.system_managed.take_control")}
</ha-button>
`
: nothing}
</ha-alert>
`;
}
private _takeControl() {
fireEvent(this, "system-managed-take-control");
}
static styles = css`
ha-alert {
display: block;
margin-bottom: 16px;
}
ha-button {
white-space: nowrap;
}
`;
}
declare global {
interface HTMLElementTagNameMap {
"hassio-addon-system-managed": HassioAddonSystemManaged;
}
interface HASSDomEvents {
"system-managed-take-control": undefined;
}
}

View File

@@ -1,6 +1,6 @@
import "@material/mwc-button";
import type { ActionDetail } from "@material/mwc-list";
import "@material/mwc-list/mwc-list-item";
import { mdiBackupRestore, mdiDelete, mdiDotsVertical, mdiPlus } from "@mdi/js";
import type { CSSResultGroup, PropertyValues } from "lit";
import { LitElement, css, html, nothing } from "lit";
@@ -18,6 +18,7 @@ import type {
import "../../../src/components/ha-button-menu";
import "../../../src/components/ha-fab";
import "../../../src/components/ha-icon-button";
import "../../../src/components/ha-list-item";
import "../../../src/components/ha-svg-icon";
import type { HassioBackup } from "../../../src/data/hassio/backup";
import {
@@ -32,6 +33,7 @@ import {
showAlertDialog,
showConfirmationDialog,
} from "../../../src/dialogs/generic/show-dialog-box";
import "../../../src/layouts/hass-loading-screen";
import "../../../src/layouts/hass-tabs-subpage-data-table";
import type { HaTabsSubpageDataTable } from "../../../src/layouts/hass-tabs-subpage-data-table";
import { haStyle } from "../../../src/resources/styles";
@@ -42,7 +44,6 @@ import { showHassioBackupDialog } from "../dialogs/backup/show-dialog-hassio-bac
import { showHassioCreateBackupDialog } from "../dialogs/backup/show-dialog-hassio-create-backup";
import { supervisorTabs } from "../hassio-tabs";
import { hassioStyle } from "../resources/hassio-style";
import "../../../src/layouts/hass-loading-screen";
type BackupItem = HassioBackup & {
secondary: string;
@@ -211,16 +212,16 @@ export class HassioBackups extends LitElement {
.path=${mdiDotsVertical}
slot="trigger"
></ha-icon-button>
<mwc-list-item>
<ha-list-item>
${this.supervisor.localize("common.reload")}
</mwc-list-item>
<mwc-list-item>
</ha-list-item>
<ha-list-item>
${this.supervisor.localize("dialog.backup_location.title")}
</mwc-list-item>
</ha-list-item>
${atLeastVersion(this.hass.config.version, 0, 116)
? html`<mwc-list-item>
? html`<ha-list-item>
${this.supervisor.localize("backup.upload_backup")}
</mwc-list-item>`
</ha-list-item>`
: ""}
</ha-button-menu>

View File

@@ -85,7 +85,7 @@ class HassioCardContent extends LitElement {
}
ha-svg-icon.hassupdate,
ha-svg-icon.backup {
color: var(--paper-item-icon-color);
color: var(--state-icon-color);
}
ha-svg-icon.not_available {
color: var(--error-color);

View File

@@ -130,7 +130,7 @@ export class HassioUpdate extends LitElement {
color: var(--primary-text-color);
}
.update-heading {
font-size: var(--paper-font-subhead_-_font-size);
font-size: var(--ha-font-size-l);
font-weight: 500;
margin-bottom: 0.5em;
color: var(--primary-text-color);

View File

@@ -1,5 +1,5 @@
import type { ActionDetail } from "@material/mwc-list";
import "@material/mwc-list/mwc-list-item";
import { mdiClose, mdiDotsVertical } from "@mdi/js";
import type { CSSResultGroup } from "lit";
import { css, html, LitElement, nothing } from "lit";
@@ -8,15 +8,17 @@ import { atLeastVersion } from "../../../../src/common/config/version";
import { fireEvent } from "../../../../src/common/dom/fire_event";
import { stopPropagation } from "../../../../src/common/dom/stop_propagation";
import { slugify } from "../../../../src/common/string/slugify";
import "../../../../src/components/ha-md-dialog";
import "../../../../src/components/ha-dialog-header";
import "../../../../src/components/buttons/ha-progress-button";
import "../../../../src/components/ha-alert";
import "../../../../src/components/ha-spinner";
import "../../../../src/components/ha-button";
import "../../../../src/components/ha-button-menu";
import "../../../../src/components/ha-dialog-header";
import "../../../../src/components/ha-header-bar";
import "../../../../src/components/ha-icon-button";
import "../../../../src/components/ha-list-item";
import "../../../../src/components/ha-md-dialog";
import type { HaMdDialog } from "../../../../src/components/ha-md-dialog";
import "../../../../src/components/ha-spinner";
import { getSignedPath } from "../../../../src/data/auth";
import type { HassioBackupDetail } from "../../../../src/data/hassio/backup";
import {
@@ -36,7 +38,6 @@ import { fileDownload } from "../../../../src/util/file_download";
import "../../components/supervisor-backup-content";
import type { SupervisorBackupContent } from "../../components/supervisor-backup-content";
import type { HassioBackupDialogParams } from "./show-dialog-hassio-backup";
import type { HaMdDialog } from "../../../../src/components/ha-md-dialog";
@customElement("dialog-hassio-backup")
class HassioBackupDialog
@@ -121,15 +122,15 @@ class HassioBackupDialog
.path=${mdiDotsVertical}
slot="trigger"
></ha-icon-button>
<mwc-list-item
<ha-list-item
>${this._dialogParams.supervisor.localize(
"backup.download_backup"
)}</mwc-list-item
)}</ha-list-item
>
<mwc-list-item class="error"
<ha-list-item class="error"
>${this._dialogParams.supervisor.localize(
"backup.delete_backup_title"
)}</mwc-list-item
)}</ha-list-item
>
</ha-button-menu>`
: nothing}

View File

@@ -1,12 +1,12 @@
import "@material/mwc-list/mwc-list-item";
import type { CSSResultGroup } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../../../src/common/dom/fire_event";
import "../../../../src/components/ha-spinner";
import "../../../../src/components/ha-select";
import "../../../../src/components/ha-dialog";
import "../../../../src/components/ha-list-item";
import "../../../../src/components/ha-select";
import "../../../../src/components/ha-spinner";
import {
extractApiErrorMessage,
ignoreSupervisorError,
@@ -95,8 +95,8 @@ class HassioDatadiskDialog extends LitElement {
>
${this.devices.map(
(device) =>
html`<mwc-list-item .value=${device}
>${device}</mwc-list-item
html`<ha-list-item .value=${device}
>${device}</ha-list-item
>`
)}
</ha-select>

View File

@@ -16,23 +16,14 @@ import type { HomeAssistant } from "../../../../src/types";
import type { HassioHardwareDialogParams } from "./show-dialog-hassio-hardware";
const _filterDevices = memoizeOne(
(
showAdvanced: boolean,
hardware: HassioHardwareInfo,
filter: string,
language: string
) =>
(hardware: HassioHardwareInfo, filter: string, language: string) =>
hardware.devices
.filter(
(device) =>
(showAdvanced ||
["tty", "gpio", "input"].includes(device.subsystem)) &&
(device.by_id?.toLowerCase().includes(filter) ||
device.name.toLowerCase().includes(filter) ||
device.dev_path.toLocaleLowerCase().includes(filter) ||
JSON.stringify(device.attributes)
.toLocaleLowerCase()
.includes(filter))
device.by_id?.toLowerCase().includes(filter) ||
device.name.toLowerCase().includes(filter) ||
device.dev_path.toLocaleLowerCase().includes(filter) ||
JSON.stringify(device.attributes).toLocaleLowerCase().includes(filter)
)
.sort((a, b) => stringCompare(a.name, b.name, language))
);
@@ -60,7 +51,6 @@ class HassioHardwareDialog extends LitElement {
}
const devices = _filterDevices(
this.hass.userData?.showAdvanced || false,
this._dialogParams.hardware,
(this._filter || "").toLowerCase(),
this.hass.locale.language
@@ -180,7 +170,7 @@ class HassioHardwareDialog extends LitElement {
padding: 16px;
overflow: auto;
line-height: 1.45;
font-family: var(--code-font-family, monospace);
font-family: var(--ha-font-family-code);
}
code {
font-size: 85%;

View File

@@ -38,6 +38,7 @@ class HassioMarkdownDialog extends LitElement {
open
@closed=${this.closeDialog}
.heading=${createCloseHeading(this.hass, this.title)}
hideactions
>
<ha-markdown
.content=${this.content || ""}

View File

@@ -1,8 +1,4 @@
import "@material/mwc-button/mwc-button";
import "@material/mwc-list/mwc-list";
import "@material/mwc-list/mwc-list-item";
import "@material/mwc-tab";
import "@material/mwc-tab-bar";
import { mdiClose } from "@mdi/js";
import type { CSSResultGroup } from "lit";
import { css, html, LitElement, nothing } from "lit";
@@ -10,14 +6,16 @@ import { customElement, property, state } from "lit/decorators";
import { cache } from "lit/directives/cache";
import { fireEvent } from "../../../../src/common/dom/fire_event";
import "../../../../src/components/ha-alert";
import "../../../../src/components/ha-spinner";
import "../../../../src/components/ha-dialog";
import "../../../../src/components/ha-expansion-panel";
import "../../../../src/components/ha-formfield";
import "../../../../src/components/ha-header-bar";
import "../../../../src/components/ha-icon-button";
import "../../../../src/components/ha-list";
import "../../../../src/components/ha-list-item";
import "../../../../src/components/ha-password-field";
import "../../../../src/components/ha-radio";
import "../../../../src/components/ha-spinner";
import "../../../../src/components/ha-textfield";
import type { HaTextField } from "../../../../src/components/ha-textfield";
import { extractApiErrorMessage } from "../../../../src/data/hassio/common";
@@ -39,6 +37,7 @@ import type { HassDialog } from "../../../../src/dialogs/make-dialog-manager";
import { haStyleDialog } from "../../../../src/resources/styles";
import type { HomeAssistant } from "../../../../src/types";
import type { HassioNetworkDialogParams } from "./show-dialog-network";
import "../../../../src/components/sl-tab-group";
const IP_VERSIONS = ["ipv4", "ipv6"];
@@ -116,19 +115,19 @@ export class DialogHassioNetwork
></ha-icon-button>
</ha-header-bar>
${this._interfaces.length > 1
? html`<mwc-tab-bar
.activeIndex=${this._curTabIndex}
@MDCTabBar:activated=${this._handleTabActivated}
? html`<sl-tab-group @sl-tab-show=${this._handleTabActivated}
>${this._interfaces.map(
(device) =>
html`<mwc-tab
(device, index) =>
html`<sl-tab
slot="nav"
.id=${device.interface}
.label=${device.interface}
dialogInitialFocus
.panel=${index.toString()}
.active=${this._curTabIndex === index}
>
</mwc-tab>`
${device.interface}
</sl-tab>`
)}
</mwc-tab-bar>`
</sl-tab-group>`
: ""}
</div>
${cache(this._renderTab())}
@@ -169,12 +168,12 @@ export class DialogHassioNetwork
this._accessPoints.accesspoints &&
this._accessPoints.accesspoints.length !== 0
? html`
<mwc-list>
<ha-list>
${this._accessPoints.accesspoints
.filter((ap) => ap.ssid)
.map(
(ap) => html`
<mwc-list-item
<ha-list-item
twoline
@click=${this._selectAP}
.activated=${ap.ssid ===
@@ -189,10 +188,10 @@ export class DialogHassioNetwork
)}:
${ap.signal}
</span>
</mwc-list-item>
</ha-list-item>
`
)}
</mwc-list>
</ha-list>
`
: ""}
${this._wifiConfiguration
@@ -485,8 +484,8 @@ export class DialogHassioNetwork
return;
}
}
this._curTabIndex = ev.detail.index;
this._interface = { ...this._interfaces[ev.detail.index] };
this._curTabIndex = Number(ev.detail.name);
this._interface = { ...this._interfaces[this._curTabIndex] };
}
private _handleRadioValueChanged(ev: CustomEvent): void {
@@ -560,11 +559,6 @@ export class DialogHassioNetwork
flex-shrink: 0;
}
mwc-tab-bar {
border-bottom: 1px solid
var(--mdc-dialog-scroll-divider-color, rgba(0, 0, 0, 0.12));
}
ha-dialog {
--dialog-content-position: static;
--dialog-content-padding: 0;
@@ -634,9 +628,17 @@ export class DialogHassioNetwork
ha-textfield {
padding: 0 14px;
}
mwc-list-item {
ha-list-item {
--mdc-list-side-padding: 10px;
}
sl-tab {
flex: 1;
}
sl-tab::part(base) {
width: 100%;
justify-content: center;
}
`,
];
}

View File

@@ -183,9 +183,6 @@ class HassioRepositoriesDialog extends LitElement {
ha-dialog.button-left {
--justify-action-buttons: flex-start;
}
paper-icon-item {
cursor: pointer;
}
.form {
color: var(--primary-text-color);
}

View File

@@ -0,0 +1,192 @@
import { mdiClose, mdiPuzzle, mdiSwapHorizontal } from "@mdi/js";
import type { CSSResultGroup } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { atLeastVersion } from "../../../../src/common/config/version";
import "../../../../src/components/ha-dialog-header";
import "../../../../src/components/ha-icon-button";
import "../../../../src/components/ha-icon-next";
import "../../../../src/components/ha-md-dialog";
import type { HaMdDialog } from "../../../../src/components/ha-md-dialog";
import "../../../../src/components/ha-md-list";
import "../../../../src/components/ha-md-list-item";
import "../../../../src/components/ha-svg-icon";
import {
getConfigEntry,
type ConfigEntry,
} from "../../../../src/data/config_entries";
import type { HassioAddonDetails } from "../../../../src/data/hassio/addon";
import type { Supervisor } from "../../../../src/data/supervisor/supervisor";
import { mdiHomeAssistant } from "../../../../src/resources/home-assistant-logo-svg";
import { haStyle } from "../../../../src/resources/styles";
import type { HomeAssistant } from "../../../../src/types";
import { brandsUrl } from "../../../../src/util/brands-url";
import type { SystemManagedDialogParams } from "./show-dialog-system-managed";
@customElement("dialog-system-managed")
class HassioSystemManagedDialog extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@state() private _supervisor?: Supervisor;
@state() private _addon?: HassioAddonDetails;
@state() private _open = false;
@state() private _configEntry?: ConfigEntry;
@query("ha-md-dialog") private _dialog?: HaMdDialog;
public async showDialog(
dialogParams: SystemManagedDialogParams
): Promise<void> {
this._addon = dialogParams.addon;
this._supervisor = dialogParams.supervisor;
this._open = true;
this._loadConfigEntry();
}
private _dialogClosed() {
this._addon = undefined;
this._supervisor = undefined;
this._configEntry = undefined;
this._open = false;
}
public closeDialog() {
this._dialog?.close();
return true;
}
protected render() {
if (!this._addon || !this._open || !this._supervisor) {
return nothing;
}
const addonImage =
atLeastVersion(this.hass.config.version, 0, 105) && this._addon.icon
? `/api/hassio/addons/${this._addon.slug}/icon`
: undefined;
return html`
<ha-md-dialog open @closed=${this._dialogClosed}>
<ha-dialog-header slot="headline">
<ha-icon-button
slot="navigationIcon"
.path=${mdiClose}
@click=${this.closeDialog}
></ha-icon-button>
<span slot="title">${this._addon?.name}</span>
</ha-dialog-header>
<div slot="content">
<div class="icons">
<ha-svg-icon
class="primary"
.path=${mdiHomeAssistant}
></ha-svg-icon>
<ha-svg-icon .path=${mdiSwapHorizontal}></ha-svg-icon>
${addonImage
? html`<img src=${addonImage} alt=${this._addon.name} />`
: html`<ha-svg-icon .path=${mdiPuzzle}></ha-svg-icon>`}
</div>
${this._supervisor.localize("addon.system_managed.title")}.<br />
${this._supervisor.localize("addon.system_managed.description")}
${this._configEntry
? html`
<h3>
${this._supervisor.localize(
"addon.system_managed.managed_by"
)}:
</h3>
<ha-md-list>
<ha-md-list-item
type="link"
href=${`/config/integrations/integration/${this._configEntry.domain}`}
>
<img
slot="start"
class="integration-icon"
alt=${this._configEntry.title}
src=${brandsUrl({
domain: this._configEntry.domain,
type: "icon",
darkOptimized: this.hass.themes?.darkMode,
})}
crossorigin="anonymous"
referrerpolicy="no-referrer"
@error=${this._onImageError}
@load=${this._onImageLoad}
/>
${this._configEntry.title}
<ha-icon-next slot="end"></ha-icon-next>
</ha-md-list-item>
</ha-md-list>
`
: nothing}
</div>
</ha-md-dialog>
`;
}
private _onImageLoad(ev) {
ev.target.style.visibility = "initial";
}
private _onImageError(ev) {
ev.target.style.visibility = "hidden";
}
private async _loadConfigEntry() {
if (this._addon?.system_managed_config_entry) {
try {
const { config_entry } = await getConfigEntry(
this.hass,
this._addon.system_managed_config_entry
);
this._configEntry = config_entry;
} catch (err) {
// eslint-disable-next-line no-console
console.error(err);
}
}
}
static get styles(): CSSResultGroup {
return [
haStyle,
css`
.icons {
display: flex;
justify-content: center;
align-items: center;
gap: 16px;
--mdc-icon-size: 48px;
margin-bottom: 32px;
}
.icons img {
width: 48px;
}
.icons .primary {
color: var(--primary-color);
}
.actions {
display: flex;
justify-content: space-between;
}
.integration-icon {
width: 24px;
}
ha-md-list-item {
--md-list-item-leading-space: 4px;
--md-list-item-trailing-space: 4px;
}
`,
];
}
}
declare global {
interface HTMLElementTagNameMap {
"dialog-system-managed": HassioSystemManagedDialog;
}
}

View File

@@ -0,0 +1,19 @@
import { fireEvent } from "../../../../src/common/dom/fire_event";
import type { HassioAddonDetails } from "../../../../src/data/hassio/addon";
import type { Supervisor } from "../../../../src/data/supervisor/supervisor";
export interface SystemManagedDialogParams {
addon: HassioAddonDetails;
supervisor: Supervisor;
}
export const showSystemManagedDialog = (
element: HTMLElement,
dialogParams: SystemManagedDialogParams
): void => {
fireEvent(element, "show-dialog", {
dialogTag: "dialog-system-managed",
dialogImport: () => import("./dialog-system-managed"),
dialogParams,
});
};

View File

@@ -1,9 +1,6 @@
import "./hassio-main";
import("../../src/resources/ha-style");
import("@polymer/polymer/lib/utils/settings").then(
({ setCancelSyntheticClickEvents }) => setCancelSyntheticClickEvents(false)
);
import("../../src/resources/append-ha-style");
const styleEl = document.createElement("style");
styleEl.textContent = `

View File

@@ -12,12 +12,11 @@ export const hassioStyle = css`
h1 {
font-size: 2em;
margin-bottom: 8px;
font-family: var(--paper-font-headline_-_font-family);
-webkit-font-smoothing: var(--paper-font-headline_-_-webkit-font-smoothing);
font-size: var(--paper-font-headline_-_font-size);
font-weight: var(--paper-font-headline_-_font-weight);
letter-spacing: var(--paper-font-headline_-_letter-spacing);
line-height: var(--paper-font-headline_-_line-height);
font-family: var(--ha-font-family-body);
-webkit-font-smoothing: var(--ha-font-smoothing);
font-size: var(--ha-font-size-2xl);
font-weight: var(--ha-font-weight-normal);
line-height: var(--ha-line-height-condensed);
padding-left: 8px;
padding-inline-start: 8px;
padding-inline-end: initial;

View File

@@ -1,5 +1,5 @@
import "@material/mwc-button";
import "@material/mwc-list/mwc-list-item";
import type { CSSResultGroup, TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators";
@@ -197,9 +197,6 @@ class HassioCoreInfo extends LitElement {
color: var(--secondary-text-color);
--mdc-menu-min-width: 200px;
}
mwc-list-item ha-svg-icon {
color: var(--secondary-text-color);
}
a {
text-decoration: none;
}

View File

@@ -1,5 +1,5 @@
import "@material/mwc-button";
import "@material/mwc-list/mwc-list-item";
import { mdiDotsVertical } from "@mdi/js";
import type { CSSResultGroup, TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
@@ -10,6 +10,7 @@ import { fireEvent } from "../../../src/common/dom/fire_event";
import "../../../src/components/buttons/ha-progress-button";
import "../../../src/components/ha-button-menu";
import "../../../src/components/ha-card";
import "../../../src/components/ha-list-item";
import "../../../src/components/ha-icon-button";
import "../../../src/components/ha-settings-row";
import {
@@ -188,31 +189,31 @@ class HassioHostInfo extends LitElement {
.path=${mdiDotsVertical}
slot="trigger"
></ha-icon-button>
<mwc-list-item
<ha-list-item
.action=${"hardware"}
@click=${this._handleMenuAction}
>
${this.supervisor.localize("system.host.hardware")}
</mwc-list-item>
</ha-list-item>
${this.supervisor.host.features.includes("haos")
? html`
<mwc-list-item
<ha-list-item
.action=${"import_from_usb"}
@click=${this._handleMenuAction}
>
${this.supervisor.localize("system.host.import_from_usb")}
</mwc-list-item>
</ha-list-item>
${this.supervisor.host.features.includes("os_agent") &&
atLeastVersion(this.supervisor.host.agent_version, 1, 2, 0)
? html`
<mwc-list-item
<ha-list-item
.action=${"move_datadisk"}
@click=${this._handleMenuAction}
>
${this.supervisor.localize(
"system.host.move_datadisk"
)}
</mwc-list-item>
</ha-list-item>
`
: ""}
`
@@ -438,7 +439,7 @@ class HassioHostInfo extends LitElement {
color: var(--secondary-text-color);
--mdc-menu-min-width: 200px;
}
mwc-list-item ha-svg-icon {
ha-list-item ha-svg-icon {
color: var(--secondary-text-color);
}
a {

View File

@@ -1,5 +1,5 @@
import "@material/mwc-button";
import "@material/mwc-list/mwc-list-item";
import type { CSSResultGroup, TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators";
@@ -8,6 +8,7 @@ import "../../../src/components/ha-alert";
import "../../../src/components/ha-ansi-to-html";
import "../../../src/components/ha-card";
import "../../../src/components/ha-select";
import "../../../src/components/ha-list-item";
import { extractApiErrorMessage } from "../../../src/data/hassio/common";
import { fetchHassioLogs } from "../../../src/data/hassio/supervisor";
import type { Supervisor } from "../../../src/data/supervisor/supervisor";
@@ -80,9 +81,9 @@ class HassioSupervisorLog extends LitElement {
>
${logProviders.map(
(provider) => html`
<mwc-list-item .value=${provider.key}>
<ha-list-item .value=${provider.key}>
${provider.name}
</mwc-list-item>
</ha-list-item>
`
)}
</ha-select>

View File

@@ -1,4 +1,3 @@
import "@material/mwc-list/mwc-list-item";
import {
css,
type CSSResultGroup,

View File

@@ -1,3 +1,3 @@
import "./ha-landing-page";
import("../../src/resources/ha-style");
import("../../src/resources/append-ha-style");

View File

@@ -2,6 +2,8 @@ import "@material/mwc-linear-progress";
import { type PropertyValues, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../src/components/ha-alert";
import "../../src/components/ha-fade-in";
import "../../src/components/ha-spinner";
import { haStyle } from "../../src/resources/styles";
import "../../src/onboarding/onboarding-welcome-links";
import "./components/landing-page-network";
@@ -40,6 +42,14 @@ class HaLandingPage extends LandingPageBaseElement {
render() {
const networkIssue = this._networkInfo && !this._networkInfo.host_internet;
if (!this.localize) {
return html`
<ha-fade-in>
<ha-spinner size="large"></ha-spinner>
</ha-fade-in>
`;
}
return html`
<ha-card>
<div class="card-content">
@@ -229,6 +239,12 @@ class HaLandingPage extends LandingPageBaseElement {
margin-inline-end: 16px;
margin-inline-start: initial;
}
ha-fade-in {
min-height: calc(100vh - 64px - 88px);
display: flex;
justify-content: center;
align-items: center;
}
`,
];
}

View File

@@ -6,23 +6,23 @@ import {
type LandingPageKeys,
type LocalizeFunc,
} from "../../src/common/translations/localize";
import { computeDirectionStyles } from "../../src/common/util/compute_rtl";
import { ProvideHassLitMixin } from "../../src/mixins/provide-hass-lit-mixin";
import { translationMetadata } from "../../src/resources/translations-metadata";
import type { HassBaseEl } from "../../src/state/hass-base-mixin";
import themesMixin from "../../src/state/themes-mixin";
import type { Constructor, Resources } from "../../src/types";
import {
getLocalLanguage,
getTranslation,
} from "../../src/util/common-translation";
import { computeDirectionStyles } from "../../src/common/util/compute_rtl";
import themesMixin from "../../src/state/themes-mixin";
import { translationMetadata } from "../../src/resources/translations-metadata";
import type { HassBaseEl } from "../../src/state/hass-base-mixin";
export class LandingPageBaseElement extends themesMixin(
ProvideHassLitMixin(LitElement) as unknown as Constructor<HassBaseEl>
) {
// Initialized to empty will prevent undefined errors if called before connected to DOM.
@property({ attribute: false })
public localize: LocalizeFunc<LandingPageKeys> = () => "";
public localize?: LocalizeFunc<LandingPageKeys>;
// Use browser language setup before login.
@property() public language?: string = getLocalLanguage();

View File

@@ -31,10 +31,10 @@
"@codemirror/autocomplete": "6.18.6",
"@codemirror/commands": "6.8.1",
"@codemirror/language": "6.11.0",
"@codemirror/legacy-modes": "6.5.0",
"@codemirror/legacy-modes": "6.5.1",
"@codemirror/search": "6.5.10",
"@codemirror/state": "6.5.2",
"@codemirror/view": "6.36.5",
"@codemirror/view": "6.36.6",
"@egjs/hammerjs": "2.0.17",
"@formatjs/intl-datetimeformat": "6.18.0",
"@formatjs/intl-displaynames": "6.8.11",
@@ -52,10 +52,11 @@
"@fullcalendar/luxon3": "6.1.17",
"@fullcalendar/timegrid": "6.1.17",
"@lezer/highlight": "1.2.1",
"@lit-labs/context": "0.4.1",
"@lit-labs/motion": "1.0.8",
"@lit-labs/observers": "2.0.5",
"@lit-labs/virtualizer": "2.1.0",
"@lit/context": "1.1.5",
"@lit/reactive-element": "2.1.0",
"@material/chips": "=14.0.0-canary.53b3cad2f.0",
"@material/data-table": "=14.0.0-canary.53b3cad2f.0",
"@material/mwc-base": "0.27.0",
@@ -65,17 +66,15 @@
"@material/mwc-drawer": "0.27.0",
"@material/mwc-fab": "0.27.0",
"@material/mwc-floating-label": "0.27.0",
"@material/mwc-formfield": "0.27.0",
"@material/mwc-formfield": "patch:@material/mwc-formfield@npm%3A0.27.0#~/.yarn/patches/@material-mwc-formfield-npm-0.27.0-9528cb60f6.patch",
"@material/mwc-icon-button": "0.27.0",
"@material/mwc-linear-progress": "0.27.0",
"@material/mwc-list": "0.27.0",
"@material/mwc-list": "patch:@material/mwc-list@npm%3A0.27.0#~/.yarn/patches/@material-mwc-list-npm-0.27.0-5344fc9de4.patch",
"@material/mwc-menu": "0.27.0",
"@material/mwc-radio": "0.27.0",
"@material/mwc-select": "0.27.0",
"@material/mwc-snackbar": "0.27.0",
"@material/mwc-switch": "0.27.0",
"@material/mwc-tab": "0.27.0",
"@material/mwc-tab-bar": "0.27.0",
"@material/mwc-textarea": "0.27.0",
"@material/mwc-textfield": "0.27.0",
"@material/mwc-top-app-bar": "0.27.0",
@@ -84,17 +83,14 @@
"@material/web": "2.3.0",
"@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/polymer": "3.5.2",
"@replit/codemirror-indentation-markers": "6.5.3",
"@shoelace-style/shoelace": "2.20.1",
"@swc/helpers": "0.5.17",
"@thomasloven/round-slider": "0.6.0",
"@tsparticles/engine": "3.8.1",
"@tsparticles/preset-links": "3.2.0",
"@vaadin/combo-box": "24.7.2",
"@vaadin/vaadin-themable-mixin": "24.7.2",
"@vaadin/combo-box": "24.7.4",
"@vaadin/vaadin-themable-mixin": "24.7.4",
"@vibrant/color": "4.0.0",
"@vue/web-component-wrapper": "1.3.0",
"@webcomponents/scoped-custom-element-registry": "0.0.10",
@@ -111,22 +107,22 @@
"deep-freeze": "0.0.1",
"dialog-polyfill": "0.5.6",
"echarts": "5.6.0",
"element-internals-polyfill": "3.0.1",
"element-internals-polyfill": "3.0.2",
"fuse.js": "7.1.0",
"google-timezones-json": "1.2.0",
"gulp-zopfli-green": "6.0.2",
"hls.js": "patch:hls.js@npm%3A1.5.7#~/.yarn/patches/hls.js-npm-1.5.7-f5bbd3d060.patch",
"home-assistant-js-websocket": "9.4.0",
"home-assistant-js-websocket": "9.5.0",
"idb-keyval": "6.2.1",
"intl-messageformat": "10.7.16",
"js-yaml": "4.1.0",
"leaflet": "1.9.4",
"leaflet-draw": "patch:leaflet-draw@npm%3A1.0.4#./.yarn/patches/leaflet-draw-npm-1.0.4-0ca0ebcf65.patch",
"leaflet.markercluster": "1.5.3",
"lit": "2.8.0",
"lit-html": "2.8.0",
"lit": "3.3.0",
"lit-html": "3.3.0",
"luxon": "3.6.1",
"marked": "15.0.7",
"marked": "15.0.11",
"memoize-one": "6.0.0",
"node-vibrant": "4.0.3",
"object-hash": "3.0.0",
@@ -156,18 +152,16 @@
"devDependencies": {
"@babel/core": "7.26.10",
"@babel/helper-define-polyfill-provider": "0.6.4",
"@babel/plugin-proposal-decorators": "7.25.9",
"@babel/plugin-transform-runtime": "7.26.10",
"@babel/preset-env": "7.26.9",
"@babel/preset-typescript": "7.27.0",
"@bundle-stats/plugin-webpack-filter": "4.19.1",
"@lokalise/node-api": "14.2.1",
"@octokit/auth-oauth-device": "7.1.4",
"@octokit/plugin-retry": "7.2.0",
"@lokalise/node-api": "14.4.0",
"@octokit/auth-oauth-device": "7.1.5",
"@octokit/plugin-retry": "7.2.1",
"@octokit/rest": "21.1.1",
"@rsdoctor/rspack-plugin": "1.0.1",
"@rspack/cli": "1.3.2",
"@rspack/core": "1.3.2",
"@rsdoctor/rspack-plugin": "1.0.2",
"@rspack/cli": "1.3.7",
"@rspack/core": "1.3.7",
"@types/babel__plugin-transform-runtime": "7.9.5",
"@types/chromecast-caf-receiver": "6.0.21",
"@types/chromecast-caf-sender": "1.0.11",
@@ -186,32 +180,32 @@
"@types/tar": "6.1.13",
"@types/ua-parser-js": "0.7.39",
"@types/webspeechapi": "0.0.29",
"@vitest/coverage-v8": "3.1.1",
"@vitest/coverage-v8": "3.1.2",
"babel-loader": "10.0.0",
"babel-plugin-template-html-minifier": "4.1.0",
"browserslist-useragent-regexp": "4.1.3",
"del": "8.0.0",
"eslint": "9.24.0",
"eslint": "9.25.1",
"eslint-config-airbnb-base": "15.0.0",
"eslint-config-prettier": "10.1.1",
"eslint-config-prettier": "10.1.2",
"eslint-import-resolver-webpack": "0.13.10",
"eslint-plugin-import": "2.31.0",
"eslint-plugin-lit": "2.0.0",
"eslint-plugin-lit": "2.1.1",
"eslint-plugin-lit-a11y": "4.1.4",
"eslint-plugin-unused-imports": "4.1.4",
"eslint-plugin-wc": "3.0.0",
"fancy-log": "2.0.0",
"fs-extra": "11.3.0",
"glob": "11.0.1",
"glob": "11.0.2",
"gulp": "5.0.0",
"gulp-brotli": "3.0.0",
"gulp-json-transform": "0.5.0",
"gulp-rename": "2.0.0",
"html-minifier-terser": "7.2.0",
"husky": "9.1.7",
"jsdom": "26.0.0",
"jsdom": "26.1.0",
"jszip": "3.10.1",
"lint-staged": "15.5.0",
"lint-staged": "15.5.1",
"lit-analyzer": "2.0.3",
"lodash.merge": "4.6.2",
"lodash.template": "4.5.0",
@@ -225,24 +219,23 @@
"terser-webpack-plugin": "5.3.14",
"ts-lit-plugin": "2.0.2",
"typescript": "5.8.3",
"typescript-eslint": "8.29.0",
"typescript-eslint": "8.31.0",
"vite-tsconfig-paths": "5.1.4",
"vitest": "3.1.1",
"vitest": "3.1.2",
"webpack-stats-plugin": "1.1.3",
"webpackbar": "7.0.0",
"workbox-build": "patch:workbox-build@npm%3A7.1.1#~/.yarn/patches/workbox-build-npm-7.1.1-a854f3faae.patch"
},
"_comment": "Polymer 3.2 contained a bug, fixed in https://github.com/Polymer/polymer/pull/5569, add as patch",
"resolutions": {
"@polymer/polymer": "patch:@polymer/polymer@3.5.2#./.yarn/patches/@polymer/polymer/pr-5569.patch",
"@material/mwc-button@^0.25.3": "^0.27.0",
"lit": "2.8.0",
"lit-html": "2.8.0",
"lit": "3.3.0",
"lit-html": "3.3.0",
"clean-css": "5.3.3",
"@lit/reactive-element": "1.6.3",
"@lit/reactive-element": "2.1.0",
"@fullcalendar/daygrid": "6.1.17",
"globals": "16.0.0",
"tslib": "2.8.1"
"tslib": "2.8.1",
"@material/mwc-list@^0.27.0": "patch:@material/mwc-list@npm%3A0.27.0#~/.yarn/patches/@material-mwc-list-npm-0.27.0-5344fc9de4.patch"
},
"packageManager": "yarn@4.8.1"
"packageManager": "yarn@4.9.1"
}

View File

@@ -0,0 +1,17 @@
<svg width="94" height="24" viewBox="0 0 94 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1349_5726)">
<rect width="94" height="24" rx="8" fill="white"/>
<path d="M8 12C8 14.2091 9.79086 16 12 16H16C18.2091 16 20 14.2091 20 12C20 9.79086 18.2091 8 16 8H12C9.79086 8 8 9.79086 8 12Z" fill="black" fill-opacity="0.32"/>
<path d="M24.5 13C24.5 14.6569 25.8431 16 27.5 16H33.5C35.1569 16 36.5 14.6569 36.5 13V11C36.5 9.34315 35.1569 8 33.5 8H27.5C25.8431 8 24.5 9.34315 24.5 11V13Z" fill="black" fill-opacity="0.12"/>
<path d="M41 13C41 14.6569 42.3431 16 44 16H50C51.6569 16 53 14.6569 53 13V11C53 9.34315 51.6569 8 50 8H44C42.3431 8 41 9.34315 41 11V13Z" fill="black" fill-opacity="0.12"/>
<path d="M57.5 13C57.5 14.6569 58.8431 16 60.5 16H66.5C68.1569 16 69.5 14.6569 69.5 13V11C69.5 9.34315 68.1569 8 66.5 8H60.5C58.8431 8 57.5 9.34315 57.5 11V13Z" fill="black" fill-opacity="0.12"/>
<path d="M74 13C74 14.6569 75.3431 16 77 16H83C84.6569 16 86 14.6569 86 13V11C86 9.34315 84.6569 8 83 8H77C75.3431 8 74 9.34315 74 11V13Z" fill="black" fill-opacity="0.12"/>
<path d="M90 13C90 14.6569 91.3431 16 93 16H99C100.657 16 102 14.6569 102 13V11C102 9.34315 100.657 8 99 8H93C91.3431 8 90 9.34315 90 11V13Z" fill="black" fill-opacity="0.12"/>
</g>
<rect x="0.5" y="0.5" width="93" height="23" rx="7.5" stroke="black" stroke-opacity="0.12" stroke-dasharray="4 4"/>
<defs>
<clipPath id="clip0_1349_5726">
<rect width="94" height="24" rx="8" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,17 @@
<svg width="94" height="24" viewBox="0 0 94 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1349_5798)">
<path d="M0 8C0 3.58172 3.58172 0 8 0H86C90.4183 0 94 3.58172 94 8V16C94 20.4183 90.4183 24 86 24H8C3.58172 24 0 20.4183 0 16V8Z" fill="#1C1C1C"/>
<path d="M8 12C8 14.2091 9.79086 16 12 16H16C18.2091 16 20 14.2091 20 12C20 9.79086 18.2091 8 16 8H12C9.79086 8 8 9.79086 8 12Z" fill="white" fill-opacity="0.48"/>
<path d="M24.5 12C24.5 14.2091 26.2909 16 28.5 16H32.5C34.7091 16 36.5 14.2091 36.5 12C36.5 9.79086 34.7091 8 32.5 8H28.5C26.2909 8 24.5 9.79086 24.5 12Z" fill="white" fill-opacity="0.24"/>
<path d="M41 12C41 14.2091 42.7909 16 45 16H49C51.2091 16 53 14.2091 53 12C53 9.79086 51.2091 8 49 8H45C42.7909 8 41 9.79086 41 12Z" fill="white" fill-opacity="0.24"/>
<path d="M57.5 12C57.5 14.2091 59.2909 16 61.5 16H65.5C67.7091 16 69.5 14.2091 69.5 12C69.5 9.79086 67.7091 8 65.5 8H61.5C59.2909 8 57.5 9.79086 57.5 12Z" fill="white" fill-opacity="0.24"/>
<path d="M74 12C74 14.2091 75.7909 16 78 16H82C84.2091 16 86 14.2091 86 12C86 9.79086 84.2091 8 82 8H78C75.7909 8 74 9.79086 74 12Z" fill="white" fill-opacity="0.24"/>
<path d="M90 12C90 14.2091 91.7909 16 94 16H98C100.209 16 102 14.2091 102 12V12C102 9.79086 100.209 8 98 8H94C91.7909 8 90 9.79086 90 12V12Z" fill="white" fill-opacity="0.24"/>
</g>
<path d="M1.34748 20.4449C0.772837 19.5866 0.359906 18.6109 0.152272 17.5613L0.642766 17.4643C0.549158 16.9911 0.5 16.5015 0.5 16V14H0V10H0.5V8C0.5 7.49847 0.549158 7.00892 0.642766 6.53574L0.152272 6.4387C0.359906 5.38915 0.772837 4.41341 1.34748 3.55508L1.76296 3.83324C2.31067 3.01513 3.01513 2.31067 3.83323 1.76296L3.55507 1.34748C4.41341 0.772837 5.38915 0.359906 6.4387 0.152272L6.53574 0.642766C7.00892 0.549158 7.49847 0.5 8 0.5H9.94999V0H13.85V0.5H17.75V0H21.65V0.5H25.55V0H29.45V0.5H33.35V0H37.25V0.5H41.15V0H45.05V0.5H48.95V0H52.85V0.5H56.75V0H60.65V0.5H64.55V0H68.45V0.5H72.35V0H76.25V0.5H80.15V0H84.05V0.5H86C86.5015 0.5 86.9911 0.549158 87.4643 0.642766L87.5613 0.152273C88.6108 0.359907 89.5866 0.772837 90.4449 1.34747L90.1668 1.76296C90.9849 2.31067 91.6893 3.01513 92.237 3.83323L92.6525 3.55507C93.2272 4.41341 93.6401 5.38915 93.8477 6.4387L93.3572 6.53574C93.4508 7.00892 93.5 7.49847 93.5 8V10H94V14H93.5V16C93.5 16.5015 93.4508 16.9911 93.3572 17.4643L93.8477 17.5613C93.6401 18.6109 93.2272 19.5866 92.6525 20.4449L92.237 20.1668C91.6893 20.9849 90.9849 21.6893 90.1668 22.237L90.4449 22.6525C89.5866 23.2272 88.6108 23.6401 87.5613 23.8477L87.4643 23.3572C86.9911 23.4508 86.5015 23.5 86 23.5H84.05V24H80.15V23.5H76.25V24H72.35V23.5H68.45V24H64.55V23.5H60.65V24H56.75V23.5H52.85V24H48.95V23.5H45.05V24H41.15V23.5H37.25V24H33.35V23.5H29.45V24H25.55V23.5H21.65V24H17.75V23.5H13.85V24H9.95V23.5H8C7.49847 23.5 7.00892 23.4508 6.53574 23.3572L6.4387 23.8477C5.38915 23.6401 4.41341 23.2272 3.55507 22.6525L3.83323 22.237C3.01513 21.6893 2.31067 20.9849 1.76296 20.1668L1.34748 20.4449Z" stroke="white" stroke-opacity="0.24" stroke-dasharray="4 4"/>
<defs>
<clipPath id="clip0_1349_5798">
<path d="M0 8C0 3.58172 3.58172 0 8 0H86C90.4183 0 94 3.58172 94 8V16C94 20.4183 90.4183 24 86 24H8C3.58172 24 0 20.4183 0 16V8Z" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -0,0 +1,11 @@
<svg width="94" height="40" viewBox="0 0 94 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="94" height="40" rx="8" fill="white"/>
<rect x="0.5" y="0.5" width="93" height="39" rx="7.5" stroke="black" stroke-opacity="0.12" stroke-dasharray="4 4"/>
<path d="M8 12C8 14.2091 9.79086 16 12 16H16C18.2091 16 20 14.2091 20 12C20 9.79086 18.2091 8 16 8H12C9.79086 8 8 9.79086 8 12Z" fill="black" fill-opacity="0.32"/>
<path d="M24.5 13C24.5 14.6569 25.8431 16 27.5 16H33.5C35.1569 16 36.5 14.6569 36.5 13V11C36.5 9.34315 35.1569 8 33.5 8H27.5C25.8431 8 24.5 9.34315 24.5 11V13Z" fill="black" fill-opacity="0.12"/>
<path d="M41 13C41 14.6569 42.3431 16 44 16H50C51.6569 16 53 14.6569 53 13V11C53 9.34315 51.6569 8 50 8H44C42.3431 8 41 9.34315 41 11V13Z" fill="black" fill-opacity="0.12"/>
<path d="M57.5 13C57.5 14.6569 58.8431 16 60.5 16H66.5C68.1569 16 69.5 14.6569 69.5 13V11C69.5 9.34315 68.1569 8 66.5 8H60.5C58.8431 8 57.5 9.34315 57.5 11V13Z" fill="black" fill-opacity="0.12"/>
<path d="M74 13C74 14.6569 75.3431 16 77 16H83C84.6569 16 86 14.6569 86 13V11C86 9.34315 84.6569 8 83 8H77C75.3431 8 74 9.34315 74 11V13Z" fill="black" fill-opacity="0.12"/>
<path d="M8 29C8 30.6569 9.34315 32 11 32H17C18.6569 32 20 30.6569 20 29V27C20 25.3431 18.6569 24 17 24H11C9.34315 24 8 25.3431 8 27V29Z" fill="black" fill-opacity="0.12"/>
<path d="M24.5 29C24.5 30.6569 25.8431 32 27.5 32H33.5C35.1569 32 36.5 30.6569 36.5 29V27C36.5 25.3431 35.1569 24 33.5 24H27.5C25.8431 24 24.5 25.3431 24.5 27V29Z" fill="black" fill-opacity="0.12"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,11 @@
<svg width="94" height="40" viewBox="0 0 94 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 8C0 3.58172 3.58172 0 8 0H86C90.4183 0 94 3.58172 94 8V32C94 36.4183 90.4183 40 86 40H8C3.58172 40 0 36.4183 0 32V8Z" fill="#1C1C1C"/>
<path d="M1.34748 36.4449C0.772837 35.5866 0.359906 34.6109 0.152272 33.5613L0.642766 33.4643C0.549158 32.9911 0.5 32.5015 0.5 32V30H0V26H0.5V22H0V18H0.5V14H0V10H0.5V8C0.5 7.49847 0.549158 7.00892 0.642766 6.53574L0.152272 6.4387C0.359906 5.38915 0.772837 4.41341 1.34748 3.55508L1.76296 3.83324C2.31067 3.01513 3.01513 2.31067 3.83323 1.76296L3.55507 1.34748C4.41341 0.772837 5.38915 0.359906 6.4387 0.152272L6.53574 0.642766C7.00892 0.549158 7.49847 0.5 8 0.5H9.94999V0H13.85V0.5H17.75V0H21.65V0.5H25.55V0H29.45V0.5H33.35V0H37.25V0.5H41.15V0H45.05V0.5H48.95V0H52.85V0.5H56.75V0H60.65V0.5H64.55V0H68.45V0.5H72.35V0H76.25V0.5H80.15V0H84.05V0.5H86C86.5015 0.5 86.9911 0.549158 87.4643 0.642766L87.5613 0.152273C88.6108 0.359907 89.5866 0.772837 90.4449 1.34747L90.1668 1.76296C90.9849 2.31067 91.6893 3.01513 92.237 3.83323L92.6525 3.55507C93.2272 4.41341 93.6401 5.38915 93.8477 6.4387L93.3572 6.53574C93.4508 7.00892 93.5 7.49847 93.5 8V10H94V14H93.5V18H94V22H93.5V26H94V30H93.5V32C93.5 32.5015 93.4508 32.9911 93.3572 33.4643L93.8477 33.5613C93.6401 34.6109 93.2272 35.5866 92.6525 36.4449L92.237 36.1668C91.6893 36.9849 90.9849 37.6893 90.1668 38.237L90.4449 38.6525C89.5866 39.2272 88.6108 39.6401 87.5613 39.8477L87.4643 39.3572C86.9911 39.4508 86.5015 39.5 86 39.5H84.05V40H80.15V39.5H76.25V40H72.35V39.5H68.45V40H64.55V39.5H60.65V40H56.75V39.5H52.85V40H48.95V39.5H45.05V40H41.15V39.5H37.25V40H33.35V39.5H29.45V40H25.55V39.5H21.65V40H17.75V39.5H13.85V40H9.95V39.5H8C7.49847 39.5 7.00892 39.4508 6.53574 39.3572L6.4387 39.8477C5.38915 39.6401 4.41341 39.2272 3.55508 38.6525L3.83323 38.237C3.01513 37.6893 2.31067 36.9849 1.76296 36.1668L1.34748 36.4449Z" stroke="white" stroke-opacity="0.24" stroke-dasharray="4 4"/>
<path d="M8 12C8 14.2091 9.79086 16 12 16H16C18.2091 16 20 14.2091 20 12C20 9.79086 18.2091 8 16 8H12C9.79086 8 8 9.79086 8 12Z" fill="white" fill-opacity="0.48"/>
<path d="M24.5 12C24.5 14.2091 26.2909 16 28.5 16H32.5C34.7091 16 36.5 14.2091 36.5 12C36.5 9.79086 34.7091 8 32.5 8H28.5C26.2909 8 24.5 9.79086 24.5 12Z" fill="white" fill-opacity="0.24"/>
<path d="M41 12C41 14.2091 42.7909 16 45 16H49C51.2091 16 53 14.2091 53 12C53 9.79086 51.2091 8 49 8H45C42.7909 8 41 9.79086 41 12Z" fill="white" fill-opacity="0.24"/>
<path d="M57.5 12C57.5 14.2091 59.2909 16 61.5 16H65.5C67.7091 16 69.5 14.2091 69.5 12C69.5 9.79086 67.7091 8 65.5 8H61.5C59.2909 8 57.5 9.79086 57.5 12Z" fill="white" fill-opacity="0.24"/>
<path d="M74 12C74 14.2091 75.7909 16 78 16H82C84.2091 16 86 14.2091 86 12C86 9.79086 84.2091 8 82 8H78C75.7909 8 74 9.79086 74 12Z" fill="white" fill-opacity="0.24"/>
<path d="M8 28C8 30.2091 9.79086 32 12 32H16C18.2091 32 20 30.2091 20 28C20 25.7909 18.2091 24 16 24H12C9.79086 24 8 25.7909 8 28Z" fill="white" fill-opacity="0.24"/>
<path d="M24.5 28C24.5 30.2091 26.2909 32 28.5 32H32.5C34.7091 32 36.5 30.2091 36.5 28C36.5 25.7909 34.7091 24 32.5 24H28.5C26.2909 24 24.5 25.7909 24.5 28Z" fill="white" fill-opacity="0.24"/>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -0,0 +1,15 @@
<svg width="94" height="72" viewBox="0 0 94 72" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M76.9105 39.4999C77.739 39.4999 78.4105 38.8284 78.4105 37.9999C78.4105 37.1715 77.739 36.4999 76.9105 36.4999V39.4999ZM37.5 37.9999L37.5 39.4999L76.9105 39.4999V37.9999V36.4999L37.5 36.4999L37.5 37.9999Z" fill="#00AFFF" fill-opacity="0.3"/>
<path d="M30.8239 22.3365L38.8239 38.8365L30.3239 50.3365" stroke="black" stroke-opacity="0.12" stroke-width="3" stroke-linecap="round"/>
<mask id="mask0_2_779" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="30" y="27" width="18" height="18">
<path d="M45.75 42.075C45.75 42.4462 45.4462 42.75 45.075 42.75H32.925C32.5538 42.75 32.25 42.4462 32.25 42.075V36.675C32.25 36.3037 32.4649 35.7851 32.7276 35.5224L38.5224 29.7275C38.7851 29.4649 39.2143 29.4649 39.477 29.7275L45.2724 35.523C45.5351 35.7857 45.75 36.3043 45.75 36.6755V42.075Z" fill="black"/>
</mask>
<g mask="url(#mask0_2_779)">
<rect x="30" y="27" width="18" height="18" fill="#00AFFF"/>
</g>
<path d="M85 34.9999C86.6569 34.9999 88 36.343 88 37.9999C88 39.6567 86.6569 40.9999 85 40.9999C83.3431 40.9999 82 39.6567 82 37.9999C82 36.343 83.3431 34.9999 85 34.9999Z" stroke="#00AFFF" stroke-width="2"/>
<rect x="23" y="11" width="8" height="8" rx="4" fill="black" fill-opacity="0.32"/>
<rect x="22" y="52" width="8" height="8" rx="4" fill="black" fill-opacity="0.32"/>
<path d="M21.5715 19.5C17.4983 23.801 15 29.6087 15 36C15 41.9085 17.1351 47.3183 20.6759 51.5" stroke="black" stroke-opacity="0.12" stroke-width="3" stroke-linecap="round"/>
<circle cx="39" cy="36" r="33.5" stroke="black" stroke-opacity="0.12"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1,15 @@
<svg width="94" height="72" viewBox="0 0 94 72" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M30.824 22.3365L38.824 38.8365L30.324 50.3365" stroke="white" stroke-opacity="0.24" stroke-width="3" stroke-linecap="round"/>
<mask id="mask0_1180_4955" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="30" y="27" width="18" height="18">
<path d="M45.75 42.075C45.75 42.4462 45.4462 42.75 45.075 42.75H32.925C32.5538 42.75 32.25 42.4462 32.25 42.075V36.675C32.25 36.3037 32.4649 35.7851 32.7276 35.5224L38.5224 29.7275C38.7851 29.4649 39.2143 29.4649 39.477 29.7275L45.2724 35.523C45.5351 35.7857 45.75 36.3043 45.75 36.6755V42.075Z" fill="black"/>
</mask>
<g mask="url(#mask0_1180_4955)">
<rect x="30" y="27" width="18" height="18" fill="#00AFFF"/>
</g>
<path d="M76.9105 39.4999C77.739 39.4999 78.4105 38.8283 78.4105 37.9999C78.4105 37.1715 77.739 36.4999 76.9105 36.4999V39.4999ZM37.5 39.4999L76.9105 39.4999V36.4999L37.5 36.4999L37.5 39.4999Z" fill="#00AFFF" fill-opacity="0.3"/>
<path d="M82 37.9999C82 36.343 83.3431 34.9999 85 34.9999C86.6569 34.9999 88 36.343 88 37.9999C88 39.6567 86.6569 40.9999 85 40.9999C83.3431 40.9999 82 39.6567 82 37.9999Z" stroke="#00AFFF" stroke-width="2"/>
<rect x="23" y="11" width="8" height="8" rx="4" fill="white" fill-opacity="0.48"/>
<rect x="22" y="52" width="8" height="8" rx="4" fill="white" fill-opacity="0.48"/>
<path d="M21.5715 19.5C17.4983 23.801 15 29.6087 15 36C15 41.9085 17.1351 47.3183 20.6759 51.5" stroke="white" stroke-opacity="0.24" stroke-width="3" stroke-linecap="round"/>
<circle cx="39" cy="36" r="33.5" stroke="white" stroke-opacity="0.24"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1,19 @@
<svg width="94" height="72" viewBox="0 0 94 72" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M55.1358 38.5084C55.9608 38.4334 56.5688 37.7038 56.4938 36.8788C56.4188 36.0538 55.6892 35.4457 54.8642 35.5207L55.1358 38.5084ZM38.5 38.5146L38.6358 40.0084L55.1358 38.5084L55 37.0146L54.8642 35.5207L38.3642 37.0207L38.5 38.5146Z" fill="#00AFFF" fill-opacity="0.3"/>
<path d="M30.5 22L37.9722 37.4115C38.2967 38.0807 38.223 38.8747 37.781 39.4728L30 50" stroke="#00AFFF" stroke-opacity="0.3" stroke-width="3" stroke-linecap="round" stroke-linejoin="bevel"/>
<circle cx="39" cy="36" r="34" fill="white"/>
<circle cx="39" cy="36" r="33.5" stroke="black" stroke-opacity="0.12"/>
<path d="M33.8777 12.5216C35.4905 12.1798 37.1631 12 38.8777 12C50.2401 12 59.7582 19.8959 62.2445 30.5M32 59C34.1788 59.6506 36.4874 60 38.8777 60C48.9498 60 57.5728 53.7955 61.1332 45" stroke="#00AFFF" stroke-opacity="0.3" stroke-width="3" stroke-linecap="round" stroke-linejoin="bevel"/>
<path d="M30.5 22L37.9722 37.4115C38.2967 38.0807 38.223 38.8747 37.781 39.4728L30 50" stroke="#00AFFF" stroke-opacity="0.3" stroke-width="3" stroke-linecap="round" stroke-linejoin="bevel"/>
<mask id="mask0_2_810" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="30" y="27" width="18" height="18">
<path d="M45.75 42.075C45.75 42.4462 45.4463 42.75 45.075 42.75H32.925C32.5538 42.75 32.25 42.4462 32.25 42.075V36.675C32.25 36.3037 32.4649 35.7851 32.7276 35.5224L38.5224 29.7275C38.7851 29.4649 39.2143 29.4649 39.477 29.7275L45.2724 35.523C45.5351 35.7857 45.75 36.3043 45.75 36.6755V42.075Z" fill="black"/>
</mask>
<g mask="url(#mask0_2_810)">
<rect x="30" y="27" width="18" height="18" fill="#00AFFF"/>
</g>
<path d="M55.5 39.4999C56.3284 39.4999 57 38.8283 57 37.9999C57 37.1715 56.3284 36.4999 55.5 36.4999L55.5 39.4999ZM41.5 37.9999L41.5 39.4999L55.5 39.4999L55.5 37.9999L55.5 36.4999L41.5 36.4999L41.5 37.9999Z" fill="#00AFFF" fill-opacity="0.3"/>
<rect x="23" y="11" width="8" height="8" rx="4" fill="#00AFFF" fill-opacity="0.6"/>
<rect x="22" y="52" width="8" height="8" rx="4" fill="#00AFFF" fill-opacity="0.6"/>
<path d="M21.5715 19.5C17.4983 23.801 15 29.6087 15 36C15 41.9085 17.1351 47.3183 20.6759 51.5" stroke="#00AFFF" stroke-opacity="0.3" stroke-width="3" stroke-linecap="round" stroke-linejoin="bevel"/>
<path d="M63 34.9999C64.6569 34.9999 66 36.343 66 37.9999C66 39.6567 64.6569 40.9999 63 40.9999C61.3431 40.9999 60 39.6567 60 37.9999C60 36.343 61.3431 34.9999 63 34.9999Z" stroke="#00AFFF" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1,18 @@
<svg width="94" height="72" viewBox="0 0 94 72" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M55.1358 38.5084C55.9608 38.4334 56.5688 37.7038 56.4938 36.8788C56.4188 36.0538 55.6892 35.4457 54.8642 35.5207L55.1358 38.5084ZM38.5 38.5146L38.6358 40.0084L55.1358 38.5084L55 37.0146L54.8642 35.5207L38.3642 37.0207L38.5 38.5146Z" fill="#00AFFF" fill-opacity="0.3"/>
<path d="M30.5 22L37.9722 37.4115C38.2967 38.0807 38.223 38.8747 37.781 39.4728L30 50" stroke="#00AFFF" stroke-opacity="0.3" stroke-width="3" stroke-linecap="round" stroke-linejoin="bevel"/>
<circle cx="39" cy="36" r="33.5" stroke="white" stroke-opacity="0.24"/>
<path d="M33.8777 12.5216C35.4905 12.1798 37.1631 12 38.8777 12C50.2401 12 59.7582 19.8959 62.2445 30.5M32 59C34.1788 59.6506 36.4874 60 38.8777 60C48.9498 60 57.5728 53.7955 61.1332 45" stroke="#00AFFF" stroke-opacity="0.3" stroke-width="3" stroke-linecap="round" stroke-linejoin="bevel"/>
<path d="M30.5 22L37.9722 37.4115C38.2967 38.0807 38.223 38.8747 37.781 39.4728L30 50" stroke="#00AFFF" stroke-opacity="0.3" stroke-width="3" stroke-linecap="round" stroke-linejoin="bevel"/>
<mask id="mask0_2_810" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="30" y="27" width="18" height="18">
<path d="M45.75 42.075C45.75 42.4462 45.4463 42.75 45.075 42.75H32.925C32.5538 42.75 32.25 42.4462 32.25 42.075V36.675C32.25 36.3037 32.4649 35.7851 32.7276 35.5224L38.5224 29.7275C38.7851 29.4649 39.2143 29.4649 39.477 29.7275L45.2724 35.523C45.5351 35.7857 45.75 36.3043 45.75 36.6755V42.075Z" fill="black"/>
</mask>
<g mask="url(#mask0_2_810)">
<rect x="30" y="27" width="18" height="18" fill="#00AFFF"/>
</g>
<path d="M55.5 39.4999C56.3284 39.4999 57 38.8283 57 37.9999C57 37.1715 56.3284 36.4999 55.5 36.4999L55.5 39.4999ZM41.5 37.9999L41.5 39.4999L55.5 39.4999L55.5 37.9999L55.5 36.4999L41.5 36.4999L41.5 37.9999Z" fill="#00AFFF" fill-opacity="0.3"/>
<rect x="23" y="11" width="8" height="8" rx="4" fill="#00AFFF" fill-opacity="0.6"/>
<rect x="22" y="52" width="8" height="8" rx="4" fill="#00AFFF" fill-opacity="0.6"/>
<path d="M21.5715 19.5C17.4983 23.801 15 29.6087 15 36C15 41.9085 17.1351 47.3183 20.6759 51.5" stroke="#00AFFF" stroke-opacity="0.3" stroke-width="3" stroke-linecap="round" stroke-linejoin="bevel"/>
<path d="M63 34.9999C64.6569 34.9999 66 36.343 66 37.9999C66 39.6567 64.6569 40.9999 63 40.9999C61.3431 40.9999 60 39.6567 60 37.9999C60 36.343 61.3431 34.9999 63 34.9999Z" stroke="#00AFFF" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "home-assistant-frontend"
version = "20250326.0"
version = "20250507.0"
license = "Apache-2.0"
license-files = ["LICENSE*"]
description = "The Home Assistant frontend"

View File

@@ -265,7 +265,10 @@ export class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
);
}
if (window.innerWidth > 450) {
if (
window.innerWidth > 450 &&
!matchMedia("(prefers-reduced-motion)").matches
) {
import("../resources/particles");
}

View File

@@ -1,9 +1,9 @@
import "@material/mwc-list";
import { css, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import { fireEvent } from "../common/dom/fire_event";
import type { LocalizeFunc } from "../common/translations/localize";
import "../components/ha-icon-next";
import "../components/ha-list";
import "../components/ha-list-item";
import type { AuthProvider } from "../data/auth";
@@ -29,7 +29,7 @@ export class HaPickAuthProvider extends LitElement {
>${this.localize("ui.panel.page-authorize.pick_auth_provider")}</span
>
</h3>
<mwc-list>
<ha-list>
${this.authProviders.map(
(provider) => html`
<ha-list-item
@@ -43,7 +43,7 @@ export class HaPickAuthProvider extends LitElement {
</ha-list-item>
`
)}
</mwc-list>
</ha-list>
`;
}
@@ -77,7 +77,7 @@ export class HaPickAuthProvider extends LitElement {
background: var(--card-background-color);
padding: 0 15px;
}
mwc-list {
ha-list {
margin: 16px -16px 0;
--mdc-list-side-padding: 24px;
}

View File

@@ -144,7 +144,7 @@ export function theme2hex(themeColor: string): string {
return themeColor;
}
const rgbFromColorName = colors[themeColor];
const rgbFromColorName = colors[themeColor.toLowerCase()];
if (rgbFromColorName) {
return rgb2hex(rgbFromColorName);
}

View File

@@ -0,0 +1,140 @@
import type {
ReactiveController,
ReactiveControllerHost,
} from "@lit/reactive-element/reactive-controller";
import type { LitElement } from "lit";
/**
* The config options for a DragScrollController.
*/
export interface DragScrollControllerConfig {
selector: string;
enabled?: boolean;
}
export class DragScrollController implements ReactiveController {
public mouseIsDown = false;
public scrolled = false;
public scrolling = false;
public scrollStartX = 0;
public scrollLeft = 0;
private _host: ReactiveControllerHost & LitElement;
private _selector: string;
private _scrollContainer?: HTMLElement | null;
private _enabled = true;
public get enabled(): boolean {
return this._enabled;
}
public set enabled(value: boolean) {
if (value === this._enabled) {
return;
}
this._enabled = value;
if (this._enabled) {
this._attach();
} else {
this._detach();
}
this._host.requestUpdate();
}
constructor(
host: ReactiveControllerHost & LitElement,
{ selector, enabled }: DragScrollControllerConfig
) {
this._selector = selector;
this._host = host;
this.enabled = enabled ?? true;
host.addController(this);
}
hostUpdated() {
if (!this.enabled || this._scrollContainer) {
return;
}
this._attach();
}
hostDisconnected() {
this._detach();
}
private _attach() {
this._scrollContainer = this._host.renderRoot?.querySelector(
this._selector
);
if (this._scrollContainer) {
this._scrollContainer.addEventListener("mousedown", this._mouseDown);
}
}
private _detach() {
window.removeEventListener("mousemove", this._mouseMove);
window.removeEventListener("mouseup", this._mouseUp);
if (this._scrollContainer) {
this._scrollContainer.removeEventListener("mousedown", this._mouseDown);
this._scrollContainer = undefined;
}
this.scrolled = false;
this.scrolling = false;
this.mouseIsDown = false;
this.scrollStartX = 0;
this.scrollLeft = 0;
}
private _mouseDown = (event: MouseEvent) => {
const scrollContainer = this._scrollContainer;
if (!scrollContainer) {
return;
}
this.scrollStartX = event.pageX - scrollContainer.offsetLeft;
this.scrollLeft = scrollContainer.scrollLeft;
this.mouseIsDown = true;
this.scrolled = false;
window.addEventListener("mousemove", this._mouseMove);
window.addEventListener("mouseup", this._mouseUp, { once: true });
};
private _mouseUp = () => {
this.mouseIsDown = false;
this.scrolling = false;
this._host.requestUpdate();
window.removeEventListener("mousemove", this._mouseMove);
};
private _mouseMove = (event: MouseEvent) => {
if (!this.mouseIsDown) {
return;
}
const scrollContainer = this._scrollContainer;
if (!scrollContainer) {
return;
}
const x = event.pageX - scrollContainer.offsetLeft;
const scroll = x - this.scrollStartX;
if (!this.scrolled) {
this.scrolled = Math.abs(scroll) > 1;
this.scrolling = this.scrolled;
this._host.requestUpdate();
}
scrollContainer.scrollLeft = this.scrollLeft - scroll;
};
}

View File

@@ -84,12 +84,12 @@ export const calcDateRange = (
case "now-7d":
return [
calcDate(today, subDays, hass.locale, hass.config, 7),
calcDate(today, subDays, hass.locale, hass.config, 1),
calcDate(today, subDays, hass.locale, hass.config, 0),
];
case "now-30d":
return [
calcDate(today, subDays, hass.locale, hass.config, 30),
calcDate(today, subDays, hass.locale, hass.config, 1),
calcDate(today, subDays, hass.locale, hass.config, 0),
];
case "now-12m":
return [

View File

@@ -1,46 +1,65 @@
import type { LitElement } from "lit";
import type { ClassElement } from "../../types";
import type { ReactiveElement } from "lit";
import { throttle } from "../util/throttle";
const throttleReplaceState = throttle((value) => {
history.replaceState({ scrollPosition: value }, "");
}, 300);
export const restoreScroll =
(selector: string): any =>
(element: ClassElement) => ({
kind: "method",
placement: "prototype",
key: element.key,
descriptor: {
set(this: LitElement, value: number) {
throttleReplaceState(value);
this[`__${String(element.key)}`] = value;
},
get(this: LitElement) {
return (
this[`__${String(element.key)}`] || history.state?.scrollPosition
);
},
enumerable: true,
configurable: true,
},
finisher(cls: typeof LitElement) {
const connectedCallback = cls.prototype.connectedCallback;
cls.prototype.connectedCallback = function () {
connectedCallback.call(this);
const scrollPos = this[element.key];
if (scrollPos) {
this.updateComplete.then(() => {
const target = this.renderRoot.querySelector(selector);
if (!target) {
return;
}
setTimeout(() => {
target.scrollTop = scrollPos;
}, 0);
});
}
export function restoreScroll(selector: string) {
return <ElemClass extends ReactiveElement>(
proto: ElemClass,
propertyKey: string
) => {
if (typeof propertyKey === "object") {
throw new Error("This decorator does not support this compilation type.");
}
const connectedCallback = proto.connectedCallback;
proto.connectedCallback = function () {
connectedCallback.call(this);
const scrollPos = this[propertyKey];
if (scrollPos) {
this.updateComplete.then(() => {
const target = this.renderRoot.querySelector(selector);
if (!target) {
return;
}
setTimeout(() => {
target.scrollTop = scrollPos;
}, 0);
});
}
};
const descriptor = Object.getOwnPropertyDescriptor(proto, propertyKey);
let newDescriptor: PropertyDescriptor;
if (descriptor === undefined) {
newDescriptor = {
get(this: ReactiveElement) {
return (
this[`__${String(propertyKey)}`] || history.state?.scrollPosition
);
},
set(this: ReactiveElement, value) {
throttleReplaceState(value);
this[`__${String(propertyKey)}`] = value;
},
configurable: true,
enumerable: true,
};
},
});
} else {
const oldSetter = descriptor.set;
newDescriptor = {
...descriptor,
set(this: ReactiveElement, value) {
throttleReplaceState(value);
this[`__${String(propertyKey)}`] = value;
oldSetter?.call(this, value);
},
};
}
Object.defineProperty(proto, propertyKey, newDescriptor);
};
}

View File

@@ -1,14 +1,17 @@
import type { UnsubscribeFunc } from "home-assistant-js-websocket";
import type { ReactiveElement } from "lit";
import type { InternalPropertyDeclaration } from "lit/decorators";
import type { ClassElement } from "../../types";
type Callback = (oldValue: any, newValue: any) => void;
type ReactiveStorageElement = ReactiveElement & {
__unbsubLocalStorage: UnsubscribeFunc | undefined;
__initialized: boolean;
};
class StorageClass {
constructor(storage = window.localStorage) {
this.storage = storage;
if (storage !== window.localStorage) {
constructor(store = window.localStorage) {
this.storage = store;
if (this.storage !== window.localStorage) {
// storage events only work for localStorage
return;
}
@@ -99,17 +102,22 @@ class StorageClass {
const storages: Record<string, StorageClass> = {};
export const storage =
(options: {
key?: string;
storage?: "localStorage" | "sessionStorage";
subscribe?: boolean;
state?: boolean;
stateOptions?: InternalPropertyDeclaration;
serializer?: (value: any) => any;
deserializer?: (value: any) => any;
}): any =>
(clsElement: ClassElement) => {
export function storage(options: {
key?: string;
storage?: "localStorage" | "sessionStorage";
subscribe?: boolean;
state?: boolean;
serializer?: (value: any) => any;
deserializer?: (value: any) => any;
}) {
return <ElemClass extends ReactiveElement>(
proto: ElemClass,
propertyKey: string
) => {
if (typeof propertyKey === "object") {
throw new Error("This decorator does not support this compilation type.");
}
const storageName = options.storage || "localStorage";
let storageInstance: StorageClass;
@@ -120,11 +128,7 @@ export const storage =
storages[storageName] = storageInstance;
}
const key = String(clsElement.key);
const storageKey = options.key || String(clsElement.key);
const initVal = clsElement.initializer
? clsElement.initializer()
: undefined;
const storageKey = options.key || String(propertyKey);
storageInstance.addFromStorage(storageKey);
@@ -134,7 +138,7 @@ export const storage =
storageInstance.subscribeChanges(
storageKey!,
(oldValue, _newValue) => {
el.requestUpdate(clsElement.key, oldValue);
el.requestUpdate(propertyKey, oldValue);
}
)
: undefined;
@@ -144,7 +148,7 @@ export const storage =
? options.deserializer
? options.deserializer(storageInstance.getValue(storageKey!))
: storageInstance.getValue(storageKey!)
: initVal;
: undefined;
const setValue = (el: ReactiveElement, value: any) => {
let oldValue: unknown | undefined;
@@ -156,44 +160,68 @@ export const storage =
options.serializer ? options.serializer(value) : value
);
if (options.state) {
el.requestUpdate(clsElement.key, oldValue);
el.requestUpdate(propertyKey, oldValue);
}
};
return {
kind: "method",
placement: "prototype",
key: clsElement.key,
descriptor: {
set(this: ReactiveElement, value: unknown) {
setValue(this, value);
},
get() {
// @ts-ignore
const performUpdate = proto.performUpdate;
// @ts-ignore
proto.performUpdate = function () {
(this as unknown as ReactiveStorageElement).__initialized = true;
performUpdate.call(this);
};
if (options.subscribe) {
const connectedCallback = proto.connectedCallback;
const disconnectedCallback = proto.disconnectedCallback;
proto.connectedCallback = function () {
connectedCallback.call(this);
const el = this as unknown as ReactiveStorageElement;
if (!el.__unbsubLocalStorage) {
el.__unbsubLocalStorage = subscribeChanges?.(this);
}
};
proto.disconnectedCallback = function () {
disconnectedCallback.call(this);
const el = this as unknown as ReactiveStorageElement;
el.__unbsubLocalStorage?.();
el.__unbsubLocalStorage = undefined;
};
}
const descriptor = Object.getOwnPropertyDescriptor(proto, propertyKey);
let newDescriptor: PropertyDescriptor;
if (descriptor === undefined) {
newDescriptor = {
get(this: ReactiveStorageElement) {
return getValue();
},
enumerable: true,
set(this: ReactiveStorageElement, value) {
// Don't set the initial value if we have a value in localStorage
if (this.__initialized || getValue() === undefined) {
setValue(this, value);
this.requestUpdate(propertyKey, undefined);
}
},
configurable: true,
},
finisher(cls: typeof ReactiveElement) {
if (options.state && options.subscribe) {
const connectedCallback = cls.prototype.connectedCallback;
const disconnectedCallback = cls.prototype.disconnectedCallback;
cls.prototype.connectedCallback = function () {
connectedCallback.call(this);
this[`__unbsubLocalStorage${key}`] = subscribeChanges?.(this);
};
cls.prototype.disconnectedCallback = function () {
disconnectedCallback.call(this);
this[`__unbsubLocalStorage${key}`]?.();
this[`__unbsubLocalStorage${key}`] = undefined;
};
}
if (options.state) {
cls.createProperty(clsElement.key, {
noAccessor: true,
...options.stateOptions,
});
}
},
};
enumerable: true,
};
} else {
const oldSetter = descriptor.set;
newDescriptor = {
...descriptor,
set(this: ReactiveStorageElement, value) {
// Don't set the initial value if we have a value in localStorage
if (this.__initialized || getValue() === undefined) {
setValue(this, value);
this.requestUpdate(propertyKey, undefined);
}
oldSetter?.call(this, value);
},
};
}
Object.defineProperty(proto, propertyKey, newDescriptor);
};
}

View File

@@ -1,39 +1,91 @@
import type { PropertyDeclaration, PropertyValues, ReactiveElement } from "lit";
import type { ClassElement } from "../../types";
import { shallowEqual } from "../util/shallow-equal";
import type { ReactiveElement, PropertyValues } from "lit";
/**
* Transform function type.
*/
export type Transformer<T = any, V = any> = (value: V) => T;
export type Transformer<T = any, V = any> = (value: T) => V | undefined;
type ReactiveTransformElement = ReactiveElement & {
_transformers: Map<PropertyKey, Transformer>;
_watching: Map<PropertyKey, Set<PropertyKey>>;
};
type ReactiveElementClassWithTransformers = typeof ReactiveElement & {
prototype: ReactiveTransformElement;
};
/**
* Specifies a transformer callback that is run when the value of the decorated property, or any of the properties in the watching array, changes.
* The result of the transformer is assigned to the decorated property.
* The transformer receives the current as argument.
*/
export const transform =
<T, V>(config: {
transformer: Transformer<T, V>;
watch?: PropertyKey[];
propertyOptions?: PropertyDeclaration;
}): any =>
(clsElement: ClassElement) => {
const key = String(clsElement.key);
return {
...clsElement,
kind: "method",
descriptor: {
set(this: ReactiveTransformElement, value: V) {
export function transform<T, V>(config: {
transformer: Transformer<T, V>;
watch?: PropertyKey[];
}) {
return <ElemClass extends ReactiveElement>(
proto: ElemClass,
propertyKey: string
) => {
if (typeof propertyKey === "object") {
throw new Error("This decorator does not support this compilation type.");
}
const key = String(propertyKey);
const el = proto as unknown as ReactiveTransformElement;
// if we haven't wrapped `willUpdate` in this class, do so
if (!el._transformers) {
el._transformers = new Map<PropertyKey, Transformer>();
el._watching = new Map<PropertyKey, Set<PropertyKey>>();
// @ts-ignore
const userWillUpdate = el.willUpdate;
// @ts-ignore
el.willUpdate = function (
this: ReactiveTransformElement,
changedProperties: PropertyValues
) {
userWillUpdate.call(this, changedProperties);
const keys = new Set<PropertyKey>();
changedProperties.forEach((_v, k) => {
const watchers = this._watching;
const ks: Set<PropertyKey> | undefined = watchers.get(k);
if (ks !== undefined) {
ks.forEach((wk) => keys.add(wk));
}
});
keys.forEach((k) => {
// trigger setter
this[k] = this[`__original_${String(k)}`];
});
};
// clone any existing observers (superclasses)
// eslint-disable-next-line no-prototype-builtins
} else if (!el.hasOwnProperty("_transformers")) {
const tranformers = el._transformers;
el._transformers = new Map();
tranformers.forEach((v: any, k: PropertyKey) =>
el._transformers.set(k, v)
);
}
// set this method
el._transformers.set(propertyKey, config.transformer);
if (config.watch) {
// store watchers
config.watch.forEach((k) => {
let curWatch = el._watching.get(k);
if (!curWatch) {
curWatch = new Set();
el._watching.set(k, curWatch);
}
curWatch.add(propertyKey);
});
}
const descriptor = Object.getOwnPropertyDescriptor(proto, propertyKey);
let newDescriptor: PropertyDescriptor;
if (descriptor === undefined) {
newDescriptor = {
get(this: ReactiveTransformElement): V {
return this[`__transform_${key}`];
},
set(this: ReactiveTransformElement, value: T) {
const oldValue = this[`__transform_${key}`];
const trnsformr: Transformer<T, V> | undefined =
this._transformers.get(key);
@@ -45,65 +97,28 @@ export const transform =
this[`__original_${key}`] = value;
this.requestUpdate(key, oldValue);
},
get(): T {
return this[`__transform_${key}`];
},
enumerable: true,
configurable: true,
},
finisher(cls: ReactiveElementClassWithTransformers) {
// if we haven't wrapped `willUpdate` in this class, do so
if (!cls.prototype._transformers) {
cls.prototype._transformers = new Map<PropertyKey, Transformer>();
cls.prototype._watching = new Map<PropertyKey, Set<PropertyKey>>();
// @ts-ignore
const userWillUpdate = cls.prototype.willUpdate;
// @ts-ignore
cls.prototype.willUpdate = function (
this: ReactiveTransformElement,
changedProperties: PropertyValues
) {
userWillUpdate.call(this, changedProperties);
const keys = new Set<PropertyKey>();
changedProperties.forEach((_v, k) => {
const watchers = this._watching;
const ks: Set<PropertyKey> | undefined = watchers.get(k);
if (ks !== undefined) {
ks.forEach((wk) => keys.add(wk));
}
});
keys.forEach((k) => {
// trigger setter
this[k] = this[`__original_${String(k)}`];
});
};
// clone any existing observers (superclasses)
// eslint-disable-next-line no-prototype-builtins
} else if (!cls.prototype.hasOwnProperty("_transformers")) {
const tranformers = cls.prototype._transformers;
cls.prototype._transformers = new Map();
tranformers.forEach((v: any, k: PropertyKey) =>
cls.prototype._transformers.set(k, v)
);
}
// set this method
cls.prototype._transformers.set(clsElement.key, config.transformer);
if (config.watch) {
// store watchers
config.watch.forEach((k) => {
let curWatch = cls.prototype._watching.get(k);
if (!curWatch) {
curWatch = new Set();
cls.prototype._watching.set(k, curWatch);
}
curWatch.add(clsElement.key);
});
}
cls.createProperty(clsElement.key, {
noAccessor: true,
hasChanged: (v: any, o: any) => !shallowEqual(v, o),
...config.propertyOptions,
});
},
};
enumerable: true,
};
} else {
const oldSetter = descriptor.set;
newDescriptor = {
...descriptor,
set(this: ReactiveTransformElement, value: T) {
const oldValue = this[`__transform_${key}`];
const trnsformr: Transformer | undefined =
this._transformers.get(key);
if (trnsformr) {
this[`__transform_${key}`] = trnsformr.call(this, value);
} else {
this[`__transform_${key}`] = value;
}
this[`__original_${key}`] = value;
this.requestUpdate(key, oldValue);
oldSetter?.call(this, value);
},
};
}
Object.defineProperty(proto, propertyKey, newDescriptor);
};
}

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