Compare commits

...
Author SHA1 Message Date
Bram Kragten e98eb8de7f Add inital form data to hui-form-editor 2023-12-12 09:58:50 +01:00
renovate[bot]andGitHub 12e6701ffa Update dependency marked to v11.0.1 (#19007) 2023-12-11 20:56:46 -05:00
karwostsandGitHub 7167b66719 Don't leave empty arrays in the service control target (#18986) 2023-12-11 11:19:28 +01:00
dependabot[bot]andGitHub a52ba5fbd1 Bump actions/stale from 8.0.0 to 9.0.0 (#19004) 2023-12-11 08:06:47 +01:00
dependabot[bot]andGitHub 22cf903656 Bump actions/setup-python from 4 to 5 (#19005) 2023-12-11 08:05:40 +01:00
dependabot[bot]andGitHub d77b657036 Bump actions/labeler from 4.3.0 to 5.0.0 (#19003) 2023-12-11 07:46:59 +01:00
renovate[bot]andGitHub 4a3038c12c Update dependency hls.js to v1.4.13 (#18994) 2023-12-10 22:02:24 -05:00
renovate[bot]andGitHub 3ac7cd5d4a Update dependency @codemirror/state to v6.3.3 (#18984) 2023-12-09 20:57:44 -05:00
renovate[bot]andGitHub 58eddd2b42 Update dependency typescript to v5.3.3 (#18993) 2023-12-09 16:44:38 -05:00
renovate[bot]andGitHub d808da68bd Update dependency @lokalise/node-api to v12.1.0 (#18973) 2023-12-08 22:09:23 -05:00
renovate[bot]andGitHub 2ed4d1efa0 Update dependency @braintree/sanitize-url to v7 (#18975) 2023-12-08 22:00:36 -05:00
Paul Bottein fcb9e13a84 Bumped version to 20231208.2 2023-12-08 14:49:04 +01:00
Bram KragtenandGitHub 3ada2f3279 Fix label when there is no target (#18969) 2023-12-08 13:38:01 +00:00
Paul BotteinandGitHub 8d2d45ae4e Add dropdown style to hvac_modes feature (#18963) 2023-12-08 13:43:59 +01:00
c9e6963387 Fix todo url (#18954)
* Fix todo url

* Move searchParams

* Update src/panels/todo/ha-panel-todo.ts

* check if saved entity exists

---------

Co-authored-by: Bram Kragten <[email protected]>
2023-12-08 13:35:57 +01:00
Paul BotteinandGitHub 6d36b0e28c Hide climate mode control on default dashboard if there is only one hvac mode (#18964)
Hide hvac mode on default dashboard if there is only one hvac mode
2023-12-08 10:58:08 +00:00
Paul Bottein 61117bb34f Bumped version to 20231208.1 2023-12-08 10:30:33 +01:00
86a3c32844 Fix area in device picker (#18955)
Co-authored-by: Bram Kragten <[email protected]>
2023-12-08 09:17:40 +00:00
Paul BotteinandGitHub b855b3e103 Format number attribute for media player (#18949) 2023-12-08 10:14:55 +01:00
renovate[bot]andGitHub 80edeebab9 Update dependency chart.js to v4.4.1 (#18957) 2023-12-07 20:38:49 -05:00
renovate[bot]andGitHub f366e287b1 Update typescript-eslint monorepo to v6.13.2 (#18953) 2023-12-07 20:34:08 -05:00
renovate[bot]andGitHub 9ce8684aba Update dependency lint-staged to v15.2.0 (#18930) 2023-12-07 20:32:47 -05:00
renovate[bot]andGitHub caa6ea531c Update dependency @types/luxon to v3.3.7 (#18956) 2023-12-07 20:28:26 -05:00
Paul BotteinandGitHub cca1183ee3 Revert "Remove card features for humidifier and climate on default dashboard" (#18944)
* Revert "Remove card features for humidifier and climate on default dashboard (#18747)"

This reverts commit 2afd2788e2.

* Rename humidifier feature
2023-12-07 16:53:07 +01:00
Paul BotteinandGitHub 0f9c97aea0 Center login content for every screen size (#18943) 2023-12-07 13:45:05 +00:00
Paul BotteinandGitHub 8d08aa8c79 Fix tile card interaction when border width is set to 0 (#18941) 2023-12-07 14:40:23 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
eebcab435d Update dependency rollup-plugin-visualizer to v5.10.0 (#18936)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-07 11:15:26 +01:00
Bram KragtenandGitHub 76d3c6e237 Revert fetching config flow after subscribe for progress (#18939) 2023-12-07 09:31:34 +01:00
karwostsandGitHub a820ca1e90 Fix number selector display for 0 (#18927) 2023-12-06 17:03:44 +01:00
Paul Bottein 39260d172f Bumped version to 20231206.0 2023-12-06 14:23:09 +01:00
Paul BotteinandGitHub e646528b86 Fix empty classmap in state control (#18922)
* Fix empy classmap in state control

* Don't use class map
2023-12-06 14:22:32 +01:00
Bram KragtenandGitHub 86726102fb Fix issues with circular progress (#18920) 2023-12-06 14:21:28 +01:00
Bram KragtenandGitHub 1330558819 Force media player browser dialog re-layout after open animation (#18910) 2023-12-06 14:14:14 +01:00
Paul BotteinandGitHub b4ab0fc10b Reduce sensitivity of the circular slider on touch devices (#18921) 2023-12-06 14:13:19 +01:00
Paul BotteinandGitHub 15becf9ef6 Add ellipsis to thermostat and humidifier card title (#18924) 2023-12-06 13:28:03 +01:00
Paul BotteinandGitHub ef3785ce9f Fix particles over alert in login screen (#18923) 2023-12-06 13:16:47 +01:00
renovate[bot]andGitHub 134e13005d Update dependency eslint-config-prettier to v9.1.0 (#18909) 2023-12-05 18:18:46 -05:00
Bram Kragten dccd9b2541 Bumped version to 20231205.0 2023-12-05 18:07:59 +01:00
de83ad7a7a Reduce circular slider sensitivity when used in card (#18908)
Co-authored-by: Bram Kragten <[email protected]>
2023-12-05 18:06:29 +01:00
Paul BotteinandGitHub 7e55b9e6b8 Add humidifier modes and toggle feature (#18912) 2023-12-05 18:06:03 +01:00
Paul BotteinandGitHub 1b74ca47bf Add target humidity feature (#18913) 2023-12-05 16:42:07 +01:00
Bram KragtenandGitHub c3d4be9ceb wrap config validation (#18914) 2023-12-05 14:32:35 +00:00
karwostsandGitHub b8d0c7f7c7 Consistent sortable cursor (#18897) 2023-12-05 10:45:20 +01:00
karwostsandGitHub 92bce4078f Confirmation dialog for todo clear checked items (#18905) 2023-12-05 10:44:40 +01:00
Bram KragtenandGitHub ff8f0697c2 Fix media control card background image (#18891) 2023-12-05 09:15:04 +01:00
renovate[bot]andGitHub dddba7af00 Update dependency eslint to v8.55.0 (#18904) 2023-12-05 02:19:03 +00:00
karwostsandGitHub 14a49d6664 Copy to clipboard button for service response (#18872) 2023-12-04 14:24:35 +00:00
Bram KragtenandGitHub 22da402d56 Fix border radius for outlined icon button old browsers (#18888) 2023-12-04 15:17:43 +01:00
Bram KragtenandGitHub aa4acc6572 Use resize polyfill from lit virtualizer (#18886) 2023-12-04 08:34:31 -05:00
Simon LamonandGitHub 4d432fba57 Hide battery level and battery icon in tile card (#18826) 2023-12-04 14:26:45 +01:00
97b71c785b Fix use of "" on lock entity more info (use default code) (#18706)
Co-authored-by: Bram Kragten <[email protected]>
2023-12-04 13:23:11 +00:00
Paul BotteinandGitHub 8a93284bb3 Use resize-controller instead of container queries (#18885) 2023-12-04 14:16:10 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>Bram Kragten
bb2abe4efc Update dependency marked to v11 (#18860)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Bram Kragten <[email protected]>
2023-12-04 13:11:51 +00:00
Simon LamonandGitHub ccada33caf Accessibility improvements for circular progress indicators (#18506) 2023-12-04 14:06:25 +01:00
ildar170975andGitHub c5f15ee6ba Update ha-chart-base.ts: fix "Tooltip: a long name may overflow" (#18849) 2023-12-04 14:05:02 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
6f240ec681 Update vaadinWebComponents monorepo to v24.2.5 (#18887)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-04 12:59:01 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
fc6aef138d Update dependency fs-extra to v11.2.0 (#18848)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-04 13:57:40 +01:00
Bram Kragten 6d0eb05954 Bumped version to 20231204.0 2023-12-04 12:08:11 +01:00
Bram KragtenandGitHub 96fbbc55e1 Make history split by device class option in history card (#18871) 2023-12-04 12:06:26 +01:00
Bram KragtenandGitHub 7e74502ba3 Add particles to login, move forgot password link (#18868) 2023-12-04 11:34:42 +01:00
Paul BotteinandGitHub b273b31b03 Don't allow yaml dashboard to be in edit mode (#18879) 2023-12-04 10:17:52 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
cf00ac74c6 Update dependency sortablejs to v1.15.1 (#18876)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-04 00:57:31 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
cc702f0fb3 Update dependency @types/luxon to v3.3.6 (#18875)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-04 00:53:54 -05:00
renovate[bot]andGitHub cc6eb5789d Update dependency clean-css to v5.3.3 (#18870) 2023-12-03 11:28:51 -05:00
renovate[bot]andGitHub 669b80a9e1 Update babel monorepo to v7.23.5 (#18865) 2023-12-02 19:41:02 -05:00
karwostsandGitHub 4c4fddee94 Fix for energy cards not refreshing hourly (#18854) 2023-12-02 23:33:04 +01:00
renovate[bot]andGitHub b28a4e6b50 Update fullcalendar monorepo to v6.1.10 (#18859) 2023-12-02 03:26:39 +00:00
renovate[bot]andGitHub bdd6a55a84 Update dependency @codemirror/commands to v6.3.2 (#18857) 2023-12-01 22:16:38 -05:00
renovate[bot]andGitHub d1ebc06994 Update typescript-eslint monorepo to v6.13.1 (#18853) 2023-12-01 22:15:42 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2a150788b4 Update typescript-eslint monorepo to v6.13.0 (#18845)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-30 15:06:07 -05:00
Bram Kragten 72caf72e80 Bumped version to 20231130.0 2023-11-30 17:18:58 +01:00
Bram KragtenandGitHub a6ff1899df Prevent double quick action (#18842) 2023-11-30 16:18:04 +00:00
Paul BotteinandGitHub 6a999597df Rename number feature to number value feature (#18836) 2023-11-30 16:17:54 +00:00
Bram KragtenandGitHub 219fc9e53a Group history by device class (#18841) 2023-11-30 17:17:26 +01:00
Bram KragtenandGitHub 861959ed2d add previous button to login screen (#18837) 2023-11-30 17:06:22 +01:00
Damian SypniewskiandGitHub f7f50294e7 Added hold and double tap actions for tile card (#18345) 2023-11-30 16:03:07 +01:00
Bram Kragten a226333c1e Update area-filter-dialog.ts 2023-11-30 15:16:01 +01:00
75f18aa69b Move disabled items always to the bottom, only change color of text, … (#18814)
* Move disabled items always to the bottom, only change color of text, dont drag disabled items

* Don't allow to drag hidden items

---------

Co-authored-by: Paul Bottein <[email protected]>
2023-11-30 14:37:10 +01:00
Simon LamonandGitHub 60ff4fdc1f Ensure helper type is always localized (#18825)
* Ensure helper type is always localized

* Remove the check
2023-11-30 14:14:13 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
8d14cb0ab7 Update vaadinWebComponents monorepo to v24.2.4 (#18835)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-30 08:12:43 -05:00
Bram KragtenandGitHub 606c809880 Update size of icon on launch screen (#18833) 2023-11-30 12:34:46 +01:00
f1692038f8 Fix developer tools set state for unexisting entity (#18827)
Co-authored-by: Bram Kragten <[email protected]>
2023-11-30 10:59:51 +00:00
Paul BotteinandGitHub 79f5ec0cd5 Fix dashboard crashed when deleting hidden area (#18832) 2023-11-30 10:59:31 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
416a2a080d Update CodeMirror (#18829)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-30 10:58:49 +00:00
Paul BotteinandGitHub 92dc8b1561 Fix map dark mode (#18830) 2023-11-30 11:47:44 +01:00
karwostsandGitHub 07b807adfc Fit map on load (#18819) 2023-11-30 10:49:40 +01:00
Simon LamonandGitHub 843430ef41 Cleanup iron resize event (#18813) 2023-11-29 21:02:57 +01:00
Bram KragtenandGitHub b5b2392dd2 Guard for no person for user (#18812) 2023-11-29 20:59:06 +01:00
karwostsandGitHub bf24740c7b Fix non-hass shouldUpdate regressions (#18810) 2023-11-29 14:28:38 +00:00
Bram Kragten 4ec11c7cf6 Bumped version to 20231129.1 2023-11-29 15:25:35 +01:00
Bram Kragten 8ff36d0ccf Merge branch 'master' into dev 2023-11-29 12:39:58 +01:00
Bram Kragten e7e465df69 Bumped version to 20231129.0 2023-11-29 12:38:24 +01:00
0c042079ed ha-selector-selector implementation (#18421)
Co-authored-by: Bram Kragten <[email protected]>
2023-11-29 11:09:49 +00:00
lunmayandGitHub a5a9bcafa7 Typo fixes: "url" -> "URL" in blueprint (#18808) 2023-11-29 11:48:20 +01:00
Bram KragtenandGitHub 867f625b0a Fix has changed for when hass is not changed (#18778) 2023-11-29 11:20:04 +01:00
3876c67588 Add translation support for script errors (#18786)
Co-authored-by: Bram Kragten <[email protected]>
2023-11-29 11:14:29 +01:00
Paul BotteinandGitHub 93158bb3af Add re-import blueprint (#18807)
* Add re-import blueprint

* Add disabled color to icon
2023-11-29 10:56:52 +01:00
schelvandGitHub 5c47d8652d Add Option For Kelvin Unit To Color Temperature Selector (#18627) 2023-11-29 10:56:44 +01:00
eda0d12867 Dev tools events layout (#18389)
Co-authored-by: Bram Kragten <[email protected]>
2023-11-29 09:51:33 +00:00
Bram KragtenandGitHub 4a53de4466 Lazy load language picker in auth and onboarding (#18806) 2023-11-29 10:50:05 +01:00
karwostsandGitHub e730649a8d Fix condition key function for template shorthand notation (#18107) 2023-11-29 10:46:22 +01:00
Steve RepsherandGitHub 3a94deef69 Fix minifying templates from dependencies (#18795) 2023-11-29 10:35:53 +01:00
Bram KragtenandGitHub c1c186d279 Cleanup event listeners (#18803) 2023-11-29 10:21:12 +01:00
Matthias AlphartandGitHub 7356db919a Default to ltr for reading direction (#18767) 2023-11-29 10:17:31 +01:00
Amit FinkelsteinandGitHub 44157a5df3 Fix map auto-fit (#18801) 2023-11-29 10:16:34 +01:00
Paul BotteinandGitHub 2acd1ff5e8 Refactor and cleanup device picker (#18804) 2023-11-29 10:01:54 +01:00
Bram KragtenandGitHub 150a5571cf Refactor and cleanup entity config page (#18797) 2023-11-29 09:19:53 +01:00
Bram KragtenandGitHub 1eb25f4829 Add import thread credentials to external bus (#18777) 2023-11-29 09:01:33 +01:00
Bram KragtenandGitHub d8d4ecf79f Refactor and clean up of device pages (#18796) 2023-11-29 09:01:11 +01:00
karwostsandGitHub 081bd98e98 Fix map autofit (#18799) 2023-11-29 00:29:52 +01:00
Robert Van GorkomandGitHub 6134f415e9 Fix race condition with picture-elements card custom elements (#18765) 2023-11-28 21:23:06 +00:00
b6a7581eca Augment history panel with Long Term Statistics (#18213)
Co-authored-by: Bram Kragten <[email protected]>
2023-11-28 22:14:05 +01:00
7727f34e8f Add area filter selector for default dashboard (#18779)
Co-authored-by: Bram Kragten <[email protected]>
2023-11-28 21:43:34 +01:00
Amit FinkelsteinandGitHub 9b20e1cf56 Avoid re-rendering map with "sources" (#18635) 2023-11-28 20:30:28 +01:00
Steve RepsherandGitHub b901ecacca Add missing Intl polyfills to modern build (#18794) 2023-11-28 19:28:10 +00:00
Simon LamonandGitHub 7691f7eb05 PolymerElement cleanup (#18793) 2023-11-28 20:25:12 +01:00
Bram KragtenandGitHub 8c0c56b954 Login page feedback (#18791) 2023-11-28 20:21:10 +01:00
karwostsandGitHub d968a20862 More disconnected callback errors (#18792) 2023-11-28 20:19:49 +01:00
9f1cd80a31 Add a Grid/List toggle for Media Browser (#18256)
Co-authored-by: Bram Kragten <[email protected]>
2023-11-28 16:34:34 +00:00
Paul BotteinandGitHub 5a9ccc5ae7 Fix humidifier more info (#18789) 2023-11-28 17:30:39 +01:00
Paul BotteinandGitHub 6d7b0c5626 Fix tile features colors (#18788) 2023-11-28 17:30:23 +01:00
karwostsandGitHub 400b8034e1 missing disconnectedCallback in energy-period-selector (#18790) 2023-11-28 17:27:08 +01:00
Bram KragtenandGitHub 05a22e3271 Keep targets when switching services (#18772) 2023-11-28 14:42:40 +01:00
Bram Kragten c1f76e0565 Update ha-authorize.ts 2023-11-28 13:44:23 +01:00
Simon LamonandGitHub 4582c3ba0a Migrate state cards from Polymer to Lit (#18257) 2023-11-28 13:30:39 +01:00
f4ee734ea3 Use new localize format (#18574)
Co-authored-by: Bram Kragten <[email protected]>
2023-11-28 12:29:41 +00:00
Bram Kragten 2087028c47 Update home.markdown 2023-11-28 13:24:09 +01:00
37a56b250a Add multiple option to text selector (#18785)
* Add multiple option to text selector

* Make multiple optional

* Update src/components/ha-selector/ha-selector-text.ts

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

---------

Co-authored-by: Bram Kragten <[email protected]>
2023-11-28 11:28:29 +01:00
Márton BraunandGitHub 71a41be20a Add fit_zones parameter to map card (#18760) 2023-11-28 11:04:43 +01:00
Bram KragtenandGitHub ffb19b31a5 Use subscribe for todo items (#18776) 2023-11-28 08:28:13 +01:00
Bram KragtenandGitHub db68c7faa9 Log errors when downloading lokalise translations (#18781) 2023-11-28 08:21:19 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
07ae958eb0 Update dependency vis-data to v7.1.9 (#18783)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-27 19:16:43 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
b62b5f6575 Update dependency rollup-plugin-visualizer to v5.9.3 (#18782)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-27 19:15:00 -05:00
Bram KragtenandGitHub 2e1fb9df66 Update design of login page (#18770) 2023-11-27 23:06:51 +01:00
Bram Kragten 31c91cea9a Update translations_upload_base 2023-11-27 17:59:13 +01:00
Bram KragtenandGitHub 9dc844ca28 Dont change pipeline if local storage changes (#18773) 2023-11-27 15:42:07 +01:00
02ebc028c8 Add custom card names to the edit card dialog header (#18750)
Co-authored-by: Bram Kragten <[email protected]>
2023-11-27 15:30:39 +01:00
karwostsandGitHub 5d35605b82 Filter energy card updates with shouldUpdate (#18763) 2023-11-27 15:29:15 +01:00
Bram KragtenandGitHub 22e86af5b3 Fix race condition with Data Entry Flow Progress (#18775) 2023-11-27 11:28:49 +01:00
dependabot[bot]andGitHub 8c39ed46a8 Bump dessant/lock-threads from 5.0.0 to 5.0.1 (#18769) 2023-11-27 07:40:59 +01:00
Raman GuptaandGitHub 5965c3fdaa Add alert to zwave_js device info page for custom device config (#18686) 2023-11-26 11:09:02 +01:00
renovate[bot]andGitHub 15a5d2bc38 Update dependency @bundle-stats/plugin-webpack-filter to v4.8.3 (#18761) 2023-11-25 22:22:03 -05:00
Paul BotteinandGitHub 0432cc95fc Allow overriding blueprints (#18718) 2023-11-25 11:49:58 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
6dafaac021 Update dependency @types/sortablejs to v1.15.7 (#18756)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-25 00:03:20 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
d8929c9252 Update dependency @types/mocha to v10.0.6 (#18755)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-25 00:02:42 -05:00
renovate[bot]andGitHub 5fa3a720b3 Update dependency @bundle-stats/plugin-webpack-filter to v4.8.2 (#18752) 2023-11-24 23:34:03 -05:00
renovate[bot]andGitHub 6d3b838b6a Update dependency @types/leaflet-draw to v1.0.11 (#18753) 2023-11-24 23:33:03 -05:00
Bram KragtenandGitHub 58e0179321 Add local login flow (#18717) 2023-11-24 17:22:05 +01:00
Paul BotteinandGitHub eaf7e29b8a Fix thermostat humidifier card size (#18749) 2023-11-24 16:27:01 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
260f1df1b9 Update babel monorepo to v7.23.4 (#18730)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-24 15:58:57 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
a88a4ef82c Update dependency typescript to v5.3.2 (#18736)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-24 15:57:57 +01:00
Steve RepsherandGitHub 075cca5991 Inject polyfills where used (#18719) 2023-11-24 15:57:21 +01:00
Simon LamonandGitHub 1d2dc37f75 Migrate push notification toggle from Polymer to Lit (#18565) 2023-11-24 15:47:09 +01:00
Paul BotteinandGitHub 3da7025d78 Improve search for single character (#18748) 2023-11-24 14:37:59 +00:00
Paul BotteinandGitHub 15b1d8ee14 Move more info control component to state control (#18745) 2023-11-24 14:33:11 +00:00
239d8fa948 Fix card-picker search for single character (#18733)
* Fix card-picker search for single character

* Update src/panels/lovelace/editor/card-editor/hui-card-picker.ts

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

---------

Co-authored-by: Bram Kragten <[email protected]>
Co-authored-by: Paul Bottein <[email protected]>
2023-11-24 15:23:27 +01:00
Bram KragtenandGitHub 1de2e6161d Make thermostat centered in panel or grid view (#18731)
* Make thermostat centered in panel or grid view

* Update hui-humidifier-card.ts
2023-11-24 14:17:06 +01:00
Paul BotteinandGitHub 3e7f008277 Rename tile features to card features (#18732) 2023-11-24 13:36:58 +01:00
G JohanssonandGitHub 31a93d360d Make lock default code a password field (#18722) 2023-11-24 13:11:18 +01:00
Paul BotteinandGitHub 2afd2788e2 Remove card features for humidifier and climate on default dashboard (#18747) 2023-11-24 12:53:41 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
322fa99147 Update dependency @types/tar to v6.1.10 (#18742)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-24 11:13:49 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
c43ad52ff1 Update dependency @types/sortablejs to v1.15.6 (#18741)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-24 12:03:01 +01:00
Paul BotteinandGitHub 6aa9737481 Fix ha control select option size (#18746) 2023-11-24 12:02:44 +01:00
renovate[bot]andGitHub 7d9d6b99d9 Update dependency @types/luxon to v3.3.5 (#18739) 2023-11-24 03:46:28 +00:00
renovate[bot]andGitHub 9c69e6f87c Update dependency @types/mocha to v10.0.5 (#18740) 2023-11-23 22:36:00 -05:00
renovate[bot]andGitHub 0c90021895 Update typescript-eslint monorepo to v6.12.0 (#18734) 2023-11-23 21:59:42 -05:00
Paul BotteinandGitHub 9163b9c124 Add new design to humidifier card (#18711) 2023-11-23 00:37:19 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
61717e1529 Update dependency core-js to v3.33.3 (#18721)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-22 13:38:08 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
168d418c27 Update dependency @bundle-stats/plugin-webpack-filter to v4.8.1 (#18720)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-22 13:36:11 -05:00
Paul BotteinandGitHub c787c920fc Add new design to thermostat card (#18709)
* Add new design for thermostat card

* Add feature to thermostat card

* Fix margin

* Add current

* use big number component

* Add current

* Fix translations

* Add theme and name options

* Reduce margin on small card

* Fix types

* Add hvac mode to default dashboard

* Don't put feature full size

* Full width for features

* Improve design on small screen
2023-11-22 14:42:42 +01:00
Steve RepsherandGitHub 1526209f82 Adjust bundle filenames for stats and debugging (#18677) 2023-11-22 14:11:23 +01:00
Steve RepsherandGitHub cf355c419d Fix Babel runtime helper injections (#18698) 2023-11-22 14:10:28 +01:00
Paul BotteinandGitHub eef024587b Use entity component translations for update entity (#18608) 2023-11-22 12:43:33 +01:00
270d463d02 Add configuration to default dashboard (#18658)
Co-authored-by: Simon Lamon <[email protected]>
2023-11-22 12:40:17 +01:00
renovate[bot]andGitHub 0735705dd3 Update dependency eslint to v8.54.0 (#18707) 2023-11-20 19:21:17 -05:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Franck Nijhof
0a1dbe6d9d Bump dessant/lock-threads from 4.0.1 to 5.0.0 (#18699)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Franck Nijhof <[email protected]>
2023-11-20 08:47:54 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>Steve Repsher
15395275ba Update dependency prettier to v3.1.0 (#18675)
* Update dependency prettier to v3.1.0

* Reformat

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Steve Repsher <[email protected]>
2023-11-19 23:31:56 -05:00
6e66ba202f Add a button to delete all refresh tokens (#18680)
Co-authored-by: Bram Kragten <[email protected]>
2023-11-19 13:32:25 +01:00
karwostsandGitHub 5ebe1e0369 Add shortcut from energy dashboard to energy settings (#18596) 2023-11-19 13:31:55 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
860ab7a3ba Lock file maintenance (#18696)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-18 22:50:36 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
d499640304 Update dependency @lezer/highlight to v1.2.0 (#18672)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-18 22:28:46 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
4f3f516767 Update dependency rrule to v2.8.1 (#18648)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-18 21:06:30 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
0996dbf2a1 Update formatjs monorepo (#18684)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-18 21:37:37 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
bc59e52cea Update dependency marked to v10 (#18651)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-18 16:33:31 -05:00
wittypluckandGitHub b8d4e957e2 Add logarithmic scale option to Statistics and History graph cards (#18637) 2023-11-18 17:31:29 +01:00
karwostsandGitHub 8002ec75bc Temporarily filter cleared statistics from devtools table (#18694) 2023-11-18 17:30:48 +01:00
karwostsandGitHub a45eefa742 Add live camera & custom AR to Area card (#18643) 2023-11-18 17:26:21 +01:00
Jan BouwhuisandGitHub a1236924aa Ensure websocket_api error messages shows longer (#18690) 2023-11-17 20:35:08 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
9320e8c1a3 Update Yarn to v4.0.2 (#18687)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-17 11:35:32 -05:00
karwostsandGitHub addcd3a983 Typo in bug_report.yml (#18681)
Update bug_report.yml
2023-11-17 15:53:12 +01:00
Paul BotteinandGitHub e1dc73e992 Fix yaml editor lovelace (#18664) 2023-11-16 18:55:09 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
ba8849ed4d Update typescript-eslint monorepo to v6.11.0 (#18679)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-16 12:48:12 -05:00
Thomas LovénandGitHub 36bca04341 Polyfill ElementInternals for material-web components. Fix #18600 (#18638) 2023-11-16 18:17:41 +01:00
Simon LamonandGitHub fb95de1f73 Add translations for the developer tools statistic issues (#18646) 2023-11-16 18:16:51 +01:00
karwostsandGitHub 3addfc3548 Localization bugfixes in config devices/entities/helpers (#18645) 2023-11-16 18:13:31 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
e2e80d1f49 Update vaadinWebComponents monorepo to v24.2.3 (#18678)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-16 12:03:38 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
a96eba2637 Update dependency @lit-labs/virtualizer to v2.0.11 (#18583)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-16 11:55:24 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
274810b954 Update dependency luxon to v3.4.4 (#18674)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-16 11:40:03 -05:00
Paul BotteinandGitHub 842df983c3 Add new dashboard dialog (#18657)
* Add new dashboard dialog

* Update default dashboard wording
2023-11-16 13:43:55 +01:00
Simon LamonandGitHub 0eeadcd31a Replace paper-input in cast (#18647) 2023-11-16 12:39:54 +01:00
Josh McCartyandGitHub 8d37c5612b Move attribute pre styles to ha-attribute-value component (#18649) 2023-11-16 12:28:45 +01:00
dniklesandGitHub e94461f7fe Update dialog-add-integration.ts (#18615) 2023-11-16 12:18:18 +01:00
Bram KragtenandGitHub f5edee1e91 Add support for warnings in check_config (#18489) 2023-11-16 12:17:14 +01:00
Paul BotteinandGitHub 98cdbb4559 Add minimal UI for climate and water entity without target (#18666) 2023-11-16 12:16:37 +01:00
Paul BotteinandGitHub f3f63d95b5 Restore map filter theme (#18667) 2023-11-16 12:12:17 +01:00
karwostsandGitHub 244340f211 Allow search for integration name in log search (#18668) 2023-11-16 12:08:10 +01:00
Paul BotteinandGitHub 75626431b1 Improve ripple background color for tile card (#18579) 2023-11-16 10:57:24 +01:00
Allen PorterandGitHub 244868348b Delete To-do items in a batched single request (#18662) 2023-11-16 09:52:03 +01:00
renovate[bot]andGitHub a909c6d905 Update formatjs monorepo (#18663) 2023-11-15 20:49:16 -05:00
Michael HansenandGitHub f2efff9d71 Use stt-vad-end event in assist debug panel (#18671)
* Use stt-vad-end event in assist debug panel

* Remove end_suffix
2023-11-15 21:36:49 +00:00
karwostsandGitHub 08a7a10e1c Don't save new automation when save dialog is cancelled (#18655) 2023-11-15 18:03:47 +01:00
Simon LamonandGitHub b35e5abd83 Fix Edit Area dialog doesn't save area (#18659)
secondary action
2023-11-15 18:00:35 +01:00
karwostsandGitHub 291e9fc0a2 Fix onboarding password form (#18665) 2023-11-15 17:58:22 +01:00
Paul BotteinandGitHub de370d6384 Add todo entity_id in URL (#18653) 2023-11-15 11:26:03 +01:00
Paul BotteinandGitHub 1cf928b425 Improve Lovelace types (#18652) 2023-11-15 11:13:49 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
b9c62c34a0 Update dependency lint-staged to v15.1.0 (#18660)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-15 10:49:33 +01:00
renovate[bot]andGitHub 37554213dc Update dependency @bundle-stats/plugin-webpack-filter to v4.8.0 (#18654) 2023-11-14 20:37:44 -05:00
renovate[bot]andGitHub 3845fd2ef9 Update dependency @types/tar to v6.1.9 (#18650) 2023-11-14 20:35:55 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
837b36a430 Update dependency marked to v9.1.6 (#18644)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-13 19:46:13 +01:00
karwostsandGitHub bff09a7a36 Fix login password form (#18619) 2023-11-13 19:45:34 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
a5e5efa526 Update dependency @codemirror/autocomplete to v6.11.0 (#18633)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-12 22:29:54 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
1cd5b9ff37 Update babel monorepo to v7.23.3 (#18632)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-12 21:16:45 -05:00
renovate[bot]andGitHub 6a11155dd7 Update dependency vis-data to v7.1.8 (#18625) 2023-11-11 21:09:28 -05:00
renovate[bot]andGitHub 1acb76d2f0 Update dependency @types/leaflet to v1.9.8 (#18622) 2023-11-12 02:07:18 +00:00
renovate[bot]andGitHub 2e8a40efd5 Update dependency @types/ua-parser-js to v0.7.39 (#18616) 2023-11-11 20:58:50 -05:00
renovate[bot]andGitHub 845a0e4e39 Update dependency @types/js-yaml to v4.0.9 (#18621) 2023-11-11 20:56:30 -05:00
Paul BotteinandGitHub 9417f13cc9 Add unit for number tile feature (#18602) 2023-11-10 19:30:07 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
d3f52f3bc0 Update dependency @types/tar to v6.1.8 (#18614)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-10 18:17:57 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
7d0ec00fde Update dependency @types/sortablejs to v1.15.5 (#18613)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-10 13:06:13 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
6dbb5dd4be Update dependency @types/qrcode to v1.5.5 (#18610)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-10 13:05:36 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
f30e7948cb Update dependency @types/luxon to v3.3.4 (#18605)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-10 13:04:49 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
41472d8160 Update dependency @types/serve-handler to v6.1.4 (#18612)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-10 12:43:05 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
e596d32426 Update dependency @types/mocha to v10.0.4 (#18606)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-10 12:41:33 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
89de62812f Update dependency @types/leaflet-draw to v1.0.10 (#18603)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-10 12:39:56 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
3e391fcbe6 Update dependency @types/html-minifier-terser to v7.0.2 (#18601)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-10 12:37:31 -05:00
karwostsandGitHub 708ab2ed69 Localize hide/show password (#18607) 2023-11-10 18:12:36 +01:00
Paul BotteinandGitHub 1d45cb78fe Rename tooltipUnit to unit for slider (#18599) 2023-11-10 18:08:12 +01:00
d3f6ebd1d0 Add unit to temperature tile number button group (#17841)
* Add unit to temperature tile number button group

* Update gallery

* Use blank before unit

* Hide unit if no space

* Fix build

---------

Co-authored-by: Paul Bottein <[email protected]>
2023-11-10 14:22:10 +01:00
21644c70b3 Add number tile feature (#18562)
* hui-number-tile-feature

* Added support for number domain

* Apply suggestions from code review (thanks @piitaya)

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

* Fixed the callback to use the correct service

* fix formatting

---------

Co-authored-by: Paul Bottein <[email protected]>
2023-11-10 08:34:29 +00:00
karwostsandGitHub eb75389cac Localize clear in entity filter (#18598)
Localize  in entity filter
2023-11-10 08:27:36 +01:00
Bram KragtenandGitHub cd4f3a091b Fix add device dialog (#18591) 2023-11-10 08:27:02 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
19c1973ec1 Update dependency @types/chromecast-caf-sender to v1.0.8 (#18597)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-10 03:35:04 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
a8efbe5b06 Update dependency @types/chromecast-caf-receiver to v6.0.12 (#18595)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-10 03:22:14 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
44b5c66c19 Update dependency @types/babel__plugin-transform-runtime to v7.9.5 (#18594)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-09 22:08:58 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
3fa3bba4d8 Update formatjs monorepo (#18592)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-09 22:07:01 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
ab09c821a2 Update typescript-eslint monorepo to v6.10.0 (#18586)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-09 22:05:26 -05:00
18b5215ce6 Only update dev tools yaml editor on entity change or submit (#18575)
Co-authored-by: Simon Lamon <[email protected]>
2023-11-09 18:24:45 +01:00
Bram Kragten 00a311bd63 Bumped version to 20231030.2 2023-11-09 18:23:17 +01:00
tzagimandBram Kragten 749c2ab8ac Fix for RTL (#18509) 2023-11-09 18:22:27 +01:00
Kendell RandBram Kragten d06fdeb265 Fix "ttme" typo on the demo page (#18543) 2023-11-09 18:22:12 +01:00
Simon LamonandBram Kragten 06d76be2c2 Fix refresh in developer state tools (#18532) 2023-11-09 18:21:50 +01:00
David BellandBram Kragten 6728e8d107 Don't display hidden/non-visible calendars on the Calendar panel (#18541) 2023-11-09 18:21:32 +01:00
Kendell RandBram Kragten 533e2bed8a Properly set direction styles (#18483) 2023-11-09 18:20:44 +01:00
karwostsandBram Kragten 310a08f3e6 Fix choose add option (#18493) 2023-11-09 18:19:19 +01:00
Paul BotteinandBram Kragten 0566889a1e Use strict comparison for above condition in conditional card (#18560) 2023-11-09 18:18:37 +01:00
Paul BotteinandGitHub 37b7395986 Migrate chips to Material 3 chips. (#18513) 2023-11-09 17:57:37 +01:00
Bram KragtenandGitHub 4933413140 Fix virtualizer with v2.0.10 (#18584) 2023-11-09 11:53:35 -05:00
Bram KragtenandGitHub 1c16bd5ab2 rollback lit-labs/virtualizer to 2.0.8 (#18580) 2023-11-09 16:26:09 +01:00
Paul BotteinandGitHub 3a926c6f83 Add pointer-events none to slider tooltip (#18577) 2023-11-09 14:57:23 +01:00
7a619ad55a Only update dev tools yaml editor on entity change or submit (#18575)
Co-authored-by: Simon Lamon <[email protected]>
2023-11-09 10:00:24 +01:00
Paul BotteinandGitHub bc21425981 Add tooltip to tile sliders and more info sliders (#18567) 2023-11-08 12:47:55 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
f2505c0798 Update dependency eslint to v8.53.0 (#18558)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-08 11:48:22 +01:00
Steve RepsherandGitHub cee8c756fc Remove dependency esprima (#18564) 2023-11-08 11:24:03 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
396b3aace9 Update dependency @codemirror/view to v6.22.0 (#18553)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-07 18:02:11 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
28dc1e4da9 Update vaadinWebComponents monorepo to v24.2.2 (#18552)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-07 17:59:54 -05:00
Kendell RandGitHub aa0419e783 Minify logos (#18542) 2023-11-07 13:39:38 +01:00
Jan BouwhuisandGitHub fd9c24d05e Add localization to service call exceptions (#18447) 2023-11-07 12:04:53 +01:00
Paul BotteinandGitHub 8bdbe8c6a6 Use strict comparison for above condition in conditional card (#18560) 2023-11-07 12:04:04 +01:00
Steve RepsherandGitHub 39550cefa0 Add some Renovate groups and enable NVM updates (#18559) 2023-11-07 11:53:47 +01:00
David BellandGitHub 589e3b63c7 Don't display hidden/non-visible calendars on the Calendar panel (#18541) 2023-11-06 15:09:54 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
0cc38278b9 Update dependency @lit-labs/virtualizer to v2.0.10 (#18547)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-06 15:56:45 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
aafdf7bed7 Update dependency vis-network to v9.1.9 (#18548)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-06 15:55:24 +01:00
Simon LamonandGitHub a7f6ce3079 Fix refresh in developer state tools (#18532) 2023-11-06 15:53:23 +01:00
karwostsandGitHub 3d03f74d66 Improve template trigger/condition descriptions (#18504) 2023-11-06 10:04:58 +01:00
tzagimandGitHub e09a6a23fc Fix for RTL (#18509) 2023-11-06 10:02:44 +01:00
Kendell RandGitHub 9e4bb6ed0c Fix "ttme" typo on the demo page (#18543) 2023-11-06 10:02:00 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
c45c8ab5c0 Update dependency sinon to v17.0.1 (#18535)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-05 14:16:21 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
5ef6973933 Update dependency marked to v9.1.5 (#18523)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-05 14:14:50 -05:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
1df344580a Update dependency eslint-plugin-lit-a11y to v4.1.1 (#18534)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-05 14:13:25 -05:00
renovate[bot]andGitHub 25acc479b9 Update dependency core-js to v3.33.2 (#18515) 2023-11-02 20:54:59 -04:00
renovate[bot]andGitHub c9f051374b Update dependency punycode to v2.3.1 (#18516) 2023-11-02 20:50:03 -04:00
renovate[bot]andGitHub bf5116fc0b Update typescript-eslint monorepo to v6.9.1 (#18518) 2023-11-02 20:47:03 -04:00
renovate[bot]andGitHub edc8cb1d2e Update dependency @rollup/plugin-replace to v5.0.5 (#18505) 2023-11-02 20:42:05 -04:00
Bram KragtenandGitHub a60bb3ae0a Clean up auth flow translation placeholders (#18502) 2023-11-02 21:02:42 +01:00
Paul BotteinandGitHub 784f753f07 Display default action label in action selector (#18398) 2023-11-02 16:10:15 +01:00
Paul BotteinandGitHub e63c7e3763 Add trigger selector for blueprint (#18469) 2023-11-02 16:01:59 +01:00
karwostsandGitHub cfa522068c Localize trigger condition and add list formatting (#18488) 2023-11-01 15:42:43 +01:00
schelvandGitHub 5f2375fe84 feat: Dynamically adjust gradient percentages based on min/max values (#18479) 2023-11-01 15:41:26 +01:00
Kendell RandGitHub a9e34d7590 Stop using ha-markdown on the auth page (#18480) 2023-11-01 15:36:17 +01:00
Paul BotteinandGitHub 463cfb869f Add and and or condition to conditional card (#18409) 2023-11-01 15:28:37 +01:00
Paul BotteinandGitHub acb5a2b283 Add test button to conditional card (#18411) 2023-11-01 15:25:56 +01:00
Bram KragtenandGitHub 08597d6e91 Bump node to v20 (#18497) 2023-11-01 15:22:23 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>Steve RepsherBram Kragten
9478485268 Update Yarn to v4 (#18414)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Steve Repsher <[email protected]>
Co-authored-by: Bram Kragten <[email protected]>
2023-11-01 10:16:46 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
0af9ec2fff Pin dependencies (#18498)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-01 09:51:15 +00:00
Kendell RandGitHub f6e74de05e Properly set direction styles (#18483) 2023-11-01 10:38:02 +01:00
Bram KragtenandGitHub 8b0373d5c0 Revert bump to @lit/[email protected] (#18496) 2023-11-01 10:35:50 +01:00
Bram Kragten ddca7584ef Bumped version to 20231030.1 2023-11-01 10:21:08 +01:00
karwostsandBram Kragten e6cfe74cac Fix choose add option (#18493) 2023-11-01 10:20:25 +01:00
karwostsandGitHub d4218250af Fix choose add option (#18493) 2023-11-01 09:37:26 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>Steve Repsher
78783942be Update dependency @lit-labs/observers to v2.0.2 (#18484)
* Update dependency @lit-labs/observers to v2.0.2

* Resolve @lit/reactive-element to v1

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Steve Repsher <[email protected]>
2023-10-31 14:42:28 -04:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>Steve Repsher
17ad8013ca Update dependency @lit-labs/context to v0.5.1 (#18208)
* Update dependency @lit-labs/context to v0.5.1

* Switch to @lit/context and resolve reactive-element to v1

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Steve Repsher <[email protected]>
2023-10-31 13:53:53 -04:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>Steve Repsher
f70767f084 Update dependency @lit-labs/motion to v1.0.6 (#18205)
* Update dependency @lit-labs/motion to v1.0.6

* Resolve to lit v2

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Steve Repsher <[email protected]>
2023-10-31 14:31:42 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>Steve Repsher
3972394d82 Update dependency @lit-labs/virtualizer to v2.0.9 (#18206)
* Update dependency @lit-labs/virtualizer to v2.0.9

* Resolve to lit v2

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Steve Repsher <[email protected]>
2023-10-31 13:22:54 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
5331fb4f5f Update dependency marked to v9.1.3 (#18485)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-31 08:44:18 -04:00
Matthias de BaatandGitHub 16df352ba8 Update ha-dialogs.markdown (#18487) 2023-10-31 12:27:46 +00:00
Bram KragtenandGitHub 3b553a3a4b 20231030.0 (#18478) 2023-10-30 21:45:08 +01:00
Bram Kragten 8e1e75dee1 Bumped version to 20231030.0 2023-10-30 21:44:17 +01:00
Bram KragtenandGitHub d27b4e04a9 Adapt to new todo services (#18477) 2023-10-30 20:32:32 +00:00
36f7b34ac5 Use trigger and condition type translation labels (#18413)
Co-authored-by: Bram Kragten <[email protected]>
2023-10-30 20:54:30 +01:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
c0ff24bf1b Update dependency ua-parser-js to v1.0.37 (#18473)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-30 12:29:17 -04:00
abb5aa348f Allow individual item deletion in To-do list (#18464)
Co-authored-by: Bram Kragten <[email protected]>
2023-10-30 14:21:29 +00:00
renovate[bot]GitHubrenovate[bot] <29139614+renovate[bot]@users.noreply.github.com>Bram Kragten
37ab5cbdc3 Update dependency fuse.js to v7 (#18462)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Bram Kragten <[email protected]>
2023-10-30 15:09:12 +01:00
Bram KragtenandGitHub 42be3b331c Fix buttons (#18472) 2023-10-30 13:56:48 +01:00
Paul BotteinandGitHub 71e05f79c2 Update ts-lit-plugin to 2.0.1 (#18471) 2023-10-30 13:40:07 +01:00
karwostsandGitHub c5a0a5bbbf Fix statistics bar chart time axis (#18450) 2023-10-30 13:39:15 +01:00
Bram KragtenandGitHub 3d674cf237 20231027.0 (#18448) 2023-10-27 16:55:37 +02:00
Paul BotteinandGitHub 4e6e924a40 20231026.0 (#18431) 2023-10-26 15:57:36 +02:00
Bram KragtenandGitHub 073ead5828 20231025.1 (#18399) 2023-10-25 13:59:53 +02:00
Bram KragtenandGitHub fdaefadd18 20231025.0 (#18395) 2023-10-25 12:17:22 +02:00
693 changed files with 22837 additions and 18084 deletions
+1 -1
View File
@@ -9,7 +9,7 @@ body:
If you have a feature or enhancement request for the frontend, please [start an discussion][fr] instead of creating an issue.
**Please not not report issues for custom cards.**
**Please do not report issues for custom cards.**
[fr]: https://github.com/home-assistant/frontend/discussions
[releases]: https://github.com/home-assistant/home-assistant/releases
+1 -1
View File
@@ -10,6 +10,6 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Apply labels
uses: actions/labeler@v4.3.0
uses: actions/labeler@v5.0.0
with:
sync-labels: true
+2 -1
View File
@@ -9,9 +9,10 @@ jobs:
lock:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v4.0.1
- uses: dessant/lock-threads@v5.0.1
with:
github-token: ${{ github.token }}
process-only: "issues, prs"
issue-lock-inactive-days: "30"
issue-exclude-created-before: "2020-10-01T00:00:00Z"
issue-lock-reason: ""
+1 -1
View File
@@ -23,7 +23,7 @@ jobs:
uses: actions/[email protected]
- name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
+1 -1
View File
@@ -29,7 +29,7 @@ jobs:
uses: home-assistant/actions/helpers/verify-version@master
- name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
+1 -1
View File
@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: 90 days stale policy
uses: actions/stale@v8.0.0
uses: actions/stale@v9.0.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 90
+1 -1
View File
@@ -1 +1 @@
18
lts/iron
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-874
View File
File diff suppressed because one or more lines are too long
+893
View File
File diff suppressed because one or more lines are too long
+5 -7
View File
@@ -1,11 +1,9 @@
compressionLevel: mixed
defaultSemverRangePrefix: ""
enableGlobalCache: false
nodeLinker: node-modules
plugins:
- path: .yarn/plugins/@yarnpkg/plugin-typescript.cjs
spec: "@yarnpkg/plugin-typescript"
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
spec: "@yarnpkg/plugin-interactive-tools"
yarnPath: .yarn/releases/yarn-3.6.4.cjs
yarnPath: .yarn/releases/yarn-4.0.2.cjs
@@ -0,0 +1,56 @@
import defineProvider from "@babel/helper-define-polyfill-provider";
// List of polyfill keys with supported browser targets for the functionality
const PolyfillSupport = {
fetch: {
android: 42,
chrome: 42,
edge: 14,
firefox: 39,
ios: 10.3,
opera: 29,
opera_mobile: 29,
safari: 10.1,
samsung: 4.0,
},
proxy: {
android: 49,
chrome: 49,
edge: 12,
firefox: 18,
ios: 10.0,
opera: 36,
opera_mobile: 36,
safari: 10.0,
samsung: 5.0,
},
};
// Map of global variables and/or instance and static properties to the
// corresponding polyfill key and actual module to import
const polyfillMap = {
global: {
Proxy: { key: "proxy", module: "proxy-polyfill" },
fetch: { key: "fetch", module: "unfetch/polyfill" },
},
instance: {},
static: {},
};
// Create plugin using the same factory as for CoreJS
export default defineProvider(
({ createMetaResolver, debug, shouldInjectPolyfill }) => {
const resolvePolyfill = createMetaResolver(polyfillMap);
return {
name: "HA Custom",
polyfills: PolyfillSupport,
usageGlobal(meta, utils) {
const polyfill = resolvePolyfill(meta);
if (polyfill && shouldInjectPolyfill(polyfill.desc.key)) {
debug(polyfill.desc.key);
utils.injectGlobalImport(polyfill.desc.module);
}
},
};
}
);
+34 -18
View File
@@ -12,11 +12,7 @@ module.exports.sourceMapURL = () => {
};
// Files from NPM Packages that should not be imported
// eslint-disable-next-line unused-imports/no-unused-vars
module.exports.ignorePackages = ({ latestBuild }) => [
// Part of yaml.js and only used for !!js functions that we don't use
require.resolve("esprima"),
];
module.exports.ignorePackages = () => [];
// Files from NPM packages that we should replace with empty file
module.exports.emptyPackages = ({ latestBuild, isHassioBuild }) =>
@@ -35,8 +31,6 @@ module.exports.emptyPackages = ({ latestBuild, isHassioBuild }) =>
require.resolve(
path.resolve(paths.polymer_dir, "src/resources/compatibility.ts")
),
// This polyfill is loaded in workers to support ES5, filter it out.
latestBuild && require.resolve("proxy-polyfill/src/index.js"),
// Icons in supervisor conflict with icons in HA so we don't load.
isHassioBuild &&
require.resolve(
@@ -91,14 +85,12 @@ module.exports.babelOptions = ({ latestBuild, isProdBuild, isTestBuild }) => ({
setSpreadProperties: true,
},
browserslistEnv: latestBuild ? "modern" : "legacy",
// Must be unambiguous because some dependencies are CommonJS only
sourceType: "unambiguous",
presets: [
[
"@babel/preset-env",
{
useBuiltIns: latestBuild ? false : "entry",
corejs: latestBuild ? false : { version: "3.33", proposals: true },
useBuiltIns: latestBuild ? false : "usage",
corejs: latestBuild ? false : "3.33",
bugfixes: true,
shippedProposals: true,
},
@@ -116,21 +108,33 @@ module.exports.babelOptions = ({ latestBuild, isProdBuild, isTestBuild }) => ({
ignoreModuleNotFound: true,
},
],
[
path.resolve(
paths.polymer_dir,
"build-scripts/babel-plugins/custom-polyfill-plugin.js"
),
{ method: "usage-global" },
],
// Minify template literals for production
isProdBuild && [
"template-html-minifier",
{
modules: {
lit: [
"html",
{ name: "svg", encapsulation: "svg" },
{ name: "css", encapsulation: "style" },
],
"@polymer/polymer/lib/utils/html-tag": ["html"],
...Object.fromEntries(
["lit", "lit-element", "lit-html"].map((m) => [
m,
[
"html",
{ name: "svg", encapsulation: "svg" },
{ name: "css", encapsulation: "style" },
],
])
),
"@polymer/polymer/lib/utils/html-tag.js": ["html"],
},
strictCSS: true,
htmlMinifier: module.exports.htmlMinifierOptions,
failOnError: true, // we can turn this off in case of false positives
failOnError: false, // we can turn this off in case of false positives
},
],
// Import helpers and regenerator from runtime package
@@ -147,6 +151,18 @@ module.exports.babelOptions = ({ latestBuild, isProdBuild, isTestBuild }) => ({
/node_modules[\\/]webpack[\\/]buildin/,
],
sourceMaps: !isTestBuild,
overrides: [
{
// Use unambiguous for dependencies so that require() is correctly injected into CommonJS files
// Exclusions are needed in some cases where ES modules have no static imports or exports, such as polyfills
sourceType: "unambiguous",
include: /\/node_modules\//,
exclude: [
"element-internals-polyfill",
"@?lit(?:-labs|-element|-html)?",
].map((p) => new RegExp(`/node_modules/${p}/`)),
},
],
});
const nameSuffix = (latestBuild) => (latestBuild ? "-modern" : "-legacy");
+2 -2
View File
@@ -30,8 +30,8 @@ gulp.task(
env.useWDS()
? "wds-watch-app"
: env.useRollup()
? "rollup-watch-app"
: "webpack-watch-app"
? "rollup-watch-app"
: "webpack-watch-app"
)
);
@@ -161,6 +161,10 @@ gulp.task("fetch-lokalise", async function () {
})
);
})
.catch((err) => {
console.error(err);
throw err;
})
)
);
});
+5 -5
View File
@@ -51,8 +51,8 @@ const createWebpackConfig = ({
devtool: isTestBuild
? false
: isProdBuild
? "nosources-source-map"
: "eval-cheap-module-source-map",
? "nosources-source-map"
: "eval-cheap-module-source-map",
entry,
node: false,
module: {
@@ -191,11 +191,11 @@ const createWebpackConfig = ({
filename: ({ chunk }) =>
!isProdBuild || isStatsBuild || dontHash.has(chunk.name)
? "[name].js"
: "[name]-[contenthash].js",
: "[name].[contenthash].js",
chunkFilename:
isProdBuild && !isStatsBuild ? "[id]-[contenthash].js" : "[name].js",
isProdBuild && !isStatsBuild ? "[name].[contenthash].js" : "[name].js",
assetModuleFilename:
isProdBuild && !isStatsBuild ? "[id]-[contenthash][ext]" : "[id][ext]",
isProdBuild && !isStatsBuild ? "[id].[contenthash][ext]" : "[id][ext]",
crossOriginLoading: "use-credentials",
hashFunction: "xxhash64",
hashDigest: "base64url",
+50 -46
View File
@@ -3,7 +3,7 @@ import { mdiCast, mdiCastConnected } from "@mdi/js";
import "@polymer/paper-item/paper-icon-item";
import "@polymer/paper-listbox/paper-listbox";
import { Auth, Connection } from "home-assistant-js-websocket";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { CSSResultGroup, LitElement, TemplateResult, css, html } from "lit";
import { customElement, property, state } from "lit/decorators";
import { CastManager } from "../../../../src/cast/cast_manager";
import {
@@ -22,8 +22,9 @@ import "../../../../src/components/ha-svg-icon";
import {
getLegacyLovelaceCollection,
getLovelaceCollection,
LovelaceConfig,
} from "../../../../src/data/lovelace";
import { isStrategyDashboard } from "../../../../src/data/lovelace/config/types";
import { LovelaceViewConfig } from "../../../../src/data/lovelace/config/view";
import "../../../../src/layouts/hass-loading-screen";
import { generateDefaultViewConfig } from "../../../../src/panels/lovelace/common/generate-lovelace-config";
import "./hc-layout";
@@ -38,10 +39,10 @@ class HcCast extends LitElement {
@state() private askWrite = false;
@state() private lovelaceConfig?: LovelaceConfig | null;
@state() private lovelaceViews?: LovelaceViewConfig[] | null;
protected render(): TemplateResult {
if (this.lovelaceConfig === undefined) {
if (this.lovelaceViews === undefined) {
return html`<hass-loading-screen no-toolbar></hass-loading-screen>`;
}
@@ -72,43 +73,44 @@ class HcCast extends LitElement {
${error
? html` <div class="card-content">${error}</div> `
: !this.castManager.status
? html`
<p class="center-item">
<mwc-button raised @click=${this._handleLaunch}>
<ha-svg-icon .path=${mdiCast}></ha-svg-icon>
Start Casting
</mwc-button>
</p>
`
: html`
<div class="section-header">PICK A VIEW</div>
<paper-listbox
attr-for-selected="data-path"
.selected=${this.castManager.status.lovelacePath || ""}
>
${(this.lovelaceConfig
? this.lovelaceConfig.views
: [generateDefaultViewConfig({}, {}, {}, {}, () => "")]
).map(
(view, idx) => html`
<paper-icon-item
@click=${this._handlePickView}
data-path=${view.path || idx}
>
${view.icon
? html`
<ha-icon
.icon=${view.icon}
slot="item-icon"
></ha-icon>
`
: ""}
${view.title || view.path}
</paper-icon-item>
`
)}
</paper-listbox>
`}
? html`
<p class="center-item">
<mwc-button raised @click=${this._handleLaunch}>
<ha-svg-icon .path=${mdiCast}></ha-svg-icon>
Start Casting
</mwc-button>
</p>
`
: html`
<div class="section-header">PICK A VIEW</div>
<paper-listbox
attr-for-selected="data-path"
.selected=${this.castManager.status.lovelacePath || ""}
>
${(
this.lovelaceViews ?? [
generateDefaultViewConfig({}, {}, {}, {}, () => ""),
]
).map(
(view, idx) => html`
<paper-icon-item
@click=${this._handlePickView}
data-path=${view.path || idx}
>
${view.icon
? html`
<ha-icon
.icon=${view.icon}
slot="item-icon"
></ha-icon>
`
: ""}
${view.title || view.path}
</paper-icon-item>
`
)}
</paper-listbox>
`}
<div class="card-actions">
${this.castManager.status
? html`
@@ -136,11 +138,15 @@ class HcCast extends LitElement {
llColl.refresh().then(
() => {
llColl.subscribe((config) => {
this.lovelaceConfig = config;
if (isStrategyDashboard(config)) {
this.lovelaceViews = null;
} else {
this.lovelaceViews = config.views;
}
});
},
async () => {
this.lovelaceConfig = null;
this.lovelaceViews = null;
}
);
@@ -159,9 +165,7 @@ class HcCast extends LitElement {
toggleAttribute(
this,
"hide-icons",
this.lovelaceConfig
? !this.lovelaceConfig.views.some((view) => view.icon)
: true
this.lovelaceViews ? !this.lovelaceViews.some((view) => view.icon) : true
);
}
+18 -16
View File
@@ -1,6 +1,5 @@
import "@material/mwc-button";
import { mdiCastConnected, mdiCast } from "@mdi/js";
import "@polymer/paper-input/paper-input";
import {
Auth,
Connection,
@@ -24,6 +23,7 @@ import "../../../../src/components/ha-svg-icon";
import "../../../../src/layouts/hass-loading-screen";
import { registerServiceWorker } from "../../../../src/util/register-service-worker";
import "./hc-layout";
import "../../../../src/components/ha-textfield";
const seeFAQ = (qid) => html`
See <a href="./faq.html${qid ? `#${qid}` : ""}">the FAQ</a> for more
@@ -33,13 +33,13 @@ const translateErr = (err) =>
err === ERR_CANNOT_CONNECT
? "Unable to connect"
: err === ERR_HASS_HOST_REQUIRED
? "Please enter a Home Assistant URL."
: err === ERR_INVALID_HTTPS_TO_HTTP
? html`
Cannot connect to Home Assistant instances over "http://".
${seeFAQ("https")}
`
: `Unknown error (${err}).`;
? "Please enter a Home Assistant URL."
: err === ERR_INVALID_HTTPS_TO_HTTP
? html`
Cannot connect to Home Assistant instances over "http://".
${seeFAQ("https")}
`
: `Unknown error (${err}).`;
const INTRO = html`
<p>
@@ -116,13 +116,11 @@ export class HcConnect extends LitElement {
To get started, enter your Home Assistant URL and click authorize.
If you want a preview instead, click the show demo button.
</p>
<p>
<paper-input
label="Home Assistant URL"
placeholder="https://abcdefghijklmnop.ui.nabu.casa"
@keydown=${this._handleInputKeyDown}
></paper-input>
</p>
<ha-textfield
label="Home Assistant URL"
placeholder="https://abcdefghijklmnop.ui.nabu.casa"
@keydown=${this._handleInputKeyDown}
></ha-textfield>
${this.error ? html` <p class="error">${this.error}</p> ` : ""}
</div>
<div class="card-actions">
@@ -196,7 +194,7 @@ export class HcConnect extends LitElement {
}
private async _handleConnect() {
const inputEl = this.shadowRoot!.querySelector("paper-input")!;
const inputEl = this.shadowRoot!.querySelector("ha-textfield")!;
const value = inputEl.value || "";
this.error = undefined;
@@ -315,6 +313,10 @@ export class HcConnect extends LitElement {
.spacer {
flex: 1;
}
ha-textfield {
width: 100%;
}
`;
}
}
+2 -4
View File
@@ -1,7 +1,5 @@
import {
LovelaceCardConfig,
LovelaceConfig,
} from "../../../../src/data/lovelace";
import { LovelaceCardConfig } from "../../../../src/data/lovelace/config/card";
import { LovelaceConfig } from "../../../../src/data/lovelace/config/types";
import { castContext } from "../cast_context";
export const castDemoLovelace: () => LovelaceConfig = () => {
+1 -1
View File
@@ -1,7 +1,7 @@
import { html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { mockHistory } from "../../../../demo/src/stubs/history";
import { LovelaceConfig } from "../../../../src/data/lovelace";
import { LovelaceConfig } from "../../../../src/data/lovelace/config/types";
import {
MockHomeAssistant,
provideHass,
+3 -2
View File
@@ -1,7 +1,7 @@
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, query } from "lit/decorators";
import { fireEvent } from "../../../../src/common/dom/fire_event";
import { LovelaceConfig } from "../../../../src/data/lovelace";
import { LovelaceConfig } from "../../../../src/data/lovelace/config/types";
import { Lovelace } from "../../../../src/panels/lovelace/types";
import "../../../../src/panels/lovelace/views/hui-view";
import { HomeAssistant } from "../../../../src/types";
@@ -14,7 +14,8 @@ import "./hc-launch-screen";
class HcLovelace extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public lovelaceConfig!: LovelaceConfig;
@property({ attribute: false })
public lovelaceConfig!: LovelaceConfig;
@property() public viewPath?: string | number;
+29 -12
View File
@@ -21,18 +21,26 @@ import {
import { atLeastVersion } from "../../../../src/common/config/version";
import { isNavigationClick } from "../../../../src/common/dom/is-navigation-click";
import {
fetchResources,
getLegacyLovelaceCollection,
getLovelaceCollection,
} from "../../../../src/data/lovelace";
import {
isStrategyDashboard,
LegacyLovelaceConfig,
LovelaceConfig,
} from "../../../../src/data/lovelace";
LovelaceDashboardStrategyConfig,
} from "../../../../src/data/lovelace/config/types";
import { fetchResources } from "../../../../src/data/lovelace/resource";
import { loadLovelaceResources } from "../../../../src/panels/lovelace/common/load-resources";
import { HassElement } from "../../../../src/state/hass-element";
import { castContext } from "../cast_context";
import "./hc-launch-screen";
const DEFAULT_STRATEGY = "original-states";
const DEFAULT_CONFIG: LovelaceDashboardStrategyConfig = {
strategy: {
type: "original-states",
},
};
let resourcesLoaded = false;
@customElement("hc-main")
@@ -93,7 +101,7 @@ export class HcMain extends HassElement {
.lovelaceConfig=${this._lovelaceConfig}
.viewPath=${this._lovelacePath}
.urlPath=${this._urlPath}
@config-refresh=${this._generateLovelaceConfig}
@config-refresh=${this._generateDefaultLovelaceConfig}
></hc-lovelace>
`;
}
@@ -284,9 +292,20 @@ export class HcMain extends HassElement {
// configuration.
try {
await llColl.refresh();
this._unsubLovelace = llColl.subscribe((lovelaceConfig) =>
this._handleNewLovelaceConfig(lovelaceConfig)
);
this._unsubLovelace = llColl.subscribe(async (rawConfig) => {
if (isStrategyDashboard(rawConfig)) {
const { generateLovelaceDashboardStrategy } = await import(
"../../../../src/panels/lovelace/strategies/get-strategy"
);
const config = await generateLovelaceDashboardStrategy(
rawConfig.strategy,
this.hass!
);
this._handleNewLovelaceConfig(config);
} else {
this._handleNewLovelaceConfig(rawConfig);
}
});
} catch (err: any) {
if (
atLeastVersion(this.hass.connection.haVersion, 0, 107) &&
@@ -300,7 +319,7 @@ export class HcMain extends HassElement {
}
// Generate a Lovelace config.
this._unsubLovelace = () => undefined;
await this._generateLovelaceConfig();
await this._generateDefaultLovelaceConfig();
}
}
if (!resourcesLoaded) {
@@ -316,15 +335,13 @@ export class HcMain extends HassElement {
this._sendStatus();
}
private async _generateLovelaceConfig() {
private async _generateDefaultLovelaceConfig() {
const { generateLovelaceDashboardStrategy } = await import(
"../../../../src/panels/lovelace/strategies/get-strategy"
);
this._handleNewLovelaceConfig(
await generateLovelaceDashboardStrategy(
{
type: DEFAULT_STRATEGY,
},
DEFAULT_CONFIG.strategy,
this.hass!
)
);
+1 -1
View File
@@ -1,5 +1,5 @@
import { LocalizeFunc } from "../../../src/common/translations/localize";
import { LovelaceConfig } from "../../../src/data/lovelace";
import { LovelaceConfig } from "../../../src/data/lovelace/config/types";
import { Entity } from "../../../src/fake_data/entity";
export interface DemoConfig {
+5 -4
View File
@@ -4,7 +4,7 @@ import { customElement, property, state } from "lit/decorators";
import { until } from "lit/directives/until";
import "../../../src/components/ha-card";
import "../../../src/components/ha-circular-progress";
import { LovelaceCardConfig } from "../../../src/data/lovelace";
import { LovelaceCardConfig } from "../../../src/data/lovelace/config/card";
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
import { Lovelace, LovelaceCard } from "../../../src/panels/lovelace/types";
import {
@@ -39,7 +39,9 @@ export class HADemoCard extends LitElement implements LovelaceCard {
<div class="picker">
<div class="label">
${this._switching
? html`<ha-circular-progress active></ha-circular-progress>`
? html`<ha-circular-progress
indeterminate
></ha-circular-progress>`
: until(
selectedDemoConfig.then(
(conf) => html`
@@ -48,8 +50,7 @@ export class HADemoCard extends LitElement implements LovelaceCard {
<a target="_blank" href=${conf.authorUrl}>
${this.hass.localize(
"ui.panel.page-demo.cards.demo.demo_by",
"name",
conf.authorName
{ name: conf.authorName }
)}
</a>
</small>
+3 -13
View File
@@ -74,19 +74,9 @@
<body>
<div id="ha-launch-screen">
<div class="ha-launch-screen-spacer"></div>
<svg
viewBox="0 0 240 240"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M240 224.762C240 233.012 233.25 239.762 225 239.762H15C6.75 239.762 0 233.012 0 224.762V134.762C0 126.512 4.77 114.993 10.61 109.153L109.39 10.3725C115.22 4.5425 124.77 4.5425 130.6 10.3725L229.39 109.162C235.22 114.992 240 126.522 240 134.772V224.772V224.762Z"
fill="#F2F4F9"
/>
<path
d="M229.39 109.153L130.61 10.3725C124.78 4.5425 115.23 4.5425 109.4 10.3725L10.61 109.153C4.78 114.983 0 126.512 0 134.762V224.762C0 233.012 6.75 239.762 15 239.762H107.27L66.64 199.132C64.55 199.852 62.32 200.262 60 200.262C48.7 200.262 39.5 191.062 39.5 179.762C39.5 168.462 48.7 159.262 60 159.262C71.3 159.262 80.5 168.462 80.5 179.762C80.5 182.092 80.09 184.322 79.37 186.412L111 218.042V102.162C104.2 98.8225 99.5 91.8425 99.5 83.7725C99.5 72.4725 108.7 63.2725 120 63.2725C131.3 63.2725 140.5 72.4725 140.5 83.7725C140.5 91.8425 135.8 98.8225 129 102.162V183.432L160.46 151.972C159.84 150.012 159.5 147.932 159.5 145.772C159.5 134.472 168.7 125.272 180 125.272C191.3 125.272 200.5 134.472 200.5 145.772C200.5 157.072 191.3 166.272 180 166.272C177.5 166.272 175.12 165.802 172.91 164.982L129 208.892V239.772H225C233.25 239.772 240 233.022 240 224.772V134.772C240 126.522 235.23 115.002 229.39 109.162V109.153Z"
fill="#18BCF2"
/>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 240">
<path fill="#18BCF2" d="M240 224.762a15 15 0 0 1-15 15H15a15 15 0 0 1-15-15v-90c0-8.25 4.77-19.769 10.61-25.609l98.78-98.7805c5.83-5.83 15.38-5.83 21.21 0l98.79 98.7895c5.83 5.83 10.61 17.36 10.61 25.61v90-.01Z"/>
<path fill="#F2F4F9" d="m107.27 239.762-40.63-40.63c-2.09.72-4.32 1.13-6.64 1.13-11.3 0-20.5-9.2-20.5-20.5s9.2-20.5 20.5-20.5 20.5 9.2 20.5 20.5c0 2.33-.41 4.56-1.13 6.65l31.63 31.63v-115.88c-6.8-3.3395-11.5-10.3195-11.5-18.3895 0-11.3 9.2-20.5 20.5-20.5s20.5 9.2 20.5 20.5c0 8.07-4.7 15.05-11.5 18.3895v81.27l31.46-31.46c-.62-1.96-.96-4.04-.96-6.2 0-11.3 9.2-20.5 20.5-20.5s20.5 9.2 20.5 20.5-9.2 20.5-20.5 20.5c-2.5 0-4.88-.47-7.09-1.29L129 208.892v30.88z"/>
</svg>
<div id="ha-launch-screen-info-box" class="ha-launch-screen-spacer"></div>
</div>
+4 -4
View File
@@ -43,8 +43,8 @@ const generateMeanStatistics = (
period === "day"
? addDays(currentDate, 1)
: period === "month"
? addMonths(currentDate, 1)
: addHours(currentDate, 1);
? addMonths(currentDate, 1)
: addHours(currentDate, 1);
}
return statistics;
};
@@ -80,8 +80,8 @@ const generateSumStatistics = (
period === "day"
? addDays(currentDate, 1)
: period === "month"
? addMonths(currentDate, 1)
: addHours(currentDate, 1);
? addMonths(currentDate, 1)
: addHours(currentDate, 1);
}
return statistics;
};
+1 -1
View File
@@ -23,7 +23,7 @@ class DemoMoreInfo extends LitElement {
<state-card-content
.stateObj=${state}
.hass=${this.hass}
in-dialog
inDialog
></state-card-content>
<more-info-content
+65 -27
View File
@@ -1,8 +1,10 @@
import { css, html, LitElement, TemplateResult } from "lit";
import { css, html, LitElement, TemplateResult, nothing } from "lit";
import { customElement } from "lit/decorators";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-chip";
import "../../../../src/components/ha-chip-set";
import "../../../../src/components/chips/ha-chip-set";
import "../../../../src/components/chips/ha-assist-chip";
import "../../../../src/components/chips/ha-input-chip";
import "../../../../src/components/chips/ha-filter-chip";
import "../../../../src/components/ha-svg-icon";
import { mdiHomeAssistant } from "../../../../src/resources/home-assistant-logo-svg";
@@ -10,10 +12,6 @@ const chips: {
icon?: string;
content?: string;
}[] = [
{},
{
icon: mdiHomeAssistant,
},
{
content: "Content",
},
@@ -29,31 +27,73 @@ export class DemoHaChips extends LitElement {
return html`
<ha-card header="ha-chip demo">
<div class="card-content">
${chips.map(
(chip) => html`
<ha-chip .hasIcon=${chip.icon !== undefined}>
${chip.icon
? html`<ha-svg-icon slot="icon" .path=${chip.icon}>
</ha-svg-icon>`
: ""}
${chip.content}
</ha-chip>
`
)}
</div>
</ha-card>
<ha-card header="ha-chip-set demo">
<div class="card-content">
<p>Action chip</p>
<ha-chip-set>
${chips.map(
(chip) => html`
<ha-chip .hasIcon=${chip.icon !== undefined}>
<ha-assist-chip .label=${chip.content}>
${chip.icon
? html`<ha-svg-icon slot="icon" .path=${chip.icon}>
</ha-svg-icon>`
: nothing}
</ha-assist-chip>
`
)}
${chips.map(
(chip) => html`
<ha-assist-chip .label=${chip.content} selected>
${chip.icon
? html`<ha-svg-icon slot="icon" .path=${chip.icon}>
</ha-svg-icon>`
: nothing}
</ha-assist-chip>
`
)}
</ha-chip-set>
<p>Filter chip</p>
<ha-chip-set>
${chips.map(
(chip) => html`
<ha-filter-chip .label=${chip.content}>
${chip.icon
? html`<ha-svg-icon slot="icon" .path=${chip.icon}>
</ha-svg-icon>`
: nothing}
</ha-filter-chip>
`
)}
${chips.map(
(chip) => html`
<ha-filter-chip .label=${chip.content} selected>
${chip.icon
? html`<ha-svg-icon slot="icon" .path=${chip.icon}>
</ha-svg-icon>`
: nothing}
</ha-filter-chip>
`
)}
</ha-chip-set>
<p>Input chip</p>
<ha-chip-set>
${chips.map(
(chip) => html`
<ha-input-chip .label=${chip.content}>
${chip.icon
? html`<ha-svg-icon slot="icon" .path=${chip.icon}>
</ha-svg-icon>`
: ""}
${chip.content}
</ha-chip>
</ha-input-chip>
`
)}
${chips.map(
(chip) => html`
<ha-input-chip .label=${chip.content} selected>
${chip.icon
? html`<ha-svg-icon slot="icon" .path=${chip.icon}>
</ha-svg-icon>`
: nothing}
</ha-input-chip>
`
)}
</ha-chip-set>
@@ -68,12 +108,10 @@ export class DemoHaChips extends LitElement {
max-width: 600px;
margin: 24px auto;
}
ha-chip {
margin-bottom: 4px;
}
.card-content {
display: flex;
flex-direction: column;
align-items: flex-start;
}
`;
}
@@ -0,0 +1,4 @@
---
title: Circular Progress
subtitle: Can be used to indicate an ongoing task.
---
@@ -0,0 +1,64 @@
import { html, css, LitElement, TemplateResult } from "lit";
import { customElement, property } from "lit/decorators";
import "../../../../src/components/ha-bar";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-circular-progress";
import "@material/web/progress/circular-progress";
import { HomeAssistant } from "../../../../src/types";
@customElement("demo-components-ha-circular-progress")
export class DemoHaCircularProgress extends LitElement {
@property({ attribute: false }) hass!: HomeAssistant;
protected render(): TemplateResult {
return html`<ha-card header="Basic circular progress">
<div class="card-content">
<ha-circular-progress indeterminate></ha-circular-progress></div
></ha-card>
<ha-card header="Different circular progress sizes">
<div class="card-content">
<ha-circular-progress
indeterminate
size="tiny"
></ha-circular-progress>
<ha-circular-progress
indeterminate
size="small"
></ha-circular-progress>
<ha-circular-progress
indeterminate
size="medium"
></ha-circular-progress>
<ha-circular-progress
indeterminate
size="large"
></ha-circular-progress></div
></ha-card>
<ha-card header="Circular progress with an aria-label">
<div class="card-content">
<ha-circular-progress
indeterminate
aria-label="Doing something..."
></ha-circular-progress>
<ha-circular-progress
indeterminate
.ariaLabel=${"Doing something..."}
></ha-circular-progress></div
></ha-card>`;
}
static get styles() {
return css`
ha-card {
max-width: 600px;
margin: 24px auto;
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"demo-components-ha-circular-progress": DemoHaCircularProgress;
}
}
@@ -11,6 +11,7 @@ const buttons: {
min?: number;
max?: number;
step?: number;
unit?: string;
class?: string;
}[] = [
{
@@ -29,6 +30,11 @@ const buttons: {
label: "Custom",
class: "custom",
},
{
id: "unit",
label: "With unit",
unit: "m",
},
];
@customElement("demo-components-ha-control-number-buttons")
@@ -50,6 +56,7 @@ export class DemoHarControlNumberButtons extends LitElement {
<pre>Config: ${JSON.stringify(config)}</pre>
<ha-control-number-buttons
.value=${this.value}
.unit=${config.unit}
.min=${config.min}
.max=${config.max}
.step=${config.step}
@@ -9,6 +9,7 @@ const sliders: {
id: string;
label: string;
mode?: "start" | "end" | "cursor";
unit?: string;
class?: string;
}[] = [
{
@@ -31,18 +32,21 @@ const sliders: {
label: "Slider (start mode) and custom style",
mode: "start",
class: "custom",
unit: "mm",
},
{
id: "slider-end-custom",
label: "Slider (end mode) and custom style",
mode: "end",
class: "custom",
unit: "mm",
},
{
id: "slider-cursor-custom",
label: "Slider (cursor mode) and custom style",
mode: "cursor",
class: "custom",
unit: "mm",
},
];
@@ -93,6 +97,7 @@ export class DemoHaBarSlider extends LitElement {
@value-changed=${this.handleValueChanged}
@slider-moved=${this.handleSliderMoved}
aria-labelledby=${id}
.unit=${config.unit}
>
</ha-control-slider>
</div>
@@ -114,6 +119,7 @@ export class DemoHaBarSlider extends LitElement {
@value-changed=${this.handleValueChanged}
@slider-moved=${this.handleSliderMoved}
aria-label=${label}
.unit=${config.unit}
>
</ha-control-slider>
`;
@@ -5,9 +5,22 @@ subtitle: Dialogs provide important prompts in a user flow.
# Material Design 3
Our dialogs are based on the latest version of Material Design. Specs and guidelines can be found on its [website](https://m3.material.io/components/dialogs/overview).
Our dialogs are based on the latest version of Material Design. Please note that we have made some well-considered adjustments to these guideliness. Specs and guidelines can be found on its [website](https://m3.material.io/components/dialogs/overview).
# Highlighted guidelines
# Guidelines
## Design
- Dialogs have a max width of 560px. Alert and confirmation dialogs got a fixed width of 320px. If you need more width, consider a dedicated page instead.
- The close X-icon is on the top left, on all screen sizes. Except for alert and confirmation dialogs, they only have buttons and no X-icon. This is different compared to the Material guideliness.
- Dialogs can't be closed with ESC or clicked outside of the dialog when there is a form that the user needs to fill out. Instead it will animate "no" by a little shake.
- Extra icon buttons are on the top right, for example help, settings and expand dialog. More than 2 icon buttons, they will be in an overflow menu.
- The submit button is grouped with a cancel button at the bottom right, on all screen sizes. Fullscreen mobile dialogs have them sticky at the bottom.
- Keep the labels short, for example `Save`, `Delete`, `Enable`.
- Dialog with actions must always have a discard button. On desktop a `Cancel` button and X-icon, on mobile only the X-icon.
- Destructive actions should be a red warning button.
- Alert or confirmation dialogs only have buttons and no X-icon.
- Try to avoid three buttons in one dialog. Especially when you leave the dialog task unfinished.
## Content
@@ -17,14 +30,6 @@ Our dialogs are based on the latest version of Material Design. Specs and guidel
- If users become unsure, they read the description. Make sure this explains what will happen.
- Strive for minimalism.
## Buttons and X-icon
- Keep the labels short, for example `Save`, `Delete`, `Enable`.
- Dialog with actions must always have a discard button. On desktop a `Cancel` button and X-icon, on mobile only the X-icon.
- Destructive actions should be a red warning button.
- Alert or confirmation dialogs only have buttons and no X-icon.
- Try to avoid three buttons in one dialog. Especially when you leave the dialog task unfinished.
## Example
### Confirmation dialog
+1 -1
View File
@@ -18,7 +18,7 @@ The Home Assistant interface is based on Material Design. It's a design system c
We want to make it as easy for designers to contribute as it is for developers. Theres a lot a designer can contribute to:
- Meet us at <a href="https://discord.gg/BPBc8rZ9" rel="noopener noreferrer" target="_blank">devs_ux Discord</a>. Feel free to share your designs, user test or strategic ideas.
- Meet us at <a href="https://www.home-assistant.io/join-chat" rel="noopener noreferrer" target="_blank">devs_ux Discord</a>. Feel free to share your designs, user test or strategic ideas.
- Start designing with our <a href="https://www.figma.com/community/file/967153512097289521/Home-Assistant-DesignKit" rel="noopener noreferrer" target="_blank">Figma DesignKit</a>.
- Find the latest UX <a href="https://github.com/home-assistant/frontend/discussions?discussions_q=label%3Aux" rel="noopener noreferrer" target="_blank">discussions</a> and <a href="https://github.com/home-assistant/frontend/labels/ux" rel="noopener noreferrer" target="_blank">issues</a> on GitHub. Everyone can start a new issue or discussion!
-1
View File
@@ -10,7 +10,6 @@ import { computeStateDisplay } from "../../../../src/common/entity/compute_state
import "../../../../src/components/data-table/ha-data-table";
import type { DataTableColumnContainer } from "../../../../src/components/data-table/ha-data-table";
import "../../../../src/components/entity/state-badge";
import "../../../../src/components/ha-chip";
import { provideHass } from "../../../../src/fake_data/provide_hass";
import { HomeAssistant } from "../../../../src/types";
+1 -1
View File
@@ -2,7 +2,7 @@ import "@material/mwc-button";
import { css, html, LitElement, TemplateResult } from "lit";
import { customElement } from "lit/decorators";
import "../../../../src/components/ha-card";
import { ActionHandlerEvent } from "../../../../src/data/lovelace";
import { ActionHandlerEvent } from "../../../../src/data/lovelace/action_handler";
import { actionHandler } from "../../../../src/panels/lovelace/common/directives/action-handler-directive";
@customElement("demo-misc-util-long-press")
@@ -0,0 +1,3 @@
---
title: Input Text
---
+46
View File
@@ -0,0 +1,46 @@
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
import { customElement, property, query } from "lit/decorators";
import "../../../../src/components/ha-card";
import "../../../../src/dialogs/more-info/more-info-content";
import { getEntity } from "../../../../src/fake_data/entity";
import {
MockHomeAssistant,
provideHass,
} from "../../../../src/fake_data/provide_hass";
import "../../components/demo-more-infos";
const ENTITIES = [
getEntity("input_text", "text", "Inspiration", {
friendly_name: "Text",
mode: "text",
}),
];
@customElement("demo-more-info-input-text")
class DemoMoreInfoInputText extends LitElement {
@property() public hass!: MockHomeAssistant;
@query("demo-more-infos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
return html`
<demo-more-infos
.hass=${this.hass}
.entities=${ENTITIES.map((ent) => ent.entityId)}
></demo-more-infos>
`;
}
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
const hass = provideHass(this._demoRoot);
hass.updateTranslations(null, "en");
hass.addEntities(ENTITIES);
}
}
declare global {
interface HTMLElementTagNameMap {
"demo-more-info-input-text": DemoMoreInfoInputText;
}
}
@@ -0,0 +1,3 @@
---
title: Lock
---
+49
View File
@@ -0,0 +1,49 @@
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
import { customElement, property, query } from "lit/decorators";
import "../../../../src/components/ha-card";
import "../../../../src/dialogs/more-info/more-info-content";
import { getEntity } from "../../../../src/fake_data/entity";
import {
MockHomeAssistant,
provideHass,
} from "../../../../src/fake_data/provide_hass";
import "../../components/demo-more-infos";
const ENTITIES = [
getEntity("lock", "lock", "locked", {
friendly_name: "Lock",
device_class: "lock",
}),
getEntity("lock", "unavailable", "unavailable", {
friendly_name: "Unavailable lock",
}),
];
@customElement("demo-more-info-lock")
class DemoMoreInfoLock extends LitElement {
@property() public hass!: MockHomeAssistant;
@query("demo-more-infos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
return html`
<demo-more-infos
.hass=${this.hass}
.entities=${ENTITIES.map((ent) => ent.entityId)}
></demo-more-infos>
`;
}
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
const hass = provideHass(this._demoRoot);
hass.updateTranslations(null, "en");
hass.addEntities(ENTITIES);
}
}
declare global {
interface HTMLElementTagNameMap {
"demo-more-info-lock": DemoMoreInfoLock;
}
}
@@ -0,0 +1,3 @@
---
title: Media Player
---
@@ -0,0 +1,41 @@
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
import { customElement, property, query } from "lit/decorators";
import "../../../../src/components/ha-card";
import "../../../../src/dialogs/more-info/more-info-content";
import {
MockHomeAssistant,
provideHass,
} from "../../../../src/fake_data/provide_hass";
import "../../components/demo-more-infos";
import { createMediaPlayerEntities } from "../../data/media_players";
const ENTITIES = createMediaPlayerEntities();
@customElement("demo-more-info-media-player")
class DemoMoreInfoMediaPlayer extends LitElement {
@property() public hass!: MockHomeAssistant;
@query("demo-more-infos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
return html`
<demo-more-infos
.hass=${this.hass}
.entities=${ENTITIES.map((ent) => ent.entityId)}
></demo-more-infos>
`;
}
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
const hass = provideHass(this._demoRoot);
hass.updateTranslations(null, "en");
hass.addEntities(ENTITIES);
}
}
declare global {
interface HTMLElementTagNameMap {
"demo-more-info-media-player": DemoMoreInfoMediaPlayer;
}
}
@@ -0,0 +1,3 @@
---
title: Number
---
+78
View File
@@ -0,0 +1,78 @@
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
import { customElement, property, query } from "lit/decorators";
import "../../../../src/components/ha-card";
import "../../../../src/dialogs/more-info/more-info-content";
import { getEntity } from "../../../../src/fake_data/entity";
import {
MockHomeAssistant,
provideHass,
} from "../../../../src/fake_data/provide_hass";
import "../../components/demo-more-infos";
const ENTITIES = [
getEntity("number", "box1", 0, {
friendly_name: "Box1",
min: 0,
max: 100,
step: 1,
initial: 0,
mode: "box",
unit_of_measurement: "items",
}),
getEntity("number", "slider1", 0, {
friendly_name: "Slider1",
min: 0,
max: 100,
step: 1,
initial: 0,
mode: "slider",
unit_of_measurement: "items",
}),
getEntity("number", "auto1", 0, {
friendly_name: "Auto1",
min: 0,
max: 1000,
step: 1,
initial: 0,
mode: "auto",
unit_of_measurement: "items",
}),
getEntity("number", "auto2", 0, {
friendly_name: "Auto2",
min: 0,
max: 100,
step: 1,
initial: 0,
mode: "auto",
unit_of_measurement: "items",
}),
];
@customElement("demo-more-info-number")
class DemoMoreInfoNumber extends LitElement {
@property() public hass!: MockHomeAssistant;
@query("demo-more-infos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
return html`
<demo-more-infos
.hass=${this.hass}
.entities=${ENTITIES.map((ent) => ent.entityId)}
></demo-more-infos>
`;
}
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
const hass = provideHass(this._demoRoot);
hass.updateTranslations(null, "en");
hass.addEntities(ENTITIES);
}
}
declare global {
interface HTMLElementTagNameMap {
"demo-more-info-number": DemoMoreInfoNumber;
}
}
@@ -0,0 +1,3 @@
---
title: Scene
---
+49
View File
@@ -0,0 +1,49 @@
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
import { customElement, property, query } from "lit/decorators";
import "../../../../src/components/ha-card";
import "../../../../src/dialogs/more-info/more-info-content";
import { getEntity } from "../../../../src/fake_data/entity";
import {
MockHomeAssistant,
provideHass,
} from "../../../../src/fake_data/provide_hass";
import "../../components/demo-more-infos";
const ENTITIES = [
getEntity("scene", "romantic_lights", "scening", {
entity_id: ["light.bed_light", "light.ceiling_lights"],
friendly_name: "Romantic Scene",
}),
getEntity("scene", "unavailable", "unavailable", {
friendly_name: "Romantic Scene",
}),
];
@customElement("demo-more-info-scene")
class DemoMoreInfoScene extends LitElement {
@property() public hass!: MockHomeAssistant;
@query("demo-more-infos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
return html`
<demo-more-infos
.hass=${this.hass}
.entities=${ENTITIES.map((ent) => ent.entityId)}
></demo-more-infos>
`;
}
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
const hass = provideHass(this._demoRoot);
hass.updateTranslations(null, "en");
hass.addEntities(ENTITIES);
}
}
declare global {
interface HTMLElementTagNameMap {
"demo-more-info-scene": DemoMoreInfoScene;
}
}
@@ -0,0 +1,3 @@
---
title: Timer
---
+46
View File
@@ -0,0 +1,46 @@
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
import { customElement, property, query } from "lit/decorators";
import "../../../../src/components/ha-card";
import "../../../../src/dialogs/more-info/more-info-content";
import { getEntity } from "../../../../src/fake_data/entity";
import {
MockHomeAssistant,
provideHass,
} from "../../../../src/fake_data/provide_hass";
import "../../components/demo-more-infos";
const ENTITIES = [
getEntity("timer", "timer", "idle", {
friendly_name: "Timer",
duration: "0:05:00",
}),
];
@customElement("demo-more-info-timer")
class DemoMoreInfoTimer extends LitElement {
@property() public hass!: MockHomeAssistant;
@query("demo-more-infos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
return html`
<demo-more-infos
.hass=${this.hass}
.entities=${ENTITIES.map((ent) => ent.entityId)}
></demo-more-infos>
`;
}
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
const hass = provideHass(this._demoRoot);
hass.updateTranslations(null, "en");
hass.addEntities(ENTITIES);
}
}
declare global {
interface HTMLElementTagNameMap {
"demo-more-info-timer": DemoMoreInfoTimer;
}
}
@@ -0,0 +1,3 @@
---
title: Vacuum
---
+50
View File
@@ -0,0 +1,50 @@
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
import { customElement, property, query } from "lit/decorators";
import "../../../../src/components/ha-card";
import "../../../../src/dialogs/more-info/more-info-content";
import { getEntity } from "../../../../src/fake_data/entity";
import {
MockHomeAssistant,
provideHass,
} from "../../../../src/fake_data/provide_hass";
import "../../components/demo-more-infos";
import { VacuumEntityFeature } from "../../../../src/data/vacuum";
const ENTITIES = [
getEntity("vacuum", "first_floor_vacuum", "docked", {
friendly_name: "First floor vacuum",
supported_features:
VacuumEntityFeature.START +
VacuumEntityFeature.STOP +
VacuumEntityFeature.RETURN_HOME,
}),
];
@customElement("demo-more-info-vacuum")
class DemoMoreInfoVacuum extends LitElement {
@property() public hass!: MockHomeAssistant;
@query("demo-more-infos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
return html`
<demo-more-infos
.hass=${this.hass}
.entities=${ENTITIES.map((ent) => ent.entityId)}
></demo-more-infos>
`;
}
protected firstUpdated(changedProperties: PropertyValues) {
super.firstUpdated(changedProperties);
const hass = provideHass(this._demoRoot);
hass.updateTranslations(null, "en");
hass.addEntities(ENTITIES);
}
}
declare global {
interface HTMLElementTagNameMap {
"demo-more-info-vacuum": DemoMoreInfoVacuum;
}
}
@@ -49,11 +49,9 @@ export class HassioAddonRepositoryEl extends LitElement {
return html`
<div class="content">
<p class="description">
${this.supervisor.localize(
"store.no_results_found",
"repository",
repo.name
)}
${this.supervisor.localize("store.no_results_found", {
repository: repo.name,
})}
</p>
</div>
`;
@@ -86,15 +84,15 @@ export class HassioAddonRepositoryEl extends LitElement {
)
: this.supervisor.localize("addon.state.installed")
: addon.available
? this.supervisor.localize("addon.state.not_installed")
: this.supervisor.localize("addon.state.not_available")}
? this.supervisor.localize("addon.state.not_installed")
: this.supervisor.localize("addon.state.not_available")}
.iconClass=${addon.installed
? addon.update_available
? "update"
: "installed"
: !addon.available
? "not_available"
: ""}
? "not_available"
: ""}
.iconImage=${atLeastVersion(
this.hass.config.version,
0,
@@ -108,8 +106,8 @@ export class HassioAddonRepositoryEl extends LitElement {
? "update"
: "installed"
: !addon.available
? "unavailable"
: ""}
? "unavailable"
: ""}
></hassio-card-content>
</div>
</ha-card>
@@ -20,7 +20,7 @@ class HassioAddonConfigDashboard extends LitElement {
protected render(): TemplateResult {
if (!this.addon) {
return html`<ha-circular-progress active></ha-circular-progress>`;
return html`<ha-circular-progress indeterminate></ha-circular-progress>`;
}
const hasConfiguration =
(this.addon.options && Object.keys(this.addon.options).length) ||
@@ -104,50 +104,50 @@ class HassioAddonConfig extends LitElement {
selector: { select: { options: entry.options } },
}
: entry.type === "string"
? entry.multiple
? {
name: entry.name,
required: entry.required,
selector: {
select: { options: [], multiple: true, custom_value: true },
},
}
: {
name: entry.name,
required: entry.required,
selector: {
text: {
type:
entry.format || MASKED_FIELDS.includes(entry.name)
? "password"
: "text",
? entry.multiple
? {
name: entry.name,
required: entry.required,
selector: {
select: { options: [], multiple: true, custom_value: true },
},
},
}
: entry.type === "boolean"
? {
name: entry.name,
required: entry.required,
selector: { boolean: {} },
}
: entry.type === "schema"
? {
name: entry.name,
required: entry.required,
selector: { object: {} },
}
: entry.type === "float" || entry.type === "integer"
? {
name: entry.name,
required: entry.required,
selector: {
number: {
mode: "box",
step: entry.type === "float" ? "any" : undefined,
},
},
}
: entry
}
: {
name: entry.name,
required: entry.required,
selector: {
text: {
type:
entry.format || MASKED_FIELDS.includes(entry.name)
? "password"
: "text",
},
},
}
: entry.type === "boolean"
? {
name: entry.name,
required: entry.required,
selector: { boolean: {} },
}
: entry.type === "schema"
? {
name: entry.name,
required: entry.required,
selector: { object: {} },
}
: entry.type === "float" || entry.type === "integer"
? {
name: entry.name,
required: entry.required,
selector: {
number: {
mode: "box",
step: entry.type === "float" ? "any" : undefined,
},
},
}
: entry
)
);
@@ -340,11 +340,9 @@ class HassioAddonConfig extends LitElement {
};
fireEvent(this, "hass-api-called", eventdata);
} catch (err: any) {
this._error = this.supervisor.localize(
"addon.failed_to_reset",
"error",
extractApiErrorMessage(err)
);
this._error = this.supervisor.localize("addon.failed_to_reset", {
error: extractApiErrorMessage(err),
});
}
button.progress = false;
}
@@ -381,11 +379,9 @@ class HassioAddonConfig extends LitElement {
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
}
} catch (err: any) {
this._error = this.supervisor.localize(
"addon.failed_to_save",
"error",
extractApiErrorMessage(err)
);
this._error = this.supervisor.localize("addon.failed_to_save", {
error: extractApiErrorMessage(err),
});
eventdata.success = false;
}
button.progress = false;
@@ -180,11 +180,9 @@ class HassioAddonNetwork extends LitElement {
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
}
} catch (err: any) {
this._error = this.supervisor.localize(
"addon.failed_to_reset",
"error",
extractApiErrorMessage(err)
);
this._error = this.supervisor.localize("addon.failed_to_reset", {
error: extractApiErrorMessage(err),
});
button.actionError();
}
}
@@ -220,11 +218,9 @@ class HassioAddonNetwork extends LitElement {
await suggestAddonRestart(this, this.hass, this.supervisor, this.addon);
}
} catch (err: any) {
this._error = this.supervisor.localize(
"addon.failed_to_save",
"error",
extractApiErrorMessage(err)
);
this._error = this.supervisor.localize("addon.failed_to_save", {
error: extractApiErrorMessage(err),
});
button.actionError();
}
}
@@ -34,7 +34,7 @@ class HassioAddonDocumentationDashboard extends LitElement {
protected render(): TemplateResult {
if (!this.addon) {
return html`<ha-circular-progress active></ha-circular-progress>`;
return html`<ha-circular-progress indeterminate></ha-circular-progress>`;
}
return html`
<div class="content">
@@ -85,8 +85,7 @@ class HassioAddonDocumentationDashboard extends LitElement {
} catch (err: any) {
this._error = this.supervisor.localize(
"addon.documentation.get_documentation",
"error",
extractApiErrorMessage(err)
{ error: extractApiErrorMessage(err) }
);
}
}
@@ -22,7 +22,7 @@ class HassioAddonInfoDashboard extends LitElement {
protected render(): TemplateResult {
if (!this.addon) {
return html`<ha-circular-progress active></ha-circular-progress>`;
return html`<ha-circular-progress indeterminate></ha-circular-progress>`;
}
return html`
+181 -132
View File
@@ -31,8 +31,8 @@ import { navigate } from "../../../../src/common/navigate";
import "../../../../src/components/buttons/ha-progress-button";
import "../../../../src/components/ha-alert";
import "../../../../src/components/ha-card";
import "../../../../src/components/ha-chip";
import "../../../../src/components/ha-chip-set";
import "../../../../src/components/chips/ha-chip-set";
import "../../../../src/components/chips/ha-assist-chip";
import "../../../../src/components/ha-markdown";
import "../../../../src/components/ha-settings-row";
import "../../../../src/components/ha-svg-icon";
@@ -78,6 +78,7 @@ import { showHassioMarkdownDialog } from "../../dialogs/markdown/show-dialog-has
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";
const STAGE_ICON = {
stable: mdiCheckCircle,
@@ -234,28 +235,32 @@ class HassioAddonInfo extends LitElement {
<ha-chip-set class="capabilities">
${this.addon.stage !== "stable"
? html` <ha-chip
hasIcon
class=${classMap({
yellow: this.addon.stage === "experimental",
red: this.addon.stage === "deprecated",
})}
@click=${this._showMoreInfo}
id="stage"
>
<ha-svg-icon
slot="icon"
.path=${STAGE_ICON[this.addon.stage]}
? html`
<ha-assist-chip
filled
class=${classMap({
yellow: this.addon.stage === "experimental",
red: this.addon.stage === "deprecated",
})}
@click=${this._showMoreInfo}
id="stage"
.label=${capitalizeFirstLetter(
this.supervisor.localize(
`addon.dashboard.capability.stages.${this.addon.stage}`
)
)}
>
</ha-svg-icon>
${this.supervisor.localize(
`addon.dashboard.capability.stages.${this.addon.stage}`
)}
</ha-chip>`
<ha-svg-icon
slot="icon"
.path=${STAGE_ICON[this.addon.stage]}
>
</ha-svg-icon>
</ha-assist-chip>
`
: ""}
<ha-chip
hasIcon
<ha-assist-chip
filled
class=${classMap({
green: Number(this.addon.rating) >= 6,
yellow: [3, 4, 5].includes(Number(this.addon.rating)),
@@ -263,151 +268,197 @@ class HassioAddonInfo extends LitElement {
})}
@click=${this._showMoreInfo}
id="rating"
.label=${capitalizeFirstLetter(
this.supervisor.localize(
"addon.dashboard.capability.label.rating"
)
)}
>
<ha-svg-icon slot="icon" .path=${RATING_ICON[this.addon.rating]}>
</ha-svg-icon>
${this.supervisor.localize(
"addon.dashboard.capability.label.rating"
)}
</ha-chip>
</ha-assist-chip>
${this.addon.host_network
? html`
<ha-chip
hasIcon
<ha-assist-chip
filled
@click=${this._showMoreInfo}
id="host_network"
.label=${capitalizeFirstLetter(
this.supervisor.localize(
"addon.dashboard.capability.label.host"
)
)}
>
<ha-svg-icon slot="icon" .path=${mdiNetwork}> </ha-svg-icon>
${this.supervisor.localize(
"addon.dashboard.capability.label.host"
)}
</ha-chip>
</ha-assist-chip>
`
: ""}
${this.addon.full_access
? html`
<ha-chip
hasIcon
<ha-assist-chip
filled
@click=${this._showMoreInfo}
id="full_access"
.label=${capitalizeFirstLetter(
this.supervisor.localize(
"addon.dashboard.capability.label.hardware"
)
)}
>
<ha-svg-icon slot="icon" .path=${mdiChip}></ha-svg-icon>
${this.supervisor.localize(
"addon.dashboard.capability.label.hardware"
)}
</ha-chip>
</ha-assist-chip>
`
: ""}
${this.addon.homeassistant_api
? html`
<ha-chip
hasIcon
<ha-assist-chip
filled
@click=${this._showMoreInfo}
id="homeassistant_api"
.label=${capitalizeFirstLetter(
this.supervisor.localize(
"addon.dashboard.capability.label.core"
)
)}
>
<ha-svg-icon
slot="icon"
.path=${mdiHomeAssistant}
></ha-svg-icon>
${this.supervisor.localize(
"addon.dashboard.capability.label.core"
)}
</ha-chip>
</ha-assist-chip>
`
: ""}
${this._computeHassioApi
? html`
<ha-chip hasIcon @click=${this._showMoreInfo} id="hassio_api">
<ha-assist-chip
filled
@click=${this._showMoreInfo}
id="hassio_api"
.label=${capitalizeFirstLetter(
this.supervisor.localize(
`addon.dashboard.capability.role.${this.addon.hassio_role}`
) || this.addon.hassio_role
)}
>
<ha-svg-icon
slot="icon"
.path=${mdiHomeAssistant}
></ha-svg-icon>
${this.supervisor.localize(
`addon.dashboard.capability.role.${this.addon.hassio_role}`
) || this.addon.hassio_role}
</ha-chip>
</ha-assist-chip>
`
: ""}
${this.addon.docker_api
? html`
<ha-chip hasIcon @click=${this._showMoreInfo} id="docker_api">
<ha-svg-icon slot="icon" .path=${mdiDocker}></ha-svg-icon>
${this.supervisor.localize(
"addon.dashboard.capability.label.docker"
<ha-assist-chip
filled
@click=${this._showMoreInfo}
id="docker_api"
.label=${capitalizeFirstLetter(
this.supervisor.localize(
"addon.dashboard.capability.label.docker"
)
)}
</ha-chip>
>
<ha-svg-icon slot="icon" .path=${mdiDocker}></ha-svg-icon>
</ha-assist-chip>
`
: ""}
${this.addon.host_pid
? html`
<ha-chip hasIcon @click=${this._showMoreInfo} id="host_pid">
<ha-svg-icon slot="icon" .path=${mdiPound}></ha-svg-icon>
${this.supervisor.localize(
"addon.dashboard.capability.label.host_pid"
<ha-assist-chip
filled
@click=${this._showMoreInfo}
id="host_pid"
.label=${capitalizeFirstLetter(
this.supervisor.localize(
"addon.dashboard.capability.label.host_pid"
)
)}
</ha-chip>
>
<ha-svg-icon slot="icon" .path=${mdiPound}></ha-svg-icon>
</ha-assist-chip>
`
: ""}
${this.addon.apparmor !== "default"
? html`
<ha-chip
hasIcon
<ha-assist-chip
filled
@click=${this._showMoreInfo}
class=${this._computeApparmorClassName}
id="apparmor"
.label=${capitalizeFirstLetter(
this.supervisor.localize(
"addon.dashboard.capability.label.apparmor"
)
)}
>
<ha-svg-icon slot="icon" .path=${mdiShield}></ha-svg-icon>
${this.supervisor.localize(
"addon.dashboard.capability.label.apparmor"
)}
</ha-chip>
</ha-assist-chip>
`
: ""}
${this.addon.auth_api
? html`
<ha-chip hasIcon @click=${this._showMoreInfo} id="auth_api">
<ha-svg-icon slot="icon" .path=${mdiKey}></ha-svg-icon>
${this.supervisor.localize(
"addon.dashboard.capability.label.auth"
<ha-assist-chip
filled
@click=${this._showMoreInfo}
id="auth_api"
.label=${capitalizeFirstLetter(
this.supervisor.localize(
"addon.dashboard.capability.label.auth"
)
)}
</ha-chip>
>
<ha-svg-icon slot="icon" .path=${mdiKey}></ha-svg-icon>
</ha-assist-chip>
`
: ""}
${this.addon.ingress
? html`
<ha-chip hasIcon @click=${this._showMoreInfo} id="ingress">
<ha-assist-chip
filled
@click=${this._showMoreInfo}
id="ingress"
.label=${capitalizeFirstLetter(
this.supervisor.localize(
"addon.dashboard.capability.label.ingress"
)
)}
>
<ha-svg-icon
slot="icon"
.path=${mdiCursorDefaultClickOutline}
></ha-svg-icon>
${this.supervisor.localize(
"addon.dashboard.capability.label.ingress"
)}
</ha-chip>
</ha-assist-chip>
`
: ""}
${this.addon.signed
? html`
<ha-chip hasIcon @click=${this._showMoreInfo} id="signed">
<ha-svg-icon slot="icon" .path=${mdiLinkLock}></ha-svg-icon>
${this.supervisor.localize(
"addon.dashboard.capability.label.signed"
<ha-assist-chip
filled
@click=${this._showMoreInfo}
id="signed"
.label=${capitalizeFirstLetter(
this.supervisor.localize(
"addon.dashboard.capability.label.signed"
)
)}
</ha-chip>
>
<ha-svg-icon slot="icon" .path=${mdiLinkLock}></ha-svg-icon>
</ha-assist-chip>
`
: ""}
</ha-chip-set>
<div class="description light-color">
${this.addon.description}.<br />
${this.supervisor.localize(
"addon.dashboard.visit_addon_page",
"name",
html`<a href=${this.addon.url!} target="_blank" rel="noreferrer"
${this.supervisor.localize("addon.dashboard.visit_addon_page", {
name: html`<a
href=${this.addon.url!}
target="_blank"
rel="noreferrer"
>${this.addon.name}</a
>`
)}
>`,
})}
</div>
<div class="addon-container">
<div>
@@ -574,10 +625,10 @@ class HassioAddonInfo extends LitElement {
<ha-alert alert-type="warning">
${this.supervisor.localize(
"addon.dashboard.not_available_version",
"core_version_installed",
this.supervisor.core.version,
"core_version_needed",
addonStoreInfo!.homeassistant
{
core_version_installed: this.supervisor.core.version,
core_version_needed: addonStoreInfo!.homeassistant,
}
)}
</ha-alert>
`
@@ -750,12 +801,11 @@ class HassioAddonInfo extends LitElement {
id === "stage"
? this.supervisor.localize(
`addon.dashboard.capability.${id}.description`,
"icon_stable",
`<ha-svg-icon path="${STAGE_ICON.stable}"></ha-svg-icon>`,
"icon_experimental",
`<ha-svg-icon path="${STAGE_ICON.experimental}"></ha-svg-icon>`,
"icon_deprecated",
`<ha-svg-icon path="${STAGE_ICON.deprecated}"></ha-svg-icon>`
{
icon_stable: `<ha-svg-icon path="${STAGE_ICON.stable}"></ha-svg-icon>`,
icon_experimental: `<ha-svg-icon path="${STAGE_ICON.experimental}"></ha-svg-icon>`,
icon_deprecated: `<ha-svg-icon path="${STAGE_ICON.deprecated}"></ha-svg-icon>`,
}
)
: this.supervisor.localize(
`addon.dashboard.capability.${id}.description`
@@ -817,11 +867,9 @@ class HassioAddonInfo extends LitElement {
};
fireEvent(this, "hass-api-called", eventdata);
} catch (err: any) {
this._error = this.supervisor.localize(
"addon.failed_to_save",
"error",
extractApiErrorMessage(err)
);
this._error = this.supervisor.localize("addon.failed_to_save", {
error: extractApiErrorMessage(err),
});
}
}
@@ -839,11 +887,9 @@ class HassioAddonInfo extends LitElement {
};
fireEvent(this, "hass-api-called", eventdata);
} catch (err: any) {
this._error = this.supervisor.localize(
"addon.failed_to_save",
"error",
extractApiErrorMessage(err)
);
this._error = this.supervisor.localize("addon.failed_to_save", {
error: extractApiErrorMessage(err),
});
}
}
@@ -861,11 +907,9 @@ class HassioAddonInfo extends LitElement {
};
fireEvent(this, "hass-api-called", eventdata);
} catch (err: any) {
this._error = this.supervisor.localize(
"addon.failed_to_save",
"error",
extractApiErrorMessage(err)
);
this._error = this.supervisor.localize("addon.failed_to_save", {
error: extractApiErrorMessage(err),
});
}
}
@@ -883,11 +927,9 @@ class HassioAddonInfo extends LitElement {
};
fireEvent(this, "hass-api-called", eventdata);
} catch (err: any) {
this._error = this.supervisor.localize(
"addon.failed_to_save",
"error",
extractApiErrorMessage(err)
);
this._error = this.supervisor.localize("addon.failed_to_save", {
error: extractApiErrorMessage(err),
});
}
}
@@ -905,11 +947,9 @@ class HassioAddonInfo extends LitElement {
};
fireEvent(this, "hass-api-called", eventdata);
} catch (err: any) {
this._error = this.supervisor.localize(
"addon.failed_to_save",
"error",
extractApiErrorMessage(err)
);
this._error = this.supervisor.localize("addon.failed_to_save", {
error: extractApiErrorMessage(err),
});
}
}
@@ -1185,23 +1225,35 @@ class HassioAddonInfo extends LitElement {
.description a {
color: var(--primary-color);
}
ha-chip {
text-transform: capitalize;
--ha-chip-text-color: var(--text-primary-color);
--ha-chip-background-color: var(--primary-color);
ha-assist-chip {
--md-sys-color-primary: var(--text-primary-color);
--md-sys-color-on-surface: var(--text-primary-color);
--ha-assist-chip-filled-container-color: var(--primary-color);
}
.red {
--ha-chip-background-color: var(--label-badge-red, #df4c1e);
--ha-assist-chip-filled-container-color: var(
--label-badge-red,
#df4c1e
);
}
.blue {
--ha-chip-background-color: var(--label-badge-blue, #039be5);
--ha-assist-chip-filled-container-color: var(
--label-badge-blue,
#039be5
);
}
.green {
--ha-chip-background-color: var(--label-badge-green, #0da035);
--ha-assist-chip-filled-container-color: var(
--label-badge-green,
#0da035
);
}
.yellow {
--ha-chip-background-color: var(--label-badge-yellow, #f4b400);
--ha-assist-chip-filled-container-color: var(
--label-badge-yellow,
#f4b400
);
}
.capabilities {
margin-bottom: 16px;
@@ -1260,9 +1312,6 @@ class HassioAddonInfo extends LitElement {
}
@media (max-width: 720px) {
ha-chip {
line-height: 36px;
}
.addon-options {
max-width: 100%;
}
@@ -18,7 +18,9 @@ class HassioAddonLogDashboard extends LitElement {
protected render(): TemplateResult {
if (!this.addon) {
return html` <ha-circular-progress active></ha-circular-progress> `;
return html`
<ha-circular-progress indeterminate></ha-circular-progress>
`;
}
return html`
<div class="content">
@@ -72,11 +72,9 @@ class HassioAddonLogs extends LitElement {
try {
this._content = await fetchHassioAddonLogs(this.hass, this.addon.slug);
} catch (err: any) {
this._error = this.supervisor.localize(
"addon.logs.get_logs",
"error",
extractApiErrorMessage(err)
);
this._error = this.supervisor.localize("addon.logs.get_logs", {
error: extractApiErrorMessage(err),
});
}
}
@@ -1,11 +1,12 @@
import Fuse from "fuse.js";
import type { IFuseOptions } from "fuse.js";
import { StoreAddon } from "../../../src/data/supervisor/store";
export function filterAndSort(addons: StoreAddon[], filter: string) {
const options: Fuse.IFuseOptions<StoreAddon> = {
const options: IFuseOptions<StoreAddon> = {
keys: ["name", "description", "slug"],
isCaseSensitive: false,
minMatchCharLength: 2,
minMatchCharLength: Math.min(filter.length, 2),
threshold: 0.2,
};
const fuse = new Fuse(addons, options);
@@ -17,8 +17,11 @@ class SupervisorFormfieldLabel extends LitElement {
${this.imageUrl
? html`<img loading="lazy" alt="" src=${this.imageUrl} class="icon" />`
: this.iconPath
? html`<ha-svg-icon .path=${this.iconPath} class="icon"></ha-svg-icon>`
: ""}
? html`<ha-svg-icon
.path=${this.iconPath}
class="icon"
></ha-svg-icon>`
: ""}
<span class="label">${this.label}</span>
${this.version
? html`<span class="version">(${this.version})</span>`
+8 -6
View File
@@ -68,17 +68,19 @@ class HassioAddons extends LitElement {
.iconTitle=${addon.state !== "started"
? this.supervisor.localize("dashboard.addon_stopped")
: addon.update_available!
? this.supervisor.localize(
"dashboard.addon_new_version"
)
: this.supervisor.localize("dashboard.addon_running")}
? this.supervisor.localize(
"dashboard.addon_new_version"
)
: this.supervisor.localize(
"dashboard.addon_running"
)}
.iconClass=${addon.update_available
? addon.state === "started"
? "update"
: "update stopped"
: addon.state === "started"
? "running"
: "stopped"}
? "running"
: "stopped"}
.iconImage=${atLeastVersion(
this.hass.config.version,
0,
+3 -5
View File
@@ -46,11 +46,9 @@ export class HassioUpdate extends LitElement {
return html`
<div class="content">
<h1>
${this.supervisor.localize(
"common.update_available",
"count",
updatesAvailable
)}
${this.supervisor.localize("common.update_available", {
count: updatesAvailable,
})}
🎉
</h1>
<div class="card-group">
@@ -95,7 +95,7 @@ class HassioBackupDialog
</ha-header-bar>
</div>
${this._restoringBackup
? html`<ha-circular-progress active></ha-circular-progress>`
? html`<ha-circular-progress indeterminate></ha-circular-progress>`
: html`
<supervisor-backup-content
.hass=${this.hass}
@@ -57,7 +57,7 @@ class HassioCreateBackupDialog extends LitElement {
)}
>
${this._creatingBackup
? html`<ha-circular-progress active></ha-circular-progress>`
? html`<ha-circular-progress indeterminate></ha-circular-progress>`
: html`<supervisor-backup-content
.hass=${this.hass}
.supervisor=${this._dialogParams.supervisor}
@@ -71,7 +71,11 @@ class HassioDatadiskDialog extends LitElement {
?hideActions=${this.moving}
>
${this.moving
? html` <ha-circular-progress alt="Moving" size="large" active>
? html` <ha-circular-progress
aria-label="Moving"
size="large"
indeterminate
>
</ha-circular-progress>
<p class="progress-text">
${this.dialogParams.supervisor.localize(
@@ -105,12 +109,12 @@ class HassioDatadiskDialog extends LitElement {
</ha-select>
`
: this.devices === undefined
? this.dialogParams.supervisor.localize(
"dialog.datadisk_move.loading_devices"
)
: this.dialogParams.supervisor.localize(
"dialog.datadisk_move.no_devices"
)}
? this.dialogParams.supervisor.localize(
"dialog.datadisk_move.loading_devices"
)
: this.dialogParams.supervisor.localize(
"dialog.datadisk_move.no_devices"
)}
<mwc-button
slot="secondaryAction"
@@ -145,8 +145,7 @@ export class DialogHassioNetwork
? html`<p>
${this.supervisor.localize(
"dialog.network.connected_to",
"ssid",
this._interface?.wifi?.ssid
{ ssid: this._interface?.wifi?.ssid }
)}
</p>`
: ""}
@@ -156,7 +155,11 @@ export class DialogHassioNetwork
.disabled=${this._scanning}
>
${this._scanning
? html`<ha-circular-progress active size="small">
? html`<ha-circular-progress
aria-label="Scanning"
indeterminate
size="small"
>
</ha-circular-progress>`
: this.supervisor.localize("dialog.network.scan_ap")}
</mwc-button>
@@ -275,7 +278,7 @@ export class DialogHassioNetwork
</mwc-button>
<mwc-button @click=${this._updateNetwork} .disabled=${!this._dirty}>
${this._processing
? html`<ha-circular-progress active size="small">
? html`<ha-circular-progress indeterminate size="small">
</ha-circular-progress>`
: this.supervisor.localize("common.save")}
</mwc-button>
@@ -158,7 +158,7 @@ class HassioRepositoriesDialog extends LitElement {
<mwc-button @click=${this._addRepository}>
${this._processing
? html`<ha-circular-progress
active
indeterminate
size="small"
></ha-circular-progress>`
: this._dialogParams!.supervisor.localize(
+4 -6
View File
@@ -76,17 +76,15 @@ class HassioMyRedirect extends LitElement {
const redirect = REDIRECTS[path];
if (!redirect) {
this._error = this.supervisor.localize(
"my.not_supported",
"link",
html`<a
this._error = this.supervisor.localize("my.not_supported", {
link: html`<a
target="_blank"
rel="noreferrer noopener"
href="https://my.home-assistant.io/faq.html#supported-pages"
>
${this.supervisor.localize("my.faq_link")}
</a>`
);
</a>`,
});
return;
}
+2 -2
View File
@@ -67,8 +67,8 @@ class HassioRouter extends HassRouterPage {
const route = hassioPanel
? this.route
: ingressPanel && this.panel.config?.ingress
? this._ingressRoute(this.panel.config?.ingress)
: this.routeTail;
? this._ingressRoute(this.panel.config?.ingress)
: this.routeTail;
el.hass = this.hass;
el.narrow = this.narrow;
+13 -21
View File
@@ -96,13 +96,11 @@ class HassioCoreInfo extends LitElement {
slot="primaryAction"
class="warning"
@click=${this._coreRestart}
.title=${this.supervisor.localize(
"common.restart_name",
"name",
"Core"
)}
.title=${this.supervisor.localize("common.restart_name", {
name: "Core",
})}
>
${this.supervisor.localize("common.restart_name", "name", "Core")}
${this.supervisor.localize("common.restart_name", { name: "Core" })}
</ha-progress-button>
</div>
</ha-card>
@@ -122,16 +120,12 @@ class HassioCoreInfo extends LitElement {
button.progress = true;
const confirmed = await showConfirmationDialog(this, {
title: this.supervisor.localize(
"confirm.restart.title",
"name",
"Home Assistant Core"
),
text: this.supervisor.localize(
"confirm.restart.text",
"name",
"Home Assistant Core"
),
title: this.supervisor.localize("confirm.restart.title", {
name: "Home Assistant Core",
}),
text: this.supervisor.localize("confirm.restart.text", {
name: "Home Assistant Core",
}),
confirmText: this.supervisor.localize("common.restart"),
dismissText: this.supervisor.localize("common.cancel"),
});
@@ -146,11 +140,9 @@ class HassioCoreInfo extends LitElement {
} catch (err: any) {
if (this.hass.connection.connected) {
showAlertDialog(this, {
title: this.supervisor.localize(
"common.failed_to_restart_name",
"name",
"Home AssistantCore"
),
title: this.supervisor.localize("common.failed_to_restart_name", {
name: "Home Assistant Core",
}),
text: extractApiErrorMessage(err),
});
}
+29 -40
View File
@@ -109,19 +109,19 @@ class HassioSupervisorInfo extends LitElement {
</ha-progress-button>
`
: this.supervisor.supervisor.channel === "stable"
? html`
<ha-progress-button
@click=${this._toggleBeta}
.title=${this.supervisor.localize(
"system.supervisor.join_beta_description"
)}
>
${this.supervisor.localize(
"system.supervisor.join_beta_action"
)}
</ha-progress-button>
`
: ""}
? html`
<ha-progress-button
@click=${this._toggleBeta}
.title=${this.supervisor.localize(
"system.supervisor.join_beta_description"
)}
>
${this.supervisor.localize(
"system.supervisor.join_beta_action"
)}
</ha-progress-button>
`
: ""}
</ha-settings-row>
${this.supervisor.supervisor.supported
@@ -200,17 +200,13 @@ class HassioSupervisorInfo extends LitElement {
<ha-progress-button
class="warning"
@click=${this._supervisorRestart}
.title=${this.supervisor.localize(
"common.restart_name",
"name",
"Supervisor"
)}
.title=${this.supervisor.localize("common.restart_name", {
name: "Supervisor",
})}
>
${this.supervisor.localize(
"common.restart_name",
"name",
"Supervisor"
)}
${this.supervisor.localize("common.restart_name", {
name: "Supervisor",
})}
</ha-progress-button>
</div>
</ha-card>
@@ -292,16 +288,12 @@ class HassioSupervisorInfo extends LitElement {
button.progress = true;
const confirmed = await showConfirmationDialog(this, {
title: this.supervisor.localize(
"confirm.restart.title",
"name",
"Supervisor"
),
text: this.supervisor.localize(
"confirm.restart.text",
"name",
"Supervisor"
),
title: this.supervisor.localize("confirm.restart.title", {
name: "Supervisor",
}),
text: this.supervisor.localize("confirm.restart.text", {
name: "Supervisor",
}),
confirmText: this.supervisor.localize("common.restart"),
dismissText: this.supervisor.localize("common.cancel"),
});
@@ -315,11 +307,9 @@ class HassioSupervisorInfo extends LitElement {
await restartSupervisor(this.hass);
} catch (err: any) {
showAlertDialog(this, {
title: this.supervisor.localize(
"common.failed_to_restart_name",
"name",
"Supervisor"
),
title: this.supervisor.localize("common.failed_to_restart_name", {
name: "Supervisor",
}),
text: extractApiErrorMessage(err),
});
} finally {
@@ -334,8 +324,7 @@ class HassioSupervisorInfo extends LitElement {
),
text: this.supervisor.localize(
"system.supervisor.share_diagonstics_description",
"line_break",
html`<br /><br />`
{ line_break: html`<br /><br />` }
),
});
}
+4 -7
View File
@@ -124,13 +124,10 @@ class HassioSupervisorLog extends LitElement {
this._selectedLogProvider
);
} catch (err: any) {
this._error = this.supervisor.localize(
"system.log.get_logs",
"provider",
this._selectedLogProvider,
"error",
extractApiErrorMessage(err)
);
this._error = this.supervisor.localize("system.log.get_logs", {
provider: this._selectedLogProvider,
error: extractApiErrorMessage(err),
});
}
}
@@ -70,8 +70,8 @@ const changelogUrl = (
return version.includes("dev")
? "https://github.com/home-assistant/core/commits/dev"
: version.includes("b")
? "https://next.home-assistant.io/latest-release-notes/"
: "https://www.home-assistant.io/latest-release-notes/";
? "https://next.home-assistant.io/latest-release-notes/"
: "https://www.home-assistant.io/latest-release-notes/";
}
if (entry === "os") {
return version.includes("dev")
@@ -141,44 +141,51 @@ class UpdateAvailableCard extends LitElement {
})}
</p>`
: !this._updating
? html`
${this._changelogContent
? html`
<ha-faded>
<ha-markdown .content=${this._changelogContent}>
</ha-markdown>
</ha-faded>
`
: ""}
<div class="versions">
<p>
${this.supervisor.localize("update_available.description", {
? html`
${this._changelogContent
? html`
<ha-faded>
<ha-markdown .content=${this._changelogContent}>
</ha-markdown>
</ha-faded>
`
: ""}
<div class="versions">
<p>
${this.supervisor.localize(
"update_available.description",
{
name: this._name,
version: this._version,
newest_version: this._version_latest,
}
)}
</p>
</div>
${["core", "addon"].includes(this._updateType)
? html`
<ha-formfield
.label=${this.supervisor.localize(
"update_available.create_backup"
)}
>
<ha-checkbox checked></ha-checkbox>
</ha-formfield>
`
: ""}
`
: html`<ha-circular-progress
aria-label="Updating"
size="large"
indeterminate
>
</ha-circular-progress>
<p class="progress-text">
${this.supervisor.localize("update_available.updating", {
name: this._name,
version: this._version,
newest_version: this._version_latest,
version: this._version_latest,
})}
</p>
</div>
${["core", "addon"].includes(this._updateType)
? html`
<ha-formfield
.label=${this.supervisor.localize(
"update_available.create_backup"
)}
>
<ha-checkbox checked></ha-checkbox>
</ha-formfield>
`
: ""}
`
: html`<ha-circular-progress alt="Updating" size="large" active>
</ha-circular-progress>
<p class="progress-text">
${this.supervisor.localize("update_available.updating", {
name: this._name,
version: this._version_latest,
})}
</p>`}
</p>`}
</div>
${this._version !== this._version_latest && !this._updating
? html`
+80 -83
View File
@@ -25,42 +25,41 @@
"license": "Apache-2.0",
"type": "module",
"dependencies": {
"@babel/runtime": "7.23.2",
"@braintree/sanitize-url": "6.0.4",
"@codemirror/autocomplete": "6.10.2",
"@codemirror/commands": "6.3.0",
"@codemirror/language": "6.9.2",
"@babel/runtime": "7.23.5",
"@braintree/sanitize-url": "7.0.0",
"@codemirror/autocomplete": "6.11.1",
"@codemirror/commands": "6.3.2",
"@codemirror/language": "6.9.3",
"@codemirror/legacy-modes": "6.3.3",
"@codemirror/search": "6.5.4",
"@codemirror/state": "6.3.1",
"@codemirror/view": "6.21.4",
"@codemirror/search": "6.5.5",
"@codemirror/state": "6.3.3",
"@codemirror/view": "6.22.1",
"@egjs/hammerjs": "2.0.17",
"@formatjs/intl-datetimeformat": "6.11.1",
"@formatjs/intl-displaynames": "6.6.1",
"@formatjs/intl-datetimeformat": "6.12.0",
"@formatjs/intl-displaynames": "6.6.4",
"@formatjs/intl-getcanonicallocales": "2.3.0",
"@formatjs/intl-listformat": "7.5.0",
"@formatjs/intl-locale": "3.4.0",
"@formatjs/intl-numberformat": "8.8.0",
"@formatjs/intl-pluralrules": "5.2.7",
"@formatjs/intl-relativetimeformat": "11.2.7",
"@fullcalendar/core": "6.1.9",
"@fullcalendar/daygrid": "6.1.9",
"@fullcalendar/interaction": "6.1.9",
"@fullcalendar/list": "6.1.9",
"@fullcalendar/luxon3": "6.1.9",
"@fullcalendar/timegrid": "6.1.9",
"@lezer/highlight": "1.1.6",
"@formatjs/intl-listformat": "7.5.3",
"@formatjs/intl-locale": "3.4.3",
"@formatjs/intl-numberformat": "8.9.0",
"@formatjs/intl-pluralrules": "5.2.10",
"@formatjs/intl-relativetimeformat": "11.2.10",
"@fullcalendar/core": "6.1.10",
"@fullcalendar/daygrid": "6.1.10",
"@fullcalendar/interaction": "6.1.10",
"@fullcalendar/list": "6.1.10",
"@fullcalendar/luxon3": "6.1.10",
"@fullcalendar/timegrid": "6.1.10",
"@lezer/highlight": "1.2.0",
"@lit-labs/context": "0.4.1",
"@lit-labs/motion": "1.0.4",
"@lit-labs/observers": "2.0.1",
"@lit-labs/virtualizer": "2.0.7",
"@lit-labs/motion": "1.0.6",
"@lit-labs/observers": "2.0.2",
"@lit-labs/virtualizer": "2.0.11",
"@lrnwebcomponents/simple-tooltip": "7.0.18",
"@material/chips": "=14.0.0-canary.53b3cad2f.0",
"@material/data-table": "=14.0.0-canary.53b3cad2f.0",
"@material/mwc-base": "0.27.0",
"@material/mwc-button": "0.27.0",
"@material/mwc-checkbox": "0.27.0",
"@material/mwc-circular-progress": "0.27.0",
"@material/mwc-dialog": "0.27.0",
"@material/mwc-drawer": "0.27.0",
"@material/mwc-fab": "0.27.0",
@@ -84,9 +83,6 @@
"@material/web": "=1.0.1",
"@mdi/js": "7.3.67",
"@mdi/svg": "7.3.67",
"@polymer/iron-flex-layout": "3.0.1",
"@polymer/iron-input": "3.0.1",
"@polymer/iron-resizable-behavior": "3.0.1",
"@polymer/paper-input": "3.2.1",
"@polymer/paper-item": "3.0.1",
"@polymer/paper-listbox": "3.0.1",
@@ -94,8 +90,8 @@
"@polymer/paper-toast": "3.0.1",
"@polymer/polymer": "3.5.1",
"@thomasloven/round-slider": "0.6.0",
"@vaadin/combo-box": "24.2.1",
"@vaadin/vaadin-themable-mixin": "24.2.1",
"@vaadin/combo-box": "24.2.5",
"@vaadin/vaadin-themable-mixin": "24.2.5",
"@vibrant/color": "3.2.1-alpha.1",
"@vibrant/core": "3.2.1-alpha.1",
"@vibrant/quantizer-mmcq": "3.2.1-alpha.1",
@@ -103,45 +99,45 @@
"@webcomponents/scoped-custom-element-registry": "0.0.9",
"@webcomponents/webcomponentsjs": "2.8.0",
"app-datepicker": "5.1.1",
"chart.js": "4.4.0",
"chart.js": "4.4.1",
"comlink": "4.4.1",
"core-js": "3.33.1",
"core-js": "3.33.3",
"cropperjs": "1.6.1",
"date-fns": "2.30.0",
"date-fns-tz": "2.0.0",
"deep-clone-simple": "1.1.1",
"deep-freeze": "0.0.1",
"fuse.js": "6.6.2",
"element-internals-polyfill": "1.3.9",
"fuse.js": "7.0.0",
"google-timezones-json": "1.2.0",
"hls.js": "1.4.12",
"hls.js": "1.4.13",
"home-assistant-js-websocket": "9.1.0",
"idb-keyval": "6.2.1",
"intl-messageformat": "10.5.4",
"intl-messageformat": "10.5.8",
"js-yaml": "4.1.0",
"leaflet": "1.9.4",
"leaflet-draw": "1.0.4",
"lit": "2.8.0",
"luxon": "3.4.3",
"marked": "9.1.2",
"luxon": "3.4.4",
"marked": "11.0.1",
"memoize-one": "6.0.0",
"node-vibrant": "3.2.1-alpha.1",
"proxy-polyfill": "0.3.2",
"punycode": "2.3.0",
"punycode": "2.3.1",
"qr-scanner": "1.4.2",
"qrcode": "1.5.3",
"resize-observer-polyfill": "1.5.1",
"roboto-fontface": "0.10.0",
"rrule": "2.7.2",
"sortablejs": "1.15.0",
"rrule": "2.8.1",
"sortablejs": "1.15.1",
"stacktrace-js": "2.0.2",
"superstruct": "1.0.3",
"tinykeys": "2.1.0",
"tsparticles-engine": "2.12.0",
"tsparticles-preset-links": "2.12.0",
"ua-parser-js": "1.0.36",
"ua-parser-js": "1.0.37",
"unfetch": "5.0.0",
"vis-data": "7.1.7",
"vis-network": "9.1.8",
"vis-data": "7.1.9",
"vis-network": "9.1.9",
"vue": "2.7.15",
"vue2-daterange-picker": "0.6.8",
"weekstart": "2.0.0",
@@ -154,14 +150,15 @@
"xss": "1.0.14"
},
"devDependencies": {
"@babel/core": "7.23.2",
"@babel/plugin-proposal-decorators": "7.23.2",
"@babel/plugin-transform-runtime": "7.23.2",
"@babel/preset-env": "7.23.2",
"@babel/preset-typescript": "7.23.2",
"@bundle-stats/plugin-webpack-filter": "4.7.8",
"@babel/core": "7.23.5",
"@babel/helper-define-polyfill-provider": "0.4.3",
"@babel/plugin-proposal-decorators": "7.23.5",
"@babel/plugin-transform-runtime": "7.23.4",
"@babel/preset-env": "7.23.5",
"@babel/preset-typescript": "7.23.3",
"@bundle-stats/plugin-webpack-filter": "4.8.3",
"@koa/cors": "4.0.0",
"@lokalise/node-api": "12.0.0",
"@lokalise/node-api": "12.1.0",
"@octokit/auth-oauth-device": "6.0.1",
"@octokit/plugin-retry": "6.0.1",
"@octokit/rest": "20.0.2",
@@ -170,46 +167,44 @@
"@rollup/plugin-commonjs": "25.0.7",
"@rollup/plugin-json": "6.0.1",
"@rollup/plugin-node-resolve": "15.2.3",
"@rollup/plugin-replace": "5.0.4",
"@types/babel__plugin-transform-runtime": "7.9.4",
"@types/chromecast-caf-receiver": "6.0.11",
"@types/chromecast-caf-sender": "1.0.7",
"@types/esprima": "4.0.5",
"@rollup/plugin-replace": "5.0.5",
"@types/babel__plugin-transform-runtime": "7.9.5",
"@types/chromecast-caf-receiver": "6.0.12",
"@types/chromecast-caf-sender": "1.0.8",
"@types/glob": "8.1.0",
"@types/html-minifier-terser": "7.0.1",
"@types/js-yaml": "4.0.8",
"@types/leaflet": "1.9.7",
"@types/leaflet-draw": "1.0.9",
"@types/luxon": "3.3.3",
"@types/mocha": "10.0.3",
"@types/qrcode": "1.5.4",
"@types/serve-handler": "6.1.3",
"@types/sortablejs": "1.15.4",
"@types/tar": "6.1.7",
"@types/ua-parser-js": "0.7.38",
"@types/html-minifier-terser": "7.0.2",
"@types/js-yaml": "4.0.9",
"@types/leaflet": "1.9.8",
"@types/leaflet-draw": "1.0.11",
"@types/luxon": "3.3.7",
"@types/mocha": "10.0.6",
"@types/qrcode": "1.5.5",
"@types/serve-handler": "6.1.4",
"@types/sortablejs": "1.15.7",
"@types/tar": "6.1.10",
"@types/ua-parser-js": "0.7.39",
"@types/webspeechapi": "0.0.29",
"@typescript-eslint/eslint-plugin": "6.9.0",
"@typescript-eslint/parser": "6.9.0",
"@typescript-eslint/eslint-plugin": "6.13.2",
"@typescript-eslint/parser": "6.13.2",
"@web/dev-server": "0.1.38",
"@web/dev-server-rollup": "0.4.1",
"babel-loader": "9.1.3",
"babel-plugin-template-html-minifier": "4.1.0",
"chai": "4.3.10",
"del": "7.1.0",
"eslint": "8.52.0",
"eslint": "8.55.0",
"eslint-config-airbnb-base": "15.0.0",
"eslint-config-airbnb-typescript": "17.1.0",
"eslint-config-prettier": "9.0.0",
"eslint-config-prettier": "9.1.0",
"eslint-import-resolver-webpack": "0.13.8",
"eslint-plugin-disable": "2.0.3",
"eslint-plugin-import": "2.29.0",
"eslint-plugin-lit": "1.10.1",
"eslint-plugin-lit-a11y": "4.1.0",
"eslint-plugin-lit-a11y": "4.1.1",
"eslint-plugin-unused-imports": "3.0.0",
"eslint-plugin-wc": "2.0.4",
"esprima": "4.0.1",
"fancy-log": "2.0.0",
"fs-extra": "11.1.1",
"fs-extra": "11.2.0",
"glob": "10.3.10",
"gulp": "4.0.2",
"gulp-flatmap": "1.0.2",
@@ -221,7 +216,7 @@
"husky": "8.0.3",
"instant-mocha": "1.5.2",
"jszip": "3.10.1",
"lint-staged": "15.0.2",
"lint-staged": "15.2.0",
"lit-analyzer": "2.0.1",
"lodash.template": "4.5.0",
"magic-string": "0.30.5",
@@ -230,19 +225,19 @@
"object-hash": "3.0.0",
"open": "9.1.0",
"pinst": "3.0.0",
"prettier": "3.0.3",
"prettier": "3.1.0",
"rollup": "2.79.1",
"rollup-plugin-string": "3.0.0",
"rollup-plugin-terser": "7.0.2",
"rollup-plugin-visualizer": "5.9.2",
"rollup-plugin-visualizer": "5.10.0",
"serve-handler": "6.1.5",
"sinon": "17.0.0",
"sinon": "17.0.1",
"source-map-url": "0.4.1",
"systemjs": "6.14.2",
"tar": "6.2.0",
"terser-webpack-plugin": "5.3.9",
"ts-lit-plugin": "2.0.0",
"typescript": "5.2.2",
"ts-lit-plugin": "2.0.1",
"typescript": "5.3.3",
"vinyl-buffer": "1.0.1",
"vinyl-source-stream": "2.0.0",
"webpack": "5.89.0",
@@ -257,9 +252,11 @@
"resolutions": {
"@polymer/polymer": "patch:@polymer/[email protected]#./.yarn/patches/@polymer/polymer/pr-5569.patch",
"@material/mwc-button@^0.25.3": "^0.27.0",
"lit@^2.7.4 || ^3.0.0": "^2.7.4",
"lit": "2.8.0",
"clean-css": "5.3.3",
"@lit/reactive-element": "1.6.3",
"[email protected]": "patch:sortablejs@npm%3A1.15.0#./.yarn/patches/sortablejs-npm-1.15.0-f3a393abcc.patch",
"[email protected]": "patch:leaflet-draw@npm%3A1.0.4#./.yarn/patches/leaflet-draw-npm-1.0.4-0ca0ebcf65.patch"
},
"packageManager": "yarn@3.6.4"
"packageManager": "yarn@4.0.2"
}
+1 -23
View File
@@ -1,23 +1 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="480.000000pt" height="480.000000pt" viewBox="0 0 480.000000 480.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,480.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M2313 4666 c-23 -7 -56 -23 -75 -34 -47 -30 -2059 -2048 -2095 -2102
-45 -67 -77 -135 -109 -230 l-29 -85 0 -995 0 -995 27 -51 c31 -59 93 -118
152 -145 39 -18 83 -19 1001 -19 l960 0 -406 405 c-395 395 -406 406 -433 395
-15 -5 -63 -10 -107 -10 -429 0 -566 577 -181 767 67 34 86 38 164 42 105 4
165 -13 246 -67 113 -74 175 -190 176 -327 1 -44 -3 -96 -7 -115 l-8 -35 316
-315 315 -315 0 1160 -1 1160 -51 35 c-260 177 -226 567 62 704 82 39 209 48
293 21 239 -78 354 -352 242 -575 -32 -63 -89 -125 -141 -156 l-44 -26 0 -811
0 -812 315 315 c218 217 313 320 309 330 -14 35 -16 134 -4 190 26 122 111
227 230 284 82 39 209 48 293 21 115 -38 214 -130 258 -242 19 -46 23 -78 24
-153 0 -86 -3 -101 -32 -163 -40 -84 -118 -163 -198 -202 -49 -23 -77 -29
-150 -33 -50 -2 -108 1 -130 7 l-40 11 -437 -438 -438 -437 0 -307 0 -308 998
0 c981 0 998 1 1042 21 58 26 115 81 148 144 l27 50 0 995 0 995 -33 95 c-72
209 -6 135 -1147 1278 -840 843 -1040 1037 -1082 1059 -64 31 -159 39 -220 19z"/>
</g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="640" viewBox="0 0 240 240"><path d="M120.001 0c-3.787 0-7.573 1.499-10.444 4.49L12.211 105.905a25.921 25.921 0 0 0-2.098 2.501 35.25 35.25 0 0 0-1.96 2.942c-3.01 5.021-5.285 11.318-6.074 16.898-.03.21-.088.429-.11.636a27.355 27.355 0 0 0-.213 3.317v93.023a14.78 14.78 90 0 0 14.78 14.78h90.92L67.422 198.29a20.2 20.2 90 1 1 12.542-13.06l31.17 32.474V98.726a20.2 20.2 90 1 1 17.734 0v83.44l31.001-32.299a20.2 20.2 90 1 1 12.267 13.357l-43.269 45.082V240h94.9a14.479 14.479 90 0 0 14.478-14.479v-93.314c0-1.059-.069-2.168-.214-3.314-.7-5.73-3.06-12.327-6.183-17.537a35.801 35.801 0 0 0-1.955-2.937 26.271 26.271 0 0 0-2.102-2.506L130.444 4.486C127.573 1.494 123.786-.002 120.001 0"/></svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 747 B

+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "home-assistant-frontend"
version = "20231027.0"
version = "20231208.2"
license = {text = "Apache-2.0"}
description = "The Home Assistant frontend"
readme = "README.md"
+13 -1
View File
@@ -1,5 +1,6 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"configMigration": true,
"extends": [
":ignoreModulesAndTests",
":label(Dependencies)",
@@ -10,7 +11,7 @@
"group:recommended",
"npm:unpublishSafe"
],
"enabledManagers": ["npm"],
"enabledManagers": ["npm", "nvm"],
"postUpdateOptions": ["yarnDedupeHighest"],
"lockFileMaintenance": {
"description": ["Run after patch releases but before next beta"],
@@ -28,11 +29,22 @@
"matchPackageNames": ["vue"],
"allowedVersions": "< 3"
},
{
"description": "Group MDI packages",
"groupName": "Material Design Icons",
"matchPackageNames": ["@mdi/js", "@mdi/svg"]
},
{
"description": "Group tsparticles engine and presets",
"groupName": "tsparticles",
"matchPackageNames": ["tsparticles-engine"],
"matchPackagePrefixes": ["tsparticles-preset-"]
},
{
"description": "Group and temporarily disable WDS packages",
"groupName": "Web Dev Server",
"matchPackagePrefixes": ["@web/dev-server"],
"enabled": false
}
]
}
+2 -1
View File
@@ -40,4 +40,5 @@ docker run \
--file /opt/src/${LOCAL_FILE} \
--lang-iso ${LANG_ISO} \
--convert-placeholders=false \
--replace-modified=true
--replace-modified=true \
# --cleanup-mode=true
+121 -107
View File
@@ -8,13 +8,20 @@ import "../components/ha-alert";
import "../components/ha-checkbox";
import { computeInitialHaFormData } from "../components/ha-form/compute-initial-ha-form-data";
import "../components/ha-formfield";
import "../components/ha-markdown";
import { AuthProvider, autocompleteLoginFields } from "../data/auth";
import {
AuthProvider,
autocompleteLoginFields,
createLoginFlow,
deleteLoginFlow,
redirectWithAuthCode,
submitLoginFlow,
} from "../data/auth";
import {
DataEntryFlowStep,
DataEntryFlowStepForm,
} from "../data/data_entry_flow";
import "./ha-auth-form";
import { fireEvent } from "../common/dom/fire_event";
type State = "loading" | "error" | "step";
@@ -30,18 +37,18 @@ export class HaAuthFlow extends LitElement {
@property() public localize!: LocalizeFunc;
@property({ attribute: false }) public step?: DataEntryFlowStep;
@property({ type: Boolean }) private storeToken = false;
@state() private _state: State = "loading";
@state() private _stepData?: Record<string, any>;
@state() private _step?: DataEntryFlowStep;
@state() private _errorMessage?: string;
@state() private _submitting = false;
@state() private _storeToken = false;
createRenderRoot() {
return this;
}
@@ -49,27 +56,29 @@ export class HaAuthFlow extends LitElement {
willUpdate(changedProps: PropertyValues) {
super.willUpdate(changedProps);
if (!changedProps.has("_step")) {
if (!changedProps.has("step")) {
return;
}
if (!this._step) {
if (!this.step) {
this._stepData = undefined;
return;
}
const oldStep = changedProps.get("_step") as HaAuthFlow["_step"];
this._state = "step";
const oldStep = changedProps.get("step") as HaAuthFlow["step"];
if (
!oldStep ||
this._step.flow_id !== oldStep.flow_id ||
(this._step.type === "form" &&
this.step.flow_id !== oldStep.flow_id ||
(this.step.type === "form" &&
oldStep.type === "form" &&
this._step.step_id !== oldStep.step_id)
this.step.step_id !== oldStep.step_id)
) {
this._stepData =
this._step.type === "form"
? computeInitialHaFormData(this._step.data_schema)
this.step.type === "form"
? computeInitialHaFormData(this.step.data_schema)
: undefined;
}
}
@@ -77,14 +86,28 @@ export class HaAuthFlow extends LitElement {
protected render() {
return html`
<style>
ha-auth-flow .action {
margin: 24px 0 8px;
text-align: center;
}
ha-auth-flow .store-token {
margin-top: 10px;
margin-left: -16px;
}
a.forgot-password {
color: var(--primary-color);
text-decoration: none;
font-size: 0.875rem;
}
.space-between {
display: flex;
justify-content: space-between;
align-items: center;
}
form {
text-align: center;
max-width: 336px;
width: 100%;
}
ha-auth-form {
display: block;
margin-top: 16px;
}
</style>
<form>${this._renderForm()}</form>
`;
@@ -118,7 +141,7 @@ export class HaAuthFlow extends LitElement {
this._providerChanged(this.authProvider);
}
if (!changedProps.has("_step") || this._step?.type !== "form") {
if (!changedProps.has("step") || this.step?.type !== "form") {
return;
}
@@ -132,20 +155,31 @@ export class HaAuthFlow extends LitElement {
}
private _renderForm() {
const showBack =
this.step?.type === "form" &&
this.authProvider?.users &&
!["select_mfa_module", "mfa"].includes(this.step.step_id);
switch (this._state) {
case "step":
if (this._step == null) {
if (this.step == null) {
return nothing;
}
return html`
${this._renderStep(this._step)}
<div class="action">
${this._renderStep(this.step)}
<div class="action ${showBack ? "space-between" : ""}">
${showBack
? html`<mwc-button @click=${this._localFlow}>
${this.localize("ui.panel.page-authorize.form.previous")}
</mwc-button>`
: nothing}
<mwc-button
raised
@click=${this._handleSubmit}
.disabled=${this._submitting}
>
${this._step.type === "form"
${this.step.type === "form"
? this.localize("ui.panel.page-authorize.form.next")
: this.localize("ui.panel.page-authorize.form.start_over")}
</mwc-button>
@@ -154,11 +188,9 @@ export class HaAuthFlow extends LitElement {
case "error":
return html`
<ha-alert alert-type="error">
${this.localize(
"ui.panel.page-authorize.form.error",
"error",
this._errorMessage
)}
${this.localize("ui.panel.page-authorize.form.error", {
error: this._errorMessage,
})}
</ha-alert>
<div class="action">
<mwc-button raised @click=${this._startOver}>
@@ -182,24 +214,18 @@ export class HaAuthFlow extends LitElement {
case "abort":
return html`
${this.localize("ui.panel.page-authorize.abort_intro")}:
<ha-markdown
allowsvg
breaks
.content=${this.localize(
`ui.panel.page-authorize.form.providers.${step.handler[0]}.abort.${step.reason}`
)}
></ha-markdown>
${this.localize(
`ui.panel.page-authorize.form.providers.${step.handler[0]}.abort.${step.reason}`
)}
`;
case "form":
return html`
${this._computeStepDescription(step)
? html`
<ha-markdown
breaks
.content=${this._computeStepDescription(step)}
></ha-markdown>
`
: nothing}
<h1>
${!["select_mfa_module", "mfa"].includes(step.step_id)
? this.localize("ui.panel.page-authorize.welcome_home")
: this.localize("ui.panel.page-authorize.just_checking")}
</h1>
${this._computeStepDescription(step)}
<ha-auth-form
.data=${this._stepData}
.schema=${autocompleteLoginFields(step.data_schema)}
@@ -212,15 +238,28 @@ export class HaAuthFlow extends LitElement {
${this.clientId === genClientId() &&
!["select_mfa_module", "mfa"].includes(step.step_id)
? html`
<ha-formfield
class="store-token"
.label=${this.localize("ui.panel.page-authorize.store_token")}
>
<ha-checkbox
.checked=${this._storeToken}
@change=${this._storeTokenChanged}
></ha-checkbox>
</ha-formfield>
<div class="space-between">
<ha-formfield
class="store-token"
.label=${this.localize(
"ui.panel.page-authorize.store_token"
)}
>
<ha-checkbox
.checked=${this.storeToken}
@change=${this._storeTokenChanged}
></ha-checkbox>
</ha-formfield>
<a
class="forgot-password"
href="https://www.home-assistant.io/docs/locked_out/#forgot-password"
target="_blank"
rel="noreferrer noopener"
>${this.localize(
"ui.panel.page-authorize.forgot_password"
)}</a
>
</div>
`
: ""}
`;
@@ -230,15 +269,12 @@ export class HaAuthFlow extends LitElement {
}
private _storeTokenChanged(e: CustomEvent<HTMLInputElement>) {
this._storeToken = (e.currentTarget as HTMLInputElement).checked;
this.storeToken = (e.currentTarget as HTMLInputElement).checked;
}
private async _providerChanged(newProvider?: AuthProvider) {
if (this._step && this._step.type === "form") {
fetch(`/auth/login_flow/${this._step.flow_id}`, {
method: "DELETE",
credentials: "same-origin",
}).catch((err) => {
if (this.step && this.step.type === "form") {
deleteLoginFlow(this.step.flow_id).catch((err) => {
// eslint-disable-next-line no-console
console.error("Error delete obsoleted auth flow", err);
});
@@ -253,26 +289,26 @@ export class HaAuthFlow extends LitElement {
}
try {
const response = await fetch("/auth/login_flow", {
method: "POST",
credentials: "same-origin",
body: JSON.stringify({
client_id: this.clientId,
handler: [newProvider.type, newProvider.id],
redirect_uri: this.redirectUri,
}),
});
const response = await createLoginFlow(this.clientId, this.redirectUri, [
newProvider.type,
newProvider.id,
]);
const data = await response.json();
if (response.ok) {
// allow auth provider bypass the login form
if (data.type === "create_entry") {
this._redirect(data.result);
redirectWithAuthCode(
this.redirectUri!,
data.result,
this.oauth2State,
this.storeToken
);
return;
}
this._step = data;
this.step = data;
this._state = "step";
} else {
this._state = "error";
@@ -286,27 +322,6 @@ export class HaAuthFlow extends LitElement {
}
}
private _redirect(authCode: string) {
// OAuth 2: 3.1.2 we need to retain query component of a redirect URI
let url = this.redirectUri!;
if (!url.includes("?")) {
url += "?";
} else if (!url.endsWith("&")) {
url += "&";
}
url += `code=${encodeURIComponent(authCode)}`;
if (this.oauth2State) {
url += `&state=${encodeURIComponent(this.oauth2State)}`;
}
if (this._storeToken) {
url += `&storeToken=true`;
}
document.location.assign(url);
}
private _stepDataChanged(ev: CustomEvent) {
this._stepData = ev.detail.value;
}
@@ -314,13 +329,7 @@ export class HaAuthFlow extends LitElement {
private _computeStepDescription(step: DataEntryFlowStepForm) {
const resourceKey =
`ui.panel.page-authorize.form.providers.${step.handler[0]}.step.${step.step_id}.description` as const;
const args: string[] = [];
const placeholders = step.description_placeholders || {};
Object.keys(placeholders).forEach((key) => {
args.push(key);
args.push(placeholders[key]);
});
return this.localize(resourceKey, ...args);
return this.localize(resourceKey, step.description_placeholders);
}
private _computeLabelCallback(step: DataEntryFlowStepForm) {
@@ -349,10 +358,10 @@ export class HaAuthFlow extends LitElement {
private async _handleSubmit(ev: Event) {
ev.preventDefault();
if (this._step == null) {
if (this.step == null) {
return;
}
if (this._step.type !== "form") {
if (this.step.type !== "form") {
this._providerChanged(this.authProvider);
return;
}
@@ -361,11 +370,7 @@ export class HaAuthFlow extends LitElement {
const postData = { ...this._stepData, client_id: this.clientId };
try {
const response = await fetch(`/auth/login_flow/${this._step.flow_id}`, {
method: "POST",
credentials: "same-origin",
body: JSON.stringify(postData),
});
const response = await submitLoginFlow(this.step.flow_id, postData);
const newStep = await response.json();
@@ -376,10 +381,15 @@ export class HaAuthFlow extends LitElement {
}
if (newStep.type === "create_entry") {
this._redirect(newStep.result);
redirectWithAuthCode(
this.redirectUri!,
newStep.result,
this.oauth2State,
this.storeToken
);
return;
}
this._step = newStep;
this.step = newStep;
this._state = "step";
} catch (err: any) {
// eslint-disable-next-line no-console
@@ -390,6 +400,10 @@ export class HaAuthFlow extends LitElement {
this._submitting = false;
}
}
private _localFlow() {
fireEvent(this, "default-login-flow", { value: false });
}
}
declare global {
+2 -2
View File
@@ -41,8 +41,8 @@ export class HaAuthFormString extends HaFormString {
!this.isPassword
? this.stringType
: this.unmaskedPassword
? "text"
: "password"
? "text"
: "password"
}
.label=${this.label}
.value=${this.data || ""}
+145 -42
View File
@@ -13,6 +13,7 @@ import {
import { litLocalizeLiteMixin } from "../mixins/lit-localize-lite-mixin";
import { registerServiceWorker } from "../util/register-service-worker";
import "./ha-auth-flow";
import "./ha-local-auth-flow";
import("./ha-pick-auth-provider");
@@ -39,6 +40,8 @@ export class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
@state() private _error?: string;
@state() private _forceDefaultLogin = false;
constructor() {
super();
const query = extractSearchParamsObject() as AuthUrlSearchParams;
@@ -60,6 +63,7 @@ export class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
ha-authorize ha-alert {
display: block;
margin: 16px 0;
background-color: var(--primary-background-color, #fafafa);
}
</style>
<ha-alert alert-type="error"
@@ -68,19 +72,7 @@ export class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
`;
}
if (!this._authProviders) {
return html`
<style>
ha-authorize p {
font-size: 14px;
line-height: 20px;
}
</style>
<p>${this.localize("ui.panel.page-authorize.initializing")}</p>
`;
}
const inactiveProviders = this._authProviders.filter(
const inactiveProviders = this._authProviders?.filter(
(prv) => prv !== this._authProvider
);
@@ -89,21 +81,83 @@ export class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
return html`
<style>
ha-pick-auth-provider {
display: block;
margin-top: 48px;
}
ha-auth-flow {
display: block;
margin-top: 24px;
}
ha-auth-flow,
ha-local-auth-flow {
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
}
ha-alert {
display: block;
margin: 16px 0;
background-color: var(--primary-background-color, #fafafa);
}
p {
font-size: 14px;
line-height: 20px;
}
.card-content {
background: var(
--ha-card-background,
var(--card-background-color, white)
);
box-shadow: var(--ha-card-box-shadow, none);
box-sizing: border-box;
border-radius: var(--ha-card-border-radius, 12px);
border-width: var(--ha-card-border-width, 1px);
border-style: solid;
border-color: var(
--ha-card-border-color,
var(--divider-color, #e0e0e0)
);
color: var(--primary-text-color);
position: relative;
padding: 16px;
}
.action {
margin: 16px 0 8px;
display: flex;
width: 100%;
max-width: 336px;
justify-content: center;
}
.space-between {
justify-content: space-between;
}
.footer {
padding-top: 8px;
display: flex;
justify-content: space-between;
align-items: center;
}
ha-language-picker {
width: 200px;
border-radius: 4px;
overflow: hidden;
--ha-select-height: 40px;
--mdc-select-fill-color: none;
--mdc-select-label-ink-color: var(--primary-text-color, #212121);
--mdc-select-ink-color: var(--primary-text-color, #212121);
--mdc-select-idle-line-color: transparent;
--mdc-select-hover-line-color: transparent;
--mdc-select-dropdown-icon-color: var(--primary-text-color, #212121);
--mdc-shape-small: 0;
}
.footer a {
text-decoration: none;
color: var(--primary-text-color);
margin-right: 16px;
}
h1 {
font-size: 28px;
font-weight: 400;
margin-top: 16px;
margin-bottom: 16px;
}
</style>
${!this._ownInstance
@@ -120,33 +174,61 @@ export class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
>`,
})}
</ha-alert>`
: html`<p>${this.localize("ui.panel.page-authorize.authorizing")}</p>`}
${inactiveProviders.length > 0
? html`<p>
${this.localize("ui.panel.page-authorize.logging_in_with", {
authProviderName: html`<b>${this._authProvider!.name}</b>`,
})}
</p>`
: nothing}
<ha-auth-flow
.clientId=${this.clientId}
.redirectUri=${this.redirectUri}
.oauth2State=${this.oauth2State}
.authProvider=${this._authProvider}
.localize=${this.localize}
></ha-auth-flow>
${inactiveProviders.length > 0
? html`
<ha-pick-auth-provider
.localize=${this.localize}
.clientId=${this.clientId}
.authProviders=${inactiveProviders}
@pick-auth-provider=${this._handleAuthProviderPick}
></ha-pick-auth-provider>
`
: ""}
<div
class="card-content"
@default-login-flow=${this._handleDefaultLoginFlow}
>
${!this._authProvider
? html`<p>
${this.localize("ui.panel.page-authorize.initializing")}
</p> `
: !this._forceDefaultLogin &&
this._authProvider!.users &&
this.clientId != null &&
this.redirectUri != null
? html`<ha-local-auth-flow
.clientId=${this.clientId}
.redirectUri=${this.redirectUri}
.oauth2State=${this.oauth2State}
.authProvider=${this._authProvider}
.authProviders=${this._authProviders}
.localize=${this.localize}
.ownInstance=${this._ownInstance}
></ha-local-auth-flow>`
: html`<ha-auth-flow
.clientId=${this.clientId}
.redirectUri=${this.redirectUri}
.oauth2State=${this.oauth2State}
.authProvider=${this._authProvider}
.localize=${this.localize}
></ha-auth-flow>
${inactiveProviders!.length > 0
? html`
<ha-pick-auth-provider
.localize=${this.localize}
.clientId=${this.clientId}
.authProviders=${inactiveProviders}
@pick-auth-provider=${this._handleAuthProviderPick}
></ha-pick-auth-provider>
`
: ""}`}
</div>
<div class="footer">
<ha-language-picker
.value=${this.language}
.label=${""}
nativeName
@value-changed=${this._languageChanged}
></ha-language-picker>
<a
href="https://www.home-assistant.io/docs/authentication/"
target="_blank"
rel="noreferrer noopener"
>${this.localize("ui.panel.page-authorize.help")}</a
>
</div>
`;
}
@@ -199,12 +281,18 @@ export class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
);
}
if (window.innerWidth > 450) {
import("../resources/particles");
}
// If we are logging into the instance that is hosting this auth form
// we will register the service worker to start preloading.
if (url.host === location.host) {
this._ownInstance = true;
registerServiceWorker(this, false);
}
import("../components/ha-language-picker");
}
protected updated(changedProps: PropertyValues) {
@@ -245,7 +333,22 @@ export class HaAuthorize extends litLocalizeLiteMixin(LitElement) {
}
}
private _handleDefaultLoginFlow(ev) {
this._forceDefaultLogin = ev.detail.value;
}
private async _handleAuthProviderPick(ev) {
this._authProvider = ev.detail;
}
private _languageChanged(ev: CustomEvent) {
const language = ev.detail.value;
this.language = language;
try {
localStorage.setItem("selectedLanguage", JSON.stringify(language));
} catch (err: any) {
// Ignore
}
}
}
+485
View File
@@ -0,0 +1,485 @@
/* eslint-disable lit/prefer-static-styles */
import "@material/mwc-button";
import { mdiEye, mdiEyeOff } from "@mdi/js";
import { html, LitElement, nothing, PropertyValues } from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../common/dom/fire_event";
import { LocalizeFunc } from "../common/translations/localize";
import "../components/ha-alert";
import "../components/ha-button";
import "../components/ha-icon-button";
import "../components/user/ha-person-badge";
import {
AuthProvider,
createLoginFlow,
deleteLoginFlow,
redirectWithAuthCode,
submitLoginFlow,
} from "../data/auth";
import { DataEntryFlowStep } from "../data/data_entry_flow";
import { BasePerson, listUserPersons } from "../data/person";
import "./ha-auth-textfield";
import type { HaAuthTextField } from "./ha-auth-textfield";
@customElement("ha-local-auth-flow")
export class HaLocalAuthFlow extends LitElement {
@property({ attribute: false }) public authProvider?: AuthProvider;
@property({ attribute: false }) public authProviders?: AuthProvider[];
@property() public clientId?: string;
@property() public redirectUri?: string;
@property() public oauth2State?: string;
@property({ type: Boolean }) public ownInstance = false;
@property() public localize!: LocalizeFunc;
@state() private _error?: string;
@state() private _step?: DataEntryFlowStep;
@state() private _submitting = false;
@state() private _persons?: Record<string, BasePerson>;
@state() private _selectedUser?: string;
@state() private _unmaskedPassword = false;
createRenderRoot() {
return this;
}
willUpdate(changedProps: PropertyValues) {
super.willUpdate(changedProps);
if (!this.hasUpdated) {
this._load();
}
}
protected render() {
if (!this.authProvider?.users || !this._persons) {
return nothing;
}
const userIds = Object.keys(this.authProvider.users).filter(
(userId) => userId in this._persons!
);
return html`
<style>
.content {
max-width: 560px;
}
.persons {
margin-top: 24px;
display: flex;
flex-wrap: wrap;
gap: 16px;
justify-content: center;
}
.persons.force-small {
max-width: 350px;
}
.person {
display: flex;
flex-direction: column;
align-items: center;
flex-shrink: 0;
text-align: center;
cursor: pointer;
width: 80px;
}
.person[role="button"] {
outline: none;
padding: 8px;
border-radius: 4px;
}
.person[role="button"]:focus-visible {
background: rgba(var(--rgb-primary-color), 0.1);
}
.person p {
margin-bottom: 0;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
width: 100%;
}
ha-person-badge {
width: 80px;
height: 80px;
--person-badge-font-size: 2em;
}
form {
width: 100%;
}
ha-auth-textfield {
display: block !important;
position: relative;
}
ha-auth-textfield ha-icon-button {
position: absolute;
top: 4px;
right: 4px;
z-index: 9;
}
.login-form {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
max-width: 336px;
margin-top: 24px;
}
.login-form .person {
cursor: default;
width: auto;
}
.login-form .person p {
font-size: 28px;
margin-top: 24px;
margin-bottom: 32px;
line-height: normal;
}
.login-form ha-person-badge {
width: 120px;
height: 120px;
--person-badge-font-size: 3em;
}
ha-list-item {
margin-top: 16px;
}
ha-button {
--mdc-typography-button-text-transform: none;
}
.forgot-password-container {
text-align: right;
padding: 8px 0 16px 0;
}
a.forgot-password {
color: var(--primary-color);
text-decoration: none;
font-size: 0.875rem;
}
button {
color: var(--primary-color);
background: none;
border: none;
padding: 8px;
font: inherit;
font-size: 0.875rem;
text-align: left;
cursor: pointer;
outline: none;
border-radius: 4px;
}
button:focus-visible {
background: rgba(var(--rgb-primary-color), 0.1);
}
</style>
${this._error
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
: nothing}
${this._step
? html`<ha-auth-flow
.clientId=${this.clientId}
.redirectUri=${this.redirectUri}
.oauth2State=${this.oauth2State}
.step=${this._step}
storeToken
.localize=${this.localize}
></ha-auth-flow>`
: this._selectedUser
? html`<div class="login-form">
<div class="person">
<ha-person-badge
.person=${this._persons[this._selectedUser]}
></ha-person-badge>
<p>${this._persons[this._selectedUser].name}</p>
</div>
<form>
<input
type="hidden"
name="username"
autocomplete="username"
readonly
.value=${this.authProvider.users[this._selectedUser]}
/>
<ha-auth-textfield
.type=${this._unmaskedPassword ? "text" : "password"}
autocomplete="current-password"
id="password"
name="password"
.label=${this.localize(
"ui.panel.page-authorize.form.providers.homeassistant.step.init.data.password"
)}
required
autoValidate
iconTrailing
validationMessage="Required"
>
<ha-icon-button
toggles
.label=${this.localize(
this._unmaskedPassword
? "ui.panel.page-authorize.form.hide_password"
: "ui.panel.page-authorize.form.show_password"
) ||
(this._unmaskedPassword
? "Hide password"
: "Show password")}
@click=${this._toggleUnmaskedPassword}
.path=${this._unmaskedPassword ? mdiEyeOff : mdiEye}
></ha-icon-button>
</ha-auth-textfield>
<div class="forgot-password-container">
<a
class="forgot-password"
href="https://www.home-assistant.io/docs/locked_out/#forgot-password"
target="_blank"
rel="noreferrer noopener"
>${this.localize(
"ui.panel.page-authorize.forgot_password"
)}</a
>
</div>
<div class="action space-between">
<mwc-button
@click=${this._restart}
.disabled=${this._submitting}
>
${this.localize("ui.panel.page-authorize.form.previous")}
</mwc-button>
<mwc-button
raised
@click=${this._handleSubmit}
.disabled=${this._submitting}
>
${this.localize("ui.panel.page-authorize.form.next")}
</mwc-button>
</div>
</form>
</div>`
: html`<h1>
${this.localize("ui.panel.page-authorize.welcome_home")}
</h1>
${this.localize("ui.panel.page-authorize.who_is_logging_in")}
<div
class="persons ${userIds.length < 10 && userIds.length % 4 === 1
? "force-small"
: ""}"
>
${userIds.map((userId) => {
const person = this._persons![userId];
return html`<div
class="person"
.userId=${userId}
@click=${this._personSelected}
@keyup=${this._handleKeyUp}
role="button"
tabindex="0"
>
<ha-person-badge .person=${person}></ha-person-badge>
<p>${person.name}</p>
</div>`;
})}
</div>
<div class="action">
<button @click=${this._otherLogin} tabindex="0">
${this.localize("ui.panel.page-authorize.other_options")}
</button>
</div>`}
`;
}
protected firstUpdated(changedProps: PropertyValues) {
super.firstUpdated(changedProps);
this.addEventListener("keypress", (ev) => {
if (ev.key === "Enter") {
this._handleSubmit(ev);
}
});
}
protected updated(changedProps: PropertyValues) {
if (changedProps.has("_selectedUser") && this._selectedUser) {
const passwordElement = this.renderRoot.querySelector(
"#password"
) as HaAuthTextField;
passwordElement.updateComplete.then(() => {
passwordElement.focus();
});
}
}
private async _load() {
try {
this._persons = await listUserPersons();
} catch {
this._persons = {};
this._error = "Failed to fetch persons";
}
}
private _restart() {
this._selectedUser = undefined;
this._error = undefined;
}
private _toggleUnmaskedPassword() {
this._unmaskedPassword = !this._unmaskedPassword;
}
private _handleKeyUp(ev: KeyboardEvent) {
if (ev.key === "Enter" || ev.key === " ") {
this._personSelected(ev);
}
}
private async _personSelected(ev) {
const userId = ev.currentTarget.userId;
if (
this.ownInstance &&
this.authProviders?.find((prv) => prv.type === "trusted_networks")
) {
try {
const flowResponse = await createLoginFlow(
this.clientId,
this.redirectUri,
["trusted_networks", null]
);
const data = await flowResponse.json();
if (data.type === "create_entry") {
redirectWithAuthCode(
this.redirectUri!,
data.result,
this.oauth2State,
true
);
return;
}
try {
if (!data.data_schema[0].options.find((opt) => opt[0] === userId)) {
throw new Error("User not available");
}
const postData = { user: userId, client_id: this.clientId };
const response = await submitLoginFlow(data.flow_id, postData);
if (response.ok) {
const result = await response.json();
if (result.type === "create_entry") {
redirectWithAuthCode(
this.redirectUri!,
result.result,
this.oauth2State,
true
);
return;
}
} else {
throw new Error("Invalid response");
}
} catch {
deleteLoginFlow(data.flow_id).catch((err) => {
// eslint-disable-next-line no-console
console.error("Error delete obsoleted auth flow", err);
});
}
} catch {
// Ignore
}
}
this._selectedUser = userId;
}
private async _handleSubmit(ev: Event) {
ev.preventDefault();
if (!this.authProvider?.users || !this._selectedUser) {
return;
}
this._error = undefined;
this._submitting = true;
const flowResponse = await createLoginFlow(
this.clientId,
this.redirectUri,
["homeassistant", null]
);
const data = await flowResponse.json();
const postData = {
username: this.authProvider.users[this._selectedUser],
password: (this.renderRoot.querySelector("#password") as HaAuthTextField)
.value,
client_id: this.clientId,
};
try {
const response = await submitLoginFlow(data.flow_id, postData);
const newStep = await response.json();
if (response.status === 403) {
this._error = newStep.message;
return;
}
if (newStep.type === "create_entry") {
redirectWithAuthCode(
this.redirectUri!,
newStep.result,
this.oauth2State,
true
);
return;
}
if (newStep.errors.base) {
this._error = this.localize(
`ui.panel.page-authorize.form.providers.homeassistant.error.${newStep.errors.base}`
);
throw new Error(this._error);
}
this._step = newStep;
} catch {
deleteLoginFlow(data.flow_id).catch((err) => {
// eslint-disable-next-line no-console
console.error("Error delete obsoleted auth flow", err);
});
if (!this._error) {
this._error = this.localize(
"ui.panel.page-authorize.form.unknown_error"
);
}
} finally {
this._submitting = false;
}
}
private _otherLogin() {
fireEvent(this, "default-login-flow", { value: true });
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-local-auth-flow": HaLocalAuthFlow;
}
interface HASSDomEvents {
"default-login-flow": { value: boolean };
}
}
+33 -7
View File
@@ -21,7 +21,11 @@ export class HaPickAuthProvider extends LitElement {
protected render() {
return html`
<p>${this.localize("ui.panel.page-authorize.pick_auth_provider")}:</p>
<h3>
<span
>${this.localize("ui.panel.page-authorize.pick_auth_provider")}</span
>
</h3>
<mwc-list>
${this.authProviders.map(
(provider) => html`
@@ -35,8 +39,8 @@ export class HaPickAuthProvider extends LitElement {
<ha-icon-next slot="meta"></ha-icon-next>
</ha-list-item>
`
)}</mwc-list
>
)}
</mwc-list>
`;
}
@@ -45,12 +49,34 @@ export class HaPickAuthProvider extends LitElement {
}
static styles = css`
p {
margin-top: 0;
h3 {
margin: 0 -16px;
position: relative;
z-index: 1;
text-align: center;
font-size: 14px;
font-weight: 400;
line-height: 20px;
}
h3:before {
border-top: 1px solid var(--divider-color);
content: "";
margin: 0 auto;
position: absolute;
top: 50%;
left: 0;
right: 0;
bottom: 0;
width: 100%;
z-index: -1;
}
h3 span {
background: var(--card-background-color);
padding: 0 15px;
}
mwc-list {
margin: 0 -16px;
--mdc-list-side-padding: 16px;
margin: 16px -16px 0;
--mdc-list-side-padding: 24px;
}
`;
}
+2 -2
View File
@@ -58,10 +58,10 @@ const matchMaxScale = (
return outputColors.map((value) => Math.round(value * factor));
};
const mired2kelvin = (miredTemperature: number) =>
export const mired2kelvin = (miredTemperature: number) =>
Math.floor(1000000 / miredTemperature);
const kelvin2mired = (kelvintTemperature: number) =>
export const kelvin2mired = (kelvintTemperature: number) =>
Math.floor(1000000 / kelvintTemperature);
export const rgbww2rgb = (
+4 -4
View File
@@ -10,10 +10,10 @@ const isLoadedIntegration = (hass: HomeAssistant, page: PageNavigation) =>
page.component
? isComponentLoaded(hass, page.component)
: page.components
? page.components.some((integration) =>
isComponentLoaded(hass, integration)
)
: true;
? page.components.some((integration) =>
isComponentLoaded(hass, integration)
)
: true;
const isCore = (page: PageNavigation) => page.core;
const isAdvancedPage = (page: PageNavigation) => page.advancedOnly;
const userWantsAdvanced = (hass: HomeAssistant) => hass.userData?.showAdvanced;
+1
View File
@@ -203,6 +203,7 @@ export const DOMAINS_WITH_CARD = [
"select",
"timer",
"text",
"update",
"vacuum",
"water_heater",
];
-33
View File
@@ -1,33 +0,0 @@
/**
* Update root's child element to be newElementTag replacing another existing child if any.
* Copy attributes into the child element.
*/
export default function dynamicContentUpdater(root, newElementTag, attributes) {
const rootEl = root;
let customEl;
if (rootEl.lastChild && rootEl.lastChild.tagName === newElementTag) {
customEl = rootEl.lastChild;
} else {
if (rootEl.lastChild) {
rootEl.removeChild(rootEl.lastChild);
}
// Creating an element with upper case works fine in Chrome, but in FF it doesn't immediately
// become a defined Custom Element. Polymer does that in some later pass.
customEl = document.createElement(newElementTag.toLowerCase());
}
if (customEl.setProperties) {
customEl.setProperties(attributes);
} else {
// If custom element definition wasn't loaded yet - setProperties would be
// missing, but no harm in setting attributes one-by-one then.
Object.keys(attributes).forEach((key) => {
customEl[key] = attributes[key];
});
}
if (customEl.parentNode === null) {
rootEl.appendChild(customEl);
}
}
+2 -2
View File
@@ -4,5 +4,5 @@ export const mainWindow =
window.name === MAIN_WINDOW_NAME
? window
: parent.name === MAIN_WINDOW_NAME
? parent
: top!;
? parent
: top!;
+11 -19
View File
@@ -1,5 +1,6 @@
import { HassConfig, HassEntity } from "home-assistant-js-websocket";
import {
DOMAIN_ATTRIBUTES_FORMATERS,
DOMAIN_ATTRIBUTES_UNITS,
TEMPERATURE_ATTRIBUTES,
} from "../../data/entity_attributes";
@@ -14,7 +15,7 @@ import { formatNumber } from "../number/format_number";
import { capitalizeFirstLetter } from "../string/capitalize-first-letter";
import { isDate } from "../string/is_date";
import { isTimestamp } from "../string/is_timestamp";
import { blankBeforePercent } from "../translations/blank_before_percent";
import { blankBeforeUnit } from "../translations/blank_before_unit";
import { LocalizeFunc } from "../translations/localize";
import { computeDomain } from "./compute_domain";
import { computeStateDomain } from "./compute_state_domain";
@@ -38,37 +39,28 @@ export const computeAttributeValueDisplay = (
// Number value, return formatted number
if (typeof attributeValue === "number") {
const formattedValue = formatNumber(attributeValue, locale);
const domain = computeStateDomain(stateObj);
const formatter = DOMAIN_ATTRIBUTES_FORMATERS[domain]?.[attribute];
const formattedValue = formatter
? formatter(attributeValue, locale)
: formatNumber(attributeValue, locale);
let unit = DOMAIN_ATTRIBUTES_UNITS[domain]?.[attribute] as
| string
| undefined;
if (domain === "light" && attribute === "brightness") {
const percentage = Math.round((attributeValue / 255) * 100);
return `${percentage}${blankBeforePercent(locale)}%`;
}
if (domain === "weather") {
unit = getWeatherUnit(config, stateObj as WeatherEntity, attribute);
}
if (unit === "%") {
return `${formattedValue}${blankBeforePercent(locale)}${unit}`;
}
if (unit === "°") {
return `${formattedValue}${unit}`;
if (TEMPERATURE_ATTRIBUTES.has(attribute)) {
unit = config.unit_system.temperature;
}
if (unit) {
return `${formattedValue} ${unit}`;
}
if (TEMPERATURE_ATTRIBUTES.has(attribute)) {
return `${formattedValue} ${config.unit_system.temperature}`;
return `${formattedValue}${blankBeforeUnit(unit, locale)}${unit}`;
}
return formattedValue;
+13 -35
View File
@@ -2,14 +2,10 @@ import { HassConfig, HassEntity } from "home-assistant-js-websocket";
import { UNAVAILABLE, UNKNOWN } from "../../data/entity";
import { EntityRegistryDisplayEntry } from "../../data/entity_registry";
import { FrontendLocaleData, TimeZone } from "../../data/translation";
import {
updateIsInstallingFromAttributes,
UPDATE_SUPPORT_PROGRESS,
} from "../../data/update";
import { HomeAssistant } from "../../types";
import {
formatDuration,
UNIT_TO_MILLISECOND_CONVERT,
formatDuration,
} from "../datetime/duration";
import { formatDate } from "../datetime/format_date";
import { formatDateTime } from "../datetime/format_date_time";
@@ -19,10 +15,9 @@ import {
getNumberFormatOptions,
isNumericFromAttributes,
} from "../number/format_number";
import { blankBeforePercent } from "../translations/blank_before_percent";
import { blankBeforeUnit } from "../translations/blank_before_unit";
import { LocalizeFunc } from "../translations/localize";
import { computeDomain } from "./compute_domain";
import { supportsFeatureFromAttributes } from "./supports-feature";
export const computeStateDisplaySingleEntity = (
localize: LocalizeFunc,
@@ -108,16 +103,20 @@ export const computeStateDisplayFromEntityAttributes = (
// fallback to default
}
}
const unit = !attributes.unit_of_measurement
? ""
: attributes.unit_of_measurement === "%"
? blankBeforePercent(locale) + "%"
: ` ${attributes.unit_of_measurement}`;
return `${formatNumber(
const value = formatNumber(
state,
locale,
getNumberFormatOptions({ state, attributes } as HassEntity, entity)
)}${unit}`;
);
const unit = attributes.unit_of_measurement;
if (unit) {
return `${value}${blankBeforeUnit(unit)}${unit}`;
}
return value;
}
const domain = computeDomain(entityId);
@@ -204,27 +203,6 @@ export const computeStateDisplayFromEntityAttributes = (
}
}
if (domain === "update") {
// When updating, and entity does not support % show "Installing"
// When updating, and entity does support % show "Installing (xx%)"
// When update available, show the version
// When the latest version is skipped, show the latest version
// When update is not available, show "Up-to-date"
// When update is not available and there is no latest_version show "Unavailable"
return state === "on"
? updateIsInstallingFromAttributes(attributes)
? supportsFeatureFromAttributes(attributes, UPDATE_SUPPORT_PROGRESS) &&
typeof attributes.in_progress === "number"
? localize("ui.card.update.installing_with_progress", {
progress: attributes.in_progress,
})
: localize("ui.card.update.installing")
: attributes.latest_version
: attributes.skipped_version === attributes.latest_version
? attributes.latest_version ?? localize("state.default.unavailable")
: localize("ui.card.update.up_to_date");
}
return (
(entity?.translation_key &&
localize(
+2 -2
View File
@@ -100,8 +100,8 @@ export const domainIconWithoutDefault = (
return compareState === "unavailable"
? mdiRobotConfused
: compareState === "off"
? mdiRobotOff
: mdiRobot;
? mdiRobotOff
: mdiRobot;
case "binary_sensor":
return binarySensorIcon(compareState, stateObj);
@@ -0,0 +1,15 @@
import { FrontendLocaleData } from "../../data/translation";
import { blankBeforePercent } from "./blank_before_percent";
export const blankBeforeUnit = (
unit: string,
localeOptions?: FrontendLocaleData
): string => {
if (unit === "°") {
return "";
}
if (localeOptions && unit === "%") {
return blankBeforePercent(localeOptions);
}
return " ";
};
+7 -1
View File
@@ -1,4 +1,5 @@
import IntlMessageFormat from "intl-messageformat";
import type { HTMLTemplateResult } from "lit";
import { polyfillLocaleData } from "../../resources/locale-data-polyfill";
import { Resources, TranslationDict } from "../../types";
@@ -40,9 +41,13 @@ export type FlattenObjectKeys<
: `${Key}`
: never;
// Later, don't return string when HTML is passed, and don't allow undefined
export type LocalizeFunc<Keys extends string = LocalizeKeys> = (
key: Keys,
...args: any[]
values?: Record<
string,
string | number | HTMLTemplateResult | null | undefined
>
) => string;
interface FormatType {
@@ -124,6 +129,7 @@ export const computeLocalize = async <Keys extends string = LocalizeKeys>(
argObject = args[0];
} else {
for (let i = 0; i < args.length; i += 2) {
// @ts-expect-error in some places the old format (key, value, key, value) is used
argObject[args[i]] = args[i + 1];
}
}
+1
View File
@@ -23,6 +23,7 @@ export function computeDirectionStyles(isRTL: boolean, element: LitElement) {
}
export function setDirectionStyles(direction: string, element: LitElement) {
document.dir = direction;
element.style.direction = direction;
element.style.setProperty("--direction", direction);
element.style.setProperty(
+9 -9
View File
@@ -40,15 +40,15 @@ export class HaProgressButton extends LitElement {
${this._result === "success"
? html`<ha-svg-icon .path=${mdiCheckBold}></ha-svg-icon>`
: this._result === "error"
? html`<ha-svg-icon .path=${mdiAlertOctagram}></ha-svg-icon>`
: this.progress
? html`
<ha-circular-progress
size="small"
active
></ha-circular-progress>
`
: ""}
? html`<ha-svg-icon .path=${mdiAlertOctagram}></ha-svg-icon>`
: this.progress
? html`
<ha-circular-progress
size="small"
indeterminate
></ha-circular-progress>
`
: ""}
</div>
`}
`;
+1 -1
View File
@@ -134,7 +134,7 @@ _adapters._date.override({
this.options.config
);
case "week":
return formatDate(
return formatDateVeryShort(
new Date(time),
this.options.locale,
this.options.config
+2
View File
@@ -469,6 +469,7 @@ export class HaChartBase extends LitElement {
.chartTooltip li {
display: flex;
white-space: pre-line;
word-break: break-word;
align-items: center;
line-height: 16px;
padding: 4px 0;
@@ -476,6 +477,7 @@ export class HaChartBase extends LitElement {
.chartTooltip .title {
text-align: center;
font-weight: 500;
word-break: break-word;
direction: ltr;
}
.chartTooltip .footer {
@@ -45,10 +45,14 @@ export class StateHistoryChartLine extends LitElement {
@property({ type: Number }) public chartIndex?;
@property({ type: Boolean }) public logarithmicScale = false;
@state() private _chartData?: ChartData<"line">;
@state() private _entityIds: string[] = [];
private _datasetToDataIndex: number[] = [];
@state() private _chartOptions?: ChartOptions;
@state() private _yWidth = 0;
@@ -78,7 +82,9 @@ export class StateHistoryChartLine extends LitElement {
!this.hasUpdated ||
changedProps.has("showNames") ||
changedProps.has("startTime") ||
changedProps.has("endTime")
changedProps.has("endTime") ||
changedProps.has("unit") ||
changedProps.has("logarithmicScale")
) {
this._chartOptions = {
parsing: false,
@@ -132,20 +138,38 @@ export class StateHistoryChartLine extends LitElement {
}
},
position: computeRTL(this.hass) ? "right" : "left",
type: this.logarithmicScale ? "logarithmic" : "linear",
},
},
plugins: {
tooltip: {
callbacks: {
label: (context) =>
`${context.dataset.label}: ${formatNumber(
label: (context) => {
let label = `${context.dataset.label}: ${formatNumber(
context.parsed.y,
this.hass.locale,
getNumberFormatOptions(
undefined,
this.hass.entities[this._entityIds[context.datasetIndex]]
)
)} ${this.unit}`,
)} ${this.unit}`;
const dataIndex =
this._datasetToDataIndex[context.datasetIndex];
const data = this.data[dataIndex];
if (data.statistics && data.statistics.length > 0) {
const source =
data.states.length === 0 ||
context.parsed.x < data.states[0].last_changed
? `\n${this.hass.localize(
"ui.components.history_charts.source_stats"
)}`
: `\n${this.hass.localize(
"ui.components.history_charts.source_history"
)}`;
label += source;
}
return label;
},
},
},
filler: {
@@ -167,6 +191,19 @@ export class StateHistoryChartLine extends LitElement {
hitRadius: 50,
},
},
segment: {
borderColor: (context) => {
// render stat data with a slightly transparent line
const dataIndex = this._datasetToDataIndex[context.datasetIndex];
const data = this.data[dataIndex];
return data.statistics &&
data.statistics.length > 0 &&
(data.states.length === 0 ||
context.p0.parsed.x < data.states[0].last_changed)
? this._chartData!.datasets[dataIndex].borderColor + "7F"
: undefined;
},
},
// @ts-expect-error
locale: numberFormatToLocale(this.hass.locale),
onClick: (e: any) => {
@@ -212,6 +249,7 @@ export class StateHistoryChartLine extends LitElement {
const entityStates = this.data;
const datasets: ChartDataset<"line">[] = [];
const entityIds: string[] = [];
const datasetToDataIndex: number[] = [];
if (entityStates.length === 0) {
return;
}
@@ -219,7 +257,7 @@ export class StateHistoryChartLine extends LitElement {
this._chartTime = new Date();
const endTime = this.endTime;
const names = this.names || {};
entityStates.forEach((states) => {
entityStates.forEach((states, dataIdx) => {
const domain = states.domain;
const name = names[states.entity_id] || states.name;
// array containing [value1, value2, etc]
@@ -264,6 +302,7 @@ export class StateHistoryChartLine extends LitElement {
data: [],
});
entityIds.push(states.entity_id);
datasetToDataIndex.push(dataIdx);
};
if (
@@ -470,7 +509,7 @@ export class StateHistoryChartLine extends LitElement {
// Process chart data.
// When state is `unknown`, calculate the value and break the line.
states.states.forEach((entityState) => {
const processData = (entityState: LineChartState) => {
const value = safeParseFloat(entityState.state);
const date = new Date(entityState.last_changed);
if (value !== null && lastNullDate) {
@@ -499,6 +538,22 @@ export class StateHistoryChartLine extends LitElement {
) {
lastNullDate = date;
}
};
if (states.statistics) {
const stopTime =
!states.states || states.states.length === 0
? 0
: states.states[0].last_changed;
for (let i = 0; i < states.statistics.length; i++) {
if (stopTime && states.statistics[i].last_changed >= stopTime) {
break;
}
processData(states.statistics[i]);
}
}
states.states.forEach((entityState) => {
processData(entityState);
});
if (lastNullDate !== null) {
pushData(lastNullDate, [null]);
@@ -516,6 +571,7 @@ export class StateHistoryChartLine extends LitElement {
datasets,
};
this._entityIds = entityIds;
this._datasetToDataIndex = datasetToDataIndex;
}
}
customElements.define("state-history-chart-line", StateHistoryChartLine);

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