Compare commits

...

34 Commits

Author SHA1 Message Date
Thomas Lovén
aecbfeaaa0 Force editor rebuild on stack card switch 2022-05-31 11:39:56 +00:00
Thomas Lovén
498732566e Highlight cards in stacks 2022-05-31 11:18:37 +00:00
Thomas Lovén
b22c51bc2c Highlight entities card rows 2022-05-31 11:16:02 +00:00
Thomas Lovén
5bc2fd059c Allow data passed from editor to preview 2022-05-31 11:13:41 +00:00
Joakim Sørensen
0183e32267 Use supervisor envs instead of hassio (#12812) 2022-05-30 12:46:43 +02:00
Raman Gupta
588fd87654 Update style of zwave_js controller statistics (#12810) 2022-05-27 15:33:07 -05:00
Philip Allgaier
e2944b098d Align "Browse Media" button while being wrapped (#12800) 2022-05-27 00:37:43 +00:00
Bram Kragten
cbb962f084 Fix width of application creds page (#12806) 2022-05-26 23:59:26 +02:00
Paulus Schoutsen
93f4ae1bea Add redirects to cast to catch some common mistakes in custom cards (#12808) 2022-05-26 23:58:54 +02:00
Bram Kragten
6797e17fc8 Merge branch 'master' into dev 2022-05-26 23:23:54 +02:00
Bram Kragten
6e58cd5d12 Bumped version to 20220526.0 2022-05-26 23:21:56 +02:00
Bram Kragten
a72fd19b73 Fix combo box inside dialog (#12805) 2022-05-26 20:28:05 +00:00
Zack Barett
41c61a2895 Update Narrow Order on Device Page (#12801)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2022-05-26 22:05:17 +02:00
Paulus Schoutsen
f35af9ed98 Bump HAWS to 7.1.0 (#12804) 2022-05-26 22:03:07 +02:00
Philip Allgaier
abf7cb7a74 Add dynamic header/footer config determination and update struct (#12795) 2022-05-26 21:02:44 +02:00
Zack Barett
6ec2e32241 Hide Cloud information a bit more (#12802) 2022-05-26 11:33:37 -07:00
Yosi Levy
b7cdd9a22f Merge pull request #12772 from yosilevy/RTL-switch
Various RTL fixes
2022-05-26 21:04:50 +03:00
Yosi Levy
6278eefc5d Remove import 2022-05-26 20:50:52 +03:00
Philip Allgaier
73cf0b54c9 Dynamically determine the correct action config struct (#12798) 2022-05-26 19:26:25 +02:00
Zack Barett
00dcecabb7 Set Error if entity is unavailable (#12791) 2022-05-26 19:25:00 +02:00
Zack Barett
c9df93bc54 Fix Zwave Alerts on device page (#12785)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
2022-05-26 10:15:24 -05:00
Zack Barett
3550a8c263 Fix Switch as X unable to change to a new type (#12797) 2022-05-26 10:15:14 -05:00
Zack Barett
c0d30c56d6 Fix Media Player More info cramped controls (#12790) 2022-05-26 16:59:59 +02:00
Zack Barett
10813d06b6 Use Hardware Integration for System Menu (#12789) 2022-05-26 12:57:14 +02:00
Yosi Levy
d65e45ecfd Various RTL fixes 2022-05-25 06:01:40 +03:00
Paulus Schoutsen
1b158d8310 Merge pull request #12619 from home-assistant/cherry-pick-search
20220504.1
2022-05-07 14:14:39 -07:00
Zack
9d2fcec458 Version Bump 2022-05-06 22:30:34 -05:00
Zack Barett
60cd6c65f0 Revert #10991 (#12618) 2022-05-06 22:00:01 -05:00
Bram Kragten
a39af9c307 Merge pull request #12582 from home-assistant/dev 2022-05-04 13:28:04 +02:00
Paulus Schoutsen
02af4c2156 Bump Master to 20220503.0 (#12567)
* Use selectors for add-on configurations (#12234)

* replace ToggleSwitch with new LightSwitch (#12218)

* Fix statistics chart for sum stat without state (#12238)

* Use selectors for add-on network configuration (#12235)

* Use selectors for add-on network configuration

* Show container port as UOM if advanced user

* adjust

* Only show "required" indicator if we have a selector label (#12241)

* Lineup sidebar badges

* Exclude hidden entities from area card

* Fix entity and device selector with `multiple: true`

* Adjust import

* Guard for partial translations (#12296)

* Fix add-on security rating range (#12300)

* Use more text selector types for add-on configuration (#12303)

* Prevent empty brackets if no manufacturer during config entry creation (#12288)

* Fix endless loading screen in zwave-js config (#12295)

* Update cloud text (#12305)

* Select default mode if none set (#12306)

* Decode view path URL (#12310)

* Always render title field (#12319)

* Use new mdi icons for smoke and co detection (#12323)

* Split only on first comma in media browser (#12331)

* Allow tapping on the name on a picture entity card (#12332)

* RTL calendar fix - arrows fix and views fix (#12314)

* RTL calendar fix - arrows fix and views fix

* Removed path attributes

* Quickly search for entities from the Overview Dashboard (#12324)

* Allow selecting multiple entities for state trigger (#12334)

Co-authored-by: Zack Barett <zackbarett@hey.com>

* Add Template selector (#12348)

* Add basic frontend support for siren (#12345)

* Fix strict error handling in developer tools templates (#12352)

* Bump HAWS to 7.0.3 (#12358)

* Add clear skipped to update more-info dialog (#12361)

* Adding blueprint input description markdown/multi-line support (#12291)

* Github no longer supports the (insecure) git protocol (#12359)

* Add if/else automation/script action (#12301)

Co-authored-by: Zack Barett <zackbarett@hey.com>

* Add stop script/automation action (#12299)

* Getting started on Configuration Changes (#12309)

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

* Config menu updates to get it ready for nightly (#12368)

* Bumped version to 20220420.0 (#12369)

* Use template selector in wait_template (#12366)

* Add jinja2 editor to template triggers/conditions (#12365)

Co-authored-by: Zack <zackbarett@hey.com>

* Fix for monetary entities (#12378)

* Add entity search tip to dev-tools set state (#12355)

* Added ability to retry on initialization errors. (#12103)

* RTL fixes (#12367)

* zwave_js: Add title tag to config box heading (#12387)

* Accept new value when hitting ENTER to close a prompt dialog (#12360)

Co-authored-by: Zack Barett <zackbarett@hey.com>

* RTL reading orders and alignments in system log (#12388)

* Add automation editor for calendar trigger (#12343)

* Add calendar event end trigger to automation editor (#12389)

* Show vacuum state in more-info dialog for StateVacuumEntity (#12391)

* Add Empty list item for None (#12356)

* Force LTR on time & number inputs (#12393)

* Fix Dashboard URLs (#12394)

* Update zwavejs controller model (#12390)

* Configuration Menu Updates 3 (#12377)

* Bumped version to 20220424.0

* Config Menu: Addressing Comments in #12377 (#12399)

* Add shorthand condition to the gallery (#12400)

* Virtualize Media Player Grid (#11898)

* Hide supervisor only config, fix backup config page (#12401)

* Fix broken cards being able to crash entire view (#11440)

* Add supervisor network interface settings (#12403)

* Fix zones (#12409)

* Add supervisor hostname config (#12407)

* Add Hardware Page to Configuration System Menu (#12405)

* Add Supervisor logs to core page (#12410)

* Allow Showing Skipped Updates on Updates Page (#12415)

* Configuration Menu Cleanup items (#12413)

* Backup Page - Will load which is available (#12414)

* Move System Health to a page (#12412)

* Show what updates are skipped (#12418)

* Don't show tabs in supervisor (#12417)

* Better gauge segment coloring (#11570)

* Move Data Disk Moving to Storage (#12416)

* Add supervisor, OS version info to about page (#12421)

* Add supervisor, OS version info to about page

* description

* description

* Allow for checking for updates (#12422)

* Fix title and description for menu step in options flow (#12420)

* link to updates page (#12423)

* Show usage stats in System Health (#12424)

* Bumped version to 20220425.0 (#12425)

* Format sensors with state class duration (#12426)

* Guard against non OS installation (#12427)

* Typo in en.json (#12428)

* Move unsupported and unhealthy alerts (#12431)

* Fix log syntax highlight when fetching logs from supervisor (#12430)

* Resources lovelace should just go back (#12432)

* Redirect hassio system my links to new locations (#12429)

* Fix backup back path (#12435)

* Add join/leave beta to updates panel (#12436)

* Fix settings row width (#12438)

* Dont show tabs when less than 2 (#12439)

* Set border radius in config to 8px (#12437)

* Fix incorrect text if no backups are found (#12441)

* Add header to supervisor backups page (#12444)

* Fix content display for `ha-network` after #12438 (#12445)

* Fix content display for `ha-network` after #12438

* Add var default

* Add title to backups config page (#12442)

* Fix integration page on mobile (#12447)

* Add "m" keyboard shortcut to get to the create my link page (#12451)

* Terms based entities search (#10991)

* Small edits on config menu (#12440)

* Fix for backup overflow (#12454)

* Update the hint for key C (#12458)

* Fix when creating new area in picker #11392 (#12457)

* Fix more info input number #12396 (#12456)

* Update Configuration badge color to be accent color to match (#12455)

* Move Provider Selection to Menu on top header (#12443)

* Move the analytics link (#12459)

* Fix Updates Page Toast - Move to overflow (#12453)

* Move Zones Edit to General config + add general config page (#12452)

* Move Zones Edit to General config + add general

* Update src/translations/en.json

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>

* add paper tooltip back for yaml

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>

* Tweak menu descriptions (#12460)

* Fix my link for config dashboard and profile (#12461)

* Fix my link for config dashboard and profile

* add server control redirect

Co-authored-by: Zack <zackbarett@hey.com>

* Fix icon alignment in nav list (#12463)

* Add a tip for my shortcut (#12462)

* Move Restart to Overflow and yaml config advanced (#12446)

* Move Restart to Overflow and yaml config advanced

* Move around YAML Config page

* Move to developer tools

* Make card actions

* Update Translations

* Bumped version to 20220427.0

* Use correct label for update config menu (#12465)

* Make helper option button more user friendly (#12468)

* Add hass-quick-bar-trigger event to trigger quickbar from supervisor (#12467)

* Use startsWith for m shortcut for partial match (#12464)

* Add supervisor redirects to m keyboard shortcut (#12466)

* Safeguard against non-existant area in device handling (#12475)

* RTL fix for log buttons (#12474)

* Fix YAML Config Invalid button (#12476)

* Small config fixes (#12472)

* Visual tweaks to YAML validation results (#12479)

* Add some bottom padding to YAML conf dev tools page (#12477)

Co-authored-by: Zack Barett <zackbarett@hey.com>

* Fix Restarting Home Assistant (#12480)

* Fix Restarting Home ASsistant

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

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>

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

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>

* reviews

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>

* Move General Up in the system menu (#12483)

* Media panel fix (#12485)

* add my redirects for new config pages (#12481)

* Add template editor to Markdown card editor (#12490)

* Address minor comments about config menu (#12492)

* Hide and sort secondary device automations (#12496)

* Evaluate condition shorthands in editors (#12473)

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>

* Add support for enabling/disabling trigger/condition/action (#12493)

* Add support for enabling/disabling trigger/condition/action

* Add more visual indication of disabled

* review

* margin

* Dont make overflow transparent

* Change color of bar

* Add parallel automation/script action (#12491)

* Add Board Names, Move All Hardware (#12484)

Co-authored-by: Joakim Sørensen <ludeeus@ludeeus.dev>
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>

* Change Restart to be a button, update dialogs (#12499)

* Bumped version to 20220428.0 (#12501)

* Fix Wrap menu and remove menu title (#12505)

* form-string password fix (#12507)

* Use media query for config menu mobile (#12510)

* Fix incorrect 3-dot menu labels (config hardware & storage) (#12512)

* Media browser RTL fixes (#12506)

* Fix `continue_on_timeout` default on `wait_template` automation visual editor (#12511)

* Support shorthand logical operators in script sequences (#12509)

* Only show Card Content if OS exist (#12513)

* Add condition shorthand to action types (#12514)

* Fix for external url not logged into cloud (#12516)

* Restart Home ASsistant button - Make less red and less big (#12515)

* Add actions to design gallery (#12518)

* Add actions to design gallery

* Update describe-action.ts

* Move integrations to System Health (#12504)

* Add if, parallel and stop action to trace graph (#12520)

* Bumped version to 20220429.0 (#12521)

* Change color of persons for real this time (#12527)

* Ignore modifier keys when forwarding events to quickbar (#12525)

* Add optional repository_url to supervisor_addon my link (#12524)

* Calendar-card fix (#12532)

* Handle condition shorthands in trace graphs (#12533)

* Make the "Aborted: Reauthentication successful" more user friendly (#12530)

Replace the "Aborted" in the title with the integration name to make the user error
messages more user friendly. The message itself ("Reauthentication successful" or "Missing configuraiton, etc) error
message is descriptive enought that we can replace the title with the integration
name and still preserve the meeting. The advance is that this doesn't confuse users
who are surprised by it saying "Aborted" when things were successful

https://github.com/home-assistant/core/issues/47135

* Prevent color temp selector mired exception (#12536)

* Fix some issues and feedback with About and system health (#12537)

* Add descriptions for actions (#12541)

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>

* Add repeat to trace timeline (#12547)

* Change name to Settings (#12548)

* Add trace timeline for if (#12543)

* Fix script graph parallel (#12545)

* Handle if in repeat (#12544)

* Add parallel action to trace timeline (#12549)

* Indicate things are disabled in trace graph (#12550)

* Indicate things are disabled in trace graph

* Update hat-script-graph.ts

* Bumped version to 20220502.0

* Add add-on logs to log selector (#12556)

* Fix Webhook Overflow (#12551)

* Search in Overflow on Mobile (#12552)

* Use ha-tip for yaml move tip (#12559)

* Update Quickbar Section Logic to include all (#12553)

* Use outline for cards on config pages (#12558)

* Add supervisor redirects to quickbar (#12557)

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

* Fix searching in hassio logs (#12560)

* Add disabled support to trace timeline and step details (#12555)

* Add new system menu descriptions (#12564)

* Add missing outlined to supervisor panel (#12565)

* Bumped version to 20220503.0 (#12566)

Co-authored-by: Joakim Sørensen <ludeeus@ludeeus.dev>
Co-authored-by: Marius <33354141+Mariusthvdb@users.noreply.github.com>
Co-authored-by: Erik Montnemery <erik@montnemery.com>
Co-authored-by: Philip Allgaier <mail@spacegaier.de>
Co-authored-by: Franck Nijhof <git@frenck.dev>
Co-authored-by: Kuba Wolanin <hi@kubawolanin.com>
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: Yosi Levy <37745463+yosilevy@users.noreply.github.com>
Co-authored-by: Raman Gupta <7243222+raman325@users.noreply.github.com>
Co-authored-by: Simon Vallières <simon@vallieres.ca>
Co-authored-by: Eric Stern <stormalong@gmail.com>
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
Co-authored-by: Wesley Vos <17592840+Wesley-Vos@users.noreply.github.com>
Co-authored-by: Mark Lopez <m@silvenga.com>
Co-authored-by: Allen Porter <allen@thebends.org>
Co-authored-by: yangqian <yanyangqian@gmail.com>
Co-authored-by: Thomas Lovén <thomasloven@gmail.com>
Co-authored-by: Netzwerkfehler <16437929+Netzwerkfehler@users.noreply.github.com>
Co-authored-by: Artem Sorokin <artem@sorokin.pp.ru>
Co-authored-by: Jaroslav Hanslík <kukulich@kukulich.cz>
Co-authored-by: Johann Vanackere <johann.vanackere@gmail.com>
Co-authored-by: Bruno Maia <bruno.mm.maia@gmail.com>
2022-05-03 11:14:32 -07:00
Zack Barett
d02cd122a9 Merge pull request #12233 from home-assistant/dev
Co-authored-by: Joakim Sørensen <ludeeus@ludeeus.dev>
Co-authored-by: Philip Allgaier <mail@spacegaier.de>
Co-authored-by: Zack Barett <zackbarett@hey.com>
2022-04-05 18:02:02 -05:00
Joakim Sørensen
8e962fdecb Use installed_version for update entities (#12194) 2022-04-01 19:29:26 +02:00
Bram Kragten
1f65193a97 Merge pull request #12193 from home-assistant/dev 2022-04-01 18:56:12 +02:00
Bram Kragten
24484d0e74 20220330.0 (#12165)
* Add a docs icon to the config flow dialog

* Use same help icon everywhere

* Fix quickbar overlaying, fix click handling (#11900)

* Supervisor mobile click accessibility (#11915)

* Convert objects to string in config flow error (#11908)

* Fix datepicker triangle (#11920)

* Always show tab labels (#11919)

* Remove zwave and ozw panels (#11911)

Remove zwave and ozw panels

* Convert lovelace config dialogs to ha-form (#11910)

* Guard setting up config flow for an unsupported domain (#11937)

* Show triggered vars on click (#11924)

* Allow marking YAML editor as read only (#11960)

* Convert inputs (#11907)

* Convert inputs

* Update dialog-thingtalk.ts

* imports

* Remove some additional old zwave code (#11941)

* Correct media upload error + add file name (#11949)

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

* Fix humidifier more info mode dropdown (#11964)

* Make min width of select configurable (#11965)

* Fix for Statistics Editor (#11942)

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

* A11y expansion panel (#11967)

* Convert file upload to mdc (#11906)

* Add location selector, convert zone editor (#11902)

* Add systemd_resolved unsupported reason (#11971)

* replace default switch icon 

to  make it stand out against a power entity which uses the same mdiFlash https://github.com/home-assistant/core/issues/67620#issuecomment-1061949527

suggest the Outline version, so create a subtle difference with the on/off icons.

* Allow selecting multiple entities (#11986)

* Fix theme setting (#11977)

* Update Style of Design Page (#11982)

* change icon to mimic physical device

and follow comments

* Use entities-picker in entity selector (#11990)

* #11971 Change order of alarm panel buttons (#11998)

* Fix zwave_js 'add/remove device' disabled bug (#12000)

* Fix zwave_js 'add/remove device' disabled bug

* revert extra change

* Fix zwave_js set config dropdown default value (#11974)

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>

* Fix changing cost number in energy settings (#12009)

* Fix Dashboard Editing (#12011)

* Fix For Selecting Device Class (#12010)

* Fix: Allow for deleting Input_select options (#12007)

* Script ID update with Alias (#12008)

* HAWS 6.1 (#12016)

* Bumped version to 20220301.1

* Bumped version to 20220301.2

* Bumped version to 20220312.0

* Add shade to device class overrides (#11874)

* Fix: Changing Blueprint Automation Name (#12036)

* Fix @changed where using ev.detail (#12043)

* Add all cover device classes (#12042)

* Rename Lovelace Dashboard to just Dashboard (#12044)

Co-authored-by: Zack Barett <zackbarett@hey.com>

* Add Color Temp Selector (#12041)

* Utilize Hide Hidden Entities

* Reviews

* add to demo

* Add `Brand` folder and `Our story` page (#11978)

Co-authored-by: Zack Barett <zackbarett@hey.com>

* Add HA to public folder and show in markdown

* Update Translations

* Disabled by

* remove 1

* Add Description of chosen

* Add icons and buttons

* Add Color RGB Selector (#12039)

* Add Date Selector

* Add ha-form context (#12062)

* test condition (#11925)

* Revamp URL form (#12060)

* Add support for menu data entry flow option (#12055)

* Add translation

* add to basic editor and update advanced style

* clean up

* Entity Status

* Add Devices Picker (#12056)

* Remvoe redunency

* Bumped version to 20220316.0

* Bump HAWS to 7.0.0 (#12067)

* Create new Logo page

* Add files via upload

* Ignore diagnostics not found exceptions (#12066)

* Bump HAWS to 7.0.1

* Update lock

* Add Date Time Selector (#12070)

* Add radio Form Logic to Select Selector (#12063)

* Bumped version to 20220317.0 (#12074)

* Update gallery/src/pages/brand/logo.markdown

Co-authored-by: Zack Barett <zackbarett@hey.com>

* Update gallery/src/pages/brand/logo.markdown

Co-authored-by: Zack Barett <zackbarett@hey.com>

* Update logo.markdown

* Fetch history with `no_attributes` for entities that do not need them (#12082)

* Update required version of MDI to 6.6.95

* Upload release assets (#11566)

Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>

* Update styles for hui-editor

Update the background-color and text-color of the app-toolbar in
hui-editor to match the styles of hui-root while in edit-mode.

Previously, these properties were set using undefined css variables that
could not be changed via themes (--dark-background-color and
--dark-text-color).

* Fix gas energy graph units if stats added by external source (#11892)

* Change Netlify preview URL (#12095)

* Update src/dialogs/config-flow/dialog-data-entry-flow.ts

* Stack Action Inputs in the Button Editor (#12076)

* Stack Action Inputs in the Button Editor

* update style

* Update for other editors

* Add support for update entities (#12059)

* Add support for update entities

* Apply suggestions from code review

Co-authored-by: Zack Barett <zackbarett@hey.com>

* Add to gallery

* implement xx%

* Adjustments for skipped

* Add progress bar

* Add UPDATE_SUPPORT_INSTALL

* Allow skipping without install support

* Add version to service call if supported

* Adjust changelog link

* Use Installing

* adjustments

* Use unavailable

Co-authored-by: Zack Barett <zackbarett@hey.com>

* Add support for integration type (#12077)

* Update When entity can change enabled or hidden (#12096)

* Add entity include and exclude to selector (#12078)

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>

* change from hidden to not shown (#12097)

* Add statistic adjust dialog (#12101)

Co-authored-by: Zack Barett <zackbarett@hey.com>

* Fix Duration Selector Default (#12098)

* Fix Duration Default

* USe initial form data function

* Bumped version to 20220322.0 (#12102)

* Create user types page and rename the category (#12089)

Co-authored-by: Zack Barett <zackbarett@hey.com>
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>

* Remove `setup.py` (#11593)

* Fix selecting 0 with number selector

* Update lock file with MDI updates

* Use update entities for showing updates on configuration panel (#12100)

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>

* Fix loading traces for automation with custom id (#12112)

* Only show docs link when showing a form

* Exclude restored automations from dashboard (#12113)

* Support descriptions in flow menu steps (#12108)

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>

* Sort selectors (#12120)

* Update type for backend (#12122)

* Fix issue where theme select does not appear when user's theme is deleted (#12104)

* Fix possibility to enable entity disabled by integration (#12121)

Co-authored-by: Zack Barett <zackbarett@hey.com>

* Allow rendering helper text from strings.json (#12119)

* Allow rendering helper text from strings.json

* Persistent helpers

* Update src/components/ha-base-time-input.ts

Co-authored-by: Zack Barett <zackbarett@hey.com>

* Update src/components/ha-base-time-input.ts

Co-authored-by: Zack Barett <zackbarett@hey.com>

* Add Day to duration selector (#12125)

* Add variables to automation trigger type

* Fix z-index map, always set icon for location selector (#12137)

* Make padding on settings row content consistent (#12139)

* Add Area Multiple Selector option (#12138)

* break theme picker out of lovelace (#12140)

* Allow binary sensor device class updates (#12124)

* Add selector initial values (#12142)

* Add badge to configuration sidebar to indicate pending updates (#12146)

* Bumped version to 20220329.0 (#12152)

* Add entity source API (#12149)

* Update adjust statistic dialog (#12118)

* Update text for adjust statistic dialog

* Change everything

* Import type

* Max show 5

* Revert back the API change

* Hide adjust button if no sum

* Adjustments

* Update src/panels/developer-tools/statistics/developer-tools-statistics.ts

* Render optional

Co-authored-by: Zack <zackbarett@hey.com>

* Fetch release notes for update entities that provides it (#12148)

* Fetch release notes for update entities that provides it

* lint

* Add support for new timer properties (#11940)

* Fix theme settings on design page (#12154)

* Allow ha-alert to be used in our markdown render (#12153)

* Allow device_tracker entities to use state_color (#12127)

* Automation description text overflow (#12040)

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

* Update Pickers and selectors with required (#12151)

* Update Pickers and selectors with required

* Use native * for device and entity

* Add support for my links to create a helper config entry (#12155)

* Use brand icon instead of domain icon for helpers (#12157)

* Import components that are allowed to be defined in markdown (#12158)

* Add options to selectors gallery (#12156)

* Add helpers to list when searching in add integration (#12159)

* List Selector (#12099)

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

* Add shuffle and repeat-mode of media_player to UI (#12052)

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>

* Add panel to Backup integration (#11671)

Co-authored-by: Zack Barett <zackbarett@hey.com>
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>

* Fix for Mobile View of Entities Table (#12160)

* Allow Sensor Units to be updated via Entity Registry (#12143)

* Add switch as x to entity settings (#12161)

Co-authored-by: Zack <zackbarett@hey.com>

* Bumped version to 20220330.0 (#12164)

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
Co-authored-by: Steve Repsher <steverep@users.noreply.github.com>
Co-authored-by: Robin Wittebol <robinwittebol@live.nl>
Co-authored-by: Raman Gupta <7243222+raman325@users.noreply.github.com>
Co-authored-by: Philip Allgaier <philip.allgaier@gmx.de>
Co-authored-by: Joakim Sørensen <ludeeus@ludeeus.dev>
Co-authored-by: Marius <33354141+Mariusthvdb@users.noreply.github.com>
Co-authored-by: Emil Stjerneman <emil@stjerneman.com>
Co-authored-by: Charles Garwood <cgarwood@gmail.com>
Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
Co-authored-by: jpearl <jpearl@users.noreply.github.com>
Co-authored-by: Matthias de Baat <matthias.debaat@nabucasa.com>
Co-authored-by: Matthias de Baat <hello@matthiasdebaat.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: Michael Irigoyen <michael@irigoyen.dev>
Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com>
Co-authored-by: Joakim Sørensen <hi@ludeeus.dev>
Co-authored-by: Nick Iacullo <duckycrayfish@gmail.com>
Co-authored-by: Pawel <pszafer@gmail.com>
Co-authored-by: Erik <erik@montnemery.com>
Co-authored-by: Brynley McDonald <brynley+github@zephire.nz>
Co-authored-by: blair <1585872+blairun@users.noreply.github.com>
Co-authored-by: NachtaktiverHalbaffe <57433516+NachtaktiverHalbaffe@users.noreply.github.com>
2022-03-30 20:49:00 +02:00
37 changed files with 762 additions and 511 deletions

2
.vscode/tasks.json vendored
View File

@@ -181,7 +181,7 @@
{
"label": "Run HA Core for Supervisor in devcontainer",
"type": "shell",
"command": "HASSIO=${input:supervisorHost} HASSIO_TOKEN=${input:supervisorToken} script/core",
"command": "SUPERVISOR=${input:supervisorHost} SUPERVISOR_TOKEN=${input:supervisorToken} script/core",
"isBackground": true,
"group": {
"kind": "build",

9
cast/public/_redirects Normal file
View File

@@ -0,0 +1,9 @@
# These redirects are handled by Netlify
#
# Some custom cards are not prefixing the instance URL when fetching data
# and can end up fetching the data from the Cast domain instead of HA.
# This will make sure that some common ones are replaced with a placeholder.
/api/camera_proxy/* /images/google-nest-hub.png
/api/camera_proxy_stream/* /images/google-nest-hub.png
/api/media_player_proxy/* /images/google-nest-hub.png

View File

@@ -89,8 +89,8 @@
"@polymer/paper-tooltip": "^3.0.1",
"@polymer/polymer": "3.4.1",
"@thomasloven/round-slider": "0.5.4",
"@vaadin/combo-box": "^22.0.4",
"@vaadin/vaadin-themable-mixin": "^22.0.4",
"@vaadin/combo-box": "^23.0.10",
"@vaadin/vaadin-themable-mixin": "^23.0.10",
"@vibrant/color": "^3.2.1-alpha.1",
"@vibrant/core": "^3.2.1-alpha.1",
"@vibrant/quantizer-mmcq": "^3.2.1-alpha.1",
@@ -108,7 +108,7 @@
"fuse.js": "^6.0.0",
"google-timezones-json": "^1.0.2",
"hls.js": "^1.1.5",
"home-assistant-js-websocket": "^7.0.3",
"home-assistant-js-websocket": "^7.1.0",
"idb-keyval": "^5.1.3",
"intl-messageformat": "^9.9.1",
"js-yaml": "^4.1.0",

View File

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

View File

@@ -31,6 +31,7 @@ const rowRenderer: ComboBoxLitRenderer<HassEntityWithCachedName> = (item) =>
<span>${item.friendly_name}</span>
<span slot="secondary">${item.entity_id}</span>
</mwc-list-item>`;
@customElement("ha-entity-picker")
export class HaEntityPicker extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;

View File

@@ -1,13 +1,17 @@
import "@material/mwc-list/mwc-list-item";
import { mdiClose, mdiMenuDown, mdiMenuUp } from "@mdi/js";
import "@vaadin/combo-box/theme/material/vaadin-combo-box-light";
import type { ComboBoxLight } from "@vaadin/combo-box/vaadin-combo-box-light";
import type {
ComboBoxLight,
ComboBoxLightFilterChangedEvent,
ComboBoxLightOpenedChangedEvent,
ComboBoxLightValueChangedEvent,
} from "@vaadin/combo-box/vaadin-combo-box-light";
import { registerStyles } from "@vaadin/vaadin-themable-mixin/register-styles";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { ComboBoxLitRenderer, comboBoxRenderer } from "lit-vaadin-helpers";
import { customElement, property, query } from "lit/decorators";
import { fireEvent } from "../common/dom/fire_event";
import { PolymerChangedEvent } from "../polymer-types";
import { HomeAssistant } from "../types";
import "./ha-icon-button";
import "./ha-textfield";
@@ -96,6 +100,8 @@ export class HaComboBox extends LitElement {
@query("vaadin-combo-box-light", true) private _comboBox!: ComboBoxLight;
private _overlayMutationObserver?: MutationObserver;
public open() {
this.updateComplete.then(() => {
this._comboBox?.open();
@@ -108,6 +114,14 @@ export class HaComboBox extends LitElement {
});
}
public disconnectedCallback() {
super.disconnectedCallback();
if (this._overlayMutationObserver) {
this._overlayMutationObserver.disconnect();
this._overlayMutationObserver = undefined;
}
}
public get selectedItem() {
return this._comboBox.selectedItem;
}
@@ -193,21 +207,64 @@ export class HaComboBox extends LitElement {
}
}
private _openedChanged(ev: PolymerChangedEvent<boolean>) {
private _openedChanged(ev: ComboBoxLightOpenedChangedEvent) {
const opened = ev.detail.value;
// delay this so we can handle click event before setting _opened
setTimeout(() => {
this._opened = ev.detail.value;
this._opened = opened;
}, 0);
// @ts-ignore
fireEvent(this, ev.type, ev.detail);
if (
opened &&
"MutationObserver" in window &&
!this._overlayMutationObserver
) {
const overlay = document.querySelector<HTMLElement>(
"vaadin-combo-box-overlay"
);
if (!overlay) {
return;
}
this._overlayMutationObserver = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (
mutation.type === "attributes" &&
mutation.attributeName === "inert"
) {
this._overlayMutationObserver?.disconnect();
this._overlayMutationObserver = undefined;
// @ts-expect-error
overlay.inert = false;
} else if (mutation.type === "childList") {
mutation.removedNodes.forEach((node) => {
if (node.nodeName === "VAADIN-COMBO-BOX-OVERLAY") {
this._overlayMutationObserver?.disconnect();
this._overlayMutationObserver = undefined;
}
});
}
});
});
this._overlayMutationObserver.observe(overlay, {
attributes: true,
});
this._overlayMutationObserver.observe(document.body, {
childList: true,
});
}
}
private _filterChanged(ev: PolymerChangedEvent<string>) {
private _filterChanged(ev: ComboBoxLightFilterChangedEvent) {
// @ts-ignore
fireEvent(this, ev.type, ev.detail, { composed: false });
}
private _valueChanged(ev: PolymerChangedEvent<string>) {
private _valueChanged(ev: ComboBoxLightValueChangedEvent) {
ev.stopPropagation();
const newValue = ev.detail.value;

View File

@@ -28,10 +28,15 @@ export class HaFormfield extends FormfieldBase {
css`
:host(:not([alignEnd])) ::slotted(ha-switch) {
margin-right: 10px;
margin-inline-end: 10px;
margin-inline-start: inline;
}
:host([dir="rtl"]:not([alignEnd])) ::slotted(ha-switch) {
margin-left: 10px;
margin-right: auto;
.mdc-form-field > label {
direction: var(--direction);
margin-inline-start: 0;
margin-inline-end: auto;
padding-inline-start: 4px;
padding-inline-end: 0;
}
`,
];

View File

@@ -1,4 +1,3 @@
import "@material/mwc-formfield/mwc-formfield";
import "@material/mwc-list/mwc-list-item";
import { mdiClose } from "@mdi/js";
import { css, html, LitElement } from "lit";
@@ -47,14 +46,14 @@ export class HaSelectSelector extends LitElement {
${this.label}
${options.map(
(item: SelectOption) => html`
<mwc-formfield .label=${item.label}>
<ha-formfield .label=${item.label}>
<ha-radio
.checked=${item.value === this.value}
.value=${item.value}
.disabled=${this.disabled}
@change=${this._valueChanged}
></ha-radio>
</mwc-formfield>
</ha-formfield>
`
)}
</div>

View File

@@ -28,6 +28,7 @@ import { fireEvent } from "../../common/dom/fire_event";
import { computeRTLDirection } from "../../common/util/compute_rtl";
import { debounce } from "../../common/util/debounce";
import { getSignedPath } from "../../data/auth";
import { UNAVAILABLE_STATES } from "../../data/entity";
import type { MediaPlayerItem } from "../../data/media-player";
import {
browseMediaPlayer,
@@ -45,6 +46,7 @@ import type { HomeAssistant } from "../../types";
import { brandsUrl, extractDomainFromBrandUrl } from "../../util/brands-url";
import { documentationUrl } from "../../util/documentation-url";
import "../entity/ha-entity-picker";
import "../ha-alert";
import "../ha-button-menu";
import "../ha-card";
import "../ha-circular-progress";
@@ -246,6 +248,16 @@ export class HaMediaPlayerBrowse extends LitElement {
],
replace: true,
});
} else if (
err.code === "entity_not_found" &&
UNAVAILABLE_STATES.includes(this.hass.states[this.entityId]?.state)
) {
this._setError({
message: this.hass.localize(
`ui.components.media-browser.media_player_unavailable`
),
code: "entity_not_found",
});
} else {
this._setError(err);
}
@@ -305,7 +317,11 @@ export class HaMediaPlayerBrowse extends LitElement {
protected render(): TemplateResult {
if (this._error) {
return html`
<div class="container">${this._renderError(this._error)}</div>
<div class="container">
<ha-alert alert-type="error">
${this._renderError(this._error)}
</ha-alert>
</div>
`;
}
@@ -420,7 +436,9 @@ export class HaMediaPlayerBrowse extends LitElement {
this._error
? html`
<div class="container">
${this._renderError(this._error)}
<ha-alert alert-type="error">
${this._renderError(this._error)}
</ha-alert>
</div>
`
: isTTSMediaSource(currentItem.media_content_id)

View File

@@ -159,6 +159,7 @@ export interface CustomActionConfig extends BaseActionConfig {
}
export interface BaseActionConfig {
action: string;
confirmation?: ConfirmationRestrictionConfig;
}

View File

@@ -78,6 +78,7 @@ class MoreInfoMediaPlayer extends LitElement {
@click=${this._showBrowseMedia}
>
<ha-svg-icon
class="browse-media-icon"
.path=${mdiPlayBoxMultiple}
slot="icon"
></ha-svg-icon>
@@ -211,6 +212,7 @@ class MoreInfoMediaPlayer extends LitElement {
.controls {
display: flex;
flex-wrap: wrap;
align-items: center;
--mdc-theme-primary: currentColor;
}
@@ -242,6 +244,10 @@ class MoreInfoMediaPlayer extends LitElement {
mwc-button > ha-svg-icon {
vertical-align: text-bottom;
}
.browse-media-icon {
margin-left: 8px;
}
`;
}

View File

@@ -14,7 +14,6 @@ import {
ApplicationCredential,
} from "../../../data/application_credential";
import { domainToName } from "../../../data/integration";
import { PolymerChangedEvent } from "../../../polymer-types";
import { haStyleDialog } from "../../../resources/styles";
import { HomeAssistant } from "../../../types";
import { AddApplicationCredentialDialogParams } from "./show-dialog-add-application-credential";
@@ -169,11 +168,9 @@ export class DialogAddApplicationCredential extends LitElement {
fireEvent(this, "dialog-closed", { dialog: this.localName });
}
private async _handleDomainPicked(ev: PolymerChangedEvent<string>) {
const target = ev.target as any;
if (target.selectedItem) {
this._domain = target.selectedItem.id;
}
private async _handleDomainPicked(ev: CustomEvent) {
ev.stopPropagation();
this._domain = ev.detail.value;
}
private _handleValueChanged(ev: CustomEvent) {

View File

@@ -53,7 +53,6 @@ export class HaConfigApplicationCredentials extends LitElement {
title: localize(
"ui.panel.config.application_credentials.picker.headers.name"
),
width: "40%",
direction: "asc",
grows: true,
template: (_, entry: ApplicationCredential) => html`${entry.name}`,

View File

@@ -88,7 +88,10 @@ export class CloudAccount extends SubscribeMixin(LitElement) {
>
<div class="account-row">
<paper-item-body two-line>
${this.cloudStatus.email}
${this.cloudStatus.email.replace(
/(\w{3})[\w.-]+@([\w.]+\w)/,
"$1***@$2"
)}
<div secondary class="wrap">
${this._subscription
? this._subscription.human_description.replace(

View File

@@ -51,11 +51,6 @@ export class CloudRemotePref extends LitElement {
`;
}
const urlParts = remote_domain!.split(".");
const hiddenURL = `https://${urlParts[0].substring(0, 5)}***.${
urlParts[1]
}.${urlParts[2]}.${urlParts[3]}`;
return html`
<ha-card
outlined
@@ -92,8 +87,9 @@ export class CloudRemotePref extends LitElement {
target="_blank"
class="break-word"
rel="noreferrer"
>
${hiddenURL}</a
>${this.hass.localize(
"ui.panel.config.cloud.account.remote.nabu_casa_url"
)}</a
>.
<ha-svg-icon
.url=${`https://${remote_domain}`}

View File

@@ -8,7 +8,7 @@ import "../../../components/ha-navigation-list";
import "../../../components/ha-tip";
import { BackupContent, fetchBackupInfo } from "../../../data/backup";
import { CloudStatus, fetchCloudStatus } from "../../../data/cloud";
import { BOARD_NAMES } from "../../../data/hardware";
import { BOARD_NAMES, HardwareInfo } from "../../../data/hardware";
import { fetchHassioBackups, HassioBackup } from "../../../data/hassio/backup";
import {
fetchHassioHassOsInfo,
@@ -156,8 +156,8 @@ class HaConfigSystemNavigation extends LitElement {
this._fetchNetworkStatus();
const isHassioLoaded = isComponentLoaded(this.hass, "hassio");
this._fetchBackupInfo(isHassioLoaded);
this._fetchHardwareInfo(isHassioLoaded);
if (isHassioLoaded) {
this._fetchHardwareInfo();
this._fetchStorageInfo();
}
}
@@ -202,10 +202,17 @@ class HaConfigSystemNavigation extends LitElement {
}
}
private async _fetchHardwareInfo() {
const osData: HassioHassOSInfo = await fetchHassioHassOsInfo(this.hass);
if (osData.board) {
this._boardName = BOARD_NAMES[osData.board];
private async _fetchHardwareInfo(isHassioLoaded: boolean) {
if (isComponentLoaded(this.hass, "hardware")) {
const hardwareInfo: HardwareInfo = await this.hass.callWS({
type: "hardware/info",
});
this._boardName = hardwareInfo?.hardware?.[0].name;
} else if (isHassioLoaded) {
const osData: HassioHassOSInfo = await fetchHassioHassOsInfo(this.hass);
if (osData.board) {
this._boardName = BOARD_NAMES[osData.board];
}
}
}

View File

@@ -0,0 +1,20 @@
import { DeviceRegistryEntry } from "../../../../../../data/device_registry";
import { fetchZwaveNodeComments } from "../../../../../../data/zwave_js";
import { HomeAssistant } from "../../../../../../types";
import { DeviceAlert } from "../../../ha-config-device-page";
export const getZwaveDeviceAlerts = async (
hass: HomeAssistant,
device: DeviceRegistryEntry
): Promise<DeviceAlert[]> => {
const nodeComments = await fetchZwaveNodeComments(hass, device.id);
if (!nodeComments?.comments?.length) {
return [];
}
return nodeComments.comments.map((comment) => ({
level: comment.level,
text: comment.text,
}));
};

View File

@@ -1,52 +0,0 @@
import { html, LitElement, PropertyValues, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import { DeviceRegistryEntry } from "../../../../../../data/device_registry";
import {
ZwaveJSNodeComments,
fetchZwaveNodeComments,
} from "../../../../../../data/zwave_js";
import { HomeAssistant } from "../../../../../../types";
@customElement("ha-device-alerts-zwave_js")
export class HaDeviceAlertsZWaveJS extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property({ attribute: false }) public device!: DeviceRegistryEntry;
@state() private _nodeComments?: ZwaveJSNodeComments;
protected willUpdate(changedProperties: PropertyValues) {
super.willUpdate(changedProperties);
if (changedProperties.has("device")) {
this._fetchNodeDetails();
}
}
private async _fetchNodeDetails() {
this._nodeComments = await fetchZwaveNodeComments(
this.hass,
this.device.id
);
}
protected render(): TemplateResult {
if (this._nodeComments && this._nodeComments.comments?.length > 0) {
return html`
<div>
${this._nodeComments.comments.map(
(comment) => html`<ha-alert .alertType=${comment.level}>
${comment.text}
</ha-alert>`
)}
</div>
`;
}
return html``;
}
}
declare global {
interface HTMLElementTagNameMap {
"ha-device-alerts-zwave_js": HaDeviceAlertsZWaveJS;
}
}

View File

@@ -83,6 +83,11 @@ export interface DeviceAction {
classes?: string;
}
export interface DeviceAlert {
level: "warning" | "error" | "info";
text: string;
}
@customElement("ha-config-device-page")
export class HaConfigDevicePage extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -114,6 +119,8 @@ export class HaConfigDevicePage extends LitElement {
@state() private _deviceActions?: DeviceAction[];
@state() private _deviceAlerts?: DeviceAlert[];
private _logbookTime = { recent: 86400 };
private _device = memoizeOne(
@@ -215,12 +222,14 @@ export class HaConfigDevicePage extends LitElement {
this._diagnosticDownloadLinks = undefined;
this._deleteButtons = undefined;
this._deviceActions = undefined;
this._deviceAlerts = undefined;
}
if (
(this._diagnosticDownloadLinks &&
this._deleteButtons &&
this._deviceActions) ||
this._deviceActions &&
this._deviceAlerts) ||
!this.devices ||
!this.deviceId ||
!this.entries
@@ -231,9 +240,11 @@ export class HaConfigDevicePage extends LitElement {
this._diagnosticDownloadLinks = Math.random();
this._deleteButtons = []; // To prevent re-rendering if no delete buttons
this._deviceActions = [];
this._deviceAlerts = [];
this._getDiagnosticButtons(this._diagnosticDownloadLinks);
this._getDeleteActions();
this._getDeviceActions();
this._getDeviceAlerts();
}
protected firstUpdated(changedProps) {
@@ -279,7 +290,6 @@ export class HaConfigDevicePage extends LitElement {
const area = this._computeArea(this.areas, device);
const deviceInfo: TemplateResult[] = [];
const deviceAlerts: TemplateResult[] = [];
const actions = [...(this._deviceActions || [])];
if (Array.isArray(this._diagnosticDownloadLinks)) {
@@ -320,7 +330,268 @@ export class HaConfigDevicePage extends LitElement {
);
}
this._renderIntegrationInfo(device, integrations, deviceInfo, deviceAlerts);
this._renderIntegrationInfo(device, integrations, deviceInfo);
const automationCard = isComponentLoaded(this.hass, "automation")
? html`
<ha-card outlined>
<h1 class="card-header">
${this.hass.localize(
"ui.panel.config.devices.automation.automations_heading"
)}
<ha-icon-button
@click=${this._showAutomationDialog}
.disabled=${device.disabled_by}
.label=${device.disabled_by
? this.hass.localize(
"ui.panel.config.devices.automation.create_disabled",
"type",
this.hass.localize(
`ui.panel.config.devices.type.${
device.entry_type || "device"
}`
)
)
: this.hass.localize(
"ui.panel.config.devices.automation.create",
"type",
this.hass.localize(
`ui.panel.config.devices.type.${
device.entry_type || "device"
}`
)
)}
.path=${mdiPlusCircle}
></ha-icon-button>
</h1>
${this._related?.automation?.length
? html`
<div class="items">
${this._related.automation.map((automation) => {
const entityState = this.hass.states[automation];
return entityState
? html`<div>
<a
href=${ifDefined(
entityState.attributes.id
? `/config/automation/edit/${entityState.attributes.id}`
: undefined
)}
>
<paper-item
.automation=${entityState}
.disabled=${!entityState.attributes.id}
>
<paper-item-body>
${computeStateName(entityState)}
</paper-item-body>
<ha-icon-next></ha-icon-next>
</paper-item>
</a>
${!entityState.attributes.id
? html`
<paper-tooltip animation-delay="0">
${this.hass.localize(
"ui.panel.config.devices.cant_edit"
)}
</paper-tooltip>
`
: ""}
</div> `
: "";
})}
</div>
`
: html`
<div class="card-content">
${this.hass.localize(
"ui.panel.config.devices.add_prompt",
"name",
this.hass.localize(
"ui.panel.config.devices.automation.automations"
),
"type",
this.hass.localize(
`ui.panel.config.devices.type.${
device.entry_type || "device"
}`
)
)}
</div>
`}
</ha-card>
`
: "";
const sceneCard =
isComponentLoaded(this.hass, "scene") && entities.length
? html`
<ha-card outlined>
<h1 class="card-header">
${this.hass.localize(
"ui.panel.config.devices.scene.scenes_heading"
)}
<ha-icon-button
@click=${this._createScene}
.disabled=${device.disabled_by}
.label=${device.disabled_by
? this.hass.localize(
"ui.panel.config.devices.scene.create_disabled",
"type",
this.hass.localize(
`ui.panel.config.devices.type.${
device.entry_type || "device"
}`
)
)
: this.hass.localize(
"ui.panel.config.devices.scene.create",
"type",
this.hass.localize(
`ui.panel.config.devices.type.${
device.entry_type || "device"
}`
)
)}
.path=${mdiPlusCircle}
></ha-icon-button>
</h1>
${this._related?.scene?.length
? html`
<div class="items">
${this._related.scene.map((scene) => {
const entityState = this.hass.states[scene];
return entityState
? html`
<div>
<a
href=${ifDefined(
entityState.attributes.id
? `/config/scene/edit/${entityState.attributes.id}`
: undefined
)}
>
<paper-item
.scene=${entityState}
.disabled=${!entityState.attributes.id}
>
<paper-item-body>
${computeStateName(entityState)}
</paper-item-body>
<ha-icon-next></ha-icon-next>
</paper-item>
</a>
${!entityState.attributes.id
? html`
<paper-tooltip animation-delay="0">
${this.hass.localize(
"ui.panel.config.devices.cant_edit"
)}
</paper-tooltip>
`
: ""}
</div>
`
: "";
})}
</div>
`
: html`
<div class="card-content">
${this.hass.localize(
"ui.panel.config.devices.add_prompt",
"name",
this.hass.localize(
"ui.panel.config.devices.scene.scenes"
),
"type",
this.hass.localize(
`ui.panel.config.devices.type.${
device.entry_type || "device"
}`
)
)}
</div>
`}
</ha-card>
`
: "";
const scriptCard = isComponentLoaded(this.hass, "script")
? html`
<ha-card outlined>
<h1 class="card-header">
${this.hass.localize(
"ui.panel.config.devices.script.scripts_heading"
)}
<ha-icon-button
@click=${this._showScriptDialog}
.disabled=${device.disabled_by}
.label=${device.disabled_by
? this.hass.localize(
"ui.panel.config.devices.script.create_disabled",
"type",
this.hass.localize(
`ui.panel.config.devices.type.${
device.entry_type || "device"
}`
)
)
: this.hass.localize(
"ui.panel.config.devices.script.create",
"type",
this.hass.localize(
`ui.panel.config.devices.type.${
device.entry_type || "device"
}`
)
)}
.path=${mdiPlusCircle}
></ha-icon-button>
</h1>
${this._related?.script?.length
? html`
<div class="items">
${this._related.script.map((script) => {
const entityState = this.hass.states[script];
return entityState
? html`
<a
href=${`/config/script/edit/${entityState.entity_id}`}
>
<paper-item .script=${script}>
<paper-item-body>
${computeStateName(entityState)}
</paper-item-body>
<ha-icon-next></ha-icon-next>
</paper-item>
</a>
`
: "";
})}
</div>
`
: html`
<div class="card-content">
${this.hass.localize(
"ui.panel.config.devices.add_prompt",
"name",
this.hass.localize(
"ui.panel.config.devices.script.scripts"
),
"type",
this.hass.localize(
`ui.panel.config.devices.type.${
device.entry_type || "device"
}`
)
)}
</div>
`}
</ha-card>
`
: "";
return html`
<hass-tabs-subpage
@@ -411,8 +682,19 @@ export class HaConfigDevicePage extends LitElement {
</div>
<div class="column">
${
deviceAlerts.length
? html` <div class="fullwidth">${deviceAlerts}</div> `
this._deviceAlerts?.length
? html`
<div>
${this._deviceAlerts.map(
(alert) =>
html`
<ha-alert .alertType=${alert.level}>
${alert.text}
</ha-alert>
`
)}
</div>
`
: ""
}
<ha-device-info-card
@@ -486,275 +768,7 @@ export class HaConfigDevicePage extends LitElement {
: ""
}
</ha-device-info-card>
${
isComponentLoaded(this.hass, "automation")
? html`
<ha-card outlined>
<h1 class="card-header">
${this.hass.localize(
"ui.panel.config.devices.automation.automations_heading"
)}
<ha-icon-button
@click=${this._showAutomationDialog}
.disabled=${device.disabled_by}
.label=${device.disabled_by
? this.hass.localize(
"ui.panel.config.devices.automation.create_disabled",
"type",
this.hass.localize(
`ui.panel.config.devices.type.${
device.entry_type || "device"
}`
)
)
: this.hass.localize(
"ui.panel.config.devices.automation.create",
"type",
this.hass.localize(
`ui.panel.config.devices.type.${
device.entry_type || "device"
}`
)
)}
.path=${mdiPlusCircle}
></ha-icon-button>
</h1>
${this._related?.automation?.length
? html`
<div class="items">
${this._related.automation.map((automation) => {
const entityState =
this.hass.states[automation];
return entityState
? html`<div>
<a
href=${ifDefined(
entityState.attributes.id
? `/config/automation/edit/${entityState.attributes.id}`
: undefined
)}
>
<paper-item
.automation=${entityState}
.disabled=${!entityState.attributes
.id}
>
<paper-item-body>
${computeStateName(entityState)}
</paper-item-body>
<ha-icon-next></ha-icon-next>
</paper-item>
</a>
${!entityState.attributes.id
? html`
<paper-tooltip animation-delay="0">
${this.hass.localize(
"ui.panel.config.devices.cant_edit"
)}
</paper-tooltip>
`
: ""}
</div> `
: "";
})}
</div>
`
: html`
<div class="card-content">
${this.hass.localize(
"ui.panel.config.devices.add_prompt",
"name",
this.hass.localize(
"ui.panel.config.devices.automation.automations"
),
"type",
this.hass.localize(
`ui.panel.config.devices.type.${
device.entry_type || "device"
}`
)
)}
</div>
`}
</ha-card>
`
: ""
}
${
isComponentLoaded(this.hass, "scene") && entities.length
? html`
<ha-card outlined>
<h1 class="card-header">
${this.hass.localize(
"ui.panel.config.devices.scene.scenes_heading"
)}
<ha-icon-button
@click=${this._createScene}
.disabled=${device.disabled_by}
.label=${device.disabled_by
? this.hass.localize(
"ui.panel.config.devices.scene.create_disabled",
"type",
this.hass.localize(
`ui.panel.config.devices.type.${
device.entry_type || "device"
}`
)
)
: this.hass.localize(
"ui.panel.config.devices.scene.create",
"type",
this.hass.localize(
`ui.panel.config.devices.type.${
device.entry_type || "device"
}`
)
)}
.path=${mdiPlusCircle}
></ha-icon-button>
</h1>
${this._related?.scene?.length
? html`
<div class="items">
${this._related.scene.map((scene) => {
const entityState = this.hass.states[scene];
return entityState
? html`
<div>
<a
href=${ifDefined(
entityState.attributes.id
? `/config/scene/edit/${entityState.attributes.id}`
: undefined
)}
>
<paper-item
.scene=${entityState}
.disabled=${!entityState.attributes
.id}
>
<paper-item-body>
${computeStateName(entityState)}
</paper-item-body>
<ha-icon-next></ha-icon-next>
</paper-item>
</a>
${!entityState.attributes.id
? html`
<paper-tooltip
animation-delay="0"
>
${this.hass.localize(
"ui.panel.config.devices.cant_edit"
)}
</paper-tooltip>
`
: ""}
</div>
`
: "";
})}
</div>
`
: html`
<div class="card-content">
${this.hass.localize(
"ui.panel.config.devices.add_prompt",
"name",
this.hass.localize(
"ui.panel.config.devices.scene.scenes"
),
"type",
this.hass.localize(
`ui.panel.config.devices.type.${
device.entry_type || "device"
}`
)
)}
</div>
`}
</ha-card>
`
: ""
}
${
isComponentLoaded(this.hass, "script")
? html`
<ha-card outlined>
<h1 class="card-header">
${this.hass.localize(
"ui.panel.config.devices.script.scripts_heading"
)}
<ha-icon-button
@click=${this._showScriptDialog}
.disabled=${device.disabled_by}
.label=${device.disabled_by
? this.hass.localize(
"ui.panel.config.devices.script.create_disabled",
"type",
this.hass.localize(
`ui.panel.config.devices.type.${
device.entry_type || "device"
}`
)
)
: this.hass.localize(
"ui.panel.config.devices.script.create",
"type",
this.hass.localize(
`ui.panel.config.devices.type.${
device.entry_type || "device"
}`
)
)}
.path=${mdiPlusCircle}
></ha-icon-button>
</h1>
${this._related?.script?.length
? html`
<div class="items">
${this._related.script.map((script) => {
const entityState = this.hass.states[script];
return entityState
? html`
<a
href=${`/config/script/edit/${entityState.entity_id}`}
>
<paper-item .script=${script}>
<paper-item-body>
${computeStateName(entityState)}
</paper-item-body>
<ha-icon-next></ha-icon-next>
</paper-item>
</a>
`
: "";
})}
</div>
`
: html`
<div class="card-content">
${this.hass.localize(
"ui.panel.config.devices.add_prompt",
"name",
this.hass.localize(
"ui.panel.config.devices.script.scripts"
),
"type",
this.hass.localize(
`ui.panel.config.devices.type.${
device.entry_type || "device"
}`
)
)}
</div>
`}
</ha-card>
`
: ""
}
${!this.narrow ? [automationCard, sceneCard, scriptCard] : ""}
</div>
<div class="column">
${["control", "sensor", "config", "diagnostic"].map((category) =>
@@ -777,6 +791,7 @@ export class HaConfigDevicePage extends LitElement {
)}
</div>
<div class="column">
${this.narrow ? [automationCard, sceneCard, scriptCard] : ""}
${
isComponentLoaded(this.hass, "logbook")
? html`
@@ -976,6 +991,33 @@ export class HaConfigDevicePage extends LitElement {
this._deviceActions = deviceActions;
}
private async _getDeviceAlerts() {
const device = this._device(this.deviceId, this.devices);
if (!device) {
return;
}
const deviceAlerts: DeviceAlert[] = [];
const domains = this._integrations(device, this.entries).map(
(int) => int.domain
);
if (domains.includes("zwave_js")) {
const zwave = await import(
"./device-detail/integration-elements/zwave_js/device-alerts"
);
const alerts = await zwave.getZwaveDeviceAlerts(this.hass, device);
deviceAlerts.push(...alerts);
}
if (deviceAlerts.length) {
this._deviceAlerts = deviceAlerts;
}
}
private _computeEntityName(entity: EntityRegistryEntry) {
if (entity.name) {
return entity.name;
@@ -1023,8 +1065,7 @@ export class HaConfigDevicePage extends LitElement {
private _renderIntegrationInfo(
device: DeviceRegistryEntry,
integrations: ConfigEntry[],
deviceInfo: TemplateResult[],
deviceAlerts: TemplateResult[]
deviceInfo: TemplateResult[]
) {
const domains = integrations.map((int) => int.domain);
if (domains.includes("zha")) {
@@ -1037,18 +1078,9 @@ export class HaConfigDevicePage extends LitElement {
`);
}
if (domains.includes("zwave_js")) {
import(
"./device-detail/integration-elements/zwave_js/ha-device-alerts-zwave_js"
);
import(
"./device-detail/integration-elements/zwave_js/ha-device-info-zwave_js"
);
deviceAlerts.push(html`
<ha-device-alerts-zwave_js
.hass=${this.hass}
.device=${device}
></ha-device-alerts-zwave_js>
`);
deviceInfo.push(html`
<ha-device-info-zwave_js
.hass=${this.hass}

View File

@@ -378,8 +378,7 @@ export class EntityRegistrySettings extends SubscribeMixin(LitElement) {
</mwc-list-item>
<mwc-list-item
value="outlet"
.selected=${!this._deviceClass ||
this._deviceClass === "outlet"}
.selected=${this._deviceClass === "outlet"}
>
${this.hass.localize(
"ui.dialogs.entity_registry.editor.device_classes.switch.outlet"

View File

@@ -694,6 +694,11 @@ class ZWaveJSConfigDashboard extends SubscribeMixin(LitElement) {
justify-content: space-between;
}
span[slot="meta"] {
font-size: 0.95em;
color: var(--primary-text-color);
}
.network-status div.heading {
display: flex;
align-items: center;

View File

@@ -2,7 +2,6 @@ import "@material/mwc-button";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { computeRTLDirection } from "../../../common/util/compute_rtl";
import "../../../components/entity/ha-entities-picker";
import { createCloseHeading } from "../../../components/ha-dialog";
import "../../../components/ha-formfield";
@@ -159,7 +158,6 @@ class DialogPersonDetail extends LitElement {
.label=${this.hass.localize(
"ui.panel.config.person.detail.local_only"
)}
.dir=${computeRTLDirection(this.hass)}
>
<ha-switch
.checked=${this._localOnly}
@@ -171,7 +169,6 @@ class DialogPersonDetail extends LitElement {
.label=${this.hass.localize(
"ui.panel.config.person.detail.admin"
)}
.dir=${computeRTLDirection(this.hass)}
>
<ha-switch
.disabled=${this._user.system_generated ||

View File

@@ -6,7 +6,8 @@ import {
PropertyValues,
TemplateResult,
} from "lit";
import { customElement, state } from "lit/decorators";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { DOMAINS_TOGGLE } from "../../../common/const";
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
import { computeDomain } from "../../../common/entity/compute_domain";
@@ -54,6 +55,8 @@ class HuiEntitiesCard extends LitElement implements LovelaceCard {
return { type: "entities", entities: foundEntities };
}
@property() public editMode?: boolean | any;
@state() private _config?: EntitiesCardConfig;
private _hass?: HomeAssistant;
@@ -217,9 +220,15 @@ class HuiEntitiesCard extends LitElement implements LovelaceCard {
`}
</h1>
`}
<div id="states" class="card-content">
${this._configEntities!.map((entityConf) =>
this.renderEntity(entityConf)
<div
id="states"
class=${classMap({
"card-content": true,
highlight: this.editMode?.selectedRow !== undefined,
})}
>
${this._configEntities!.map((entityConf, idx) =>
this.renderEntity(entityConf, idx)
)}
</div>
@@ -272,6 +281,12 @@ class HuiEntitiesCard extends LitElement implements LovelaceCard {
#states > div {
position: relative;
}
#states.highlight > div.selected {
opacity: 1;
}
#states.highlight > div {
opacity: 0.5;
}
.icon {
padding: 0px 18px 0px 8px;
@@ -293,7 +308,10 @@ class HuiEntitiesCard extends LitElement implements LovelaceCard {
`;
}
private renderEntity(entityConf: LovelaceRowConfig): TemplateResult {
private renderEntity(
entityConf: LovelaceRowConfig,
idx: number
): TemplateResult {
const element = createRowElement(
(!("type" in entityConf) || entityConf.type === "conditional") &&
this._config!.state_color
@@ -307,7 +325,13 @@ class HuiEntitiesCard extends LitElement implements LovelaceCard {
element.hass = this._hass;
}
return html`<div>${element}</div>`;
return html`<div
class=${classMap({
selected: this.editMode?.selectedRow === idx,
})}
>
${element}
</div>`;
}
}

View File

@@ -7,6 +7,7 @@ import {
TemplateResult,
} from "lit";
import { property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { LovelaceCardConfig } from "../../../data/lovelace";
import { HomeAssistant } from "../../../types";
import { createCardElement } from "../create-element/create-card-element";
@@ -28,7 +29,7 @@ export abstract class HuiStackCard<T extends StackCardConfig = StackCardConfig>
@property({ attribute: false }) public hass?: HomeAssistant;
@property() public editMode?: boolean;
@property() public editMode?: any;
@property() protected _cards?: LovelaceCard[];
@@ -43,8 +44,16 @@ export abstract class HuiStackCard<T extends StackCardConfig = StackCardConfig>
throw new Error("Invalid configuration");
}
this._config = config;
this._cards = config.cards.map((card) => {
this._cards = config.cards.map((card, idx) => {
const element = this._createCardElement(card) as LovelaceCard;
if (this.editMode !== undefined) {
if (this.editMode?.selected === idx) {
element.classList.add("selected");
element.editMode = this.editMode.data;
} else {
element.editMode = true;
}
}
return element;
});
}
@@ -58,12 +67,18 @@ export abstract class HuiStackCard<T extends StackCardConfig = StackCardConfig>
return;
}
for (const element of this._cards) {
for (const [idx, element] of this._cards.entries()) {
if (this.hass) {
element.hass = this.hass;
}
if (this.editMode !== undefined) {
element.editMode = this.editMode;
if (this.editMode.selected === idx) {
element.editMode = this.editMode.data ?? true;
element.classList.add("selected");
} else {
element.editMode = true;
element.classList.remove("selected");
}
}
}
}
@@ -77,7 +92,12 @@ export abstract class HuiStackCard<T extends StackCardConfig = StackCardConfig>
${this._config.title
? html`<h1 class="card-header">${this._config.title}</h1>`
: ""}
<div id="root">${this._cards}</div>
<div
id="root"
class=${classMap({ highlight: this.editMode?.selected !== undefined })}
>
${this._cards}
</div>
`;
}
@@ -95,6 +115,12 @@ export abstract class HuiStackCard<T extends StackCardConfig = StackCardConfig>
display: block;
padding: 24px 16px 16px;
}
#root.highlight > *.selected {
opacity: 1;
}
#root.highlight > * {
opacity: 0.5;
}
`;
}

View File

@@ -193,6 +193,9 @@ export class HuiEntityEditor extends LitElement {
.add-entity {
display: block;
margin-left: 31px;
margin-inline-start: 31px;
margin-inline-end: initial;
direction: var(--direction);
}
.entity {
display: flex;

View File

@@ -12,6 +12,8 @@ export class HuiCardPreview extends ReactiveElement {
@property() public config?: LovelaceCardConfig;
@property() public editMode = true;
private _element?: LovelaceCard;
private get _error() {
@@ -81,6 +83,9 @@ export class HuiCardPreview extends ReactiveElement {
this._element.hass = this.hass;
}
}
if (changedProperties.has("editMode")) {
this._element!.editMode = this.editMode;
}
}
private _createCard(configValue: LovelaceCardConfig): void {
@@ -90,6 +95,7 @@ export class HuiCardPreview extends ReactiveElement {
if (this.hass) {
this._element!.hass = this.hass;
}
this._element!.editMode = this.editMode;
this.appendChild(this._element!);
}

View File

@@ -43,6 +43,13 @@ declare global {
interface HTMLElementEventMap {
"reload-lovelace": HASSDomEvent<undefined>;
}
interface HASSDomEvents {
"edit-mode-changed": any;
}
interface HTMLElementEventMap {
"edit-mode-changed": HASSDomEvent<any>;
}
}
@customElement("hui-dialog-edit-card")
@@ -77,10 +84,13 @@ export class HuiDialogEditCard
@state() private _isEscapeEnabled = true;
@state() private _editMode = true;
public async showDialog(params: EditCardDialogParams): Promise<void> {
this._params = params;
this._GUImode = true;
this._guiModeAvailable = true;
this._editMode = true;
const [view, card] = params.path;
this._viewConfig = params.lovelaceConfig.views[view];
this._cardConfig =
@@ -205,6 +215,7 @@ export class HuiDialogEditCard
.lovelace=${this._params.lovelaceConfig}
.value=${this._cardConfig}
@config-changed=${this._handleConfigChanged}
@edit-mode-changed=${this._handleEditModeChanged}
@GUImode-changed=${this._handleGUIModeChanged}
@editor-save=${this._save}
dialogInitialFocus
@@ -214,6 +225,7 @@ export class HuiDialogEditCard
<hui-card-preview
.hass=${this.hass}
.config=${this._cardConfig}
.editMode=${this._editMode}
class=${this._error ? "blur" : ""}
></hui-card-preview>
${this._error
@@ -284,6 +296,10 @@ export class HuiDialogEditCard
this._dirty = true;
}
private _handleEditModeChanged(ev: HASSDomEvent<any>) {
this._editMode = ev.detail ?? true;
}
private _handleGUIModeChanged(ev: HASSDomEvent<GUIModeChangedEvent>): void {
ev.stopPropagation();
this._GUImode = ev.detail.guiMode;

View File

@@ -49,6 +49,7 @@ import {
SubElementEditorConfig,
} from "../types";
import { configElementStyle } from "./config-elements-style";
import { buttonEntityConfigStruct } from "../structs/button-entity-struct";
const buttonEntitiesRowConfigStruct = object({
type: literal("button"),
@@ -112,22 +113,7 @@ const webLinkEntitiesRowConfigStruct = object({
const buttonsEntitiesRowConfigStruct = object({
type: literal("buttons"),
entities: array(
union([
object({
entity: string(),
name: optional(string()),
icon: optional(string()),
image: optional(string()),
show_name: optional(boolean()),
show_icon: optional(boolean()),
tap_action: optional(actionConfigStruct),
hold_action: optional(actionConfigStruct),
double_tap_action: optional(actionConfigStruct),
}),
string(),
])
),
entities: array(buttonEntityConfigStruct),
});
const attributeEntitiesRowConfigStruct = object({
@@ -422,10 +408,15 @@ export class HuiEntitiesCardEditor
private _editDetailElement(ev: HASSDomEvent<EditSubElementEvent>): void {
this._subElementEditorConfig = ev.detail.subElementConfig;
fireEvent(this, "edit-mode-changed", {
selectedRow: ev.detail.subElementConfig?.index,
});
}
private _goBack(): void {
this._subElementEditorConfig = undefined;
fireEvent(this, "edit-mode-changed", true);
}
static get styles(): CSSResultGroup {

View File

@@ -144,6 +144,7 @@ export class HuiStackCardEditor
.lovelace=${this.lovelace}
@config-changed=${this._handleConfigChanged}
@GUImode-changed=${this._handleGUIModeChanged}
@edit-mode-changed=${this._handleEditModeChanged}
></hui-card-element-editor>
`
: html`
@@ -166,6 +167,9 @@ export class HuiStackCardEditor
this._setMode(true);
this._guiModeAvailable = true;
this._selectedCard = parseInt(ev.detail.selected, 10);
if (this._cardEditorEl) {
this._cardEditorEl.forceRebuild = true;
}
}
protected _handleConfigChanged(ev: HASSDomEvent<ConfigChangedEvent>) {
@@ -226,6 +230,14 @@ export class HuiStackCardEditor
this._guiModeAvailable = ev.detail.guiModeAvailable;
}
protected _handleEditModeChanged(ev: HASSDomEvent<any>) {
ev.stopPropagation();
fireEvent(this, "edit-mode-changed", {
selected: this._selectedCard,
data: ev.detail,
});
}
protected _toggleMode(): void {
this._cardEditorEl?.toggleMode();
}
@@ -237,6 +249,13 @@ export class HuiStackCardEditor
}
}
protected updated(changedProperties) {
if (changedProperties.has("_selectedCard"))
fireEvent(this, "edit-mode-changed", {
selected: this._selectedCard,
});
}
static get styles(): CSSResultGroup {
return [
configElementStyle,

View File

@@ -53,6 +53,8 @@ export abstract class HuiElementEditor<T> extends LitElement {
@property({ attribute: false }) public lovelace?: LovelaceConfig;
public forceRebuild = false;
@state() private _yaml?: string;
@state() private _config?: T;
@@ -292,7 +294,11 @@ export abstract class HuiElementEditor<T> extends LitElement {
this._errors = undefined;
this._warnings = undefined;
if (this._configElementType !== this.configElementType) {
if (
this._configElementType !== this.configElementType ||
this.forceRebuild
) {
this.forceRebuild = false;
// If the type has changed, we need to load a new GUI editor
this._guiSupported = undefined;
this._configElement = undefined;

View File

@@ -261,6 +261,9 @@ export class HuiEntitiesCardRowEditor extends LitElement {
display: block;
margin-left: 31px;
margin-right: 71px;
margin-inline-start: 31px;
margin-inline-end: 71px;
direction: var(--direction);
}
.entity {
display: flex;
@@ -270,6 +273,9 @@ export class HuiEntitiesCardRowEditor extends LitElement {
.entity .handle {
padding-right: 8px;
cursor: move;
padding-inline-end: 8px;
padding-inline-start: initial;
direction: var(--direction);
}
.entity ha-entity-picker {

View File

@@ -1,14 +1,16 @@
import {
object,
string,
union,
boolean,
optional,
array,
literal,
boolean,
dynamic,
enums,
literal,
object,
optional,
string,
type,
union,
} from "superstruct";
import { BaseActionConfig } from "../../../../data/lovelace";
const actionConfigStructUser = object({
user: string(),
@@ -65,10 +67,23 @@ export const actionConfigStructType = object({
confirmation: optional(actionConfigStructConfirmation),
});
export const actionConfigStruct = union([
actionConfigStructType,
actionConfigStructUrl,
actionConfigStructNavigate,
actionConfigStructService,
actionConfigStructCustom,
]);
export const actionConfigStruct = dynamic<any>((value) => {
if (value && typeof value === "object" && "action" in value) {
switch ((value as BaseActionConfig).action!) {
case "call-service": {
return actionConfigStructService;
}
case "fire-dom-event": {
return actionConfigStructCustom;
}
case "navigate": {
return actionConfigStructNavigate;
}
case "url": {
return actionConfigStructUrl;
}
}
}
return actionConfigStructType;
});

View File

@@ -0,0 +1,14 @@
import { boolean, object, optional, string } from "superstruct";
import { actionConfigStruct } from "./action-struct";
export const buttonEntityConfigStruct = object({
entity: string(),
name: optional(string()),
icon: optional(string()),
image: optional(string()),
show_name: optional(boolean()),
show_icon: optional(boolean()),
tap_action: optional(actionConfigStruct),
hold_action: optional(actionConfigStruct),
double_tap_action: optional(actionConfigStruct),
});

View File

@@ -1,6 +1,15 @@
import { object, string, optional, array, number, union } from "superstruct";
import {
array,
dynamic,
number,
object,
optional,
union,
string,
} from "superstruct";
import { actionConfigStruct } from "../editor/structs/action-struct";
import { entitiesConfigStruct } from "../editor/structs/entities-struct";
import { buttonEntityConfigStruct } from "../editor/structs/button-entity-struct";
import { LovelaceHeaderFooterConfig } from "./types";
export const pictureHeaderFooterConfigStruct = object({
type: string(),
@@ -12,7 +21,7 @@ export const pictureHeaderFooterConfigStruct = object({
export const buttonsHeaderFooterConfigStruct = object({
type: string(),
entities: array(entitiesConfigStruct),
entities: array(buttonEntityConfigStruct),
});
export const graphHeaderFooterConfigStruct = object({
@@ -22,8 +31,25 @@ export const graphHeaderFooterConfigStruct = object({
hours_to_show: optional(number()),
});
export const headerFooterConfigStructs = union([
pictureHeaderFooterConfigStruct,
buttonsHeaderFooterConfigStruct,
graphHeaderFooterConfigStruct,
]);
export const headerFooterConfigStructs = dynamic<any>((value) => {
if (value && typeof value === "object" && "type" in value) {
switch ((value as LovelaceHeaderFooterConfig).type!) {
case "buttons": {
return buttonsHeaderFooterConfigStruct;
}
case "graph": {
return graphHeaderFooterConfigStruct;
}
case "picture": {
return pictureHeaderFooterConfigStruct;
}
}
}
// No "type" property => we fallback to a union of all potential types
return union([
buttonsHeaderFooterConfigStruct,
graphHeaderFooterConfigStruct,
pictureHeaderFooterConfigStruct,
]);
});

View File

@@ -38,7 +38,7 @@ export interface LovelaceBadge extends HTMLElement {
export interface LovelaceCard extends HTMLElement {
hass?: HomeAssistant;
isPanel?: boolean;
editMode?: boolean;
editMode?: any;
getCardSize(): number | Promise<number>;
setConfig(config: LovelaceCardConfig): void;
}

View File

@@ -609,7 +609,8 @@
"tv_show": "TV Show",
"url": "URL",
"video": "Video"
}
},
"media_player_unavailable": "The selected media player is unavailable."
},
"calendar": {
"my_calendars": "My Calendars",
@@ -2372,8 +2373,8 @@
"reconnecting": "Not connected. Trying to reconnect.",
"access_is_being_prepared": "Remote control is being prepared. We will notify you when it's ready.",
"info": "Home Assistant Cloud provides a secure remote connection to your instance while away from home.",
"instance_is_available": "Your instance is available at",
"instance_will_be_available": "Your instance will be available at",
"instance_is_available": "Your instance is available at your",
"instance_will_be_available": "Your instance will be available at your",
"link_learn_how_it_works": "Learn how it works",
"certificate_info": "Certificate Info"
},

151
yarn.lock
View File

@@ -3246,7 +3246,7 @@ __metadata:
languageName: node
linkType: hard
"@polymer/iron-resizable-behavior@npm:^3.0.0, @polymer/iron-resizable-behavior@npm:^3.0.0-pre.26, @polymer/iron-resizable-behavior@npm:^3.0.1":
"@polymer/iron-resizable-behavior@npm:^3.0.0-pre.26, @polymer/iron-resizable-behavior@npm:^3.0.1":
version: 3.0.1
resolution: "@polymer/iron-resizable-behavior@npm:3.0.1"
dependencies:
@@ -4196,87 +4196,86 @@ __metadata:
languageName: node
linkType: hard
"@vaadin/combo-box@npm:^22.0.4":
version: 22.0.4
resolution: "@vaadin/combo-box@npm:22.0.4"
"@vaadin/combo-box@npm:^23.0.10":
version: 23.0.10
resolution: "@vaadin/combo-box@npm:23.0.10"
dependencies:
"@open-wc/dedupe-mixin": ^1.3.0
"@polymer/iron-resizable-behavior": ^3.0.0
"@polymer/polymer": ^3.0.0
"@vaadin/component-base": ^22.0.4
"@vaadin/field-base": ^22.0.4
"@vaadin/input-container": ^22.0.4
"@vaadin/item": ^22.0.4
"@vaadin/vaadin-lumo-styles": ^22.0.4
"@vaadin/vaadin-material-styles": ^22.0.4
"@vaadin/vaadin-overlay": ^22.0.4
"@vaadin/vaadin-themable-mixin": ^22.0.4
checksum: a3cde710d1187bba8e9e7eeb7f6397e6e1158befa3412c3aa684b3b45a1425cdee28d408d5e4dc4f586e1f6881db8850fc51c38f4658c4eb65c51a26a9623c56
"@vaadin/component-base": ^23.0.10
"@vaadin/field-base": ^23.0.10
"@vaadin/input-container": ^23.0.10
"@vaadin/item": ^23.0.10
"@vaadin/vaadin-lumo-styles": ^23.0.10
"@vaadin/vaadin-material-styles": ^23.0.10
"@vaadin/vaadin-overlay": ^23.0.10
"@vaadin/vaadin-themable-mixin": ^23.0.10
checksum: daaa0bd0cc0e8f1622417bd311e389f860c76d31fe8885f23fcdd486ff966a0945d6fe504f8d7251ec1ec54b95ef66b52d8a9e9e03ec21791bb6ca8b7f24efeb
languageName: node
linkType: hard
"@vaadin/component-base@npm:^22.0.4":
version: 22.0.4
resolution: "@vaadin/component-base@npm:22.0.4"
"@vaadin/component-base@npm:^23.0.10":
version: 23.0.10
resolution: "@vaadin/component-base@npm:23.0.10"
dependencies:
"@open-wc/dedupe-mixin": ^1.3.0
"@polymer/polymer": ^3.0.0
"@vaadin/vaadin-development-mode-detector": ^2.0.0
"@vaadin/vaadin-usage-statistics": ^2.1.0
lit: ^2.0.0
checksum: d18e7cebdd2928e33641ee035927540239e8a65d23521aca2e35d9992a44060d951e877af09088de0ffa88daa11f86a02b86a087cb29b51d9ada574009159509
checksum: 2b4d851999aad9dc8e1131d66924e26db64ce5a61d2c895bdf00c8daef774a651f5c2d5ade7274d3c7a1b8286170ee21a7ef873547895e0ceef4f7a7e07073a7
languageName: node
linkType: hard
"@vaadin/field-base@npm:^22.0.4":
version: 22.0.4
resolution: "@vaadin/field-base@npm:22.0.4"
"@vaadin/field-base@npm:^23.0.10":
version: 23.0.10
resolution: "@vaadin/field-base@npm:23.0.10"
dependencies:
"@open-wc/dedupe-mixin": ^1.3.0
"@polymer/polymer": ^3.0.0
"@vaadin/component-base": ^22.0.4
"@vaadin/component-base": ^23.0.10
lit: ^2.0.0
checksum: 4ca54ea3efd1bad2cea6ada97484e24f77f7ebb2ab5da7de5b9b7949d624b049d357c7f6f69206f1f10023b1711dc7b8bde9f6dfad774578efec00e1907c4763
checksum: 0f8d631af00a8268997beed8bde3f6080482eaf044577fd0df0b518fe06b90cbfa6f5c1b2b6e054171de652914d5596749484e4eaecff9754aef70760f25f493
languageName: node
linkType: hard
"@vaadin/icon@npm:^22.0.4":
version: 22.0.4
resolution: "@vaadin/icon@npm:22.0.4"
"@vaadin/icon@npm:^23.0.10":
version: 23.0.10
resolution: "@vaadin/icon@npm:23.0.10"
dependencies:
"@polymer/polymer": ^3.0.0
"@vaadin/component-base": ^22.0.4
"@vaadin/vaadin-lumo-styles": ^22.0.4
"@vaadin/vaadin-themable-mixin": ^22.0.4
"@vaadin/component-base": ^23.0.10
"@vaadin/vaadin-lumo-styles": ^23.0.10
"@vaadin/vaadin-themable-mixin": ^23.0.10
lit: ^2.0.0
checksum: 65e5195a8eb6f8ce24471c3f52ffdd7edc49249e39922e945eb8f02fc2b277d8d527a1538241b9660ca568a87663912b1be9c82fa8a841f286e713630d52f3db
checksum: 1b7da9116ac649796e7852572280be67176fd609c46f37cb1f35fdd1daba0d44ac4c81642de07104c16580b9165f1f05af15c15c3828c95bc9d795b3050b31a1
languageName: node
linkType: hard
"@vaadin/input-container@npm:^22.0.4":
version: 22.0.4
resolution: "@vaadin/input-container@npm:22.0.4"
"@vaadin/input-container@npm:^23.0.10":
version: 23.0.10
resolution: "@vaadin/input-container@npm:23.0.10"
dependencies:
"@polymer/polymer": ^3.0.0
"@vaadin/component-base": ^22.0.4
"@vaadin/vaadin-lumo-styles": ^22.0.4
"@vaadin/vaadin-material-styles": ^22.0.4
"@vaadin/vaadin-themable-mixin": ^22.0.4
checksum: 718cb7d8f715427d9085feee8a0df987440511059c5bbfcaa80d63ecd989a693f8f50af9da0f483555396aece21b75eff280921eda7cf0b6358e67518e53ba85
"@vaadin/component-base": ^23.0.10
"@vaadin/vaadin-lumo-styles": ^23.0.10
"@vaadin/vaadin-material-styles": ^23.0.10
"@vaadin/vaadin-themable-mixin": ^23.0.10
checksum: 2a21486ef0d4618bf890823bae2471a4e476cf37d5b53059c80e0516acc34990dd0a627751b17ea3ab7eb3040dd343b222b9984d734bd07985a6b9f441015aa3
languageName: node
linkType: hard
"@vaadin/item@npm:^22.0.4":
version: 22.0.4
resolution: "@vaadin/item@npm:22.0.4"
"@vaadin/item@npm:^23.0.10":
version: 23.0.10
resolution: "@vaadin/item@npm:23.0.10"
dependencies:
"@open-wc/dedupe-mixin": ^1.3.0
"@polymer/polymer": ^3.0.0
"@vaadin/component-base": ^22.0.4
"@vaadin/vaadin-lumo-styles": ^22.0.4
"@vaadin/vaadin-material-styles": ^22.0.4
"@vaadin/vaadin-themable-mixin": ^22.0.4
checksum: ef8c253668852a129656e083149b3866327dfae8671e30bb1bf78b39f969bd1db74892f090c7632b64fd91c25334f0542ad9dc6848486609de4350da5e5ea44c
"@vaadin/component-base": ^23.0.10
"@vaadin/vaadin-lumo-styles": ^23.0.10
"@vaadin/vaadin-material-styles": ^23.0.10
"@vaadin/vaadin-themable-mixin": ^23.0.10
checksum: 790fb48a12c37ad20fbb8f498601585006e27e2b78164336932c64071b1a7d34e88541d4f190c5357c32694dc76676d63c22b4c9cee64debecef90ea5f9ebbc5
languageName: node
linkType: hard
@@ -4287,49 +4286,49 @@ __metadata:
languageName: node
linkType: hard
"@vaadin/vaadin-lumo-styles@npm:^22.0.4":
version: 22.0.4
resolution: "@vaadin/vaadin-lumo-styles@npm:22.0.4"
"@vaadin/vaadin-lumo-styles@npm:^23.0.10":
version: 23.0.10
resolution: "@vaadin/vaadin-lumo-styles@npm:23.0.10"
dependencies:
"@polymer/iron-icon": ^3.0.0
"@polymer/iron-iconset-svg": ^3.0.0
"@polymer/polymer": ^3.0.0
"@vaadin/icon": ^22.0.4
"@vaadin/vaadin-themable-mixin": ^22.0.4
checksum: 15e9becd675e0d12024fbdfaecedd03f55841f685932ff5cf8a2143641f895309f21b84f378f1fca3af538c3aba26dad81421f05a28f31ad7bb5550ede8a3aea
"@vaadin/icon": ^23.0.10
"@vaadin/vaadin-themable-mixin": ^23.0.10
checksum: c2a9c9f9d441bc55f326b267c4953361d64fed4bfe08727e7c3ea1d1598711c18c4e78faedb7ae192ba474b72a6f1521f366be1a9ed80132f83bc400869275c7
languageName: node
linkType: hard
"@vaadin/vaadin-material-styles@npm:^22.0.4":
version: 22.0.4
resolution: "@vaadin/vaadin-material-styles@npm:22.0.4"
"@vaadin/vaadin-material-styles@npm:^23.0.10":
version: 23.0.10
resolution: "@vaadin/vaadin-material-styles@npm:23.0.10"
dependencies:
"@polymer/polymer": ^3.0.0
"@vaadin/vaadin-themable-mixin": ^22.0.4
checksum: 0e341e03eab9641cc317a9cbf6d57e7d026539d7bc77159226625aad63a379f31cd70da5e02f10a3d79e9fe0cba1b058935beb2c5d98f146bfb9dd45d8634ee6
"@vaadin/vaadin-themable-mixin": ^23.0.10
checksum: d2f47272ac6ec3c099a6bebb0d6d861837f5d506b4c1c1ce2fe7d691b1aa8dd944afaaa9c3d4fc51cbee2cfb2efb677a89428fc124a1a4c4cc2b98058a6d2ef7
languageName: node
linkType: hard
"@vaadin/vaadin-overlay@npm:^22.0.4":
version: 22.0.4
resolution: "@vaadin/vaadin-overlay@npm:22.0.4"
"@vaadin/vaadin-overlay@npm:^23.0.10":
version: 23.0.10
resolution: "@vaadin/vaadin-overlay@npm:23.0.10"
dependencies:
"@polymer/polymer": ^3.0.0
"@vaadin/component-base": ^22.0.4
"@vaadin/vaadin-lumo-styles": ^22.0.4
"@vaadin/vaadin-material-styles": ^22.0.4
"@vaadin/vaadin-themable-mixin": ^22.0.4
checksum: 1b012ff0beac7879da498cf50ee0974d4c3e5637ebea7f7834b9bfc45b9f02e80c61267794c0f3f4e1d4853aa2f35113e1d94bc187d9fe072f37a03eb99f3ab6
"@vaadin/component-base": ^23.0.10
"@vaadin/vaadin-lumo-styles": ^23.0.10
"@vaadin/vaadin-material-styles": ^23.0.10
"@vaadin/vaadin-themable-mixin": ^23.0.10
checksum: 25bbca730426a87967ea0648db760b2669a257e46cd2e60cd9506bbfd8c0e7c353fc23063aa338b8feee9f6ed0a763c78a458b79c39d04c34591fdc8e476274c
languageName: node
linkType: hard
"@vaadin/vaadin-themable-mixin@npm:^22.0.4":
version: 22.0.4
resolution: "@vaadin/vaadin-themable-mixin@npm:22.0.4"
"@vaadin/vaadin-themable-mixin@npm:^23.0.10":
version: 23.0.10
resolution: "@vaadin/vaadin-themable-mixin@npm:23.0.10"
dependencies:
"@open-wc/dedupe-mixin": ^1.3.0
lit: ^2.0.0
checksum: 0b2dce09626c92b85ff2d2ad48c8130239bf41fd95147a5fd4490cab4767f074ba9d1008d732d9e90b9219cb1ac0509f4a5fc8637eb5847d6d33e14b20552186
checksum: 056bff097ebc7fe1756c53018272b8b3b9006a53e77bf5ba964cff2f3b43ede52d980352a3bd38bc9eb6889ab85e897dcdc67493e9c0380993afd4fa0f2e7796
languageName: node
linkType: hard
@@ -9084,8 +9083,8 @@ fsevents@^1.2.7:
"@types/webspeechapi": ^0.0.29
"@typescript-eslint/eslint-plugin": ^4.32.0
"@typescript-eslint/parser": ^4.32.0
"@vaadin/combo-box": ^22.0.4
"@vaadin/vaadin-themable-mixin": ^22.0.4
"@vaadin/combo-box": ^23.0.10
"@vaadin/vaadin-themable-mixin": ^23.0.10
"@vibrant/color": ^3.2.1-alpha.1
"@vibrant/core": ^3.2.1-alpha.1
"@vibrant/quantizer-mmcq": ^3.2.1-alpha.1
@@ -9128,7 +9127,7 @@ fsevents@^1.2.7:
gulp-rename: ^2.0.0
gulp-zopfli-green: ^3.0.1
hls.js: ^1.1.5
home-assistant-js-websocket: ^7.0.3
home-assistant-js-websocket: ^7.1.0
html-minifier: ^4.0.0
husky: ^1.3.1
idb-keyval: ^5.1.3
@@ -9198,10 +9197,10 @@ fsevents@^1.2.7:
languageName: unknown
linkType: soft
"home-assistant-js-websocket@npm:^7.0.3":
version: 7.0.3
resolution: "home-assistant-js-websocket@npm:7.0.3"
checksum: f2647fab4599069a6422b53661de0c8c5177408e297e89f35b442c5d8e65d31d7f607e6e6a813f4ec8af9d581b45a20b88b44bfedbe25b6c3f01fcc38d0e396e
"home-assistant-js-websocket@npm:^7.1.0":
version: 7.1.0
resolution: "home-assistant-js-websocket@npm:7.1.0"
checksum: 726f1e8ec0f900203a04ccf57723b448d2fec0a940fa1515f40814e5ae9cda982724d5c4658fd176bd3d8ca82edbe8ddfcef599fd513ca315e8d35cb61c6c142
languageName: node
linkType: hard