Compare commits

..

105 Commits

Author SHA1 Message Date
renovate[bot]
cca4cc512b Update dependency @rsdoctor/rspack-plugin to v1.3.12 (#28350)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-04 14:54:27 +00:00
Petar Petrov
8eb65f327a Append current state to power-sources-graph (#28330) 2025-12-04 10:18:48 +01:00
Petar Petrov
f3495feacb Fix markdown sections and styling (#28333) 2025-12-04 10:15:11 +01:00
Petar Petrov
2161bcfa3f Fix gauge severity using entity state instead of attribute value (#28331) 2025-12-04 10:13:41 +01:00
Paul Bottein
1400398422 Move reorder areas and floors to floor overflow (#28335) 2025-12-04 10:58:27 +02:00
Preet Patel
506d466c03 Fix energy dashboard redirect for device-consumption-only configs (#28322)
When users configure energy with only device consumption (no
grid/solar/battery/gas/water sources), the dashboard would redirect
to /config/energy instead of displaying. This occurred because
_generateLovelaceConfig() returned an empty views array.

The fix adds hasDeviceConsumption check and includes ENERGY_VIEW
when device consumption is configured, since energy-view-strategy
already supports device consumption cards.
2025-12-04 06:38:43 +00:00
Bram Kragten
46735c72ed Add more info to the energy demo (#28316)
* Add more info to the energy demo

* Also add battery power
2025-12-03 20:46:59 +01:00
Copilot
c43d41053b Migrate ha-button-menu to ha-dropdown in 4 files (#28300)
Co-authored-by: wendevlin <12148533+wendevlin@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Wendelin <w@pe8.at>
Co-authored-by: uptimeZERO_ <pavilionsahota@gmail.com>
2025-12-03 16:43:07 +00:00
Petar Petrov
844d53a0ba Always show energy-sources-table in overview (#28315) 2025-12-03 17:18:07 +01:00
Bram Kragten
1c8b78eae9 Bumped version to 20251203.0 2025-12-03 15:31:03 +01:00
Bram Kragten
a918e878fa Fix add matter device my link (#28313) 2025-12-03 15:30:26 +01:00
Petar Petrov
ebc354bf55 Fix label filter losing selections when searching (#28312) 2025-12-03 15:29:48 +01:00
Wendelin
98a1f5ca3a Use ha-dropdown for automations/scripts (#28293)
Co-authored-by: uptimeZERO_ <pavilionsahota@gmail.com>
2025-12-03 13:33:48 +00:00
Bram Kragten
48015ab312 Fix sticky headers in TCA dialog when target is selected (#28310) 2025-12-03 14:24:29 +01:00
Aidan Timson
09515b1937 Add subscribeLabFeature function (#28309)
* Add subscribe to lab feature function

* Add docstrings to exported functions
2025-12-03 14:16:09 +01:00
Aidan Timson
5a40627676 Add small rotation to snowflakes (#28308) 2025-12-03 14:12:08 +01:00
Wendelin
cd34447603 Hide disabled devices in automation target tree (#28307) 2025-12-03 14:02:25 +01:00
Paul Bottein
803fabbf64 Use svg for snowflakes (#28306) 2025-12-03 11:46:07 +00:00
Paul Bottein
78c4dc48d0 Rename unassigned areas to other areas (#28305) 2025-12-03 12:42:14 +01:00
Paul Bottein
147600ea43 Use core area sorting everywhere (#28304) 2025-12-03 12:28:55 +01:00
Wendelin
2f91f0dd15 Revert "Migrate updates dropdown to ha-dropdown" (#28303)
Revert "Migrate updates dropdown to ha-dropdown (#28039)"

This reverts commit ba9bab38c9.
2025-12-03 12:27:39 +01:00
ildar170975
3fa330acfb computeLovelaceEntityName(): allow "number" names to be processed (#28231)
* allow "number" names to be processed

* Apply suggestion from @MindFreeze

---------

Co-authored-by: Petar Petrov <MindFreeze@users.noreply.github.com>
2025-12-03 10:40:29 +00:00
Paul Bottein
e0a6b671ce Always set ha-wa-dialog position to fixed (#28301) 2025-12-03 10:11:54 +00:00
Wendelin
d6edd150a8 Fix filtering of floors in getAreasAndFloorsItems function (#28302) 2025-12-03 10:45:18 +01:00
Petar Petrov
2c00889921 Add Y-axis label formatter to energy charts (#28298) 2025-12-03 10:33:00 +01:00
Petar Petrov
0447d87f18 Hide empty System message in assist debug view (#28296) 2025-12-03 10:29:07 +01:00
Petar Petrov
d7e18b0520 Fix binary sensor history timeline not rendering properly (#28297) 2025-12-03 10:18:32 +01:00
Luca Félix
e7254b1587 feat: round_temperature on weather forecast card (#28103)
* feat: round_temperature on weather forecast card

* fix: use round util function

* refactor: applied comments from review
2025-12-03 10:02:25 +02:00
renovate[bot]
8681a7d450 Update dependency prettier to v3.7.3 (#28295)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-03 07:19:24 +01:00
Paul Bottein
fff12acb6b Handle not existing panels in dashboard config (#28292) 2025-12-02 17:23:09 +01:00
Petar Petrov
3d327ed628 Update Energy dashboard layout (#28283) 2025-12-02 16:01:17 +01:00
Wendelin
0d51648de1 Use history to manage back button click in automations add TCA (#28289) 2025-12-02 15:43:13 +01:00
Wendelin
c5642c15b8 Automation add TCA: fix narrow subtitles & icons (#28291) 2025-12-02 14:17:55 +00:00
Paul Bottein
7f885010de Add dialog to reorder areas and floors (#28272) 2025-12-02 15:12:36 +01:00
Paul Bottein
356d51f974 Only show current weather in home overview (#28288) 2025-12-02 15:38:34 +02:00
Dave T
38a907e51e Separate action field YAML examples (#27218)
* Comma separate field examples if it is a list

* Remove prettier ignore and json.stringify all examples

* Use YAML format

---------

Co-authored-by: Petar Petrov <MindFreeze@users.noreply.github.com>
2025-12-02 13:34:25 +00:00
Bram Kragten
87c0b1d887 fix paste in add tca dialog (#28286) 2025-12-02 14:30:16 +01:00
Paul Bottein
0f195015b7 Fix container alignment in section view (#28287) 2025-12-02 15:29:11 +02:00
Petar Petrov
17a976af67 Fix index value for grid return in power sankey card (#28281) 2025-12-02 14:47:15 +02:00
Aidan Timson
a41a7e822a Remove placeholder for non device area picker in entity settings (#28285)
Remove placeholder for non device area picker
2025-12-02 11:52:02 +00:00
dependabot[bot]
5473bf56c6 Bump express from 4.21.2 to 4.22.1 (#28280)
Bumps [express](https://github.com/expressjs/express) from 4.21.2 to 4.22.1.
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/v4.22.1/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.21.2...v4.22.1)

---
updated-dependencies:
- dependency-name: express
  dependency-version: 4.22.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-02 08:17:59 +02:00
karwosts
029eba7ab8 Safer lookup of description_placeholders when service is invalid (#28273) 2025-12-02 08:08:36 +02:00
Silas Krause
824a3f288d Revert custom markdown styles (#28277) 2025-12-02 08:07:45 +02:00
renovate[bot]
fdd89c05d3 Update dependency prettier to v3.7.2 (#28276)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-02 08:06:30 +02:00
Paul Bottein
c33cb7fff9 Clean reference to floor compare (#28269)
Fix floor compare
2025-12-01 16:47:09 +02:00
Paul Bottein
de53ad8dce Add helper for floor level (#28268)
* Add helper for floor level

* Update src/translations/en.json

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

---------

Co-authored-by: Petar Petrov <MindFreeze@users.noreply.github.com>
2025-12-01 15:43:57 +01:00
Simon Lamon
2dec7490b6 Include background in light, climate and security views (#28264)
* Include background

* Remove background key

* Add imports
2025-12-01 16:20:50 +02:00
Aidan Timson
6ed4bd5ce8 Match more-info-update backup preferences (#28266) 2025-12-01 15:51:31 +02:00
Petar Petrov
4e899c56ed Reduce the duration of init animation for charts to 500ms (#28262)
Reduce the duration of init animation for charts
2025-12-01 15:43:20 +02:00
Petar Petrov
53c20a0493 Add power view and restructure energy dashboard layout (#28240) 2025-12-01 14:16:11 +01:00
Wendelin
be2d6e9212 Fix automation trigger ha icon (#28265) 2025-12-01 13:05:36 +00:00
Wendelin
915442c571 Respect system area sort in automation target tree (#28263) 2025-12-01 14:01:06 +01:00
Aidan Timson
de6ebc2d0a Add missing key for labs to show in quick bar (#28261) 2025-12-01 12:26:41 +00:00
Bram Kragten
bcb12fa062 Use name instead of description_configured for triggers and conditions (#28260) 2025-12-01 13:19:19 +01:00
Aidan Timson
078915743d Make labs toolbar icon use default color (#28255) 2025-12-01 12:08:25 +01:00
Petar Petrov
54c524127f Fix refresh in energy panel subviews (#28252) 2025-12-01 12:07:45 +01:00
Wendelin
334e1c35e1 Fix ha-bottom-sheet closed event (#28257) 2025-12-01 12:04:15 +01:00
Aidan Timson
528c7727e2 Fix 1px padding for subpage titles (#28256) 2025-12-01 12:03:38 +01:00
Aidan Timson
d1043e33df Fix subpage layout icon alignment (#28254) 2025-12-01 09:54:25 +00:00
dependabot[bot]
b088f2c0e5 Bump home-assistant/wheels from 2025.10.0 to 2025.11.0 (#28251)
Bumps [home-assistant/wheels](https://github.com/home-assistant/wheels) from 2025.10.0 to 2025.11.0.
- [Release notes](https://github.com/home-assistant/wheels/releases)
- [Commits](https://github.com/home-assistant/wheels/compare/2025.10.0...2025.11.0)

---
updated-dependencies:
- dependency-name: home-assistant/wheels
  dependency-version: 2025.11.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-01 08:53:24 +02:00
dependabot[bot]
b33f407493 Bump relative-ci/agent-action from 3.2.0 to 3.2.1 (#28250)
Bumps [relative-ci/agent-action](https://github.com/relative-ci/agent-action) from 3.2.0 to 3.2.1.
- [Release notes](https://github.com/relative-ci/agent-action/releases)
- [Commits](feb19ddc69...c45aaa919e)

---
updated-dependencies:
- dependency-name: relative-ci/agent-action
  dependency-version: 3.2.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-01 08:48:44 +02:00
dependabot[bot]
502d76b316 Bump actions/setup-python from 6.0.0 to 6.1.0 (#28249)
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 6.0.0 to 6.1.0.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](e797f83bcb...83679a892e)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-01 08:48:24 +02:00
dependabot[bot]
1ddc07c215 Bump softprops/action-gh-release from 2.4.2 to 2.5.0 (#28248)
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.4.2 to 2.5.0.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](5be0e66d93...a06a81a03e)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-01 08:47:32 +02:00
dependabot[bot]
a611a5fc4e Bump github/codeql-action from 4.31.4 to 4.31.5 (#28247)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.31.4 to 4.31.5.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](e12f017898...fdbfb4d275)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.31.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-01 08:46:51 +02:00
eringerli
c13bece6d0 fix stacking of multiple power sources (#28243) 2025-12-01 06:25:47 +00:00
Paulus Schoutsen
28a89ff9e6 Add custom element decorators instead of customElements.define (#28235)
* Add custom element decorators instead of customElements.define

* Ignore

* prettier
2025-12-01 06:38:31 +01:00
karwosts
81b5ddec9d Add water devices to energy data download (#28242) 2025-11-30 16:00:14 +01:00
renovate[bot]
ce86aabe32 Update dependency prettier to v3.7.1 (#28239)
* Update dependency prettier to v3.7.1

* format

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Petar Petrov <MindFreeze@users.noreply.github.com>
2025-11-30 13:33:41 +00:00
Silas Krause
a8910bcbe4 Fix markdown rendering for cached html (#28229)
* Render markdown table in wrapper.

* Fix markdown styles

* Fix formatting

* fix rendering for cache
2025-11-30 15:21:39 +02:00
ildar170975
0e4cf9f62d ha-picker-field: change left padding to align with other controls (#28217)
change --md-list-item-leading-space & --md-list-item-trailing-space
2025-11-29 14:00:27 +02:00
renovate[bot]
506635d649 Update vaadinWebComponents monorepo to v24.9.6 (#28225)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-29 11:44:28 +00:00
karwosts
27e24ee49b Add missing helper to language selector (#28218) 2025-11-29 12:35:04 +01:00
renovate[bot]
bcd712b48c Update vitest monorepo to v4.0.14 (#28215)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-28 20:23:38 +01:00
renovate[bot]
461ef9b916 Update dependency @rspack/core to v1.6.5 (#28207)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-28 11:14:57 +01:00
renovate[bot]
b794989daa Update dependency @bundle-stats/plugin-webpack-filter to v4.21.7 (#28205)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-28 08:29:33 +02:00
Silas Krause
6727ffaae0 Fix markdown styles regression (#28202)
* Render markdown table in wrapper.

* Fix markdown styles

* Fix formatting
2025-11-28 08:28:57 +02:00
Paul Bottein
4df8501b20 Fix ha icon size (#28201) 2025-11-27 22:54:44 +01:00
Aidan Timson
539d0e443f Fix ha-wa-dialog fullscreen and make alerts not fullscreen (#28175) 2025-11-27 22:01:30 +01:00
renovate[bot]
9c9d274b5c Update dependency typescript-eslint to v8.48.0 (#28196)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-27 19:20:07 +01:00
Paul Bottein
d6e6bc0e80 Fix safe area for sidebar section views in Android (#28194) 2025-11-27 19:46:56 +02:00
ildar170975
530a70b168 Automations, scripts, scenes: add a tooltip for relative time (#28158)
* add a tooltip for last_triggered

* add a tooltip for last_triggered

* add a tooltip for last_activated

* Apply suggestions from code review

* Apply suggestion from @MindFreeze

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

* Apply suggestion from @MindFreeze

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

* Apply suggestion from @MindFreeze

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

---------

Co-authored-by: Petar Petrov <MindFreeze@users.noreply.github.com>
2025-11-27 19:44:11 +02:00
Wendelin
23137500f8 Add TCA by target sort like item collections (#28192) 2025-11-27 17:03:27 +01:00
Wendelin
63e7ed21a4 Fix lab automations icons and sidebar width (#28184)
Co-authored-by: Petar Petrov <MindFreeze@users.noreply.github.com>
2025-11-27 16:57:42 +01:00
Petar Petrov
92611f46f4 Fix water sankey calculation to include total supply from sources (#28191) 2025-11-27 16:44:56 +01:00
Bram Kragten
9bc896241d Always store token when using develop and serve (#28179) 2025-11-27 16:43:36 +01:00
Paul Bottein
2baafe620c Add hint to reorder areas and floors (#28189) 2025-11-27 16:32:23 +01:00
Wendelin
ce52bbaf8c Show hidden entities in target tree (#28181)
* Show hidden entities in target tree

* Fix types
2025-11-27 15:44:50 +02:00
Wendelin
0b4b8d9082 "Add TCA" dialog desktop height to 800px (#28182) 2025-11-27 14:42:18 +01:00
Petar Petrov
bddbb773b7 Fix sankey chart resizing (#28180) 2025-11-27 15:41:46 +02:00
Paul Bottein
d52e1e8835 Use hui-root for panel energy (#28149)
* Use hui-root for panel energy

* Review feedback

* Set empty prefs
2025-11-27 15:35:36 +02:00
Petar Petrov
0a9dccfd19 Refactor power sankey hierarchy to handle devices with not power sensor (#28164) 2025-11-27 12:21:55 +01:00
Petar Petrov
bfd78670cc Disable axis pointer on the energy devices bar chart to fix refresh issues on touch devices (#28163) 2025-11-27 12:20:06 +01:00
Petar Petrov
11276af1a0 Handle grouping by floor and area in power sankey card (#28162) 2025-11-27 12:19:42 +01:00
Paul Bottein
d7be46c00b Fix box shadow for sidebar tabs (#28170) 2025-11-27 12:19:15 +01:00
Paul Bottein
94f32ce242 Fix disabled dashboard picker when no custom dashboard (#28172) 2025-11-27 12:18:48 +01:00
Wendelin
ef3e8186bc Fix add condition default tab and blank styles (#28166) 2025-11-27 12:18:21 +01:00
Paul Bottein
50fcf622aa Fix labs back button (#28174) 2025-11-27 12:42:55 +02:00
Paul Bottein
77c2444be8 Restore sidebar view when clicking back (#28167) 2025-11-27 12:42:36 +02:00
Wendelin
e5cb26cd3d Fix automation add TCA autofocus (#28168)
Fix automation add tca autofocus
2025-11-27 11:28:18 +01:00
Simon Lamon
2896519bfd Don't show more info for untracked consumption (#28151) 2025-11-27 09:55:23 +02:00
ildar170975
0b6e35eb53 Data tables: make sorting direction 2-state instead of 3-state (#28160)
* sorting is 2-state

* sorting is 2-state

* sorting is 2-state
2025-11-27 09:54:38 +02:00
Iván Pereira
e80a855f87 Fix hide sidebar tooltip on touchend events (#28042)
* fix: hide sidebar tooltip on touchend events

* Add a comment recommended by Copilot

* Clear timeouts id in disconnectedCallback
2025-11-27 09:03:23 +02:00
dependabot[bot]
7c88cf4e30 Bump node-forge from 1.3.1 to 1.3.2 (#28157)
Bumps [node-forge](https://github.com/digitalbazaar/forge) from 1.3.1 to 1.3.2.
- [Changelog](https://github.com/digitalbazaar/forge/blob/main/CHANGELOG.md)
- [Commits](https://github.com/digitalbazaar/forge/compare/v1.3.1...v1.3.2)

---
updated-dependencies:
- dependency-name: node-forge
  dependency-version: 1.3.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-27 06:49:09 +01:00
Petar Petrov
9001cd3e65 Replace gauges with energy usage graph in energy overview (#28150) 2025-11-26 17:37:18 +01:00
renovate[bot]
ca8923d8f4 Update dependency glob to v13 (#28135)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-26 18:13:05 +02:00
139 changed files with 2266 additions and 1863 deletions

View File

@@ -36,14 +36,14 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@e12f0178983d466f2f6028f5cc7a6d786fd97f4b # v4.31.4
uses: github/codeql-action/init@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5
with:
languages: ${{ matrix.language }}
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@e12f0178983d466f2f6028f5cc7a6d786fd97f4b # v4.31.4
uses: github/codeql-action/autobuild@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -57,4 +57,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@e12f0178983d466f2f6028f5cc7a6d786fd97f4b # v4.31.4
uses: github/codeql-action/analyze@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5

View File

@@ -23,7 +23,7 @@ jobs:
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6
with:
python-version: ${{ env.PYTHON_VERSION }}

View File

@@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Send bundle stats and build information to RelativeCI
uses: relative-ci/agent-action@feb19ddc698445db27401f1490f6ac182da0816f # v3.2.0
uses: relative-ci/agent-action@c45aaa919ef85620af54242a241ac17a8fa35983 # v3.2.1
with:
key: ${{ secrets[format('RELATIVE_CI_KEY_{0}_{1}', matrix.bundle, matrix.build)] }}
token: ${{ github.token }}

View File

@@ -26,7 +26,7 @@ jobs:
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
with:
python-version: ${{ env.PYTHON_VERSION }}
@@ -55,7 +55,7 @@ jobs:
script/release
- name: Upload release assets
uses: softprops/action-gh-release@5be0e66d93ac7ed76da52eca8bb058f665c3a5fe # v2.4.2
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
with:
files: |
dist/*.whl
@@ -75,7 +75,7 @@ jobs:
# home-assistant/wheels doesn't support SHA pinning
- name: Build wheels
uses: home-assistant/wheels@2025.10.0
uses: home-assistant/wheels@2025.11.0
with:
abi: cp313
tag: musllinux_1_2
@@ -108,7 +108,7 @@ jobs:
- name: Tar folder
run: tar -czf landing-page/home_assistant_frontend_landingpage-${{ github.event.release.tag_name }}.tar.gz -C landing-page/dist .
- name: Upload release asset
uses: softprops/action-gh-release@5be0e66d93ac7ed76da52eca8bb058f665c3a5fe # v2.4.2
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
with:
files: landing-page/home_assistant_frontend_landingpage-${{ github.event.release.tag_name }}.tar.gz
@@ -137,6 +137,6 @@ jobs:
- name: Tar folder
run: tar -czf hassio/home_assistant_frontend_supervisor-${{ github.event.release.tag_name }}.tar.gz -C hassio/build .
- name: Upload release asset
uses: softprops/action-gh-release@5be0e66d93ac7ed76da52eca8bb058f665c3a5fe # v2.4.2
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
with:
files: hassio/home_assistant_frontend_supervisor-${{ github.event.release.tag_name }}.tar.gz

View File

@@ -156,7 +156,9 @@ const createTestTranslation = () =>
*/
const createMasterTranslation = () =>
gulp
.src([EN_SRC, ...(mergeBackend ? [`${inBackendDir}/en.json`] : [])])
.src([EN_SRC, ...(mergeBackend ? [`${inBackendDir}/en.json`] : [])], {
allowEmpty: true,
})
.pipe(new CustomJSON(lokaliseTransform))
.pipe(new MergeJSON("en"))
.pipe(gulp.dest(workDir));

View File

@@ -305,9 +305,8 @@ export class HcMain extends HassElement {
await llColl.refresh();
this._unsubLovelace = llColl.subscribe(async (rawConfig) => {
if (isStrategyDashboard(rawConfig)) {
const { generateLovelaceDashboardStrategy } = await import(
"../../../../src/panels/lovelace/strategies/get-strategy"
);
const { generateLovelaceDashboardStrategy } =
await import("../../../../src/panels/lovelace/strategies/get-strategy");
const config = await generateLovelaceDashboardStrategy(
rawConfig,
this.hass!
@@ -347,9 +346,8 @@ export class HcMain extends HassElement {
}
private async _generateDefaultLovelaceConfig() {
const { generateLovelaceDashboardStrategy } = await import(
"../../../../src/panels/lovelace/strategies/get-strategy"
);
const { generateLovelaceDashboardStrategy } =
await import("../../../../src/panels/lovelace/strategies/get-strategy");
this._handleNewLovelaceConfig(
await generateLovelaceDashboardStrategy(DEFAULT_CONFIG, this.hass!)
);

View File

@@ -44,18 +44,24 @@ export const mockEnergy = (hass: MockHomeAssistant) => {
number_energy_price: null,
},
],
power: [
{ stat_rate: "sensor.power_grid" },
{ stat_rate: "sensor.power_grid_return" },
],
cost_adjustment_day: 0,
},
{
type: "solar",
stat_energy_from: "sensor.solar_production",
stat_rate: "sensor.power_solar",
config_entry_solar_forecast: ["solar_forecast"],
},
/* {
{
type: "battery",
stat_energy_from: "sensor.battery_output",
stat_energy_to: "sensor.battery_input",
}, */
stat_rate: "sensor.power_battery",
},
{
type: "gas",
stat_energy_from: "sensor.energy_gas",
@@ -63,28 +69,48 @@ export const mockEnergy = (hass: MockHomeAssistant) => {
entity_energy_price: null,
number_energy_price: null,
},
{
type: "water",
stat_energy_from: "sensor.energy_water",
stat_cost: "sensor.energy_water_cost",
entity_energy_price: null,
number_energy_price: null,
},
],
device_consumption: [
{
stat_consumption: "sensor.energy_car",
stat_rate: "sensor.power_car",
},
{
stat_consumption: "sensor.energy_ac",
stat_rate: "sensor.power_ac",
},
{
stat_consumption: "sensor.energy_washing_machine",
stat_rate: "sensor.power_washing_machine",
},
{
stat_consumption: "sensor.energy_dryer",
stat_rate: "sensor.power_dryer",
},
{
stat_consumption: "sensor.energy_heat_pump",
stat_rate: "sensor.power_heat_pump",
},
{
stat_consumption: "sensor.energy_boiler",
stat_rate: "sensor.power_boiler",
},
],
device_consumption_water: [
{
stat_consumption: "sensor.water_kitchen",
},
{
stat_consumption: "sensor.water_garden",
},
],
device_consumption_water: [],
})
);
hass.mockWS(

View File

@@ -154,6 +154,38 @@ export const energyEntities = () =>
unit_of_measurement: "EUR",
},
},
"sensor.power_grid": {
entity_id: "sensor.power_grid",
state: "500",
attributes: {
state_class: "measurement",
unit_of_measurement: "W",
},
},
"sensor.power_grid_return": {
entity_id: "sensor.power_grid_return",
state: "-100",
attributes: {
state_class: "measurement",
unit_of_measurement: "W",
},
},
"sensor.power_solar": {
entity_id: "sensor.power_solar",
state: "200",
attributes: {
state_class: "measurement",
unit_of_measurement: "W",
},
},
"sensor.power_battery": {
entity_id: "sensor.power_battery",
state: "100",
attributes: {
state_class: "measurement",
unit_of_measurement: "W",
},
},
"sensor.energy_gas_cost": {
entity_id: "sensor.energy_gas_cost",
state: "2",
@@ -171,6 +203,15 @@ export const energyEntities = () =>
unit_of_measurement: "m³",
},
},
"sensor.energy_water": {
entity_id: "sensor.energy_water",
state: "4000",
attributes: {
last_reset: "1970-01-01T00:00:00:00+00",
friendly_name: "Water",
unit_of_measurement: "L",
},
},
"sensor.energy_car": {
entity_id: "sensor.energy_car",
state: "4",
@@ -225,4 +266,58 @@ export const energyEntities = () =>
unit_of_measurement: "kWh",
},
},
"sensor.power_car": {
entity_id: "sensor.power_car",
state: "40",
attributes: {
state_class: "measurement",
friendly_name: "Electric car",
unit_of_measurement: "W",
},
},
"sensor.power_ac": {
entity_id: "sensor.power_ac",
state: "30",
attributes: {
state_class: "measurement",
friendly_name: "Air conditioning",
unit_of_measurement: "W",
},
},
"sensor.power_washing_machine": {
entity_id: "sensor.power_washing_machine",
state: "60",
attributes: {
state_class: "measurement",
friendly_name: "Washing machine",
unit_of_measurement: "W",
},
},
"sensor.power_dryer": {
entity_id: "sensor.power_dryer",
state: "55",
attributes: {
state_class: "measurement",
friendly_name: "Dryer",
unit_of_measurement: "W",
},
},
"sensor.power_heat_pump": {
entity_id: "sensor.power_heat_pump",
state: "60",
attributes: {
state_class: "measurement",
friendly_name: "Heat pump",
unit_of_measurement: "W",
},
},
"sensor.power_boiler": {
entity_id: "sensor.power_boiler",
state: "70",
attributes: {
state_class: "measurement",
friendly_name: "Boiler",
unit_of_measurement: "W",
},
},
});

View File

@@ -17,17 +17,15 @@ const generateMeanStatistics = (
end: Date,
// eslint-disable-next-line default-param-last
period: "5minute" | "hour" | "day" | "month" = "hour",
initValue: number,
maxDiff: number
): StatisticValue[] => {
const statistics: StatisticValue[] = [];
let currentDate = new Date(start);
currentDate.setMinutes(0, 0, 0);
let lastVal = initValue;
const now = new Date();
while (end > currentDate && currentDate < now) {
const delta = Math.random() * maxDiff;
const mean = lastVal + delta;
const mean = delta;
statistics.push({
start: currentDate.getTime(),
end: currentDate.getTime(),
@@ -38,7 +36,6 @@ const generateMeanStatistics = (
state: mean,
sum: null,
});
lastVal = mean;
currentDate =
period === "day"
? addDays(currentDate, 1)
@@ -336,7 +333,6 @@ export const mockRecorder = (mockHass: MockHomeAssistant) => {
start,
end,
period,
state,
state * (state > 80 ? 0.05 : 0.1)
);
}

View File

@@ -88,8 +88,8 @@ class HassioRegistriesDialog extends LitElement {
<ha-button
?disabled=${Boolean(
!this._input.registry ||
!this._input.username ||
!this._input.password
!this._input.username ||
!this._input.password
)}
@click=${this._addNewRegistry}
appearance="filled"

View File

@@ -52,7 +52,7 @@
"@fullcalendar/list": "6.1.19",
"@fullcalendar/luxon3": "6.1.19",
"@fullcalendar/timegrid": "6.1.19",
"@home-assistant/webawesome": "3.0.0-ha.0",
"@home-assistant/webawesome": "3.0.0-ha.1",
"@lezer/highlight": "1.2.3",
"@lit-labs/motion": "1.0.9",
"@lit-labs/observers": "2.0.6",
@@ -89,8 +89,8 @@
"@thomasloven/round-slider": "0.6.0",
"@tsparticles/engine": "3.9.1",
"@tsparticles/preset-links": "3.2.0",
"@vaadin/combo-box": "24.9.5",
"@vaadin/vaadin-themable-mixin": "24.9.5",
"@vaadin/combo-box": "24.9.6",
"@vaadin/vaadin-themable-mixin": "24.9.6",
"@vibrant/color": "4.0.0",
"@vue/web-component-wrapper": "1.3.0",
"@webcomponents/scoped-custom-element-registry": "0.0.10",
@@ -152,13 +152,13 @@
"@babel/helper-define-polyfill-provider": "0.6.5",
"@babel/plugin-transform-runtime": "7.28.5",
"@babel/preset-env": "7.28.5",
"@bundle-stats/plugin-webpack-filter": "4.21.6",
"@bundle-stats/plugin-webpack-filter": "4.21.7",
"@lokalise/node-api": "15.4.0",
"@octokit/auth-oauth-device": "8.0.3",
"@octokit/plugin-retry": "8.0.3",
"@octokit/rest": "22.0.1",
"@rsdoctor/rspack-plugin": "1.3.11",
"@rspack/core": "1.6.4",
"@rsdoctor/rspack-plugin": "1.3.12",
"@rspack/core": "1.6.5",
"@rspack/dev-server": "1.1.4",
"@types/babel__plugin-transform-runtime": "7.9.5",
"@types/chromecast-caf-receiver": "6.0.22",
@@ -178,7 +178,7 @@
"@types/tar": "6.1.13",
"@types/ua-parser-js": "0.7.39",
"@types/webspeechapi": "0.0.29",
"@vitest/coverage-v8": "4.0.13",
"@vitest/coverage-v8": "4.0.14",
"babel-loader": "10.0.0",
"babel-plugin-template-html-minifier": "4.1.0",
"browserslist-useragent-regexp": "4.1.3",
@@ -194,7 +194,7 @@
"eslint-plugin-wc": "3.0.2",
"fancy-log": "2.0.0",
"fs-extra": "11.3.2",
"glob": "12.0.0",
"glob": "13.0.0",
"gulp": "5.0.1",
"gulp-brotli": "3.0.0",
"gulp-json-transform": "0.5.0",
@@ -209,7 +209,7 @@
"lodash.template": "4.5.0",
"map-stream": "0.0.7",
"pinst": "3.0.0",
"prettier": "3.6.2",
"prettier": "3.7.3",
"rspack-manifest-plugin": "5.2.0",
"serve": "14.2.5",
"sinon": "21.0.0",
@@ -217,9 +217,9 @@
"terser-webpack-plugin": "5.3.14",
"ts-lit-plugin": "2.0.2",
"typescript": "5.9.3",
"typescript-eslint": "8.47.0",
"typescript-eslint": "8.48.0",
"vite-tsconfig-paths": "5.1.4",
"vitest": "4.0.13",
"vitest": "4.0.14",
"webpack-stats-plugin": "1.1.3",
"webpackbar": "7.0.0",
"workbox-build": "patch:workbox-build@npm%3A7.1.1#~/.yarn/patches/workbox-build-npm-7.1.1-a854f3faae.patch"

View File

@@ -45,9 +45,8 @@ export const computeFormatFunctions = async (
formatEntityAttributeName: FormatEntityAttributeNameFunc;
formatEntityName: FormatEntityNameFunc;
}> => {
const { computeStateDisplay } = await import(
"../entity/compute_state_display"
);
const { computeStateDisplay } =
await import("../entity/compute_state_display");
const { computeAttributeValueDisplay, computeAttributeNameDisplay } =
await import("../entity/compute_attribute_display");

View File

@@ -1,6 +1,6 @@
import type { PropertyValues } from "lit";
import { html, LitElement } from "lit";
import { property, state } from "lit/decorators";
import { customElement, property, state } from "lit/decorators";
import type { VisualMapComponentOption } from "echarts/components";
import type { LineSeriesOption } from "echarts/charts";
import type { YAXisOption } from "echarts/types/dist/shared";
@@ -27,6 +27,7 @@ const safeParseFloat = (value) => {
return isFinite(parsed) ? parsed : null;
};
@customElement("state-history-chart-line")
export class StateHistoryChartLine extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -795,7 +796,6 @@ export class StateHistoryChartLine extends LitElement {
return Math.abs(value) < 1 ? value : roundingFn(value);
}
}
customElements.define("state-history-chart-line", StateHistoryChartLine);
declare global {
interface HTMLElementTagNameMap {

View File

@@ -838,10 +838,10 @@ export class HaDataTable extends LitElement {
} else if (this.sortDirection === "asc") {
this.sortDirection = "desc";
} else {
this.sortDirection = null;
this.sortDirection = "asc";
}
this.sortColumn = this.sortDirection === null ? undefined : columnId;
this.sortColumn = columnId;
fireEvent(this, "sorting-changed", {
column: columnId,

View File

@@ -2,7 +2,7 @@ import { mdiAlert } from "@mdi/js";
import type { HassEntity } from "home-assistant-js-websocket";
import type { CSSResultGroup, PropertyValues } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { property, state } from "lit/decorators";
import { customElement, property, state } from "lit/decorators";
import { ifDefined } from "lit/directives/if-defined";
import { styleMap } from "lit/directives/style-map";
import { computeDomain } from "../../common/entity/compute_domain";
@@ -17,6 +17,7 @@ import { CLIMATE_HVAC_ACTION_TO_MODE } from "../../data/climate";
import type { HomeAssistant } from "../../types";
import "../ha-state-icon";
@customElement("state-badge")
export class StateBadge extends LitElement {
public hass?: HomeAssistant;
@@ -265,5 +266,3 @@ declare global {
"state-badge": StateBadge;
}
}
customElements.define("state-badge", StateBadge);

View File

@@ -99,10 +99,7 @@ class HaMarkdownElement extends ReactiveElement {
}
);
render(
elements.map((e) => h(unsafeHTML(e))),
this.renderRoot
);
render(h(unsafeHTML(elements.join(""))), this.renderRoot);
this._resize();

View File

@@ -25,11 +25,11 @@ export class HaMarkdown extends LitElement {
@property({ type: Boolean }) public cache = false;
@query("ha-markdown-element") private _markdownElement!: ReactiveElement;
@query("ha-markdown-element") private _markdownElement?: ReactiveElement;
protected async getUpdateComplete() {
const result = await super.getUpdateComplete();
await this._markdownElement.updateComplete;
await this._markdownElement?.updateComplete;
return result;
}

View File

@@ -103,8 +103,8 @@ export class HaPickerField extends LitElement {
--md-list-item-two-line-container-height: 56px;
--md-list-item-top-space: 0px;
--md-list-item-bottom-space: 0px;
--md-list-item-leading-space: 8px;
--md-list-item-trailing-space: 8px;
--md-list-item-leading-space: var(--ha-space-4);
--md-list-item-trailing-space: var(--ha-space-2);
--ha-md-list-item-gap: var(--ha-space-2);
/* Remove the default focus ring */
--md-focus-ring-width: 0px;

View File

@@ -450,7 +450,7 @@ export class HaServiceControl extends LitElement {
const hasOptional = Boolean(
!shouldRenderServiceDataYaml &&
serviceData?.flatFields.some((field) => showOptionalToggle(field))
serviceData?.flatFields.some((field) => showOptionalToggle(field))
);
const targetEntities = this._getTargetedEntities(

View File

@@ -1,10 +1,11 @@
import { LitElement, html, css } from "lit";
import { property } from "lit/decorators";
import { customElement, property } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import type { HomeAssistant } from "../../types";
import { fireEvent } from "../../common/dom/fire_event";
import "../ha-state-icon";
@customElement("ha-entity-marker")
class HaEntityMarker extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -89,8 +90,6 @@ class HaEntityMarker extends LitElement {
`;
}
customElements.define("ha-entity-marker", HaEntityMarker);
declare global {
interface HTMLElementTagNameMap {
"ha-entity-marker": HaEntityMarker;

View File

@@ -11,7 +11,7 @@ import {
isLastDayOfMonth,
addYears,
} from "date-fns";
import type { Collection } from "home-assistant-js-websocket";
import type { Collection, HassEntity } from "home-assistant-js-websocket";
import { getCollection } from "home-assistant-js-websocket";
import memoizeOne from "memoize-one";
import {
@@ -1361,3 +1361,37 @@ export const calculateSolarConsumedGauge = (
}
return undefined;
};
/**
* Get current power value from entity state, normalized to kW
* @param stateObj - The entity state object to get power value from
* @returns Power value in kW, or 0 if entity not found or invalid
*/
export const getPowerFromState = (stateObj: HassEntity): number | undefined => {
if (!stateObj) {
return undefined;
}
const value = parseFloat(stateObj.state);
if (isNaN(value)) {
return undefined;
}
// Normalize to kW based on unit of measurement (case-sensitive)
// Supported units: GW, kW, MW, mW, TW, W
const unit = stateObj.attributes.unit_of_measurement;
switch (unit) {
case "W":
return value / 1000;
case "mW":
return value / 1000000;
case "MW":
return value * 1000;
case "GW":
return value * 1000000;
case "TW":
return value * 1000000000;
default:
// Assume kW if no unit or unit is kW
return value;
}
};

View File

@@ -47,8 +47,7 @@ export interface HassioFullBackupCreateParams {
confirm_password?: string;
background?: boolean;
}
export interface HassioPartialBackupCreateParams
extends HassioFullBackupCreateParams {
export interface HassioPartialBackupCreateParams extends HassioFullBackupCreateParams {
folders?: string[];
addons?: string[];
homeassistant?: boolean;

View File

@@ -18,8 +18,7 @@ export const enum LawnMowerEntityFeature {
}
interface LawnMowerEntityAttributes
extends HassEntityAttributeBase,
Record<string, any> {}
extends HassEntityAttributeBase, Record<string, any> {}
export interface LawnMowerEntity extends HassEntityBase {
attributes: LawnMowerEntityAttributes;

View File

@@ -18,8 +18,7 @@ export interface LovelaceSectionConfig extends LovelaceBaseSectionConfig {
cards?: LovelaceCardConfig[];
}
export interface LovelaceStrategySectionConfig
extends LovelaceBaseSectionConfig {
export interface LovelaceStrategySectionConfig extends LovelaceBaseSectionConfig {
strategy: LovelaceStrategyConfig;
}

View File

@@ -11,8 +11,7 @@ export interface LovelaceConfig extends LovelaceDashboardBaseConfig {
views: LovelaceViewRawConfig[];
}
export interface LovelaceDashboardStrategyConfig
extends LovelaceDashboardBaseConfig {
export interface LovelaceDashboardStrategyConfig extends LovelaceDashboardBaseConfig {
strategy: LovelaceStrategyConfig;
}

View File

@@ -29,8 +29,7 @@ export interface LovelaceDashboardMutableParams {
title: string;
}
export interface LovelaceDashboardCreateParams
extends LovelaceDashboardMutableParams {
export interface LovelaceDashboardCreateParams extends LovelaceDashboardMutableParams {
url_path: string;
mode: "storage";
}

View File

@@ -106,8 +106,7 @@ export interface AutomationTrace extends BaseTrace {
}
export interface AutomationTraceExtended
extends AutomationTrace,
BaseTraceExtended {
extends AutomationTrace, BaseTraceExtended {
config: ManualAutomationConfig;
blueprint_inputs?: BlueprintAutomationConfig;
}

View File

@@ -82,6 +82,12 @@ export interface WeatherEntity extends HassEntityBase {
attributes: WeatherEntityAttributes;
}
export const WEATHER_TEMPERATURE_ATTRIBUTES = new Set<string>([
"temperature",
"apparent_temperature",
"dew_point",
]);
export const weatherSVGs = new Set<string>([
"clear-night",
"cloudy",
@@ -256,9 +262,15 @@ export const getWeatherUnit = (
export const getSecondaryWeatherAttribute = (
hass: HomeAssistant,
stateObj: WeatherEntity,
forecast: ForecastAttribute[]
forecast: ForecastAttribute[],
temperatureFractionDigits?: number
): TemplateResult | undefined => {
const extrema = getWeatherExtrema(hass, stateObj, forecast);
const extrema = getWeatherExtrema(
hass,
stateObj,
forecast,
temperatureFractionDigits
);
if (extrema) {
return extrema;
@@ -298,7 +310,8 @@ export const getSecondaryWeatherAttribute = (
const getWeatherExtrema = (
hass: HomeAssistant,
stateObj: WeatherEntity,
forecast: ForecastAttribute[]
forecast: ForecastAttribute[],
temperatureFractionDigits?: number
): TemplateResult | undefined => {
if (!forecast?.length) {
return undefined;
@@ -313,13 +326,22 @@ const getWeatherExtrema = (
break;
}
if (!tempHigh || fc.temperature > tempHigh) {
tempHigh = fc.temperature;
tempHigh =
temperatureFractionDigits === undefined
? fc.temperature
: round(fc.temperature, temperatureFractionDigits);
}
if (!tempLow || (fc.templow && fc.templow < tempLow)) {
tempLow = fc.templow;
if (fc.templow !== undefined && (!tempLow || fc.templow < tempLow)) {
tempLow =
temperatureFractionDigits === undefined
? fc.templow
: round(fc.templow, temperatureFractionDigits);
}
if (!fc.templow && (!tempLow || fc.temperature < tempLow)) {
tempLow = fc.temperature;
tempLow =
temperatureFractionDigits === undefined
? fc.temperature
: round(fc.temperature, temperatureFractionDigits);
}
}

View File

@@ -32,8 +32,7 @@ export interface PromptDialogParams extends BaseDialogBoxParams {
}
export interface DialogBoxParams
extends ConfirmationDialogParams,
PromptDialogParams {
extends ConfirmationDialogParams, PromptDialogParams {
confirm?: (out?: string) => void;
confirmation?: boolean;
prompt?: boolean;

View File

@@ -19,8 +19,9 @@ declare global {
}
}
export interface HassDialog<T = HASSDomEvents[ValidHassDomEvent]>
extends HTMLElement {
export interface HassDialog<
T = HASSDomEvents[ValidHassDomEvent],
> extends HTMLElement {
showDialog(params: T);
closeDialog?: (historyState?: any) => boolean;
}

View File

@@ -1,5 +1,5 @@
import { css, html, LitElement, nothing } from "lit";
import { property, state } from "lit/decorators";
import { customElement, property, state } from "lit/decorators";
import { slugify } from "../../../common/string/slugify";
import "../../../components/buttons/ha-progress-button";
import "../../../components/ha-camera-stream";
@@ -9,6 +9,7 @@ import type { HomeAssistant } from "../../../types";
import { fileDownload } from "../../../util/file_download";
import { showToast } from "../../../util/toast";
@customElement("more-info-camera")
class MoreInfoCamera extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -112,8 +113,6 @@ class MoreInfoCamera extends LitElement {
`;
}
customElements.define("more-info-camera", MoreInfoCamera);
declare global {
interface HTMLElementTagNameMap {
"more-info-camera": MoreInfoCamera;

View File

@@ -7,7 +7,7 @@ import {
} from "@mdi/js";
import type { CSSResultGroup, PropertyValues } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { property, state } from "lit/decorators";
import { customElement, property, state } from "lit/decorators";
import { stopPropagation } from "../../../common/dom/stop_propagation";
import { supportsFeature } from "../../../common/entity/supports-feature";
import "../../../components/ha-attribute-icon";
@@ -32,6 +32,7 @@ import { moreInfoControlStyle } from "../components/more-info-control-style";
type MainControl = "temperature" | "humidity";
@customElement("more-info-climate")
class MoreInfoClimate extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -567,8 +568,6 @@ class MoreInfoClimate extends LitElement {
}
}
customElements.define("more-info-climate", MoreInfoClimate);
declare global {
interface HTMLElementTagNameMap {
"more-info-climate": MoreInfoClimate;

View File

@@ -1,7 +1,7 @@
import type { HassEntity } from "home-assistant-js-websocket";
import type { CSSResultGroup, PropertyValues } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { property, state } from "lit/decorators";
import { customElement, property, state } from "lit/decorators";
import { dynamicElement } from "../../../common/dom/dynamic-element-directive";
import type { GroupEntity } from "../../../data/group";
import { computeGroupDomain } from "../../../data/group";
@@ -13,6 +13,7 @@ import {
importMoreInfoControl,
} from "../state_more_info_control";
@customElement("more-info-group")
class MoreInfoGroup extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -106,8 +107,6 @@ class MoreInfoGroup extends LitElement {
}
}
customElements.define("more-info-group", MoreInfoGroup);
declare global {
interface HTMLElementTagNameMap {
"more-info-group": MoreInfoGroup;

View File

@@ -1,7 +1,7 @@
import { mdiPower, mdiTuneVariant } from "@mdi/js";
import type { CSSResultGroup, PropertyValues } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { property, state } from "lit/decorators";
import { customElement, property, state } from "lit/decorators";
import { stopPropagation } from "../../../common/dom/stop_propagation";
import { supportsFeature } from "../../../common/entity/supports-feature";
import "../../../components/ha-control-select-menu";
@@ -15,6 +15,7 @@ import type { HomeAssistant } from "../../../types";
import "../components/ha-more-info-control-select-container";
import { moreInfoControlStyle } from "../components/more-info-control-style";
@customElement("more-info-humidifier")
class MoreInfoHumidifier extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -249,8 +250,6 @@ class MoreInfoHumidifier extends LitElement {
}
}
customElements.define("more-info-humidifier", MoreInfoHumidifier);
declare global {
interface HTMLElementTagNameMap {
"more-info-humidifier": MoreInfoHumidifier;

View File

@@ -1,9 +1,10 @@
import type { PropertyValues } from "lit";
import { css, html, LitElement } from "lit";
import { property, state } from "lit/decorators";
import { customElement, property, state } from "lit/decorators";
import "../components/ha-spinner";
import "../components/ha-button";
@customElement("ha-init-page")
class HaInitPage extends LitElement {
@property({ type: Boolean }) public error = false;
@@ -120,8 +121,6 @@ class HaInitPage extends LitElement {
`;
}
customElements.define("ha-init-page", HaInitPage);
declare global {
interface HTMLElementTagNameMap {
"ha-init-page": HaInitPage;

View File

@@ -128,6 +128,8 @@ class HassSubpage extends LitElement {
ha-menu-button,
ha-icon-button-arrow-prev,
::slotted([slot="toolbar-icon"]) {
display: flex;
align-items: center;
pointer-events: auto;
color: var(--sidebar-icon-color);
}

View File

@@ -621,9 +621,9 @@ export class HaTabsSubpageDataTable extends KeyboardShortcutMixin(LitElement) {
} else if (this._sortDirection === "asc") {
this._sortDirection = "desc";
} else {
this._sortDirection = null;
this._sortDirection = "asc";
}
this._sortColumn = this._sortDirection === null ? undefined : columnId;
this._sortColumn = columnId;
fireEvent(this, "sorting-changed", {
column: columnId,

View File

@@ -1,6 +1,6 @@
import { mdiClose } from "@mdi/js";
import { html, LitElement, nothing } from "lit";
import { property, query, state } from "lit/decorators";
import { customElement, property, query, state } from "lit/decorators";
import type { LocalizeKeys } from "../common/translations/localize";
import "../components/ha-button";
import "../components/ha-icon-button";
@@ -26,6 +26,7 @@ export interface ToastActionParams {
| { translationKey: LocalizeKeys; args?: Record<string, string> };
}
@customElement("notification-manager")
class NotificationManager extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -115,8 +116,6 @@ class NotificationManager extends LitElement {
}
}
customElements.define("notification-manager", NotificationManager);
declare global {
interface HTMLElementTagNameMap {
"notification-manager": NotificationManager;

View File

@@ -90,9 +90,7 @@ class OnboardingRestoreBackupCloudLogin extends LitElement {
this._email = this._cloudLoginElement.emailField.value;
}
await import(
"../../panels/config/cloud/forgot-password/cloud-forgot-password-card"
);
await import("../../panels/config/cloud/forgot-password/cloud-forgot-password-card");
this._view = "forgot-password";
}

View File

@@ -3,7 +3,7 @@ import { TZDate } from "@date-fns/tz";
import { addDays, isSameDay } from "date-fns";
import type { CSSResultGroup } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { property, state } from "lit/decorators";
import { customElement, property, state } from "lit/decorators";
import { formatDate } from "../../common/datetime/format_date";
import { formatDateTime } from "../../common/datetime/format_date_time";
import { formatTime } from "../../common/datetime/format_time";
@@ -26,6 +26,7 @@ import type { CalendarEventDetailDialogParams } from "./show-dialog-calendar-eve
import { showCalendarEventEditDialog } from "./show-dialog-calendar-event-editor";
import { resolveTimeZone } from "../../common/datetime/resolve-time-zone";
@customElement("dialog-calendar-event-detail")
class DialogCalendarEventDetail extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -271,8 +272,3 @@ declare global {
"dialog-calendar-event-detail": DialogCalendarEventDetail;
}
}
customElements.define(
"dialog-calendar-event-detail",
DialogCalendarEventDetail
);

View File

@@ -1,7 +1,7 @@
import type { HassEntity } from "home-assistant-js-websocket";
import type { CSSResultGroup } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { property, state } from "lit/decorators";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../../common/dom/fire_event";
import "../../../components/entity/ha-entity-picker";
import type { HaEntityPicker } from "../../../components/entity/ha-entity-picker";
@@ -40,6 +40,7 @@ const SENSOR_DOMAINS = ["sensor"];
const TEMPERATURE_DEVICE_CLASSES = [SENSOR_DEVICE_CLASS_TEMPERATURE];
const HUMIDITY_DEVICE_CLASSES = [SENSOR_DEVICE_CLASS_HUMIDITY];
@customElement("dialog-area-registry-detail")
class DialogAreaDetail extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -426,5 +427,3 @@ declare global {
"dialog-area-registry-detail": DialogAreaDetail;
}
}
customElements.define("dialog-area-registry-detail", DialogAreaDetail);

View File

@@ -81,8 +81,11 @@ class DialogAreasFloorsOrder extends LitElement {
return nothing;
}
const hasFloors = this._hierarchy.floors.length > 0;
const dialogTitle = this.hass.localize(
"ui.panel.config.areas.dialog.reorder_title"
hasFloors
? "ui.panel.config.areas.dialog.reorder_floors_areas_title"
: "ui.panel.config.areas.dialog.reorder_areas_title"
);
return html`
@@ -418,7 +421,6 @@ class DialogAreasFloorsOrder extends LitElement {
}
.floor.unassigned {
border-style: dashed;
margin-top: 16px;
}

View File

@@ -1,7 +1,7 @@
import { mdiTextureBox } from "@mdi/js";
import type { CSSResultGroup } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { property, state } from "lit/decorators";
import { customElement, property, state } from "lit/decorators";
import { repeat } from "lit/directives/repeat";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../../common/dom/fire_event";
@@ -27,6 +27,7 @@ import type { HomeAssistant } from "../../../types";
import { showAreaRegistryDetailDialog } from "./show-dialog-area-registry-detail";
import type { FloorRegistryDetailDialogParams } from "./show-dialog-floor-registry-detail";
@customElement("dialog-floor-registry-detail")
class DialogFloorDetail extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -361,5 +362,3 @@ declare global {
"dialog-floor-registry-detail": DialogFloorDetail;
}
}
customElements.define("dialog-floor-registry-detail", DialogFloorDetail);

View File

@@ -175,21 +175,12 @@ export class HaConfigAreasDashboard extends LitElement {
.route=${this.route}
has-fab
>
<ha-button-menu slot="toolbar-icon">
<ha-icon-button
slot="trigger"
.label=${this.hass.localize("ui.common.menu")}
.path=${mdiDotsVertical}
></ha-icon-button>
<ha-list-item graphic="icon" @click=${this._showReorderDialog}>
<ha-svg-icon .path=${mdiSort} slot="graphic"></ha-svg-icon>
${this.hass.localize("ui.panel.config.areas.picker.reorder")}
</ha-list-item>
<ha-list-item graphic="icon" @click=${this._showHelp}>
<ha-svg-icon .path=${mdiHelpCircle} slot="graphic"></ha-svg-icon>
${this.hass.localize("ui.common.help")}
</ha-list-item>
</ha-button-menu>
<ha-icon-button
slot="toolbar-icon"
.label=${this.hass.localize("ui.common.help")}
.path=${mdiHelpCircle}
@click=${this._showHelp}
></ha-icon-button>
<div class="container">
<div class="floors">
${this._hierarchy.floors.map(({ areas, id }) => {
@@ -213,6 +204,16 @@ export class HaConfigAreasDashboard extends LitElement {
slot="trigger"
.path=${mdiDotsVertical}
></ha-icon-button>
<ha-list-item graphic="icon"
><ha-svg-icon
.path=${mdiSort}
slot="graphic"
></ha-svg-icon
>${this.hass.localize(
"ui.panel.config.areas.picker.reorder"
)}</ha-list-item
>
<li divider role="separator"></li>
<ha-list-item graphic="icon"
><ha-svg-icon
.path=${mdiPencil}
@@ -266,9 +267,30 @@ export class HaConfigAreasDashboard extends LitElement {
<div class="header">
<h2>
${this.hass.localize(
"ui.panel.config.areas.picker.other_areas"
this._hierarchy.floors.length
? "ui.panel.config.areas.picker.other_areas"
: "ui.panel.config.areas.picker.header"
)}
</h2>
<div class="actions">
<ha-button-menu
@action=${this._handleUnassignedAreasAction}
>
<ha-icon-button
slot="trigger"
.path=${mdiDotsVertical}
></ha-icon-button>
<ha-list-item graphic="icon"
><ha-svg-icon
.path=${mdiSort}
slot="graphic"
></ha-svg-icon
>${this.hass.localize(
"ui.panel.config.areas.picker.reorder"
)}</ha-list-item
>
</ha-button-menu>
</div>
</div>
<ha-sortable
handle-selector="a"
@@ -515,14 +537,23 @@ export class HaConfigAreasDashboard extends LitElement {
const floor = (ev.currentTarget as any).floor;
switch (ev.detail.index) {
case 0:
this._editFloor(floor);
this._showReorderDialog();
break;
case 1:
this._editFloor(floor);
break;
case 2:
this._deleteFloor(floor);
break;
}
}
private _handleUnassignedAreasAction(ev: CustomEvent<ActionDetail>) {
if (ev.detail.index === 0) {
this._showReorderDialog();
}
}
private _createFloor() {
this._openFloorDialog();
}

View File

@@ -1,3 +1,4 @@
import "@home-assistant/webawesome/dist/components/divider/divider";
import { consume } from "@lit/context";
import {
mdiAlertCircleCheck,
@@ -32,11 +33,11 @@ import { copyToClipboard } from "../../../../common/util/copy-clipboard";
import "../../../../components/ha-automation-row";
import type { HaAutomationRow } from "../../../../components/ha-automation-row";
import "../../../../components/ha-card";
import "../../../../components/ha-dropdown";
import "../../../../components/ha-dropdown-item";
import type { HaDropdownItem } from "../../../../components/ha-dropdown-item";
import "../../../../components/ha-expansion-panel";
import "../../../../components/ha-icon-button";
import "../../../../components/ha-md-button-menu";
import "../../../../components/ha-md-divider";
import "../../../../components/ha-md-menu-item";
import "../../../../components/ha-service-icon";
import "../../../../components/ha-tooltip";
import {
@@ -288,15 +289,12 @@ export default class HaAutomationActionRow extends LitElement {
</ha-tooltip>`
: nothing}
<ha-md-button-menu
quick
<ha-dropdown
slot="icons"
@click=${preventDefaultStopPropagation}
@keydown=${stopPropagation}
@closed=${stopPropagation}
positioning="fixed"
anchor-corner="end-end"
menu-corner="start-end"
@wa-select=${this._handleDropdownSelect}
placement="bottom-end"
>
<ha-icon-button
slot="trigger"
@@ -304,30 +302,24 @@ export default class HaAutomationActionRow extends LitElement {
.path=${mdiDotsVertical}
></ha-icon-button>
<ha-md-menu-item .clickAction=${this._runAction}>
<ha-svg-icon slot="start" .path=${mdiPlay}></ha-svg-icon>
<ha-dropdown-item value="run">
<ha-svg-icon slot="icon" .path=${mdiPlay}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize("ui.panel.config.automation.editor.actions.run")
)}
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._renameAction}
.disabled=${this.disabled}
>
<ha-svg-icon slot="start" .path=${mdiRenameBox}></ha-svg-icon>
</ha-dropdown-item>
<ha-dropdown-item value="rename" .disabled=${this.disabled}>
<ha-svg-icon slot="icon" .path=${mdiRenameBox}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.triggers.rename"
)
)}
</ha-md-menu-item>
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
<ha-md-menu-item
.clickAction=${this._duplicateAction}
.disabled=${this.disabled}
>
</ha-dropdown-item>
<wa-divider></wa-divider>
<ha-dropdown-item value="duplicate" .disabled=${this.disabled}>
<ha-svg-icon
slot="start"
slot="icon"
.path=${mdiPlusCircleMultipleOutline}
></ha-svg-icon>
@@ -336,13 +328,10 @@ export default class HaAutomationActionRow extends LitElement {
"ui.panel.config.automation.editor.actions.duplicate"
)
)}
</ha-md-menu-item>
</ha-dropdown-item>
<ha-md-menu-item
.clickAction=${this._copyAction}
.disabled=${this.disabled}
>
<ha-svg-icon slot="start" .path=${mdiContentCopy}></ha-svg-icon>
<ha-dropdown-item value="copy" .disabled=${this.disabled}>
<ha-svg-icon slot="icon" .path=${mdiContentCopy}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.triggers.copy"
@@ -351,7 +340,6 @@ export default class HaAutomationActionRow extends LitElement {
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
@@ -362,13 +350,10 @@ export default class HaAutomationActionRow extends LitElement {
<span>C</span>
</span>`
)}
</ha-md-menu-item>
</ha-dropdown-item>
<ha-md-menu-item
.clickAction=${this._cutAction}
.disabled=${this.disabled}
>
<ha-svg-icon slot="start" .path=${mdiContentCut}></ha-svg-icon>
<ha-dropdown-item value="cut" .disabled=${this.disabled}>
<ha-svg-icon slot="icon" .path=${mdiContentCut}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.triggers.cut"
@@ -377,7 +362,6 @@ export default class HaAutomationActionRow extends LitElement {
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
@@ -388,51 +372,48 @@ export default class HaAutomationActionRow extends LitElement {
<span>X</span>
</span>`
)}
</ha-md-menu-item>
</ha-dropdown-item>
${!this.optionsInSidebar
? html`
<ha-md-menu-item
.clickAction=${this._moveUp}
<ha-dropdown-item
value="move_up"
.disabled=${this.disabled || !!this.first}
>
${this.hass.localize(
"ui.panel.config.automation.editor.move_up"
)}
<ha-svg-icon slot="start" .path=${mdiArrowUp}></ha-svg-icon
></ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._moveDown}
<ha-svg-icon slot="icon" .path=${mdiArrowUp}></ha-svg-icon
></ha-dropdown-item>
<ha-dropdown-item
value="move_down"
.disabled=${this.disabled || !!this.last}
>
${this.hass.localize(
"ui.panel.config.automation.editor.move_down"
)}
<ha-svg-icon slot="start" .path=${mdiArrowDown}></ha-svg-icon
></ha-md-menu-item>
<ha-svg-icon slot="icon" .path=${mdiArrowDown}></ha-svg-icon
></ha-dropdown-item>
`
: nothing}
<ha-md-menu-item
.clickAction=${this._toggleYamlMode}
<ha-dropdown-item
value="toggle_yaml_mode"
.disabled=${!this._uiModeAvailable || !!this._warnings}
>
<ha-svg-icon slot="start" .path=${mdiPlaylistEdit}></ha-svg-icon>
<ha-svg-icon slot="icon" .path=${mdiPlaylistEdit}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
`ui.panel.config.automation.editor.edit_${!this._yamlMode ? "yaml" : "ui"}`
)
)}
</ha-md-menu-item>
</ha-dropdown-item>
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
<wa-divider></wa-divider>
<ha-md-menu-item
.clickAction=${this._onDisable}
.disabled=${this.disabled}
>
<ha-dropdown-item value="disable" .disabled=${this.disabled}>
<ha-svg-icon
slot="start"
slot="icon"
.path=${this.action.enabled === false
? mdiPlayCircleOutline
: mdiStopCircleOutline}
@@ -443,15 +424,15 @@ export default class HaAutomationActionRow extends LitElement {
`ui.panel.config.automation.editor.actions.${this.action.enabled === false ? "enable" : "disable"}`
)
)}
</ha-md-menu-item>
<ha-md-menu-item
class="warning"
.clickAction=${this._onDelete}
</ha-dropdown-item>
<ha-dropdown-item
value="delete"
variant="danger"
.disabled=${this.disabled}
>
<ha-svg-icon
class="warning"
slot="start"
slot="icon"
.path=${mdiDelete}
></ha-svg-icon>
@@ -463,7 +444,6 @@ export default class HaAutomationActionRow extends LitElement {
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
@@ -478,8 +458,8 @@ export default class HaAutomationActionRow extends LitElement {
>
</span>`
)}
</ha-md-menu-item>
</ha-md-button-menu>
</ha-dropdown-item>
</ha-dropdown>
${!this.optionsInSidebar
? html`${this._warnings
@@ -890,6 +870,47 @@ export default class HaAutomationActionRow extends LitElement {
this._automationRowElement?.focus();
}
private _handleDropdownSelect(ev: CustomEvent<{ item: HaDropdownItem }>) {
const action = ev.detail?.item?.value;
if (!action) {
return;
}
switch (action) {
case "run":
this._runAction();
break;
case "rename":
this._renameAction();
break;
case "duplicate":
this._duplicateAction();
break;
case "copy":
this._copyAction();
break;
case "cut":
this._cutAction();
break;
case "move_up":
this._moveUp();
break;
case "move_down":
this._moveDown();
break;
case "toggle_yaml_mode":
this._toggleYamlMode(ev.target as HTMLElement);
break;
case "disable":
this._onDisable();
break;
case "delete":
this._onDelete();
break;
}
}
static styles = [rowStyles, overflowStyles];
}

View File

@@ -1,3 +1,4 @@
import "@home-assistant/webawesome/dist/components/divider/divider";
import { consume } from "@lit/context";
import {
mdiAppleKeyboardCommand,
@@ -33,11 +34,11 @@ import "../../../../components/ha-automation-row";
import type { HaAutomationRow } from "../../../../components/ha-automation-row";
import "../../../../components/ha-card";
import "../../../../components/ha-condition-icon";
import "../../../../components/ha-dropdown";
import "../../../../components/ha-dropdown-item";
import type { HaDropdownItem } from "../../../../components/ha-dropdown-item";
import "../../../../components/ha-expansion-panel";
import "../../../../components/ha-icon-button";
import "../../../../components/ha-md-button-menu";
import "../../../../components/ha-md-divider";
import "../../../../components/ha-md-menu-item";
import type {
AutomationClipboard,
Condition,
@@ -194,15 +195,12 @@ export default class HaAutomationConditionRow extends LitElement {
<slot name="icons" slot="icons"></slot>
<ha-md-button-menu
quick
<ha-dropdown
slot="icons"
@click=${preventDefaultStopPropagation}
@keydown=${stopPropagation}
@closed=${stopPropagation}
positioning="fixed"
anchor-corner="end-end"
menu-corner="start-end"
@wa-select=${this._handleDropdownSelect}
placement="bottom-end"
>
<ha-icon-button
slot="trigger"
@@ -211,34 +209,28 @@ export default class HaAutomationConditionRow extends LitElement {
>
</ha-icon-button>
<ha-md-menu-item .clickAction=${this._testCondition}>
<ha-svg-icon slot="start" .path=${mdiFlask}></ha-svg-icon>
<ha-dropdown-item value="test">
<ha-svg-icon slot="icon" .path=${mdiFlask}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.conditions.test"
)
)}
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._renameCondition}
.disabled=${this.disabled}
>
<ha-svg-icon slot="start" .path=${mdiRenameBox}></ha-svg-icon>
</ha-dropdown-item>
<ha-dropdown-item value="rename" .disabled=${this.disabled}>
<ha-svg-icon slot="icon" .path=${mdiRenameBox}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.conditions.rename"
)
)}
</ha-md-menu-item>
</ha-dropdown-item>
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
<wa-divider></wa-divider>
<ha-md-menu-item
.clickAction=${this._duplicateCondition}
.disabled=${this.disabled}
>
<ha-dropdown-item value="duplicate" .disabled=${this.disabled}>
<ha-svg-icon
slot="start"
slot="icon"
.path=${mdiPlusCircleMultipleOutline}
></ha-svg-icon>
${this._renderOverflowLabel(
@@ -246,13 +238,10 @@ export default class HaAutomationConditionRow extends LitElement {
"ui.panel.config.automation.editor.actions.duplicate"
)
)}
</ha-md-menu-item>
</ha-dropdown-item>
<ha-md-menu-item
.clickAction=${this._copyCondition}
.disabled=${this.disabled}
>
<ha-svg-icon slot="start" .path=${mdiContentCopy}></ha-svg-icon
<ha-dropdown-item value="copy" .disabled=${this.disabled}>
<ha-svg-icon slot="icon" .path=${mdiContentCopy}></ha-svg-icon
>${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.triggers.copy"
@@ -261,7 +250,6 @@ export default class HaAutomationConditionRow extends LitElement {
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
@@ -272,13 +260,10 @@ export default class HaAutomationConditionRow extends LitElement {
<span>C</span>
</span>`
)}
</ha-md-menu-item>
</ha-dropdown-item>
<ha-md-menu-item
.clickAction=${this._cutCondition}
.disabled=${this.disabled}
>
<ha-svg-icon slot="start" .path=${mdiContentCut}></ha-svg-icon
<ha-dropdown-item value="cut" .disabled=${this.disabled}>
<ha-svg-icon slot="icon" .path=${mdiContentCut}></ha-svg-icon
>${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.triggers.cut"
@@ -287,7 +272,6 @@ export default class HaAutomationConditionRow extends LitElement {
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
@@ -298,48 +282,45 @@ export default class HaAutomationConditionRow extends LitElement {
<span>X</span>
</span>`
)}
</ha-md-menu-item>
</ha-dropdown-item>
${!this.optionsInSidebar
? html`
<ha-md-menu-item
.clickAction=${this._moveUp}
.disabled=${this.disabled || this.first}
<ha-dropdown-item
value="move_up"
.disabled=${this.disabled || !!this.first}
>
${this.hass.localize(
"ui.panel.config.automation.editor.move_up"
)}
<ha-svg-icon slot="start" .path=${mdiArrowUp}></ha-svg-icon
></ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._moveDown}
.disabled=${this.disabled || this.last}
<ha-svg-icon slot="icon" .path=${mdiArrowUp}></ha-svg-icon
></ha-dropdown-item>
<ha-dropdown-item
value="move_down"
.disabled=${this.disabled || !!this.last}
>
${this.hass.localize(
"ui.panel.config.automation.editor.move_down"
)}
<ha-svg-icon slot="start" .path=${mdiArrowDown}></ha-svg-icon
></ha-md-menu-item>
<ha-svg-icon slot="icon" .path=${mdiArrowDown}></ha-svg-icon
></ha-dropdown-item>
`
: nothing}
<ha-md-menu-item .clickAction=${this._toggleYamlMode}>
<ha-svg-icon slot="start" .path=${mdiPlaylistEdit}></ha-svg-icon>
<ha-dropdown-item value="toggle_yaml_mode">
<ha-svg-icon slot="icon" .path=${mdiPlaylistEdit}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
`ui.panel.config.automation.editor.edit_${!this._yamlMode ? "yaml" : "ui"}`
)
)}
</ha-md-menu-item>
</ha-dropdown-item>
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
<wa-divider></wa-divider>
<ha-md-menu-item
.clickAction=${this._onDisable}
.disabled=${this.disabled}
>
<ha-dropdown-item value="disable" .disabled=${this.disabled}>
<ha-svg-icon
slot="start"
slot="icon"
.path=${this.condition.enabled === false
? mdiPlayCircleOutline
: mdiStopCircleOutline}
@@ -350,15 +331,15 @@ export default class HaAutomationConditionRow extends LitElement {
`ui.panel.config.automation.editor.actions.${this.condition.enabled === false ? "enable" : "disable"}`
)
)}
</ha-md-menu-item>
<ha-md-menu-item
class="warning"
.clickAction=${this._onDelete}
</ha-dropdown-item>
<ha-dropdown-item
variant="danger"
value="delete"
.disabled=${this.disabled}
>
<ha-svg-icon
class="warning"
slot="start"
slot="icon"
.path=${mdiDelete}
></ha-svg-icon>
${this._renderOverflowLabel(
@@ -369,7 +350,6 @@ export default class HaAutomationConditionRow extends LitElement {
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
@@ -384,8 +364,8 @@ export default class HaAutomationConditionRow extends LitElement {
>
</span>`
)}
</ha-md-menu-item>
</ha-md-button-menu>
</ha-dropdown-item>
</ha-dropdown>
${!this.optionsInSidebar
? html`${this._warnings
? html`<ha-automation-editor-warning
@@ -837,6 +817,47 @@ export default class HaAutomationConditionRow extends LitElement {
this._automationRowElement?.focus();
}
private _handleDropdownSelect(ev: CustomEvent<{ item: HaDropdownItem }>) {
const action = ev.detail?.item?.value;
if (!action) {
return;
}
switch (action) {
case "test":
this._testCondition();
break;
case "rename":
this._renameCondition();
break;
case "duplicate":
this._duplicateCondition();
break;
case "copy":
this._copyCondition();
break;
case "cut":
this._cutCondition();
break;
case "move_up":
this._moveUp();
break;
case "move_down":
this._moveDown();
break;
case "toggle_yaml_mode":
this._toggleYamlMode(ev.target as HTMLElement);
break;
case "disable":
this._onDisable();
break;
case "delete":
this._onDelete();
break;
}
}
static get styles(): CSSResultGroup {
return [
rowStyles,

View File

@@ -124,9 +124,9 @@ export class HaPlatformCondition extends LitElement {
const hasOptional = Boolean(
conditionDesc?.fields &&
Object.values(conditionDesc.fields).some((field) =>
showOptionalToggle(field)
)
Object.values(conditionDesc.fields).some((field) =>
showOptionalToggle(field)
)
);
return html`

View File

@@ -1,3 +1,4 @@
import "@home-assistant/webawesome/dist/components/divider/divider";
import { consume } from "@lit/context";
import {
mdiAppleKeyboardCommand,
@@ -23,20 +24,22 @@ import {
import type { UnsubscribeFunc } from "home-assistant-js-websocket";
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { property, query, state } from "lit/decorators";
import { customElement, property, query, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { UndoRedoController } from "../../../common/controllers/undo-redo-controller";
import { transform } from "../../../common/decorators/transform";
import { fireEvent } from "../../../common/dom/fire_event";
import { goBack, navigate } from "../../../common/navigate";
import { promiseTimeout } from "../../../common/util/promise-timeout";
import { afterNextRender } from "../../../common/util/render-status";
import "../../../components/ha-button";
import "../../../components/ha-button-menu";
import "../../../components/ha-dropdown";
import "../../../components/ha-dropdown-item";
import type { HaDropdownItem } from "../../../components/ha-dropdown-item";
import "../../../components/ha-fab";
import "../../../components/ha-fade-in";
import "../../../components/ha-icon";
import "../../../components/ha-icon-button";
import "../../../components/ha-list-item";
import "../../../components/ha-spinner";
import "../../../components/ha-svg-icon";
import "../../../components/ha-yaml-editor";
@@ -74,7 +77,6 @@ import { showMoreInfoDialog } from "../../../dialogs/more-info/show-ha-more-info
import "../../../layouts/hass-subpage";
import { KeyboardShortcutMixin } from "../../../mixins/keyboard-shortcut-mixin";
import { PreventUnsavedMixin } from "../../../mixins/prevent-unsaved-mixin";
import { UndoRedoController } from "../../../common/controllers/undo-redo-controller";
import { haStyle } from "../../../resources/styles";
import type { Entries, HomeAssistant, Route } from "../../../types";
import { isMac } from "../../../util/is_mac";
@@ -86,10 +88,10 @@ import {
type EntityRegistryUpdate,
showAutomationSaveDialog,
} from "./automation-save-dialog/show-dialog-automation-save";
import { showAutomationSaveTimeoutDialog } from "./automation-save-timeout-dialog/show-dialog-automation-save-timeout";
import "./blueprint-automation-editor";
import "./manual-automation-editor";
import type { HaManualAutomationEditor } from "./manual-automation-editor";
import { showAutomationSaveTimeoutDialog } from "./automation-save-timeout-dialog/show-dialog-automation-save-timeout";
declare global {
interface HTMLElementTagNameMap {
@@ -112,6 +114,7 @@ declare global {
}
}
@customElement("ha-automation-editor")
export class HaAutomationEditor extends PreventUnsavedMixin(
KeyboardShortcutMixin(LitElement)
) {
@@ -291,7 +294,10 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
</ha-button>
`
: ""}
<ha-button-menu slot="toolbar-icon">
<ha-dropdown
slot="toolbar-icon"
@wa-select=${this._handleDropdownSelect}
>
<ha-icon-button
slot="trigger"
.label=${this.hass.localize("ui.common.menu")}
@@ -299,99 +305,73 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
></ha-icon-button>
${this._mode === "gui" && this.narrow
? html`<ha-list-item
graphic="icon"
@click=${this._undo}
? html`<ha-dropdown-item
value="undo"
.disabled=${!this._undoRedoController.canUndo}
>
${this.hass.localize("ui.common.undo")}
<ha-svg-icon slot="graphic" .path=${mdiUndo}></ha-svg-icon>
</ha-list-item>
<ha-list-item
graphic="icon"
@click=${this._redo}
<ha-svg-icon slot="icon" .path=${mdiUndo}></ha-svg-icon>
</ha-dropdown-item>
<ha-dropdown-item
value="redo"
.disabled=${!this._undoRedoController.canRedo}
>
${this.hass.localize("ui.common.redo")}
<ha-svg-icon slot="graphic" .path=${mdiRedo}></ha-svg-icon>
</ha-list-item>`
<ha-svg-icon slot="icon" .path=${mdiRedo}></ha-svg-icon>
</ha-dropdown-item>`
: nothing}
<ha-list-item
graphic="icon"
.disabled=${!stateObj}
@click=${this._showInfo}
>
<ha-dropdown-item .disabled=${!stateObj} value="info">
${this.hass.localize("ui.panel.config.automation.editor.show_info")}
<ha-svg-icon
slot="graphic"
slot="icon"
.path=${mdiInformationOutline}
></ha-svg-icon>
</ha-list-item>
</ha-dropdown-item>
<ha-list-item
graphic="icon"
.disabled=${!stateObj}
@click=${this._showSettings}
>
<ha-dropdown-item .disabled=${!stateObj} value="settings">
${this.hass.localize(
"ui.panel.config.automation.picker.show_settings"
)}
<ha-svg-icon slot="graphic" .path=${mdiCog}></ha-svg-icon>
</ha-list-item>
<ha-svg-icon slot="icon" .path=${mdiCog}></ha-svg-icon>
</ha-dropdown-item>
<ha-list-item
graphic="icon"
.disabled=${!stateObj}
@click=${this._editCategory}
>
<ha-dropdown-item .disabled=${!stateObj} value="category">
${this.hass.localize(
`ui.panel.config.scene.picker.${this._registryEntry?.categories?.automation ? "edit_category" : "assign_category"}`
)}
<ha-svg-icon slot="graphic" .path=${mdiTag}></ha-svg-icon>
</ha-list-item>
<ha-svg-icon slot="icon" .path=${mdiTag}></ha-svg-icon>
</ha-dropdown-item>
<ha-list-item
graphic="icon"
.disabled=${!stateObj}
@click=${this._runActions}
>
<ha-dropdown-item .disabled=${!stateObj} value="run">
${this.hass.localize("ui.panel.config.automation.editor.run")}
<ha-svg-icon slot="graphic" .path=${mdiPlay}></ha-svg-icon>
</ha-list-item>
<ha-svg-icon slot="icon" .path=${mdiPlay}></ha-svg-icon>
</ha-dropdown-item>
${stateObj && this.narrow
? html`<a
href="/config/automation/trace/${encodeURIComponent(
this._config.id!
)}"
>
<ha-list-item graphic="icon">
${this.hass.localize(
"ui.panel.config.automation.editor.show_trace"
)}
<ha-svg-icon
slot="graphic"
.path=${mdiTransitConnection}
></ha-svg-icon>
</ha-list-item>
</a>`
? html`<ha-dropdown-item value="trace">
${this.hass.localize(
"ui.panel.config.automation.editor.show_trace"
)}
<ha-svg-icon
slot="icon"
.path=${mdiTransitConnection}
></ha-svg-icon>
</ha-dropdown-item>`
: nothing}
<ha-list-item
graphic="icon"
@click=${this._promptAutomationAlias}
<ha-dropdown-item
value="rename"
.disabled=${this._readOnly ||
!this.automationId ||
this._mode === "yaml"}
>
${this.hass.localize("ui.panel.config.automation.editor.rename")}
<ha-svg-icon slot="graphic" .path=${mdiRenameBox}></ha-svg-icon>
</ha-list-item>
<ha-svg-icon slot="icon" .path=${mdiRenameBox}></ha-svg-icon>
</ha-dropdown-item>
${!useBlueprint
? html`
<ha-list-item
graphic="icon"
<ha-dropdown-item
@click=${this._promptAutomationMode}
.disabled=${this._readOnly || this._mode === "yaml"}
>
@@ -399,18 +379,17 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
"ui.panel.config.automation.editor.change_mode"
)}
<ha-svg-icon
slot="graphic"
slot="icon"
.path=${mdiDebugStepOver}
></ha-svg-icon>
</ha-list-item>
</ha-dropdown-item>
`
: nothing}
<ha-list-item
.disabled=${this._blueprintConfig ||
<ha-dropdown-item
.disabled=${!!this._blueprintConfig ||
(!this._readOnly && !this.automationId)}
graphic="icon"
@click=${this._duplicate}
value="duplicate"
>
${this.hass.localize(
this._readOnly
@@ -418,74 +397,60 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
: "ui.panel.config.automation.editor.duplicate"
)}
<ha-svg-icon
slot="graphic"
slot="icon"
.path=${mdiPlusCircleMultipleOutline}
></ha-svg-icon>
</ha-list-item>
</ha-dropdown-item>
${useBlueprint
? html`
<ha-list-item
graphic="icon"
@click=${this._takeControl}
<ha-dropdown-item
value="take_control"
.disabled=${this._readOnly}
>
${this.hass.localize(
"ui.panel.config.automation.editor.take_control"
)}
<ha-svg-icon
slot="graphic"
.path=${mdiFileEdit}
></ha-svg-icon>
</ha-list-item>
<ha-svg-icon slot="icon" .path=${mdiFileEdit}></ha-svg-icon>
</ha-dropdown-item>
`
: nothing}
<ha-list-item
graphic="icon"
@click=${this._mode === "gui"
? this._switchYamlMode
: this._switchUiMode}
>
<ha-dropdown-item value="toggle_yaml_mode">
${this.hass.localize(
`ui.panel.config.automation.editor.edit_${this._mode === "gui" ? "yaml" : "ui"}`
)}
<ha-svg-icon slot="graphic" .path=${mdiPlaylistEdit}></ha-svg-icon>
</ha-list-item>
<ha-svg-icon slot="icon" .path=${mdiPlaylistEdit}></ha-svg-icon>
</ha-dropdown-item>
<li divider role="separator"></li>
<wa-divider></wa-divider>
<ha-list-item
graphic="icon"
.disabled=${!stateObj}
@click=${this._toggle}
>
<ha-dropdown-item .disabled=${!stateObj} value="disable">
${stateObj?.state === "off"
? this.hass.localize("ui.panel.config.automation.editor.enable")
: this.hass.localize("ui.panel.config.automation.editor.disable")}
<ha-svg-icon
slot="graphic"
slot="icon"
.path=${stateObj?.state === "off"
? mdiPlayCircleOutline
: mdiStopCircleOutline}
></ha-svg-icon>
</ha-list-item>
</ha-dropdown-item>
<ha-list-item
<ha-dropdown-item
.disabled=${!this.automationId}
class=${classMap({ warning: Boolean(this.automationId) })}
graphic="icon"
@click=${this._deleteConfirm}
.variant=${this.automationId ? "danger" : "default"}
value="delete"
>
${this.hass.localize("ui.panel.config.automation.picker.delete")}
<ha-svg-icon
class=${classMap({ warning: Boolean(this.automationId) })}
slot="graphic"
slot="icon"
.path=${mdiDelete}
>
</ha-svg-icon>
</ha-list-item>
</ha-button-menu>
</ha-dropdown-item>
</ha-dropdown>
<div
class=${this._mode === "yaml" ? "yaml-mode" : ""}
@subscribe-automation-config=${this._subscribeAutomationConfig}
@@ -1248,6 +1213,63 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
this._undoRedoController.redo();
}
private _handleDropdownSelect(ev: CustomEvent<{ item: HaDropdownItem }>) {
const action = ev.detail?.item?.value;
if (!action) {
return;
}
switch (action) {
case "undo":
this._undo();
break;
case "redo":
this._redo();
break;
case "info":
this._showInfo();
break;
case "settings":
this._showSettings();
break;
case "category":
this._editCategory();
break;
case "run":
this._runActions();
break;
case "rename":
this._promptAutomationAlias();
break;
case "change_mode":
this._promptAutomationMode();
break;
case "duplicate":
this._duplicate();
break;
case "take_control":
this._takeControl();
break;
case "toggle_yaml_mode":
if (this._mode === "gui") {
this._switchYamlMode();
break;
}
this._switchUiMode();
break;
case "disable":
this._toggle();
break;
case "delete":
this._deleteConfirm();
break;
case "trace":
this._showTrace();
break;
}
}
static get styles(): CSSResultGroup {
return [
haStyle,
@@ -1300,13 +1322,6 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
margin-inline-end: 8px;
margin-inline-start: initial;
}
li[role="separator"] {
border-bottom-color: var(--divider-color);
}
ha-button-menu a {
text-decoration: none;
color: var(--primary-color);
}
h1 {
margin: 0;
}
@@ -1339,5 +1354,3 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
];
}
}
customElements.define("ha-automation-editor", HaAutomationEditor);

View File

@@ -35,6 +35,8 @@ import type { HASSDomEvent } from "../../../common/dom/fire_event";
import { fireEvent } from "../../../common/dom/fire_event";
import { computeStateName } from "../../../common/entity/compute_state_name";
import { navigate } from "../../../common/navigate";
import { slugify } from "../../../common/string/slugify";
import "../../../components/ha-tooltip";
import type { LocalizeFunc } from "../../../common/translations/localize";
import {
hasRejectedItems,
@@ -327,14 +329,19 @@ class HaAutomationPicker extends SubscribeMixin(LitElement) {
const date = new Date(automation.last_triggered);
const now = new Date();
const dayDifference = differenceInDays(now, date);
const formattedTime = formatShortDateTimeWithConditionalYear(
date,
this.hass.locale,
this.hass.config
);
const elementId = "last-triggered-" + slugify(automation.entity_id);
return html`
${dayDifference > 3
? formatShortDateTimeWithConditionalYear(
date,
this.hass.locale,
this.hass.config
)
: relativeTime(date, locale)}
? formattedTime
: html`
<ha-tooltip for=${elementId}>${formattedTime}</ha-tooltip>
<span id=${elementId}>${relativeTime(date, locale)}</span>
`}
`;
},
},

View File

@@ -1,3 +1,4 @@
import "@home-assistant/webawesome/dist/components/divider/divider";
import {
mdiDotsVertical,
mdiDownload,
@@ -15,11 +16,13 @@ import { repeat } from "lit/directives/repeat";
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
import { formatDateTimeWithSeconds } from "../../../common/datetime/format_date_time";
import { fireEvent } from "../../../common/dom/fire_event";
import { navigate } from "../../../common/navigate";
import { computeRTL } from "../../../common/util/compute_rtl";
import "../../../components/ha-button";
import "../../../components/ha-button-menu";
import "../../../components/ha-dropdown";
import "../../../components/ha-dropdown-item";
import type { HaDropdownItem } from "../../../components/ha-dropdown-item";
import "../../../components/ha-icon-button";
import "../../../components/ha-list-item";
import "../../../components/trace/ha-trace-blueprint-config";
import "../../../components/trace/ha-trace-config";
import "../../../components/trace/ha-trace-logbook";
@@ -104,9 +107,7 @@ export class HaAutomationTrace extends LitElement {
appearance="plain"
size="small"
class="trace-link"
href="/config/automation/edit/${encodeURIComponent(
stateObj.attributes.id
)}"
@click=${this._navigateToAutomation}
slot="toolbar-icon"
>
${this.hass.localize(
@@ -114,65 +115,50 @@ export class HaAutomationTrace extends LitElement {
)}
</ha-button>
`
: ""}
<ha-button-menu slot="toolbar-icon">
: nothing}
<ha-dropdown
slot="toolbar-icon"
@wa-select=${this._handleDropdownSelect}
>
<ha-icon-button
slot="trigger"
.label=${this.hass.localize("ui.common.menu")}
.path=${mdiDotsVertical}
></ha-icon-button>
<ha-list-item
graphic="icon"
.disabled=${!stateObj}
@click=${this._showInfo}
>
<ha-dropdown-item .disabled=${!stateObj} value="show_info">
${this.hass.localize("ui.panel.config.automation.editor.show_info")}
<ha-svg-icon
slot="graphic"
slot="icon"
.path=${mdiInformationOutline}
></ha-svg-icon>
</ha-list-item>
</ha-dropdown-item>
${stateObj?.attributes.id && this.narrow
? html`
<a
class="trace-link"
href="/config/automation/edit/${encodeURIComponent(
stateObj.attributes.id
)}"
>
<ha-list-item graphic="icon">
${this.hass.localize(
"ui.panel.config.automation.trace.edit_automation"
)}
<ha-svg-icon
slot="graphic"
.path=${mdiPencil}
></ha-svg-icon>
</ha-list-item>
</a>
<ha-dropdown-item value="edit_automation">
${this.hass.localize(
"ui.panel.config.automation.trace.edit_automation"
)}
<ha-svg-icon slot="icon" .path=${mdiPencil}></ha-svg-icon>
</ha-dropdown-item>
`
: ""}
: nothing}
<li divider role="separator"></li>
<wa-divider></wa-divider>
<ha-list-item graphic="icon" @click=${this._refreshTraces}>
<ha-dropdown-item value="refresh">
${this.hass.localize("ui.panel.config.automation.trace.refresh")}
<ha-svg-icon slot="graphic" .path=${mdiRefresh}></ha-svg-icon>
</ha-list-item>
<ha-svg-icon slot="icon" .path=${mdiRefresh}></ha-svg-icon>
</ha-dropdown-item>
<ha-list-item
graphic="icon"
.disabled=${!this._trace}
@click=${this._downloadTrace}
>
<ha-dropdown-item .disabled=${!this._trace} value="download_trace">
${this.hass.localize(
"ui.panel.config.automation.trace.download_trace"
)}
<ha-svg-icon slot="graphic" .path=${mdiDownload}></ha-svg-icon>
</ha-list-item>
</ha-button-menu>
<ha-svg-icon slot="icon" .path=${mdiDownload}></ha-svg-icon>
</ha-dropdown-item>
</ha-dropdown>
<div class="toolbar">
${this._traces && this._traces.length > 0
@@ -520,6 +506,37 @@ export class HaAutomationTrace extends LitElement {
fireEvent(this, "hass-more-info", { entityId: this._entityId });
}
private _navigateToAutomation() {
if (this._entityId && this.hass.states[this._entityId]) {
navigate(
`/config/automation/edit/${encodeURIComponent(this.hass.states[this._entityId].attributes.id)}`
);
}
}
private _handleDropdownSelect(ev: CustomEvent<{ item: HaDropdownItem }>) {
const action = ev.detail?.item?.value;
if (!action) {
return;
}
switch (action) {
case "show_info":
this._showInfo();
break;
case "refresh":
this._refreshTraces();
break;
case "download_trace":
this._downloadTrace();
break;
case "edit_automation":
this._navigateToAutomation();
break;
}
}
static get styles(): CSSResultGroup {
return [
haStyle,

View File

@@ -20,10 +20,11 @@ import { capitalizeFirstLetter } from "../../../../common/string/capitalize-firs
import "../../../../components/ha-automation-row";
import type { HaAutomationRow } from "../../../../components/ha-automation-row";
import "../../../../components/ha-card";
import "../../../../components/ha-dropdown";
import "../../../../components/ha-dropdown-item";
import type { HaDropdownItem } from "../../../../components/ha-dropdown-item";
import "../../../../components/ha-expansion-panel";
import "../../../../components/ha-icon-button";
import "../../../../components/ha-md-button-menu";
import "../../../../components/ha-md-menu-item";
import "../../../../components/ha-svg-icon";
import type {
Condition,
@@ -36,6 +37,7 @@ import type { Action, Option } from "../../../../data/script";
import { showPromptDialog } from "../../../../dialogs/generic/show-dialog-box";
import type { HomeAssistant } from "../../../../types";
import { isMac } from "../../../../util/is_mac";
import { showToast } from "../../../../util/toast";
import "../action/ha-automation-action";
import type HaAutomationAction from "../action/ha-automation-action";
import "../condition/ha-automation-condition";
@@ -46,7 +48,6 @@ import {
overflowStyles,
rowStyles,
} from "../styles";
import { showToast } from "../../../../util/toast";
@customElement("ha-automation-option-row")
export default class HaAutomationOptionRow extends LitElement {
@@ -155,15 +156,12 @@ export default class HaAutomationOptionRow extends LitElement {
${this.option
? html`
<ha-md-button-menu
quick
<ha-dropdown
slot="icons"
@click=${preventDefaultStopPropagation}
@closed=${stopPropagation}
@keydown=${stopPropagation}
positioning="fixed"
anchor-corner="end-end"
menu-corner="start-end"
@wa-select=${this._handleDropdownSelect}
placement="bottom-end"
>
<ha-icon-button
slot="trigger"
@@ -171,24 +169,18 @@ export default class HaAutomationOptionRow extends LitElement {
.path=${mdiDotsVertical}
></ha-icon-button>
<ha-md-menu-item
@click=${this._renameOption}
.disabled=${this.disabled}
>
<ha-svg-icon slot="start" .path=${mdiRenameBox}></ha-svg-icon>
<ha-dropdown-item value="rename" .disabled=${this.disabled}>
<ha-svg-icon slot="icon" .path=${mdiRenameBox}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.triggers.rename"
)
)}
</ha-md-menu-item>
</ha-dropdown-item>
<ha-md-menu-item
@click=${this._duplicateOption}
.disabled=${this.disabled}
>
<ha-dropdown-item value="duplicate" .disabled=${this.disabled}>
<ha-svg-icon
slot="start"
slot="icon"
.path=${mdiPlusCircleMultipleOutline}
></ha-svg-icon>
@@ -197,45 +189,42 @@ export default class HaAutomationOptionRow extends LitElement {
"ui.panel.config.automation.editor.actions.duplicate"
)
)}
</ha-md-menu-item>
</ha-dropdown-item>
${!this.optionsInSidebar
? html`
<ha-md-menu-item
.clickAction=${this._moveUp}
<ha-dropdown-item
value="move_up"
.disabled=${this.disabled || !!this.first}
>
${this.hass.localize(
"ui.panel.config.automation.editor.move_up"
)}
<ha-svg-icon
slot="start"
.path=${mdiArrowUp}
></ha-svg-icon
></ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._moveDown}
<ha-svg-icon slot="icon" .path=${mdiArrowUp}></ha-svg-icon
></ha-dropdown-item>
<ha-dropdown-item
value="move_down"
.disabled=${this.disabled || !!this.last}
>
${this.hass.localize(
"ui.panel.config.automation.editor.move_down"
)}
<ha-svg-icon
slot="start"
slot="icon"
.path=${mdiArrowDown}
></ha-svg-icon
></ha-md-menu-item>
></ha-dropdown-item>
`
: nothing}
<ha-md-menu-item
@click=${this._removeOption}
class="warning"
<ha-dropdown-item
value="delete"
variant="danger"
.disabled=${this.disabled}
>
<ha-svg-icon
class="warning"
slot="start"
slot="icon"
.path=${mdiDelete}
></ha-svg-icon>
${this._renderOverflowLabel(
@@ -246,7 +235,6 @@ export default class HaAutomationOptionRow extends LitElement {
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
@@ -261,8 +249,8 @@ export default class HaAutomationOptionRow extends LitElement {
>
</span>`
)}
</ha-md-menu-item>
</ha-md-button-menu>
</ha-dropdown-item>
</ha-dropdown>
`
: nothing}
${!this.optionsInSidebar ? this._renderContent() : nothing}
@@ -361,6 +349,32 @@ export default class HaAutomationOptionRow extends LitElement {
fireEvent(this, "move-down");
}
private _handleDropdownSelect(ev: CustomEvent<{ item: HaDropdownItem }>) {
const action = ev.detail?.item?.value;
if (!action) {
return;
}
switch (action) {
case "rename":
this._renameOption();
break;
case "delete":
this._removeOption();
break;
case "duplicate":
this._duplicateOption();
break;
case "move_up":
this._moveUp();
break;
case "move_down":
this._moveDown();
break;
}
}
private _removeOption = () => {
if (this.option) {
fireEvent(this, "value-changed", {
@@ -513,9 +527,6 @@ export default class HaAutomationOptionRow extends LitElement {
overflowStyles,
indentStyle,
css`
li[role="separator"] {
border-bottom-color: var(--divider-color);
}
h4 {
color: var(--ha-color-text-secondary);
}

View File

@@ -1,3 +1,4 @@
import "@home-assistant/webawesome/dist/components/divider/divider";
import {
mdiAppleKeyboardCommand,
mdiContentCopy,
@@ -16,8 +17,8 @@ import { keyed } from "lit/directives/keyed";
import { fireEvent } from "../../../../common/dom/fire_event";
import { handleStructError } from "../../../../common/structs/handle-errors";
import type { LocalizeKeys } from "../../../../common/translations/localize";
import "../../../../components/ha-md-divider";
import "../../../../components/ha-md-menu-item";
import "../../../../components/ha-dropdown-item";
import type { HaDropdownItem } from "../../../../components/ha-dropdown-item";
import { ACTION_BUILDING_BLOCKS } from "../../../../data/action";
import type { ActionSidebarConfig } from "../../../../data/automation";
import { domainToName } from "../../../../data/integration";
@@ -116,6 +117,7 @@ export default class HaAutomationSidebarAction extends LitElement {
.yamlMode=${this.yamlMode}
.warnings=${this._warnings}
.narrow=${this.narrow}
@wa-select=${this._handleDropdownSelect}
>
<span slot="title">${title}</span>
<span slot="subtitle"
@@ -126,38 +128,35 @@ export default class HaAutomationSidebarAction extends LitElement {
: ""}</span
>
<ha-md-menu-item slot="menu-items" .clickAction=${this.config.run}>
<ha-svg-icon slot="start" .path=${mdiPlay}></ha-svg-icon>
<ha-dropdown-item slot="menu-items" value="run">
<ha-svg-icon slot="icon" .path=${mdiPlay}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize("ui.panel.config.automation.editor.actions.run")}
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-md-menu-item>
<ha-md-menu-item
</ha-dropdown-item>
<ha-dropdown-item
slot="menu-items"
.clickAction=${this.config.rename}
value="rename"
.disabled=${this.disabled}
>
<ha-svg-icon slot="start" .path=${mdiRenameBox}></ha-svg-icon>
<ha-svg-icon slot="icon" .path=${mdiRenameBox}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.rename"
)}
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-md-menu-item>
<ha-md-divider
</ha-dropdown-item>
<wa-divider slot="menu-items"></wa-divider>
<ha-dropdown-item
slot="menu-items"
role="separator"
tabindex="-1"
></ha-md-divider>
<ha-md-menu-item
slot="menu-items"
.clickAction=${this.config.duplicate}
value="duplicate"
.disabled=${this.disabled}
>
<ha-svg-icon
slot="start"
slot="icon"
.path=${mdiPlusCircleMultipleOutline}
></ha-svg-icon>
<div class="overflow-label">
@@ -166,9 +165,9 @@ export default class HaAutomationSidebarAction extends LitElement {
)}
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-md-menu-item>
<ha-md-menu-item slot="menu-items" .clickAction=${this.config.copy}>
<ha-svg-icon slot="start" .path=${mdiContentCopy}></ha-svg-icon>
</ha-dropdown-item>
<ha-dropdown-item slot="menu-items" value="copy">
<ha-svg-icon slot="icon" .path=${mdiContentCopy}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.copy"
@@ -178,7 +177,6 @@ export default class HaAutomationSidebarAction extends LitElement {
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
@@ -190,13 +188,13 @@ export default class HaAutomationSidebarAction extends LitElement {
</span>`
: nothing}
</div>
</ha-md-menu-item>
<ha-md-menu-item
</ha-dropdown-item>
<ha-dropdown-item
slot="menu-items"
.clickAction=${this.config.cut}
value="cut"
.disabled=${this.disabled}
>
<ha-svg-icon slot="start" .path=${mdiContentCut}></ha-svg-icon>
<ha-svg-icon slot="icon" .path=${mdiContentCut}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.cut"
@@ -206,7 +204,6 @@ export default class HaAutomationSidebarAction extends LitElement {
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
@@ -218,32 +215,29 @@ export default class HaAutomationSidebarAction extends LitElement {
</span>`
: nothing}
</div>
</ha-md-menu-item>
<ha-md-menu-item
</ha-dropdown-item>
<ha-dropdown-item
slot="menu-items"
.clickAction=${this._toggleYamlMode}
value="toggle_yaml_mode"
.disabled=${!this.config.uiSupported || !!this._warnings}
>
<ha-svg-icon slot="start" .path=${mdiPlaylistEdit}></ha-svg-icon>
<ha-svg-icon slot="icon" .path=${mdiPlaylistEdit}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
`ui.panel.config.automation.editor.edit_${!this.yamlMode ? "yaml" : "ui"}`
)}
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-md-menu-item>
<ha-md-divider
</ha-dropdown-item>
<wa-divider slot="menu-items"></wa-divider>
<ha-dropdown-item
slot="menu-items"
role="separator"
tabindex="-1"
></ha-md-divider>
<ha-md-menu-item
slot="menu-items"
.clickAction=${this.config.disable}
value="disable"
.disabled=${this.disabled}
>
<ha-svg-icon
slot="start"
slot="icon"
.path=${rowDisabled ? mdiPlayCircleOutline : mdiStopCircleOutline}
></ha-svg-icon>
<div class="overflow-label">
@@ -252,14 +246,14 @@ export default class HaAutomationSidebarAction extends LitElement {
)}
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-md-menu-item>
<ha-md-menu-item
</ha-dropdown-item>
<ha-dropdown-item
slot="menu-items"
.clickAction=${this.config.delete}
value="delete"
variant="danger"
.disabled=${this.disabled}
class="warning"
>
<ha-svg-icon slot="start" .path=${mdiDelete}></ha-svg-icon>
<ha-svg-icon slot="icon" .path=${mdiDelete}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
"ui.panel.config.automation.editor.actions.delete"
@@ -269,7 +263,6 @@ export default class HaAutomationSidebarAction extends LitElement {
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
@@ -285,7 +278,7 @@ export default class HaAutomationSidebarAction extends LitElement {
</span>`
: nothing}
</div>
</ha-md-menu-item>
</ha-dropdown-item>
${description && !this.yamlMode
? html`<div class="description">${description}</div>`
: keyed(
@@ -341,6 +334,41 @@ export default class HaAutomationSidebarAction extends LitElement {
fireEvent(this, "toggle-yaml-mode");
};
private _handleDropdownSelect(ev: CustomEvent<{ item: HaDropdownItem }>) {
const action = ev.detail?.item?.value;
if (!action) {
return;
}
switch (action) {
case "rename":
this.config.rename();
break;
case "run":
this.config.run();
break;
case "duplicate":
this.config.duplicate();
break;
case "copy":
this.config.copy();
break;
case "cut":
this.config.cut();
break;
case "toggle_yaml_mode":
this._toggleYamlMode();
break;
case "disable":
this.config.disable();
break;
case "delete":
this.config.delete();
break;
}
}
static styles = [sidebarEditorStyles, overflowStyles];
}

View File

@@ -3,16 +3,16 @@ import { css, html, LitElement, nothing } from "lit";
import { customElement, property, query } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { fireEvent } from "../../../../common/dom/fire_event";
import { preventDefaultStopPropagation } from "../../../../common/dom/prevent_default_stop_propagation";
import { stopPropagation } from "../../../../common/dom/stop_propagation";
import "../../../../components/ha-card";
import "../../../../components/ha-dialog-header";
import "../../../../components/ha-dropdown";
import "../../../../components/ha-icon-button";
import "../../../../components/ha-md-button-menu";
import "../../../../components/ha-md-divider";
import { ScrollableFadeMixin } from "../../../../mixins/scrollable-fade-mixin";
import { haStyleScrollbar } from "../../../../resources/styles";
import type { HomeAssistant } from "../../../../types";
import "../ha-automation-editor-warning";
import { ScrollableFadeMixin } from "../../../../mixins/scrollable-fade-mixin";
export interface SidebarOverflowMenuEntry {
clickAction: () => void;
@@ -36,6 +36,10 @@ export default class HaAutomationSidebarCard extends ScrollableFadeMixin(
@property({ attribute: false }) public warnings?: string[];
@property({ attribute: false }) public handleDropdownSelect!: (
ev: CustomEvent
) => void;
@property({ type: Boolean }) public narrow = false;
@query(".card-content") private _contentElement!: HTMLDivElement;
@@ -63,14 +67,10 @@ export default class HaAutomationSidebarCard extends ScrollableFadeMixin(
<slot slot="title" name="title"></slot>
<slot slot="subtitle" name="subtitle"></slot>
<slot name="overflow-menu" slot="actionItems">
<ha-md-button-menu
quick
@click=${this._openOverflowMenu}
<ha-dropdown
@click=${preventDefaultStopPropagation}
@keydown=${stopPropagation}
@closed=${stopPropagation}
.positioning=${this.narrow ? "absolute" : "fixed"}
anchor-corner="end-end"
menu-corner="start-end"
placement="bottom-end"
>
<ha-icon-button
slot="trigger"
@@ -78,7 +78,7 @@ export default class HaAutomationSidebarCard extends ScrollableFadeMixin(
.path=${mdiDotsVertical}
></ha-icon-button>
<slot name="menu-items"></slot>
</ha-md-button-menu>
</ha-dropdown>
</slot>
</ha-dialog-header>
${this.warnings
@@ -100,11 +100,6 @@ export default class HaAutomationSidebarCard extends ScrollableFadeMixin(
fireEvent(this, "close-sidebar");
}
private _openOverflowMenu(ev: MouseEvent) {
ev.stopPropagation();
ev.preventDefault();
}
static get styles() {
return [
...super.styles,

View File

@@ -1,3 +1,4 @@
import "@home-assistant/webawesome/dist/components/divider/divider";
import {
mdiAppleKeyboardCommand,
mdiContentCopy,
@@ -16,9 +17,11 @@ import { classMap } from "lit/directives/class-map";
import { keyed } from "lit/directives/keyed";
import { fireEvent } from "../../../../common/dom/fire_event";
import { handleStructError } from "../../../../common/structs/handle-errors";
import "../../../../components/ha-dropdown-item";
import type { HaDropdownItem } from "../../../../components/ha-dropdown-item";
import type {
LegacyCondition,
ConditionSidebarConfig,
LegacyCondition,
} from "../../../../data/automation";
import { testCondition } from "../../../../data/automation";
import {
@@ -117,6 +120,7 @@ export default class HaAutomationSidebarCondition extends LitElement {
.yamlMode=${this.yamlMode}
.warnings=${this._warnings}
.narrow=${this.narrow}
@wa-select=${this._handleDropdownSelect}
>
<span slot="title">${title}</span>
<span slot="subtitle"
@@ -124,42 +128,38 @@ export default class HaAutomationSidebarCondition extends LitElement {
? ` (${this.hass.localize("ui.panel.config.automation.editor.actions.disabled")})`
: ""}</span
>
<ha-md-menu-item slot="menu-items" .clickAction=${this._testCondition}>
<ha-svg-icon slot="start" .path=${mdiFlask}></ha-svg-icon>
<ha-dropdown-item slot="menu-items" value="test">
<ha-svg-icon slot="icon" .path=${mdiFlask}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
"ui.panel.config.automation.editor.conditions.test"
)}
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-md-menu-item>
<ha-md-menu-item
</ha-dropdown-item>
<ha-dropdown-item
slot="menu-items"
.clickAction=${this.config.rename}
value="rename"
.disabled=${this.disabled}
>
<ha-svg-icon slot="start" .path=${mdiRenameBox}></ha-svg-icon>
<ha-svg-icon slot="icon" .path=${mdiRenameBox}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.rename"
)}
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-md-menu-item>
</ha-dropdown-item>
<ha-md-divider
slot="menu-items"
role="separator"
tabindex="-1"
></ha-md-divider>
<wa-divider slot="menu-items"></wa-divider>
<ha-md-menu-item
<ha-dropdown-item
slot="menu-items"
.clickAction=${this.config.duplicate}
value="duplicate"
.disabled=${this.disabled}
>
<ha-svg-icon
slot="start"
slot="icon"
.path=${mdiPlusCircleMultipleOutline}
></ha-svg-icon>
<div class="overflow-label">
@@ -168,10 +168,10 @@ export default class HaAutomationSidebarCondition extends LitElement {
)}
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-md-menu-item>
</ha-dropdown-item>
<ha-md-menu-item slot="menu-items" .clickAction=${this.config.copy}>
<ha-svg-icon slot="start" .path=${mdiContentCopy}></ha-svg-icon>
<ha-dropdown-item slot="menu-items" value="copy">
<ha-svg-icon slot="icon" .path=${mdiContentCopy}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.copy"
@@ -181,7 +181,6 @@ export default class HaAutomationSidebarCondition extends LitElement {
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
@@ -193,14 +192,14 @@ export default class HaAutomationSidebarCondition extends LitElement {
</span>`
: nothing}
</div>
</ha-md-menu-item>
</ha-dropdown-item>
<ha-md-menu-item
<ha-dropdown-item
slot="menu-items"
.clickAction=${this.config.cut}
value="cut"
.disabled=${this.disabled}
>
<ha-svg-icon slot="start" .path=${mdiContentCut}></ha-svg-icon>
<ha-svg-icon slot="icon" .path=${mdiContentCut}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.cut"
@@ -210,7 +209,6 @@ export default class HaAutomationSidebarCondition extends LitElement {
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
@@ -222,32 +220,29 @@ export default class HaAutomationSidebarCondition extends LitElement {
</span>`
: nothing}
</div>
</ha-md-menu-item>
<ha-md-menu-item
</ha-dropdown-item>
<ha-dropdown-item
slot="menu-items"
.clickAction=${this._toggleYamlMode}
value="toggle_yaml_mode"
.disabled=${!this.config.uiSupported || !!this._warnings}
>
<ha-svg-icon slot="start" .path=${mdiPlaylistEdit}></ha-svg-icon>
<ha-svg-icon slot="icon" .path=${mdiPlaylistEdit}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
`ui.panel.config.automation.editor.edit_${!this.yamlMode ? "yaml" : "ui"}`
)}
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-md-menu-item>
<ha-md-divider
</ha-dropdown-item>
<wa-divider slot="menu-items"></wa-divider>
<ha-dropdown-item
slot="menu-items"
role="separator"
tabindex="-1"
></ha-md-divider>
<ha-md-menu-item
slot="menu-items"
.clickAction=${this.config.disable}
value="disable"
.disabled=${this.disabled}
>
<ha-svg-icon
slot="start"
slot="icon"
.path=${rowDisabled ? mdiPlayCircleOutline : mdiStopCircleOutline}
></ha-svg-icon>
<div class="overflow-label">
@@ -256,14 +251,14 @@ export default class HaAutomationSidebarCondition extends LitElement {
)}
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-md-menu-item>
<ha-md-menu-item
</ha-dropdown-item>
<ha-dropdown-item
slot="menu-items"
.clickAction=${this.config.delete}
value="delete"
variant="danger"
.disabled=${this.disabled}
class="warning"
>
<ha-svg-icon slot="start" .path=${mdiDelete}></ha-svg-icon>
<ha-svg-icon slot="icon" .path=${mdiDelete}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
"ui.panel.config.automation.editor.actions.delete"
@@ -273,7 +268,6 @@ export default class HaAutomationSidebarCondition extends LitElement {
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
@@ -289,7 +283,7 @@ export default class HaAutomationSidebarCondition extends LitElement {
</span>`
: nothing}
</div>
</ha-md-menu-item>
</ha-dropdown-item>
${description && !this.yamlMode
? html`<div class="description">${description}</div>`
: keyed(
@@ -419,6 +413,41 @@ export default class HaAutomationSidebarCondition extends LitElement {
fireEvent(this, "toggle-yaml-mode");
};
private _handleDropdownSelect(ev: CustomEvent<{ item: HaDropdownItem }>) {
const action = ev.detail?.item?.value;
if (!action) {
return;
}
switch (action) {
case "rename":
this.config.rename();
break;
case "test":
this._testCondition();
break;
case "duplicate":
this.config.duplicate();
break;
case "copy":
this.config.copy();
break;
case "cut":
this.config.cut();
break;
case "toggle_yaml_mode":
this._toggleYamlMode();
break;
case "disable":
this.config.disable();
break;
case "delete":
this.config.delete();
break;
}
}
static styles = [
sidebarEditorStyles,
overflowStyles,

View File

@@ -1,3 +1,4 @@
import "@home-assistant/webawesome/dist/components/divider/divider";
import {
mdiAppleKeyboardCommand,
mdiDelete,
@@ -6,8 +7,9 @@ import {
} from "@mdi/js";
import { html, LitElement, nothing } from "lit";
import { customElement, property, query } from "lit/decorators";
import "../../../../components/ha-md-divider";
import "../../../../components/ha-md-menu-item";
import "../../../../components/ha-dropdown-item";
import type { HaDropdownItem } from "../../../../components/ha-dropdown-item";
import "../../../../components/ha-svg-icon";
import type { OptionSidebarConfig } from "../../../../data/automation";
import type { HomeAssistant } from "../../../../types";
@@ -50,33 +52,34 @@ export default class HaAutomationSidebarOption extends LitElement {
.hass=${this.hass}
.isWide=${this.isWide}
.narrow=${this.narrow}
@wa-select=${this._handleDropdownSelect}
>
<span slot="title">${title}</span>
<span slot="subtitle">${subtitle}</span>
${this.config.defaultOption
? html`<span slot="overflow-menu"></span>`
: html`
<ha-md-menu-item
<ha-dropdown-item
slot="menu-items"
.clickAction=${this.config.rename}
value="rename"
.disabled=${!!disabled}
>
<ha-svg-icon slot="start" .path=${mdiRenameBox}></ha-svg-icon>
<ha-svg-icon slot="icon" .path=${mdiRenameBox}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.rename"
)}
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-md-menu-item>
</ha-dropdown-item>
<ha-md-menu-item
<ha-dropdown-item
slot="menu-items"
@click=${this.config.duplicate}
value="duplicate"
.disabled=${this.disabled}
>
<ha-svg-icon
slot="start"
slot="icon"
.path=${mdiPlusCircleMultipleOutline}
></ha-svg-icon>
<div class="overflow-label">
@@ -85,19 +88,15 @@ export default class HaAutomationSidebarOption extends LitElement {
)}
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-md-menu-item>
<ha-md-divider
</ha-dropdown-item>
<wa-divider slot="menu-items"></wa-divider>
<ha-dropdown-item
slot="menu-items"
role="separator"
tabindex="-1"
></ha-md-divider>
<ha-md-menu-item
slot="menu-items"
.clickAction=${this.config.delete}
value="delete"
.disabled=${this.disabled}
class="warning"
variant="danger"
>
<ha-svg-icon slot="start" .path=${mdiDelete}></ha-svg-icon>
<ha-svg-icon slot="icon" .path=${mdiDelete}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
"ui.panel.config.automation.editor.actions.type.choose.remove_option"
@@ -123,13 +122,33 @@ export default class HaAutomationSidebarOption extends LitElement {
</span>`
: nothing}
</div>
</ha-md-menu-item>
</ha-dropdown-item>
`}
<div class="description">${description}</div>
</ha-automation-sidebar-card>`;
}
private _handleDropdownSelect(ev: CustomEvent<{ item: HaDropdownItem }>) {
const action = ev.detail?.item?.value;
if (!action) {
return;
}
switch (action) {
case "rename":
this.config.rename();
break;
case "duplicate":
this.config.duplicate();
break;
case "delete":
this.config.delete();
break;
}
}
static styles = [sidebarEditorStyles, overflowStyles];
}

View File

@@ -4,6 +4,8 @@ import { customElement, property, query, state } from "lit/decorators";
import { keyed } from "lit/directives/keyed";
import { fireEvent } from "../../../../common/dom/fire_event";
import type { LocalizeKeys } from "../../../../common/translations/localize";
import "../../../../components/ha-dropdown-item";
import type { HaDropdownItem } from "../../../../components/ha-dropdown-item";
import type { ScriptFieldSidebarConfig } from "../../../../data/automation";
import type { HomeAssistant } from "../../../../types";
import { isMac } from "../../../../util/is_mac";
@@ -62,29 +64,30 @@ export default class HaAutomationSidebarScriptFieldSelector extends LitElement {
.yamlMode=${this.yamlMode}
.warnings=${this._warnings}
.narrow=${this.narrow}
@wa-select=${this._handleDropdownSelect}
>
<span slot="title">${title}</span>
<span slot="subtitle">${subtitle}</span>
<ha-md-menu-item
<ha-dropdown-item
slot="menu-items"
.clickAction=${this._toggleYamlMode}
value="toggle_yaml_mode"
.disabled=${!!this._warnings}
>
<ha-svg-icon slot="start" .path=${mdiPlaylistEdit}></ha-svg-icon>
<ha-svg-icon slot="icon" .path=${mdiPlaylistEdit}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
`ui.panel.config.automation.editor.edit_${!this.yamlMode ? "yaml" : "ui"}`
)}
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-md-menu-item>
<ha-md-menu-item
</ha-dropdown-item>
<ha-dropdown-item
slot="menu-items"
.clickAction=${this.config.delete}
value="delete"
.disabled=${this.disabled}
class="warning"
variant="danger"
>
<ha-svg-icon slot="start" .path=${mdiDelete}></ha-svg-icon>
<ha-svg-icon slot="icon" .path=${mdiDelete}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
"ui.panel.config.automation.editor.actions.delete"
@@ -94,7 +97,6 @@ export default class HaAutomationSidebarScriptFieldSelector extends LitElement {
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
@@ -110,7 +112,7 @@ export default class HaAutomationSidebarScriptFieldSelector extends LitElement {
</span>`
: nothing}
</div>
</ha-md-menu-item>
</ha-dropdown-item>
${keyed(
this.sidebarKey,
html`<ha-script-field-selector-editor
@@ -160,6 +162,23 @@ export default class HaAutomationSidebarScriptFieldSelector extends LitElement {
fireEvent(this, "toggle-yaml-mode");
};
private _handleDropdownSelect(ev: CustomEvent<{ item: HaDropdownItem }>) {
const action = ev.detail?.item?.value;
if (!action) {
return;
}
switch (action) {
case "toggle_yaml_mode":
this._toggleYamlMode();
break;
case "delete":
this.config.delete();
break;
}
}
static styles = sidebarEditorStyles;
}

View File

@@ -3,6 +3,8 @@ import { html, LitElement, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { keyed } from "lit/directives/keyed";
import { fireEvent } from "../../../../common/dom/fire_event";
import "../../../../components/ha-dropdown-item";
import type { HaDropdownItem } from "../../../../components/ha-dropdown-item";
import type { ScriptFieldSidebarConfig } from "../../../../data/automation";
import type { HomeAssistant } from "../../../../types";
import { isMac } from "../../../../util/is_mac";
@@ -56,28 +58,29 @@ export default class HaAutomationSidebarScriptField extends LitElement {
.yamlMode=${this.yamlMode}
.warnings=${this._warnings}
.narrow=${this.narrow}
@wa-select=${this._handleDropdownSelect}
>
<span slot="title">${title}</span>
<ha-md-menu-item
<ha-dropdown-item
slot="menu-items"
.clickAction=${this._toggleYamlMode}
value="toggle_yaml_mode"
.disabled=${!!this._warnings}
>
<ha-svg-icon slot="start" .path=${mdiPlaylistEdit}></ha-svg-icon>
<ha-svg-icon slot="icon" .path=${mdiPlaylistEdit}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
`ui.panel.config.automation.editor.edit_${!this.yamlMode ? "yaml" : "ui"}`
)}
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-md-menu-item>
<ha-md-menu-item
</ha-dropdown-item>
<ha-dropdown-item
slot="menu-items"
.clickAction=${this.config.delete}
value="delete"
.disabled=${this.disabled}
class="warning"
variant="danger"
>
<ha-svg-icon slot="start" .path=${mdiDelete}></ha-svg-icon>
<ha-svg-icon slot="icon" .path=${mdiDelete}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
"ui.panel.config.automation.editor.actions.delete"
@@ -87,7 +90,6 @@ export default class HaAutomationSidebarScriptField extends LitElement {
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
@@ -103,7 +105,7 @@ export default class HaAutomationSidebarScriptField extends LitElement {
</span>`
: nothing}
</div>
</ha-md-menu-item>
</ha-dropdown-item>
${keyed(
this.sidebarKey,
html`<ha-script-field-editor
@@ -154,6 +156,23 @@ export default class HaAutomationSidebarScriptField extends LitElement {
fireEvent(this, "toggle-yaml-mode");
};
private _handleDropdownSelect(ev: CustomEvent<{ item: HaDropdownItem }>) {
const action = ev.detail?.item?.value;
if (!action) {
return;
}
switch (action) {
case "toggle_yaml_mode":
this._toggleYamlMode();
break;
case "delete":
this.config.delete();
break;
}
}
static styles = [sidebarEditorStyles, overflowStyles];
}

View File

@@ -1,3 +1,4 @@
import "@home-assistant/webawesome/dist/components/divider/divider";
import {
mdiAppleKeyboardCommand,
mdiContentCopy,
@@ -15,6 +16,8 @@ import { customElement, property, query, state } from "lit/decorators";
import { keyed } from "lit/directives/keyed";
import { fireEvent } from "../../../../common/dom/fire_event";
import { handleStructError } from "../../../../common/structs/handle-errors";
import "../../../../components/ha-dropdown-item";
import type { HaDropdownItem } from "../../../../components/ha-dropdown-item";
import type {
LegacyTrigger,
TriggerSidebarConfig,
@@ -99,6 +102,7 @@ export default class HaAutomationSidebarTrigger extends LitElement {
.yamlMode=${this.yamlMode}
.warnings=${this._warnings}
.narrow=${this.narrow}
@wa-select=${this._handleDropdownSelect}
>
<span slot="title">${title}</span>
<span slot="subtitle"
@@ -106,60 +110,56 @@ export default class HaAutomationSidebarTrigger extends LitElement {
? ` (${this.hass.localize("ui.panel.config.automation.editor.actions.disabled")})`
: ""}</span
>
<ha-md-menu-item
<ha-dropdown-item
slot="menu-items"
.clickAction=${this.config.rename}
value="rename"
.disabled=${this.disabled || type === "list"}
>
<ha-svg-icon slot="start" .path=${mdiRenameBox}></ha-svg-icon>
<ha-svg-icon slot="icon" .path=${mdiRenameBox}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.rename"
)}
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-md-menu-item>
</ha-dropdown-item>
${!this.yamlMode &&
!("id" in this.config.config) &&
!this._requestShowId
? html`<ha-md-menu-item
? html`<ha-dropdown-item
slot="menu-items"
.clickAction=${this._showTriggerId}
value="show_id"
.disabled=${this.disabled || type === "list"}
>
<ha-svg-icon slot="start" .path=${mdiIdentifier}></ha-svg-icon>
<ha-svg-icon slot="icon" .path=${mdiIdentifier}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.edit_id"
)}
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-md-menu-item>`
</ha-dropdown-item>`
: nothing}
<ha-md-divider
slot="menu-items"
role="separator"
tabindex="-1"
></ha-md-divider>
<wa-divider slot="menu-items"></wa-divider>
<ha-md-menu-item
<ha-dropdown-item
slot="menu-items"
.clickAction=${this.config.duplicate}
value="duplicate"
.disabled=${this.disabled}
>
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.duplicate"
)}
<ha-svg-icon
slot="start"
slot="icon"
.path=${mdiPlusCircleMultipleOutline}
></ha-svg-icon>
</ha-md-menu-item>
</ha-dropdown-item>
<ha-md-menu-item slot="menu-items" .clickAction=${this.config.copy}>
<ha-svg-icon slot="start" .path=${mdiContentCopy}></ha-svg-icon>
<ha-dropdown-item slot="menu-items" value="copy">
<ha-svg-icon slot="icon" .path=${mdiContentCopy}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.copy"
@@ -169,7 +169,6 @@ export default class HaAutomationSidebarTrigger extends LitElement {
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
@@ -181,14 +180,14 @@ export default class HaAutomationSidebarTrigger extends LitElement {
</span>`
: nothing}
</div>
</ha-md-menu-item>
</ha-dropdown-item>
<ha-md-menu-item
<ha-dropdown-item
slot="menu-items"
.clickAction=${this.config.cut}
value="cut"
.disabled=${this.disabled}
>
<ha-svg-icon slot="start" .path=${mdiContentCut}></ha-svg-icon>
<ha-svg-icon slot="icon" .path=${mdiContentCut}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
"ui.panel.config.automation.editor.triggers.cut"
@@ -198,7 +197,6 @@ export default class HaAutomationSidebarTrigger extends LitElement {
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
@@ -210,32 +208,28 @@ export default class HaAutomationSidebarTrigger extends LitElement {
</span>`
: nothing}
</div>
</ha-md-menu-item>
<ha-md-menu-item
</ha-dropdown-item>
<ha-dropdown-item
slot="menu-items"
.clickAction=${this._toggleYamlMode}
value="toggle_yaml_mode"
.disabled=${!this.config.uiSupported || !!this._warnings}
>
<ha-svg-icon slot="start" .path=${mdiPlaylistEdit}></ha-svg-icon>
<ha-svg-icon slot="icon" .path=${mdiPlaylistEdit}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
`ui.panel.config.automation.editor.edit_${!this.yamlMode ? "yaml" : "ui"}`
)}
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-md-menu-item>
<ha-md-divider
</ha-dropdown-item>
<wa-divider slot="menu-items"></wa-divider>
<ha-dropdown-item
slot="menu-items"
role="separator"
tabindex="-1"
></ha-md-divider>
<ha-md-menu-item
slot="menu-items"
.clickAction=${this.config.disable}
value="disable"
.disabled=${this.disabled || type === "list"}
>
<ha-svg-icon
slot="start"
slot="icon"
.path=${rowDisabled ? mdiPlayCircleOutline : mdiStopCircleOutline}
></ha-svg-icon>
<div class="overflow-label">
@@ -244,14 +238,14 @@ export default class HaAutomationSidebarTrigger extends LitElement {
)}
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-md-menu-item>
<ha-md-menu-item
</ha-dropdown-item>
<ha-dropdown-item
slot="menu-items"
.clickAction=${this.config.delete}
value="delete"
.disabled=${this.disabled}
class="warning"
variant="danger"
>
<ha-svg-icon slot="start" .path=${mdiDelete}></ha-svg-icon>
<ha-svg-icon slot="icon" .path=${mdiDelete}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
"ui.panel.config.automation.editor.actions.delete"
@@ -261,7 +255,6 @@ export default class HaAutomationSidebarTrigger extends LitElement {
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
@@ -277,7 +270,7 @@ export default class HaAutomationSidebarTrigger extends LitElement {
</span>`
: nothing}
</div>
</ha-md-menu-item>
</ha-dropdown-item>
${keyed(
this.sidebarKey,
html`<ha-automation-trigger-editor
@@ -335,6 +328,41 @@ export default class HaAutomationSidebarTrigger extends LitElement {
this._requestShowId = true;
};
private _handleDropdownSelect(ev: CustomEvent<{ item: HaDropdownItem }>) {
const action = ev.detail?.item?.value;
if (!action) {
return;
}
switch (action) {
case "rename":
this.config.rename();
break;
case "show_id":
this._showTriggerId();
break;
case "duplicate":
this.config.duplicate();
break;
case "copy":
this.config.copy();
break;
case "cut":
this.config.cut();
break;
case "toggle_yaml_mode":
this._toggleYamlMode();
break;
case "disable":
this.config.disable();
break;
case "delete":
this.config.delete();
break;
}
}
static styles = [sidebarEditorStyles, overflowStyles];
}

View File

@@ -1,3 +1,4 @@
import "@home-assistant/webawesome/dist/components/divider/divider";
import { consume } from "@lit/context";
import {
mdiAppleKeyboardCommand,
@@ -34,11 +35,11 @@ import "../../../../components/ha-alert";
import "../../../../components/ha-automation-row";
import type { HaAutomationRow } from "../../../../components/ha-automation-row";
import "../../../../components/ha-card";
import "../../../../components/ha-dropdown";
import "../../../../components/ha-dropdown-item";
import type { HaDropdownItem } from "../../../../components/ha-dropdown-item";
import "../../../../components/ha-expansion-panel";
import "../../../../components/ha-icon-button";
import "../../../../components/ha-md-button-menu";
import "../../../../components/ha-md-divider";
import "../../../../components/ha-md-menu-item";
import "../../../../components/ha-svg-icon";
import { TRIGGER_ICONS } from "../../../../components/ha-trigger-icon";
import type {
@@ -208,41 +209,35 @@ export default class HaAutomationTriggerRow extends LitElement {
<slot name="icons" slot="icons"></slot>
<ha-md-button-menu
quick
<ha-dropdown
slot="icons"
@click=${preventDefaultStopPropagation}
@keydown=${stopPropagation}
@closed=${stopPropagation}
positioning="fixed"
anchor-corner="end-end"
menu-corner="start-end"
@wa-select=${this._handleDropdownSelect}
placement="bottom-end"
>
<ha-icon-button
slot="trigger"
.label=${this.hass.localize("ui.common.menu")}
.path=${mdiDotsVertical}
></ha-icon-button>
<ha-md-menu-item
.clickAction=${this._renameTrigger}
<ha-dropdown-item
value="rename"
.disabled=${this.disabled || type === "list"}
>
<ha-svg-icon slot="start" .path=${mdiRenameBox}></ha-svg-icon>
<ha-svg-icon slot="icon" .path=${mdiRenameBox}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.triggers.rename"
)
)}
</ha-md-menu-item>
</ha-dropdown-item>
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
<wa-divider></wa-divider>
<ha-md-menu-item
.clickAction=${this._duplicateTrigger}
.disabled=${this.disabled}
>
<ha-dropdown-item value="duplicate" .disabled=${this.disabled}>
<ha-svg-icon
slot="start"
slot="icon"
.path=${mdiPlusCircleMultipleOutline}
></ha-svg-icon>
@@ -251,13 +246,10 @@ export default class HaAutomationTriggerRow extends LitElement {
"ui.panel.config.automation.editor.actions.duplicate"
)
)}
</ha-md-menu-item>
</ha-dropdown-item>
<ha-md-menu-item
.clickAction=${this._copyTrigger}
.disabled=${this.disabled}
>
<ha-svg-icon slot="start" .path=${mdiContentCopy}></ha-svg-icon>
<ha-dropdown-item value="copy" .disabled=${this.disabled}>
<ha-svg-icon slot="icon" .path=${mdiContentCopy}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.triggers.copy"
@@ -266,7 +258,6 @@ export default class HaAutomationTriggerRow extends LitElement {
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
@@ -277,13 +268,10 @@ export default class HaAutomationTriggerRow extends LitElement {
<span>C</span>
</span>`
)}
</ha-md-menu-item>
</ha-dropdown-item>
<ha-md-menu-item
.clickAction=${this._cutTrigger}
.disabled=${this.disabled}
>
<ha-svg-icon slot="start" .path=${mdiContentCut}></ha-svg-icon>
<ha-dropdown-item value="cut" .disabled=${this.disabled}>
<ha-svg-icon slot="icon" .path=${mdiContentCut}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
"ui.panel.config.automation.editor.triggers.cut"
@@ -292,7 +280,6 @@ export default class HaAutomationTriggerRow extends LitElement {
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
@@ -303,51 +290,51 @@ export default class HaAutomationTriggerRow extends LitElement {
<span>X</span>
</span>`
)}
</ha-md-menu-item>
</ha-dropdown-item>
${!this.optionsInSidebar
? html`
<ha-md-menu-item
.clickAction=${this._moveUp}
<ha-dropdown-item
value="move_up"
.disabled=${this.disabled || !!this.first}
>
${this.hass.localize(
"ui.panel.config.automation.editor.move_up"
)}
<ha-svg-icon slot="start" .path=${mdiArrowUp}></ha-svg-icon
></ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._moveDown}
<ha-svg-icon slot="icon" .path=${mdiArrowUp}></ha-svg-icon
></ha-dropdown-item>
<ha-dropdown-item
value="move_down"
.disabled=${this.disabled || !!this.last}
>
${this.hass.localize(
"ui.panel.config.automation.editor.move_down"
)}
<ha-svg-icon slot="start" .path=${mdiArrowDown}></ha-svg-icon
></ha-md-menu-item>
<ha-svg-icon slot="icon" .path=${mdiArrowDown}></ha-svg-icon
></ha-dropdown-item>
`
: nothing}
<ha-md-menu-item
.clickAction=${this._toggleYamlMode}
<ha-dropdown-item
value="toggle_yaml_mode"
.disabled=${!supported || !!this._warnings}
>
<ha-svg-icon slot="start" .path=${mdiPlaylistEdit}></ha-svg-icon>
<ha-svg-icon slot="icon" .path=${mdiPlaylistEdit}></ha-svg-icon>
${this._renderOverflowLabel(
this.hass.localize(
`ui.panel.config.automation.editor.edit_${!yamlMode ? "yaml" : "ui"}`
)
)}
</ha-md-menu-item>
</ha-dropdown-item>
<ha-md-divider role="separator" tabindex="-1"></ha-md-divider>
<wa-divider></wa-divider>
<ha-md-menu-item
.clickAction=${this._onDisable}
<ha-dropdown-item
value="disable"
.disabled=${this.disabled || type === "list"}
>
<ha-svg-icon
slot="start"
slot="icon"
.path=${"enabled" in this.trigger && this.trigger.enabled === false
? mdiPlayCircleOutline
: mdiStopCircleOutline}
@@ -358,15 +345,15 @@ export default class HaAutomationTriggerRow extends LitElement {
`ui.panel.config.automation.editor.actions.${"enabled" in this.trigger && this.trigger.enabled === false ? "enable" : "disable"}`
)
)}
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._onDelete}
class="warning"
</ha-dropdown-item>
<ha-dropdown-item
value="delete"
variant="danger"
.disabled=${this.disabled}
>
<ha-svg-icon
class="warning"
slot="start"
slot="icon"
.path=${mdiDelete}
></ha-svg-icon>
${this._renderOverflowLabel(
@@ -377,7 +364,6 @@ export default class HaAutomationTriggerRow extends LitElement {
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
@@ -392,8 +378,8 @@ export default class HaAutomationTriggerRow extends LitElement {
>
</span>`
)}
</ha-md-menu-item>
</ha-md-button-menu>
</ha-dropdown-item>
</ha-dropdown>
${!this.optionsInSidebar
? html`${this._warnings
? html`<ha-automation-editor-warning
@@ -804,6 +790,44 @@ export default class HaAutomationTriggerRow extends LitElement {
this._automationRowElement?.focus();
}
private _handleDropdownSelect(ev: CustomEvent<{ item: HaDropdownItem }>) {
const action = ev.detail?.item?.value;
if (!action) {
return;
}
switch (action) {
case "rename":
this._renameTrigger();
break;
case "duplicate":
this._duplicateTrigger();
break;
case "copy":
this._copyTrigger();
break;
case "cut":
this._cutTrigger();
break;
case "move_up":
this._moveUp();
break;
case "move_down":
this._moveDown();
break;
case "toggle_yaml_mode":
this._toggleYamlMode(ev.target as HTMLElement);
break;
case "disable":
this._onDisable();
break;
case "delete":
this._onDelete();
break;
}
}
static get styles(): CSSResultGroup {
return [
rowStyles,

View File

@@ -160,9 +160,9 @@ export class HaPlatformTrigger extends LitElement {
const hasOptional = Boolean(
triggerDesc?.fields &&
Object.values(triggerDesc.fields).some((field) =>
showOptionalToggle(field)
)
Object.values(triggerDesc.fields).some((field) =>
showOptionalToggle(field)
)
);
return html`

View File

@@ -1,7 +1,7 @@
import { mdiOpenInNew } from "@mdi/js";
import type { CSSResultGroup } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { state } from "lit/decorators";
import { customElement, state } from "lit/decorators";
import { fireEvent } from "../../../../common/dom/fire_event";
import { createCloseHeading } from "../../../../components/ha-dialog";
import { showConfirmationDialog } from "../../../../dialogs/generic/show-dialog-box";
@@ -13,6 +13,7 @@ import type { WebhookDialogParams } from "./show-dialog-manage-cloudhook";
import "../../../../components/ha-button";
import "../../../../components/ha-copy-textfield";
@customElement("dialog-manage-cloudhook")
export class DialogManageCloudhook extends LitElement {
protected hass?: HomeAssistant;
@@ -155,5 +156,3 @@ declare global {
"dialog-manage-cloudhook": DialogManageCloudhook;
}
}
customElements.define("dialog-manage-cloudhook", DialogManageCloudhook);

View File

@@ -1138,23 +1138,20 @@ export class HaConfigDevicePage extends LitElement {
}
if (domains.includes("mqtt")) {
const mqtt = await import(
"./device-detail/integration-elements/mqtt/device-actions"
);
const mqtt =
await import("./device-detail/integration-elements/mqtt/device-actions");
const actions = mqtt.getMQTTDeviceActions(this, device);
deviceActions.push(...actions);
}
if (domains.includes("zha")) {
const zha = await import(
"./device-detail/integration-elements/zha/device-actions"
);
const zha =
await import("./device-detail/integration-elements/zha/device-actions");
const actions = await zha.getZHADeviceActions(this, this.hass, device);
deviceActions.push(...actions);
}
if (domains.includes("zwave_js")) {
const zwave = await import(
"./device-detail/integration-elements/zwave_js/device-actions"
);
const zwave =
await import("./device-detail/integration-elements/zwave_js/device-actions");
const actions = await zwave.getZwaveDeviceActions(
this,
this.hass,
@@ -1163,9 +1160,8 @@ export class HaConfigDevicePage extends LitElement {
deviceActions.push(...actions);
}
if (domains.includes("esphome")) {
const esphome = await import(
"./device-detail/integration-elements/esphome/device-actions"
);
const esphome =
await import("./device-detail/integration-elements/esphome/device-actions");
const actions = await esphome.getESPHomeDeviceActions(
this,
this.hass,
@@ -1174,9 +1170,8 @@ export class HaConfigDevicePage extends LitElement {
deviceActions.push(...actions);
}
if (domains.includes("matter")) {
const matter = await import(
"./device-detail/integration-elements/matter/device-actions"
);
const matter =
await import("./device-detail/integration-elements/matter/device-actions");
const defaultActions = matter.getMatterDeviceDefaultActions(
this,
this.hass,
@@ -1220,9 +1215,8 @@ export class HaConfigDevicePage extends LitElement {
).map((int) => int.domain);
if (domains.includes("zwave_js")) {
const zwave = await import(
"./device-detail/integration-elements/zwave_js/device-alerts"
);
const zwave =
await import("./device-detail/integration-elements/zwave_js/device-alerts");
const alerts = await zwave.getZwaveDeviceAlerts(this.hass, device);
deviceAlerts.push(...alerts);
@@ -1304,9 +1298,7 @@ export class HaConfigDevicePage extends LitElement {
`);
}
if (domains.includes("zwave_js")) {
import(
"./device-detail/integration-elements/zwave_js/ha-device-info-zwave_js"
);
import("./device-detail/integration-elements/zwave_js/ha-device-info-zwave_js");
deviceInfo.push(html`
<ha-device-info-zwave_js
.hass=${this.hass}
@@ -1315,9 +1307,7 @@ export class HaConfigDevicePage extends LitElement {
`);
}
if (domains.includes("matter")) {
import(
"./device-detail/integration-elements/matter/ha-device-info-matter"
);
import("./device-detail/integration-elements/matter/ha-device-info-matter");
deviceInfo.push(html`
<ha-device-info-matter
.hass=${this.hass}

View File

@@ -1012,7 +1012,6 @@ export class EntityRegistrySettingsEditor extends LitElement {
? html`<ha-area-picker
.hass=${this.hass}
.value=${this._areaId}
.placeholder=${this._device?.area_id}
.disabled=${this.disabled}
@value-changed=${this._areaPicked}
></ha-area-picker>`

View File

@@ -116,8 +116,10 @@ import { showAddIntegrationDialog } from "../integrations/show-add-integration-d
import { showLabelDetailDialog } from "../labels/show-dialog-label-detail";
import { slugify } from "../../../common/string/slugify";
export interface StateEntity
extends Omit<EntityRegistryEntry, "id" | "unique_id"> {
export interface StateEntity extends Omit<
EntityRegistryEntry,
"id" | "unique_id"
> {
readonly?: boolean;
selectable?: boolean;
id?: string;

View File

@@ -530,9 +530,7 @@ class HaPanelConfig extends SubscribeMixin(HassRouterPage) {
zha: {
tag: "zha-config-dashboard-router",
load: () =>
import(
"./integrations/integration-panels/zha/zha-config-dashboard-router"
),
import("./integrations/integration-panels/zha/zha-config-dashboard-router"),
},
mqtt: {
tag: "mqtt-config-panel",
@@ -542,30 +540,22 @@ class HaPanelConfig extends SubscribeMixin(HassRouterPage) {
zwave_js: {
tag: "zwave_js-config-router",
load: () =>
import(
"./integrations/integration-panels/zwave_js/zwave_js-config-router"
),
import("./integrations/integration-panels/zwave_js/zwave_js-config-router"),
},
matter: {
tag: "matter-config-panel",
load: () =>
import(
"./integrations/integration-panels/matter/matter-config-panel"
),
import("./integrations/integration-panels/matter/matter-config-panel"),
},
thread: {
tag: "thread-config-panel",
load: () =>
import(
"./integrations/integration-panels/thread/thread-config-panel"
),
import("./integrations/integration-panels/thread/thread-config-panel"),
},
bluetooth: {
tag: "bluetooth-config-dashboard-router",
load: () =>
import(
"./integrations/integration-panels/bluetooth/bluetooth-config-dashboard-router"
),
import("./integrations/integration-panels/bluetooth/bluetooth-config-dashboard-router"),
},
dhcp: {
tag: "dhcp-config-panel",
@@ -580,9 +570,7 @@ class HaPanelConfig extends SubscribeMixin(HassRouterPage) {
zeroconf: {
tag: "zeroconf-config-panel",
load: () =>
import(
"./integrations/integration-panels/zeroconf/zeroconf-config-panel"
),
import("./integrations/integration-panels/zeroconf/zeroconf-config-panel"),
},
application_credentials: {
tag: "ha-config-application-credentials",

View File

@@ -1,7 +1,7 @@
import type { CSSResultGroup } from "lit";
import { html, LitElement, nothing } from "lit";
import memoizeOne from "memoize-one";
import { property, state } from "lit/decorators";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../../../common/dom/fire_event";
import { createCloseHeading } from "../../../../components/ha-dialog";
import "../../../../components/ha-form/ha-form";
@@ -14,6 +14,7 @@ import type {
} from "./show-dialog-schedule-block-info";
import type { SchemaUnion } from "../../../../components/ha-form/types";
@customElement("dialog-schedule-block-info")
class DialogScheduleBlockInfo extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -156,5 +157,3 @@ declare global {
"dialog-schedule-block-info": DialogScheduleBlockInfo;
}
}
customElements.define("dialog-schedule-block-info", DialogScheduleBlockInfo);

View File

@@ -1,6 +1,6 @@
import type { CSSResultGroup, PropertyValues } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { property, state } from "lit/decorators";
import { customElement, property, state } from "lit/decorators";
import { stopPropagation } from "../../../../../common/dom/stop_propagation";
import "../../../../../components/buttons/ha-call-service-button";
import "../../../../../components/ha-card";
@@ -15,6 +15,7 @@ import type { HomeAssistant } from "../../../../../types";
import { formatAsPaddedHex } from "./functions";
import type { IssueCommandServiceData } from "./types";
@customElement("zha-cluster-commands")
export class ZHAClusterCommands extends LitElement {
@property({ attribute: false }) public hass?: HomeAssistant;
@@ -259,5 +260,3 @@ declare global {
"zha-cluster-commands": ZHAClusterCommands;
}
}
customElements.define("zha-cluster-commands", ZHAClusterCommands);

View File

@@ -192,9 +192,9 @@ export class ZHAGroupBindingControl extends LitElement {
private get _canBind(): boolean {
return Boolean(
this._groupToBind &&
this._clustersToBind &&
this._clustersToBind?.length > 0 &&
this.device
this._clustersToBind &&
this._clustersToBind?.length > 0 &&
this.device
);
}

View File

@@ -1,7 +1,7 @@
import { mdiClose, mdiContentCopy } from "@mdi/js";
import type { CSSResultGroup } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { property, state } from "lit/decorators";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../../common/dom/fire_event";
import { copyToClipboard } from "../../../common/util/copy-clipboard";
import "../../../components/ha-alert";
@@ -26,6 +26,7 @@ import { showToast } from "../../../util/toast";
import type { SystemLogDetailDialogParams } from "./show-dialog-system-log-detail";
import { formatSystemLogTime } from "./util";
@customElement("dialog-system-log-detail")
class DialogSystemLogDetail extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -272,5 +273,3 @@ declare global {
"dialog-system-log-detail": DialogSystemLogDetail;
}
}
customElements.define("dialog-system-log-detail", DialogSystemLogDetail);

View File

@@ -1,7 +1,7 @@
import { mdiPencil } from "@mdi/js";
import type { CSSResultGroup } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { property, state } from "lit/decorators";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../../common/dom/fire_event";
import "../../../components/entity/ha-entities-picker";
@@ -43,6 +43,7 @@ const cropOptions: CropOptions = {
aspectRatio: 1,
};
@customElement("dialog-person-detail")
class DialogPersonDetail extends LitElement implements HassDialog {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -567,5 +568,3 @@ declare global {
"dialog-person-detail": DialogPersonDetail;
}
}
customElements.define("dialog-person-detail", DialogPersonDetail);

View File

@@ -24,7 +24,7 @@ import { LitElement, css, html, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { computeCssColor } from "../../../common/color/compute-color";
import { formatShortDateTime } from "../../../common/datetime/format_date_time";
import { formatShortDateTimeWithConditionalYear } from "../../../common/datetime/format_date_time";
import { relativeTime } from "../../../common/datetime/relative_time";
import { storage } from "../../../common/decorators/storage";
import type { HASSDomEvent } from "../../../common/dom/fire_event";
@@ -301,10 +301,21 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
const date = new Date(scene.state);
const now = new Date();
const dayDifference = differenceInDays(now, date);
const formattedTime = formatShortDateTimeWithConditionalYear(
date,
this.hass.locale,
this.hass.config
);
const elementId = "last-activated-" + slugify(scene.entity_id);
return html`
${dayDifference > 3
? formatShortDateTime(date, this.hass.locale, this.hass.config)
: relativeTime(date, this.hass.locale)}
? formattedTime
: html`
<ha-tooltip for=${elementId}>${formattedTime}</ha-tooltip>
<span id=${elementId}
>${relativeTime(date, this.hass.locale)}</span
>
`}
`;
},
},

View File

@@ -1,3 +1,4 @@
import "@home-assistant/webawesome/dist/components/divider/divider";
import { consume } from "@lit/context";
import {
mdiAppleKeyboardCommand,
@@ -21,20 +22,21 @@ import {
} from "@mdi/js";
import type { CSSResultGroup, PropertyValues, TemplateResult } from "lit";
import { LitElement, css, html, nothing } from "lit";
import { property, query, state } from "lit/decorators";
import { customElement, property, query, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { UndoRedoController } from "../../../common/controllers/undo-redo-controller";
import { transform } from "../../../common/decorators/transform";
import { fireEvent } from "../../../common/dom/fire_event";
import { goBack, navigate } from "../../../common/navigate";
import { slugify } from "../../../common/string/slugify";
import { promiseTimeout } from "../../../common/util/promise-timeout";
import { afterNextRender } from "../../../common/util/render-status";
import "../../../components/ha-button";
import "../../../components/ha-button-menu";
import "../../../components/ha-dropdown";
import "../../../components/ha-dropdown-item";
import type { HaDropdownItem } from "../../../components/ha-dropdown-item";
import "../../../components/ha-fab";
import { transform } from "../../../common/decorators/transform";
import "../../../components/ha-icon-button";
import "../../../components/ha-list-item";
import "../../../components/ha-svg-icon";
import "../../../components/ha-yaml-editor";
import { substituteBlueprint } from "../../../data/blueprint";
@@ -65,7 +67,6 @@ import "../../../layouts/hass-subpage";
import { KeyboardShortcutMixin } from "../../../mixins/keyboard-shortcut-mixin";
import { PreventUnsavedMixin } from "../../../mixins/prevent-unsaved-mixin";
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
import { UndoRedoController } from "../../../common/controllers/undo-redo-controller";
import { haStyle } from "../../../resources/styles";
import type { Entries, HomeAssistant, Route } from "../../../types";
import { isMac } from "../../../util/is_mac";
@@ -73,12 +74,13 @@ import { showToast } from "../../../util/toast";
import { showAutomationModeDialog } from "../automation/automation-mode-dialog/show-dialog-automation-mode";
import type { EntityRegistryUpdate } from "../automation/automation-save-dialog/show-dialog-automation-save";
import { showAutomationSaveDialog } from "../automation/automation-save-dialog/show-dialog-automation-save";
import { showAutomationSaveTimeoutDialog } from "../automation/automation-save-timeout-dialog/show-dialog-automation-save-timeout";
import { showAssignCategoryDialog } from "../category/show-dialog-assign-category";
import "./blueprint-script-editor";
import "./manual-script-editor";
import type { HaManualScriptEditor } from "./manual-script-editor";
import { showAutomationSaveTimeoutDialog } from "../automation/automation-save-timeout-dialog/show-dialog-automation-save-timeout";
@customElement("ha-script-editor")
export class HaScriptEditor extends SubscribeMixin(
PreventUnsavedMixin(KeyboardShortcutMixin(LitElement))
) {
@@ -240,7 +242,10 @@ export class HaScriptEditor extends SubscribeMixin(
</ha-button>
`
: ""}
<ha-button-menu slot="toolbar-icon">
<ha-dropdown
slot="toolbar-icon"
@wa-select=${this._handleDropdownSelect}
>
<ha-icon-button
slot="trigger"
.label=${this.hass.localize("ui.common.menu")}
@@ -248,133 +253,107 @@ export class HaScriptEditor extends SubscribeMixin(
></ha-icon-button>
${this._mode === "gui" && this.narrow
? html`<ha-list-item
graphic="icon"
@click=${this._undo}
? html`<ha-dropdown-item
value="undo"
.disabled=${!this._undoRedoController.canUndo}
>
${this.hass.localize("ui.common.undo")}
<ha-svg-icon slot="graphic" .path=${mdiUndo}></ha-svg-icon>
</ha-list-item>
<ha-list-item
graphic="icon"
@click=${this._redo}
<ha-svg-icon slot="icon" .path=${mdiUndo}></ha-svg-icon>
</ha-dropdown-item>
<ha-dropdown-item
value="redo"
.disabled=${!this._undoRedoController.canRedo}
>
${this.hass.localize("ui.common.redo")}
<ha-svg-icon slot="graphic" .path=${mdiRedo}></ha-svg-icon>
</ha-list-item>`
<ha-svg-icon slot="icon" .path=${mdiRedo}></ha-svg-icon>
</ha-dropdown-item>`
: nothing}
<ha-list-item
graphic="icon"
.disabled=${!this.scriptId}
@click=${this._showInfo}
>
<ha-dropdown-item .disabled=${!this.scriptId} value="info">
${this.hass.localize("ui.panel.config.script.editor.show_info")}
<ha-svg-icon
slot="graphic"
slot="icon"
.path=${mdiInformationOutline}
></ha-svg-icon>
</ha-list-item>
</ha-dropdown-item>
<ha-list-item
graphic="icon"
.disabled=${!stateObj}
@click=${this._showSettings}
>
<ha-dropdown-item .disabled=${!stateObj} value="settings">
${this.hass.localize(
"ui.panel.config.automation.picker.show_settings"
)}
<ha-svg-icon slot="graphic" .path=${mdiCog}></ha-svg-icon>
</ha-list-item>
<ha-svg-icon slot="icon" .path=${mdiCog}></ha-svg-icon>
</ha-dropdown-item>
<ha-list-item
graphic="icon"
.disabled=${!stateObj}
@click=${this._editCategory}
>
<ha-dropdown-item .disabled=${!stateObj} value="category">
${this.hass.localize(
`ui.panel.config.scene.picker.${this._registryEntry?.categories?.script ? "edit_category" : "assign_category"}`
)}
<ha-svg-icon slot="graphic" .path=${mdiTag}></ha-svg-icon>
</ha-list-item>
<ha-svg-icon slot="icon" .path=${mdiTag}></ha-svg-icon>
</ha-dropdown-item>
<ha-list-item
graphic="icon"
.disabled=${!this.scriptId}
@click=${this._runScript}
>
<ha-dropdown-item .disabled=${!this.scriptId} value="run">
${this.hass.localize("ui.panel.config.script.picker.run_script")}
<ha-svg-icon slot="graphic" .path=${mdiPlay}></ha-svg-icon>
</ha-list-item>
<ha-svg-icon slot="icon" .path=${mdiPlay}></ha-svg-icon>
</ha-dropdown-item>
${this.scriptId && this.narrow
? html`
<a href="/config/script/trace/${this.scriptId}">
<ha-list-item graphic="icon">
${this.hass.localize(
"ui.panel.config.script.editor.show_trace"
)}
<ha-svg-icon
slot="graphic"
.path=${mdiTransitConnection}
></ha-svg-icon>
</ha-list-item>
</a>
`
? html`<ha-dropdown-item value="trace">
${this.hass.localize(
"ui.panel.config.automation.editor.show_trace"
)}
<ha-svg-icon
slot="icon"
.path=${mdiTransitConnection}
></ha-svg-icon>
</ha-dropdown-item>`
: nothing}
${!useBlueprint && !("fields" in this._config)
? html`
<ha-list-item
graphic="icon"
<ha-dropdown-item
.disabled=${this._readOnly || this._mode === "yaml"}
@click=${this._addFields}
value="add_fields"
>
${this.hass.localize(
"ui.panel.config.script.editor.field.add_fields"
)}
<ha-svg-icon
slot="graphic"
slot="icon"
.path=${mdiFormTextbox}
></ha-svg-icon>
</ha-list-item>
</ha-dropdown-item>
`
: nothing}
<ha-list-item
graphic="icon"
@click=${this._promptScriptAlias}
<ha-dropdown-item
value="rename"
.disabled=${!this.scriptId ||
this._readOnly ||
this._mode === "yaml"}
>
${this.hass.localize("ui.panel.config.script.editor.rename")}
<ha-svg-icon slot="graphic" .path=${mdiRenameBox}></ha-svg-icon>
</ha-list-item>
<ha-svg-icon slot="icon" .path=${mdiRenameBox}></ha-svg-icon>
</ha-dropdown-item>
${!useBlueprint
? html`
<ha-list-item
graphic="icon"
@click=${this._promptScriptMode}
<ha-dropdown-item
value="change_mode"
.disabled=${this._readOnly || this._mode === "yaml"}
>
${this.hass.localize(
"ui.panel.config.script.editor.change_mode"
)}
<ha-svg-icon
slot="graphic"
slot="icon"
.path=${mdiDebugStepOver}
></ha-svg-icon>
</ha-list-item>
</ha-dropdown-item>
`
: nothing}
<ha-list-item
.disabled=${this._blueprintConfig ||
<ha-dropdown-item
.disabled=${!!this._blueprintConfig ||
(!this._readOnly && !this.scriptId)}
graphic="icon"
@click=${this._duplicate}
value="duplicate"
>
${this.hass.localize(
this._readOnly
@@ -382,58 +361,48 @@ export class HaScriptEditor extends SubscribeMixin(
: "ui.panel.config.script.editor.duplicate"
)}
<ha-svg-icon
slot="graphic"
slot="icon"
.path=${mdiPlusCircleMultipleOutline}
></ha-svg-icon>
</ha-list-item>
</ha-dropdown-item>
${useBlueprint
? html`
<ha-list-item
graphic="icon"
@click=${this._takeControl}
<ha-dropdown-item
value="take_control"
.disabled=${this._readOnly}
>
${this.hass.localize(
"ui.panel.config.script.editor.take_control"
)}
<ha-svg-icon
slot="graphic"
.path=${mdiFileEdit}
></ha-svg-icon>
</ha-list-item>
<ha-svg-icon slot="icon" .path=${mdiFileEdit}></ha-svg-icon>
</ha-dropdown-item>
`
: nothing}
<ha-list-item
graphic="icon"
@click=${this._mode === "gui"
? this._switchYamlMode
: this._switchUiMode}
>
<ha-dropdown-item value="toggle_yaml_mode">
${this.hass.localize(
`ui.panel.config.automation.editor.edit_${this._mode === "gui" ? "yaml" : "ui"}`
)}
<ha-svg-icon slot="graphic" .path=${mdiPlaylistEdit}></ha-svg-icon>
</ha-list-item>
<ha-svg-icon slot="icon" .path=${mdiPlaylistEdit}></ha-svg-icon>
</ha-dropdown-item>
<li divider role="separator"></li>
<wa-divider></wa-divider>
<ha-list-item
<ha-dropdown-item
.disabled=${this._readOnly || !this.scriptId}
class=${classMap({ warning: Boolean(this.scriptId) })}
graphic="icon"
@click=${this._deleteConfirm}
value="delete"
.variant=${this.scriptId ? "danger" : "default"}
>
${this.hass.localize("ui.panel.config.script.picker.delete")}
<ha-svg-icon
class=${classMap({ warning: Boolean(this.scriptId) })}
slot="graphic"
slot="icon"
.path=${mdiDelete}
>
</ha-svg-icon>
</ha-list-item>
</ha-button-menu>
</ha-dropdown-item>
</ha-dropdown>
<div class=${this._mode === "yaml" ? "yaml-mode" : ""}>
${this._mode === "gui"
? html`
@@ -687,9 +656,7 @@ export class HaScriptEditor extends SubscribeMixin(
this._dirty = true;
}
private async _runScript(ev: CustomEvent) {
ev.stopPropagation();
private async _runScript() {
if (hasScriptFields(this.hass, this._entityId!)) {
showMoreInfoDialog(this, {
entityId: this._entityId!,
@@ -1154,6 +1121,63 @@ export class HaScriptEditor extends SubscribeMixin(
this._undoRedoController.redo();
}
private _handleDropdownSelect(ev: CustomEvent<{ item: HaDropdownItem }>) {
const action = ev.detail?.item?.value;
if (!action) {
return;
}
switch (action) {
case "undo":
this._undo();
break;
case "redo":
this._redo();
break;
case "info":
this._showInfo();
break;
case "settings":
this._showSettings();
break;
case "category":
this._editCategory();
break;
case "run":
this._runScript();
break;
case "add_fields":
this._addFields();
break;
case "rename":
this._promptScriptAlias();
break;
case "change_mode":
this._promptScriptMode();
break;
case "duplicate":
this._duplicate();
break;
case "take_control":
this._takeControl();
break;
case "toggle_yaml_mode":
if (this._mode === "gui") {
this._switchYamlMode();
break;
}
this._switchUiMode();
break;
case "delete":
this._deleteConfirm();
break;
case "trace":
this._showTrace();
break;
}
}
static get styles(): CSSResultGroup {
return [
haStyle,
@@ -1244,9 +1268,6 @@ export class HaScriptEditor extends SubscribeMixin(
ha-fab.dirty {
bottom: calc(16px + var(--safe-area-inset-bottom, 0px));
}
li[role="separator"] {
border-bottom-color: var(--divider-color);
}
.header {
display: flex;
margin: 16px 0;
@@ -1260,10 +1281,6 @@ export class HaScriptEditor extends SubscribeMixin(
.header a {
color: var(--secondary-text-color);
}
ha-button-menu a {
text-decoration: none;
color: var(--primary-color);
}
ha-tooltip ha-svg-icon {
width: 12px;
}
@@ -1278,8 +1295,6 @@ export class HaScriptEditor extends SubscribeMixin(
}
}
customElements.define("ha-script-editor", HaScriptEditor);
declare global {
interface HTMLElementTagNameMap {
"ha-script-editor": HaScriptEditor;

View File

@@ -15,18 +15,19 @@ import type { LocalizeKeys } from "../../../common/translations/localize";
import "../../../components/ha-automation-row";
import type { HaAutomationRow } from "../../../components/ha-automation-row";
import "../../../components/ha-card";
import "../../../components/ha-md-button-menu";
import "../../../components/ha-md-menu-item";
import "../../../components/ha-dropdown";
import "../../../components/ha-dropdown-item";
import type { HaDropdownItem } from "../../../components/ha-dropdown-item";
import type { ScriptFieldSidebarConfig } from "../../../data/automation";
import type { Field } from "../../../data/script";
import { SELECTOR_SELECTOR_BUILDING_BLOCKS } from "../../../data/selector/selector_selector";
import { haStyle } from "../../../resources/styles";
import type { HomeAssistant } from "../../../types";
import { isMac } from "../../../util/is_mac";
import { showToast } from "../../../util/toast";
import { indentStyle, overflowStyles } from "../automation/styles";
import "./ha-script-field-selector-editor";
import type HaScriptFieldSelectorEditor from "./ha-script-field-selector-editor";
import { showToast } from "../../../util/toast";
@customElement("ha-script-field-row")
export default class HaScriptFieldRow extends LitElement {
@@ -79,36 +80,33 @@ export default class HaScriptFieldRow extends LitElement {
.highlight=${this.highlight}
@delete-row=${this._onDelete}
>
<ha-md-button-menu
quick
<ha-dropdown
slot="icons"
@click=${preventDefaultStopPropagation}
@keydown=${stopPropagation}
@closed=${stopPropagation}
positioning="fixed"
anchor-corner="end-end"
menu-corner="start-end"
@wa-select=${this._handleDropdownSelect}
placement="bottom-end"
>
<ha-icon-button
slot="trigger"
.label=${this.hass.localize("ui.common.menu")}
.path=${mdiDotsVertical}
></ha-icon-button>
<ha-md-menu-item .clickAction=${this._toggleYamlMode}>
<ha-svg-icon slot="start" .path=${mdiPlaylistEdit}></ha-svg-icon>
<ha-dropdown-item value="toggle_yaml_mode">
<ha-svg-icon slot="icon" .path=${mdiPlaylistEdit}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
`ui.panel.config.automation.editor.edit_${!this._yamlMode ? "yaml" : "ui"}`
)}
<span class="shortcut-placeholder ${isMac ? "mac" : ""}"></span>
</div>
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._onDelete}
</ha-dropdown-item>
<ha-dropdown-item
value="delete"
.disabled=${this.disabled}
class="warning"
variant="danger"
>
<ha-svg-icon slot="start" .path=${mdiDelete}></ha-svg-icon>
<ha-svg-icon slot="icon" .path=${mdiDelete}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
"ui.panel.config.automation.editor.actions.delete"
@@ -118,7 +116,6 @@ export default class HaScriptFieldRow extends LitElement {
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
@@ -134,8 +131,8 @@ export default class HaScriptFieldRow extends LitElement {
</span>`
: nothing}
</div>
</ha-md-menu-item>
</ha-md-button-menu>
</ha-dropdown-item>
</ha-dropdown>
<h3 slot="header">${this.key}</h3>
@@ -170,27 +167,21 @@ export default class HaScriptFieldRow extends LitElement {
"ui.panel.config.script.editor.field.selector"
)}
</h3>
<ha-md-button-menu
quick
<ha-dropdown
slot="icons"
@click=${preventDefaultStopPropagation}
@keydown=${stopPropagation}
@closed=${stopPropagation}
positioning="fixed"
anchor-corner="end-end"
menu-corner="start-end"
@wa-select=${this._handleDropdownSelect}
placement="bottom-end"
>
<ha-icon-button
slot="trigger"
.label=${this.hass.localize("ui.common.menu")}
.path=${mdiDotsVertical}
></ha-icon-button>
<ha-md-menu-item
.clickAction=${this._toggleYamlMode}
selector-row
>
<ha-dropdown-item value="toggle_yaml_mode" selector-row>
<ha-svg-icon
slot="start"
slot="icon"
.path=${mdiPlaylistEdit}
></ha-svg-icon>
<div class="overflow-label">
@@ -201,16 +192,13 @@ export default class HaScriptFieldRow extends LitElement {
class="shortcut-placeholder ${isMac ? "mac" : ""}"
></span>
</div>
</ha-md-menu-item>
<ha-md-menu-item
.clickAction=${this._onDelete}
</ha-dropdown-item>
<ha-dropdown-item
value="delete"
.disabled=${this.disabled}
class="warning"
variant="danger"
>
<ha-svg-icon
slot="start"
.path=${mdiDelete}
></ha-svg-icon>
<ha-svg-icon slot="icon" .path=${mdiDelete}></ha-svg-icon>
<div class="overflow-label">
${this.hass.localize(
"ui.panel.config.automation.editor.actions.delete"
@@ -220,7 +208,6 @@ export default class HaScriptFieldRow extends LitElement {
<span
>${isMac
? html`<ha-svg-icon
slot="start"
.path=${mdiAppleKeyboardCommand}
></ha-svg-icon>`
: this.hass.localize(
@@ -236,8 +223,8 @@ export default class HaScriptFieldRow extends LitElement {
</span>`
: nothing}
</div>
</ha-md-menu-item>
</ha-md-button-menu>
</ha-dropdown-item>
</ha-dropdown>
</ha-automation-row>
</ha-card>
${typeof this.field.selector === "object" &&
@@ -420,6 +407,23 @@ export default class HaScriptFieldRow extends LitElement {
this._selectorRowElement?.focus();
}
private _handleDropdownSelect(ev: CustomEvent<{ item: HaDropdownItem }>) {
const action = ev.detail?.item?.value;
if (!action) {
return;
}
switch (action) {
case "toggle_yaml_mode":
this._toggleYamlMode(ev.target as HTMLElement);
break;
case "delete":
this._onDelete();
break;
}
}
static get styles(): CSSResultGroup {
return [
haStyle,
@@ -477,9 +481,6 @@ export default class HaScriptFieldRow extends LitElement {
.selected_menu_item {
color: var(--primary-color);
}
li[role="separator"] {
border-bottom-color: var(--divider-color);
}
.selector-row {
padding-top: 12px;
padding-bottom: 16px;

View File

@@ -33,6 +33,8 @@ import type { HASSDomEvent } from "../../../common/dom/fire_event";
import { fireEvent } from "../../../common/dom/fire_event";
import { computeStateName } from "../../../common/entity/compute_state_name";
import { navigate } from "../../../common/navigate";
import { slugify } from "../../../common/string/slugify";
import "../../../components/ha-tooltip";
import type { LocalizeFunc } from "../../../common/translations/localize";
import {
hasRejectedItems,
@@ -302,19 +304,27 @@ class HaScriptPicker extends SubscribeMixin(LitElement) {
sortable: true,
title: localize("ui.card.automation.last_triggered"),
template: (script) => {
if (!script.last_triggered) {
return this.hass.localize("ui.components.relative_time.never");
}
const date = new Date(script.last_triggered);
const now = new Date();
const dayDifference = differenceInDays(now, date);
const formattedTime = formatShortDateTimeWithConditionalYear(
date,
this.hass.locale,
this.hass.config
);
const elementId = "last-triggered-" + slugify(script.entity_id);
return html`
${script.last_triggered
? dayDifference > 3
? formatShortDateTimeWithConditionalYear(
date,
this.hass.locale,
this.hass.config
)
: relativeTime(date, this.hass.locale)
: this.hass.localize("ui.components.relative_time.never")}
${dayDifference > 3
? formattedTime
: html`
<ha-tooltip for=${elementId}>${formattedTime}</ha-tooltip>
<span id=${elementId}
>${relativeTime(date, this.hass.locale)}</span
>
`}
`;
},
},

View File

@@ -1,3 +1,4 @@
import "@home-assistant/webawesome/dist/components/divider/divider";
import {
mdiDotsVertical,
mdiDownload,
@@ -8,17 +9,19 @@ import {
mdiRefresh,
} from "@mdi/js";
import type { CSSResultGroup, TemplateResult } from "lit";
import { css, html, LitElement } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { repeat } from "lit/directives/repeat";
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
import { formatDateTimeWithSeconds } from "../../../common/datetime/format_date_time";
import { fireEvent } from "../../../common/dom/fire_event";
import "../../../components/ha-button-menu";
import { navigate } from "../../../common/navigate";
import "../../../components/ha-button";
import "../../../components/ha-dropdown";
import "../../../components/ha-dropdown-item";
import type { HaDropdownItem } from "../../../components/ha-dropdown-item";
import "../../../components/ha-icon-button";
import "../../../components/ha-list-item";
import "../../../components/trace/ha-trace-blueprint-config";
import "../../../components/trace/ha-trace-config";
import "../../../components/trace/ha-trace-logbook";
@@ -104,7 +107,7 @@ export class HaScriptTrace extends LitElement {
? html`
<ha-button
class="trace-link"
href="/config/script/edit/${this.scriptId}"
@click=${this._navigateToScript}
slot="toolbar-icon"
appearance="plain"
>
@@ -113,64 +116,49 @@ export class HaScriptTrace extends LitElement {
)}
</ha-button>
`
: ""}
: nothing}
<ha-button-menu slot="toolbar-icon">
<ha-dropdown
slot="toolbar-icon"
@wa-select=${this._handleDropdownSelect}
>
<ha-icon-button
slot="trigger"
.label=${this.hass.localize("ui.common.menu")}
.path=${mdiDotsVertical}
></ha-icon-button>
<ha-list-item
graphic="icon"
.disabled=${!stateObj}
@click=${this._showInfo}
>
<ha-dropdown-item .disabled=${!stateObj} value="show_info">
${this.hass.localize("ui.panel.config.script.editor.show_info")}
<ha-svg-icon
slot="graphic"
slot="icon"
.path=${mdiInformationOutline}
></ha-svg-icon>
</ha-list-item>
</ha-dropdown-item>
${this.narrow && this.scriptId
? html`
<a
class="trace-link"
href="/config/script/edit/${this.scriptId}"
>
<ha-list-item graphic="icon">
${this.hass.localize(
"ui.panel.config.script.trace.edit_script"
)}
<ha-svg-icon
slot="graphic"
.path=${mdiPencil}
></ha-svg-icon>
</ha-list-item>
</a>
`
: ""}
? html`<ha-dropdown-item value="edit_script">
${this.hass.localize(
"ui.panel.config.script.trace.edit_script"
)}
<ha-svg-icon slot="icon" .path=${mdiPencil}></ha-svg-icon>
</ha-dropdown-item> `
: nothing}
<li divider role="separator"></li>
<wa-divider></wa-divider>
<ha-list-item graphic="icon" @click=${this._refreshTraces}>
<ha-dropdown-item value="refresh">
${this.hass.localize("ui.panel.config.automation.trace.refresh")}
<ha-svg-icon slot="graphic" .path=${mdiRefresh}></ha-svg-icon>
</ha-list-item>
<ha-svg-icon slot="icon" .path=${mdiRefresh}></ha-svg-icon>
</ha-dropdown-item>
<ha-list-item
graphic="icon"
.disabled=${!this._trace}
@click=${this._downloadTrace}
>
<ha-dropdown-item .disabled=${!this._trace} value="download_trace">
${this.hass.localize(
"ui.panel.config.automation.trace.download_trace"
)}
<ha-svg-icon slot="graphic" .path=${mdiDownload}></ha-svg-icon>
</ha-list-item>
</ha-button-menu>
<ha-svg-icon slot="icon" .path=${mdiDownload}></ha-svg-icon>
</ha-dropdown-item>
</ha-dropdown>
<div class="toolbar">
${this._traces && this._traces.length > 0
@@ -530,6 +518,35 @@ export class HaScriptTrace extends LitElement {
fireEvent(this, "hass-more-info", { entityId: this._entityId });
}
private _navigateToScript() {
if (this.scriptId) {
navigate(`/config/script/edit/${this.scriptId}`);
}
}
private _handleDropdownSelect(ev: CustomEvent<{ item: HaDropdownItem }>) {
const action = ev.detail?.item?.value;
if (!action) {
return;
}
switch (action) {
case "show_info":
this._showInfo();
break;
case "refresh":
this._refreshTraces();
break;
case "download_trace":
this._downloadTrace();
break;
case "edit_script":
this._navigateToScript();
break;
}
}
static get styles(): CSSResultGroup {
return [
haStyle,

View File

@@ -1,6 +1,6 @@
import { mdiHelpCircle } from "@mdi/js";
import { css, html, LitElement, nothing } from "lit";
import { property, state } from "lit/decorators";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../../common/dom/fire_event";
import { isEmptyEntityDomainFilter } from "../../../common/entity/entity_domain_filter";
@@ -20,6 +20,7 @@ import {
import type { HomeAssistant } from "../../../types";
import { brandsUrl } from "../../../util/brands-url";
@customElement("cloud-alexa-pref")
export class CloudAlexaPref extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -297,5 +298,3 @@ declare global {
"cloud-alexa-pref": CloudAlexaPref;
}
}
customElements.define("cloud-alexa-pref", CloudAlexaPref);

View File

@@ -1,6 +1,6 @@
import { mdiHelpCircle } from "@mdi/js";
import { css, html, LitElement, nothing } from "lit";
import { property, state } from "lit/decorators";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../../common/dom/fire_event";
import { isEmptyEntityDomainFilter } from "../../../common/entity/entity_domain_filter";
@@ -23,6 +23,7 @@ import type { HomeAssistant } from "../../../types";
import { brandsUrl } from "../../../util/brands-url";
import { showSaveSuccessToast } from "../../../util/toast-saved-success";
@customElement("cloud-google-pref")
export class CloudGooglePref extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -367,5 +368,3 @@ declare global {
"cloud-google-pref": CloudGooglePref;
}
}
customElements.define("cloud-google-pref", CloudGooglePref);

View File

@@ -1,6 +1,6 @@
import type { CSSResultGroup } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { property, state } from "lit/decorators";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../../common/dom/fire_event";
import { createCloseHeading } from "../../../components/ha-dialog";
@@ -19,6 +19,7 @@ const SCHEMA = [
},
];
@customElement("dialog-home-zone-detail")
class DialogHomeZoneDetail extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -151,5 +152,3 @@ declare global {
"dialog-home-zone-detail": DialogHomeZoneDetail;
}
}
customElements.define("dialog-home-zone-detail", DialogHomeZoneDetail);

View File

@@ -1,6 +1,6 @@
import type { CSSResultGroup } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { property, state } from "lit/decorators";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../../common/dom/fire_event";
import { addDistanceToCoord } from "../../../common/location/add_distance_to_coord";
@@ -14,6 +14,7 @@ import { haStyleDialog } from "../../../resources/styles";
import type { HomeAssistant } from "../../../types";
import type { ZoneDetailDialogParams } from "./show-dialog-zone-detail";
@customElement("dialog-zone-detail")
class DialogZoneDetail extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -241,5 +242,3 @@ declare global {
"dialog-zone-detail": DialogZoneDetail;
}
}
customElements.define("dialog-zone-detail", DialogZoneDetail);

View File

@@ -1,6 +1,6 @@
import type { PropertyValues } from "lit";
import { ReactiveElement } from "lit";
import { property } from "lit/decorators";
import { customElement, property } from "lit/decorators";
import type { NavigateOptions } from "../../common/navigate";
import { navigate } from "../../common/navigate";
import { deepEqual } from "../../common/util/deep-equal";
@@ -22,6 +22,7 @@ declare global {
}
}
@customElement("ha-panel-custom")
export class HaPanelCustom extends ReactiveElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@@ -171,5 +172,3 @@ export class HaPanelCustom extends ReactiveElement {
iframeDoc.close();
}
}
customElements.define("ha-panel-custom", HaPanelCustom);

View File

@@ -1,7 +1,7 @@
import { mdiHelpCircle } from "@mdi/js";
import type { HassService } from "home-assistant-js-websocket";
import { ERR_CONNECTION_LOST } from "home-assistant-js-websocket";
import { load } from "js-yaml";
import { dump, load } from "js-yaml";
import type { CSSResultGroup, TemplateResult } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
@@ -320,7 +320,10 @@ class HaPanelDevAction extends LitElement {
${this.hass.localize(
`component.${domain}.services.${serviceName}.fields.${field.key}.example`,
descriptionPlaceholders
) || field.example}
) ||
(typeof field.example === "object"
? html`<pre>${dump(field.example)}</pre>`
: field.example)}
</td>
</tr>`
)}

View File

@@ -547,9 +547,9 @@ class HaPanelDevStatistics extends KeyboardShortcutMixin(LitElement) {
} else if (this._sortDirection === "asc") {
this._sortDirection = "desc";
} else {
this._sortDirection = null;
this._sortDirection = "asc";
}
this._sortColumn = this._sortDirection === null ? undefined : columnId;
this._sortColumn = columnId;
}
private _handleGroupBy(ev) {

View File

@@ -268,8 +268,10 @@ class PanelEnergy extends LitElement {
(source) => source.type === "gas"
);
const hasDeviceConsumption = this._prefs.device_consumption.length > 0;
const views: LovelaceViewConfig[] = [];
if (hasEnergy) {
if (hasEnergy || hasDeviceConsumption) {
views.push(ENERGY_VIEW);
}
if (hasGas) {

View File

@@ -8,14 +8,6 @@ import type { LovelaceStrategyConfig } from "../../../data/lovelace/config/strat
import type { LovelaceSectionConfig } from "../../../data/lovelace/config/section";
import { DEFAULT_ENERGY_COLLECTION_KEY } from "../ha-panel-energy";
const sourceHasCost = (source: Record<string, any>): boolean =>
Boolean(
source.stat_cost ||
source.stat_compensation ||
source.entity_energy_price ||
source.number_energy_price
);
@customElement("energy-overview-view-strategy")
export class EnergyOverviewViewStrategy extends ReactiveElement {
static async generate(
@@ -68,13 +60,6 @@ export class EnergyOverviewViewStrategy extends ReactiveElement {
(source.type === "battery" && source.stat_rate) ||
(source.type === "grid" && source.power?.length)
);
const hasCost = prefs.energy_sources.some(
(source) =>
sourceHasCost(source) ||
(source.type === "grid" &&
(source.flow_from?.some(sourceHasCost) ||
source.flow_to?.some(sourceHasCost)))
);
const overviewSection: LovelaceSectionConfig = {
type: "grid",
@@ -95,7 +80,7 @@ export class EnergyOverviewViewStrategy extends ReactiveElement {
}
view.sections!.push(overviewSection);
if (hasCost) {
if (prefs.energy_sources.length) {
view.sections!.push({
type: "grid",
cards: [

View File

@@ -12,7 +12,7 @@ import type {
} from "home-assistant-js-websocket/dist/types";
import type { PropertyValues } from "lit";
import { LitElement, css, html } from "lit";
import { property, query, state } from "lit/decorators";
import { customElement, property, query, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { ensureArray } from "../../common/array/ensure-array";
import { storage } from "../../common/decorators/storage";
@@ -52,6 +52,7 @@ import type { HomeAssistant } from "../../types";
import { fileDownload } from "../../util/file_download";
import { addEntitiesToLovelaceView } from "../lovelace/editor/add-entities-to-view";
@customElement("ha-panel-history")
class HaPanelHistory extends LitElement {
@property({ attribute: false }) hass!: HomeAssistant;
@@ -679,8 +680,6 @@ class HaPanelHistory extends LitElement {
}
}
customElements.define("ha-panel-history", HaPanelHistory);
declare global {
interface HTMLElementTagNameMap {
"ha-panel-history": HaPanelHistory;

View File

@@ -62,9 +62,7 @@ class HuiAlarmModeCardFeature
}
public static async getConfigElement(): Promise<LovelaceCardFeatureEditor> {
await import(
"../editor/config-elements/hui-alarm-modes-card-feature-editor"
);
await import("../editor/config-elements/hui-alarm-modes-card-feature-editor");
return document.createElement("hui-alarm-modes-card-feature-editor");
}

View File

@@ -142,9 +142,7 @@ class HuiAreaControlsCardFeature
}
public static async getConfigElement(): Promise<LovelaceCardFeatureEditor> {
await import(
"../editor/config-elements/hui-area-controls-card-feature-editor"
);
await import("../editor/config-elements/hui-area-controls-card-feature-editor");
return document.createElement("hui-area-controls-card-feature-editor");
}

View File

@@ -71,9 +71,7 @@ class HuiClimateFanModesCardFeature
}
public static async getConfigElement(): Promise<LovelaceCardFeatureEditor> {
await import(
"../editor/config-elements/hui-climate-fan-modes-card-feature-editor"
);
await import("../editor/config-elements/hui-climate-fan-modes-card-feature-editor");
return document.createElement("hui-climate-fan-modes-card-feature-editor");
}

View File

@@ -70,9 +70,7 @@ class HuiClimateHvacModesCardFeature
}
public static async getConfigElement(): Promise<LovelaceCardFeatureEditor> {
await import(
"../editor/config-elements/hui-climate-hvac-modes-card-feature-editor"
);
await import("../editor/config-elements/hui-climate-hvac-modes-card-feature-editor");
return document.createElement("hui-climate-hvac-modes-card-feature-editor");
}

View File

@@ -71,9 +71,7 @@ class HuiClimatePresetModesCardFeature
}
public static async getConfigElement(): Promise<LovelaceCardFeatureEditor> {
await import(
"../editor/config-elements/hui-climate-preset-modes-card-feature-editor"
);
await import("../editor/config-elements/hui-climate-preset-modes-card-feature-editor");
return document.createElement(
"hui-climate-preset-modes-card-feature-editor"
);

View File

@@ -71,9 +71,7 @@ class HuiClimateSwingHorizontalModesCardFeature
}
public static async getConfigElement(): Promise<LovelaceCardFeatureEditor> {
await import(
"../editor/config-elements/hui-climate-swing-horizontal-modes-card-feature-editor"
);
await import("../editor/config-elements/hui-climate-swing-horizontal-modes-card-feature-editor");
return document.createElement(
"hui-climate-swing-horizontal-modes-card-feature-editor"
);

View File

@@ -71,9 +71,7 @@ class HuiClimateSwingModesCardFeature
}
public static async getConfigElement(): Promise<LovelaceCardFeatureEditor> {
await import(
"../editor/config-elements/hui-climate-swing-modes-card-feature-editor"
);
await import("../editor/config-elements/hui-climate-swing-modes-card-feature-editor");
return document.createElement(
"hui-climate-swing-modes-card-feature-editor"
);

View File

@@ -79,9 +79,7 @@ class HuiCounterActionsCardFeature
}
public static async getConfigElement(): Promise<LovelaceCardFeatureEditor> {
await import(
"../editor/config-elements/hui-counter-actions-card-feature-editor"
);
await import("../editor/config-elements/hui-counter-actions-card-feature-editor");
return document.createElement("hui-counter-actions-card-feature-editor");
}

View File

@@ -68,9 +68,7 @@ class HuiFanPresetModesCardFeature
}
public static async getConfigElement(): Promise<LovelaceCardFeatureEditor> {
await import(
"../editor/config-elements/hui-fan-preset-modes-card-feature-editor"
);
await import("../editor/config-elements/hui-fan-preset-modes-card-feature-editor");
return document.createElement("hui-fan-preset-modes-card-feature-editor");
}

View File

@@ -71,9 +71,7 @@ class HuiHumidifierModesCardFeature
}
public static async getConfigElement(): Promise<LovelaceCardFeatureEditor> {
await import(
"../editor/config-elements/hui-humidifier-modes-card-feature-editor"
);
await import("../editor/config-elements/hui-humidifier-modes-card-feature-editor");
return document.createElement("hui-humidifier-modes-card-feature-editor");
}

View File

@@ -128,9 +128,7 @@ class HuiLawnMowerCommandCardFeature
}
public static async getConfigElement(): Promise<LovelaceCardFeatureEditor> {
await import(
"../editor/config-elements/hui-lawn-mower-commands-card-feature-editor"
);
await import("../editor/config-elements/hui-lawn-mower-commands-card-feature-editor");
return document.createElement(
"hui-lawn-mower-commands-card-feature-editor"
);

View File

@@ -60,9 +60,7 @@ class HuiMediaPlayerVolumeButtonsCardFeature
}
public static async getConfigElement(): Promise<LovelaceCardFeatureEditor> {
await import(
"../editor/config-elements/hui-media-player-volume-buttons-card-feature-editor"
);
await import("../editor/config-elements/hui-media-player-volume-buttons-card-feature-editor");
return document.createElement(
"hui-media-player-volume-buttons-card-feature-editor"
);

View File

@@ -57,9 +57,7 @@ class HuiNumericInputCardFeature
}
public static async getConfigElement(): Promise<LovelaceCardFeatureEditor> {
await import(
"../editor/config-elements/hui-numeric-input-card-feature-editor"
);
await import("../editor/config-elements/hui-numeric-input-card-feature-editor");
return document.createElement("hui-numeric-input-card-feature-editor");
}

View File

@@ -64,9 +64,7 @@ class HuiSelectOptionsCardFeature
}
public static async getConfigElement(): Promise<LovelaceCardFeatureEditor> {
await import(
"../editor/config-elements/hui-select-options-card-feature-editor"
);
await import("../editor/config-elements/hui-select-options-card-feature-editor");
return document.createElement("hui-select-options-card-feature-editor");
}

View File

@@ -54,9 +54,7 @@ class HuiHistoryChartCardFeature
}
public static async getConfigElement(): Promise<LovelaceCardFeatureEditor> {
await import(
"../editor/config-elements/hui-trend-graph-card-feature-editor"
);
await import("../editor/config-elements/hui-trend-graph-card-feature-editor");
return document.createElement("hui-trend-graph-card-feature-editor");
}

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