Compare commits

..

248 Commits

Author SHA1 Message Date
Paul Bottein
c080ebbf46 Add user selector with multiple and system option 2023-10-31 11:19:16 +01:00
dependabot[bot]
c3d809fcf3 Bump actions/setup-node from 3.8.1 to 4.0.0 (#18468)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-30 11:18:14 +01:00
renovate[bot]
cbd0c39091 Update formatjs monorepo (#18423) 2023-10-29 22:05:19 -04:00
renovate[bot]
113eb5be24 Update dependency eslint-plugin-lit to v1.10.1 (#18460) 2023-10-28 21:45:57 -04:00
renovate[bot]
c497669fd3 Update dependency ts-lit-plugin to v2.0.0 (#18459) 2023-10-29 01:39:04 +00:00
renovate[bot]
c32ca5885b Update dependency lit-analyzer to v2.0.1 (#18458) 2023-10-28 21:28:01 -04:00
renovate[bot]
3c792c4019 Update dependency @bundle-stats/plugin-webpack-filter to v4.7.8 (#18457) 2023-10-28 21:23:43 -04:00
renovate[bot]
9762e61ee2 Update vaadinWebComponents monorepo to v24.2.1 (#18454)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-28 20:36:52 +00:00
renovate[bot]
c09c39998b Update dependency vue to v2.7.15 (#18424)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-28 16:22:32 -04:00
renovate[bot]
d37e29c247 Update CodeMirror (#18453)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-28 16:20:45 -04:00
renovate[bot]
51f22cd74a Update dependency eslint-import-resolver-webpack to v0.13.8 (#18422)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-28 16:12:52 -04:00
renovate[bot]
b57dc968bd Update dependency eslint-plugin-import to v2.29.0 (#18425)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-28 16:07:23 -04:00
renovate[bot]
e2e8cb785a Update typescript-eslint monorepo to v6.9.0 (#18433)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-28 16:06:02 -04:00
Bram Kragten
9961a4ae3f Bumped version to 20231027.0 2023-10-27 16:33:32 +02:00
Bram Kragten
c25755bfcd Translate todo panel title, update assist title/icon (#18442) 2023-10-27 16:33:02 +02:00
Bram Kragten
40983619d6 Reload when entering safe mode (#18443) 2023-10-27 15:48:01 +02:00
Bram Kragten
54758b5962 Don't override ranges provided by parent (#18444) 2023-10-27 15:47:47 +02:00
Bram Kragten
4f09485b20 Update todo list items when entity changes, only refresh on shopping … (#18445) 2023-10-27 15:47:37 +02:00
Paul Bottein
9207f6c407 Fix unit of measurement not displayed in entity settings (#18440) 2023-10-27 13:29:41 +02:00
Paul Bottein
1a2312460a Disable resource panel in safe mode (#18437) 2023-10-27 13:29:00 +02:00
Simon Lamon
951b88ab4c Fix change entity in dev tools state (#18441) 2023-10-27 13:27:01 +02:00
Bram Kragten
d3cc57d8b4 Don't use lookbehind assertion in slugify (#18438) 2023-10-27 12:53:17 +02:00
karwosts
4e9b118728 Ensure energy card titles always displayed (#18432) 2023-10-27 10:42:01 +02:00
Paul Bottein
f1748e4dd5 Bumped version to 20231026.0 2023-10-26 15:39:36 +02:00
Paul Bottein
d491d8f5ac Quick fix for lovelace resources not loaded (#18430) 2023-10-26 15:37:31 +02:00
Bram Kragten
cf0fde0f3c Change move item todo API (#18410)
* Change move item todo API

* Handle entity unavailable, add link to more info, allow to delete local todo
2023-10-26 15:37:13 +02:00
Paul Bottein
a7dc2cfaa6 Reduce slider handle size (#18427) 2023-10-26 15:25:47 +02:00
Paul Bottein
d8c7db6ebf Add translations to tile state content options (#18428) 2023-10-26 10:32:09 +00:00
J. Nick Koston
c3743b57ea Speed up first load by preloading recorder info (#18412) 2023-10-25 19:29:44 +00:00
Steve Repsher
e16a101de8 Compress service worker (#18407) 2023-10-25 17:17:11 +02:00
Paul Bottein
94ad47c60e Hide reveal icon on edge for text-field (#18408) 2023-10-25 17:15:43 +02:00
Bram Kragten
184ef7b7ff Bar media player fixes (#18402) 2023-10-25 16:04:05 +02:00
karwosts
81053f2e07 Fix an undefined exception in more-info popup for history graph (#18404) 2023-10-25 15:48:05 +02:00
Paul Bottein
e8b4eeec67 Allow any number in above and below numeric condition (#18403) 2023-10-25 13:38:39 +00:00
karwosts
b0b7e77e28 Fix schedule form rendering after disconnect (#18401) 2023-10-25 13:21:05 +00:00
Bram Kragten
763f80b46a Bumped version to 20231025.1 2023-10-25 13:59:11 +02:00
Bram Kragten
0c2531a7ee Update todo list card (#18396) 2023-10-25 13:57:50 +02:00
Paul Bottein
8d2ec8098c Fix state not condition for condition card (#18397) 2023-10-25 11:09:28 +00:00
Bram Kragten
d2caed2b68 Merge branch 'master' into dev 2023-10-25 11:51:01 +02:00
Jan-Philipp Benecke
402d443843 Add mac and bluetooth address to the device info card (#18392)
Co-authored-by: Paul Bottein <paul.bottein@gmail.com>
2023-10-25 11:47:54 +02:00
Bram Kragten
399f12194a Bumped version to 20231025.0 2023-10-25 11:47:02 +02:00
Bram Kragten
a745539c33 fix height issue calendar, make default on mobile list (#18394) 2023-10-25 11:46:28 +02:00
Bram Kragten
f6fddbc6ec Add create todo list button (#18387) 2023-10-25 11:38:45 +02:00
Steve Repsher
01f51f3247 Cache brand images (#17840) 2023-10-25 09:28:28 +02:00
karwosts
80112bb662 Add Fields to Script UI (#18250) 2023-10-25 09:23:15 +02:00
Jan-Philipp Benecke
7ce7cbb755 Add serial number to the device info card (#18386)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
Co-authored-by: Franck Nijhof <frenck@frenck.nl>
Co-authored-by: Franck Nijhof <git@frenck.dev>
2023-10-25 06:32:24 +02:00
karwosts
464ecffda7 Fix a crash in trace graph generation for if/else (#18390) 2023-10-24 23:18:21 +00:00
Paul Bottein
33e0c691c7 Use expansion panel for dashboard conditions (#18380) 2023-10-25 00:45:55 +02:00
c0ffeeca7
d94f7c90c0 Restart dialog description: consistently use indicative form (#18385)
Co-authored-by: Franck Nijhof <git@frenck.dev>
2023-10-24 23:39:23 +02:00
Raman Gupta
d8d16c4d5f Add Z-Wave controller hard reset device action (certification req) (#18216)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2023-10-24 23:16:21 +02:00
Bram Kragten
1cb238ec2a Fixes for todo card (#18388) 2023-10-24 22:53:54 +02:00
karwosts
3e6ab8b179 Chart updates to improve stability, possible fix for infinite loop (#18329)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2023-10-24 20:41:34 +00:00
Bram Kragten
10bcaadcdb center icons in restart dialog 2023-10-24 21:21:02 +02:00
Bram Kragten
67517643ef Add safe mode theme and alert dialog 2023-10-24 21:08:23 +02:00
Paul Bottein
eb35eb3de5 Disable dashboard resources in safe mode (#18382) 2023-10-24 20:15:11 +02:00
Paul Bottein
8350d71f6e Add restart in safe mode in restart dialog (#18375) 2023-10-24 20:09:54 +02:00
Paul Bottein
c840f1cbb1 Redesign about page (#18383) 2023-10-24 20:07:12 +02:00
Bram Kragten
8efc0816bb Rename shopping-list-card to todo-list-card (#18378) 2023-10-24 20:06:03 +02:00
J. Nick Koston
b12e4989db Subscribe to the issue registry as early as possible (#18384) 2023-10-24 19:34:47 +02:00
Bram Kragten
2b67731906 Add resize observer to full calendar, fix missing styles (#18381) 2023-10-24 19:33:15 +02:00
Bram Kragten
ccba7a7623 Add button to create local calendar in calendar panel (#18377) 2023-10-24 19:33:03 +02:00
Bram Kragten
c0dfc9f73e Performance tweaks in energy dashboard (#18379)
* Remove unneeded refresh from energy panel

* Optimize energy-period-selector
2023-10-24 18:18:29 +02:00
Bram Kragten
be1624f66f Convert shopping list card editor to ha-form (#18376)
* Convert shopping list card editor to ha-form

* hide todo from generated dashboard
2023-10-24 18:14:14 +02:00
Steve Repsher
32edbd7b33 Remove js-yaml resource proxy (#18369) 2023-10-24 14:17:25 +02:00
Josh McCarty
18827db9ba Add bottom padding to code editor (#18368) 2023-10-24 12:59:14 +02:00
karwosts
191250a66a Fix complex attribute display in devtools (#18371) 2023-10-24 12:57:36 +02:00
Erik Montnemery
1fdf609606 Rename safe mode to recovery mode (#18374)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2023-10-24 12:56:27 +02:00
Paul Bottein
6ffc0625d3 Add support for state content customization in tile card (#18180)
* Add support for state content customization

* Add reorder option

* Do not display null attributes

* Always return a value

* Add hide state option

* Add missing attribute unit

* Fix sortable create and destroy
2023-10-24 12:08:11 +02:00
Allen Porter
c9f5d16745 Rename status code string for To-do List NEEDS-ACTION status (#18373) 2023-10-24 12:07:36 +02:00
renovate[bot]
eb4afedf2e Update dependency eslint to v8.52.0 (#18370) 2023-10-23 20:46:04 -04:00
Bram Kragten
2b9540fe03 Add support for todo component (#18289) 2023-10-23 22:53:09 +02:00
renovate[bot]
53b8d1bb0a Update dependency sinon to v17 (#18346)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-23 15:18:23 +00:00
Simon Lamon
0ff5bffd0c Make time condition translatable (#18298) 2023-10-23 17:02:51 +02:00
Paul Bottein
82a464f50f Add translation to numeric condition card 2023-10-23 16:37:27 +02:00
Paul Bottein
fdddc18291 Add numeric state condition for conditional card (#18288)
* Add numeric state condition for conditional card

* Add validate ui

* Clean entity data

* Check for numeric state
2023-10-23 14:17:23 +00:00
Bram Kragten
463a3244cf Add two pane view to calendar panel (#18286)
Co-authored-by: Paul Bottein <paul.bottein@gmail.com>
2023-10-23 14:13:38 +00:00
karwosts
6cae11f0a6 Update statistics chart to respect entity display precision, fix precision bug in history chart (#18334) 2023-10-23 16:03:42 +02:00
renovate[bot]
65112b36ce Update dependency @material/web to v1.0.1 (#18335)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-23 15:53:18 +02:00
renovate[bot]
58625d2a9d Update dependency core-js to v3.33.1 (#18339)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-23 15:50:55 +02:00
Paul Bottein
9bafbdd989 Allow multiple states in conditional card (#18273)
* Allow multiple states in conditional card

* Update src/panels/lovelace/editor/conditions/types/ha-card-condition-state.ts

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

---------

Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2023-10-23 13:49:43 +00:00
Paul Bottein
eedb42b2f3 Add user condition to conditional card (#18265)
* Add user condition to conditional card

* Refactor user fetch

* Add validate ui

* Use ha-check-list-item
2023-10-23 13:49:27 +00:00
Paul Bottein
4354ad3807 Move condition editor into its own file (#18340) 2023-10-23 15:31:49 +02:00
Paul Bottein
aeaf091b50 Use sensor device class for graph and precision (#18099)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2023-10-23 15:01:24 +02:00
Paul Bottein
c6be4d6f4d Improve warning messages in conditional card (#18272)
* Improve warning messages in conditional card

* Update src/panels/lovelace/editor/conditions/ha-card-condition-editor.ts

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

---------

Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2023-10-23 14:50:45 +02:00
Caius-Bonus
c48b620e03 Fix inconsistencies in slugify between frontend and core implementation (#18297) 2023-10-23 08:37:56 +00:00
Steve Repsher
77e05decdf Remove ondemand methods for CodeMirror and SortableJS (#18336) 2023-10-23 10:29:49 +02:00
Necroneco
b24e99c56c Fix oscillating handler in more info fan card (#18305) (#18306) 2023-10-23 10:26:31 +02:00
J. Nick Koston
768344c3f7 Fix double load of lovelace resources (#18332) 2023-10-23 10:05:26 +02:00
Bram Kragten
03a21d5519 Only calculate opening direction when we are opening the datepicker (#18313) 2023-10-23 09:58:20 +02:00
dependabot[bot]
1247a5c8d3 Bump home-assistant/wheels from 2023.10.4 to 2023.10.5 (#18338)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-23 09:54:53 +02:00
dependabot[bot]
db8287df89 Bump actions/checkout from 4.1.0 to 4.1.1 (#18337)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-23 09:03:17 +02:00
renovate[bot]
71edbd6352 Update dependency sinon to v16.1.3 (#18325)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-22 13:05:20 -04:00
renovate[bot]
9d87a66908 Update dependency lint-staged to v15.0.2 (#18326)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-22 13:03:45 -04:00
renovate[bot]
11d62cece2 Lock file maintenance (#18284)
* Lock file maintenance

* Add resolution to keep lit at v2

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Steve Repsher <steverep@users.noreply.github.com>
2023-10-22 03:34:14 +00:00
renovate[bot]
f15a65f5a6 Update dependency sinon to v16.1.1 (#18322)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-21 22:41:15 -04:00
renovate[bot]
a03d3f796b Update dependency @types/ua-parser-js to v0.7.38 (#18321) 2023-10-21 22:26:22 -04:00
renovate[bot]
d0f5b0e864 Update dependency @types/tar to v6.1.7 (#18320) 2023-10-21 23:43:59 +00:00
renovate[bot]
e4a67dd555 Update dependency @types/sortablejs to v1.15.4 (#18319) 2023-10-21 19:33:02 -04:00
renovate[bot]
f72ab94742 Update dependency @types/qrcode to v1.5.4 (#18317)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-21 23:22:48 +00:00
renovate[bot]
b521be6d3b Update dependency @types/serve-handler to v6.1.3 (#18318)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-21 19:11:27 -04:00
renovate[bot]
3fa7001be6 Update dependency @types/mocha to v10.0.3 (#18316)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-21 20:37:21 +00:00
renovate[bot]
b45226509b Update dependency @types/js-yaml to v4.0.8 (#18309)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-21 20:31:43 +00:00
renovate[bot]
2a5f8097bc Update dependency @types/luxon to v3.3.3 (#18315)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-21 16:24:47 -04:00
renovate[bot]
0ffe0f38e1 Update dependency @types/leaflet to v1.9.7 (#18310)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-21 20:19:23 +00:00
renovate[bot]
c48491088e Update dependency @codemirror/state to v6.3.1 (#18307)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-21 16:15:23 -04:00
renovate[bot]
f115e4025d Update dependency @types/html-minifier-terser to v7.0.1 (#18308)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-21 16:06:07 -04:00
renovate[bot]
7be8a799aa Update dependency @types/leaflet-draw to v1.0.9 (#18311)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-21 16:04:54 -04:00
karwosts
d992b2d40b Fix missing range labels in date-range-picker (#18274)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2023-10-21 15:40:38 +00:00
karwosts
96fbd8aefb Don't round statistic values before plotting (#18312) 2023-10-21 17:19:03 +02:00
renovate[bot]
17df761a1b Update dependency @types/esprima to v4.0.5 (#18304) 2023-10-20 23:44:38 -04:00
renovate[bot]
79b2fa96ed Update dependency @types/chromecast-caf-receiver to v6.0.11 (#18302) 2023-10-21 03:08:33 +00:00
renovate[bot]
c14e3333cf Update dependency @types/chromecast-caf-sender to v1.0.7 (#18303) 2023-10-20 22:56:56 -04:00
renovate[bot]
4af0ecbaa8 Update dependency @types/babel__plugin-transform-runtime to v7.9.4 (#18301) 2023-10-20 22:50:11 -04:00
Bram Kragten
ce11301516 Fix initial theming (#18296) 2023-10-20 20:44:53 +02:00
Josh McCarty
16766f8878 Wrap dict attributes (#18290) 2023-10-20 17:07:14 +02:00
renovate[bot]
5e933e8e15 Update typescript-eslint monorepo to v6.8.0 (#18292)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-19 23:28:11 -04:00
renovate[bot]
7eb92be84a Update formatjs monorepo (#18285)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-19 23:26:56 -04:00
Kendell R
60ec4d31db Fix some minor inconsistencies/duplications (#18071) 2023-10-19 17:29:05 +02:00
Steve Repsher
3526ba308f Remove unused imports from ZHA card and alias editor (#18282) 2023-10-19 17:17:27 +02:00
Steve Repsher
02a212a47d Load and set Polymer settings asynchronously (#18278) 2023-10-19 17:09:35 +02:00
Simon Vallières
49f88a98a5 Add multi-path icon support and path attributes (#18189) 2023-10-19 15:35:50 +02:00
Steve Repsher
feb371839c Fix yarn lock file (#18283) 2023-10-19 01:27:57 +02:00
renovate[bot]
24c37f5293 Update dependency @rollup/plugin-replace to v5.0.4 (#18280)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-18 18:25:15 -04:00
renovate[bot]
8f3fea5a33 Update dependency vis-network to v9.1.8 (#18281)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-18 18:24:28 -04:00
renovate[bot]
b2bc529d7b Update dependency @rollup/plugin-commonjs to v25.0.7 (#18279)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-18 18:23:24 -04:00
Jonas Lang
ad68782b79 Typo automation (#18266) 2023-10-18 13:42:30 +00:00
renovate[bot]
f432528388 Update dependency lint-staged to v15 (#18267)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-18 15:29:38 +02:00
Kendell R
f98c0769b0 Fix "No visual editor support for action: " (#18271) 2023-10-18 15:24:36 +02:00
Josh McCarty
b2cb0d8e0f Fixes alarm dialog inputmode for code input (#18263) 2023-10-17 12:23:40 +02:00
renovate[bot]
4c7c04bdc0 Update dependency marked to v9.1.2 (#18259) 2023-10-16 21:46:43 -04:00
renovate[bot]
ffb7469a7e Update dependency webpack to v5.89.0 (#18260) 2023-10-16 21:44:07 -04:00
Steve Repsher
d88831b719 Enable CORS for legacy bundle loading (#18248) 2023-10-16 20:40:15 +02:00
Steve Repsher
3b2f6d71f5 Minify ha-style/Roboto and load asynchronously (#18226) 2023-10-16 20:37:50 +02:00
Simon Lamon
a08185a1a5 Migrate developer state tools to LitElement (#18134)
Co-authored-by: Steve Repsher <steverep@users.noreply.github.com>
2023-10-16 20:37:04 +02:00
renovate[bot]
7ee91ca8fc Update vaadinWebComponents monorepo to v24.2.0 (#18255)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-16 15:54:20 +02:00
Simon Lamon
b6fe0cfa1b Replace internal material/web usages (#18219)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2023-10-16 15:42:59 +02:00
karwosts
c3a9682861 An alias editor and overflow menu for choose options (#18183) 2023-10-16 14:02:34 +02:00
Simon Lamon
62d21bea4f Replace polymer paper-slider (#18168)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2023-10-16 13:35:13 +02:00
Steve Repsher
434b9595c0 Remove SystemJS loader from Webpack builds (#18249) 2023-10-16 12:42:46 +02:00
renovate[bot]
a0f1b7f365 Update dependency @codemirror/autocomplete to v6.10.2 (#18253)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-16 12:40:37 +02:00
dependabot[bot]
628c2c39cf Bump relative-ci/agent-action from 2.1.8 to 2.1.10 (#18252)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-16 09:04:34 +02:00
Bram Kragten
4b885cbd93 Remove narrow from strategies (#18201) 2023-10-16 00:20:36 -04:00
Simon Lamon
02d9786f8c Fix lokalise translation upload (#18221)
Fix translation upload
2023-10-15 23:52:12 -04:00
renovate[bot]
88d14cd7b5 Update dependency magic-string to v0.30.5 (#18238)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-15 16:53:32 -04:00
renovate[bot]
4ea8f599cf Update dependency @codemirror/state to v6.3.0 (#18228)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-15 16:52:50 -04:00
renovate[bot]
37ef444180 Update babel monorepo to v7.23.2 (#18223)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-15 01:10:47 +00:00
renovate[bot]
4253feb8a2 Update dependency marked to v9.1.1 (#18224)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-14 21:00:11 -04:00
renovate[bot]
ce33cf7ff3 Update dependency @codemirror/autocomplete to v6.10.1 (#18218)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-14 20:59:07 -04:00
renovate[bot]
faa4455951 Update dependency @bundle-stats/plugin-webpack-filter to v4.7.7 (#18220)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-14 15:57:36 -04:00
renovate[bot]
08d8b43f44 Update dependency @types/js-yaml to v4.0.7 (#18212) 2023-10-13 20:59:48 -04:00
Paul Bottein
15c67fe299 Improve state and name display on state-card-display (#18207) 2023-10-13 10:38:19 +02:00
renovate[bot]
a10ec1f53c Update typescript-eslint monorepo to v6.7.5 (#18203)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-12 15:47:12 -04:00
Bram Kragten
1b220abf70 run on all branches 2023-10-12 19:09:33 +02:00
Till
607175706b Add date range picker to energy period selector (#14337) 2023-10-12 18:29:04 +02:00
Bram Kragten
f8966a2114 Slug not needed for reactive ci (#18200) 2023-10-12 17:00:29 +02:00
G Johansson
4c94ac5dda CountrySelector (#18035) 2023-10-12 16:47:28 +02:00
Bram Kragten
6d1e923b83 Voice assistant dev: fix wake word continue (#18181)
Start wake word when continue when wake word was used the previous run
2023-10-12 16:10:14 +02:00
Bram Kragten
2c743b7b56 Update relative-ci.yaml (#18197) 2023-10-12 15:26:33 +02:00
tzagim
6686da1f24 Fix for RTL languages - Profile panel + weather forecast card (#18191) 2023-10-12 14:27:01 +02:00
renovate[bot]
6bdeb45f6b Update vaadinWebComponents monorepo to v24.1.11 (#18195)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-12 14:25:06 +02:00
Simon Lamon
9f05a9679b Fix RelativeCI input issues (#18196) 2023-10-12 14:17:13 +02:00
Simon Lamon
51a6376991 Fix RelativeCI format issues (#18194) 2023-10-12 12:35:11 +02:00
Simon Lamon
c5056eb4d2 Allow Multiple Entities for Numeric State Trigger (#18064) 2023-10-12 09:37:19 +02:00
Steve Repsher
79f3759756 Create webpack bundle stats for Relative CI (#18178) 2023-10-12 09:28:34 +02:00
renovate[bot]
6c3b748279 Update dependency @rollup/plugin-node-resolve to v15.2.3 (#18193) 2023-10-11 16:52:28 -04:00
Bram Kragten
4293192e74 Use progress button when adding/updating mount (#18182) 2023-10-11 13:22:56 +02:00
Bram Kragten
ceaceaf47b Move select clearing to ha-select (#18190) 2023-10-11 13:22:17 +02:00
Piero
479a625662 Update url on tab reorder (#18169)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2023-10-11 12:49:08 +02:00
fustom
095d171a61 Tile card current temperature for climate entity (#18143) 2023-10-11 09:01:34 +02:00
renovate[bot]
8c3a7de6d9 Update dependency @mdi/js to v7.3.67 (#18185)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-10 23:42:48 -04:00
renovate[bot]
84e743c4c0 Update dependency @mdi/svg to v7.3.67 (#18186)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-10 23:26:46 -04:00
Paul Bottein
51f8d91ddf Fix user name in config page (#18187) 2023-10-10 23:25:21 -04:00
Kendell R
8f1a6ef1b1 Improve password show/hide buttons (#18176) 2023-10-10 13:26:54 +00:00
Kendell R
b3f1783269 Say "log in" instead of "login" on the authorize page (#18175) 2023-10-10 12:47:31 +02:00
renovate[bot]
7e630d0fc5 Update dependency eslint to v8.51.0 (#18172) 2023-10-09 21:38:05 -04:00
renovate[bot]
a4533251a1 Update dependency vis-network to v9.1.7 (#18167)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-09 15:32:45 -04:00
renovate[bot]
659db109aa Update CodeMirror (#18166)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-09 15:31:34 -04:00
Kendell R
d3fd27910a Separate outline color (#18109) 2023-10-09 18:29:25 +02:00
Simon Lamon
eae3c1309f Localize durations using Intl.NumberFormat (#18067) 2023-10-09 18:28:08 +02:00
Thomas Konrad
4a5b67e320 Add 'max devices' config to Energy Devices Graph (#17553) 2023-10-09 17:27:22 +02:00
Paul Bottein
86c014b677 Add screen condition to conditional card. (#18041) 2023-10-09 15:06:58 +02:00
karwosts
5a6d6dc7d3 Fix period selector in statistic card (#18131) 2023-10-09 14:41:27 +02:00
Steve Repsher
294df396f4 Remove test language from production (really) (#18137) 2023-10-09 14:40:06 +02:00
renovate[bot]
cc01e8d6a8 Update dependency core-js to v3.33.0 (#18119)
* Update dependency core-js to v3.33.0

* Update babel setting

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Steve Repsher <steverep@users.noreply.github.com>
2023-10-09 12:38:31 +00:00
Michael
a3532a41da Add before offset to sun condition description (#18152) 2023-10-09 14:36:16 +02:00
karwosts
ae35fd1eb8 Fix handling of negative zero in number selectors (#17127) 2023-10-09 14:34:16 +02:00
Simon Lamon
63095f1501 Replace paper-items in Scene Editor (#18101) 2023-10-09 14:29:58 +02:00
Steve Repsher
bf9e2cd404 Move polyfill time zone data out of bundles (#18142) 2023-10-09 14:28:16 +02:00
Bram Kragten
5b7ef941e4 Make it possible to clear an optional select (#18047) 2023-10-09 14:24:18 +02:00
ildar170975
352e721d0c Update state-badge.ts: change border-radius for media_player (#18066) 2023-10-09 14:11:29 +02:00
ildar170975
220b4794c5 Update developer-tools-state.js: fix alignment for ha-tips (#17608) 2023-10-09 13:59:09 +02:00
karwosts
811ebde42a Add per-set theme coloring to remainder of energy dashboard (#17826) 2023-10-09 13:55:21 +02:00
ildar170975
bfeee618f4 more-info: make long states "multilined" (#17649)
* align info when a state is multiline

* Enable multiline for long states

* Update state-info.ts

* Update state-card-display.ts
2023-10-09 13:52:03 +02:00
karwosts
db9b16e9f5 Change help link in statistics pickers in energy dashboard (#18138) 2023-10-09 13:47:46 +02:00
Philip Allgaier
7861d813b1 Add translations for voice assistant debug page (#17843)
* Add translations for voice assistant debug page

* Apply suggestions from code review

---------

Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2023-10-09 11:46:59 +00:00
breakthestatic
d7760c4b7a Expose history replace in action editor (#17740)
* Expose existing navigation history replace to the UI

* Remove navigation_replace from GUI editor

* Restore default value
2023-10-09 12:02:30 +02:00
dependabot[bot]
a60a721ea5 Bump home-assistant/wheels from 2023.10.1 to 2023.10.4 (#18162)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-09 08:40:14 +02:00
renovate[bot]
36219e1cb4 Update dependency marked to v9.1.0 (#18148)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-08 13:33:17 -04:00
renovate[bot]
7fdbc9dd32 Update dependency sinon to v16.1.0 (#18158)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-08 13:31:05 -04:00
renovate[bot]
334be93254 Update dependency @rollup/plugin-commonjs to v25.0.5 (#18154)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-08 17:28:14 +00:00
renovate[bot]
c14a6d59e2 Update dependency @rollup/plugin-replace to v5.0.3 (#18157)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-08 13:19:25 -04:00
renovate[bot]
7a8139b650 Update dependency @rollup/plugin-json to v6.0.1 (#18155)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-08 17:16:16 +00:00
renovate[bot]
9d2a443217 Update dependency @rollup/plugin-babel to v6.0.4 (#18153)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-08 13:07:16 -04:00
renovate[bot]
484b166233 Update dependency @rollup/plugin-node-resolve to v15.2.2 (#18156)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-08 13:04:52 -04:00
renovate[bot]
530208cb6a Update Yarn to v3.6.4 (#18139)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-07 00:01:49 -04:00
renovate[bot]
b534ff8ca3 Update dependency @codemirror/view to v6.21.2 (#18132) 2023-10-05 20:17:36 -04:00
renovate[bot]
02bd50c434 Update typescript-eslint monorepo to v6.7.4 (#18128) 2023-10-05 20:14:53 -04:00
Paul Bottein
9a84ce7b81 20231005.0 (#18126)
* Update dependency @material/web to v1.0.0 (#18070)

* Update dependency @material/web to v1.0.0

* Fix icon button size

* Remove unused ios override

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Paul Bottein <paul.bottein@gmail.com>

* Update dependency magic-string to v0.30.4 (#18089)

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

* Bump postcss from 8.4.30 to 8.4.31 (#18110)

Bumps [postcss](https://github.com/postcss/postcss) from 8.4.30 to 8.4.31.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.30...8.4.31)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Update CodeMirror (#18096)

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

* Update vaadinWebComponents monorepo to v24.1.10 (#18092)

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

* Make the "icon next/prev" series load faster (#18087)

* Preserve ancillary fields in a repeat action when modifying the form (#18068)

* Do not clear alias when editing automation action, condition or trigger (#18114)

* Use restart dialog confirmation for quick command (#18113)

* Add translations for restore backup dialogs (#18112)

Co-authored-by: c0ffeeca7 <38767475+c0ffeeca7@users.noreply.github.com>

* Hide tooltip after clicking on a chart to display more info (cosmetic change) (#18103)

* fix setting wake word to first option everytime (#18121)

* Fix class field for ha-icon-next/prev (#18118)

* Set border-radius to 0 for img in thread panel (#18124)

* Load Intl locale data in parallel (#18120)

* Load Intl locale data in parallel

* Switch to check result.ok

* Update dependency @codemirror/view to v6.21.1 (#18125)

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

* Bumped version to 20231005.0

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Kendell R <KTibow@users.noreply.github.com>
Co-authored-by: karwosts <32912880+karwosts@users.noreply.github.com>
Co-authored-by: c0ffeeca7 <38767475+c0ffeeca7@users.noreply.github.com>
Co-authored-by: K3A <966992+k3a@users.noreply.github.com>
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
Co-authored-by: Steve Repsher <steverep@users.noreply.github.com>
2023-10-05 18:29:15 +02:00
Paul Bottein
6e00be6684 Bumped version to 20231005.0 2023-10-05 18:28:19 +02:00
renovate[bot]
91ec43b9bc Update dependency @codemirror/view to v6.21.1 (#18125)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-05 18:19:22 +02:00
Steve Repsher
4a4d9a08d5 Load Intl locale data in parallel (#18120)
* Load Intl locale data in parallel

* Switch to check result.ok
2023-10-05 10:26:15 -04:00
Paul Bottein
0c32d1eb4e Set border-radius to 0 for img in thread panel (#18124) 2023-10-05 15:48:18 +02:00
Steve Repsher
f43171f91c Fix class field for ha-icon-next/prev (#18118) 2023-10-05 12:52:31 +00:00
Bram Kragten
48593eee0d fix setting wake word to first option everytime (#18121) 2023-10-05 11:30:05 +02:00
K3A
c106a0ac85 Hide tooltip after clicking on a chart to display more info (cosmetic change) (#18103) 2023-10-05 11:28:07 +02:00
Paul Bottein
e1a71fbfaa Add translations for restore backup dialogs (#18112)
Co-authored-by: c0ffeeca7 <38767475+c0ffeeca7@users.noreply.github.com>
2023-10-05 11:26:50 +02:00
Paul Bottein
0489d8922e Use restart dialog confirmation for quick command (#18113) 2023-10-05 11:24:43 +02:00
Paul Bottein
d7f1e9d091 Do not clear alias when editing automation action, condition or trigger (#18114) 2023-10-05 11:23:44 +02:00
karwosts
32bc8bd01d Preserve ancillary fields in a repeat action when modifying the form (#18068) 2023-10-04 14:36:58 +02:00
Kendell R
242b018ece Make the "icon next/prev" series load faster (#18087) 2023-10-04 13:59:51 +02:00
renovate[bot]
c25447d001 Update vaadinWebComponents monorepo to v24.1.10 (#18092)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-04 13:57:42 +02:00
renovate[bot]
d2d718475f Update CodeMirror (#18096)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-04 13:56:13 +02:00
dependabot[bot]
8e1e42cd50 Bump postcss from 8.4.30 to 8.4.31 (#18110)
Bumps [postcss](https://github.com/postcss/postcss) from 8.4.30 to 8.4.31.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.30...8.4.31)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-04 03:29:36 +00:00
renovate[bot]
014f9b8b73 Update dependency magic-string to v0.30.4 (#18089)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-03 23:15:36 -04:00
renovate[bot]
774c7e275c Update dependency @material/web to v1.0.0 (#18070)
* Update dependency @material/web to v1.0.0

* Fix icon button size

* Remove unused ios override

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Paul Bottein <paul.bottein@gmail.com>
2023-10-03 09:48:27 +00:00
Bram Kragten
75c43d15e1 20231002.0 (#18102) 2023-10-02 21:43:12 +02:00
Bram Kragten
e288b003d8 Bumped version to 20231002.0 2023-10-02 21:41:37 +02:00
yousaf465
4aa8518ed6 Change Urdu language to RTL (#18063)
Co-authored-by: karwosts <32912880+karwosts@users.noreply.github.com>
2023-10-02 21:26:07 +02:00
Bram Kragten
6acbf6395c Ignore prettier styling for tooltip of disk life time (#18097) 2023-10-02 21:23:13 +02:00
Bram Kragten
2030feabf7 Only set wakeword when not in new wakewords (#18095) 2023-10-02 21:23:02 +02:00
Bram Kragten
46d1dbcb47 Dont continue debug assist run when disconnected (#18098) 2023-10-02 21:22:50 +02:00
Bram Kragten
2f6297ec17 Always deduplicate found integrations in onboarding (#18091)
always deduplicate found integrations in onboarding
2023-10-02 14:30:28 +02:00
Paul Bottein
a3400a2f9c Prevent ha-form data lost if quick data updates (#18094) 2023-10-02 11:44:43 +02:00
Kendell R
c345f41416 Factor out style data to reduce bundle size (#18077) 2023-10-02 11:18:44 +02:00
Kendell R
292cdc7621 Fix clicking on radio buttons (and improve code) (#18078) 2023-10-02 10:58:10 +02:00
dependabot[bot]
c5ba74e0b4 Bump home-assistant/wheels from 2023.09.1 to 2023.10.1 (#18088)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-02 08:54:53 +02:00
renovate[bot]
41b24de559 Update dependency chai to v4.3.10 (#18082) 2023-10-01 20:24:14 -04:00
renovate[bot]
4fe7b18161 Update dependency chai to v4.3.9 (#18074)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-30 16:17:27 -04:00
renovate[bot]
399a979c33 Update dependency glob to v10.3.10 (#18072)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-30 16:16:20 -04:00
renovate[bot]
03c5482860 Update dependency @types/mocha to v10.0.2 (#18075)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-30 16:15:30 -04:00
Franck Nijhof
a116a50604 Hide shopping list from discovered onboarding integrations (#18069) 2023-09-29 22:39:57 +02:00
renovate[bot]
0dfa292c40 Update dependency glob to v10.3.9 (#18060)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-29 13:30:08 -04:00
Bram Kragten
5914a6c1a4 Clear wake word when new engine is picked, select first wake word. by… (#18058)
* Clear wake word when new engine is picked, select first wake word. by default

* Update assist-pipeline-detail-wakeword.ts
2023-09-29 12:38:11 +02:00
Bram Kragten
8daff17d6a Change linear-progress bar background color for dark mode (#18059) 2023-09-29 10:33:26 +02:00
renovate[bot]
59bd852e7a Update dependency @octokit/rest to v20.0.2 (#18053)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-28 22:51:10 -04:00
renovate[bot]
246fe2861e Update dependency eslint-plugin-wc to v2.0.4 (#18050)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-28 14:18:22 -04:00
renovate[bot]
dbf623ada2 Update typescript-eslint monorepo to v6.7.3 (#18051)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-28 14:17:33 -04:00
renovate[bot]
c848356a6d Update dependency @types/sortablejs to v1.15.3 (#18049)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-28 14:16:08 -04:00
312 changed files with 10830 additions and 6069 deletions

View File

@@ -21,12 +21,12 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps:
- name: Check out files from GitHub
uses: actions/checkout@v4.1.0
uses: actions/checkout@v4.1.1
with:
ref: dev
- name: Setup Node
uses: actions/setup-node@v3.8.1
uses: actions/setup-node@v4.0.0
with:
node-version-file: ".nvmrc"
cache: yarn
@@ -57,12 +57,12 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps:
- name: Check out files from GitHub
uses: actions/checkout@v4.1.0
uses: actions/checkout@v4.1.1
with:
ref: master
- name: Setup Node
uses: actions/setup-node@v3.8.1
uses: actions/setup-node@v4.0.0
with:
node-version-file: ".nvmrc"
cache: yarn

View File

@@ -24,9 +24,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
uses: actions/checkout@v4.1.0
uses: actions/checkout@v4.1.1
- name: Setup Node
uses: actions/setup-node@v3.8.1
uses: actions/setup-node@v4.0.0
with:
node-version-file: ".nvmrc"
cache: yarn
@@ -55,9 +55,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
uses: actions/checkout@v4.1.0
uses: actions/checkout@v4.1.1
- name: Setup Node
uses: actions/setup-node@v3.8.1
uses: actions/setup-node@v4.0.0
with:
node-version-file: ".nvmrc"
cache: yarn
@@ -73,9 +73,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
uses: actions/checkout@v4.1.0
uses: actions/checkout@v4.1.1
- name: Setup Node
uses: actions/setup-node@v3.8.1
uses: actions/setup-node@v4.0.0
with:
node-version-file: ".nvmrc"
cache: yarn
@@ -85,15 +85,21 @@ jobs:
run: ./node_modules/.bin/gulp build-app
env:
IS_TEST: "true"
- name: Upload bundle stats
uses: actions/upload-artifact@v3.1.3
with:
name: frontend-bundle-stats
path: build/stats/*.json
if-no-files-found: error
supervisor:
name: Build supervisor
needs: [lint, test]
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
uses: actions/checkout@v4.1.0
uses: actions/checkout@v4.1.1
- name: Setup Node
uses: actions/setup-node@v3.8.1
uses: actions/setup-node@v4.0.0
with:
node-version-file: ".nvmrc"
cache: yarn
@@ -103,3 +109,9 @@ jobs:
run: ./node_modules/.bin/gulp build-hassio
env:
IS_TEST: "true"
- name: Upload bundle stats
uses: actions/upload-artifact@v3.1.3
with:
name: supervisor-bundle-stats
path: build/stats/*.json
if-no-files-found: error

View File

@@ -23,7 +23,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4.1.0
uses: actions/checkout@v4.1.1
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.

View File

@@ -22,12 +22,12 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps:
- name: Check out files from GitHub
uses: actions/checkout@v4.1.0
uses: actions/checkout@v4.1.1
with:
ref: dev
- name: Setup Node
uses: actions/setup-node@v3.8.1
uses: actions/setup-node@v4.0.0
with:
node-version-file: ".nvmrc"
cache: yarn
@@ -58,12 +58,12 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps:
- name: Check out files from GitHub
uses: actions/checkout@v4.1.0
uses: actions/checkout@v4.1.1
with:
ref: master
- name: Setup Node
uses: actions/setup-node@v3.8.1
uses: actions/setup-node@v4.0.0
with:
node-version-file: ".nvmrc"
cache: yarn

View File

@@ -16,10 +16,10 @@ jobs:
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
steps:
- name: Check out files from GitHub
uses: actions/checkout@v4.1.0
uses: actions/checkout@v4.1.1
- name: Setup Node
uses: actions/setup-node@v3.8.1
uses: actions/setup-node@v4.0.0
with:
node-version-file: ".nvmrc"
cache: yarn

View File

@@ -21,10 +21,10 @@ jobs:
if: github.repository == 'home-assistant/frontend' && contains(github.event.pull_request.labels.*.name, 'needs design preview')
steps:
- name: Check out files from GitHub
uses: actions/checkout@v4.1.0
uses: actions/checkout@v4.1.1
- name: Setup Node
uses: actions/setup-node@v3.8.1
uses: actions/setup-node@v4.0.0
with:
node-version-file: ".nvmrc"
cache: yarn

View File

@@ -20,7 +20,7 @@ jobs:
contents: write
steps:
- name: Checkout the repository
uses: actions/checkout@v4.1.0
uses: actions/checkout@v4.1.1
- name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@v4
@@ -28,7 +28,7 @@ jobs:
python-version: ${{ env.PYTHON_VERSION }}
- name: Setup Node
uses: actions/setup-node@v3.8.1
uses: actions/setup-node@v4.0.0
with:
node-version-file: ".nvmrc"
cache: yarn
@@ -57,14 +57,14 @@ jobs:
run: tar -czvf translations.tar.gz translations
- name: Upload build artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v3.1.3
with:
name: wheels
path: dist/home_assistant_frontend*.whl
if-no-files-found: error
- name: Upload translations
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v3.1.3
with:
name: translations
path: translations.tar.gz

25
.github/workflows/relative-ci.yaml vendored Normal file
View File

@@ -0,0 +1,25 @@
name: RelativeCI
on:
workflow_run:
workflows: [CI]
types:
- completed
jobs:
upload:
name: Upload stats
if: ${{ github.event.workflow_run.conclusion == 'success' }}
strategy:
matrix:
bundle: [frontend, supervisor]
build: [modern, legacy]
runs-on: ubuntu-latest
steps:
- name: Send bundle stats and build information to RelativeCI
uses: relative-ci/agent-action@v2.1.10
with:
key: ${{ secrets[format('RELATIVE_CI_KEY_{0}_{1}', matrix.bundle, matrix.build)] }}
token: ${{ github.token }}
artifactName: ${{ format('{0}-bundle-stats', matrix.bundle) }}
webpackStatsFile: ${{ format('{0}-{1}.json', matrix.bundle, matrix.build) }}

View File

@@ -23,7 +23,7 @@ jobs:
contents: write # Required to upload release assets
steps:
- name: Checkout the repository
uses: actions/checkout@v4.1.0
uses: actions/checkout@v4.1.1
- name: Verify version
uses: home-assistant/actions/helpers/verify-version@master
@@ -34,7 +34,7 @@ jobs:
python-version: ${{ env.PYTHON_VERSION }}
- name: Setup Node
uses: actions/setup-node@v3.8.1
uses: actions/setup-node@v4.0.0
with:
node-version-file: ".nvmrc"
cache: yarn
@@ -74,7 +74,7 @@ jobs:
echo "home-assistant-frontend==$version" > ./requirements.txt
- name: Build wheels
uses: home-assistant/wheels@2023.09.1
uses: home-assistant/wheels@2023.10.5
with:
abi: cp311
tag: musllinux_1_2

View File

@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v4.1.0
uses: actions/checkout@v4.1.1
- name: Upload Translations
run: |

3
.gitignore vendored
View File

@@ -47,3 +47,6 @@ src/cast/dev_const.ts
# Home Assistant config
/config/
# Jetbrains
/.idea/

File diff suppressed because one or more lines are too long

View File

@@ -8,4 +8,4 @@ plugins:
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
spec: "@yarnpkg/plugin-interactive-tools"
yarnPath: .yarn/releases/yarn-3.6.3.cjs
yarnPath: .yarn/releases/yarn-3.6.4.cjs

View File

@@ -98,7 +98,7 @@ module.exports.babelOptions = ({ latestBuild, isProdBuild, isTestBuild }) => ({
"@babel/preset-env",
{
useBuiltIns: latestBuild ? false : "entry",
corejs: latestBuild ? false : { version: "3.32", proposals: true },
corejs: latestBuild ? false : { version: "3.33", proposals: true },
bugfixes: true,
shippedProposals: true,
},
@@ -149,7 +149,7 @@ module.exports.babelOptions = ({ latestBuild, isProdBuild, isTestBuild }) => ({
sourceMaps: !isTestBuild,
});
const nameSuffix = (latestBuild) => (latestBuild ? "-latest" : "-es5");
const nameSuffix = (latestBuild) => (latestBuild ? "-modern" : "-legacy");
const outputPath = (outputRoot, latestBuild) =>
path.resolve(outputRoot, latestBuild ? "frontend_latest" : "frontend_es5");
@@ -183,7 +183,7 @@ const publicPath = (latestBuild, root = "") =>
module.exports.config = {
app({ isProdBuild, latestBuild, isStatsBuild, isTestBuild, isWDS }) {
return {
name: "app" + nameSuffix(latestBuild),
name: "frontend" + nameSuffix(latestBuild),
entry: {
service_worker: "./src/entrypoints/service_worker.ts",
app: "./src/entrypoints/app.ts",

View File

@@ -45,8 +45,8 @@ gulp.task(
gulp.parallel("gen-icons-json", "build-translations", "build-locale-data"),
"copy-static-app",
env.useRollup() ? "rollup-prod-app" : "webpack-prod-app",
gulp.parallel("gen-pages-app-prod", "gen-service-worker-app-prod"),
// Don't compress running tests
...(env.isTestBuild() ? [] : ["compress-app"]),
gulp.parallel("gen-pages-app-prod", "gen-service-worker-app-prod")
...(env.isTestBuild() ? [] : ["compress-app"])
)
);

View File

@@ -4,6 +4,7 @@ import fs from "fs-extra";
import gulp from "gulp";
import path from "path";
import paths from "../paths.cjs";
import env from "../env.cjs";
const npmPath = (...parts) =>
path.resolve(paths.polymer_dir, "node_modules", ...parts);
@@ -62,6 +63,9 @@ function copyPolyfills(staticDir) {
}
function copyLoaderJS(staticDir) {
if (!env.useRollup()) {
return;
}
const staticPath = genStaticPath(staticDir);
copyFileDir(npmPath("systemjs/dist/s.min.js"), staticPath("js"));
copyFileDir(npmPath("systemjs/dist/s.min.js.map"), staticPath("js"));

View File

@@ -1,51 +1,54 @@
import { deleteSync } from "del";
import { mkdir, readFile, writeFile } from "fs/promises";
import gulp from "gulp";
import path from "path";
import { join, resolve } from "node:path";
import paths from "../paths.cjs";
const outDir = path.join(paths.build_dir, "locale-data");
const formatjsDir = join(paths.polymer_dir, "node_modules", "@formatjs");
const outDir = join(paths.build_dir, "locale-data");
const INTL_PACKAGES = {
"intl-relativetimeformat": "RelativeTimeFormat",
const INTL_POLYFILLS = {
"intl-datetimeformat": "DateTimeFormat",
"intl-numberformat": "NumberFormat",
"intl-displaynames": "DisplayNames",
"intl-listformat": "ListFormat",
"intl-numberformat": "NumberFormat",
"intl-relativetimeformat": "RelativeTimeFormat",
};
const convertToJSON = async (pkg, lang) => {
const convertToJSON = async (
pkg,
lang,
subDir = "locale-data",
addFunc = "__addLocaleData",
skipMissing = true
) => {
let localeData;
try {
localeData = await readFile(
path.resolve(
paths.polymer_dir,
`node_modules/@formatjs/${pkg}/locale-data/${lang}.js`
),
join(formatjsDir, pkg, subDir, `${lang}.js`),
"utf-8"
);
} catch (e) {
// Ignore if language is missing (i.e. not supported by @formatjs)
if (e.code === "ENOENT") {
if (e.code === "ENOENT" && skipMissing) {
console.warn(`Skipped missing data for language ${lang} from ${pkg}`);
return;
} else {
throw e;
}
throw e;
}
// Convert to JSON
const className = INTL_PACKAGES[pkg];
localeData = localeData
.replace(
new RegExp(
`\\/\\*\\s*@generated\\s*\\*\\/\\s*\\/\\/\\s*prettier-ignore\\s*if\\s*\\(Intl\\.${className}\\s*&&\\s*typeof\\s*Intl\\.${className}\\.__addLocaleData\\s*===\\s*'function'\\)\\s*{\\s*Intl\\.${className}\\.__addLocaleData\\(`,
"im"
),
""
)
.replace(/\)\s*}/im, "");
const obj = INTL_POLYFILLS[pkg];
const dataRegex = new RegExp(
`Intl\\.${obj}\\.${addFunc}\\((?<data>.*)\\)`,
"s"
);
localeData = localeData.match(dataRegex)?.groups?.data;
if (!localeData) {
throw Error(`Failed to extract data for language ${lang} from ${pkg}`);
}
// Parse to validate JSON, then stringify to minify
localeData = JSON.stringify(JSON.parse(localeData));
await writeFile(path.join(outDir, `${pkg}/${lang}.json`), localeData);
await writeFile(join(outDir, `${pkg}/${lang}.json`), localeData);
};
gulp.task("clean-locale-data", async () => deleteSync([outDir]));
@@ -53,17 +56,27 @@ gulp.task("clean-locale-data", async () => deleteSync([outDir]));
gulp.task("create-locale-data", async () => {
const translationMeta = JSON.parse(
await readFile(
path.resolve(paths.translations_src, "translationMetadata.json"),
resolve(paths.translations_src, "translationMetadata.json"),
"utf-8"
)
);
const conversions = [];
for (const pkg of Object.keys(INTL_PACKAGES)) {
await mkdir(path.join(outDir, pkg), { recursive: true });
for (const pkg of Object.keys(INTL_POLYFILLS)) {
// eslint-disable-next-line no-await-in-loop
await mkdir(join(outDir, pkg), { recursive: true });
for (const lang of Object.keys(translationMeta)) {
conversions.push(convertToJSON(pkg, lang));
}
}
conversions.push(
convertToJSON(
"intl-datetimeformat",
"add-all-tz",
".",
"__addTZData",
false
)
);
await Promise.all(conversions);
});

View File

@@ -1,12 +1,7 @@
import { createHash } from "crypto";
import { deleteSync } from "del";
import {
mkdirSync,
readdirSync,
readFileSync,
renameSync,
writeFile,
} from "fs";
import { mkdirSync, readdirSync, readFileSync, renameSync } from "fs";
import { writeFile } from "node:fs/promises";
import gulp from "gulp";
import flatmap from "gulp-flatmap";
import transform from "gulp-json-transform";
@@ -136,27 +131,23 @@ gulp.task("ensure-translations-build-dir", async () => {
mkdirSync(workDir, { recursive: true });
});
gulp.task("create-test-metadata", (cb) => {
writeFile(
workDir + "/testMetadata.json",
JSON.stringify({
test: {
nativeName: "Test",
},
}),
cb
);
});
gulp.task("create-test-metadata", () =>
env.isProdBuild()
? Promise.resolve()
: writeFile(
workDir + "/testMetadata.json",
JSON.stringify({ test: { nativeName: "Test" } })
)
);
gulp.task(
"create-test-translation",
gulp.series("create-test-metadata", () =>
gulp
.src(path.join(paths.translations_src, "en.json"))
.pipe(transform((data, _file) => recursiveEmpty(data)))
.pipe(rename("test.json"))
.pipe(gulp.dest(workDir))
)
gulp.task("create-test-translation", () =>
env.isProdBuild()
? Promise.resolve()
: gulp
.src(path.join(paths.translations_src, "en.json"))
.pipe(transform((data, _file) => recursiveEmpty(data)))
.pipe(rename("test.json"))
.pipe(gulp.dest(workDir))
);
/**
@@ -188,16 +179,11 @@ gulp.task("build-master-translation", () => {
gulp.task("build-merged-translations", () =>
gulp
.src(
[
inFrontendDir + "/*.json",
"!" + inFrontendDir + "/en.json",
workDir + "/test.json",
],
{
allowEmpty: true,
}
)
.src([
inFrontendDir + "/*.json",
"!" + inFrontendDir + "/en.json",
...(env.isProdBuild() ? [] : [workDir + "/test.json"]),
])
.pipe(transform((data, file) => lokaliseTransform(data, data, file)))
.pipe(
flatmap((stream, file) => {
@@ -377,14 +363,11 @@ gulp.task("build-translation-flatten-supervisor", () =>
gulp.task("build-translation-write-metadata", () =>
gulp
.src(
[
path.join(paths.translations_src, "translationMetadata.json"),
workDir + "/testMetadata.json",
workDir + "/translationFingerprints.json",
],
{ allowEmpty: true }
)
.src([
path.join(paths.translations_src, "translationMetadata.json"),
...(env.isProdBuild() ? [] : [workDir + "/testMetadata.json"]),
workDir + "/translationFingerprints.json",
])
.pipe(merge({}))
.pipe(
transform((data) => {
@@ -415,7 +398,7 @@ gulp.task("build-translation-write-metadata", () =>
gulp.task(
"create-translations",
gulp.series(
...(env.isProdBuild() ? [] : ["create-test-translation"]),
gulp.parallel("create-test-metadata", "create-test-translation"),
"build-master-translation",
"build-merged-translations",
gulp.parallel(...splitTasks),

View File

@@ -1,6 +1,8 @@
const { existsSync } = require("fs");
const path = require("path");
const webpack = require("webpack");
const { StatsWriterPlugin } = require("webpack-stats-plugin");
const filterStats = require("@bundle-stats/plugin-webpack-filter").default;
const TerserPlugin = require("terser-webpack-plugin");
const { WebpackManifestPlugin } = require("webpack-manifest-plugin");
const log = require("fancy-log");
@@ -152,6 +154,15 @@ const createWebpackConfig = ({
)
),
!isProdBuild && new LogStartCompilePlugin(),
isProdBuild &&
new StatsWriterPlugin({
filename: path.relative(
outputPath,
path.join(paths.build_dir, "stats", `${name}.json`)
),
stats: { assets: true, chunks: true, modules: true },
transform: (stats) => JSON.stringify(filterStats(stats)),
}),
].filter(Boolean),
resolve: {
extensions: [".ts", ".js", ".json"],
@@ -171,6 +182,8 @@ const createWebpackConfig = ({
"@lit-labs/virtualizer/layouts/grid.js",
"@lit-labs/virtualizer/polyfills/resize-observer-polyfill/ResizeObserver":
"@lit-labs/virtualizer/polyfills/resize-observer-polyfill/ResizeObserver.js",
"@lit-labs/observers/resize-controller":
"@lit-labs/observers/resize-controller.js",
},
},
output: {
@@ -183,6 +196,7 @@ const createWebpackConfig = ({
isProdBuild && !isStatsBuild ? "[id]-[contenthash].js" : "[name].js",
assetModuleFilename:
isProdBuild && !isStatsBuild ? "[id]-[contenthash][ext]" : "[id][ext]",
crossOriginLoading: "use-credentials",
hashFunction: "xxhash64",
hashDigest: "base64url",
hashDigestLength: 11, // full length of 64 bit base64url

View File

@@ -1,4 +1,4 @@
import "../../../src/resources/safari-14-attachshadow-patch";
import "../../../src/resources/ha-style";
import "../../../src/resources/roboto";
import "./layout/hc-connect";
import("../../../src/resources/ha-style");

View File

@@ -100,7 +100,9 @@ export class HcMain extends HassElement {
protected firstUpdated(changedProps) {
super.firstUpdated(changedProps);
import("../second-load");
import("./hc-lovelace");
import("../../../../src/resources/ha-style");
window.addEventListener("location-changed", () => {
const panelPath = `/${this._urlPath || "lovelace"}/`;
if (location.pathname.startsWith(panelPath)) {
@@ -260,7 +262,6 @@ export class HcMain extends HassElement {
{
strategy: {
type: "energy",
show_date_selection: true,
},
},
],
@@ -308,7 +309,7 @@ export class HcMain extends HassElement {
? await fetchResources(this.hass!.connection)
: (this._lovelaceConfig as LegacyLovelaceConfig).resources;
if (resources) {
loadLovelaceResources(resources, this.hass!.auth.data.hassUrl);
loadLovelaceResources(resources, this.hass!);
}
}
@@ -324,8 +325,7 @@ export class HcMain extends HassElement {
{
type: DEFAULT_STRATEGY,
},
this.hass!,
{ narrow: false }
this.hass!
)
);
}

View File

@@ -1,3 +0,0 @@
import "../../../src/resources/ha-style";
import "../../../src/resources/roboto";
import "./layout/hc-lovelace";

View File

@@ -3,6 +3,15 @@ import { DemoConfig } from "../types";
export const demoEntitiesArsaboo: DemoConfig["entities"] = (localize) =>
convertEntities({
"todo.shopping_list": {
entity_id: "todo.shopping_list",
state: "2",
attributes: {
supported_features: 15,
friendly_name: "Shopping List",
icon: "mdi:cart",
},
},
"zone.home": {
entity_id: "zone.home",
state: "zoning",

View File

@@ -3,6 +3,15 @@ import { DemoConfig } from "../types";
export const demoEntitiesJimpower: DemoConfig["entities"] = () =>
convertEntities({
"todo.shopping_list": {
entity_id: "todo.shopping_list",
state: "2",
attributes: {
supported_features: 15,
friendly_name: "Shopping List",
icon: "mdi:cart",
},
},
"zone.powertec": {
entity_id: "zone.powertec",
state: "zoning",

View File

@@ -4,16 +4,11 @@ export const demoThemeJimpower = () => ({
"primary-color": "#5294E2",
"label-badge-red": "var(--accent-color)",
"paper-tabs-selection-bar-color": "green",
"paper-slider-knob-color": "var(--accent-color)",
"light-primary-color": "var(--accent-color)",
"primary-background-color": "#383C45",
"primary-text-color": "#FFFFFF",
"paper-item-selected_-_background-color": "#434954",
"paper-slider-active-color": "var(--accent-color)",
"secondary-background-color": "#383C45",
"paper-slider-container-color":
"linear-gradient(var(--primary-background-color), var(--secondary-background-color)) no-repeat",
"paper-slider-disabled-active-color": "var(--disabled-text-color)",
"disabled-text-color": "#7F848E",
"paper-item-icon_-_color": "green",
"paper-grey-200": "#414A59",
@@ -32,14 +27,10 @@ export const demoThemeJimpower = () => ({
"switch-unchecked-button-color": "var(--disabled-text-color)",
"label-badge-border-color": "green",
"paper-listbox-color": "var(--primary-color)",
"paper-slider-disabled-secondary-color": "var(--disabled-text-color)",
"card-background-color": "#434954",
"label-badge-text-color": "var(--primary-text-color)",
"paper-slider-knob-start-color": "var(--accent-color)",
"switch-unchecked-track-color": "var(--disabled-text-color)",
"dark-primary-color": "var(--accent-color)",
"paper-slider-secondary-color": "var(--secondary-background-color)",
"paper-slider-pin-color": "var(--accent-color)",
"paper-item-icon-active-color": "#F9C536",
"accent-color": "#E45E65",
"table-row-alternative-background-color": "#3E424B",

View File

@@ -3,6 +3,15 @@ import { DemoConfig } from "../types";
export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
convertEntities({
"todo.shopping_list": {
entity_id: "todo.shopping_list",
state: "2",
attributes: {
supported_features: 15,
friendly_name: "Shopping List",
icon: "mdi:cart",
},
},
"zone.anna": {
entity_id: "zone.anna",
state: "zoning",

View File

@@ -5,17 +5,12 @@ export const demoThemeKernehed = () => ({
"primary-color": "#2980b9",
"label-badge-red": "var(--accent-color)",
"paper-tabs-selection-bar-color": "green",
"paper-slider-knob-color": "var(--accent-color)",
"primary-text-color": "#FFFFFF",
"light-primary-color": "var(--accent-color)",
"primary-background-color": "#222222",
"sidebar-icon-color": "#777777",
"paper-item-selected_-_background-color": "#292929",
"paper-slider-active-color": "var(--accent-color)",
"secondary-background-color": "#222222",
"paper-slider-container-color":
"linear-gradient(var(--primary-background-color), var(--secondary-background-color)) no-repeat",
"paper-slider-disabled-active-color": "var(--disabled-text-color)",
"disabled-text-color": "#777777",
"paper-item-icon_-_color": "green",
"paper-grey-200": "#222222",
@@ -33,14 +28,10 @@ export const demoThemeKernehed = () => ({
"switch-unchecked-button-color": "var(--disabled-text-color)",
"label-badge-border-color": "green",
"paper-listbox-color": "#777777",
"paper-slider-disabled-secondary-color": "var(--disabled-text-color)",
"card-background-color": "#292929",
"label-badge-text-color": "var(--primary-text-color)",
"paper-slider-knob-start-color": "var(--accent-color)",
"switch-unchecked-track-color": "var(--disabled-text-color)",
"dark-primary-color": "var(--accent-color)",
"paper-slider-secondary-color": "var(--secondary-background-color)",
"paper-slider-pin-color": "var(--accent-color)",
"paper-item-icon-active-color": "#b58e31",
"accent-color": "#2980b9",
"table-row-alternative-background-color": "#292929",

View File

@@ -3,6 +3,15 @@ import { DemoConfig } from "../types";
export const demoEntitiesTeachingbirds: DemoConfig["entities"] = () =>
convertEntities({
"todo.shopping_list": {
entity_id: "todo.shopping_list",
state: "2",
attributes: {
supported_features: 15,
friendly_name: "Shopping List",
icon: "mdi:cart",
},
},
"sensor.pollen_grabo": {
entity_id: "sensor.pollen_grabo",
state: "",

View File

@@ -220,7 +220,8 @@ export const demoLovelaceTeachingbirds: DemoConfig["lovelace"] = () => ({
state_filter: ["on"],
},
{
type: "shopping-list",
type: "todo-list",
entity: "todo.shopping_list",
},
{
entities: [

View File

@@ -1,6 +1,5 @@
export const demoThemeTeachingbirds = () => ({
"paper-card-header-color": "var(--paper-item-icon-color)",
"paper-slider-pin-color": "var(--primary-color)",
"paper-listbox-background-color": "#202020",
"paper-grey-50": "var(--primary-text-color)",
"paper-item-icon-color": "#d3d3d3",
@@ -8,8 +7,6 @@ export const demoThemeTeachingbirds = () => ({
"primary-color": "#389638",
"light-primary-color": "#6f956f",
"label-badge-red": "var(--primary-color)",
"paper-slider-secondary-color": "var(--light-primary-color)",
"paper-slider-knob-color": "var(--primary-color)",
"paper-listbox-color": "#FFFFFF",
"paper-toggle-button-checked-bar-color": "var(--light-primary-color)",
"switch-unchecked-track-color": "var(--primary-text-color)",
@@ -17,9 +14,7 @@ export const demoThemeTeachingbirds = () => ({
"label-badge-text-color": "var(--text-primary-color)",
"primary-background-color": "#303030",
"sidebar-icon-color": "var(--paper-item-icon-color)",
"paper-slider-active-color": "#d8bf50",
"secondary-background-color": "#2b2b2b",
"paper-slider-knob-start-color": "var(--primary-color)",
"paper-item-icon-active-color": "#d8bf50",
"switch-checked-color": "var(--primary-color)",
"secondary-text-color": "#389638",

View File

@@ -1,4 +1,4 @@
import "../../src/resources/ha-style";
import "../../src/resources/roboto";
import "../../src/resources/safari-14-attachshadow-patch";
import "./ha-demo";
import("../../src/resources/ha-style");

View File

@@ -22,7 +22,7 @@ import { mockLovelace } from "./stubs/lovelace";
import { mockMediaPlayer } from "./stubs/media_player";
import { mockPersistentNotification } from "./stubs/persistent_notification";
import { mockRecorder } from "./stubs/recorder";
import { mockShoppingList } from "./stubs/shopping_list";
import { mockTodo } from "./stubs/todo";
import { mockSystemLog } from "./stubs/system_log";
import { mockTemplate } from "./stubs/template";
import { mockTranslations } from "./stubs/translations";
@@ -49,7 +49,7 @@ export class HaDemo extends HomeAssistantAppEl {
mockTranslations(hass);
mockHistory(hass);
mockRecorder(hass);
mockShoppingList(hass);
mockTodo(hass);
mockSystemLog(hass);
mockTemplate(hass);
mockEvents(hass);

View File

@@ -1,44 +0,0 @@
import { ShoppingListItem } from "../../../src/data/shopping-list";
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
let items: ShoppingListItem[] = [
{
id: 12,
name: "Milk",
complete: false,
},
{
id: 13,
name: "Eggs",
complete: false,
},
{
id: 14,
name: "Oranges",
complete: true,
},
];
export const mockShoppingList = (hass: MockHomeAssistant) => {
hass.mockWS("shopping_list/items", () => items);
hass.mockWS("shopping_list/items/add", (msg) => {
const item: ShoppingListItem = {
id: new Date().getTime(),
complete: false,
name: msg.name,
};
items.push(item);
hass.mockEvent("shopping_list_updated");
return item;
});
hass.mockWS("shopping_list/items/update", ({ type, item_id, ...updates }) => {
items = items.map((item) =>
item.id === item_id ? { ...item, ...updates } : item
);
hass.mockEvent("shopping_list_updated");
});
hass.mockWS("shopping_list/items/clear", () => {
items = items.filter((item) => !item.complete);
hass.mockEvent("shopping_list_updated");
});
};

24
demo/src/stubs/todo.ts Normal file
View File

@@ -0,0 +1,24 @@
import { TodoItem, TodoItemStatus } from "../../../src/data/todo";
import { MockHomeAssistant } from "../../../src/fake_data/provide_hass";
export const mockTodo = (hass: MockHomeAssistant) => {
hass.mockWS("todo/item/list", () => ({
items: [
{
uid: "12",
summary: "Milk",
status: TodoItemStatus.NeedsAction,
},
{
uid: "13",
summary: "Eggs",
status: TodoItemStatus.NeedsAction,
},
{
uid: "14",
summary: "Oranges",
status: TodoItemStatus.Completed,
},
] as TodoItem[],
}));
};

View File

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

View File

@@ -49,11 +49,11 @@ export class DemoHaCircularSlider extends LitElement {
<div class="field">
<p>Current</p>
<ha-slider
labeled
min="10"
max="30"
.value=${this.current}
@change=${this._currentChanged}
pin
></ha-slider>
<p>${this.current} °C</p>
</div>

View File

@@ -57,6 +57,7 @@ const DEVICES = [
sw_version: null,
hw_version: null,
via_device_id: null,
serial_number: null,
},
{
area_id: "backyard",
@@ -74,6 +75,7 @@ const DEVICES = [
sw_version: null,
hw_version: null,
via_device_id: null,
serial_number: null,
},
{
area_id: null,
@@ -91,6 +93,7 @@ const DEVICES = [
sw_version: null,
hw_version: null,
via_device_id: null,
serial_number: null,
},
];

View File

@@ -57,8 +57,8 @@ export class DemoHaHsColorPicker extends LitElement {
></ha-hs-color-picker>
<p>Hue : ${this.value[0]}</p>
<ha-slider
labeled
step="1"
pin
min="0"
max="360"
.value=${this.value[0]}
@@ -67,8 +67,8 @@ export class DemoHaHsColorPicker extends LitElement {
</ha-slider>
<p>Saturation : ${this.value[1]}</p>
<ha-slider
labeled
step="0.01"
pin
min="0"
max="1"
.value=${this.value[1]}
@@ -77,8 +77,8 @@ export class DemoHaHsColorPicker extends LitElement {
</ha-slider>
<p>Color Brighness : ${this.brightness}</p>
<ha-slider
labeled
step="1"
pin
min="0"
max="255"
.value=${this.brightness}

View File

@@ -53,6 +53,7 @@ const DEVICES = [
sw_version: null,
hw_version: null,
via_device_id: null,
serial_number: null,
},
{
area_id: "backyard",
@@ -70,6 +71,7 @@ const DEVICES = [
sw_version: null,
hw_version: null,
via_device_id: null,
serial_number: null,
},
{
area_id: null,
@@ -87,6 +89,7 @@ const DEVICES = [
sw_version: null,
hw_version: null,
via_device_id: null,
serial_number: null,
},
];

View File

@@ -1,3 +0,0 @@
---
title: Shopping List Card
---

View File

@@ -0,0 +1,3 @@
---
title: Todo List Card
---

View File

@@ -2,25 +2,39 @@ import { html, LitElement, PropertyValues, TemplateResult } from "lit";
import { customElement, query } from "lit/decorators";
import { provideHass } from "../../../../src/fake_data/provide_hass";
import "../../components/demo-cards";
import { getEntity } from "../../../../src/fake_data/entity";
import { mockTodo } from "../../../../demo/src/stubs/todo";
const ENTITIES = [
getEntity("todo", "shopping_list", "2", {
friendly_name: "Shopping List",
supported_features: 15,
}),
getEntity("todo", "read_only", "2", {
friendly_name: "Read only",
}),
];
const CONFIGS = [
{
heading: "List example",
config: `
- type: shopping-list
- type: todo-list
entity: todo.shopping_list
`,
},
{
heading: "List with title example",
config: `
- type: shopping-list
- type: todo-list
title: Shopping List
entity: todo.read_only
`,
},
];
@customElement("demo-lovelace-shopping-list-card")
class DemoShoppingListEntity extends LitElement {
@customElement("demo-lovelace-todo-list-card")
class DemoTodoListEntity extends LitElement {
@query("#demos") private _demoRoot!: HTMLElement;
protected render(): TemplateResult {
@@ -32,18 +46,14 @@ class DemoShoppingListEntity extends LitElement {
const hass = provideHass(this._demoRoot);
hass.updateTranslations(null, "en");
hass.updateTranslations("lovelace", "en");
hass.addEntities(ENTITIES);
hass.mockAPI("shopping_list", () => [
{ name: "list", id: 1, complete: false },
{ name: "all", id: 2, complete: false },
{ name: "the", id: 3, complete: false },
{ name: "things", id: 4, complete: true },
]);
mockTodo(hass);
}
}
declare global {
interface HTMLElementTagNameMap {
"demo-lovelace-shopping-list-card": DemoShoppingListEntity;
"demo-lovelace-todo-list-card": DemoTodoListEntity;
}
}

View File

@@ -213,6 +213,7 @@ const createDeviceRegistryEntries = (
name: "Tag Reader",
sw_version: null,
hw_version: "1.0.0",
serial_number: "00_12_4B_00_22_98_88_7F",
id: "mock-device-id",
identifiers: [],
via_device_id: null,

View File

@@ -360,11 +360,9 @@ export class HassioBackups extends LitElement {
if (this.supervisor!.info.state !== "running") {
showAlertDialog(this, {
title: this.supervisor!.localize("backup.could_not_create"),
text: this.supervisor!.localize(
"backup.create_blocked_not_running",
"state",
this.supervisor!.info.state
),
text: this.supervisor!.localize("backup.create_blocked_not_running", {
state: this.supervisor!.info.state,
}),
});
return;
}

View File

@@ -31,6 +31,7 @@ import { fileDownload } from "../../../../src/util/file_download";
import "../../components/supervisor-backup-content";
import type { SupervisorBackupContent } from "../../components/supervisor-backup-content";
import { HassioBackupDialogParams } from "./show-dialog-hassio-backup";
import { BackupOrRestoreKey } from "../../util/translations";
@customElement("dialog-hassio-backup")
class HassioBackupDialog
@@ -64,6 +65,13 @@ class HassioBackupDialog
fireEvent(this, "dialog-closed", { dialog: this.localName });
}
private _localize(key: BackupOrRestoreKey) {
return (
this._dialogParams!.supervisor?.localize(`backup.${key}`) ||
this._dialogParams!.localize!(`ui.panel.page-onboarding.restore.${key}`)
);
}
protected render() {
if (!this._dialogParams || !this._backup) {
return nothing;
@@ -79,7 +87,7 @@ class HassioBackupDialog
<ha-header-bar>
<span slot="title">${this._backup.name}</span>
<ha-icon-button
.label=${this.hass?.localize("ui.common.close") || "Close"}
.label=${this._localize("close")}
.path=${mdiClose}
slot="actionItems"
dialogAction="cancel"
@@ -87,29 +95,31 @@ class HassioBackupDialog
</ha-header-bar>
</div>
${this._restoringBackup
? html` <ha-circular-progress active></ha-circular-progress>`
: html`<supervisor-backup-content
.hass=${this.hass}
.supervisor=${this._dialogParams.supervisor}
.backup=${this._backup}
.onboarding=${this._dialogParams.onboarding || false}
.localize=${this._dialogParams.localize}
dialogInitialFocus
>
</supervisor-backup-content>`}
? html`<ha-circular-progress active></ha-circular-progress>`
: html`
<supervisor-backup-content
.hass=${this.hass}
.supervisor=${this._dialogParams.supervisor}
.backup=${this._backup}
.onboarding=${this._dialogParams.onboarding || false}
.localize=${this._dialogParams.localize}
dialogInitialFocus
>
</supervisor-backup-content>
`}
${this._error
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
: ""}
: nothing}
<mwc-button
.disabled=${this._restoringBackup}
slot="secondaryAction"
@click=${this._restoreClicked}
>
Restore
${this._localize("restore")}
</mwc-button>
${!this._dialogParams.onboarding
${!this._dialogParams.onboarding && this._dialogParams.supervisor
? html`<ha-button-menu
fixed
slot="primaryAction"
@@ -117,22 +127,24 @@ class HassioBackupDialog
@closed=${stopPropagation}
>
<ha-icon-button
.label=${this.hass!.localize("ui.common.menu") || "Menu"}
.label=${this._dialogParams.supervisor.localize(
"backup.more_actions"
)}
.path=${mdiDotsVertical}
slot="trigger"
></ha-icon-button>
<mwc-list-item
>${this._dialogParams.supervisor?.localize(
>${this._dialogParams.supervisor.localize(
"backup.download_backup"
)}</mwc-list-item
>
<mwc-list-item class="error"
>${this._dialogParams.supervisor?.localize(
>${this._dialogParams.supervisor.localize(
"backup.delete_backup_title"
)}</mwc-list-item
>
</ha-button-menu>`
: ""}
: nothing}
</ha-dialog>
`;
}
@@ -183,21 +195,22 @@ class HassioBackupDialog
}
private async _partialRestoreClicked(backupDetails) {
if (
this._dialogParams?.supervisor !== undefined &&
this._dialogParams?.supervisor.info.state !== "running"
) {
const supervisor = this._dialogParams?.supervisor;
if (supervisor !== undefined && supervisor.info.state !== "running") {
await showAlertDialog(this, {
title: "Could not restore backup",
text: `Restoring a backup is not possible right now because the system is in ${this._dialogParams?.supervisor.info.state} state.`,
title: supervisor.localize("backup.could_not_restore"),
text: supervisor.localize("backup.restore_blocked_not_running", {
state: supervisor.info.state,
}),
});
return;
}
if (
!(await showConfirmationDialog(this, {
title: "Are you sure you want to restore this partial backup?",
confirmText: "restore",
dismissText: "cancel",
title: this._localize("confirm_restore_partial_backup_title"),
text: this._localize("confirm_restore_partial_backup_text"),
confirmText: this._localize("restore"),
dismissText: this._localize("cancel"),
}))
) {
return;
@@ -230,22 +243,22 @@ class HassioBackupDialog
}
private async _fullRestoreClicked(backupDetails) {
if (
this._dialogParams?.supervisor !== undefined &&
this._dialogParams?.supervisor.info.state !== "running"
) {
const supervisor = this._dialogParams?.supervisor;
if (supervisor !== undefined && supervisor.info.state !== "running") {
await showAlertDialog(this, {
title: "Could not restore backup",
text: `Restoring a backup is not possible right now because the system is in ${this._dialogParams?.supervisor.info.state} state.`,
title: supervisor.localize("backup.could_not_restore"),
text: supervisor.localize("backup.restore_blocked_not_running", {
state: supervisor.info.state,
}),
});
return;
}
if (
!(await showConfirmationDialog(this, {
title:
"Are you sure you want to wipe your system and restore this backup?",
confirmText: "restore",
dismissText: "cancel",
title: this._localize("confirm_restore_full_backup_title"),
text: this._localize("confirm_restore_full_backup_text"),
confirmText: this._localize("restore"),
dismissText: this._localize("cancel"),
}))
) {
return;
@@ -279,11 +292,15 @@ class HassioBackupDialog
}
private async _deleteClicked() {
const supervisor = this._dialogParams?.supervisor;
if (!supervisor) return;
if (
!(await showConfirmationDialog(this, {
title: "Are you sure you want to delete this backup?",
confirmText: "delete",
dismissText: "cancel",
title: supervisor!.localize("backup.confirm_delete_title"),
text: supervisor!.localize("backup.confirm_delete_text"),
confirmText: supervisor!.localize("backup.delete"),
dismissText: supervisor!.localize("backup.cancel"),
}))
) {
return;
@@ -301,6 +318,9 @@ class HassioBackupDialog
}
private async _downloadClicked() {
const supervisor = this._dialogParams?.supervisor;
if (!supervisor) return;
let signedPath: { path: string };
try {
signedPath = await getSignedPath(
@@ -320,10 +340,10 @@ class HassioBackupDialog
if (window.location.href.includes("ui.nabu.casa")) {
const confirm = await showConfirmationDialog(this, {
title: "Potential slow download",
text: "Downloading backups over the Nabu Casa URL will take some time, it is recomended to use your local URL instead, do you want to continue?",
confirmText: "continue",
dismissText: "cancel",
title: supervisor.localize("backup.remote_download_title"),
text: supervisor.localize("backup.remote_download_text"),
confirmText: supervisor.localize("backup.download"),
dismissText: this._localize("cancel"),
});
if (!confirm) {
return;

View File

@@ -89,8 +89,7 @@ class HassioCreateBackupDialog extends LitElement {
),
text: this._dialogParams!.supervisor.localize(
"backup.create_blocked_not_running",
"state",
this._dialogParams!.supervisor.info.state
{ state: this._dialogParams!.supervisor.info.state }
),
});
return;

View File

@@ -1,4 +1,5 @@
import { mdiClose } from "@mdi/js";
import { dump } from "js-yaml";
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
@@ -9,7 +10,6 @@ import "../../../../src/components/ha-expansion-panel";
import "../../../../src/components/ha-icon-button";
import "../../../../src/components/search-input";
import { HassioHardwareInfo } from "../../../../src/data/hassio/hardware";
import { dump } from "../../../../src/resources/js-yaml-dump";
import { haStyle, haStyleDialog } from "../../../../src/resources/styles";
import { HomeAssistant } from "../../../../src/types";
import { HassioHardwareDialogParams } from "./show-dialog-hassio-hardware";

View File

@@ -1,15 +1,15 @@
// Compat needs to be first import
import "../../src/resources/compatibility";
import { setCancelSyntheticClickEvents } from "@polymer/polymer/lib/utils/settings";
import "../../src/resources/roboto";
import "../../src/resources/ha-style";
import "../../src/resources/safari-14-attachshadow-patch";
import "./hassio-main";
setCancelSyntheticClickEvents(false);
import("../../src/resources/ha-style");
import("@polymer/polymer/lib/utils/settings").then(
({ setCancelSyntheticClickEvents }) => setCancelSyntheticClickEvents(false)
);
const styleEl = document.createElement("style");
styleEl.innerHTML = `
styleEl.textContent = `
body {
font-family: Roboto, sans-serif;
-moz-osx-font-smoothing: grayscale;

View File

@@ -0,0 +1,4 @@
import type { TranslationDict } from "../../../src/types";
export type BackupOrRestoreKey = keyof TranslationDict["supervisor"]["backup"] &
keyof TranslationDict["ui"]["panel"]["page-onboarding"]["restore"];

View File

@@ -25,24 +25,24 @@
"license": "Apache-2.0",
"type": "module",
"dependencies": {
"@babel/runtime": "7.23.1",
"@babel/runtime": "7.23.2",
"@braintree/sanitize-url": "6.0.4",
"@codemirror/autocomplete": "6.9.1",
"@codemirror/commands": "6.2.5",
"@codemirror/language": "6.9.1",
"@codemirror/autocomplete": "6.10.2",
"@codemirror/commands": "6.3.0",
"@codemirror/language": "6.9.2",
"@codemirror/legacy-modes": "6.3.3",
"@codemirror/search": "6.5.4",
"@codemirror/state": "6.2.1",
"@codemirror/view": "6.20.2",
"@codemirror/state": "6.3.1",
"@codemirror/view": "6.21.4",
"@egjs/hammerjs": "2.0.17",
"@formatjs/intl-datetimeformat": "6.10.3",
"@formatjs/intl-displaynames": "6.5.2",
"@formatjs/intl-getcanonicallocales": "2.2.1",
"@formatjs/intl-listformat": "7.4.2",
"@formatjs/intl-locale": "3.3.4",
"@formatjs/intl-numberformat": "8.7.2",
"@formatjs/intl-pluralrules": "5.2.6",
"@formatjs/intl-relativetimeformat": "11.2.6",
"@formatjs/intl-datetimeformat": "6.11.1",
"@formatjs/intl-displaynames": "6.6.1",
"@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",
@@ -52,10 +52,12 @@
"@lezer/highlight": "1.1.6",
"@lit-labs/context": "0.4.1",
"@lit-labs/motion": "1.0.4",
"@lit-labs/observers": "2.0.1",
"@lit-labs/virtualizer": "2.0.7",
"@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",
@@ -71,7 +73,6 @@
"@material/mwc-radio": "0.27.0",
"@material/mwc-ripple": "0.27.0",
"@material/mwc-select": "0.27.0",
"@material/mwc-slider": "0.27.0",
"@material/mwc-switch": "0.27.0",
"@material/mwc-tab": "0.27.0",
"@material/mwc-tab-bar": "0.27.0",
@@ -80,22 +81,21 @@
"@material/mwc-top-app-bar": "0.27.0",
"@material/mwc-top-app-bar-fixed": "0.27.0",
"@material/top-app-bar": "=14.0.0-canary.53b3cad2f.0",
"@material/web": "=1.0.0-pre.17",
"@mdi/js": "7.2.96",
"@mdi/svg": "7.2.96",
"@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",
"@polymer/paper-slider": "3.0.1",
"@polymer/paper-tabs": "3.1.0",
"@polymer/paper-toast": "3.0.1",
"@polymer/polymer": "3.5.1",
"@thomasloven/round-slider": "0.6.0",
"@vaadin/combo-box": "24.1.9",
"@vaadin/vaadin-themable-mixin": "24.1.9",
"@vaadin/combo-box": "24.2.1",
"@vaadin/vaadin-themable-mixin": "24.2.1",
"@vibrant/color": "3.2.1-alpha.1",
"@vibrant/core": "3.2.1-alpha.1",
"@vibrant/quantizer-mmcq": "3.2.1-alpha.1",
@@ -105,7 +105,7 @@
"app-datepicker": "5.1.1",
"chart.js": "4.4.0",
"comlink": "4.4.1",
"core-js": "3.32.2",
"core-js": "3.33.1",
"cropperjs": "1.6.1",
"date-fns": "2.30.0",
"date-fns-tz": "2.0.0",
@@ -114,15 +114,15 @@
"fuse.js": "6.6.2",
"google-timezones-json": "1.2.0",
"hls.js": "1.4.12",
"home-assistant-js-websocket": "8.2.0",
"home-assistant-js-websocket": "9.1.0",
"idb-keyval": "6.2.1",
"intl-messageformat": "10.5.3",
"intl-messageformat": "10.5.4",
"js-yaml": "4.1.0",
"leaflet": "1.9.4",
"leaflet-draw": "1.0.4",
"lit": "2.8.0",
"luxon": "3.4.3",
"marked": "9.0.3",
"marked": "9.1.2",
"memoize-one": "6.0.0",
"node-vibrant": "3.2.1-alpha.1",
"proxy-polyfill": "0.3.2",
@@ -141,8 +141,8 @@
"ua-parser-js": "1.0.36",
"unfetch": "5.0.0",
"vis-data": "7.1.7",
"vis-network": "9.1.6",
"vue": "2.7.14",
"vis-network": "9.1.8",
"vue": "2.7.15",
"vue2-daterange-picker": "0.6.8",
"weekstart": "2.0.0",
"workbox-cacheable-response": "7.0.0",
@@ -154,62 +154,63 @@
"xss": "1.0.14"
},
"devDependencies": {
"@babel/core": "7.23.0",
"@babel/plugin-proposal-decorators": "7.23.0",
"@babel/plugin-transform-runtime": "7.22.15",
"@babel/preset-env": "7.22.20",
"@babel/preset-typescript": "7.23.0",
"@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",
"@koa/cors": "4.0.0",
"@lokalise/node-api": "12.0.0",
"@octokit/auth-oauth-device": "6.0.1",
"@octokit/plugin-retry": "6.0.1",
"@octokit/rest": "20.0.1",
"@octokit/rest": "20.0.2",
"@open-wc/dev-server-hmr": "0.1.4",
"@rollup/plugin-babel": "6.0.3",
"@rollup/plugin-commonjs": "25.0.4",
"@rollup/plugin-json": "6.0.0",
"@rollup/plugin-node-resolve": "15.2.1",
"@rollup/plugin-replace": "5.0.2",
"@types/babel__plugin-transform-runtime": "7.9.3",
"@types/chromecast-caf-receiver": "6.0.10",
"@types/chromecast-caf-sender": "1.0.6",
"@types/esprima": "4.0.4",
"@rollup/plugin-babel": "6.0.4",
"@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",
"@types/glob": "8.1.0",
"@types/html-minifier-terser": "7.0.0",
"@types/js-yaml": "4.0.6",
"@types/leaflet": "1.9.6",
"@types/leaflet-draw": "1.0.8",
"@types/luxon": "3.3.2",
"@types/mocha": "10.0.1",
"@types/qrcode": "1.5.2",
"@types/serve-handler": "6.1.2",
"@types/sortablejs": "1.15.2",
"@types/tar": "6.1.6",
"@types/ua-parser-js": "0.7.37",
"@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/webspeechapi": "0.0.29",
"@typescript-eslint/eslint-plugin": "6.7.2",
"@typescript-eslint/parser": "6.7.2",
"@typescript-eslint/eslint-plugin": "6.9.0",
"@typescript-eslint/parser": "6.9.0",
"@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.8",
"chai": "4.3.10",
"del": "7.1.0",
"eslint": "8.50.0",
"eslint": "8.52.0",
"eslint-config-airbnb-base": "15.0.0",
"eslint-config-airbnb-typescript": "17.1.0",
"eslint-config-prettier": "9.0.0",
"eslint-import-resolver-webpack": "0.13.7",
"eslint-import-resolver-webpack": "0.13.8",
"eslint-plugin-disable": "2.0.3",
"eslint-plugin-import": "2.28.1",
"eslint-plugin-lit": "1.9.1",
"eslint-plugin-import": "2.29.0",
"eslint-plugin-lit": "1.10.1",
"eslint-plugin-lit-a11y": "4.1.0",
"eslint-plugin-unused-imports": "3.0.0",
"eslint-plugin-wc": "2.0.3",
"eslint-plugin-wc": "2.0.4",
"esprima": "4.0.1",
"fancy-log": "2.0.0",
"fs-extra": "11.1.1",
"glob": "10.3.7",
"glob": "10.3.10",
"gulp": "4.0.2",
"gulp-flatmap": "1.0.2",
"gulp-json-transform": "0.4.8",
@@ -220,10 +221,10 @@
"husky": "8.0.3",
"instant-mocha": "1.5.2",
"jszip": "3.10.1",
"lint-staged": "14.0.1",
"lit-analyzer": "2.0.0-pre.3",
"lint-staged": "15.0.2",
"lit-analyzer": "2.0.1",
"lodash.template": "4.5.0",
"magic-string": "0.30.3",
"magic-string": "0.30.5",
"map-stream": "0.0.7",
"mocha": "10.2.0",
"object-hash": "3.0.0",
@@ -235,19 +236,20 @@
"rollup-plugin-terser": "7.0.2",
"rollup-plugin-visualizer": "5.9.2",
"serve-handler": "6.1.5",
"sinon": "16.0.0",
"sinon": "17.0.0",
"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-pre.1",
"ts-lit-plugin": "2.0.0",
"typescript": "5.2.2",
"vinyl-buffer": "1.0.1",
"vinyl-source-stream": "2.0.0",
"webpack": "5.88.2",
"webpack": "5.89.0",
"webpack-cli": "5.1.4",
"webpack-dev-server": "4.15.1",
"webpack-manifest-plugin": "5.0.0",
"webpack-stats-plugin": "1.1.3",
"webpackbar": "5.0.2",
"workbox-build": "7.0.0"
},
@@ -255,8 +257,9 @@
"resolutions": {
"@polymer/polymer": "patch:@polymer/polymer@3.5.1#./.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",
"sortablejs@1.15.0": "patch:sortablejs@npm%3A1.15.0#./.yarn/patches/sortablejs-npm-1.15.0-f3a393abcc.patch",
"leaflet-draw@1.0.4": "patch:leaflet-draw@npm%3A1.0.4#./.yarn/patches/leaflet-draw-npm-1.0.4-0ca0ebcf65.patch"
},
"packageManager": "yarn@3.6.3"
"packageManager": "yarn@3.6.4"
}

View File

@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "home-assistant-frontend"
version = "20230928.0"
version = "20231027.0"
license = {text = "Apache-2.0"}
description = "The Home Assistant frontend"
readme = "README.md"

View File

@@ -33,7 +33,7 @@ fi
docker run \
-v ${LOCAL_FILE}:/opt/src/${LOCAL_FILE} \
lokalise/lokalise-cli-2@sha256:f1860b26be22fa73b8c93bc5f8690f2afc867610a42de6fc27adc790e5d4425d lokalise2 \
lokalise/lokalise-cli-2:v2.6.10 lokalise2 \
--token ${LOKALISE_TOKEN} \
--project-id ${PROJECT_ID} \
file upload \

View File

@@ -26,14 +26,13 @@ export class HaAuthFormString extends HaFormString {
}
ha-auth-form-string ha-icon-button {
position: absolute;
top: 1em;
right: 12px;
--mdc-icon-button-size: 24px;
color: var(--secondary-text-color);
}
ha-auth-form-string ha-icon-button {
top: 8px;
right: 8px;
inset-inline-start: initial;
inset-inline-end: 12px;
inset-inline-end: 8px;
--mdc-icon-button-size: 40px;
--mdc-icon-size: 20px;
color: var(--secondary-text-color);
direction: var(--direction);
}
</style>
@@ -63,7 +62,7 @@ export class HaAuthFormString extends HaFormString {
.validationMessage=${this.schema.required ? "Required" : undefined}
@input=${this._valueChanged}
@change=${this._valueChanged}
></ha-auth-textfield>
></ha-auth-textfield>
${this.renderIcon()}
</ha-auth-textfield>
`;

View File

@@ -0,0 +1,9 @@
export function getAllCombinations<T>(arr: T[]) {
return arr.reduce<T[][]>(
(combinations, element) =>
combinations.concat(
combinations.map((combination) => [...combination, element])
),
[[]]
);
}

View File

@@ -16,6 +16,7 @@ import {
mdiCarCoolantLevel,
mdiCash,
mdiChatSleep,
mdiClipboardList,
mdiClock,
mdiCloudUpload,
mdiCog,
@@ -120,6 +121,7 @@ export const FIXED_DOMAIN_ICONS = {
siren: mdiBullhorn,
stt: mdiMicrophoneMessage,
text: mdiFormTextbox,
todo: mdiClipboardList,
time: mdiClock,
timer: mdiTimerOutline,
tts: mdiSpeakerMessage,

View File

@@ -5,12 +5,15 @@ import { FrontendLocaleData, TimeZone } from "../../data/translation";
const calcZonedDate = (
date: Date,
tz: string,
fn: (date: Date, options?: any) => Date,
fn: (date: Date, options?: any) => Date | number | boolean,
options?
) => {
const inputZoned = utcToZonedTime(date, tz);
const fnZoned = fn(inputZoned, options);
return zonedTimeToUtc(fnZoned, tz);
if (fnZoned instanceof Date) {
return zonedTimeToUtc(fnZoned, tz) as Date;
}
return fnZoned;
};
export const calcDate = (
@@ -21,5 +24,16 @@ export const calcDate = (
options?
) =>
locale.time_zone === TimeZone.server
? calcZonedDate(date, config.time_zone, fn, options)
? (calcZonedDate(date, config.time_zone, fn, options) as Date)
: fn(date, options);
export const calcDateProperty = (
date: Date,
fn: (date: Date, options?: any) => boolean | number,
locale: FrontendLocaleData,
config: HassConfig,
options?
) =>
locale.time_zone === TimeZone.server
? (calcZonedDate(date, config.time_zone, fn, options) as number | boolean)
: fn(date, options);

View File

@@ -37,6 +37,23 @@ const formatDateMem = memoizeOne(
})
);
// Aug 10, 2021
export const formatDateShort = (
dateObj: Date,
locale: FrontendLocaleData,
config: HassConfig
) => formatDateShortMem(locale, config.time_zone).format(dateObj);
const formatDateShortMem = memoizeOne(
(locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(locale.language, {
year: "numeric",
month: "short",
day: "numeric",
timeZone: locale.time_zone === "server" ? serverTimeZone : undefined,
})
);
// 10/08/2021
export const formatDateNumeric = (
dateObj: Date,
@@ -102,13 +119,13 @@ const formatDateNumericMem = memoizeOne(
);
// Aug 10
export const formatDateShort = (
export const formatDateVeryShort = (
dateObj: Date,
locale: FrontendLocaleData,
config: HassConfig
) => formatDateShortMem(locale, config.time_zone).format(dateObj);
) => formatDateVeryShortMem(locale, config.time_zone).format(dateObj);
const formatDateShortMem = memoizeOne(
const formatDateVeryShortMem = memoizeOne(
(locale: FrontendLocaleData, serverTimeZone: string) =>
new Intl.DateTimeFormat(locale.language, {
day: "numeric",

View File

@@ -1,8 +1,13 @@
import { HaDurationData } from "../../components/ha-duration-input";
import { FrontendLocaleData } from "../../data/translation";
import "../../resources/intl-polyfill";
const leftPad = (num: number) => (num < 10 ? `0${num}` : num);
export const formatDuration = (duration: HaDurationData) => {
export const formatDuration = (
locale: FrontendLocaleData,
duration: HaDurationData
) => {
const d = duration.days || 0;
const h = duration.hours || 0;
const m = duration.minutes || 0;
@@ -10,7 +15,11 @@ export const formatDuration = (duration: HaDurationData) => {
const ms = duration.milliseconds || 0;
if (d > 0) {
return `${d} day${d === 1 ? "" : "s"} ${h}:${leftPad(m)}:${leftPad(s)}`;
return `${Intl.NumberFormat(locale.language, {
style: "unit",
unit: "day",
unitDisplay: "long",
}).format(d)} ${h}:${leftPad(m)}:${leftPad(s)}`;
}
if (h > 0) {
return `${h}:${leftPad(m)}:${leftPad(s)}`;
@@ -19,10 +28,18 @@ export const formatDuration = (duration: HaDurationData) => {
return `${m}:${leftPad(s)}`;
}
if (s > 0) {
return `${s} second${s === 1 ? "" : "s"}`;
return Intl.NumberFormat(locale.language, {
style: "unit",
unit: "second",
unitDisplay: "long",
}).format(s);
}
if (ms > 0) {
return `${ms} millisecond${ms === 1 ? "" : "s"}`;
return Intl.NumberFormat(locale.language, {
style: "unit",
unit: "millisecond",
unitDisplay: "long",
}).format(ms);
}
return null;
};

View File

@@ -1,5 +1,5 @@
import { ThemeVars } from "../../data/ws-themes";
import { darkStyles, derivedStyles } from "../../resources/styles";
import { darkStyles, derivedStyles } from "../../resources/styles-data";
import type { HomeAssistant } from "../../types";
import {
hex2rgb,
@@ -41,9 +41,7 @@ export const applyThemesOnElement = (
// If there is no explicitly desired dark mode provided, we automatically
// use the active one from `themes`.
const darkMode =
themeSettings && themeSettings?.dark !== undefined
? themeSettings?.dark
: themes.darkMode;
themeSettings?.dark !== undefined ? themeSettings.dark : themes.darkMode;
let cacheKey = themeToApply;
let themeRules: Partial<ThemeVars> = {};
@@ -135,10 +133,19 @@ export const applyThemesOnElement = (
// Set and/or reset styles
if (element.updateStyles) {
// Use updateStyles() method of Polymer elements
element.updateStyles(styles);
} else if (window.ShadyCSS) {
// Implement updateStyles() method of Polymer elements
// Use ShadyCSS if available
window.ShadyCSS.styleSubtree(/** @type {!HTMLElement} */ element, styles);
} else {
for (const s in styles) {
if (s === null) {
element.style.removeProperty(s);
} else {
element.style.setProperty(s, styles[s]);
}
}
}
};

View File

@@ -1,19 +1,29 @@
// https://gist.github.com/hagemann/382adfc57adbd5af078dc93feef01fe1
export const slugify = (value: string, delimiter = "_") => {
const a =
"àáäâãåăæąçćčđďèéěėëêęğǵḧìíïîįłḿǹńňñòóöôœøṕŕřßşśšșťțùúüûǘůűūųẃẍÿýźžż·/_,:;";
const b = `aaaaaaaaacccddeeeeeeegghiiiiilmnnnnooooooprrsssssttuuuuuuuuuwxyyzzz${delimiter}${delimiter}${delimiter}${delimiter}${delimiter}${delimiter}`;
"àáâäæãåāăąçćčđďèéêëēėęěğǵḧîïíīįìıİłḿñńǹňôöòóœøōõőṕŕřßśšşșťțûüùúūǘůűųẃẍÿýžźż·";
const b = `aaaaaaaaaacccddeeeeeeeegghiiiiiiiilmnnnnoooooooooprrsssssttuuuuuuuuuwxyyzzz${delimiter}`;
const p = new RegExp(a.split("").join("|"), "g");
return value
.toString()
.toLowerCase()
.replace(/\s+/g, delimiter) // Replace spaces with delimiter
.replace(p, (c) => b.charAt(a.indexOf(c))) // Replace special characters
.replace(/&/g, `${delimiter}and${delimiter}`) // Replace & with 'and'
.replace(/[^\w-]+/g, "") // Remove all non-word characters
.replace(/-/g, delimiter) // Replace - with delimiter
.replace(new RegExp(`(${delimiter})\\1+`, "g"), "$1") // Replace multiple delimiters with single delimiter
.replace(new RegExp(`^${delimiter}+`), "") // Trim delimiter from start of text
.replace(new RegExp(`${delimiter}+$`), ""); // Trim delimiter from end of text
let slugified;
if (value === "") {
slugified = "";
} else {
slugified = value
.toString()
.toLowerCase()
.replace(p, (c) => b.charAt(a.indexOf(c))) // Replace special characters
.replace(/(\d),(?=\d)/g, "$1") // Remove Commas between numbers
.replace(/[^a-z0-9]+/g, delimiter) // Replace all non-word characters
.replace(new RegExp(`(${delimiter})\\1+`, "g"), "$1") // Replace multiple delimiters with single delimiter
.replace(new RegExp(`^${delimiter}+`), "") // Trim delimiter from start of text
.replace(new RegExp(`${delimiter}+$`), ""); // Trim delimiter from end of text
if (slugified === "") {
slugified = "unknown";
}
}
return slugified;
};

View File

@@ -13,45 +13,33 @@ export const handleStructError = (
for (const failure of err.failures()) {
if (failure.value === undefined) {
errors.push(
hass.localize(
"ui.errors.config.key_missing",
"key",
failure.path.join(".")
)
hass.localize("ui.errors.config.key_missing", {
key: failure.path.join("."),
})
);
} else if (failure.type === "never") {
warnings.push(
hass.localize(
"ui.errors.config.key_not_expected",
"key",
failure.path.join(".")
)
hass.localize("ui.errors.config.key_not_expected", {
key: failure.path.join("."),
})
);
} else if (failure.type === "union") {
continue;
} else if (failure.type === "enums") {
warnings.push(
hass.localize(
"ui.errors.config.key_wrong_type",
"key",
failure.path.join("."),
"type_correct",
failure.message.replace("Expected ", "").split(", ")[0],
"type_wrong",
JSON.stringify(failure.value)
)
hass.localize("ui.errors.config.key_wrong_type", {
key: failure.path.join("."),
type_correct: failure.message.replace("Expected ", "").split(", ")[0],
type_wrong: JSON.stringify(failure.value),
})
);
} else {
warnings.push(
hass.localize(
"ui.errors.config.key_wrong_type",
"key",
failure.path.join("."),
"type_correct",
failure.refinement || failure.type,
"type_wrong",
JSON.stringify(failure.value)
)
hass.localize("ui.errors.config.key_wrong_type", {
key: failure.path.join("."),
type_correct: failure.refinement || failure.type,
type_wrong: JSON.stringify(failure.value),
})
);
}
}

View File

@@ -1,6 +1,13 @@
import "@material/mwc-button";
import { mdiAlertOctagram, mdiCheckBold } from "@mdi/js";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import {
css,
CSSResultGroup,
html,
LitElement,
nothing,
TemplateResult,
} from "lit";
import { customElement, property, state } from "lit/decorators";
import "../ha-circular-progress";
import "../ha-svg-icon";
@@ -27,7 +34,7 @@ export class HaProgressButton extends LitElement {
<slot></slot>
</mwc-button>
${!overlay
? ""
? nothing
: html`
<div class="progress">
${this._result === "success"

View File

@@ -39,7 +39,7 @@ import {
formatDate,
formatDateMonth,
formatDateMonthYear,
formatDateShort,
formatDateVeryShort,
formatDateWeekdayDay,
formatDateYear,
} from "../../common/datetime/format_date";
@@ -128,7 +128,7 @@ _adapters._date.override({
this.options.config
);
case "day":
return formatDateShort(
return formatDateVeryShort(
new Date(time),
this.options.locale,
this.options.config

View File

@@ -12,6 +12,7 @@ import { styleMap } from "lit/directives/style-map";
import { clamp } from "../../common/number/clamp";
import { computeRTL } from "../../common/util/compute_rtl";
import { HomeAssistant } from "../../types";
import { debounce } from "../../common/util/debounce";
export const MIN_TIME_BETWEEN_UPDATES = 60 * 5 * 1000;
@@ -52,6 +53,12 @@ export class HaChartBase extends LitElement {
@state() private _hiddenDatasets: Set<number> = new Set();
private _paddingUpdateCount = 0;
private _paddingUpdateLock = false;
private _paddingYAxisInternal = 0;
public disconnectedCallback() {
super.disconnectedCallback();
this._releaseCanvas();
@@ -104,9 +111,44 @@ export class HaChartBase extends LitElement {
});
}
public shouldUpdate(changedProps: PropertyValues): boolean {
if (
this._paddingUpdateLock &&
changedProps.size === 1 &&
changedProps.has("paddingYAxis")
) {
return false;
}
return true;
}
private _debouncedClearUpdates = debounce(
() => {
this._paddingUpdateCount = 0;
},
2000,
false
);
public willUpdate(changedProps: PropertyValues): void {
super.willUpdate(changedProps);
if (!this._paddingUpdateLock) {
this._paddingYAxisInternal = this.paddingYAxis;
if (changedProps.size === 1 && changedProps.has("paddingYAxis")) {
this._paddingUpdateCount++;
if (this._paddingUpdateCount > 300) {
this._paddingUpdateLock = true;
// eslint-disable-next-line
console.error(
"Detected excessive chart padding updates, possibly an infinite loop. Disabling axis padding."
);
} else {
this._debouncedClearUpdates();
}
}
}
if (!this.hasUpdated || !this.chart) {
return;
}
@@ -171,10 +213,10 @@ export class HaChartBase extends LitElement {
this.height ?? this._chartHeight ?? this.clientWidth / 2
}px`,
"padding-left": `${
computeRTL(this.hass) ? 0 : this.paddingYAxis
computeRTL(this.hass) ? 0 : this._paddingYAxisInternal
}px`,
"padding-right": `${
computeRTL(this.hass) ? this.paddingYAxis : 0
computeRTL(this.hass) ? this._paddingYAxisInternal : 0
}px`,
})}
>
@@ -324,7 +366,7 @@ export class HaChartBase extends LitElement {
clamp(
context.tooltip.caretX,
100,
this.clientWidth - 100 - this.paddingYAxis
this.clientWidth - 100 - this._paddingYAxisInternal
) -
100 +
"px",

View File

@@ -141,16 +141,10 @@ export class StateHistoryChartLine extends LitElement {
`${context.dataset.label}: ${formatNumber(
context.parsed.y,
this.hass.locale,
this.data[context.datasetIndex]?.entity_id
? getNumberFormatOptions(
this.hass.states[
this.data[context.datasetIndex].entity_id
],
this.hass.entities[
this.data[context.datasetIndex].entity_id
]
)
: undefined
getNumberFormatOptions(
undefined,
this.hass.entities[this._entityIds[context.datasetIndex]]
)
)} ${this.unit}`,
},
},
@@ -180,7 +174,9 @@ export class StateHistoryChartLine extends LitElement {
return;
}
const points = e.chart.getElementsAtEventForMode(
const chart = e.chart;
const points = chart.getElementsAtEventForMode(
e,
"nearest",
{ intersect: true },
@@ -192,6 +188,7 @@ export class StateHistoryChartLine extends LitElement {
fireEvent(this, "hass-more-info", {
entityId: this._entityIds[firstPoint.datasetIndex],
});
chart.canvas.dispatchEvent(new Event("mouseout")); // to hide tooltip
}
},
};

View File

@@ -238,6 +238,7 @@ export class StateHistoryChartTimeline extends LitElement {
// @ts-ignore
entityId: this._chartData?.datasets[index]?.label,
});
chart.canvas.dispatchEvent(new Event("mouseout")); // to hide tooltip
},
};
}

View File

@@ -73,9 +73,9 @@ export class StateHistoryCharts extends LitElement {
@property({ type: Boolean }) public isLoadingData = false;
@state() private _computedStartTime!: Date;
private _computedStartTime!: Date;
@state() private _computedEndTime!: Date;
private _computedEndTime!: Date;
@state() private _maxYWidth = 0;
@@ -114,31 +114,6 @@ export class StateHistoryCharts extends LitElement {
${this.hass.localize("ui.components.history_charts.no_history_found")}
</div>`;
}
const now = new Date();
this._computedEndTime =
this.upToNow || !this.endTime || this.endTime > now ? now : this.endTime;
if (this.startTime) {
this._computedStartTime = this.startTime;
} else if (this.hoursToShow) {
this._computedStartTime = new Date(
new Date().getTime() - 60 * 60 * this.hoursToShow * 1000
);
} else {
this._computedStartTime = new Date(
this.historyData.timeline.reduce(
(minTime, stateInfo) =>
Math.min(
minTime,
new Date(stateInfo.data[0].last_changed).getTime()
),
new Date().getTime()
)
);
}
const combinedItems = this.historyData.timeline.length
? (this.virtualize
? chunkData(this.historyData.timeline, CANVAS_TIMELINE_ROWS_CHUNK)
@@ -220,10 +195,45 @@ export class StateHistoryCharts extends LitElement {
return true;
}
protected willUpdate() {
protected willUpdate(changedProps: PropertyValues) {
if (!this.hasUpdated) {
loadVirtualizer();
}
if (
[...changedProps.keys()].some(
(prop) =>
!(
["_maxYWidth", "_childYWidths", "_chartCount"] as PropertyKey[]
).includes(prop)
)
) {
// Don't recompute times when we just want to update layout
const now = new Date();
this._computedEndTime =
this.upToNow || !this.endTime || this.endTime > now
? now
: this.endTime;
if (this.startTime) {
this._computedStartTime = this.startTime;
} else if (this.hoursToShow) {
this._computedStartTime = new Date(
new Date().getTime() - 60 * 60 * this.hoursToShow * 1000
);
} else {
this._computedStartTime = new Date(
(this.historyData?.timeline ?? []).reduce(
(minTime, stateInfo) =>
Math.min(
minTime,
new Date(stateInfo.data[0].last_changed).getTime()
),
new Date().getTime()
)
);
}
}
}
protected updated(changedProps: PropertyValues) {

View File

@@ -19,6 +19,7 @@ import { isComponentLoaded } from "../../common/config/is_component_loaded";
import {
formatNumber,
numberFormatToLocale,
getNumberFormatOptions,
} from "../../common/number/format_number";
import {
getDisplayUnit,
@@ -74,6 +75,8 @@ export class StatisticsChart extends LitElement {
@state() private _chartData: ChartData = { datasets: [] };
@state() private _statisticIds: string[] = [];
@state() private _chartOptions?: ChartOptions;
@query("ha-chart-base") private _chart?: HaChartBase;
@@ -189,7 +192,11 @@ export class StatisticsChart extends LitElement {
label: (context) =>
`${context.dataset.label}: ${formatNumber(
context.parsed.y,
this.hass.locale
this.hass.locale,
getNumberFormatOptions(
undefined,
this.hass.entities[this._statisticIds[context.datasetIndex]]
)
)} ${
// @ts-ignore
context.dataset.unit || ""
@@ -248,6 +255,7 @@ export class StatisticsChart extends LitElement {
let colorIndex = 0;
const statisticsData = Object.entries(this.statisticsData);
const totalDataSets: ChartDataset<"line">[] = [];
const statisticIds: string[] = [];
let endTime: Date;
if (statisticsData.length === 0) {
@@ -386,6 +394,7 @@ export class StatisticsChart extends LitElement {
unit: meta?.unit_of_measurement,
band,
});
statisticIds.push(statistic_id);
}
});
@@ -411,11 +420,7 @@ export class StatisticsChart extends LitElement {
} else {
val = stat[type];
}
dataValues.push(
val !== null && val !== undefined
? Math.round(val * 100) / 100
: null
);
dataValues.push(val ?? null);
});
pushData(startDate, new Date(stat.end), dataValues);
});
@@ -431,6 +436,7 @@ export class StatisticsChart extends LitElement {
this._chartData = {
datasets: totalDataSets,
};
this._statisticIds = statisticIds;
}
static get styles(): CSSResultGroup {

View File

@@ -31,6 +31,10 @@ const Component = Vue.extend({
type: Boolean,
default: true,
},
openingDirection: {
type: String,
default: "right",
},
disabled: {
type: Boolean,
default: false,
@@ -66,7 +70,7 @@ const Component = Vue.extend({
props: {
"time-picker": this.timePicker,
"auto-apply": this.autoApply,
opens: "right",
opens: this.openingDirection,
"show-dropdowns": false,
"time-picker24-hour": this.twentyfourHours,
disabled: this.disabled,
@@ -126,9 +130,9 @@ class DateRangePickerElement extends WrappedElement {
${dateRangePickerStyles}
.calendars {
display: flex;
flex-wrap: nowrap !important;
}
.daterangepicker {
left: 0px !important;
top: auto;
box-shadow: var(--ha-card-box-shadow, none);
background-color: var(--card-background-color);
@@ -252,6 +256,10 @@ class DateRangePickerElement extends WrappedElement {
direction: ltr;
text-align: left;
}
.vue-daterange-picker{
min-width: unset !important;
display: block !important;
}
`;
const shadowRoot = this.shadowRoot!;
shadowRoot.appendChild(style);

View File

@@ -71,7 +71,8 @@ class HaEntitiesPickerLight extends LitElement {
@property({ attribute: "picked-entity-label" })
public pickedEntityLabel?: string;
@property({ attribute: "pick-entity-label" }) public pickEntityLabel?: string;
@property({ attribute: "pick-entity-label" })
public pickEntityLabel?: string;
@property() public entityFilter?: HaEntityPickerEntityFilterFunc;

View File

@@ -87,6 +87,8 @@ export class HaStatisticPicker extends LitElement {
@property({ type: Array, attribute: "exclude-statistics" })
public excludeStatistics?: string[];
@property() public helpMissingEntityUrl = "/more-info/statistics/";
@state() private _opened?: boolean;
@query("ha-combo-box", true) public comboBox!: HaComboBox;
@@ -111,7 +113,7 @@ export class HaStatisticPicker extends LitElement {
? html`<a
target="_blank"
rel="noopener noreferrer"
href=${documentationUrl(this.hass, "/more-info/statistics/")}
href=${documentationUrl(this.hass, this.helpMissingEntityUrl)}
>${this.hass.localize(
"ui.components.statistic-picker.learn_more"
)}</a

View File

@@ -112,9 +112,7 @@ export class StateBadge extends LitElement {
const stateObj = this.stateObj;
const iconStyle: { [name: string]: string } = {};
const hostStyle: Partial<CSSStyleDeclaration> = {
backgroundImage: "",
};
let backgroundImage = "";
this._showIcon = true;
@@ -135,10 +133,12 @@ export class StateBadge extends LitElement {
if (domain === "camera") {
imageUrl = cameraUrlWithWidthHeight(imageUrl, 80, 80);
}
hostStyle.backgroundImage = `url(${imageUrl})`;
backgroundImage = `url(${imageUrl})`;
this._showIcon = false;
if (domain === "update") {
hostStyle.borderRadius = "0";
this.style.borderRadius = "0";
} else if (domain === "media_player") {
this.style.borderRadius = "8%";
}
} else if (this.color) {
// Externally provided overriding color wins over state color
@@ -179,12 +179,12 @@ export class StateBadge extends LitElement {
if (this.hass) {
imageUrl = this.hass.hassUrl(imageUrl);
}
hostStyle.backgroundImage = `url(${imageUrl})`;
backgroundImage = `url(${imageUrl})`;
this._showIcon = false;
}
this._iconStyle = iconStyle;
Object.assign(this.style, hostStyle);
this.style.backgroundImage = backgroundImage;
}
static get styles(): CSSResultGroup {

View File

@@ -95,25 +95,25 @@ class StateInfo extends LitElement {
:host {
min-width: 120px;
white-space: nowrap;
display: flex;
align-items: center;
}
state-badge {
float: left;
}
:host([rtl]) state-badge {
float: right;
flex: none;
}
.info {
margin-left: 56px;
margin-left: 8px;
display: flex;
flex-direction: column;
justify-content: center;
height: 100%;
min-width: 0;
}
:host([rtl]) .info {
margin-right: 56px;
margin-right: 8px;
margin-left: 0;
text-align: right;
}

View File

@@ -4,7 +4,6 @@ import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import { haStyle } from "../resources/styles";
import { HomeAssistant } from "../types";
import "./ha-area-picker";
import "./ha-textfield";
import type { HaTextField } from "./ha-textfield";
import { fireEvent } from "../common/dom/fire_event";

View File

@@ -1,11 +1,9 @@
import { HassEntity } from "home-assistant-js-websocket";
import { html, LitElement, nothing } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import { until } from "lit/directives/until";
import { HomeAssistant } from "../types";
import { formatNumber } from "../common/number/format_number";
let jsYamlPromise: Promise<typeof import("../resources/js-yaml-dump")>;
import { HomeAssistant } from "../types";
@customElement("ha-attribute-value")
class HaAttributeValue extends LitElement {
@@ -44,7 +42,7 @@ class HaAttributeValue extends LitElement {
${attributeValue}
</a>
`;
} catch (_) {
} catch {
// Nothing to do here
}
}
@@ -55,15 +53,19 @@ class HaAttributeValue extends LitElement {
attributeValue.some((val) => val instanceof Object)) ||
(!Array.isArray(attributeValue) && attributeValue instanceof Object)
) {
if (!jsYamlPromise) {
jsYamlPromise = import("../resources/js-yaml-dump");
}
const yaml = jsYamlPromise.then((jsYaml) => jsYaml.dump(attributeValue));
const yaml = import("js-yaml").then(({ dump }) => dump(attributeValue));
return html`<pre>${until(yaml, "")}</pre>`;
}
return this.hass.formatEntityAttributeValue(this.stateObj!, this.attribute);
}
static styles = css`
pre {
margin: 0;
white-space: pre-wrap;
}
`;
}
declare global {

View File

@@ -26,6 +26,8 @@ export class HaButtonMenu extends LitElement {
@property({ type: Boolean }) public fixed = false;
@property({ type: Boolean, attribute: "no-anchor" }) public noAnchor = false;
@query("mwc-menu", true) private _menu?: Menu;
public get items() {
@@ -82,7 +84,7 @@ export class HaButtonMenu extends LitElement {
if (this.disabled) {
return;
}
this._menu!.anchor = this;
this._menu!.anchor = this.noAnchor ? null : this;
this._menu!.show();
}

View File

@@ -17,6 +17,13 @@ export class HaButton extends Button {
.mdc-button {
height: var(--button-height, 36px);
}
.trailing-icon {
display: flex;
}
.slot-container {
width: 100%;
overflow: hidden;
}
`,
];
}

View File

@@ -12,7 +12,6 @@ import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../common/dom/fire_event";
import { stopPropagation } from "../common/dom/stop_propagation";
import { CodeMirror, loadCodeMirror } from "../resources/codemirror.ondemand";
import { HomeAssistant } from "../types";
import "./ha-icon";
@@ -58,7 +57,7 @@ export class HaCodeEditor extends ReactiveElement {
@state() private _value = "";
private _loadedCodeMirror?: CodeMirror;
private _loadedCodeMirror?: typeof import("../resources/codemirror");
private _iconList?: Completion[];
@@ -110,7 +109,7 @@ export class HaCodeEditor extends ReactiveElement {
// Ensure CodeMirror module is loaded before any update
protected override async scheduleUpdate() {
this._loadedCodeMirror ??= await loadCodeMirror();
this._loadedCodeMirror ??= await import("../resources/codemirror");
super.scheduleUpdate();
}

View File

@@ -64,6 +64,7 @@ class HaConfigEntryPicker extends LitElement {
type: "icon",
darkOptimized: this.hass.themes?.darkMode,
})}
crossorigin="anonymous"
referrerpolicy="no-referrer"
@error=${this._onImageError}
@load=${this._onImageLoad}

View File

@@ -269,37 +269,61 @@ export class HaCountryPicker extends LitElement {
@property() public label?: string;
@property() public countries?: string[];
@property() public helper?: string;
@property({ type: Boolean }) public required = false;
@property({ type: Boolean, reflect: true }) public disabled = false;
private _getOptions = memoizeOne((language?: string) => {
const countryDisplayNames =
Intl && "DisplayNames" in Intl
? new Intl.DisplayNames(language, {
type: "region",
fallback: "code",
})
: undefined;
@property({ type: Boolean }) public noSort = false;
const options = COUNTRIES.map((country) => ({
value: country,
label: countryDisplayNames ? countryDisplayNames.of(country)! : country,
}));
options.sort((a, b) =>
caseInsensitiveStringCompare(a.label, b.label, language)
);
return options;
});
private _getOptions = memoizeOne(
(language?: string, countries?: string[]) => {
let options: { label: string; value: string }[] = [];
const countryDisplayNames =
Intl && "DisplayNames" in Intl
? new Intl.DisplayNames(language, {
type: "region",
fallback: "code",
})
: undefined;
if (countries) {
options = countries.map((country) => ({
value: country,
label: countryDisplayNames
? countryDisplayNames.of(country)!
: country,
}));
} else {
options = COUNTRIES.map((country) => ({
value: country,
label: countryDisplayNames
? countryDisplayNames.of(country)!
: country,
}));
}
if (!this.noSort) {
options.sort((a, b) =>
caseInsensitiveStringCompare(a.label, b.label, language)
);
}
return options;
}
);
protected render() {
const options = this._getOptions(this.language);
const options = this._getOptions(this.language, this.countries);
return html`
<ha-select
.label=${this.label}
.value=${this.value}
.required=${this.required}
.helper=${this.helper}
.disabled=${this.disabled}
@selected=${this._changed}
@closed=${stopPropagation}

View File

@@ -15,10 +15,11 @@ import {
CSSResultGroup,
html,
LitElement,
nothing,
PropertyValues,
TemplateResult,
} from "lit";
import { customElement, property } from "lit/decorators";
import { customElement, property, state } from "lit/decorators";
import { calcDate } from "../common/datetime/calc_date";
import { firstWeekdayIndex } from "../common/datetime/first_weekday";
import { formatDate } from "../common/datetime/format_date";
@@ -29,6 +30,7 @@ import { HomeAssistant } from "../types";
import "./date-range-picker";
import "./ha-svg-icon";
import "./ha-textfield";
import "./ha-icon-button";
export interface DateRangePickerRanges {
[key: string]: [Date, Date];
@@ -44,6 +46,8 @@ export class HaDateRangePicker extends LitElement {
@property() public ranges?: DateRangePickerRanges | false;
@state() private _ranges?: DateRangePickerRanges;
@property() public autoApply = false;
@property() public timePicker = true;
@@ -54,8 +58,22 @@ export class HaDateRangePicker extends LitElement {
@property({ type: String }) private _rtlDirection = "ltr";
protected willUpdate() {
if (!this.hasUpdated && this.ranges === undefined) {
@property({ type: Boolean }) private minimal = false;
@property() public openingDirection?: "right" | "left" | "center" | "inline";
@state() private _calcedOpeningDirection?:
| "right"
| "left"
| "center"
| "inline";
protected willUpdate(changedProps: PropertyValues) {
if (
(!this.hasUpdated && this.ranges === undefined) ||
(changedProps.has("hass") &&
this.hass?.localize !== changedProps.get("hass")?.localize)
) {
const today = new Date();
const weekStartsOn = firstWeekdayIndex(this.hass.locale);
const weekStart = calcDate(
@@ -77,7 +95,7 @@ export class HaDateRangePicker extends LitElement {
}
);
this.ranges = {
this._ranges = {
[this.hass.localize("ui.components.date-range-picker.ranges.today")]: [
calcDate(today, startOfDay, this.hass.locale, this.hass.config, {
weekStartsOn,
@@ -133,55 +151,76 @@ export class HaDateRangePicker extends LitElement {
<date-range-picker
?disabled=${this.disabled}
?auto-apply=${this.autoApply}
?time-picker=${this.timePicker}
time-picker=${this.timePicker}
twentyfour-hours=${this._hour24format}
start-date=${this.startDate}
end-date=${this.endDate}
?ranges=${this.ranges !== false}
opening-direction=${this.openingDirection ||
this._calcedOpeningDirection}
first-day=${firstWeekdayIndex(this.hass.locale)}
>
<div slot="input" class="date-range-inputs">
<ha-svg-icon .path=${mdiCalendar}></ha-svg-icon>
<ha-textfield
.value=${this.timePicker
? formatDateTime(
this.startDate,
this.hass.locale,
this.hass.config
)
: formatDate(this.startDate, this.hass.locale, this.hass.config)}
.label=${this.hass.localize(
"ui.components.date-range-picker.start_date"
)}
.disabled=${this.disabled}
@click=${this._handleInputClick}
readonly
></ha-textfield>
<ha-textfield
.value=${this.timePicker
? formatDateTime(this.endDate, this.hass.locale, this.hass.config)
: formatDate(this.endDate, this.hass.locale, this.hass.config)}
.label=${this.hass.localize(
"ui.components.date-range-picker.end_date"
)}
.disabled=${this.disabled}
@click=${this._handleInputClick}
readonly
></ha-textfield>
<div slot="input" class="date-range-inputs" @click=${this._handleClick}>
${!this.minimal
? html`<ha-svg-icon .path=${mdiCalendar}></ha-svg-icon>
<ha-textfield
.value=${this.timePicker
? formatDateTime(
this.startDate,
this.hass.locale,
this.hass.config
)
: formatDate(
this.startDate,
this.hass.locale,
this.hass.config
)}
.label=${this.hass.localize(
"ui.components.date-range-picker.start_date"
)}
.disabled=${this.disabled}
@click=${this._handleInputClick}
readonly
></ha-textfield>
<ha-textfield
.value=${this.timePicker
? formatDateTime(
this.endDate,
this.hass.locale,
this.hass.config
)
: formatDate(
this.endDate,
this.hass.locale,
this.hass.config
)}
.label=${this.hass.localize(
"ui.components.date-range-picker.end_date"
)}
.disabled=${this.disabled}
@click=${this._handleInputClick}
readonly
></ha-textfield>`
: html`<ha-icon-button
.label=${this.hass.localize(
"ui.components.date-range-picker.select_date_range"
)}
.path=${mdiCalendar}
></ha-icon-button>`}
</div>
${this.ranges
${this.ranges !== false && (this.ranges || this._ranges)
? html`<div
slot="ranges"
class="date-range-ranges"
.dir=${this._rtlDirection}
>
<mwc-list @action=${this._setDateRange} activatable>
${Object.keys(this.ranges).map(
(name) => html`<mwc-list-item> ${name} </mwc-list-item>`
${Object.keys(this.ranges || this._ranges!).map(
(name) => html`<mwc-list-item>${name}</mwc-list-item>`
)}
</mwc-list>
</div>`
: ""}
: nothing}
<div slot="footer" class="date-range-footer">
<mwc-button @click=${this._cancelDateRange}
>${this.hass.localize("ui.common.cancel")}</mwc-button
@@ -197,7 +236,9 @@ export class HaDateRangePicker extends LitElement {
}
private _setDateRange(ev: CustomEvent<ActionDetail>) {
const dateRange = Object.values(this.ranges!)[ev.detail.index];
const dateRange = Object.values(this.ranges || this._ranges!)[
ev.detail.index
];
const dateRangePicker = this._dateRangePicker;
dateRangePicker.clickRange(dateRange);
dateRangePicker.clickedApply();
@@ -225,6 +266,22 @@ export class HaDateRangePicker extends LitElement {
}
}
private _handleClick() {
// calculate opening direction if not set
if (!this._dateRangePicker.open && !this.openingDirection) {
const datePickerPosition = this.getBoundingClientRect().x;
let opens: "right" | "left" | "center" | "inline";
if (datePickerPosition > (2 * window.innerWidth) / 3) {
opens = "left";
} else if (datePickerPosition < window.innerWidth / 3) {
opens = "right";
} else {
opens = "center";
}
this._calcedOpeningDirection = opens;
}
}
static get styles(): CSSResultGroup {
return css`
ha-svg-icon {
@@ -234,6 +291,10 @@ export class HaDateRangePicker extends LitElement {
direction: var(--direction);
}
ha-icon-button {
direction: var(--direction);
}
.date-range-inputs {
display: flex;
align-items: center;

View File

@@ -94,6 +94,8 @@ export class HaDialog extends DialogBase {
}
.mdc-dialog__title {
padding: 24px 24px 0 24px;
text-overflow: ellipsis;
overflow: hidden;
}
.mdc-dialog__actions {
padding: 12px 24px 12px 24px;

View File

@@ -163,10 +163,7 @@ export class HaExpansionPanel extends LitElement {
box-shadow: none;
border-width: 1px;
border-style: solid;
border-color: var(
--ha-card-border-color,
var(--divider-color, #e0e0e0)
);
border-color: var(--outline-color);
border-radius: var(--ha-card-border-radius, 12px);
}

View File

@@ -66,6 +66,10 @@ export const computeInitialHaFormData = (
typeof firstOption === "string" ? firstOption : firstOption.value;
data[field.name] = selector.select.multiple ? [val] : val;
}
} else if ("country" in selector) {
if (selector.country?.countries?.length) {
data[field.name] = selector.country.countries[0];
}
} else if ("duration" in selector) {
data[field.name] = {
hours: 0,

View File

@@ -57,8 +57,7 @@ export class HaFormInteger extends LitElement implements HaFormElement {
`
: ""}
<ha-slider
pin
ignore-bar-touch
labeled
.value=${this._value}
.min=${this.schema.valueMin}
.max=${this.schema.valueMax}

View File

@@ -138,15 +138,13 @@ export class HaFormString extends LitElement implements HaFormElement {
}
ha-icon-button {
position: absolute;
top: 1em;
right: 12px;
--mdc-icon-button-size: 24px;
color: var(--secondary-text-color);
}
ha-icon-button {
top: 8px;
right: 8px;
inset-inline-start: initial;
inset-inline-end: 12px;
inset-inline-end: 8px;
--mdc-icon-button-size: 40px;
--mdc-icon-size: 20px;
color: var(--secondary-text-color);
direction: var(--direction);
}
`;

View File

@@ -189,8 +189,13 @@ export class HaForm extends LitElement implements HaFormElement {
? ev.detail.value
: { [schema.name]: ev.detail.value };
this.data = {
...this.data,
...newValue,
};
fireEvent(this, "value-changed", {
value: { ...this.data, ...newValue },
value: this.data,
});
});
}

View File

@@ -7,22 +7,25 @@ import { fireEvent } from "../common/dom/fire_event";
@customElement("ha-formfield")
export class HaFormfield extends FormfieldBase {
protected _labelClick() {
const input = this.input;
if (input) {
input.focus();
switch (input.tagName) {
case "HA-CHECKBOX":
case "HA-RADIO":
if ((input as any).disabled) {
break;
}
(input as any).checked = !(input as any).checked;
fireEvent(input, "change");
break;
default:
input.click();
break;
}
const input = this.input as HTMLInputElement | undefined;
if (!input) return;
input.focus();
if (input.disabled) {
return;
}
switch (input.tagName) {
case "HA-CHECKBOX":
input.checked = !input.checked;
fireEvent(input, "change");
break;
case "HA-RADIO":
input.checked = true;
fireEvent(input, "change");
break;
default:
input.click();
break;
}
}

View File

@@ -12,19 +12,8 @@ export class HaIconButtonArrowNext extends LitElement {
@property() public label?: string;
@state() private _icon = mdiArrowRight;
public connectedCallback() {
super.connectedCallback();
// wait to check for direction since otherwise direction is wrong even though top level is RTL
setTimeout(() => {
this._icon =
window.getComputedStyle(this).direction === "ltr"
? mdiArrowRight
: mdiArrowLeft;
}, 100);
}
@state() private _icon =
document.dir === "ltr" ? mdiArrowRight : mdiArrowLeft;
protected render(): TemplateResult {
return html`

View File

@@ -12,19 +12,8 @@ export class HaIconButtonArrowPrev extends LitElement {
@property() public label?: string;
@state() private _icon = mdiArrowLeft;
public connectedCallback() {
super.connectedCallback();
// wait to check for direction since otherwise direction is wrong even though top level is RTL
setTimeout(() => {
this._icon =
window.getComputedStyle(this).direction === "ltr"
? mdiArrowLeft
: mdiArrowRight;
}, 100);
}
@state() private _icon =
document.dir === "ltr" ? mdiArrowLeft : mdiArrowRight;
protected render(): TemplateResult {
return html`

View File

@@ -12,19 +12,8 @@ export class HaIconButtonNext extends LitElement {
@property() public label?: string;
@state() private _icon = mdiChevronRight;
public connectedCallback() {
super.connectedCallback();
// wait to check for direction since otherwise direction is wrong even though top level is RTL
setTimeout(() => {
this._icon =
window.getComputedStyle(this).direction === "ltr"
? mdiChevronRight
: mdiChevronLeft;
}, 100);
}
@state() private _icon =
document.dir === "ltr" ? mdiChevronRight : mdiChevronLeft;
protected render(): TemplateResult {
return html`

View File

@@ -12,19 +12,8 @@ export class HaIconButtonPrev extends LitElement {
@property() public label?: string;
@state() private _icon = mdiChevronLeft;
public connectedCallback() {
super.connectedCallback();
// wait to check for direction since otherwise direction is wrong even though top level is RTL
setTimeout(() => {
this._icon =
window.getComputedStyle(this).direction === "ltr"
? mdiChevronLeft
: mdiChevronRight;
}, 100);
}
@state() private _icon =
document.dir === "ltr" ? mdiChevronLeft : mdiChevronRight;
protected render(): TemplateResult {
return html`

View File

@@ -1,20 +1,11 @@
import { mdiChevronLeft, mdiChevronRight } from "@mdi/js";
import { customElement } from "lit/decorators";
import { customElement, property } from "lit/decorators";
import { HaSvgIcon } from "./ha-svg-icon";
@customElement("ha-icon-next")
export class HaIconNext extends HaSvgIcon {
public connectedCallback() {
super.connectedCallback();
// wait to check for direction since otherwise direction is wrong even though top level is RTL
setTimeout(() => {
this.path =
window.getComputedStyle(this).direction === "ltr"
? mdiChevronRight
: mdiChevronLeft;
}, 100);
}
@property() public override path =
document.dir === "ltr" ? mdiChevronRight : mdiChevronLeft;
}
declare global {

View File

@@ -1,20 +1,11 @@
import { mdiChevronLeft, mdiChevronRight } from "@mdi/js";
import { customElement } from "lit/decorators";
import { customElement, property } from "lit/decorators";
import { HaSvgIcon } from "./ha-svg-icon";
@customElement("ha-icon-prev")
export class HaIconPrev extends HaSvgIcon {
public connectedCallback() {
super.connectedCallback();
// wait to check for direction since otherwise direction is wrong even though top level is RTL
setTimeout(() => {
this.path =
window.getComputedStyle(this).direction === "ltr"
? mdiChevronLeft
: mdiChevronRight;
}, 100);
}
@property() public override path =
document.dir === "ltr" ? mdiChevronLeft : mdiChevronRight;
}
declare global {

View File

@@ -1,9 +1,9 @@
import {
css,
CSSResultGroup,
html,
LitElement,
PropertyValues,
css,
html,
nothing,
} from "lit";
import { customElement, property, state } from "lit/decorators";
@@ -11,12 +11,12 @@ import { fireEvent } from "../common/dom/fire_event";
import { debounce } from "../common/util/debounce";
import { CustomIcon, customIcons } from "../data/custom_icons";
import {
checkCacheVersion,
Chunks,
findIconChunk,
getIcon,
Icons,
MDI_PREFIXES,
checkCacheVersion,
findIconChunk,
getIcon,
writeCache,
} from "../data/iconsets";
import "./ha-svg-icon";
@@ -47,6 +47,8 @@ export class HaIcon extends LitElement {
@state() private _path?: string;
@state() private _secondaryPath?: string;
@state() private _viewBox?: string;
@state() private _legacy = false;
@@ -55,6 +57,7 @@ export class HaIcon extends LitElement {
super.willUpdate(changedProps);
if (changedProps.has("icon")) {
this._path = undefined;
this._secondaryPath = undefined;
this._viewBox = undefined;
this._loadIcon();
}
@@ -70,6 +73,7 @@ export class HaIcon extends LitElement {
}
return html`<ha-svg-icon
.path=${this._path}
.secondaryPath=${this._secondaryPath}
.viewBox=${this._viewBox}
></ha-svg-icon>`;
}
@@ -175,6 +179,7 @@ export class HaIcon extends LitElement {
return;
}
this._path = icon.path;
this._secondaryPath = icon.secondaryPath;
this._viewBox = icon.viewBox;
}

View File

@@ -1,90 +0,0 @@
import { html } from "@polymer/polymer/lib/utils/html-tag";
/* eslint-plugin-disable lit */
import { PolymerElement } from "@polymer/polymer/polymer-element";
import "./ha-icon";
import "./ha-slider";
class HaLabeledSlider extends PolymerElement {
static get template() {
return html`
<style>
:host {
display: block;
}
.title {
margin: 5px 0 8px;
color: var(--primary-text-color);
}
.slider-container {
display: flex;
}
ha-icon {
margin-top: 4px;
color: var(--secondary-text-color);
}
ha-slider {
flex-grow: 1;
background-image: var(--ha-slider-background);
border-radius: 4px;
}
</style>
<div class="title">[[_getTitle()]]</div>
<div class="extra-container"><slot name="extra"></slot></div>
<div class="slider-container">
<ha-icon icon="[[icon]]" hidden$="[[!icon]]"></ha-icon>
<ha-slider
min="[[min]]"
max="[[max]]"
step="[[step]]"
pin="[[pin]]"
disabled="[[disabled]]"
value="{{value}}"
></ha-slider>
</div>
<template is="dom-if" if="[[helper]]">
<ha-input-helper-text>[[helper]]</ha-input-helper-text>
</template>
`;
}
_getTitle() {
return `${this.caption}${this.caption && this.required ? " *" : ""}`;
}
static get properties() {
return {
caption: String,
disabled: Boolean,
required: Boolean,
min: Number,
max: Number,
pin: Boolean,
step: Number,
helper: String,
extra: {
type: Boolean,
value: false,
},
ignoreBarTouch: {
type: Boolean,
value: true,
},
icon: {
type: String,
value: "",
},
value: {
type: Number,
notify: true,
},
};
}
}
customElements.define("ha-labeled-slider", HaLabeledSlider);

View File

@@ -0,0 +1,96 @@
import { CSSResultGroup, LitElement, css, html, nothing } from "lit";
import { customElement, property } from "lit/decorators";
import "./ha-icon";
import "./ha-slider";
import { fireEvent } from "../common/dom/fire_event";
@customElement("ha-labeled-slider")
class HaLabeledSlider extends LitElement {
@property() public labeled? = false;
@property() public caption?: string;
@property() public disabled?: boolean;
@property() public required?: boolean;
@property() public min: number = 0;
@property() public max: number = 100;
@property() public step: number = 1;
@property() public helper?: string;
@property() public extra = false;
@property() public icon?: string;
@property() public value?: number;
protected render() {
return html`
<div class="title">${this._getTitle()}</div>
<div class="extra-container"><slot name="extra"></slot></div>
<div class="slider-container">
${this.icon ? html`<ha-icon icon=${this.icon}></ha-icon>` : nothing}
<ha-slider
.min=${this.min}
.max=${this.max}
.step=${this.step}
labeled=${this.labeled}
.disabled=${this.disabled}
.value=${this.value}
@change=${this._inputChanged}
></ha-slider>
</div>
${this.helper
? html`<ha-input-helper-text> ${this.helper} </ha-input-helper-text>`
: nothing}
`;
}
private _getTitle(): string {
return `${this.caption}${this.caption && this.required ? " *" : ""}`;
}
private _inputChanged(ev) {
fireEvent(this, "value-changed", {
value: Number((ev.target as any).value),
});
}
static get styles(): CSSResultGroup {
return css`
:host {
display: block;
}
.title {
margin: 5px 0 8px;
color: var(--primary-text-color);
}
.slider-container {
display: flex;
}
ha-icon {
margin-top: 8px;
color: var(--secondary-text-color);
}
ha-slider {
flex-grow: 1;
background-image: var(--ha-slider-background);
border-radius: 4px;
}
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-labeled-slider": HaLabeledSlider;
}
}

View File

@@ -1,19 +1,16 @@
import { css } from "lit";
import { customElement } from "lit/decorators";
import { OutlinedButton } from "@material/web/button/internal/outlined-button";
import { styles as outlinedStyles } from "@material/web/button/internal/outlined-styles.css";
import { styles as sharedStyles } from "@material/web/button/internal/shared-styles.css";
import { MdOutlinedButton } from "@material/web/button/outlined-button";
@customElement("ha-outlined-button")
export class HaOutlinedButton extends OutlinedButton {
export class HaOutlinedButton extends MdOutlinedButton {
static override styles = [
sharedStyles,
outlinedStyles,
...super.styles,
css`
:host {
--ha-icon-display: block;
--md-sys-color-primary: var(--primary-text-color);
--md-sys-color-outline: var(--divider-color);
--md-sys-color-outline: var(--outline-color);
}
`,
];

View File

@@ -1,21 +1,11 @@
import { css } from "lit";
import { customElement } from "lit/decorators";
import { IconButton } from "@material/web/iconbutton/internal/icon-button";
import { styles as outlinedStyles } from "@material/web/iconbutton/internal/outlined-styles.css";
import { styles as sharedStyles } from "@material/web/iconbutton/internal/shared-styles.css";
import { MdOutlinedIconButton } from "@material/web/iconbutton/outlined-icon-button";
@customElement("ha-outlined-icon-button")
export class HaOutlinedIconButton extends IconButton {
protected override getRenderClasses() {
return {
...super.getRenderClasses(),
outlined: true,
};
}
export class HaOutlinedIconButton extends MdOutlinedIconButton {
static override styles = [
sharedStyles,
outlinedStyles,
...super.styles,
css`
:host {
--ha-icon-display: block;
@@ -29,11 +19,6 @@ export class HaOutlinedIconButton extends IconButton {
--md-ripple-hover-opacity: 0;
--md-ripple-pressed-opacity: 0;
}
.outlined {
/* Fix md-outlined-icon-button padding and margin for iOS */
padding: 0;
margin: 0;
}
`,
];
}

View File

@@ -154,6 +154,8 @@ export class HaRelatedItems extends LitElement {
useFallback: true,
darkOptimized: this.hass.themes?.darkMode,
})}
crossorigin="anonymous"
referrerpolicy="no-referrer"
alt=${entry.domain}
slot="graphic"
/>

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