diff --git a/.github/dependabot.yml b/.github/dependabot.yml index b7b4ca2ddc..44500cfd3c 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,3 +6,6 @@ updates: interval: weekly time: "06:00" open-pull-requests-limit: 10 + labels: + - Dependencies + - GitHub Actions diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000000..0ad85a9bb6 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,31 @@ +Build: + - build-scripts/** + - .browserslistrc + - gulpfile.js + +Cast: + - cast/src/** + - src/cast/** + +Demo: + - demo/src/** + - src/fake_data/** + +Design: + - gallery/src/** + - src/fake_data/** + +Dependencies: + - package.json + - renovate.json + - yarn.lock + - .yarn/** + - .yarnrc.yml + - .nvmrc + +GitHub Actions: + - .github/workflows/** + - .github/*.yml + +Supervisor: + - hassio/src/** diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index 0d507d1104..26ef3a0753 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -1,8 +1,8 @@ categories: - - title: 'Dependency updates' + - title: "Dependency updates" collapse-after: 3 labels: - - 'dependencies' + - "Dependencies" template: | ## What's Changed diff --git a/.github/workflows/cast_deployment.yaml b/.github/workflows/cast_deployment.yaml index 120658dd0c..b1cde578e8 100644 --- a/.github/workflows/cast_deployment.yaml +++ b/.github/workflows/cast_deployment.yaml @@ -26,7 +26,7 @@ jobs: ref: dev - name: Setup Node - uses: actions/setup-node@v3.6.0 + uses: actions/setup-node@v3.7.0 with: node-version-file: ".nvmrc" cache: yarn @@ -62,7 +62,7 @@ jobs: ref: master - name: Setup Node - uses: actions/setup-node@v3.6.0 + uses: actions/setup-node@v3.7.0 with: node-version-file: ".nvmrc" cache: yarn diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 16656927e6..a7a7da4f92 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -26,7 +26,7 @@ jobs: - name: Check out files from GitHub uses: actions/checkout@v3.5.3 - name: Setup Node - uses: actions/setup-node@v3.6.0 + uses: actions/setup-node@v3.7.0 with: node-version-file: ".nvmrc" cache: yarn @@ -36,6 +36,14 @@ jobs: run: yarn dedupe --check - name: Build resources run: ./node_modules/.bin/gulp gen-icons-json build-translations build-locale-data gather-gallery-pages + - name: Setup lint cache + uses: actions/cache@v3.3.1 + with: + path: | + node_modules/.cache/prettier + node_modules/.cache/eslint + key: lint-${{ github.sha }} + restore-keys: lint- - name: Run eslint run: yarn run lint:eslint --quiet - name: Run tsc @@ -49,7 +57,7 @@ jobs: - name: Check out files from GitHub uses: actions/checkout@v3.5.3 - name: Setup Node - uses: actions/setup-node@v3.6.0 + uses: actions/setup-node@v3.7.0 with: node-version-file: ".nvmrc" cache: yarn @@ -67,7 +75,7 @@ jobs: - name: Check out files from GitHub uses: actions/checkout@v3.5.3 - name: Setup Node - uses: actions/setup-node@v3.6.0 + uses: actions/setup-node@v3.7.0 with: node-version-file: ".nvmrc" cache: yarn @@ -85,7 +93,7 @@ jobs: - name: Check out files from GitHub uses: actions/checkout@v3.5.3 - name: Setup Node - uses: actions/setup-node@v3.6.0 + uses: actions/setup-node@v3.7.0 with: node-version-file: ".nvmrc" cache: yarn diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index fda71956ed..bd200e208e 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -17,44 +17,44 @@ jobs: matrix: # Override automatic language detection by changing the below list # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] - language: ['javascript'] + language: ["javascript"] # Learn more... # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection steps: - - name: Checkout repository - uses: actions/checkout@v3.5.3 - with: - # We must fetch at least the immediate parents so that if this is - # a pull request then we can checkout the head. - fetch-depth: 2 + - name: Checkout repository + uses: actions/checkout@v3.5.3 + with: + # We must fetch at least the immediate parents so that if this is + # a pull request then we can checkout the head. + fetch-depth: 2 - # If this run was triggered by a pull request event, then checkout - # the head of the pull request instead of the merge commit. - - run: git checkout HEAD^2 - if: ${{ github.event_name == 'pull_request' }} + # If this run was triggered by a pull request event, then checkout + # the head of the pull request instead of the merge commit. + - run: git checkout HEAD^2 + if: ${{ github.event_name == 'pull_request' }} - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + 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@v2 + # 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@v2 - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language - #- run: | - # make bootstrap - # make release + #- run: | + # make bootstrap + # make release - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/demo_deployment.yaml b/.github/workflows/demo_deployment.yaml index 77c4b98f5c..cbf8b92d88 100644 --- a/.github/workflows/demo_deployment.yaml +++ b/.github/workflows/demo_deployment.yaml @@ -27,7 +27,7 @@ jobs: ref: dev - name: Setup Node - uses: actions/setup-node@v3.6.0 + uses: actions/setup-node@v3.7.0 with: node-version-file: ".nvmrc" cache: yarn @@ -63,7 +63,7 @@ jobs: ref: master - name: Setup Node - uses: actions/setup-node@v3.6.0 + uses: actions/setup-node@v3.7.0 with: node-version-file: ".nvmrc" cache: yarn diff --git a/.github/workflows/design_deployment.yaml b/.github/workflows/design_deployment.yaml index 8b5aec8a39..096dfd752b 100644 --- a/.github/workflows/design_deployment.yaml +++ b/.github/workflows/design_deployment.yaml @@ -19,7 +19,7 @@ jobs: uses: actions/checkout@v3.5.3 - name: Setup Node - uses: actions/setup-node@v3.6.0 + uses: actions/setup-node@v3.7.0 with: node-version-file: ".nvmrc" cache: yarn diff --git a/.github/workflows/design_preview.yaml b/.github/workflows/design_preview.yaml index a257f9ec98..d5b5bde6fd 100644 --- a/.github/workflows/design_preview.yaml +++ b/.github/workflows/design_preview.yaml @@ -24,7 +24,7 @@ jobs: uses: actions/checkout@v3.5.3 - name: Setup Node - uses: actions/setup-node@v3.6.0 + uses: actions/setup-node@v3.7.0 with: node-version-file: ".nvmrc" cache: yarn diff --git a/.github/workflows/labeler.yaml b/.github/workflows/labeler.yaml new file mode 100644 index 0000000000..166fcb1aa8 --- /dev/null +++ b/.github/workflows/labeler.yaml @@ -0,0 +1,15 @@ +name: "Pull Request Labeler" + +on: pull_request_target + +jobs: + triage: + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + steps: + - name: Apply labels + uses: actions/labeler@v4.3.0 + with: + sync-labels: true diff --git a/.github/workflows/nightly.yaml b/.github/workflows/nightly.yaml index 76f0415496..70c397083e 100644 --- a/.github/workflows/nightly.yaml +++ b/.github/workflows/nightly.yaml @@ -28,7 +28,7 @@ jobs: python-version: ${{ env.PYTHON_VERSION }} - name: Setup Node - uses: actions/setup-node@v3.6.0 + uses: actions/setup-node@v3.7.0 with: node-version-file: ".nvmrc" cache: yarn diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index a269b30074..9c181a1690 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -34,7 +34,7 @@ jobs: python-version: ${{ env.PYTHON_VERSION }} - name: Setup Node - uses: actions/setup-node@v3.6.0 + uses: actions/setup-node@v3.7.0 with: node-version-file: ".nvmrc" cache: yarn diff --git a/.prettierignore b/.prettierignore index 68fe46e32c..bd7a779fea 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,9 +1,3 @@ -build -translations/* -node_modules/* -hass_frontend/* -pip-selfcheck.json - -# vscode -.vscode/* -!.vscode/extensions.json +CLA.md +CODE_OF_CONDUCT.md +LICENSE.md diff --git a/.vscode/launch.json b/.vscode/launch.json index e3be0de9c7..9b3f7b48ad 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,9 +9,7 @@ "webRoot": "${workspaceFolder}/hass_frontend", "disableNetworkCache": true, "preLaunchTask": "Develop Frontend", - "outFiles": [ - "${workspaceFolder}/hass_frontend/frontend_latest/*.js" - ] + "outFiles": ["${workspaceFolder}/hass_frontend/frontend_latest/*.js"] }, { "name": "Debug Gallery", @@ -39,6 +37,6 @@ "webRoot": "${workspaceFolder}/cast/dist", "disableNetworkCache": true, "preLaunchTask": "Develop Cast" - }, + } ] } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 5e5bddec9c..91f8252e8f 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -197,7 +197,7 @@ "type": "gulp", "task": "setup-and-fetch-nightly-translations", "problemMatcher": [] - } + } ], "inputs": [ { diff --git a/build-scripts/gulp/download-translations.js b/build-scripts/gulp/download-translations.js index 9c2f2ddd12..a8cf9b536b 100644 --- a/build-scripts/gulp/download-translations.js +++ b/build-scripts/gulp/download-translations.js @@ -68,6 +68,7 @@ gulp.task("convert-backend-translations", function () { }); gulp.task("check-translations-html", function () { + // We exclude backend translations because they are not compliant with the HTML rule for now return gulp.src([`${inDirFrontend}/*.json`]).pipe(checkHtml()); }); diff --git a/cast/public/service_worker.js b/cast/public/service_worker.js index 9cd535c9fc..04c7fbdc2c 100644 --- a/cast/public/service_worker.js +++ b/cast/public/service_worker.js @@ -1,3 +1,3 @@ -self.addEventListener("fetch", function(event) { +self.addEventListener("fetch", (event) => { event.respondWith(fetch(event.request)); }); diff --git a/demo/public/service_worker.js b/demo/public/service_worker.js index 9cd535c9fc..04c7fbdc2c 100644 --- a/demo/public/service_worker.js +++ b/demo/public/service_worker.js @@ -1,3 +1,3 @@ -self.addEventListener("fetch", function(event) { +self.addEventListener("fetch", (event) => { event.respondWith(fetch(event.request)); }); diff --git a/gallery/src/pages/Text/remove-delete-add-create.markdown b/gallery/src/pages/Text/remove-delete-add-create.markdown index 395adc673c..89c61db638 100644 --- a/gallery/src/pages/Text/remove-delete-add-create.markdown +++ b/gallery/src/pages/Text/remove-delete-add-create.markdown @@ -4,53 +4,63 @@ subtitle: The difference between remove/delete and add/create. --- # Remove vs Delete + Remove and Delete are quite similar, but can be frustrating if used inconsistently. ## Remove + Take away and set aside, but kept in existence. For example: -* Removing a user's permission -* Removing a user from a group -* Removing links between items -* Removing a widget -* Removing a link -* Removing an item from a cart + +- Removing a user's permission +- Removing a user from a group +- Removing links between items +- Removing a widget +- Removing a link +- Removing an item from a cart ## Delete + Erase, rendered nonexistent or nonrecoverable. For example: -* Deleting a field -* Deleting a value in a field -* Deleting a task -* Deleting a group -* Deleting a permission -* Deleting a calendar event + +- Deleting a field +- Deleting a value in a field +- Deleting a task +- Deleting a group +- Deleting a permission +- Deleting a calendar event # Add vs Create + In most cases, Create can be paired with Delete, and Add can be paired with Remove. ## Add + An already-exisiting item. For example: -* Adding a permission to a user -* Adding a user to a group -* Adding links between items -* Adding a widget -* Adding a link -* Adding an item to a cart + +- Adding a permission to a user +- Adding a user to a group +- Adding links between items +- Adding a widget +- Adding a link +- Adding an item to a cart ## Create + Something made from scratch. For example: -* Creating a new field -* Creating a new value in a field -* Creating a new task -* Creating a new group -* Creating a new permission -* Creating a new calendar event + +- Creating a new field +- Creating a new value in a field +- Creating a new task +- Creating a new group +- Creating a new permission +- Creating a new calendar event Based on this is [UX magazine article](https://uxmag.com/articles/ui-copy-remove-vs-delete2-banner). diff --git a/gallery/src/pages/automation/editor-action.ts b/gallery/src/pages/automation/editor-action.ts index 376f547d72..28f9bb16e2 100644 --- a/gallery/src/pages/automation/editor-action.ts +++ b/gallery/src/pages/automation/editor-action.ts @@ -85,17 +85,16 @@ class DemoHaAutomationEditorAction extends LitElement { .value=${this.data[sampleIdx]} > ${["light", "dark"].map( - (slot) => - html` - - ` + (slot) => html` + + ` )} ` diff --git a/gallery/src/pages/automation/editor-condition.ts b/gallery/src/pages/automation/editor-condition.ts index 7504d9dc46..3a43eda71e 100644 --- a/gallery/src/pages/automation/editor-condition.ts +++ b/gallery/src/pages/automation/editor-condition.ts @@ -121,17 +121,16 @@ class DemoHaAutomationEditorCondition extends LitElement { .value=${this.data[sampleIdx]} > ${["light", "dark"].map( - (slot) => - html` - - ` + (slot) => html` + + ` )} ` diff --git a/gallery/src/pages/automation/editor-trigger.ts b/gallery/src/pages/automation/editor-trigger.ts index cdc9ed2c83..30c9721256 100644 --- a/gallery/src/pages/automation/editor-trigger.ts +++ b/gallery/src/pages/automation/editor-trigger.ts @@ -167,17 +167,16 @@ class DemoHaAutomationEditorTrigger extends LitElement { .value=${this.data[sampleIdx]} > ${["light", "dark"].map( - (slot) => - html` - - ` + (slot) => html` + + ` )} ` diff --git a/gallery/src/pages/brand/logo.markdown b/gallery/src/pages/brand/logo.markdown index 550b1e056d..9cd8722f7c 100644 --- a/gallery/src/pages/brand/logo.markdown +++ b/gallery/src/pages/brand/logo.markdown @@ -10,7 +10,6 @@ As a community, we are proud of our logo. Follow these guidelines to ensure it a ![Logo](/images/logo.png) - ## Using the icon Our icon is a shorter and most used version of our logo. The icon can exist without the wordmark, the wordmark should never exist without the icon. @@ -21,7 +20,7 @@ Our icon is a shorter and most used version of our logo. The icon can exist with The pretty blue logo with a background shadow, pictured top left, is our primary logo. It should only be used with black, white, and non-duotone photography. -When needed you can use our logo without a shadow, as seen as the second variant. +When needed you can use our logo without a shadow, as seen as the second variant. The outlined logo should only be used on packaging. diff --git a/gallery/src/pages/components/ha-alert.markdown b/gallery/src/pages/components/ha-alert.markdown index 89f2aa39d8..9d2eced805 100644 --- a/gallery/src/pages/components/ha-alert.markdown +++ b/gallery/src/pages/components/ha-alert.markdown @@ -11,6 +11,7 @@ subtitle: An alert displays a short, important message in a way that attracts th # Alert `` + The alert offers four severity levels that set a distinctive icon and color. @@ -35,38 +36,46 @@ The alert offers four severity levels that set a distinctive icon and color. 2. [Implementation](#implementation) ### Resources -| Type | Link | Status | -|----------------|----------------------------------|-----------| + +| Type | Link | Status | +| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | | Design | Home Assistant DesignKit (Figma) | Available | -| Implementation | Web Component (GitHub) | Available | +| Implementation | Web Component (GitHub) | Available | ## Guidelines + ### Usage + An alert displays a short, important message in a way that attracts the user's attention without interrupting the user's task. ### Anatomy -*Documentation coming soon* + +_Documentation coming soon_ ### Error alert + Error alerts -*Real world example coming soon* +_Real world example coming soon_ ### Warning alert + Warning alerts -*Real world example coming soon* +_Real world example coming soon_ ### Info alert + Info alerts -*Real world example coming soon* +_Real world example coming soon_ ### Success alert + Success alerts -*Real world example coming soon* +_Real world example coming soon_ ### Placement - ### Accessibility + (WAI-ARIA: [https://www.w3.org/TR/wai-aria-practices/#alert](https://www.w3.org/TR/wai-aria-practices/#alert)) When the component is dynamically displayed, the content is automatically announced by most screen readers. At this time, screen readers do not inform users of alerts that are present when the page loads. @@ -78,6 +87,7 @@ Actions must have a tab index of 0 so that they can be reached by keyboard-only ## Implementation ### Example Usage + **Alert type** @@ -96,17 +106,12 @@ Actions must have a tab index of 0 so that they can be reached by keyboard-only This is an success alert — check it out! - ```html - - This is an error alert — check it out! - + This is an error alert — check it out! This is a warning alert — check it out! - - This is an info alert — check it out! - + This is an info alert — check it out! This is a success alert — check it out! @@ -154,13 +159,14 @@ The `title ` option should not be used without a description. **Slotted icon** -*Documentation coming soon* +_Documentation coming soon_ ### API + **Properties/Attributes** | Name | Type | Default | Description | -|-------------|---------|---------|-------------------------------------------------------| +| ----------- | ------- | ------- | ----------------------------------------------------- | | title | string | `` | Title to display. | | alertType | string | `info` | Severity level that set a distinctive icon and color. | | dismissable | boolean | `false` | Gives the option to close the alert. | @@ -170,8 +176,8 @@ The `title ` option should not be used without a description. **Events** -*Documentation coming soon* +_Documentation coming soon_ **CSS Custom Properties** -*Documentation coming soon* +_Documentation coming soon_ diff --git a/gallery/src/pages/components/ha-dialogs.markdown b/gallery/src/pages/components/ha-dialogs.markdown index f3736d213a..1f9c5b65c0 100644 --- a/gallery/src/pages/components/ha-dialogs.markdown +++ b/gallery/src/pages/components/ha-dialogs.markdown @@ -5,28 +5,32 @@ subtitle: Dialogs provide important prompts in a user flow. # Material Design 3 -Our dialogs are based on the latest version of Material Design. Specs and guidelines can be found on its [website](https://m3.material.io/components/dialogs/overview). +Our dialogs are based on the latest version of Material Design. Specs and guidelines can be found on its [website](https://m3.material.io/components/dialogs/overview). # Highlighted guidelines ## Content -* A best practice is to always use a title, even if it is optional by Material guidelines. -* People mainly read the title and a button. Put the most important information in those two. -* Try to avoid user generated content in the title, this could make the title unreadable long. -* If users become unsure, they read the description. Make sure this explains what will happen. -* Strive for minimalism. + +- A best practice is to always use a title, even if it is optional by Material guidelines. +- People mainly read the title and a button. Put the most important information in those two. +- Try to avoid user generated content in the title, this could make the title unreadable long. +- If users become unsure, they read the description. Make sure this explains what will happen. +- Strive for minimalism. ## Buttons and X-icon -* Keep the labels short, for example `Save`, `Delete`, `Enable`. -* Dialog with actions must always have a discard button. On desktop a `Cancel` button and X-icon, on mobile only the X-icon. -* Destructive actions should be a red warning button. -* Alert or confirmation dialogs only have buttons and no X-icon. -* Try to avoid three buttons in one dialog. Especially when you leave the dialog task unfinished. + +- Keep the labels short, for example `Save`, `Delete`, `Enable`. +- Dialog with actions must always have a discard button. On desktop a `Cancel` button and X-icon, on mobile only the X-icon. +- Destructive actions should be a red warning button. +- Alert or confirmation dialogs only have buttons and no X-icon. +- Try to avoid three buttons in one dialog. Especially when you leave the dialog task unfinished. ## Example + ### Confirmation dialog + > **Delete dashboard?** -> +> > Dashboard [dashboard name] will be permanently deleted from Home Assistant. -> +> > Cancel / Delete diff --git a/gallery/src/pages/components/ha-gauge.markdown b/gallery/src/pages/components/ha-gauge.markdown index 33419c9588..6261408c72 100644 --- a/gallery/src/pages/components/ha-gauge.markdown +++ b/gallery/src/pages/components/ha-gauge.markdown @@ -32,7 +32,6 @@ Error color gauge Gauge with background color - ## CSS variables ### Gauge diff --git a/gallery/src/pages/components/ha-selector.ts b/gallery/src/pages/components/ha-selector.ts index 9ac7959635..4cdc97013b 100644 --- a/gallery/src/pages/components/ha-selector.ts +++ b/gallery/src/pages/components/ha-selector.ts @@ -497,24 +497,23 @@ class DemoHaSelector extends LitElement implements ProvideHassElement { ${["light", "dark"].map((slot) => Object.entries(info.input).map( - ([key, value]) => - html` - - ${value?.name || key} - ${value?.description} - - - ` + ([key, value]) => html` + + ${value?.name || key} + ${value?.description} + + + ` ) )} diff --git a/gallery/src/pages/components/ha-switch.markdown b/gallery/src/pages/components/ha-switch.markdown index d281c3b0e8..266160bd98 100644 --- a/gallery/src/pages/components/ha-switch.markdown +++ b/gallery/src/pages/components/ha-switch.markdown @@ -30,7 +30,7 @@ For the switch / toggle there are always two variables, one for the on / checked The track element (background rounded rectangle that the round circular handle travels on) is set to being half transparent, so the final color will also be impacted by the color behind the track. `switch-checked-color` / `switch-unchecked-color` -Set both the color of the round handle and the track behind it. If you want to control them separately, use the variables below instead. +Set both the color of the round handle and the track behind it. If you want to control them separately, use the variables below instead. `switch-checked-button-color` / `switch-unchecked-button-color` Color of the round handle diff --git a/gallery/src/pages/components/ha-tip.ts b/gallery/src/pages/components/ha-tip.ts index 1f349efa7e..b9e9e5fc73 100644 --- a/gallery/src/pages/components/ha-tip.ts +++ b/gallery/src/pages/components/ha-tip.ts @@ -20,9 +20,8 @@ export class DemoHaTip extends LitElement {
${tips.map( - (tip) => html`${tip}` + (tip) => + html`${tip}` )}
diff --git a/gallery/src/pages/concepts/home.markdown b/gallery/src/pages/concepts/home.markdown index 666e567455..7b8cb4ab3f 100644 --- a/gallery/src/pages/concepts/home.markdown +++ b/gallery/src/pages/concepts/home.markdown @@ -7,18 +7,21 @@ title: Home This portal aims to aid designers and developers on improving the Home Assistant interface. It consists of working code, resources and guidelines. ## Home Assistant interface + The Home Assistant frontend allows users to browse and control the state of their home, manage their automations and configure integrations. The frontend is designed as a mobile-first experience. It is a progressive web application and offers an app-like experience to our users. The Home Assistant frontend needs to be fast. But it also needs to work on a wide range of old devices. ### Material Design + The Home Assistant interface is based on Material Design. It's a design system created by Google to quickly build high-quality digital experiences. Components and guidelines that are custom made for Home Assistant are documented on this portal. For all other components check material.io. ## Designers + We want to make it as easy for designers to contribute as it is for developers. There’s a lot a designer can contribute to: - Meet us at devs_ux Discord. Feel free to share your designs, user test or strategic ideas. - Start designing with our Figma DesignKit. - Find the lates UX discussions and issues on GitHub. Everyone can start a new issue or discussion! - ## Developers + Everything you need to get started developing can be found in our Home Assistant Developer Docs. diff --git a/gallery/src/pages/date-time/date-time-numeric.markdown b/gallery/src/pages/date-time/date-time-numeric.markdown index 3310f315a1..cb52101530 100644 --- a/gallery/src/pages/date-time/date-time-numeric.markdown +++ b/gallery/src/pages/date-time/date-time-numeric.markdown @@ -4,4 +4,4 @@ title: Date-Time Format (Numeric) This pages lists all supported languages with their available date-time formats. -Formatting function: `const formatDateTimeNumeric: (dateObj: Date, locale: FrontendLocaleData) => string` \ No newline at end of file +Formatting function: `const formatDateTimeNumeric: (dateObj: Date, locale: FrontendLocaleData) => string` diff --git a/gallery/src/pages/date-time/date-time-seconds.markdown b/gallery/src/pages/date-time/date-time-seconds.markdown index 01cfa6c729..8db31b8d3a 100644 --- a/gallery/src/pages/date-time/date-time-seconds.markdown +++ b/gallery/src/pages/date-time/date-time-seconds.markdown @@ -4,4 +4,4 @@ title: Date-Time Format (Seconds) This pages lists all supported languages with their available date-time formats. -Formatting function: `const formatDateTimeWithSeconds: (dateObj: Date, locale: FrontendLocaleData) => string` \ No newline at end of file +Formatting function: `const formatDateTimeWithSeconds: (dateObj: Date, locale: FrontendLocaleData) => string` diff --git a/gallery/src/pages/date-time/date-time-short-year.markdown b/gallery/src/pages/date-time/date-time-short-year.markdown index 19e77b55b9..a69677daae 100644 --- a/gallery/src/pages/date-time/date-time-short-year.markdown +++ b/gallery/src/pages/date-time/date-time-short-year.markdown @@ -4,4 +4,4 @@ title: Date-Time Format (Short w/ Year) This pages lists all supported languages with their available date-time formats. -Formatting function: `const formatShortDateTimeWithYear: (dateObj: Date, locale: FrontendLocaleData) => string` \ No newline at end of file +Formatting function: `const formatShortDateTimeWithYear: (dateObj: Date, locale: FrontendLocaleData) => string` diff --git a/gallery/src/pages/date-time/date-time-short.markdown b/gallery/src/pages/date-time/date-time-short.markdown index 3564a7afa0..b4f5ae4ddb 100644 --- a/gallery/src/pages/date-time/date-time-short.markdown +++ b/gallery/src/pages/date-time/date-time-short.markdown @@ -4,4 +4,4 @@ title: Date-Time Format (Short) This pages lists all supported languages with their available date-time formats. -Formatting function: `const formatShortDateTime: (dateObj: Date, locale: FrontendLocaleData) => string` \ No newline at end of file +Formatting function: `const formatShortDateTime: (dateObj: Date, locale: FrontendLocaleData) => string` diff --git a/gallery/src/pages/date-time/date-time.markdown b/gallery/src/pages/date-time/date-time.markdown index cef6195ab1..0b9651125e 100644 --- a/gallery/src/pages/date-time/date-time.markdown +++ b/gallery/src/pages/date-time/date-time.markdown @@ -4,4 +4,4 @@ title: Date-Time Format This pages lists all supported languages with their available date-time formats. -Formatting function: `const formatDateTime: (dateObj: Date, locale: FrontendLocaleData) => string` \ No newline at end of file +Formatting function: `const formatDateTime: (dateObj: Date, locale: FrontendLocaleData) => string` diff --git a/gallery/src/pages/date-time/date.markdown b/gallery/src/pages/date-time/date.markdown index 599921e1c7..282160b0c2 100644 --- a/gallery/src/pages/date-time/date.markdown +++ b/gallery/src/pages/date-time/date.markdown @@ -4,4 +4,4 @@ title: Date Format (Numeric) This pages lists all supported languages with their available (numeric) date formats. -Formatting function: `const formatDateNumeric: (dateObj: Date, locale: FrontendLocaleData) => string` \ No newline at end of file +Formatting function: `const formatDateNumeric: (dateObj: Date, locale: FrontendLocaleData) => string` diff --git a/gallery/src/pages/date-time/time-seconds.markdown b/gallery/src/pages/date-time/time-seconds.markdown index 23136c29f4..d12a5a6616 100644 --- a/gallery/src/pages/date-time/time-seconds.markdown +++ b/gallery/src/pages/date-time/time-seconds.markdown @@ -4,4 +4,4 @@ title: Time Format (Seconds) This pages lists all supported languages with their available time formats. -Formatting function: `const formatTimeWithSeconds: (dateObj: Date, locale: FrontendLocaleData) => string` \ No newline at end of file +Formatting function: `const formatTimeWithSeconds: (dateObj: Date, locale: FrontendLocaleData) => string` diff --git a/gallery/src/pages/date-time/time-weekday.markdown b/gallery/src/pages/date-time/time-weekday.markdown index 637be6afe3..afb2df2904 100644 --- a/gallery/src/pages/date-time/time-weekday.markdown +++ b/gallery/src/pages/date-time/time-weekday.markdown @@ -4,4 +4,4 @@ title: Time Format (Weekday) This pages lists all supported languages with their available time formats. -Formatting function: `const formatTimeWeekday: (dateObj: Date, locale: FrontendLocaleData) => string` \ No newline at end of file +Formatting function: `const formatTimeWeekday: (dateObj: Date, locale: FrontendLocaleData) => string` diff --git a/gallery/src/pages/date-time/time.markdown b/gallery/src/pages/date-time/time.markdown index df90d8931a..c7def99887 100644 --- a/gallery/src/pages/date-time/time.markdown +++ b/gallery/src/pages/date-time/time.markdown @@ -4,4 +4,4 @@ title: Time Format This pages lists all supported languages with their available time formats. -Formatting function: `const formatTime: (dateObj: Date, locale: FrontendLocaleData) => string` \ No newline at end of file +Formatting function: `const formatTime: (dateObj: Date, locale: FrontendLocaleData) => string` diff --git a/gallery/src/pages/lovelace/entities-card.ts b/gallery/src/pages/lovelace/entities-card.ts index 075fa73351..aa6368878d 100644 --- a/gallery/src/pages/lovelace/entities-card.ts +++ b/gallery/src/pages/lovelace/entities-card.ts @@ -135,6 +135,14 @@ const ENTITIES = [ getEntity("text", "unavailable", "unavailable", { friendly_name: "Message", }), + getEntity("event", "unavailable", "unavailable", { + friendly_name: "Empty remote", + }), + getEntity("event", "doorbell", "2023-07-17T21:26:11.615+00:00", { + friendly_name: "Doorbell", + device_class: "doorbell", + event_type: "Ding-Dong", + }), ]; const CONFIGS = [ @@ -154,6 +162,7 @@ const CONFIGS = [ - input_number.number - sensor.humidity - text.message + - event.doorbell `, }, { @@ -246,6 +255,7 @@ const CONFIGS = [ - input_number.unavailable - input_select.unavailable - text.unavailable + - event.unavailable `, }, { diff --git a/gallery/src/pages/lovelace/introduction.markdown b/gallery/src/pages/lovelace/introduction.markdown index c7bfc791d9..8710ec1618 100644 --- a/gallery/src/pages/lovelace/introduction.markdown +++ b/gallery/src/pages/lovelace/introduction.markdown @@ -1,6 +1,7 @@ --- title: Introduction --- + Dashboards have many different cards. Each card allows the user to tell a different story about what is going on in their house. These cards are very customizable, as no household is the same. diff --git a/gallery/src/pages/misc/entity-state.ts b/gallery/src/pages/misc/entity-state.ts index c35c9fae1e..8a738ca873 100644 --- a/gallery/src/pages/misc/entity-state.ts +++ b/gallery/src/pages/misc/entity-state.ts @@ -35,6 +35,7 @@ const SENSOR_DEVICE_CLASSES = [ "nitrogen_monoxide", "nitrous_oxide", "ozone", + "ph", "pm1", "pm10", "pm25", diff --git a/gallery/src/pages/user-test/configuration-menu.markdown b/gallery/src/pages/user-test/configuration-menu.markdown index 2abf0d5e3c..0adb2f2e35 100644 --- a/gallery/src/pages/user-test/configuration-menu.markdown +++ b/gallery/src/pages/user-test/configuration-menu.markdown @@ -6,197 +6,217 @@ title: "User Test: Configuration menu" At the end of last year, we created one Configuration menu by merging Supervisor. In the next iteration, we want to organize our menu by creating logical grouping and combining duplicated features. We are conducting this test to see if we are on the right track. -* Anyone could join -* Respondents recruited on Twitter, Reddit and Home Assistant Forum -* This test is open for 10 days -* UsabilityHub for user test -* Figma for prototype -* 6 questions -* 3 tasks -* Due to some limitations by UsabilityHub, it only worked on desktop +- Anyone could join +- Respondents recruited on Twitter, Reddit and Home Assistant Forum +- This test is open for 10 days +- UsabilityHub for user test +- Figma for prototype +- 6 questions +- 3 tasks +- Due to some limitations by UsabilityHub, it only worked on desktop # Results + 915 respondents took part in this test and they gave 407 comments. In general there isn’t a significant difference between: -* How long a respondent has been using Home Assistant -* Installation method -* How many visits to its Home Assistant in the past 3 months -* Home Assistant expertise +- How long a respondent has been using Home Assistant +- Installation method +- How many visits to its Home Assistant in the past 3 months +- Home Assistant expertise ## Overall menu change + This prototype organized our menu by creating logical grouping and combining duplicated features. What do people think of this change? ### Stats -* 2% (21) Like extremely -* 30% (276) Like very much -* 53% (481) Neutral -* 12% (108) Dislike very much -* 3% (26) Dislike extremely -*3 respondents passed* +- 2% (21) Like extremely +- 30% (276) Like very much +- 53% (481) Neutral +- 12% (108) Dislike very much +- 3% (26) Dislike extremely + +_3 respondents passed_ ### Comments summary + **Like** -* Clean and decluttered -* Style looks better -* Faster to use -* Merging Supervisor into different pages -* Moving Developer tools to Settings +- Clean and decluttered +- Style looks better +- Faster to use +- Merging Supervisor into different pages +- Moving Developer tools to Settings **Dislike** -* Moving Developer tools to Settings -* More clicks for scripts and helpers -* Too many changes at once causes a high learning curve -* Removing the word `Integrations` makes it harder to find them -* Difference between `Addons` and `Services` is a bit subtle -* No clear distinction between `Developer` and `System` -* Material Design got the Google image +- Moving Developer tools to Settings +- More clicks for scripts and helpers +- Too many changes at once causes a high learning curve +- Removing the word `Integrations` makes it harder to find them +- Difference between `Addons` and `Services` is a bit subtle +- No clear distinction between `Developer` and `System` +- Material Design got the Google image **Suggestions** -* More top level menu items for example logs. -* What are settings and what not? Maybe better to name it `Configuration` -* Devices are a first-class citizen in the domain of Home Assistant, and so shouldn't be tucked away in "Settings" -* Rename Developer tools (or make it only for Home Assistant developers) -* Separate administration (for instance creating users / adding lights etc) from development activities (creating automations and scripts) -* Search Bar in Settings -* Feature to put menu items in sidebar -* Unification of add-ons and integrations -* Adding ‘New’ hints to show what changed -* Give `About` a less prominent size -* Accordion view option which puts every tab below -* Dev mode and a Prod Mode -* Always show config menu (on bigger screens) +- More top level menu items for example logs. +- What are settings and what not? Maybe better to name it `Configuration` +- Devices are a first-class citizen in the domain of Home Assistant, and so shouldn't be tucked away in "Settings" +- Rename Developer tools (or make it only for Home Assistant developers) +- Separate administration (for instance creating users / adding lights etc) from development activities (creating automations and scripts) +- Search Bar in Settings +- Feature to put menu items in sidebar +- Unification of add-ons and integrations +- Adding ‘New’ hints to show what changed +- Give `About` a less prominent size +- Accordion view option which puts every tab below +- Dev mode and a Prod Mode +- Always show config menu (on bigger screens) ### Conclusion + We should keep our focus on organizing our menu by creating logical grouping and combining duplicated features. With these changes we make more people happy: -* Reconsider putting `Logs` as a top-level menu item -* Add a search bar -* Use the word `Integrations` with `Devices & Services` -* Moving `Developer tools` to `Settings` is a good idea -* Rename `Developer tools` to for example `Tools` -* Add `New` explanation popups to what has changed -* We could rename `Configuration` to `Settings` -* Give `About` a less prominent size +- Reconsider putting `Logs` as a top-level menu item +- Add a search bar +- Use the word `Integrations` with `Devices & Services` +- Moving `Developer tools` to `Settings` is a good idea +- Rename `Developer tools` to for example `Tools` +- Add `New` explanation popups to what has changed +- We could rename `Configuration` to `Settings` +- Give `About` a less prominent size ## Helpers + In Home Assistant you can create toggles, text fields, number sliders, timers and counters. Also known as `Helpers`. Where should they be placed? ### Stats -* 78% (709) respondents are using helpers. They use it for: -* 92% (645) automations and scenes -* 62% (422) dashboards -* 43% (296) virtual devices + +- 78% (709) respondents are using helpers. They use it for: +- 92% (645) automations and scenes +- 62% (422) dashboards +- 43% (296) virtual devices ### Comments summary + Some respondents commented that they think `Helpers` shouldn’t be listed under `Automations & Services`. Although almost all respondents use it for that specific purpose. ### Conclusion -Helpers is, in addition to `Automations & Services`, also partly seen as virtual devices and dashboard entities. -* We might consider promoting them in their own top-level menu item -* Rename `Helpers` to something with `controls` +Helpers is, in addition to `Automations & Services`, also partly seen as virtual devices and dashboard entities. + +- We might consider promoting them in their own top-level menu item +- Rename `Helpers` to something with `controls` ## Add person + The first task in this user test was to add a person. Since this has not changed in the current menu structure, this should be an easy assignment. How do people experience the navigation to this feature? ### Stats + 95% reached the goal screen and 98% marked the task as completed. There were 18 common paths. After the task we asked how easy it was to add a person. -* 41% (378) Extremely easy -* 48% (440) Fairly easy -* 7% (67) Neutral -* 2% (19) Somewhat difficult -* 1% (11) Very difficult +- 41% (378) Extremely easy +- 48% (440) Fairly easy +- 7% (67) Neutral +- 2% (19) Somewhat difficult +- 1% (11) Very difficult ### Comments summary -*No mentionable comments * + +_No mentionable comments _ ### Conclusion + This test showed that the current navigation design works. ## YAML + In Home Assistant you can make configuration changes in YAML files. To make these changes take effect you have to reload your YAML in the UI or do a restart. How are people doing this and can they find it in this new design? ### Stats + 83% reached the goal screen and 87% marked the task as completed. There were 59 common paths. After the task we asked how easy it was to reload the YAML changes. -* 4% (40) Extremely easy -* 22% (204) Fairly easy -* 20% (179) Neutral -* 37% (336) Somewhat difficult -* 17% (156) Very difficult +- 4% (40) Extremely easy +- 22% (204) Fairly easy +- 20% (179) Neutral +- 37% (336) Somewhat difficult +- 17% (156) Very difficult And we asked if they have seen that we've moved some functionality from current `Server Controls` to `Developer Tools`. -* 57% (517) Yes -* 43% (398) No +- 57% (517) Yes +- 43% (398) No ### Comments summary + **Like** -* YAML in Developer tools +- YAML in Developer tools **Dislike** -* Hidden restart and reload -* YAML in Developer Tools -* Combining `Developer tools` with `Server management` -* Reload Home Assistant button isn't clear what it does -* Reload/restart Home Assistant in Developer Tools +- Hidden restart and reload +- YAML in Developer Tools +- Combining `Developer tools` with `Server management` +- Reload Home Assistant button isn't clear what it does +- Reload/restart Home Assistant in Developer Tools **Suggestions** -* Reload all YAML button -* Dev mode and a Prod Mode -* Show restart/reload as buttons in System instead of overflow menu -* Explain that you can reload YAML when you want to restart your system -* YAML reloading under System +- Reload all YAML button +- Dev mode and a Prod Mode +- Show restart/reload as buttons in System instead of overflow menu +- Explain that you can reload YAML when you want to restart your system +- YAML reloading under System ### Conclusion -This test showed two different kinds of user groups: UI and YAML users. -* Moving `Developer tools` to `Settings` is a good idea -* YAML users want reload YAML and Home Assistant restart in `System` -* Move the restart and reload button to the `System` page from the overflow menu -* Add suggestion to reload YAML when a user wants to restart -* Add reload all YAML button +This test showed two different kinds of user groups: UI and YAML users. + +- Moving `Developer tools` to `Settings` is a good idea +- YAML users want reload YAML and Home Assistant restart in `System` +- Move the restart and reload button to the `System` page from the overflow menu +- Add suggestion to reload YAML when a user wants to restart +- Add reload all YAML button ## Logs + ### Stats + 70% reached the goal screen and 77% marked the task as completed. There were 48 common paths. After the task we asked to find out why your Elgato light isn't working. -* 6% (57) Extremely easy -* 28% (254) Fairly easy -* 21% (188) Neutral -* 21% (196) Somewhat difficult -* 24% (220) Very difficult +- 6% (57) Extremely easy +- 28% (254) Fairly easy +- 21% (188) Neutral +- 21% (196) Somewhat difficult +- 24% (220) Very difficult ### Comments summary **Suggestions** -* Log errors on the integration page -* Problem solving center +- Log errors on the integration page +- Problem solving center ### Conclusion + Although this test shows that a large number of respondents manage to complete the task, they find it difficult to find out the light isn’t working. -* Add logs errors/warnings to the integration page -* Reconsider putting `Logs` as a top-level menu item +- Add logs errors/warnings to the integration page +- Reconsider putting `Logs` as a top-level menu item ## Learnings for next user test -* Explain that topic is closed for comments so that you can do this test without any influence -* Mobile test should work on mobile -* Testing on an iPad got some bugs -* People like doing these kind of test and we should do them more often +- Explain that topic is closed for comments so that you can do this test without any influence +- Mobile test should work on mobile +- Testing on an iPad got some bugs +- People like doing these kind of test and we should do them more often diff --git a/gallery/src/pages/user-test/user-types.markdown b/gallery/src/pages/user-test/user-types.markdown index eacc108cd4..9dda7f4f13 100644 --- a/gallery/src/pages/user-test/user-types.markdown +++ b/gallery/src/pages/user-test/user-types.markdown @@ -2,7 +2,7 @@ title: "User types" --- -We have defined three user types for Home Assistant. They are a lean segmentation of users that helps us make decisions throughout the product. User types differ from traditional personas in that the segmentation criteria aren’t demographic and don’t personify a group into a single character with a fictitious background story. +We have defined three user types for Home Assistant. They are a lean segmentation of users that helps us make decisions throughout the product. User types differ from traditional personas in that the segmentation criteria aren’t demographic and don’t personify a group into a single character with a fictitious background story. # Outgrowers diff --git a/hassio/src/addon-view/info/hassio-addon-info.ts b/hassio/src/addon-view/info/hassio-addon-info.ts index 5800d2e1b0..fee9340720 100644 --- a/hassio/src/addon-view/info/hassio-addon-info.ts +++ b/hassio/src/addon-view/info/hassio-addon-info.ts @@ -544,14 +544,13 @@ class HassioAddonInfo extends LitElement { ${this.addon.hostname} ${metrics.map( - (metric) => - html` - - ` + (metric) => html` + + ` )}` : ""} diff --git a/hassio/src/components/supervisor-backup-content.ts b/hassio/src/components/supervisor-backup-content.ts index ded21bf63a..81b4f6fbf1 100644 --- a/hassio/src/components/supervisor-backup-content.ts +++ b/hassio/src/components/supervisor-backup-content.ts @@ -384,28 +384,30 @@ export class SupervisorBackupContent extends LitElement { : undefined; let checkedItems = 0; this[section].forEach((item) => { - templates.push(html` + `} > - `} - > - - - `); + + + ` + ); if (item.checked) { checkedItems++; diff --git a/hassio/src/dialogs/backup/dialog-hassio-backup.ts b/hassio/src/dialogs/backup/dialog-hassio-backup.ts index cded8cf5ba..230ecc1f22 100644 --- a/hassio/src/dialogs/backup/dialog-hassio-backup.ts +++ b/hassio/src/dialogs/backup/dialog-hassio-backup.ts @@ -194,7 +194,7 @@ class HassioBackupDialog } if ( !(await showConfirmationDialog(this, { - title: "Are you sure you want partially to restore this backup?", + title: "Are you sure you want to restore this partial backup?", confirmText: "restore", dismissText: "cancel", })) diff --git a/hassio/src/dialogs/network/dialog-hassio-network.ts b/hassio/src/dialogs/network/dialog-hassio-network.ts index 943e92972c..f3a77f8b40 100644 --- a/hassio/src/dialogs/network/dialog-hassio-network.ts +++ b/hassio/src/dialogs/network/dialog-hassio-network.ts @@ -168,25 +168,24 @@ export class DialogHassioNetwork ${this._accessPoints.accesspoints .filter((ap) => ap.ssid) .map( - (ap) => - html` - - ${ap.ssid} - - ${ap.mac} - - ${this.supervisor.localize( - "dialog.network.signal_strength" - )}: - ${ap.signal} - - - ` + (ap) => html` + + ${ap.ssid} + + ${ap.mac} - + ${this.supervisor.localize( + "dialog.network.signal_strength" + )}: + ${ap.signal} + + + ` )} ` diff --git a/hassio/src/dialogs/registries/dialog-hassio-registries.ts b/hassio/src/dialogs/registries/dialog-hassio-registries.ts index e26753e5dc..d623ebf3b8 100644 --- a/hassio/src/dialogs/registries/dialog-hassio-registries.ts +++ b/hassio/src/dialogs/registries/dialog-hassio-registries.ts @@ -157,10 +157,11 @@ class HassioRegistriesDialog extends LitElement { } public focus(): void { - this.updateComplete.then(() => - ( - this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement - )?.focus() + this.updateComplete.then( + () => + ( + this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement + )?.focus() ); } diff --git a/hassio/src/dialogs/repositories/dialog-hassio-repositories.ts b/hassio/src/dialogs/repositories/dialog-hassio-repositories.ts index aeac743f31..bf42ff4499 100644 --- a/hassio/src/dialogs/repositories/dialog-hassio-repositories.ts +++ b/hassio/src/dialogs/repositories/dialog-hassio-repositories.ts @@ -209,10 +209,11 @@ class HassioRepositoriesDialog extends LitElement { } public focus() { - this.updateComplete.then(() => - ( - this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement - )?.focus() + this.updateComplete.then( + () => + ( + this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement + )?.focus() ); } diff --git a/hassio/src/system/hassio-core-info.ts b/hassio/src/system/hassio-core-info.ts index 254d602e87..7754728757 100644 --- a/hassio/src/system/hassio-core-info.ts +++ b/hassio/src/system/hassio-core-info.ts @@ -81,14 +81,13 @@ class HassioCoreInfo extends LitElement {
${metrics.map( - (metric) => - html` - - ` + (metric) => html` + + ` )}
diff --git a/hassio/src/system/hassio-host-info.ts b/hassio/src/system/hassio-host-info.ts index cfb039d935..4e84c0f23f 100644 --- a/hassio/src/system/hassio-host-info.ts +++ b/hassio/src/system/hassio-host-info.ts @@ -154,14 +154,13 @@ class HassioHostInfo extends LitElement { ` : ""} ${metrics.map( - (metric) => - html` - - ` + (metric) => html` + + ` )} diff --git a/hassio/src/system/hassio-supervisor-info.ts b/hassio/src/system/hassio-supervisor-info.ts index 1dbca65417..d083bfb613 100644 --- a/hassio/src/system/hassio-supervisor-info.ts +++ b/hassio/src/system/hassio-supervisor-info.ts @@ -178,14 +178,13 @@ class HassioSupervisorInfo extends LitElement {
${metrics.map( - (metric) => - html` - - ` + (metric) => html` + + ` )}
diff --git a/lint-staged.config.js b/lint-staged.config.js index be7d7f2094..8740aaab19 100644 --- a/lint-staged.config.js +++ b/lint-staged.config.js @@ -1,6 +1,9 @@ export default { - "*.?(c|m){js,ts}": ["eslint --fix", "prettier --write"], - "!(/translations)*.{json,css,md,html}": "prettier --write", + "*.?(c|m){js,ts}": [ + "eslint --cache --cache-strategy=content --cache-location=node_modules/.cache/eslint/.eslintcache --fix", + "prettier --cache --write", + ], + "*.{json,css,md,markdown,html,y?aml}": "prettier --cache --write", "translations/*/*.json": (files) => 'printf "%s\n" "Translation files should not be added or modified here. Instead, make the necessary modifications in src/translations/en.json. Other languages are managed externally. Please see https://developers.home-assistant.io/docs/translations/ for details." ' + files.join(" ") + diff --git a/package.json b/package.json index 6790976198..4689fad4b6 100644 --- a/package.json +++ b/package.json @@ -8,10 +8,10 @@ "version": "1.0.0", "scripts": { "build": "script/build_frontend", - "lint:eslint": "eslint \"**/src/**/*.{js,ts,html}\" --ignore-path .gitignore", - "format:eslint": "eslint \"**/src/**/*.{js,ts,html}\" --fix --ignore-path .gitignore", - "lint:prettier": "prettier \"**/src/**/*.{js,ts,json,css,md}\" --check", - "format:prettier": "prettier \"**/src/**/*.{js,ts,json,css,md}\" --write", + "lint:eslint": "eslint \"**/src/**/*.{js,ts,html}\" --cache --cache-strategy=content --cache-location=node_modules/.cache/eslint/.eslintcache --ignore-path=.gitignore", + "format:eslint": "eslint \"**/src/**/*.{js,ts,html}\" --cache --cache-strategy=content --cache-location=node_modules/.cache/eslint/.eslintcache --ignore-path=.gitignore --fix", + "lint:prettier": "prettier . --cache --check", + "format:prettier": "prettier . --cache --write", "lint:types": "tsc", "lint:lit": "lit-analyzer \"**/src/**/*.ts\" --format markdown --outFile result.md", "lint": "yarn run lint:eslint && yarn run lint:prettier && yarn run lint:types", @@ -25,15 +25,15 @@ "license": "Apache-2.0", "type": "module", "dependencies": { - "@babel/runtime": "7.22.5", + "@babel/runtime": "7.22.6", "@braintree/sanitize-url": "6.0.2", - "@codemirror/autocomplete": "6.8.1", + "@codemirror/autocomplete": "6.9.0", "@codemirror/commands": "6.2.4", "@codemirror/language": "6.8.0", - "@codemirror/legacy-modes": "6.3.2", + "@codemirror/legacy-modes": "6.3.3", "@codemirror/search": "6.5.0", "@codemirror/state": "6.2.1", - "@codemirror/view": "6.14.0", + "@codemirror/view": "6.15.3", "@egjs/hammerjs": "2.0.17", "@formatjs/intl-datetimeformat": "6.10.0", "@formatjs/intl-displaynames": "6.5.0", @@ -52,7 +52,7 @@ "@lezer/highlight": "1.1.6", "@lit-labs/context": "0.3.3", "@lit-labs/motion": "1.0.3", - "@lit-labs/virtualizer": "2.0.3", + "@lit-labs/virtualizer": "2.0.4", "@lrnwebcomponents/simple-tooltip": "7.0.11", "@material/chips": "=14.0.0-canary.53b3cad2f.0", "@material/data-table": "=14.0.0-canary.53b3cad2f.0", @@ -79,7 +79,7 @@ "@material/mwc-top-app-bar": "0.27.0", "@material/mwc-top-app-bar-fixed": "0.27.0", "@material/top-app-bar": "=14.0.0-canary.53b3cad2f.0", - "@material/web": "=1.0.0-pre.12", + "@material/web": "=1.0.0-pre.13", "@mdi/js": "7.2.96", "@mdi/svg": "7.2.96", "@polymer/app-layout": "3.1.0", @@ -94,8 +94,8 @@ "@polymer/paper-toast": "3.0.1", "@polymer/polymer": "3.5.1", "@thomasloven/round-slider": "0.6.0", - "@vaadin/combo-box": "24.1.2", - "@vaadin/vaadin-themable-mixin": "24.1.2", + "@vaadin/combo-box": "24.1.4", + "@vaadin/vaadin-themable-mixin": "24.1.4", "@vibrant/color": "3.2.1-alpha.1", "@vibrant/core": "3.2.1-alpha.1", "@vibrant/quantizer-mmcq": "3.2.1-alpha.1", @@ -105,22 +105,22 @@ "app-datepicker": "5.1.1", "chart.js": "3.3.2", "comlink": "4.4.1", - "core-js": "3.31.0", + "core-js": "3.31.1", "cropperjs": "1.5.13", "date-fns": "2.30.0", "date-fns-tz": "2.0.0", "deep-clone-simple": "1.1.1", "deep-freeze": "0.0.1", "fuse.js": "6.6.2", - "google-timezones-json": "1.1.0", - "hls.js": "1.4.7", - "home-assistant-js-websocket": "8.1.0", + "google-timezones-json": "1.2.0", + "hls.js": "1.4.10", + "home-assistant-js-websocket": "8.2.0", "idb-keyval": "6.2.1", "intl-messageformat": "10.5.0", "js-yaml": "4.1.0", "leaflet": "1.9.4", "leaflet-draw": "1.0.4", - "lit": "2.7.5", + "lit": "2.7.6", "luxon": "3.3.0", "marked": "4.3.0", "memoize-one": "6.0.0", @@ -135,8 +135,8 @@ "sortablejs": "1.15.0", "superstruct": "1.0.3", "tinykeys": "2.1.0", - "tsparticles-engine": "2.10.1", - "tsparticles-preset-links": "2.10.1", + "tsparticles-engine": "2.11.0", + "tsparticles-preset-links": "2.11.0", "unfetch": "5.0.0", "vis-data": "7.1.6", "vis-network": "9.1.6", @@ -152,18 +152,18 @@ "xss": "1.0.14" }, "devDependencies": { - "@babel/core": "7.22.5", - "@babel/plugin-proposal-decorators": "7.22.5", - "@babel/plugin-transform-runtime": "7.22.5", - "@babel/preset-env": "7.22.5", + "@babel/core": "7.22.9", + "@babel/plugin-proposal-decorators": "7.22.7", + "@babel/plugin-transform-runtime": "7.22.9", + "@babel/preset-env": "7.22.9", "@babel/preset-typescript": "7.22.5", "@koa/cors": "4.0.0", - "@octokit/auth-oauth-device": "5.0.2", - "@octokit/plugin-retry": "5.0.4", - "@octokit/rest": "19.0.13", + "@octokit/auth-oauth-device": "6.0.0", + "@octokit/plugin-retry": "6.0.0", + "@octokit/rest": "20.0.1", "@open-wc/dev-server-hmr": "0.1.4", "@rollup/plugin-babel": "6.0.3", - "@rollup/plugin-commonjs": "25.0.2", + "@rollup/plugin-commonjs": "25.0.3", "@rollup/plugin-json": "6.0.0", "@rollup/plugin-node-resolve": "15.1.0", "@rollup/plugin-replace": "5.0.2", @@ -176,7 +176,7 @@ "@types/js-yaml": "4.0.5", "@types/leaflet": "1.9.3", "@types/leaflet-draw": "1.0.7", - "@types/luxon": "3.3.0", + "@types/luxon": "3.3.1", "@types/marked": "4.3.1", "@types/mocha": "10.0.1", "@types/qrcode": "1.5.1", @@ -184,29 +184,29 @@ "@types/sortablejs": "1.15.1", "@types/tar": "6.1.5", "@types/webspeechapi": "0.0.29", - "@typescript-eslint/eslint-plugin": "5.60.1", - "@typescript-eslint/parser": "5.60.1", + "@typescript-eslint/eslint-plugin": "6.1.0", + "@typescript-eslint/parser": "6.1.0", "@web/dev-server": "0.1.38", "@web/dev-server-rollup": "0.4.1", - "babel-loader": "9.1.2", + "babel-loader": "9.1.3", "babel-plugin-template-html-minifier": "4.1.0", "chai": "4.3.7", "del": "7.0.0", - "eslint": "8.44.0", + "eslint": "8.45.0", "eslint-config-airbnb-base": "15.0.0", - "eslint-config-airbnb-typescript": "17.0.0", + "eslint-config-airbnb-typescript": "17.1.0", "eslint-config-prettier": "8.8.0", "eslint-import-resolver-webpack": "0.13.2", "eslint-plugin-disable": "2.0.3", "eslint-plugin-import": "2.27.5", "eslint-plugin-lit": "1.8.3", "eslint-plugin-lit-a11y": "3.0.0", - "eslint-plugin-unused-imports": "2.0.0", + "eslint-plugin-unused-imports": "3.0.0", "eslint-plugin-wc": "1.5.0", "esprima": "4.0.1", "fancy-log": "2.0.0", "fs-extra": "11.1.1", - "glob": "10.3.1", + "glob": "10.3.3", "gulp": "4.0.2", "gulp-flatmap": "1.0.2", "gulp-json-transform": "0.4.8", @@ -220,14 +220,14 @@ "lint-staged": "13.2.3", "lit-analyzer": "2.0.0-pre.3", "lodash.template": "4.5.0", - "magic-string": "0.30.0", + "magic-string": "0.30.1", "map-stream": "0.0.7", "merge-stream": "2.0.0", "mocha": "10.2.0", "object-hash": "3.0.0", "open": "9.1.0", "pinst": "3.0.0", - "prettier": "2.8.8", + "prettier": "3.0.0", "rollup": "2.79.1", "rollup-plugin-string": "3.0.0", "rollup-plugin-terser": "7.0.2", @@ -242,7 +242,7 @@ "typescript": "5.1.6", "vinyl-buffer": "1.0.1", "vinyl-source-stream": "2.0.0", - "webpack": "5.88.1", + "webpack": "5.88.2", "webpack-cli": "5.1.4", "webpack-dev-server": "4.15.1", "webpack-manifest-plugin": "5.0.0", @@ -256,9 +256,5 @@ "sortablejs@1.15.0": "patch:sortablejs@npm%3A1.15.0#./.yarn/patches/sortablejs-npm-1.15.0-f3a393abcc.patch", "leaflet-draw@1.0.4": "patch:leaflet-draw@npm%3A1.0.4#./.yarn/patches/leaflet-draw-npm-1.0.4-0ca0ebcf65.patch" }, - "prettier": { - "trailingComma": "es5", - "arrowParens": "always" - }, "packageManager": "yarn@3.6.1" } diff --git a/prettier.config.js b/prettier.config.js new file mode 100644 index 0000000000..e8646cb474 --- /dev/null +++ b/prettier.config.js @@ -0,0 +1,3 @@ +export default { + trailingComma: "es5", +}; diff --git a/pyproject.toml b/pyproject.toml index 4c2a8ff47e..e3972f0f8b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "home-assistant-frontend" -version = "20230705.1" +version = "20230725.0" license = {text = "Apache-2.0"} description = "The Home Assistant frontend" readme = "README.md" diff --git a/renovate.json b/renovate.json index 291e6a4a26..e1dabc5a5b 100644 --- a/renovate.json +++ b/renovate.json @@ -2,7 +2,7 @@ "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": [ ":ignoreModulesAndTests", - ":label(dependencies)", + ":label(Dependencies)", ":pinVersions", ":prConcurrentLimit10", ":semanticCommitsDisabled", diff --git a/src/auth/ha-authorize.ts b/src/auth/ha-authorize.ts index deadcf765e..91fed8ef07 100644 --- a/src/auth/ha-authorize.ts +++ b/src/auth/ha-authorize.ts @@ -182,6 +182,10 @@ export class HaAuthorize extends litLocalizeLiteMixin(LitElement) { display: block; margin-top: 24px; } + p { + font-size: 14px; + line-height: 20px; + } `; } } diff --git a/src/common/const.ts b/src/common/const.ts index b4f79e5126..56b632d4be 100644 --- a/src/common/const.ts +++ b/src/common/const.ts @@ -10,6 +10,7 @@ import { mdiBookmark, mdiBrightness5, mdiBullhorn, + mdiButtonPointer, mdiCalendar, mdiCalendarClock, mdiCarCoolantLevel, @@ -28,7 +29,6 @@ import { mdiFormatListBulleted, mdiFormTextbox, mdiGauge, - mdiGestureTapButton, mdiGoogleAssistant, mdiGoogleCirclesCommunities, mdiHomeAssistant, @@ -45,6 +45,7 @@ import { mdiMoleculeCo, mdiMoleculeCo2, mdiPalette, + mdiPh, mdiProgressClock, mdiRayVertex, mdiRemote, @@ -93,7 +94,7 @@ export const FIXED_DOMAIN_ICONS = { homekit: mdiHomeAutomation, image: mdiImage, image_processing: mdiImageFilterFrames, - input_button: mdiGestureTapButton, + input_button: mdiButtonPointer, input_datetime: mdiCalendarClock, input_number: mdiRayVertex, input_select: mdiFormatListBulleted, @@ -148,6 +149,7 @@ export const FIXED_DEVICE_CLASS_ICONS = { nitrogen_monoxide: mdiMolecule, nitrous_oxide: mdiMolecule, ozone: mdiMolecule, + ph: mdiPh, pm1: mdiMolecule, pm10: mdiMolecule, pm25: mdiMolecule, @@ -178,6 +180,7 @@ export const DOMAINS_WITH_CARD = [ "climate", "cover", "configurator", + "event", "input_button", "input_select", "input_number", diff --git a/src/common/entity/compute_state_display.ts b/src/common/entity/compute_state_display.ts index 998949b007..4baad8357d 100644 --- a/src/common/entity/compute_state_display.ts +++ b/src/common/entity/compute_state_display.ts @@ -185,9 +185,15 @@ export const computeStateDisplayFromEntityAttributes = ( // state is a timestamp if ( - ["button", "image", "input_button", "scene", "stt", "tts"].includes( - domain - ) || + [ + "button", + "event", + "image", + "input_button", + "scene", + "stt", + "tts", + ].includes(domain) || (domain === "sensor" && attributes.device_class === "timestamp") ) { try { diff --git a/src/common/entity/domain_icon.ts b/src/common/entity/domain_icon.ts index 3ced61b3f8..1ea45fa095 100644 --- a/src/common/entity/domain_icon.ts +++ b/src/common/entity/domain_icon.ts @@ -7,6 +7,7 @@ import { mdiAudioVideoOff, mdiBluetooth, mdiBluetoothConnect, + mdiButtonPointer, mdiCalendar, mdiCast, mdiCastConnected, @@ -16,6 +17,8 @@ import { mdiClock, mdiCloseCircleOutline, mdiCrosshairsQuestion, + mdiDoorbell, + mdiEyeCheck, mdiFan, mdiFanOff, mdiGestureTapButton, @@ -25,6 +28,7 @@ import { mdiLockAlert, mdiLockClock, mdiLockOpen, + mdiMotionSensor, mdiPackage, mdiPackageDown, mdiPackageUp, @@ -111,7 +115,7 @@ export const domainIconWithoutDefault = ( case "update": return mdiPackageUp; default: - return mdiGestureTapButton; + return mdiButtonPointer; } case "camera": @@ -131,6 +135,18 @@ export const domainIconWithoutDefault = ( } return compareState === "not_home" ? mdiAccountArrowRight : mdiAccount; + case "event": + switch (stateObj?.attributes.device_class) { + case "doorbell": + return mdiDoorbell; + case "button": + return mdiGestureTapButton; + case "motion": + return mdiMotionSensor; + default: + return mdiEyeCheck; + } + case "fan": return compareState === "off" ? mdiFanOff : mdiFan; diff --git a/src/common/entity/get_states.ts b/src/common/entity/get_states.ts index f8d10ad99f..17140b2166 100644 --- a/src/common/entity/get_states.ts +++ b/src/common/entity/get_states.ts @@ -186,6 +186,7 @@ const FIXED_DOMAIN_ATTRIBUTE_STATES = { "nitrogen_monoxide", "nitrous_oxide", "ozone", + "ph", "pm1", "pm10", "pm25", @@ -250,6 +251,11 @@ export const getStates = ( result.push("home", "not_home"); } break; + case "event": + if (attribute === "event_type") { + result.push(...state.attributes.event_types); + } + break; case "fan": if (attribute === "preset_mode") { result.push(...state.attributes.preset_modes); diff --git a/src/common/entity/state_active.ts b/src/common/entity/state_active.ts index a22ee5c9e5..34162fcc0b 100644 --- a/src/common/entity/state_active.ts +++ b/src/common/entity/state_active.ts @@ -6,7 +6,7 @@ export function stateActive(stateObj: HassEntity, state?: string): boolean { const domain = computeDomain(stateObj.entity_id); const compareState = state !== undefined ? state : stateObj?.state; - if (["button", "input_button", "scene"].includes(domain)) { + if (["button", "event", "input_button", "scene"].includes(domain)) { return compareState !== UNAVAILABLE; } diff --git a/src/common/translations/localize.ts b/src/common/translations/localize.ts index 8117af0ffe..15773a5cb5 100644 --- a/src/common/translations/localize.ts +++ b/src/common/translations/localize.ts @@ -38,7 +38,7 @@ export type LocalizeKeys = // Tweaked from https://www.raygesualdo.com/posts/flattening-object-keys-with-typescript-types export type FlattenObjectKeys< T extends Record, - Key extends keyof T = keyof T + Key extends keyof T = keyof T, > = Key extends string ? T[Key] extends Record ? `${Key}.${FlattenObjectKeys}` diff --git a/src/components/chart/ha-chart-base.ts b/src/components/chart/ha-chart-base.ts index 902d567885..389fd8dab6 100644 --- a/src/components/chart/ha-chart-base.ts +++ b/src/components/chart/ha-chart-base.ts @@ -108,23 +108,24 @@ export default class HaChartBase extends LitElement { ? html`
    ${this.data.datasets.map( - (dataset, index) => html`
  • -
    + html`
-
${dataset.label}
- ` + .title=${dataset.label} + > +
+
${dataset.label}
+ ` )} ` @@ -156,18 +157,19 @@ export default class HaChartBase extends LitElement {
    ${this._tooltip.body.map( - (item, i) => html`
  • -
    - ${item.lines.join("\n")} -
  • ` + (item, i) => + html`
  • +
    + ${item.lines.join("\n")} +
  • ` )}
diff --git a/src/components/chart/state-history-chart-line.ts b/src/components/chart/state-history-chart-line.ts index b90d57fb62..37f831c192 100644 --- a/src/components/chart/state-history-chart-line.ts +++ b/src/components/chart/state-history-chart-line.ts @@ -328,23 +328,94 @@ class StateHistoryChartLine extends LitElement { } }); } else if (domain === "humidifier") { + const hasAction = states.states.some( + (entityState) => entityState.attributes?.action + ); + const hasCurrent = states.states.some( + (entityState) => entityState.attributes?.current_humidity + ); + + const hasHumidifying = + hasAction && + states.states.some( + (entityState: LineChartState) => + entityState.attributes?.action === "humidifying" + ); + const hasDrying = + hasAction && + states.states.some( + (entityState: LineChartState) => + entityState.attributes?.action === "drying" + ); + addDataSet( `${this.hass.localize("ui.card.humidifier.target_humidity_entity", { name: name, })}` ); - addDataSet( - `${this.hass.localize("ui.card.humidifier.on_entity", { - name: name, - })}`, - true - ); + + if (hasCurrent) { + addDataSet( + `${this.hass.localize( + "ui.card.humidifier.current_humidity_entity", + { + name: name, + } + )}` + ); + } + + // If action attribute is available, we used it to shade the area below the humidity. + // If action attribute is not available, we shade the area when the device is on + if (hasHumidifying) { + addDataSet( + `${this.hass.localize("ui.card.humidifier.humidifying", { + name: name, + })}`, + true, + computedStyles.getPropertyValue("--state-humidifier-on-color") + ); + } else if (hasDrying) { + addDataSet( + `${this.hass.localize("ui.card.humidifier.drying", { + name: name, + })}`, + true, + computedStyles.getPropertyValue("--state-humidifier-on-color") + ); + } else { + addDataSet( + `${this.hass.localize("ui.card.humidifier.on_entity", { + name: name, + })}`, + true + ); + } states.states.forEach((entityState) => { if (!entityState.attributes) return; const target = safeParseFloat(entityState.attributes.humidity); + // If the current humidity is not available, then we fill up to the target humidity + const current = hasCurrent + ? safeParseFloat(entityState.attributes?.current_humidity) + : target; const series = [target]; - series.push(entityState.state === "on" ? target : null); + + if (hasCurrent) { + series.push(current); + } + + if (hasHumidifying) { + series.push( + entityState.attributes?.action === "humidifying" ? current : null + ); + } else if (hasDrying) { + series.push( + entityState.attributes?.action === "drying" ? current : null + ); + } else { + series.push(entityState.state === "on" ? current : null); + } pushData(new Date(entityState.last_changed), series); }); } else { diff --git a/src/components/chart/state-history-charts.ts b/src/components/chart/state-history-charts.ts index 0ce32a583e..2ed678b01c 100644 --- a/src/components/chart/state-history-charts.ts +++ b/src/components/chart/state-history-charts.ts @@ -184,7 +184,17 @@ export class StateHistoryCharts extends LitElement { }; protected shouldUpdate(changedProps: PropertyValues): boolean { - return !(changedProps.size === 1 && changedProps.has("hass")); + if (changedProps.size === 1 && changedProps.has("hass")) { + return false; + } + if ( + changedProps.size === 1 && + changedProps.has("_maxYWidth") && + changedProps.get("_maxYWidth") === this._maxYWidth + ) { + return false; + } + return true; } protected willUpdate() { diff --git a/src/components/data-table/ha-data-table.ts b/src/components/data-table/ha-data-table.ts index 6aa6233b6d..5426e1179e 100644 --- a/src/components/data-table/ha-data-table.ts +++ b/src/components/data-table/ha-data-table.ts @@ -338,7 +338,8 @@ export class HaDataTable extends LitElement {
- ${this.noDataText || "No data"} + ${this.noDataText || + this.hass.localize("ui.components.data-table.no-data")}
diff --git a/src/components/device/ha-area-devices-picker.ts b/src/components/device/ha-area-devices-picker.ts index d7c4a1d0b3..8964ff566c 100644 --- a/src/components/device/ha-area-devices-picker.ts +++ b/src/components/device/ha-area-devices-picker.ts @@ -36,12 +36,11 @@ interface AreaDevices { devices: string[]; } -const rowRenderer: ComboBoxLitRenderer = ( - item -) => html` - ${item.name} - ${item.devices.length} devices -`; +const rowRenderer: ComboBoxLitRenderer = (item) => + html` + ${item.name} + ${item.devices.length} devices + `; @customElement("ha-area-devices-picker") export class HaAreaDevicesPicker extends SubscribeMixin(LitElement) { diff --git a/src/components/device/ha-device-automation-picker.ts b/src/components/device/ha-device-automation-picker.ts index 0189fc5d4c..87257aba4f 100644 --- a/src/components/device/ha-device-automation-picker.ts +++ b/src/components/device/ha-device-automation-picker.ts @@ -17,7 +17,7 @@ const NO_AUTOMATION_KEY = "NO_AUTOMATION"; const UNKNOWN_AUTOMATION_KEY = "UNKNOWN_AUTOMATION"; export abstract class HaDeviceAutomationPicker< - T extends DeviceAutomation + T extends DeviceAutomation, > extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; diff --git a/src/components/device/ha-device-picker.ts b/src/components/device/ha-device-picker.ts index fb837d15b2..3b54cec2d5 100644 --- a/src/components/device/ha-device-picker.ts +++ b/src/components/device/ha-device-picker.ts @@ -45,12 +45,11 @@ export type HaDevicePickerDeviceFilterFunc = ( export type HaDevicePickerEntityFilterFunc = (entity: HassEntity) => boolean; -const rowRenderer: ComboBoxLitRenderer = (item) => html` - ${item.name} - ${item.area} -`; +const rowRenderer: ComboBoxLitRenderer = (item) => + html` + ${item.name} + ${item.area} + `; @customElement("ha-device-picker") export class HaDevicePicker extends SubscribeMixin(LitElement) { @@ -231,19 +230,23 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) { ); } - const outputDevices = inputDevices.map((device) => ({ - id: device.id, - name: computeDeviceName( + const outputDevices = inputDevices.map((device) => { + const name = computeDeviceName( device, this.hass, deviceEntityLookup[device.id] - ), - area: - device.area_id && areaLookup[device.area_id] - ? areaLookup[device.area_id].name - : this.hass.localize("ui.components.device-picker.no_area"), - strings: [device.name || ""], - })); + ); + + return { + id: device.id, + name: name, + area: + device.area_id && areaLookup[device.area_id] + ? areaLookup[device.area_id].name + : this.hass.localize("ui.components.device-picker.no_area"), + strings: [name || ""], + }; + }); if (!outputDevices.length) { return [ { diff --git a/src/components/entity/ha-entities-picker.ts b/src/components/entity/ha-entities-picker.ts index 8eae3577bb..21aebdfd2c 100644 --- a/src/components/entity/ha-entities-picker.ts +++ b/src/components/entity/ha-entities-picker.ts @@ -130,9 +130,9 @@ class HaEntitiesPickerLight extends LitElement { private _getEntityFilter = memoizeOne( ( - value: string[] | undefined, - entityFilter: HaEntityPickerEntityFilterFunc | undefined - ): HaEntityPickerEntityFilterFunc => + value: string[] | undefined, + entityFilter: HaEntityPickerEntityFilterFunc | undefined + ): HaEntityPickerEntityFilterFunc => (stateObj: HassEntity) => (!value || !value.includes(stateObj.entity_id)) && (!entityFilter || entityFilter(stateObj)) diff --git a/src/components/entity/ha-statistic-picker.ts b/src/components/entity/ha-statistic-picker.ts index fc40f169ea..e9a9388243 100644 --- a/src/components/entity/ha-statistic-picker.ts +++ b/src/components/entity/ha-statistic-picker.ts @@ -87,26 +87,28 @@ export class HaStatisticPicker extends LitElement { private _statistics: StatisticItem[] = []; - private _rowRenderer: ComboBoxLitRenderer = ( - item - ) => html` - ${item.state - ? html`` - : ""} - ${item.name} - ${item.id === "" || item.id === "__missing" - ? html`${this.hass.localize( - "ui.components.statistic-picker.learn_more" - )}` - : item.id} - `; + private _rowRenderer: ComboBoxLitRenderer = (item) => + html` + ${item.state + ? html`` + : ""} + ${item.name} + ${item.id === "" || item.id === "__missing" + ? html`${this.hass.localize( + "ui.components.statistic-picker.learn_more" + )}` + : item.id} + `; private _getStatistics = memoizeOne( ( @@ -263,7 +265,9 @@ export class HaStatisticPicker extends LitElement { .renderer=${this._rowRenderer} .disabled=${this.disabled} .allowCustomValue=${this.allowCustomEntity} - .filteredItems=${this._statistics} + .filteredItems=${this.value && this._statistics.length === 0 + ? undefined + : this._statistics} item-value-path="id" item-id-path="id" item-label-path="name" diff --git a/src/components/entity/state-badge.ts b/src/components/entity/state-badge.ts index 2b6f936497..1c91fce31b 100644 --- a/src/components/entity/state-badge.ts +++ b/src/components/entity/state-badge.ts @@ -211,7 +211,9 @@ export class StateBadge extends LitElement { background: var(--divider-color); } ha-state-icon { - transition: color 0.3s ease-in-out, filter 0.3s ease-in-out; + transition: + color 0.3s ease-in-out, + filter 0.3s ease-in-out; } .missing { color: #fce588; diff --git a/src/components/ha-addon-picker.ts b/src/components/ha-addon-picker.ts index 099da62e9f..c169ecc532 100644 --- a/src/components/ha-addon-picker.ts +++ b/src/components/ha-addon-picker.ts @@ -11,19 +11,18 @@ import "./ha-combo-box"; import type { HaComboBox } from "./ha-combo-box"; import "./ha-list-item"; -const rowRenderer: ComboBoxLitRenderer = ( - item -) => html` - ${item.name} - ${item.slug} - ${item.icon - ? html`` - : ""} -`; +const rowRenderer: ComboBoxLitRenderer = (item) => + html` + ${item.name} + ${item.slug} + ${item.icon + ? html`` + : ""} + `; @customElement("ha-addon-picker") class HaAddonPicker extends LitElement { diff --git a/src/components/ha-analytics.ts b/src/components/ha-analytics.ts index 9faec6a273..15e356582d 100644 --- a/src/components/ha-analytics.ts +++ b/src/components/ha-analytics.ts @@ -53,39 +53,38 @@ export class HaAnalytics extends LitElement { ${ADDITIONAL_PREFERENCES.map( - (preference) => - html` - - - ${this.localize( - `ui.panel.${this.translationKeyPanel}.analytics.preferences.${preference}.title` - )} - - - ${this.localize( - `ui.panel.${this.translationKeyPanel}.analytics.preferences.${preference}.description` - )} - - - - - ${!baseEnabled - ? html` - - ${this.localize( - `ui.panel.${this.translationKeyPanel}.analytics.need_base_enabled` - )} - - ` - : ""} - - - ` + (preference) => html` + + + ${this.localize( + `ui.panel.${this.translationKeyPanel}.analytics.preferences.${preference}.title` + )} + + + ${this.localize( + `ui.panel.${this.translationKeyPanel}.analytics.preferences.${preference}.description` + )} + + + + + ${!baseEnabled + ? html` + + ${this.localize( + `ui.panel.${this.translationKeyPanel}.analytics.need_base_enabled` + )} + + ` + : ""} + + + ` )} diff --git a/src/components/ha-area-picker.ts b/src/components/ha-area-picker.ts index 1ea409aafe..5d56c69082 100644 --- a/src/components/ha-area-picker.ts +++ b/src/components/ha-area-picker.ts @@ -34,13 +34,12 @@ import "./ha-svg-icon"; type ScorableAreaRegistryEntry = ScorableTextItem & AreaRegistryEntry; -const rowRenderer: ComboBoxLitRenderer = ( - item -) => html` - ${item.name} -`; +const rowRenderer: ComboBoxLitRenderer = (item) => + html` + ${item.name} + `; @customElement("ha-area-picker") export class HaAreaPicker extends LitElement { diff --git a/src/components/ha-assist-pipeline-picker.ts b/src/components/ha-assist-pipeline-picker.ts index 0d51bc1444..80a69b2d27 100644 --- a/src/components/ha-assist-pipeline-picker.ts +++ b/src/components/ha-assist-pipeline-picker.ts @@ -16,7 +16,8 @@ import "./ha-list-item"; import "./ha-select"; import type { HaSelect } from "./ha-select"; -const PREFERRED = "__PREFERRED_PIPELINE_OPTION__"; +const PREFERRED = "preferred"; +const LAST_USED = "last_used"; @customElement("ha-assist-pipeline-picker") export class HaAssistPipelinePicker extends LitElement { @@ -30,15 +31,21 @@ export class HaAssistPipelinePicker extends LitElement { @property({ type: Boolean }) public required = false; + @property() public includeLastUsed = false; + @state() _pipelines?: AssistPipeline[]; @state() _preferredPipeline: string | null = null; + private get _default() { + return this.includeLastUsed ? LAST_USED : PREFERRED; + } + protected render() { if (!this._pipelines) { return nothing; } - const value = this.value ?? PREFERRED; + const value = this.value ?? this._default; return html` + ${this.includeLastUsed + ? html` + + ${this.hass!.localize( + "ui.components.pipeline-picker.last_used" + )} + + ` + : null} ${this.hass!.localize("ui.components.pipeline-picker.preferred", { preferred: this._pipelines.find( @@ -93,11 +109,11 @@ export class HaAssistPipelinePicker extends LitElement { !this.hass || target.value === "" || target.value === this.value || - (this.value === undefined && target.value === PREFERRED) + (this.value === undefined && target.value === this._default) ) { return; } - this.value = target.value === PREFERRED ? undefined : target.value; + this.value = target.value === this._default ? undefined : target.value; fireEvent(this, "value-changed", { value: this.value }); } } diff --git a/src/components/ha-button-toggle-group.ts b/src/components/ha-button-toggle-group.ts index 8534cfba0b..e4dd2e9524 100644 --- a/src/components/ha-button-toggle-group.ts +++ b/src/components/ha-button-toggle-group.ts @@ -94,7 +94,9 @@ export class HaButtonToggleGroup extends LitElement { opacity: 0; pointer-events: none; content: ""; - transition: opacity 15ms linear, background-color 15ms linear; + transition: + opacity 15ms linear, + background-color 15ms linear; } ha-icon-button[active]::before, mwc-button[active]::before { diff --git a/src/components/ha-button.ts b/src/components/ha-button.ts index 959f679431..df7bdf46e5 100644 --- a/src/components/ha-button.ts +++ b/src/components/ha-button.ts @@ -12,6 +12,7 @@ export class HaButton extends Button { margin-inline-start: 0px; margin-inline-end: 8px; direction: var(--direction); + display: block; } .mdc-button { height: var(--button-height, 36px); diff --git a/src/components/ha-climate-state.ts b/src/components/ha-climate-state.ts index 7a1617e4ee..b90b51fee1 100644 --- a/src/components/ha-climate-state.ts +++ b/src/components/ha-climate-state.ts @@ -172,7 +172,6 @@ class HaClimateState extends LitElement { .state-label { font-weight: bold; - text-transform: capitalize; } .unit { diff --git a/src/components/ha-combo-box.ts b/src/components/ha-combo-box.ts index 4b6c9b1ed5..ca549b7567 100644 --- a/src/components/ha-combo-box.ts +++ b/src/components/ha-combo-box.ts @@ -173,7 +173,7 @@ export class HaComboBox extends LitElement { autocapitalize="none" autocomplete="off" autocorrect="off" - spellcheck="false" + input-spellcheck="false" .suffix=${html`
= ( - item - ) => html` - ${item.title || - this.hass.localize( - "ui.panel.config.integrations.config_entry.unnamed_entry" - )} - ${item.localized_domain_name} - - `; + private _rowRenderer: ComboBoxLitRenderer = (item) => + html` + ${item.title || + this.hass.localize( + "ui.panel.config.integrations.config_entry.unnamed_entry" + )} + ${item.localized_domain_name} + + `; protected render() { if (!this._configEntries) { diff --git a/src/components/ha-control-button.ts b/src/components/ha-control-button.ts index 8c8f467f76..1eee1286e6 100644 --- a/src/components/ha-control-button.ts +++ b/src/components/ha-control-button.ts @@ -122,7 +122,8 @@ export class HaControlButton extends LitElement { height: 100%; width: 100%; background-color: var(--control-button-background-color); - transition: background-color 180ms ease-in-out, + transition: + background-color 180ms ease-in-out, opacity 180ms ease-in-out; opacity: var(--control-button-background-opacity); } diff --git a/src/components/ha-control-circular-slider.ts b/src/components/ha-control-circular-slider.ts index 97bc2ea566..5b3caf3bef 100644 --- a/src/components/ha-control-circular-slider.ts +++ b/src/components/ha-control-circular-slider.ts @@ -566,7 +566,9 @@ export class HaControlCircularSlider extends LitElement { fill: none; stroke: var(--control-circular-slider-background); opacity: var(--control-circular-slider-background-opacity); - transition: stroke 180ms ease-in-out, opacity 180ms ease-in-out; + transition: + stroke 180ms ease-in-out, + opacity 180ms ease-in-out; stroke-linecap: round; stroke-width: 24px; } @@ -576,9 +578,11 @@ export class HaControlCircularSlider extends LitElement { fill: none; stroke-linecap: round; stroke-width: 24px; - transition: stroke-width 300ms ease-in-out, + transition: + stroke-width 300ms ease-in-out, stroke-dasharray 300ms ease-in-out, - stroke-dashoffset 300ms ease-in-out, stroke 180ms ease-in-out, + stroke-dashoffset 300ms ease-in-out, + stroke 180ms ease-in-out, opacity 180ms ease-in-out; } diff --git a/src/components/ha-control-select.ts b/src/components/ha-control-select.ts index 1a48c0574c..855fc338a1 100644 --- a/src/components/ha-control-select.ts +++ b/src/components/ha-control-select.ts @@ -283,7 +283,9 @@ export class HaControlSelect extends LitElement { width: 100%; background-color: var(--control-select-color); opacity: 0; - transition: background-color ease-in-out 180ms, opacity ease-in-out 80ms; + transition: + background-color ease-in-out 180ms, + opacity ease-in-out 80ms; } .option.focused::before, .option:hover::before { diff --git a/src/components/ha-control-slider.ts b/src/components/ha-control-slider.ts index 3f4abcf4e3..c3450c6014 100644 --- a/src/components/ha-control-slider.ts +++ b/src/components/ha-control-slider.ts @@ -327,7 +327,8 @@ export class HaControlSlider extends LitElement { height: 100%; width: 100%; background-color: var(--control-slider-color); - transition: transform 180ms ease-in-out, + transition: + transform 180ms ease-in-out, background-color 180ms ease-in-out; } .slider .slider-track-bar.show-handle { @@ -427,7 +428,9 @@ export class HaControlSlider extends LitElement { position: absolute; background-color: white; border-radius: var(--handle-size); - transition: left 180ms ease-in-out, bottom 180ms ease-in-out; + transition: + left 180ms ease-in-out, + bottom 180ms ease-in-out; top: 0; bottom: 0; left: calc(var(--value, 0) * (100% - var(--cursor-size))); diff --git a/src/components/ha-control-switch.ts b/src/components/ha-control-switch.ts index ae15ce98b7..759ee93f9d 100644 --- a/src/components/ha-control-switch.ts +++ b/src/components/ha-control-switch.ts @@ -208,7 +208,8 @@ export class HaControlSwitch extends LitElement { border-radius: calc( var(--control-switch-border-radius) - var(--control-switch-padding) ); - transition: transform 180ms ease-in-out, + transition: + transform 180ms ease-in-out, background-color 180ms ease-in-out; background-color: var(--control-switch-off-color); color: white; diff --git a/src/components/ha-form/ha-form-grid.ts b/src/components/ha-form/ha-form-grid.ts index f74377c12a..a3fbcb079a 100644 --- a/src/components/ha-form/ha-form-grid.ts +++ b/src/components/ha-form/ha-form-grid.ts @@ -55,17 +55,16 @@ export class HaFormGrid extends LitElement implements HaFormElement { protected render(): TemplateResult { return html` ${this.schema.schema.map( - (item) => - html` - - ` + (item) => html` + + ` )} `; } diff --git a/src/components/ha-form/ha-form-multi_select.ts b/src/components/ha-form/ha-form-multi_select.ts index e56d902b97..66c7d60ca6 100644 --- a/src/components/ha-form/ha-form-multi_select.ts +++ b/src/components/ha-form/ha-form-multi_select.ts @@ -91,7 +91,11 @@ export class HaFormMultiSelect extends LitElement implements HaFormElement { slot="trigger" .label=${this.label} .value=${data - .map((value) => this.schema.options![value] || value) + .map( + (value) => + optionLabel(options.find((v) => optionValue(v) === value)) || + value + ) .join(", ")} .disabled=${this.disabled} tabindex="-1" diff --git a/src/components/ha-form/types.ts b/src/components/ha-form/types.ts index 287b904780..e2e032312d 100644 --- a/src/components/ha-form/types.ts +++ b/src/components/ha-form/types.ts @@ -98,7 +98,7 @@ export interface HaFormTimeSchema extends HaFormBaseSchema { // Type utility to unionize a schema array by flattening any grid schemas export type SchemaUnion< SchemaArray extends readonly HaFormSchema[], - Schema = SchemaArray[number] + Schema = SchemaArray[number], > = Schema extends HaFormGridSchema | HaFormExpandableSchema ? SchemaUnion : Schema; diff --git a/src/components/ha-gauge.ts b/src/components/ha-gauge.ts index 1895e419db..e6faa19773 100644 --- a/src/components/ha-gauge.ts +++ b/src/components/ha-gauge.ts @@ -138,12 +138,12 @@ export class Gauge extends LitElement { : this.valueText || formatNumber(this.value, this.locale, this.formatOptions) }${ - this._segment_label - ? "" - : this.label === "%" - ? blankBeforePercent(this.locale) + "%" - : ` ${this.label}` - } + this._segment_label + ? "" + : this.label === "%" + ? blankBeforePercent(this.locale) + "%" + : ` ${this.label}` + } `; } diff --git a/src/components/ha-hs-color-picker.ts b/src/components/ha-hs-color-picker.ts index ba5d038526..cef11cfc38 100644 --- a/src/components/ha-hs-color-picker.ts +++ b/src/components/ha-hs-color-picker.ts @@ -406,7 +406,9 @@ class HaHsColorPicker extends LitElement { filter: url(#marker-shadow); } .container:not(.pressed) circle { - transition: transform 100ms ease-in-out, fill 100ms ease-in-out; + transition: + transform 100ms ease-in-out, + fill 100ms ease-in-out; } .container:not(.pressed) .cursor { transition: transform 200ms ease-in-out; diff --git a/src/components/ha-humidifier-state.ts b/src/components/ha-humidifier-state.ts index fbf9cfe519..45af8a3384 100644 --- a/src/components/ha-humidifier-state.ts +++ b/src/components/ha-humidifier-state.ts @@ -119,7 +119,6 @@ class HaHumidifierState extends LitElement { .state-label { font-weight: bold; - text-transform: capitalize; } .unit { diff --git a/src/components/ha-mount-picker.ts b/src/components/ha-mount-picker.ts index fd47688001..6a35dea416 100644 --- a/src/components/ha-mount-picker.ts +++ b/src/components/ha-mount-picker.ts @@ -81,28 +81,25 @@ class HaMountPicker extends LitElement { ? dataDiskOption : nothing} ${this._filterMounts(this._mounts, this.usage).map( - (mount) => html` - ${mount.name} - ${mount.server}${mount.port - ? `:${mount.port}` - : nothing}${mount.type === SupervisorMountType.NFS - ? mount.path - : `:${mount.share}`} - - ` + (mount) => + html` + ${mount.name} + ${mount.server}${mount.port + ? `:${mount.port}` + : nothing}${mount.type === SupervisorMountType.NFS + ? mount.path + : `:${mount.share}`} + + ` )} ${this.usage === SupervisorMountUsage.BACKUP && this._mounts.default_backup_mount diff --git a/src/components/ha-outlined-icon-button.ts b/src/components/ha-outlined-icon-button.ts index 33df9638bd..1ca26ccf97 100644 --- a/src/components/ha-outlined-icon-button.ts +++ b/src/components/ha-outlined-icon-button.ts @@ -23,6 +23,7 @@ export class HaOutlinedIconButton extends IconButton { --md-sys-color-on-surface: var(--secondary-text-color); --md-sys-color-on-surface-variant: var(--secondary-text-color); --md-sys-color-on-surface-rgb: var(--rgb-secondary-text-color); + --md-sys-color-outline: var(--secondary-text-color); } :host([no-ripple]) .outlined { --md-ripple-focus-opacity: 0; diff --git a/src/components/ha-selector/ha-selector-assist-pipeline.ts b/src/components/ha-selector/ha-selector-assist-pipeline.ts index 74a143b819..9a00519f07 100644 --- a/src/components/ha-selector/ha-selector-assist-pipeline.ts +++ b/src/components/ha-selector/ha-selector-assist-pipeline.ts @@ -21,14 +21,19 @@ export class HaAssistPipelineSelector extends LitElement { @property({ type: Boolean }) public required = true; protected render() { - return html``; + return html` + + `; } static styles = css` diff --git a/src/components/ha-selector/ha-selector-condition.ts b/src/components/ha-selector/ha-selector-condition.ts new file mode 100644 index 0000000000..fe76180793 --- /dev/null +++ b/src/components/ha-selector/ha-selector-condition.ts @@ -0,0 +1,48 @@ +import { css, CSSResultGroup, html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; +import { Condition } from "../../data/automation"; +import { ConditionSelector } from "../../data/selector"; +import "../../panels/config/automation/condition/ha-automation-condition"; +import { HomeAssistant } from "../../types"; + +@customElement("ha-selector-condition") +export class HaConditionSelector extends LitElement { + @property() public hass!: HomeAssistant; + + @property() public selector!: ConditionSelector; + + @property() public value?: Condition; + + @property() public label?: string; + + @property({ type: Boolean, reflect: true }) public disabled = false; + + protected render() { + return html` + + `; + } + + static get styles(): CSSResultGroup { + return css` + ha-automation-condition { + display: block; + margin-bottom: 16px; + } + :host([disabled]) ha-automation-condition { + opacity: var(--light-disabled-opacity); + pointer-events: none; + } + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-selector-condition": HaConditionSelector; + } +} diff --git a/src/components/ha-selector/ha-selector-select.ts b/src/components/ha-selector/ha-selector-select.ts index e8bd3ac4b4..71747c4d27 100644 --- a/src/components/ha-selector/ha-selector-select.ts +++ b/src/components/ha-selector/ha-selector-select.ts @@ -112,19 +112,18 @@ export class HaSelectSelector extends LitElement { ${value?.length ? html` ${value.map( - (item, idx) => - html` - - ${options.find((option) => option.value === item) - ?.label || item} - - - ` + (item, idx) => html` + + ${options.find((option) => option.value === item)?.label || + item} + + + ` )} ` : ""} diff --git a/src/components/ha-selector/ha-selector-text.ts b/src/components/ha-selector/ha-selector-text.ts index fb8033790a..2c89b3c588 100644 --- a/src/components/ha-selector/ha-selector-text.ts +++ b/src/components/ha-selector/ha-selector-text.ts @@ -65,6 +65,7 @@ export class HaTextSelector extends LitElement { .type=${this._unmaskedPassword ? "text" : this.selector.text?.type} @input=${this._handleChange} .label=${this.label || ""} + .prefix=${this.selector.text?.prefix} .suffix=${this.selector.text?.type === "password" ? // reserve some space for the icon. html`
` diff --git a/src/components/ha-selector/ha-selector.ts b/src/components/ha-selector/ha-selector.ts index 2e7e5143d8..9c831c0a10 100644 --- a/src/components/ha-selector/ha-selector.ts +++ b/src/components/ha-selector/ha-selector.ts @@ -3,9 +3,9 @@ import { customElement, property } from "lit/decorators"; import memoizeOne from "memoize-one"; import { dynamicElement } from "../../common/dom/dynamic-element-directive"; import { - Selector, - handleLegacyEntitySelector, handleLegacyDeviceSelector, + handleLegacyEntitySelector, + Selector, } from "../../data/selector"; import type { HomeAssistant } from "../../types"; @@ -17,6 +17,7 @@ const LOAD_ELEMENTS = { assist_pipeline: () => import("./ha-selector-assist-pipeline"), boolean: () => import("./ha-selector-boolean"), color_rgb: () => import("./ha-selector-color-rgb"), + condition: () => import("./ha-selector-condition"), config_entry: () => import("./ha-selector-config-entry"), conversation_agent: () => import("./ha-selector-conversation-agent"), constant: () => import("./ha-selector-constant"), diff --git a/src/components/ha-service-control.ts b/src/components/ha-service-control.ts index 21e5289e5f..5abd368056 100644 --- a/src/components/ha-service-control.ts +++ b/src/components/ha-service-control.ts @@ -89,6 +89,10 @@ export class HaServiceControl extends LitElement { @query("ha-yaml-editor") private _yamlEditor?: HaYamlEditor; protected willUpdate(changedProperties: PropertyValues) { + if (!this.hasUpdated) { + this.hass.loadBackendTranslation("services"); + this.hass.loadBackendTranslation("selector"); + } if (!changedProperties.has("value")) { return; } @@ -342,6 +346,20 @@ export class HaServiceControl extends LitElement { const filteredFields = this._filterFields(serviceData, this._value); + const domain = this._value?.service + ? computeDomain(this._value.service) + : undefined; + const serviceName = this._value?.service + ? computeObjectId(this._value.service) + : undefined; + + const description = + (serviceName && + this.hass.localize( + `component.${domain}.services.${serviceName}.description` + )) || + serviceData?.description; + return html`
- ${serviceData?.description - ? html`

${serviceData?.description}

` - : ""} + ${description ? html`

${description}

` : ""} ${this._manifest ? html` ` @@ -437,8 +455,18 @@ export class HaServiceControl extends LitElement { @change=${this._checkboxChanged} slot="prefix" >`} - ${dataField.name || dataField.key} - ${dataField?.description} + ${this.hass.localize( + `component.${domain}.services.${serviceName}.fields.${dataField.key}.name` + ) || + dataField.name || + dataField.key} + ${this.hass.localize( + `component.${domain}.services.${serviceName}.fields.${dataField.key}.description` + ) || dataField?.description} ` : ""; })}`; } + private _localizeValueCallback = (key: string) => { + if (!this._value?.service) { + return ""; + } + return this.hass.localize( + `component.${computeDomain(this._value.service)}.selector.${key}` + ); + }; + private _checkboxChanged(ev) { const checked = ev.currentTarget.checked; const key = ev.currentTarget.key; diff --git a/src/components/ha-service-description.js b/src/components/ha-service-description.js deleted file mode 100644 index c2d3359bcc..0000000000 --- a/src/components/ha-service-description.js +++ /dev/null @@ -1,27 +0,0 @@ -import { html } from "@polymer/polymer/lib/utils/html-tag"; -/* eslint-plugin-disable lit */ -import { PolymerElement } from "@polymer/polymer/polymer-element"; - -class HaServiceDescription extends PolymerElement { - static get template() { - return html` [[_getDescription(hass, domain, service)]] `; - } - - static get properties() { - return { - hass: Object, - domain: String, - service: String, - }; - } - - _getDescription(hass, domain, service) { - const domainServices = hass.services[domain]; - if (!domainServices) return ""; - const serviceObject = domainServices[service]; - if (!serviceObject) return ""; - return serviceObject.description; - } -} - -customElements.define("ha-service-description", HaServiceDescription); diff --git a/src/components/ha-service-picker.ts b/src/components/ha-service-picker.ts index 76532a331d..db4dec62d7 100644 --- a/src/components/ha-service-picker.ts +++ b/src/components/ha-service-picker.ts @@ -10,12 +10,13 @@ import "./ha-combo-box"; const rowRenderer: ComboBoxLitRenderer<{ service: string; name: string }> = ( item -) => html` - ${item.name} - ${item.name === item.service ? "" : item.service} -`; +) => + html` + ${item.name} + ${item.name === item.service ? "" : item.service} + `; @customElement("ha-service-picker") class HaServicePicker extends LitElement { @@ -27,6 +28,12 @@ class HaServicePicker extends LitElement { @state() private _filter?: string; + protected willUpdate() { + if (!this.hasUpdated) { + this.hass.loadBackendTranslation("services"); + } + } + protected render() { return html` - ${this.hass!.localize( - "ui.components.theme-picker.no_theme" - )} + ${!this.required + ? html` + + ${this.hass!.localize("ui.components.theme-picker.no_theme")} + + ` + : nothing} ${this.includeDefault - ? html`${this.hass!.localize( - "ui.components.theme-picker.default" - )}` + ? html` + + Home Assistant + + ` : nothing} ${Object.keys(this.hass!.themes.themes) .sort() diff --git a/src/components/ha-tts-voice-picker.ts b/src/components/ha-tts-voice-picker.ts index 8cbe24dffd..cfea9c3c5c 100644 --- a/src/components/ha-tts-voice-picker.ts +++ b/src/components/ha-tts-voice-picker.ts @@ -62,9 +62,10 @@ export class HaTTSVoicePicker extends LitElement { ` : nothing} ${this._voices.map( - (voice) => html` - ${voice.name} - ` + (voice) => + html` + ${voice.name} + ` )} `; diff --git a/src/components/ha-water_heater-state.js b/src/components/ha-water_heater-state.js index d4dc750640..4f2220fc58 100644 --- a/src/components/ha-water_heater-state.js +++ b/src/components/ha-water_heater-state.js @@ -29,7 +29,6 @@ class HaWaterHeaterState extends LocalizeMixin(PolymerElement) { .state-label { font-weight: bold; - text-transform: capitalize; } .label { diff --git a/src/components/map/ha-locations-editor.ts b/src/components/map/ha-locations-editor.ts index 9995094c95..76edc2606f 100644 --- a/src/components/map/ha-locations-editor.ts +++ b/src/components/map/ha-locations-editor.ts @@ -1,8 +1,9 @@ -import { +import type { Circle, DivIcon, DragEndEvent, LatLng, + LatLngExpression, Marker, MarkerOptions, } from "leaflet"; @@ -22,6 +23,8 @@ import type { HomeAssistant } from "../../types"; import "../ha-input-helper-text"; import "./ha-map"; import type { HaMap } from "./ha-map"; +import { HaIcon } from "../ha-icon"; +import { HaSvgIcon } from "../ha-svg-icon"; declare global { // for fire event @@ -40,6 +43,7 @@ export interface MarkerLocation { name?: string; id: string; icon?: string; + iconPath?: string; radius_color?: string; location_editable?: boolean; radius_editable?: boolean; @@ -81,11 +85,21 @@ export class HaLocationsEditor extends LitElement { ); } - public fitMap(): void { - this.map.fitMap(); + public fitMap(options?: { zoom?: number; pad?: number }): void { + this.map.fitMap(options); } - public async fitMarker(id: string): Promise { + public fitBounds( + boundingbox: LatLngExpression[], + options?: { zoom?: number; pad?: number } + ) { + this.map.fitBounds(boundingbox, options); + } + + public async fitMarker( + id: string, + options?: { zoom?: number } + ): Promise { if (!this.Leaflet) { await this._loadPromise; } @@ -104,7 +118,10 @@ export class HaLocationsEditor extends LitElement { if (circle) { this.map.leafletMap.fitBounds(circle.getBounds()); } else { - this.map.leafletMap.setView(marker.getLatLng(), this.zoom); + this.map.leafletMap.setView( + marker.getLatLng(), + options?.zoom || this.zoom + ); } } } @@ -199,15 +216,21 @@ export class HaLocationsEditor extends LitElement { this.locations.forEach((location: MarkerLocation) => { let icon: DivIcon | undefined; - if (location.icon) { + if (location.icon || location.iconPath) { // create icon const el = document.createElement("div"); el.className = "named-icon"; - if (location.name) { + if (location.name !== undefined) { el.innerText = location.name; } - const iconEl = document.createElement("ha-icon"); - iconEl.setAttribute("icon", location.icon); + let iconEl: HaIcon | HaSvgIcon; + if (location.icon) { + iconEl = document.createElement("ha-icon"); + iconEl.setAttribute("icon", location.icon); + } else { + iconEl = document.createElement("ha-svg-icon"); + iconEl.setAttribute("path", location.iconPath!); + } el.prepend(iconEl); icon = this.Leaflet!.divIcon({ diff --git a/src/components/map/ha-map.ts b/src/components/map/ha-map.ts index 507657ce15..8ff0b4275c 100644 --- a/src/components/map/ha-map.ts +++ b/src/components/map/ha-map.ts @@ -1,7 +1,8 @@ -import { +import type { Circle, CircleMarker, LatLngTuple, + LatLngExpression, Layer, Map, Marker, @@ -162,7 +163,7 @@ export class HaMap extends ReactiveElement { this._loaded = true; } - public fitMap(): void { + public fitMap(options?: { zoom?: number; pad?: number }): void { if (!this.leafletMap || !this.Leaflet || !this.hass) { return; } @@ -173,7 +174,7 @@ export class HaMap extends ReactiveElement { this.hass.config.latitude, this.hass.config.longitude ), - this.zoom + options?.zoom || this.zoom ); return; } @@ -196,11 +197,22 @@ export class HaMap extends ReactiveElement { ); }); - if (!this.layers) { - bounds = bounds.pad(0.5); - } + bounds = bounds.pad(options?.pad ?? 0.5); - this.leafletMap.fitBounds(bounds, { maxZoom: this.zoom }); + this.leafletMap.fitBounds(bounds, { maxZoom: options?.zoom || this.zoom }); + } + + public fitBounds( + boundingbox: LatLngExpression[], + options?: { zoom?: number; pad?: number } + ) { + if (!this.leafletMap || !this.Leaflet || !this.hass) { + return; + } + const bounds = this.Leaflet.latLngBounds(boundingbox).pad( + options?.pad ?? 0.5 + ); + this.leafletMap.fitBounds(bounds, { maxZoom: options?.zoom || this.zoom }); } private _drawLayers(prevLayers: Layer[] | undefined): void { diff --git a/src/components/media-player/ha-media-player-browse.ts b/src/components/media-player/ha-media-player-browse.ts index ae617af86b..2600758eac 100644 --- a/src/components/media-player/ha-media-player-browse.ts +++ b/src/components/media-player/ha-media-player-browse.ts @@ -930,7 +930,9 @@ export class HaMediaPlayerBrowse extends LitElement { margin-right: 16px; background-size: cover; border-radius: 2px; - transition: width 0.4s, height 0.4s; + transition: + width 0.4s, + height 0.4s; } .header-info { display: flex; @@ -977,7 +979,9 @@ export class HaMediaPlayerBrowse extends LitElement { overflow: hidden; text-overflow: ellipsis; margin-bottom: 0; - transition: height 0.5s, margin 0.5s; + transition: + height 0.5s, + margin 0.5s; } .not-shown { @@ -1121,7 +1125,9 @@ export class HaMediaPlayerBrowse extends LitElement { top: auto; bottom: 0px; right: 8px; - transition: bottom 0.1s ease-out, opacity 0.1s ease-out; + transition: + bottom 0.1s ease-out, + opacity 0.1s ease-out; } .child .play:hover { @@ -1220,7 +1226,10 @@ export class HaMediaPlayerBrowse extends LitElement { position: relative; background-position: center; border-radius: 0; - transition: width 0.4s, height 0.4s, padding-bottom 0.4s; + transition: + width 0.4s, + height 0.4s, + padding-bottom 0.4s; } ha-fab { position: absolute; diff --git a/src/components/search-input.ts b/src/components/search-input.ts index 0a2c8598d5..2f4298ecaa 100644 --- a/src/components/search-input.ts +++ b/src/components/search-input.ts @@ -33,7 +33,7 @@ class SearchInput extends LitElement { return html` - this.value?.map( - (user_id, idx) => html` -
- - - > -
- ` - ) + ${guard( + [notSelectedUsers], + () => + this.value?.map( + (user_id, idx) => html` +
+ + + > +
+ ` + ) )} + T extends Partial<{ [key in ValidKeys]: unknown }>, >( hass: HomeAssistant, config: T diff --git a/src/data/currency.ts b/src/data/currency.ts new file mode 100644 index 0000000000..a263641615 --- /dev/null +++ b/src/data/currency.ts @@ -0,0 +1,254 @@ +// From http://country.io/currency.json + +export const countryCurrency = { + BD: "BDT", + BE: "EUR", + BF: "XOF", + BG: "BGN", + BA: "BAM", + BB: "BBD", + WF: "XPF", + BL: "EUR", + BM: "BMD", + BN: "BND", + BO: "BOB", + BH: "BHD", + BI: "BIF", + BJ: "XOF", + BT: "BTN", + JM: "JMD", + BV: "NOK", + BW: "BWP", + WS: "WST", + BQ: "USD", + BR: "BRL", + BS: "BSD", + JE: "GBP", + BY: "BYN", + BZ: "BZD", + RU: "RUB", + RW: "RWF", + RS: "RSD", + TL: "USD", + RE: "EUR", + TM: "TMT", + TJ: "TJS", + RO: "RON", + TK: "NZD", + GW: "XOF", + GU: "USD", + GT: "GTQ", + GS: "GBP", + GR: "EUR", + GQ: "XAF", + GP: "EUR", + JP: "JPY", + GY: "GYD", + GG: "GBP", + GF: "EUR", + GE: "GEL", + GD: "XCD", + GB: "GBP", + GA: "XAF", + SV: "USD", + GN: "GNF", + GM: "GMD", + GL: "DKK", + GI: "GIP", + GH: "GHS", + OM: "OMR", + TN: "TND", + JO: "JOD", + HR: "EUR", + HT: "HTG", + HU: "HUF", + HK: "HKD", + HN: "HNL", + HM: "AUD", + VE: "VEF", + PR: "USD", + PS: "ILS", + PW: "USD", + PT: "EUR", + SJ: "NOK", + PY: "PYG", + IQ: "IQD", + PA: "PAB", + PF: "XPF", + PG: "PGK", + PE: "PEN", + PK: "PKR", + PH: "PHP", + PN: "NZD", + PL: "PLN", + PM: "EUR", + ZM: "ZMK", + EH: "MAD", + EE: "EUR", + EG: "EGP", + ZA: "ZAR", + EC: "USD", + IT: "EUR", + VN: "VND", + SB: "SBD", + ET: "ETB", + SO: "SOS", + ZW: "ZWL", + SA: "SAR", + ES: "EUR", + ER: "ERN", + ME: "EUR", + MD: "MDL", + MG: "MGA", + MF: "EUR", + MA: "MAD", + MC: "EUR", + UZ: "UZS", + MM: "MMK", + ML: "XOF", + MO: "MOP", + MN: "MNT", + MH: "USD", + MK: "MKD", + MU: "MUR", + MT: "EUR", + MW: "MWK", + MV: "MVR", + MQ: "EUR", + MP: "USD", + MS: "XCD", + MR: "MRO", + IM: "GBP", + UG: "UGX", + TZ: "TZS", + MY: "MYR", + MX: "MXN", + IL: "ILS", + FR: "EUR", + IO: "USD", + SH: "SHP", + FI: "EUR", + FJ: "FJD", + FK: "FKP", + FM: "USD", + FO: "DKK", + NI: "NIO", + NL: "EUR", + NO: "NOK", + NA: "NAD", + VU: "VUV", + NC: "XPF", + NE: "XOF", + NF: "AUD", + NG: "NGN", + NZ: "NZD", + NP: "NPR", + NR: "AUD", + NU: "NZD", + CK: "NZD", + XK: "EUR", + CI: "XOF", + CH: "CHF", + CO: "COP", + CN: "CNY", + CM: "XAF", + CL: "CLP", + CC: "AUD", + CA: "CAD", + CG: "XAF", + CF: "XAF", + CD: "CDF", + CZ: "CZK", + CY: "EUR", + CX: "AUD", + CR: "CRC", + CW: "ANG", + CV: "CVE", + CU: "CUP", + SZ: "SZL", + SY: "SYP", + SX: "ANG", + KG: "KGS", + KE: "KES", + SS: "SSP", + SR: "SRD", + KI: "AUD", + KH: "KHR", + KN: "XCD", + KM: "KMF", + ST: "STD", + SK: "EUR", + KR: "KRW", + SI: "EUR", + KP: "KPW", + KW: "KWD", + SN: "XOF", + SM: "EUR", + SL: "SLL", + SC: "SCR", + KZ: "KZT", + KY: "KYD", + SG: "SGD", + SE: "SEK", + SD: "SDG", + DO: "DOP", + DM: "XCD", + DJ: "DJF", + DK: "DKK", + VG: "USD", + DE: "EUR", + YE: "YER", + DZ: "DZD", + US: "USD", + UY: "UYU", + YT: "EUR", + UM: "USD", + LB: "LBP", + LC: "XCD", + LA: "LAK", + TV: "AUD", + TW: "TWD", + TT: "TTD", + TR: "TRY", + LK: "LKR", + LI: "CHF", + LV: "EUR", + TO: "TOP", + LT: "EUR", + LU: "EUR", + LR: "LRD", + LS: "LSL", + TH: "THB", + TF: "EUR", + TG: "XOF", + TD: "XAF", + TC: "USD", + LY: "LYD", + VA: "EUR", + VC: "XCD", + AE: "AED", + AD: "EUR", + AG: "XCD", + AF: "AFN", + AI: "XCD", + VI: "USD", + IS: "ISK", + IR: "IRR", + AM: "AMD", + AL: "ALL", + AO: "AOA", + AQ: "", + AS: "USD", + AR: "ARS", + AU: "AUD", + AT: "EUR", + AW: "AWG", + IN: "INR", + AX: "EUR", + AZ: "AZN", + IE: "EUR", + ID: "IDR", + UA: "UAH", + QA: "QAR", + MZ: "MZN", +}; diff --git a/src/data/entity_attributes.ts b/src/data/entity_attributes.ts index 7e3fae87aa..77dcc0b465 100644 --- a/src/data/entity_attributes.ts +++ b/src/data/entity_attributes.ts @@ -9,6 +9,7 @@ export const STATE_ATTRIBUTES = [ "emulated_hue_name", "emulated_hue", "entity_picture", + "event_types", "friendly_name", "haaska_hidden", "haaska_name", diff --git a/src/data/entity_registry.ts b/src/data/entity_registry.ts index 9063a8eade..70b0b30209 100644 --- a/src/data/entity_registry.ts +++ b/src/data/entity_registry.ts @@ -129,20 +129,20 @@ export interface EntityRegistryEntryUpdateParams { aliases?: string[]; } -export const findBatteryEntity = ( +export const findBatteryEntity = ( hass: HomeAssistant, - entities: EntityRegistryEntry[] -): EntityRegistryEntry | undefined => + entities: T[] +): T | undefined => entities.find( (entity) => hass.states[entity.entity_id] && hass.states[entity.entity_id].attributes.device_class === "battery" ); -export const findBatteryChargingEntity = ( +export const findBatteryChargingEntity = ( hass: HomeAssistant, - entities: EntityRegistryEntry[] -): EntityRegistryEntry | undefined => + entities: T[] +): T | undefined => entities.find( (entity) => hass.states[entity.entity_id] && diff --git a/src/data/frontend.ts b/src/data/frontend.ts index 8760859c65..9e0095e7a9 100644 --- a/src/data/frontend.ts +++ b/src/data/frontend.ts @@ -14,7 +14,7 @@ declare global { export type ValidUserDataKey = keyof FrontendUserData; export const fetchFrontendUserData = async < - UserDataKey extends ValidUserDataKey + UserDataKey extends ValidUserDataKey, >( conn: Connection, key: UserDataKey @@ -29,7 +29,7 @@ export const fetchFrontendUserData = async < }; export const saveFrontendUserData = async < - UserDataKey extends ValidUserDataKey + UserDataKey extends ValidUserDataKey, >( conn: Connection, key: UserDataKey, @@ -42,7 +42,7 @@ export const saveFrontendUserData = async < }); export const getOptimisticFrontendUserDataCollection = < - UserDataKey extends ValidUserDataKey + UserDataKey extends ValidUserDataKey, >( conn: Connection, userDataKey: UserDataKey diff --git a/src/data/history.ts b/src/data/history.ts index 8202f44167..653dbef356 100644 --- a/src/data/history.ts +++ b/src/data/history.ts @@ -29,6 +29,8 @@ const LINE_ATTRIBUTES_TO_KEEP = [ "hvac_action", "humidity", "mode", + "action", + "current_humidity", ]; export interface LineChartState { diff --git a/src/data/integration.ts b/src/data/integration.ts index af9478925a..151140bebd 100644 --- a/src/data/integration.ts +++ b/src/data/integration.ts @@ -4,11 +4,11 @@ import { HomeAssistant } from "../types"; import { debounce } from "../common/util/debounce"; export const integrationsWithPanel = { - matter: "/config/matter", - mqtt: "/config/mqtt", - thread: "/config/thread", - zha: "/config/zha/dashboard", - zwave_js: "/config/zwave_js/dashboard", + matter: "config/matter", + mqtt: "config/mqtt", + thread: "config/thread", + zha: "config/zha/dashboard", + zwave_js: "config/zwave_js/dashboard", }; export type IntegrationType = @@ -54,10 +54,8 @@ export interface IntegrationLogInfo { export enum LogSeverity { CRITICAL = 50, - FATAL = 50, ERROR = 40, WARNING = 30, - WARN = 30, INFO = 20, DEBUG = 10, NOTSET = 0, diff --git a/src/data/lock.ts b/src/data/lock.ts index a6c9914559..df79b4e223 100644 --- a/src/data/lock.ts +++ b/src/data/lock.ts @@ -2,6 +2,8 @@ import { HassEntityAttributeBase, HassEntityBase, } from "home-assistant-js-websocket"; +import { showEnterCodeDialogDialog } from "../dialogs/enter-code/show-enter-code-dialog"; +import { HomeAssistant } from "../types"; export const FORMAT_TEXT = "text"; export const FORMAT_NUMBER = "number"; @@ -18,3 +20,32 @@ interface LockEntityAttributes extends HassEntityAttributeBase { export interface LockEntity extends HassEntityBase { attributes: LockEntityAttributes; } + +type ProtectedLockService = "lock" | "unlock" | "open"; + +export const callProtectedLockService = async ( + element: HTMLElement, + hass: HomeAssistant, + stateObj: LockEntity, + service: ProtectedLockService +) => { + let code: string | undefined; + + if (stateObj!.attributes.code_format) { + const response = await showEnterCodeDialogDialog(element, { + codeFormat: "text", + codePattern: stateObj!.attributes.code_format, + title: hass.localize(`ui.dialogs.more_info_control.lock.${service}`), + submitText: hass.localize(`ui.dialogs.more_info_control.lock.${service}`), + }); + if (!response) { + throw new Error("Code dialog closed"); + } + code = response; + } + + await hass.callService("lock", service, { + entity_id: stateObj!.entity_id, + code, + }); +}; diff --git a/src/data/logbook.ts b/src/data/logbook.ts index f5caa718b7..75deda104e 100644 --- a/src/data/logbook.ts +++ b/src/data/logbook.ts @@ -12,6 +12,7 @@ import { LocalizeFunc } from "../common/translations/localize"; import { HaEntityPickerEntityFilterFunc } from "../components/entity/ha-entity-picker"; import { HomeAssistant } from "../types"; import { UNAVAILABLE, UNKNOWN } from "./entity"; +import { computeAttributeValueDisplay } from "../common/entity/compute_attribute_display"; const LOGBOOK_LOCALIZE_PATH = "ui.components.logbook.messages"; export const CONTINUOUS_DOMAINS = ["counter", "proximity", "sensor", "zone"]; @@ -71,71 +72,8 @@ export const getLogbookDataForContext = async ( hass: HomeAssistant, startDate: string, contextId?: string -): Promise => { - await hass.loadBackendTranslation("device_class"); - return getLogbookDataFromServer( - hass, - startDate, - undefined, - undefined, - contextId - ); -}; - -export const getLogbookData = async ( - hass: HomeAssistant, - startDate: string, - endDate: string, - entityIds?: string[], - deviceIds?: string[] -): Promise => { - await hass.loadBackendTranslation("device_class"); - return deviceIds?.length - ? getLogbookDataFromServer( - hass, - startDate, - endDate, - entityIds, - undefined, - deviceIds - ) - : getLogbookDataCache(hass, startDate, endDate, entityIds); -}; - -const getLogbookDataCache = async ( - hass: HomeAssistant, - startDate: string, - endDate: string, - entityId?: string[] -) => { - const ALL_ENTITIES = "*"; - - const entityIdKey = entityId ? entityId.toString() : ALL_ENTITIES; - const cacheKey = `${startDate}${endDate}`; - - if (!DATA_CACHE[cacheKey]) { - DATA_CACHE[cacheKey] = {}; - } - - if (entityIdKey in DATA_CACHE[cacheKey]) { - return DATA_CACHE[cacheKey][entityIdKey]!; - } - - if (entityId && DATA_CACHE[cacheKey][ALL_ENTITIES]) { - const entities = await DATA_CACHE[cacheKey][ALL_ENTITIES]!; - return entities.filter( - (entity) => entity.entity_id && entityId.includes(entity.entity_id) - ); - } - - DATA_CACHE[cacheKey][entityIdKey] = getLogbookDataFromServer( - hass, - startDate, - endDate, - entityId - ); - return DATA_CACHE[cacheKey][entityIdKey]!; -}; +): Promise => + getLogbookDataFromServer(hass, startDate, undefined, undefined, contextId); const getLogbookDataFromServer = ( hass: HomeAssistant, @@ -219,6 +157,7 @@ export const createHistoricState = ( attributes: { // Rebuild the historical state by copying static attributes only device_class: currentStateObj?.attributes.device_class, + event_type: currentStateObj?.attributes.event_type, source_type: currentStateObj?.attributes.source_type, has_date: currentStateObj?.attributes.has_date, has_time: currentStateObj?.attributes.has_time, @@ -406,6 +345,23 @@ export const localizeStateMessage = ( } break; + case "event": { + const event_type = + computeAttributeValueDisplay( + hass!.localize, + stateObj, + hass.locale, + hass.config, + hass.entities, + "event_type" + )?.toString() || + localize(`${LOGBOOK_LOCALIZE_PATH}.detected_unknown_event`); + + return localize(`${LOGBOOK_LOCALIZE_PATH}.detected_event`, { + event_type: autoCaseNoun(event_type, hass.language), + }); + } + case "lock": switch (state) { case "unlocked": diff --git a/src/data/media-player.ts b/src/data/media-player.ts index c666c0ec52..0e3ca09160 100644 --- a/src/data/media-player.ts +++ b/src/data/media-player.ts @@ -33,6 +33,7 @@ import type { HassEntityBase, } from "home-assistant-js-websocket"; import { supportsFeature } from "../common/entity/supports-feature"; +import { stateActive } from "../common/entity/state_active"; import { MediaPlayerItemId } from "../components/media-player/ha-media-player-browse"; import type { HomeAssistant, TranslationDict } from "../types"; import { isUnavailableState } from "./entity"; @@ -270,7 +271,7 @@ export const computeMediaControls = ( return undefined; } - if (state === "off") { + if (!stateActive(stateObj)) { return supportsFeature(stateObj, MediaPlayerEntityFeature.TURN_ON) ? [ { diff --git a/src/data/openstreetmap.ts b/src/data/openstreetmap.ts new file mode 100644 index 0000000000..3428d46f74 --- /dev/null +++ b/src/data/openstreetmap.ts @@ -0,0 +1,69 @@ +import { HomeAssistant } from "../types"; + +export interface OpenStreetMapPlace { + place_id: number; + licence: string; + osm_type: string; + osm_id: number; + lat: string; + lon: string; + place_rank: number; + category: string; + type: string; + importance: number; + addresstype: string; + name: string | null; + display_name: string; + address: { + house_number?: string; + road?: string; + neighbourhood?: string; + city?: string; + municipality?: string; + state?: string; + country?: string; + postcode?: string; + country_code: string; + [key: string]: string | undefined; + }; + boundingbox: number[]; +} + +export const searchPlaces = ( + address: string, + hass: HomeAssistant, + addressdetails?: boolean, + limit?: number +): Promise => + fetch( + `https://nominatim.openstreetmap.org/search.php?q=${address}&format=jsonv2${ + limit ? `&limit=${limit}` : "" + }${addressdetails ? "&addressdetails=1" : ""}&accept-language=${ + hass.locale.language + }&email=abuse@home-assistant.io`, + { headers: { "User-Agent": `HomeAssistant/${hass.config.version}` } } + ).then((res) => { + if (res.ok) { + return res.json(); + } + throw new Error(res.statusText); + }); + +export const reverseGeocode = ( + location: [number, number], + hass: HomeAssistant, + zoom?: number +): Promise => + fetch( + `https://nominatim.openstreetmap.org/reverse.php?lat=${location[0]}&lon=${ + location[1] + }&accept-language=${hass.locale.language}&zoom=${ + zoom ?? 18 + }&format=jsonv2&email=abuse@home-assistant.io`, + { headers: { "User-Agent": `HomeAssistant/${hass.config.version}` } } + ).then((res) => { + if (res.ok) { + return res.json(); + } + throw new Error(res.statusText); + }); diff --git a/src/data/otbr.ts b/src/data/otbr.ts index 93e77a1eda..154d2863ff 100644 --- a/src/data/otbr.ts +++ b/src/data/otbr.ts @@ -3,6 +3,7 @@ import { HomeAssistant } from "../types"; export interface OTBRInfo { url: string; active_dataset_tlvs: string; + channel: number; } export const getOTBRInfo = (hass: HomeAssistant): Promise => @@ -30,3 +31,12 @@ export const OTBRGetExtendedAddress = ( hass.callWS({ type: "otbr/get_extended_address", }); + +export const OTBRSetChannel = ( + hass: HomeAssistant, + channel: number +): Promise<{ delay: number }> => + hass.callWS({ + type: "otbr/set_channel", + channel, + }); diff --git a/src/data/scene.ts b/src/data/scene.ts index e8f27d6c26..b9b6fa4d2c 100644 --- a/src/data/scene.ts +++ b/src/data/scene.ts @@ -10,6 +10,7 @@ export const SCENE_IGNORED_DOMAINS = [ "button", "configuration", "device_tracker", + "event", "image_processing", "input_button", "persistent_notification", diff --git a/src/data/script_i18n.ts b/src/data/script_i18n.ts index 3cd8a36818..09e25862b3 100644 --- a/src/data/script_i18n.ts +++ b/src/data/script_i18n.ts @@ -1,17 +1,18 @@ +import { ensureArray } from "../common/array/ensure-array"; import { formatDuration } from "../common/datetime/format_duration"; import secondsToDuration from "../common/datetime/seconds_to_duration"; -import { ensureArray } from "../common/array/ensure-array"; import { computeStateName } from "../common/entity/compute_state_name"; +import { formatListWithAnds } from "../common/string/format-list"; import { isTemplate } from "../common/string/has-template"; import { HomeAssistant } from "../types"; import { Condition } from "./automation"; -import { describeCondition, describeTrigger } from "./automation_i18n"; +import { describeCondition } from "./automation_i18n"; import { localizeDeviceAutomationAction } from "./device_automation"; import { computeDeviceName } from "./device_registry"; import { + EntityRegistryEntry, computeEntityRegistryName, entityRegistryById, - EntityRegistryEntry, } from "./entity_registry"; import { domainToName } from "./integration"; import { @@ -21,7 +22,6 @@ import { DelayAction, DeviceAction, EventAction, - getActionType, IfAction, ParallelAction, PlayMediaAction, @@ -30,8 +30,8 @@ import { StopAction, VariablesAction, WaitForTriggerAction, + getActionType, } from "./script"; -import { formatListWithAnds } from "../common/string/format-list"; const actionTranslationBaseKey = "ui.panel.config.automation.editor.actions.type"; @@ -165,12 +165,14 @@ const tryDescribeAction = ( if (config.service) { const [domain, serviceName] = config.service.split(".", 2); - const service = hass.services[domain][serviceName]; + const service = + hass.localize(`component.${domain}.services.${serviceName}.name`) || + hass.services[domain][serviceName]?.name; return hass.localize( `${actionTranslationBaseKey}.service.description.service_based_on_name`, { name: service - ? `${domainToName(hass.localize, domain)}: ${service.name}` + ? `${domainToName(hass.localize, domain)}: ${service}` : config.service, targets: formatListWithAnds(hass.locale, targets), } @@ -273,12 +275,9 @@ const tryDescribeAction = ( `${actionTranslationBaseKey}.wait_for_trigger.description.wait_for_a_trigger` ); } - const triggerNames = triggers.map((trigger) => - describeTrigger(trigger, hass, entityRegistry) - ); return hass.localize( - `${actionTranslationBaseKey}.wait_for_trigger.description.wait_for_triggers_with_name`, - { triggers: formatListWithAnds(hass.locale, triggerNames) } + `${actionTranslationBaseKey}.wait_for_trigger.description.wait_for_triggers`, + { count: triggers.length } ); } @@ -326,52 +325,13 @@ const tryDescribeAction = ( if (actionType === "if") { const config = action as IfAction; - let ifConditions: string[] = []; - if (Array.isArray(config.if)) { - const conditions = ensureArray(config.if); - conditions.forEach((condition) => { - ifConditions.push(describeCondition(condition, hass, entityRegistry)); - }); - } else { - ifConditions = [config.if]; + if (config.else !== undefined) { + return hass.localize( + `${actionTranslationBaseKey}.if.description.if_else` + ); } - let elseActions: string[] = []; - if (config.else) { - if (Array.isArray(config.else)) { - const actions = ensureArray(config.else); - actions.forEach((currentAction) => { - elseActions.push( - describeAction(hass, entityRegistry, currentAction, undefined) - ); - }); - } else { - elseActions = [ - describeAction(hass, entityRegistry, config.else, undefined), - ]; - } - } - - let thenActions: string[] = []; - if (Array.isArray(config.then)) { - const actions = ensureArray(config.then); - actions.forEach((currentAction) => { - thenActions.push( - describeAction(hass, entityRegistry, currentAction, undefined) - ); - }); - } else { - thenActions = [ - describeAction(hass, entityRegistry, config.then, undefined), - ]; - } - - return hass.localize(`${actionTranslationBaseKey}.if.description.full`, { - hasElse: config.else !== undefined, - action: formatListWithAnds(hass.locale, thenActions), - conditions: formatListWithAnds(hass.locale, ifConditions), - elseAction: formatListWithAnds(hass.locale, elseActions), - }); + return hass.localize(`${actionTranslationBaseKey}.if.description.if`); } if (actionType === "choose") { @@ -400,20 +360,16 @@ const tryDescribeAction = ( { count: count } ); } else if ("while" in config.repeat) { - const conditions = ensureArray(config.repeat.while).map((condition) => - describeCondition(condition, hass, entityRegistry) - ); + const conditions = ensureArray(config.repeat.while); chosenAction = hass.localize( - `${actionTranslationBaseKey}.repeat.description.while`, - { conditions: formatListWithAnds(hass.locale, conditions) } + `${actionTranslationBaseKey}.repeat.description.while_count`, + { count: conditions.length } ); } else if ("until" in config.repeat) { - const conditions = ensureArray(config.repeat.until).map((condition) => - describeCondition(condition, hass, entityRegistry) - ); + const conditions = ensureArray(config.repeat.until); chosenAction = hass.localize( - `${actionTranslationBaseKey}.repeat.description.until`, - { conditions: formatListWithAnds(hass.locale, conditions) } + `${actionTranslationBaseKey}.repeat.description.until_count`, + { count: conditions.length } ); } else if ("for_each" in config.repeat) { const items = ensureArray(config.repeat.for_each).map((item) => diff --git a/src/data/selector.ts b/src/data/selector.ts index acbac41a43..5708470a45 100644 --- a/src/data/selector.ts +++ b/src/data/selector.ts @@ -19,6 +19,7 @@ export type Selector = | BooleanSelector | ColorRGBSelector | ColorTempSelector + | ConditionSelector | ConversationAgentSelector | ConfigEntrySelector | ConstantSelector @@ -96,6 +97,11 @@ export interface ColorTempSelector { } | null; } +export interface ConditionSelector { + // eslint-disable-next-line @typescript-eslint/ban-types + condition: {} | null; +} + export interface ConversationAgentSelector { conversation_agent: { language?: string } | null; } @@ -139,21 +145,20 @@ export interface DeviceSelector { } export interface LegacyDeviceSelector { - device: - | DeviceSelector["device"] & { - /** - * @deprecated Use filter instead - */ - integration?: DeviceSelectorFilter["integration"]; - /** - * @deprecated Use filter instead - */ - manufacturer?: DeviceSelectorFilter["manufacturer"]; - /** - * @deprecated Use filter instead - */ - model?: DeviceSelectorFilter["model"]; - }; + device: DeviceSelector["device"] & { + /** + * @deprecated Use filter instead + */ + integration?: DeviceSelectorFilter["integration"]; + /** + * @deprecated Use filter instead + */ + manufacturer?: DeviceSelectorFilter["manufacturer"]; + /** + * @deprecated Use filter instead + */ + model?: DeviceSelectorFilter["model"]; + }; } export interface DurationSelector { @@ -179,21 +184,20 @@ export interface EntitySelector { } export interface LegacyEntitySelector { - entity: - | EntitySelector["entity"] & { - /** - * @deprecated Use filter instead - */ - integration?: EntitySelectorFilter["integration"]; - /** - * @deprecated Use filter instead - */ - domain?: EntitySelectorFilter["domain"]; - /** - * @deprecated Use filter instead - */ - device_class?: EntitySelectorFilter["device_class"]; - }; + entity: EntitySelector["entity"] & { + /** + * @deprecated Use filter instead + */ + integration?: EntitySelectorFilter["integration"]; + /** + * @deprecated Use filter instead + */ + domain?: EntitySelectorFilter["domain"]; + /** + * @deprecated Use filter instead + */ + device_class?: EntitySelectorFilter["device_class"]; + }; } export interface StatisticSelector { @@ -274,7 +278,9 @@ export interface ObjectSelector { export interface AssistPipelineSelector { // eslint-disable-next-line @typescript-eslint/ban-types - assist_pipeline: {} | null; + assist_pipeline: { + include_last_used?: boolean; + } | null; } export interface SelectOption { @@ -323,6 +329,7 @@ export interface StringSelector { | "time" | "datetime-local" | "color"; + prefix?: string; suffix?: string; autocomplete?: string; } | null; diff --git a/src/data/translation.ts b/src/data/translation.ts index b64e557b6b..bc8165578a 100644 --- a/src/data/translation.ts +++ b/src/data/translation.ts @@ -67,10 +67,10 @@ export type TranslationCategory = | "device_automation" | "mfa_setup" | "system_health" - | "device_class" | "application_credentials" | "issues" - | "selector"; + | "selector" + | "services"; export const fetchTranslationPreferences = (hass: HomeAssistant) => fetchFrontendUserData(hass.connection, "language"); diff --git a/src/data/weather.ts b/src/data/weather.ts index 619240354d..d18c41ccab 100644 --- a/src/data/weather.ts +++ b/src/data/weather.ts @@ -24,10 +24,19 @@ import { } from "home-assistant-js-websocket"; import { css, html, svg, SVGTemplateResult, TemplateResult } from "lit"; import { styleMap } from "lit/directives/style-map"; +import { supportsFeature } from "../common/entity/supports-feature"; import { formatNumber } from "../common/number/format_number"; import "../components/ha-svg-icon"; import type { HomeAssistant } from "../types"; +export const enum WeatherEntityFeature { + FORECAST_DAILY = 1, + FORECAST_HOURLY = 2, + FORECAST_TWICE_DAILY = 4, +} + +export type ForecastType = "legacy" | "hourly" | "daily" | "twice_daily"; + interface ForecastAttribute { temperature: number; datetime: string; @@ -36,7 +45,7 @@ interface ForecastAttribute { precipitation_probability?: number; humidity?: number; condition?: string; - daytime?: boolean; + is_daytime?: boolean; pressure?: number; wind_speed?: string; } @@ -45,6 +54,7 @@ interface WeatherEntityAttributes extends HassEntityAttributeBase { attribution?: string; humidity?: number; forecast?: ForecastAttribute[]; + is_daytime?: boolean; pressure?: number; temperature?: number; visibility?: number; @@ -57,6 +67,11 @@ interface WeatherEntityAttributes extends HassEntityAttributeBase { wind_speed_unit: string; } +export interface ForecastEvent { + type: "hourly" | "daily" | "twice_daily"; + forecast: [ForecastAttribute] | null; +} + export interface WeatherEntity extends HassEntityBase { attributes: WeatherEntityAttributes; } @@ -225,9 +240,10 @@ export const getWeatherUnit = ( export const getSecondaryWeatherAttribute = ( hass: HomeAssistant, - stateObj: WeatherEntity + stateObj: WeatherEntity, + forecast: ForecastAttribute[] ): TemplateResult | undefined => { - const extrema = getWeatherExtrema(hass, stateObj); + const extrema = getWeatherExtrema(hass, stateObj, forecast); if (extrema) { return extrema; @@ -237,11 +253,11 @@ export const getSecondaryWeatherAttribute = ( let attribute: string; if ( - stateObj.attributes.forecast?.length && - stateObj.attributes.forecast[0].precipitation !== undefined && - stateObj.attributes.forecast[0].precipitation !== null + forecast?.length && + forecast[0].precipitation !== undefined && + forecast[0].precipitation !== null ) { - value = stateObj.attributes.forecast[0].precipitation!; + value = forecast[0].precipitation!; attribute = "precipitation"; } else if ("humidity" in stateObj.attributes) { value = stateObj.attributes.humidity!; @@ -265,9 +281,10 @@ export const getSecondaryWeatherAttribute = ( const getWeatherExtrema = ( hass: HomeAssistant, - stateObj: WeatherEntity + stateObj: WeatherEntity, + forecast: ForecastAttribute[] ): TemplateResult | undefined => { - if (!stateObj.attributes.forecast?.length) { + if (!forecast?.length) { return undefined; } @@ -275,18 +292,18 @@ const getWeatherExtrema = ( let tempHigh: number | undefined; const today = new Date().getDate(); - for (const forecast of stateObj.attributes.forecast!) { - if (new Date(forecast.datetime).getDate() !== today) { + for (const fc of forecast!) { + if (new Date(fc.datetime).getDate() !== today) { break; } - if (!tempHigh || forecast.temperature > tempHigh) { - tempHigh = forecast.temperature; + if (!tempHigh || fc.temperature > tempHigh) { + tempHigh = fc.temperature; } - if (!tempLow || (forecast.templow && forecast.templow < tempLow)) { - tempLow = forecast.templow; + if (!tempLow || (fc.templow && fc.templow < tempLow)) { + tempLow = fc.templow; } - if (!forecast.templow && (!tempLow || forecast.temperature < tempLow)) { - tempLow = forecast.temperature; + if (!fc.templow && (!tempLow || fc.temperature < tempLow)) { + tempLow = fc.temperature; } } @@ -510,7 +527,7 @@ export const weatherIcon = (state?: string, nightTime?: boolean): string => const DAY_IN_MILLISECONDS = 86400000; -export const isForecastHourly = ( +const isForecastHourly = ( forecast?: ForecastAttribute[] ): boolean | undefined => { if (forecast && forecast?.length && forecast?.length > 2) { @@ -538,3 +555,93 @@ export const getWeatherConvertibleUnits = ( hass.callWS({ type: "weather/convertible_units", }); + +const getLegacyForecast = ( + weather_attributes?: WeatherEntityAttributes | undefined +): + | { + forecast: ForecastAttribute[]; + type: "daily" | "hourly" | "twice_daily"; + } + | undefined => { + if (weather_attributes?.forecast && weather_attributes.forecast.length > 2) { + const hourly = isForecastHourly(weather_attributes.forecast); + if (hourly === true) { + const dateFirst = new Date(weather_attributes.forecast![0].datetime); + const datelast = new Date( + weather_attributes.forecast![ + weather_attributes.forecast!.length - 1 + ].datetime + ); + const dayDiff = datelast.getTime() - dateFirst.getTime(); + const dayNight = dayDiff > DAY_IN_MILLISECONDS; + return { + forecast: weather_attributes.forecast, + type: dayNight ? "twice_daily" : "hourly", + }; + } + return { forecast: weather_attributes.forecast, type: "daily" }; + } + return undefined; +}; + +export const getForecast = ( + weather_attributes?: WeatherEntityAttributes | undefined, + forecast_event?: ForecastEvent, + forecast_type?: ForecastType | undefined +): + | { + forecast: ForecastAttribute[]; + type: "daily" | "hourly" | "twice_daily"; + } + | undefined => { + if (forecast_type === undefined) { + if ( + forecast_event?.type !== undefined && + forecast_event?.forecast && + forecast_event?.forecast?.length > 2 + ) { + return { forecast: forecast_event.forecast, type: forecast_event?.type }; + } + return getLegacyForecast(weather_attributes); + } + + if (forecast_type === "legacy") { + return getLegacyForecast(weather_attributes); + } + + if ( + forecast_type === forecast_event?.type && + forecast_event?.forecast && + forecast_event?.forecast?.length > 2 + ) { + return { forecast: forecast_event.forecast, type: forecast_type }; + } + + return undefined; +}; + +export const subscribeForecast = ( + hass: HomeAssistant, + entity_id: string, + forecast_type: "daily" | "hourly" | "twice_daily", + callback: (forecastevent: ForecastEvent) => void +) => + hass.connection.subscribeMessage(callback, { + type: "weather/subscribe_forecast", + forecast_type, + entity_id, + }); + +export const getDefaultForecastType = (stateObj: HassEntityBase) => { + if (supportsFeature(stateObj, WeatherEntityFeature.FORECAST_DAILY)) { + return "daily"; + } + if (supportsFeature(stateObj, WeatherEntityFeature.FORECAST_HOURLY)) { + return "hourly"; + } + if (supportsFeature(stateObj, WeatherEntityFeature.FORECAST_TWICE_DAILY)) { + return "twice_daily"; + } + return undefined; +}; diff --git a/src/dialogs/config-flow/show-dialog-config-flow.ts b/src/dialogs/config-flow/show-dialog-config-flow.ts index a575cde11f..f7b3fc7e37 100644 --- a/src/dialogs/config-flow/show-dialog-config-flow.ts +++ b/src/dialogs/config-flow/show-dialog-config-flow.ts @@ -23,6 +23,7 @@ export const showConfigFlowDialog = ( createFlow: async (hass, handler) => { const [step] = await Promise.all([ createConfigFlow(hass, handler), + hass.loadFragmentTranslation("config"), hass.loadBackendTranslation("config", handler), hass.loadBackendTranslation("selector", handler), // Used as fallback if no header defined for step @@ -32,6 +33,7 @@ export const showConfigFlowDialog = ( }, fetchFlow: async (hass, flowId) => { const step = await fetchConfigFlow(hass, flowId); + await hass.loadFragmentTranslation("config"); await hass.loadBackendTranslation("config", step.handler); await hass.loadBackendTranslation("selector", step.handler); return step; diff --git a/src/dialogs/config-flow/show-dialog-options-flow.ts b/src/dialogs/config-flow/show-dialog-options-flow.ts index 81a7947599..d95a38c29a 100644 --- a/src/dialogs/config-flow/show-dialog-options-flow.ts +++ b/src/dialogs/config-flow/show-dialog-options-flow.ts @@ -31,6 +31,7 @@ export const showOptionsFlowDialog = ( createFlow: async (hass, handler) => { const [step] = await Promise.all([ createOptionsFlow(hass, handler), + hass.loadFragmentTranslation("config"), hass.loadBackendTranslation("options", configEntry.domain), hass.loadBackendTranslation("selector", configEntry.domain), ]); @@ -39,6 +40,7 @@ export const showOptionsFlowDialog = ( fetchFlow: async (hass, flowId) => { const [step] = await Promise.all([ fetchOptionsFlow(hass, flowId), + hass.loadFragmentTranslation("config"), hass.loadBackendTranslation("options", configEntry.domain), hass.loadBackendTranslation("selector", configEntry.domain), ]); diff --git a/src/dialogs/config-flow/step-flow-create-entry.ts b/src/dialogs/config-flow/step-flow-create-entry.ts index a43477d8c0..1ceb034b7a 100644 --- a/src/dialogs/config-flow/step-flow-create-entry.ts +++ b/src/dialogs/config-flow/step-flow-create-entry.ts @@ -48,26 +48,25 @@ class StepFlowCreateEntry extends LitElement {

${this.devices.map( - (device) => - html` -
-
- ${computeDeviceName(device, this.hass)}
- ${!device.model && !device.manufacturer - ? html` ` - : html`${device.model} - ${device.manufacturer - ? html`(${device.manufacturer})` - : ""}`} -
- + (device) => html` +
+
+ ${computeDeviceName(device, this.hass)}
+ ${!device.model && !device.manufacturer + ? html` ` + : html`${device.model} + ${device.manufacturer + ? html`(${device.manufacturer})` + : ""}`}
- ` + +
+ ` )}
`} diff --git a/src/dialogs/more-info/components/lights/dialog-light-color-favorite.ts b/src/dialogs/more-info/components/lights/dialog-light-color-favorite.ts index 410ba70c04..8549c90682 100644 --- a/src/dialogs/more-info/components/lights/dialog-light-color-favorite.ts +++ b/src/dialogs/more-info/components/lights/dialog-light-color-favorite.ts @@ -150,22 +150,21 @@ class DialogLightColorFavorite extends LitElement { ? html`
${this._modes.map( - (value) => - html` - - - - ` + (value) => html` + + + + ` )}
` diff --git a/src/dialogs/more-info/components/lights/light-color-rgb-picker.ts b/src/dialogs/more-info/components/lights/light-color-rgb-picker.ts index cf50ae5c04..90b18f4223 100644 --- a/src/dialogs/more-info/components/lights/light-color-rgb-picker.ts +++ b/src/dialogs/more-info/components/lights/light-color-rgb-picker.ts @@ -415,7 +415,7 @@ class LightRgbColorPicker extends LitElement { number, number, number, - number + number, ]; this._applyColor({ rgbww_color }); } else if (lightSupportsColorMode(this.stateObj!, LightColorMode.RGBW)) { @@ -427,7 +427,7 @@ class LightRgbColorPicker extends LitElement { number, number, number, - number + number, ]; this._applyColor({ rgbw_color }); } diff --git a/src/dialogs/more-info/components/lock/ha-more-info-lock-toggle.ts b/src/dialogs/more-info/components/lock/ha-more-info-lock-toggle.ts index aafecef40d..0f5691e408 100644 --- a/src/dialogs/more-info/components/lock/ha-more-info-lock-toggle.ts +++ b/src/dialogs/more-info/components/lock/ha-more-info-lock-toggle.ts @@ -15,9 +15,8 @@ import "../../../../components/ha-control-button"; import "../../../../components/ha-control-switch"; import { UNAVAILABLE, UNKNOWN } from "../../../../data/entity"; import { forwardHaptic } from "../../../../data/haptics"; -import { LockEntity } from "../../../../data/lock"; +import { callProtectedLockService, LockEntity } from "../../../../data/lock"; import { HomeAssistant } from "../../../../types"; -import { showEnterCodeDialogDialog } from "../../../enter-code/show-enter-code-dialog"; @customElement("ha-more-info-lock-toggle") export class HaMoreInfoLockToggle extends LitElement { @@ -68,30 +67,12 @@ export class HaMoreInfoLockToggle extends LitElement { return; } forwardHaptic("light"); - - let code: string | undefined; - - if (this.stateObj.attributes.code_format) { - const response = await showEnterCodeDialogDialog(this, { - codeFormat: "text", - codePattern: this.stateObj.attributes.code_format, - title: this.hass.localize( - `ui.dialogs.more_info_control.lock.${turnOn ? "lock" : "unlock"}` - ), - submitText: this.hass.localize( - `ui.dialogs.more_info_control.lock.${turnOn ? "lock" : "unlock"}` - ), - }); - if (response == null) { - throw new Error("cancel"); - } - code = response; - } - - await this.hass.callService("lock", turnOn ? "lock" : "unlock", { - entity_id: this.stateObj.entity_id, - code, - }); + callProtectedLockService( + this, + this.hass, + this.stateObj, + turnOn ? "lock" : "unlock" + ); } protected render(): TemplateResult { diff --git a/src/dialogs/more-info/const.ts b/src/dialogs/more-info/const.ts index d6d6d615aa..a0dc211937 100644 --- a/src/dialogs/more-info/const.ts +++ b/src/dialogs/more-info/const.ts @@ -72,6 +72,7 @@ export const DOMAINS_HIDE_DEFAULT_MORE_INFO = [ "select", "text", "update", + "event", ]; /** Domains that should have the history hidden in the more info dialog. */ diff --git a/src/dialogs/more-info/controls/more-info-configurator.ts b/src/dialogs/more-info/controls/more-info-configurator.ts index 0e68a22c7e..76c2fb9f5b 100644 --- a/src/dialogs/more-info/controls/more-info-configurator.ts +++ b/src/dialogs/more-info/controls/more-info-configurator.ts @@ -36,12 +36,13 @@ export class MoreInfoConfigurator extends LitElement { ` : ""} ${this.stateObj.attributes.fields.map( - (field) => html`` + (field) => + html`` )} ${this.stateObj.attributes.submit_caption ? html`

diff --git a/src/dialogs/more-info/controls/more-info-fan.ts b/src/dialogs/more-info/controls/more-info-fan.ts index 588397c5ce..ae841e996c 100644 --- a/src/dialogs/more-info/controls/more-info-fan.ts +++ b/src/dialogs/more-info/controls/more-info-fan.ts @@ -299,23 +299,22 @@ class MoreInfoFan extends LitElement { > ${this.stateObj.attributes.preset_modes?.map( - (mode) => - html` - - ${computeAttributeValueDisplay( - this.hass.localize, - this.stateObj!, - this.hass.locale, - this.hass.config, - this.hass.entities, - "preset_mode", - mode - )} - - ` + (mode) => html` + + ${computeAttributeValueDisplay( + this.hass.localize, + this.stateObj!, + this.hass.locale, + this.hass.config, + this.hass.entities, + "preset_mode", + mode + )} + + ` )} ` diff --git a/src/dialogs/more-info/controls/more-info-lock.ts b/src/dialogs/more-info/controls/more-info-lock.ts index 5fa6ec5df3..e17753050c 100644 --- a/src/dialogs/more-info/controls/more-info-lock.ts +++ b/src/dialogs/more-info/controls/more-info-lock.ts @@ -1,16 +1,19 @@ -import "@material/web/iconbutton/outlined-icon-button"; import { mdiDoorOpen, mdiLock, mdiLockOff } from "@mdi/js"; -import { css, CSSResultGroup, html, LitElement, nothing } from "lit"; +import { CSSResultGroup, LitElement, css, html, nothing } from "lit"; import { customElement, property } from "lit/decorators"; import { styleMap } from "lit/directives/style-map"; import { domainIcon } from "../../../common/entity/domain_icon"; import { stateColorCss } from "../../../common/entity/state_color"; import { supportsFeature } from "../../../common/entity/supports-feature"; import "../../../components/ha-attributes"; +import "../../../components/ha-outlined-icon-button"; import { UNAVAILABLE } from "../../../data/entity"; -import { LockEntity, LockEntityFeature } from "../../../data/lock"; +import { + LockEntity, + LockEntityFeature, + callProtectedLockService, +} from "../../../data/lock"; import type { HomeAssistant } from "../../../types"; -import { showEnterCodeDialogDialog } from "../../enter-code/show-enter-code-dialog"; import { moreInfoControlStyle } from "../components/ha-more-info-control-style"; import "../components/ha-more-info-state-header"; import "../components/lock/ha-more-info-lock-toggle"; @@ -22,41 +25,15 @@ class MoreInfoLock extends LitElement { @property({ attribute: false }) public stateObj?: LockEntity; private async _open() { - this._callService("open"); + callProtectedLockService(this, this.hass, this.stateObj!, "open"); } private async _lock() { - this._callService("lock"); + callProtectedLockService(this, this.hass, this.stateObj!, "lock"); } private async _unlock() { - this._callService("unlock"); - } - - private async _callService(service: "open" | "lock" | "unlock") { - let code: string | undefined; - - if (this.stateObj!.attributes.code_format) { - const response = await showEnterCodeDialogDialog(this, { - codeFormat: "text", - codePattern: this.stateObj!.attributes.code_format, - title: this.hass.localize( - `ui.dialogs.more_info_control.lock.${service}` - ), - submitText: this.hass.localize( - `ui.dialogs.more_info_control.lock.${service}` - ), - }); - if (!response) { - return; - } - code = response; - } - - this.hass.callService("lock", service, { - entity_id: this.stateObj!.entity_id, - code, - }); + callProtectedLockService(this, this.hass, this.stateObj!, "unlock"); } protected render() { @@ -105,7 +82,7 @@ class MoreInfoLock extends LitElement {

${supportsOpen ? html` - - + ` : nothing} ${isJammed ? html` - - - + - + ` : nothing}
@@ -163,13 +140,6 @@ class MoreInfoLock extends LitElement { return [ moreInfoControlStyle, css` - md-outlined-icon-button { - --ha-icon-display: block; - --md-sys-color-on-surface: var(--secondary-text-color); - --md-sys-color-on-surface-variant: var(--secondary-text-color); - --md-sys-color-on-surface-rgb: var(--rgb-secondary-text-color); - --md-sys-color-outline: var(--secondary-text-color); - } @keyframes pulse { 0% { opacity: 1; diff --git a/src/dialogs/more-info/controls/more-info-media_player.ts b/src/dialogs/more-info/controls/more-info-media_player.ts index b02fc75e9d..1d9fcbe0fc 100644 --- a/src/dialogs/more-info/controls/more-info-media_player.ts +++ b/src/dialogs/more-info/controls/more-info-media_player.ts @@ -15,12 +15,12 @@ import { stopPropagation } from "../../../common/dom/stop_propagation"; import { computeAttributeValueDisplay } from "../../../common/entity/compute_attribute_display"; import { supportsFeature } from "../../../common/entity/supports-feature"; import { computeRTLDirection } from "../../../common/util/compute_rtl"; +import { stateActive } from "../../../common/entity/state_active"; import "../../../components/ha-icon-button"; import "../../../components/ha-select"; import "../../../components/ha-slider"; import "../../../components/ha-svg-icon"; import { showMediaBrowserDialog } from "../../../components/media-player/show-media-browser-dialog"; -import { UNAVAILABLE, UNKNOWN } from "../../../data/entity"; import { computeMediaControls, handleMediaControlClick, @@ -83,7 +83,7 @@ class MoreInfoMediaPlayer extends LitElement {
${(supportsFeature(stateObj, MediaPlayerEntityFeature.VOLUME_SET) || supportsFeature(stateObj, MediaPlayerEntityFeature.VOLUME_BUTTONS)) && - ![UNAVAILABLE, UNKNOWN, "off"].includes(stateObj.state) + stateActive(stateObj) ? html`
${supportsFeature(stateObj, MediaPlayerEntityFeature.VOLUME_MUTE) @@ -141,7 +141,7 @@ class MoreInfoMediaPlayer extends LitElement {
` : ""} - ${![UNAVAILABLE, UNKNOWN, "off"].includes(stateObj.state) && + ${stateActive(stateObj) && supportsFeature(stateObj, MediaPlayerEntityFeature.SELECT_SOURCE) && stateObj.attributes.source_list?.length ? html` @@ -156,27 +156,26 @@ class MoreInfoMediaPlayer extends LitElement { @closed=${stopPropagation} > ${stateObj.attributes.source_list!.map( - (source) => - html` - ${computeAttributeValueDisplay( - this.hass.localize, - stateObj, - this.hass.locale, - this.hass.config, - this.hass.entities, - "source", - source - )} - ` + (source) => html` + ${computeAttributeValueDisplay( + this.hass.localize, + stateObj, + this.hass.locale, + this.hass.config, + this.hass.entities, + "source", + source + )} + ` )}
` : ""} - ${![UNAVAILABLE, UNKNOWN, "off"].includes(stateObj.state) && + ${stateActive(stateObj) && supportsFeature(stateObj, MediaPlayerEntityFeature.SELECT_SOUND_MODE) && stateObj.attributes.sound_mode_list?.length ? html` diff --git a/src/dialogs/more-info/controls/more-info-vacuum.ts b/src/dialogs/more-info/controls/more-info-vacuum.ts index c470b33cba..6487749d23 100644 --- a/src/dialogs/more-info/controls/more-info-vacuum.ts +++ b/src/dialogs/more-info/controls/more-info-vacuum.ts @@ -9,17 +9,26 @@ import { mdiStop, mdiTargetVariant, } from "@mdi/js"; -import { css, CSSResultGroup, html, LitElement, nothing } from "lit"; +import { CSSResultGroup, LitElement, css, html, nothing } from "lit"; import { customElement, property } from "lit/decorators"; +import memoizeOne from "memoize-one"; import { stopPropagation } from "../../../common/dom/stop_propagation"; import { computeAttributeValueDisplay } from "../../../common/entity/compute_attribute_display"; import { computeStateDisplay } from "../../../common/entity/compute_state_display"; +import { computeStateDomain } from "../../../common/entity/compute_state_domain"; import { supportsFeature } from "../../../common/entity/supports-feature"; +import { blankBeforePercent } from "../../../common/translations/blank_before_percent"; +import "../../../components/entity/ha-battery-icon"; import "../../../components/ha-attributes"; import "../../../components/ha-icon"; import "../../../components/ha-icon-button"; import "../../../components/ha-select"; import { UNAVAILABLE } from "../../../data/entity"; +import { + EntityRegistryDisplayEntry, + findBatteryChargingEntity, + findBatteryEntity, +} from "../../../data/entity_registry"; import { VacuumEntity, VacuumEntityFeature } from "../../../data/vacuum"; import { HomeAssistant } from "../../../types"; @@ -43,9 +52,11 @@ const VACUUM_COMMANDS: VacuumCommand[] = [ icon: mdiPause, serviceName: "pause", isVisible: (stateObj) => - // We need also to check if Start is supported because if not we show play-pause - supportsFeature(stateObj, VacuumEntityFeature.START) && - supportsFeature(stateObj, VacuumEntityFeature.PAUSE), + // We need also to check if Start is supported because if not we show start-pause + // Start-pause service is only available for old vacuum entities, new entities have the `STATE` feature + supportsFeature(stateObj, VacuumEntityFeature.PAUSE) && + (supportsFeature(stateObj, VacuumEntityFeature.STATE) || + supportsFeature(stateObj, VacuumEntityFeature.START)), }, { translationKey: "start_pause", @@ -53,6 +64,8 @@ const VACUUM_COMMANDS: VacuumCommand[] = [ serviceName: "start_pause", isVisible: (stateObj) => // If start is supported, we don't show this button + // This service is only available for old vacuum entities, new entities have the `STATE` feature + !supportsFeature(stateObj, VacuumEntityFeature.STATE) && !supportsFeature(stateObj, VacuumEntityFeature.START) && supportsFeature(stateObj, VacuumEntityFeature.PAUSE), }, @@ -133,19 +146,7 @@ class MoreInfoVacuum extends LitElement {
- ${supportsFeature(stateObj, VacuumEntityFeature.BATTERY) && - stateObj.attributes.battery_level - ? html` -
- - ${stateObj.attributes.battery_level} % - - -
- ` - : ""} + ${this._renderBattery()} ` : ""} ${VACUUM_COMMANDS.some((item) => item.isVisible(stateObj)) @@ -239,6 +240,81 @@ class MoreInfoVacuum extends LitElement { `; } + private _deviceEntities = memoizeOne( + ( + deviceId: string, + entities: HomeAssistant["entities"] + ): EntityRegistryDisplayEntry[] => { + const entries = Object.values(entities); + return entries.filter((entity) => entity.device_id === deviceId); + } + ); + + private _renderBattery() { + const stateObj = this.stateObj!; + + const deviceId = this.hass.entities[stateObj.entity_id]?.device_id; + + const entities = deviceId + ? this._deviceEntities(deviceId, this.hass.entities) + : []; + + const batteryEntity = findBatteryEntity(this.hass, entities); + const battery = batteryEntity + ? this.hass.states[batteryEntity.entity_id] + : undefined; + + const batteryIsBinary = + battery && computeStateDomain(battery) === "binary_sensor"; + + // Use device battery entity + if (battery && (batteryIsBinary || !isNaN(battery.state as any))) { + const batteryChargingEntity = findBatteryChargingEntity( + this.hass, + entities + ); + const batteryCharging = batteryChargingEntity + ? this.hass.states[batteryChargingEntity?.entity_id] + : undefined; + + return html` +
+ + ${batteryIsBinary + ? "" + : `${Number(battery.state).toFixed()}${blankBeforePercent( + this.hass.locale + )}%`} + + +
+ `; + } + + // Use battery_level and battery_icon deprecated attributes + if ( + supportsFeature(stateObj, VacuumEntityFeature.BATTERY) && + stateObj.attributes.battery_level + ) { + return html` +
+ + ${stateObj.attributes.battery_level.toFixed()}${blankBeforePercent( + this.hass.locale + )}% + + +
+ `; + } + + return nothing; + } + private callService(ev: CustomEvent) { const entry = (ev.target! as any).entry as VacuumCommand; this.hass.callService("vacuum", entry.serviceName, { diff --git a/src/dialogs/more-info/controls/more-info-weather.ts b/src/dialogs/more-info/controls/more-info-weather.ts index 628886339d..f76e2517f1 100644 --- a/src/dialogs/more-info/controls/more-info-weather.ts +++ b/src/dialogs/more-info/controls/more-info-weather.ts @@ -13,15 +13,18 @@ import { PropertyValues, nothing, } from "lit"; -import { customElement, property } from "lit/decorators"; +import { customElement, property, state } from "lit/decorators"; import { formatDateWeekdayDay } from "../../../common/datetime/format_date"; import { formatTimeWeekday } from "../../../common/datetime/format_time"; import { formatNumber } from "../../../common/number/format_number"; import "../../../components/ha-svg-icon"; import { + getDefaultForecastType, + getForecast, getWeatherUnit, getWind, - isForecastHourly, + subscribeForecast, + ForecastEvent, WeatherEntity, weatherIcons, } from "../../../data/weather"; @@ -33,6 +36,48 @@ class MoreInfoWeather extends LitElement { @property() public stateObj?: WeatherEntity; + @state() private _forecastEvent?: ForecastEvent; + + @state() private _subscribed?: Promise<() => void>; + + private _unsubscribeForecastEvents() { + if (this._subscribed) { + this._subscribed.then((unsub) => unsub()); + this._subscribed = undefined; + } + } + + private async _subscribeForecastEvents() { + this._unsubscribeForecastEvents(); + if (!this.isConnected || !this.hass || !this.stateObj) { + return; + } + + const forecastType = getDefaultForecastType(this.stateObj); + if (forecastType) { + this._subscribed = subscribeForecast( + this.hass!, + this.stateObj!.entity_id, + forecastType, + (event) => { + this._forecastEvent = event; + } + ); + } + } + + public connectedCallback() { + super.connectedCallback(); + if (this.hasUpdated) { + this._subscribeForecastEvents(); + } + } + + public disconnectedCallback(): void { + super.disconnectedCallback(); + this._unsubscribeForecastEvents(); + } + protected shouldUpdate(changedProps: PropertyValues): boolean { if (changedProps.has("stateObj")) { return true; @@ -50,12 +95,33 @@ class MoreInfoWeather extends LitElement { return false; } + protected updated(changedProps: PropertyValues): void { + super.updated(changedProps); + + if (changedProps.has("stateObj") || !this._subscribed) { + const oldState = changedProps.get("stateObj") as + | WeatherEntity + | undefined; + if ( + oldState?.entity_id !== this.stateObj?.entity_id || + !this._subscribed + ) { + this._subscribeForecastEvents(); + } + } + } + protected render() { if (!this.hass || !this.stateObj) { return nothing; } - const hourly = isForecastHourly(this.stateObj.attributes.forecast); + const forecastData = getForecast( + this.stateObj.attributes, + this._forecastEvent + ); + const forecast = forecastData?.forecast; + const hourly = forecastData?.type === "hourly"; return html` ${this._showValue(this.stateObj.attributes.temperature) @@ -144,12 +210,12 @@ class MoreInfoWeather extends LitElement { ` : ""} - ${this.stateObj.attributes.forecast + ${forecast ? html`
${this.hass.localize("ui.card.weather.forecast")}:
- ${this.stateObj.attributes.forecast.map((item) => + ${forecast.map((item) => this._showValue(item.templow) || this._showValue(item.temperature) ? html`
${item.condition @@ -176,6 +242,9 @@ class MoreInfoWeather extends LitElement { this.hass.locale, this.hass.config )} + ${item.is_daytime !== false + ? this.hass!.localize("ui.card.weather.day") + : this.hass!.localize("ui.card.weather.night")}
`}
diff --git a/src/dialogs/more-info/show-ha-more-info-dialog.ts b/src/dialogs/more-info/show-ha-more-info-dialog.ts index b5a4197979..de6d688fec 100644 --- a/src/dialogs/more-info/show-ha-more-info-dialog.ts +++ b/src/dialogs/more-info/show-ha-more-info-dialog.ts @@ -5,6 +5,3 @@ export const showMoreInfoDialog = ( element: HTMLElement, params: MoreInfoDialogParams ) => fireEvent(element, "hass-more-info", params); - -export const hideMoreInfoDialog = (element: HTMLElement) => - fireEvent(element, "hass-more-info", { entityId: null }); diff --git a/src/dialogs/notifications/notification-drawer.ts b/src/dialogs/notifications/notification-drawer.ts index b11a45a345..57407a62ad 100644 --- a/src/dialogs/notifications/notification-drawer.ts +++ b/src/dialogs/notifications/notification-drawer.ts @@ -108,12 +108,13 @@ export class HuiNotificationDrawer extends LitElement {
${notifications.length ? html`${notifications.map( - (notification) => html`
- -
` + (notification) => + html`
+ +
` )} ${this._notifications.length > 1 ? html`
diff --git a/src/dialogs/voice-command-dialog/ha-voice-command-dialog.ts b/src/dialogs/voice-command-dialog/ha-voice-command-dialog.ts index de68790067..7bf95f7c33 100644 --- a/src/dialogs/voice-command-dialog/ha-voice-command-dialog.ts +++ b/src/dialogs/voice-command-dialog/ha-voice-command-dialog.ts @@ -87,9 +87,16 @@ export class HaVoiceCommandDialog extends LitElement { private _pipelinePromise?: Promise; - public async showDialog(params?: VoiceCommandDialogParams): Promise { - if (params?.pipeline_id) { - this._pipelineId = params?.pipeline_id; + public async showDialog( + params: Required + ): Promise { + if (params.pipeline_id === "last_used") { + // Do not set pipeline id (retrieve from storage) + } else if (params.pipeline_id === "preferred") { + await this._loadPipelines(); + this._pipelineId = this._preferredPipeline; + } else { + this._pipelineId = params.pipeline_id; } this._conversation = [ @@ -103,7 +110,11 @@ export class HaVoiceCommandDialog extends LitElement { this._scrollMessagesBottom(); await this._pipelinePromise; - if (params?.start_listening && this._pipeline?.stt_engine) { + if ( + params?.start_listening && + this._pipeline?.stt_engine && + AudioRecorder.isSupported + ) { this._toggleListening(); } } @@ -158,20 +169,24 @@ export class HaVoiceCommandDialog extends LitElement { > ${this._pipelines?.map( - (pipeline) => html` - ${pipeline.name}${pipeline.id === this._preferredPipeline - ? html` - - ` - : nothing} - ` + (pipeline) => + html` + ${pipeline.name}${pipeline.id === this._preferredPipeline + ? html` + + ` + : nothing} + ` )} ${this.hass.user?.is_admin ? html`
  • diff --git a/src/dialogs/voice-command-dialog/show-ha-voice-command-dialog.ts b/src/dialogs/voice-command-dialog/show-ha-voice-command-dialog.ts index c755877cd3..3c29fb8d16 100644 --- a/src/dialogs/voice-command-dialog/show-ha-voice-command-dialog.ts +++ b/src/dialogs/voice-command-dialog/show-ha-voice-command-dialog.ts @@ -4,21 +4,22 @@ import { HomeAssistant } from "../../types"; const loadVoiceCommandDialog = () => import("./ha-voice-command-dialog"); export interface VoiceCommandDialogParams { - pipeline_id?: string; + pipeline_id: "last_used" | "preferred" | string; start_listening?: boolean; } export const showVoiceCommandDialog = ( element: HTMLElement, hass: HomeAssistant, - dialogParams?: VoiceCommandDialogParams + dialogParams: VoiceCommandDialogParams ): void => { if (hass.auth.external?.config.hasAssist) { hass.auth.external!.fireMessage({ type: "assist/show", payload: { - pipeline_id: dialogParams?.pipeline_id, - start_listening: dialogParams?.start_listening, + pipeline_id: dialogParams.pipeline_id, + // Start listening by default for app + start_listening: dialogParams.start_listening ?? true, }, }); return; @@ -26,6 +27,10 @@ export const showVoiceCommandDialog = ( fireEvent(element, "show-dialog", { dialogTag: "ha-voice-command-dialog", dialogImport: loadVoiceCommandDialog, - dialogParams, + dialogParams: { + pipeline_id: dialogParams.pipeline_id, + // Don't start listening by default for web + start_listening: dialogParams.start_listening ?? false, + }, }); }; diff --git a/src/entrypoints/core.ts b/src/entrypoints/core.ts index cc92ddd5bc..d9467f11ca 100644 --- a/src/entrypoints/core.ts +++ b/src/entrypoints/core.ts @@ -65,6 +65,7 @@ const authProm = isExternal : () => getAuth({ hassUrl, + limitHassInstance: true, saveTokens, loadTokens: () => Promise.resolve(loadTokens()), }); diff --git a/src/external_app/external_messaging.ts b/src/external_app/external_messaging.ts index 5c10155138..1b6e9d87f6 100644 --- a/src/external_app/external_messaging.ts +++ b/src/external_app/external_messaging.ts @@ -98,8 +98,8 @@ interface EMOutgoingMessageSidebarShow extends EMMessage { interface EMOutgoingMessageAssistShow extends EMMessage { type: "assist/show"; payload?: { - pipeline_id?: string; - start_listening?: boolean; + pipeline_id: "preferred" | "last_used" | string; + start_listening: boolean; }; } diff --git a/src/html/onboarding.html.template b/src/html/onboarding.html.template index 7e34e0bc7a..1824f4727b 100644 --- a/src/html/onboarding.html.template +++ b/src/html/onboarding.html.template @@ -11,13 +11,14 @@ } body { height: auto; + padding: 64px 0; } .content { box-sizing: border-box; padding: 20px 16px; border-radius: var(--ha-card-border-radius, 12px); max-width: 432px; - margin: 64px auto 0; + margin: 0 auto; box-shadow: var( --ha-card-box-shadow, rgba(0, 0, 0, 0.25) 0px 54px 55px, diff --git a/src/layouts/hass-tabs-subpage-data-table.ts b/src/layouts/hass-tabs-subpage-data-table.ts index ed454bccd0..5efadf1101 100644 --- a/src/layouts/hass-tabs-subpage-data-table.ts +++ b/src/layouts/hass-tabs-subpage-data-table.ts @@ -166,8 +166,7 @@ export class HaTabsSubpageDataTable extends LitElement { .filter=${this.filter} .suffix=${!this.narrow} @value-changed=${this._handleSearchChange} - .label=${this.searchLabel || - this.hass.localize("ui.components.data-table.search")} + .label=${this.searchLabel} > ${!this.narrow ? html`
    - html` - - - ${page.iconPath - ? html`` - : ""} - - - ` + (page) => html` + + + ${page.iconPath + ? html`` + : ""} + + + ` ); } ); diff --git a/src/onboarding/ha-onboarding.ts b/src/onboarding/ha-onboarding.ts index 956914856d..88b12140f1 100644 --- a/src/onboarding/ha-onboarding.ts +++ b/src/onboarding/ha-onboarding.ts @@ -211,6 +211,7 @@ class HaOnboarding extends litLocalizeLiteMixin(HassElement) { // First step is already done, so we need to get auth somewhere else. const auth = await getAuth({ hassUrl, + limitHassInstance: true, }); history.replaceState(null, "", location.pathname); await this._connectHass(auth); @@ -237,6 +238,7 @@ class HaOnboarding extends litLocalizeLiteMixin(HassElement) { try { const auth = await getAuth({ hassUrl, + limitHassInstance: true, authCode: result.auth_code, }); await this._connectHass(auth); diff --git a/src/onboarding/onboarding-analytics.ts b/src/onboarding/onboarding-analytics.ts index 09c19a6f98..aeddcb4cc7 100644 --- a/src/onboarding/onboarding-analytics.ts +++ b/src/onboarding/onboarding-analytics.ts @@ -82,10 +82,13 @@ class OnboardingAnalytics extends LitElement { static get styles(): CSSResultGroup { return css` + p { + font-size: 14px; + line-height: 20px; + } .error { color: var(--error-color); } - .footer { margin-top: 16px; display: flex; @@ -93,7 +96,6 @@ class OnboardingAnalytics extends LitElement { align-items: center; flex-direction: row-reverse; } - a { color: var(--primary-color); } diff --git a/src/onboarding/onboarding-core-config.ts b/src/onboarding/onboarding-core-config.ts index 46621294f4..3ea32cd556 100644 --- a/src/onboarding/onboarding-core-config.ts +++ b/src/onboarding/onboarding-core-config.ts @@ -5,10 +5,10 @@ import { html, LitElement, nothing, + PropertyValues, TemplateResult, } from "lit"; -import { customElement, property, query, state } from "lit/decorators"; -import memoizeOne from "memoize-one"; +import { customElement, property, state } from "lit/decorators"; import { fireEvent } from "../common/dom/fire_event"; import type { LocalizeFunc } from "../common/translations/localize"; import "../components/ha-alert"; @@ -22,22 +22,13 @@ import "../components/ha-textfield"; import type { HaTextField } from "../components/ha-textfield"; import "../components/ha-timezone-picker"; import "../components/map/ha-locations-editor"; -import type { - HaLocationsEditor, - MarkerLocation, -} from "../components/map/ha-locations-editor"; -import { - ConfigUpdateValues, - detectCoreConfig, - saveCoreConfig, -} from "../data/core"; +import { ConfigUpdateValues, saveCoreConfig } from "../data/core"; +import { countryCurrency } from "../data/currency"; import { onboardCoreConfigStep } from "../data/onboarding"; import type { HomeAssistant, ValueChangedEvent } from "../types"; import { getLocalLanguage } from "../util/common-translation"; - -const amsterdam: [number, number] = [52.3731339, 4.8903147]; -const mql = matchMedia("(prefers-color-scheme: dark)"); -const locationMarkerId = "location"; +import "./onboarding-location"; +import "./onboarding-name"; @customElement("onboarding-core-config") class OnboardingCoreConfig extends LitElement { @@ -57,19 +48,29 @@ class OnboardingCoreConfig extends LitElement { @state() private _currency?: ConfigUpdateValues["currency"]; - @state() private _timeZone? = - Intl.DateTimeFormat?.().resolvedOptions?.().timeZone; + @state() private _timeZone?: ConfigUpdateValues["time_zone"]; - @state() private _language: ConfigUpdateValues["language"] = - getLocalLanguage(); + @state() private _language: ConfigUpdateValues["language"]; @state() private _country?: ConfigUpdateValues["country"]; @state() private _error?: string; - @query("ha-locations-editor", true) private map!: HaLocationsEditor; - protected render(): TemplateResult { + if (!this._name) { + return html``; + } + if (!this._location) { + return html``; + } return html` ${ this._error @@ -78,55 +79,11 @@ class OnboardingCoreConfig extends LitElement { }

    - ${this.onboardingLocalize( - "ui.panel.page-onboarding.core-config.intro", - "name", - this.hass.user!.name - )} + ${this.onboardingLocalize( + "ui.panel.page-onboarding.core-config.intro_core_config" + )}

    - - -
    -

    - ${this.onboardingLocalize( - "ui.panel.page-onboarding.core-config.intro_location" - )} -

    - -
    -
    - ${this.onboardingLocalize( - "ui.panel.page-onboarding.core-config.intro_location_detect" - )} -
    - - ${this.onboardingLocalize( - "ui.panel.page-onboarding.core-config.button_detect" - )} - -
    -
    - -
    - -
    -
    this.renderRoot.querySelector("ha-textfield")!.focus(), - 100 - ); - this.addEventListener("keypress", (ev) => { - if (ev.key === "Enter") { + this.addEventListener("keyup", (ev) => { + if (this._location && ev.key === "Enter") { this._save(ev); } }); } - private get _nameValue() { - return this._name !== undefined - ? this._name - : this.onboardingLocalize( - "ui.panel.page-onboarding.core-config.location_name_default" - ); - } - - private get _locationValue() { - return this._location || amsterdam; - } - private get _elevationValue() { return this._elevation !== undefined ? this._elevation : 0; } @@ -324,17 +279,6 @@ class OnboardingCoreConfig extends LitElement { return this._currency !== undefined ? this._currency : ""; } - private _markerLocation = memoizeOne( - (location: [number, number]): MarkerLocation[] => [ - { - id: locationMarkerId, - latitude: location[0], - longitude: location[1], - location_editable: true, - }, - ] - ); - private _handleValueChanged(ev: ValueChangedEvent) { const target = ev.currentTarget as HTMLElement; this[`_${target.getAttribute("name")}`] = ev.detail.value; @@ -345,8 +289,25 @@ class OnboardingCoreConfig extends LitElement { this[`_${target.name}`] = target.value; } - private _locationChanged(ev) { - this._location = ev.detail.location; + private _nameChanged(ev: CustomEvent) { + this._name = ev.detail.value; + } + + private async _locationChanged(ev) { + this._location = ev.detail.value.location; + this._country = ev.detail.value.country; + this._elevation = ev.detail.value.elevation; + this._currency = ev.detail.value.currency; + this._language = ev.detail.value.language || getLocalLanguage(); + this._timeZone = + ev.detail.value.timezone || + Intl.DateTimeFormat?.().resolvedOptions?.().timeZone; + this._unitSystem = ev.detail.value.unit_system; + await this.updateComplete; + setTimeout( + () => this.renderRoot.querySelector("ha-textfield")!.focus(), + 100 + ); } private _unitSystemChanged(ev: CustomEvent) { @@ -355,55 +316,17 @@ class OnboardingCoreConfig extends LitElement { | "us_customary"; } - private async _detect() { - this._working = true; - try { - const values = await detectCoreConfig(this.hass); - - if (values.latitude && values.longitude) { - this.map.addEventListener( - "markers-updated", - () => { - this.map.fitMarker(locationMarkerId); - }, - { - once: true, - } - ); - this._location = [Number(values.latitude), Number(values.longitude)]; - } - if (values.elevation) { - this._elevation = String(values.elevation); - } - if (values.unit_system) { - this._unitSystem = values.unit_system; - } - if (values.time_zone) { - this._timeZone = values.time_zone; - } - if (values.currency) { - this._currency = values.currency; - } - if (values.country) { - this._country = values.country; - } - this._language = getLocalLanguage(); - } catch (err: any) { - this._error = `Failed to detect location information: ${err.message}`; - } finally { - this._working = false; - } - } - private async _save(ev) { + if (!this._location) { + return; + } ev.preventDefault(); this._working = true; try { - const location = this._locationValue; await saveCoreConfig(this.hass, { - location_name: this._nameValue, - latitude: location[0], - longitude: location[1], + location_name: this._name, + latitude: this._location[0], + longitude: this._location[1], elevation: Number(this._elevationValue), unit_system: this._unitSystemValue, time_zone: this._timeZoneValue || "UTC", @@ -436,12 +359,13 @@ class OnboardingCoreConfig extends LitElement { color: var(--secondary-text-color); } - ha-textfield { - display: block; + p { + font-size: 14px; + line-height: 20px; } - ha-locations-editor { - height: 200px; + ha-textfield { + display: block; } .flex { diff --git a/src/onboarding/onboarding-integrations.ts b/src/onboarding/onboarding-integrations.ts index 56622a750f..c2c145359a 100644 --- a/src/onboarding/onboarding-integrations.ts +++ b/src/onboarding/onboarding-integrations.ts @@ -211,6 +211,10 @@ class OnboardingIntegrations extends SubscribeMixin(LitElement) { static get styles(): CSSResultGroup { return css` + p { + font-size: 14px; + line-height: 20px; + } .badges { margin-top: 24px; display: flex; diff --git a/src/onboarding/onboarding-location.ts b/src/onboarding/onboarding-location.ts new file mode 100644 index 0000000000..e75a64b100 --- /dev/null +++ b/src/onboarding/onboarding-location.ts @@ -0,0 +1,542 @@ +import "@material/mwc-button/mwc-button"; +import { mdiCrosshairsGps, mdiMapMarker, mdiMapSearchOutline } from "@mdi/js"; +import { + css, + CSSResultGroup, + html, + LitElement, + nothing, + TemplateResult, +} from "lit"; +import { customElement, property, query, state } from "lit/decorators"; +import memoizeOne from "memoize-one"; +import type { LocalizeFunc } from "../common/translations/localize"; +import "../components/ha-alert"; +import "../components/ha-formfield"; +import "../components/ha-radio"; +import "../components/ha-textfield"; +import type { HaTextField } from "../components/ha-textfield"; +import "../components/map/ha-locations-editor"; +import type { + HaLocationsEditor, + MarkerLocation, +} from "../components/map/ha-locations-editor"; +import { ConfigUpdateValues, detectCoreConfig } from "../data/core"; +import { showConfirmationDialog } from "../dialogs/generic/show-dialog-box"; +import type { HomeAssistant } from "../types"; +import { fireEvent } from "../common/dom/fire_event"; +import { + OpenStreetMapPlace, + reverseGeocode, + searchPlaces, +} from "../data/openstreetmap"; + +const AMSTERDAM: [number, number] = [52.3731339, 4.8903147]; +const mql = matchMedia("(prefers-color-scheme: dark)"); +const LOCATION_MARKER_ID = "location"; + +@customElement("onboarding-location") +class OnboardingLocation extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property() public onboardingLocalize!: LocalizeFunc; + + @state() private _working = false; + + @state() private _location?: [number, number]; + + @state() private _places?: OpenStreetMapPlace[] | null; + + @state() private _error?: string; + + @state() private _search = false; + + @state() private _highlightedMarker?: number; + + private _elevation?: string; + + private _unitSystem?: ConfigUpdateValues["unit_system"]; + + private _currency?: ConfigUpdateValues["currency"]; + + private _timeZone?: ConfigUpdateValues["time_zone"]; + + private _country?: ConfigUpdateValues["country"]; + + @query("ha-locations-editor", true) private map!: HaLocationsEditor; + + protected render(): TemplateResult { + const addressAttribution = this.onboardingLocalize( + "ui.panel.page-onboarding.core-config.location_address", + { + openstreetmap: html`OpenStreetMap`, + osm_privacy_policy: html`${this.onboardingLocalize( + "ui.panel.page-onboarding.core-config.osm_privacy_policy" + )}`, + } + ); + + return html` + ${this._error + ? html`${this._error}` + : nothing} + +

    + ${this.onboardingLocalize( + "ui.panel.page-onboarding.core-config.intro_location" + )} +

    + + + ${this._working + ? html` + + ` + : html` + + `} + + ${this._places !== undefined + ? html` + + ${this._places?.length + ? this._places.map((place) => { + const primary = [ + place.name || place.address[place.category], + place.address.house_number, + place.address.road || place.address.waterway, + place.address.village || place.address.town, + place.address.suburb || place.address.subdivision, + place.address.city || place.address.municipality, + ] + .filter(Boolean) + .join(", "); + const secondary = [ + place.address.county || + place.address.state_district || + place.address.region, + place.address.state, + place.address.country, + ] + .filter(Boolean) + .join(", "); + return html` + ${primary || secondary} + ${primary ? secondary : ""} + `; + }) + : html`${this._places === null ? "" : "No results"}`} + + ` + : nothing} +

    ${addressAttribution}

    + + + + `; + } + + protected firstUpdated(changedProps) { + super.firstUpdated(changedProps); + setTimeout( + () => this.renderRoot.querySelector("ha-textfield")!.focus(), + 100 + ); + this.addEventListener("keyup", (ev) => { + if (ev.key === "Enter") { + this._save(ev); + } + }); + } + + protected updated(changedProps) { + if (changedProps.has("_highlightedMarker") && this._highlightedMarker) { + const place = this._places?.find( + (plc) => plc.place_id === this._highlightedMarker + ); + if (place?.boundingbox?.length === 4) { + this.map.fitBounds( + [ + [place.boundingbox[0], place.boundingbox[2]], + [place.boundingbox[1], place.boundingbox[3]], + ], + { zoom: 16, pad: 0 } + ); + } else { + this.map.fitMarker(String(this._highlightedMarker), { zoom: 16 }); + } + } + } + + private _markerLocations = memoizeOne( + ( + location?: [number, number], + places?: OpenStreetMapPlace[] | null, + highlightedMarker?: number + ): MarkerLocation[] => { + if (!places) { + return [ + { + id: LOCATION_MARKER_ID, + latitude: (location || AMSTERDAM)[0], + longitude: (location || AMSTERDAM)[1], + location_editable: true, + }, + ]; + } + return places?.length + ? places.map((place) => ({ + id: String(place.place_id), + iconPath: + place.place_id === highlightedMarker ? undefined : mdiMapMarker, + latitude: + location && place.place_id === highlightedMarker + ? location[0] + : Number(place.lat), + longitude: + location && place.place_id === highlightedMarker + ? location[1] + : Number(place.lon), + location_editable: place.place_id === highlightedMarker, + })) + : []; + } + ); + + private _locationChanged(ev) { + this._location = ev.detail.location; + if (ev.detail.id !== LOCATION_MARKER_ID) { + this._reverseGeocode(); + } + } + + private _markerClicked(ev) { + if (ev.detail.id === LOCATION_MARKER_ID) { + return; + } + this._highlightedMarker = ev.detail.id; + const place = this._places!.find((plc) => plc.place_id === ev.detail.id)!; + this._location = [Number(place.lat), Number(place.lon)]; + this._country = place.address.country_code.toUpperCase(); + } + + private _itemClicked(ev) { + this._highlightedMarker = ev.currentTarget.placeId; + const place = this._places!.find( + (plc) => plc.place_id === ev.currentTarget.placeId + )!; + this._location = [Number(place.lat), Number(place.lon)]; + this._country = place.address.country_code.toUpperCase(); + } + + private async _addressSearch(ev: KeyboardEvent) { + ev.stopPropagation(); + this._search = (ev.currentTarget as HaTextField).value.length > 0; + if (ev.key !== "Enter") { + return; + } + this._searchAddress((ev.currentTarget as HaTextField).value); + } + + private async _searchAddress(address: string) { + this._working = true; + this._location = undefined; + this._highlightedMarker = undefined; + this._error = undefined; + this._places = null; + this.map.addEventListener( + "markers-updated", + () => { + setTimeout(() => { + if ((this._places?.length || 0) > 2) { + this.map.fitMap({ pad: 0.5 }); + } + }, 500); + }, + { + once: true, + } + ); + try { + this._places = await searchPlaces(address, this.hass, true, 3); + if (this._places?.length === 1) { + this._highlightedMarker = this._places[0].place_id; + this._location = [ + Number(this._places[0].lat), + Number(this._places[0].lon), + ]; + this._country = this._places[0].address.country_code.toUpperCase(); + } + } catch (e: any) { + this._places = undefined; + this._error = e.message; + } finally { + this._working = false; + } + } + + private async _reverseGeocode() { + if (!this._location) { + return; + } + this._places = null; + const reverse = await reverseGeocode(this._location, this.hass); + this._country = reverse.address.country_code.toUpperCase(); + this._places = [reverse]; + this._highlightedMarker = reverse.place_id; + } + + private async _handleButtonClick(ev) { + if (this._search) { + this._searchAddress(ev.target.parentElement.value); + return; + } + this._detectLocation(); + } + + private _detectLocation() { + if (window.isSecureContext && navigator.geolocation) { + this._working = true; + const options = { + enableHighAccuracy: true, + timeout: 5000, + maximumAge: 0, + }; + navigator.geolocation.getCurrentPosition( + async (result) => { + this.map.addEventListener( + "markers-updated", + () => { + this.map.fitMarker(LOCATION_MARKER_ID); + }, + { + once: true, + } + ); + this._location = [result.coords.latitude, result.coords.longitude]; + if (result.coords.altitude) { + this._elevation = String(result.coords.altitude); + } + try { + await this._reverseGeocode(); + } finally { + this._working = false; + } + }, + () => { + // GPS is not available, get location based on IP + this._working = false; + this._whoAmI(); + }, + options + ); + } else { + this._whoAmI(); + } + } + + private async _whoAmI() { + const confirm = await showConfirmationDialog(this, { + title: this.onboardingLocalize( + "ui.panel.page-onboarding.core-config.title_location_detect" + ), + text: this.onboardingLocalize( + "ui.panel.page-onboarding.core-config.intro_location_detect" + ), + }); + if (!confirm) { + return; + } + this._working = true; + try { + const values = await detectCoreConfig(this.hass); + + if (values.latitude && values.longitude) { + this.map.addEventListener( + "markers-updated", + () => { + this.map.fitMarker(LOCATION_MARKER_ID); + }, + { + once: true, + } + ); + this._location = [Number(values.latitude), Number(values.longitude)]; + } + if (values.elevation) { + this._elevation = String(values.elevation); + } + if (values.unit_system) { + this._unitSystem = values.unit_system; + } + if (values.time_zone) { + this._timeZone = values.time_zone; + } + if (values.currency) { + this._currency = values.currency; + } + if (values.country) { + this._country = values.country; + } + } catch (err: any) { + this._error = `Failed to detect location information: ${err.message}`; + } finally { + this._working = false; + } + } + + private async _save(ev) { + if (!this._location) { + return; + } + ev.preventDefault(); + fireEvent(this, "value-changed", { + value: { + location: this._location!, + country: this._country, + elevation: this._elevation, + unit_system: this._unitSystem, + time_zone: this._timeZone, + currency: this._currency, + }, + }); + } + + static get styles(): CSSResultGroup { + return css` + p { + font-size: 14px; + line-height: 20px; + } + ha-textfield { + display: block; + } + ha-textfield > ha-icon-button { + position: absolute; + top: 10px; + right: 10px; + --mdc-icon-button-size: 36px; + --mdc-icon-size: 20px; + color: var(--secondary-text-color); + inset-inline-start: initial; + inset-inline-end: 10px; + direction: var(--direction); + } + ha-textfield > ha-circular-progress { + position: relative; + left: 12px; + } + ha-locations-editor { + display: block; + height: 300px; + margin-top: 8px; + border-radius: var(--mdc-shape-small, 4px); + overflow: hidden; + } + mwc-list { + width: 100%; + border: 1px solid var(--divider-color); + box-sizing: border-box; + border-top-width: 0; + border-bottom-left-radius: var(--mdc-shape-small, 4px); + border-bottom-right-radius: var(--mdc-shape-small, 4px); + --mdc-list-vertical-padding: 0; + } + ha-list-item { + height: 72px; + } + .footer { + margin-top: 16px; + text-align: right; + } + .attribution { + /* textfield helper style */ + margin: 0; + padding: 4px 16px 12px 16px; + color: var(--mdc-text-field-label-ink-color, rgba(0, 0, 0, 0.6)); + font-family: var( + --mdc-typography-caption-font-family, + var(--mdc-typography-font-family, Roboto, sans-serif) + ); + font-size: var(--mdc-typography-caption-font-size, 0.75rem); + font-weight: var(--mdc-typography-caption-font-weight, 400); + letter-spacing: var( + --mdc-typography-caption-letter-spacing, + 0.0333333333em + ); + text-decoration: var(--mdc-typography-caption-text-decoration, inherit); + text-transform: var(--mdc-typography-caption-text-transform, inherit); + } + .attribution a { + color: inherit; + } + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "onboarding-location": OnboardingLocation; + } +} diff --git a/src/onboarding/onboarding-name.ts b/src/onboarding/onboarding-name.ts new file mode 100644 index 0000000000..6d8d023137 --- /dev/null +++ b/src/onboarding/onboarding-name.ts @@ -0,0 +1,111 @@ +import "@material/mwc-button/mwc-button"; +import { CSSResultGroup, LitElement, TemplateResult, css, html } from "lit"; +import { customElement, property } from "lit/decorators"; +import { fireEvent } from "../common/dom/fire_event"; +import type { LocalizeFunc } from "../common/translations/localize"; +import "../components/ha-alert"; +import "../components/ha-formfield"; +import "../components/ha-radio"; +import "../components/ha-textfield"; +import "../components/map/ha-locations-editor"; +import { ConfigUpdateValues } from "../data/core"; +import type { HomeAssistant } from "../types"; + +@customElement("onboarding-name") +class OnboardingName extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property() public onboardingLocalize!: LocalizeFunc; + + private _name?: ConfigUpdateValues["location_name"]; + + protected render(): TemplateResult { + return html` +

    + ${this.onboardingLocalize( + "ui.panel.page-onboarding.core-config.intro", + { name: this.hass.user!.name } + )} +

    + + + +

    + ${this.onboardingLocalize( + "ui.panel.page-onboarding.core-config.intro_core" + )} +

    + + + `; + } + + protected firstUpdated(changedProps) { + super.firstUpdated(changedProps); + setTimeout( + () => this.renderRoot.querySelector("ha-textfield")!.focus(), + 100 + ); + this.addEventListener("keyup", (ev) => { + if (ev.key === "Enter") { + this._save(ev); + } + }); + } + + private get _nameValue() { + return this._name !== undefined + ? this._name + : this.onboardingLocalize( + "ui.panel.page-onboarding.core-config.location_name_default" + ); + } + + private _nameChanged(ev) { + this._name = ev.target.value; + } + + private async _save(ev) { + ev.preventDefault(); + fireEvent(this, "value-changed", { + value: this._nameValue, + }); + } + + static get styles(): CSSResultGroup { + return css` + ha-textfield { + display: block; + } + p { + font-size: 14px; + line-height: 20px; + } + .footer { + margin-top: 16px; + text-align: right; + } + a { + color: var(--primary-color); + } + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "onboarding-name": OnboardingName; + } +} diff --git a/src/panels/calendar/ha-panel-calendar.ts b/src/panels/calendar/ha-panel-calendar.ts index 878d6348fa..c2562d1357 100644 --- a/src/panels/calendar/ha-panel-calendar.ts +++ b/src/panels/calendar/ha-panel-calendar.ts @@ -79,23 +79,22 @@ class PanelCalendar extends LitElement { ${this.hass.localize("ui.components.calendar.my_calendars")}
    ${this._calendars.map( - (selCal) => - html` -
    - - - -
    - ` + (selCal) => html` +
    + + + +
    + ` )}
    = (item) => html` - ${item.name} -`; +const rowRenderer: ComboBoxLitRenderer = (item) => + html` + ${item.name} + `; @customElement("dialog-add-application-credential") export class DialogAddApplicationCredential extends LitElement { diff --git a/src/panels/config/areas/ha-config-area-page.ts b/src/panels/config/areas/ha-config-area-page.ts index 4edc723c0e..8a326e6867 100644 --- a/src/panels/config/areas/ha-config-area-page.ts +++ b/src/panels/config/areas/ha-config-area-page.ts @@ -283,15 +283,14 @@ class HaConfigAreaPage extends SubscribeMixin(LitElement) { .header=${this.hass.localize("ui.panel.config.devices.caption")} >${devices.length ? devices.map( - (device) => - html` - - - ${device.name} - - - - ` + (device) => html` + + + ${device.name} + + + + ` ) : html` { + this.shadowRoot!.querySelectorAll("ha-expansion-panel")[i].expanded = + true; + this.expandedUpdateFlag = !this.expandedUpdateFlag; + }); + } + + private isExpanded(i: number) { + const nodes = this.shadowRoot!.querySelectorAll("ha-expansion-panel"); + if (nodes[i]) { + return nodes[i].expanded; + } + return false; + } + + private _expandedChanged() { + this.expandedUpdateFlag = !this.expandedUpdateFlag; + } + + private _getDescription(option, idx: number) { + if (this.isExpanded(idx)) { + return ""; + } + if (!option.conditions || option.conditions.length === 0) { + return this.hass.localize( + "ui.panel.config.automation.editor.actions.type.choose.no_conditions" + ); + } + let str = ""; + if (typeof option.conditions[0] === "string") { + str += option.conditions[0]; + } else { + str += describeCondition( + option.conditions[0], + this.hass, + this._entityReg + ); + } + if (option.conditions.length > 1) { + str += this.hass.localize( + "ui.panel.config.automation.editor.actions.type.choose.option_description_additional", + "numberOfAdditionalConditions", + option.conditions.length - 1 + ); + } + return str; + } + protected render() { const action = this.action; return html` ${(action.choose ? ensureArray(action.choose) : []).map( - (option, idx) => html` - -
    -

    - ${this.hass.localize( - "ui.panel.config.automation.editor.actions.type.choose.option", - "number", - idx + 1 - )}: -

    -

    - ${this.hass.localize( - "ui.panel.config.automation.editor.actions.type.choose.conditions" - )}: -

    - (option.conditions)} - .reOrderMode=${this.reOrderMode} - .disabled=${this.disabled} - .hass=${this.hass} - .idx=${idx} - @value-changed=${this._conditionChanged} - > -

    - ${this.hass.localize( - "ui.panel.config.automation.editor.actions.type.choose.sequence" - )}: -

    - -
    -
    ` + (option, idx) => + html` + +

    + ${this.hass.localize( + "ui.panel.config.automation.editor.actions.type.choose.option", + "number", + idx + 1 + )}: + ${this._getDescription(option, idx)} +

    + + +
    +

    + ${this.hass.localize( + "ui.panel.config.automation.editor.actions.type.choose.conditions" + )}: +

    + ( + option.conditions + )} + .reOrderMode=${this.reOrderMode} + .disabled=${this.disabled} + .hass=${this.hass} + .idx=${idx} + @value-changed=${this._conditionChanged} + > +

    + ${this.hass.localize( + "ui.panel.config.automation.editor.actions.type.choose.sequence" + )}: +

    + +
    +
    +
    ` )} - html` - this._showInfo(automation), - }, - { - path: mdiPlay, - label: this.hass.localize( - "ui.panel.config.automation.editor.run" - ), - action: () => this._runActions(automation), - }, - { - path: mdiTransitConnection, - label: this.hass.localize( - "ui.panel.config.automation.editor.show_trace" - ), - action: () => this._showTrace(automation), - }, - { - divider: true, - }, - { - path: mdiContentDuplicate, - label: this.hass.localize( - "ui.panel.config.automation.picker.duplicate" - ), - action: () => this.duplicate(automation), - }, - { - path: - automation.state === "off" - ? mdiPlayCircleOutline - : mdiStopCircleOutline, - label: - automation.state === "off" - ? this.hass.localize( - "ui.panel.config.automation.editor.enable" - ) - : this.hass.localize( - "ui.panel.config.automation.editor.disable" - ), - action: () => this._toggle(automation), - }, - { - label: this.hass.localize( - "ui.panel.config.automation.picker.delete" - ), - path: mdiDelete, - action: () => this._deleteConfirm(automation), - warning: true, - }, - ]} - > - - `, + template: (_: string, automation: any) => html` + this._showInfo(automation), + }, + { + path: mdiPlay, + label: this.hass.localize( + "ui.panel.config.automation.editor.run" + ), + action: () => this._runActions(automation), + }, + { + path: mdiTransitConnection, + label: this.hass.localize( + "ui.panel.config.automation.editor.show_trace" + ), + action: () => this._showTrace(automation), + }, + { + divider: true, + }, + { + path: mdiContentDuplicate, + label: this.hass.localize( + "ui.panel.config.automation.picker.duplicate" + ), + action: () => this.duplicate(automation), + }, + { + path: + automation.state === "off" + ? mdiPlayCircleOutline + : mdiStopCircleOutline, + label: + automation.state === "off" + ? this.hass.localize( + "ui.panel.config.automation.editor.enable" + ) + : this.hass.localize( + "ui.panel.config.automation.editor.disable" + ), + action: () => this._toggle(automation), + }, + { + label: this.hass.localize( + "ui.panel.config.automation.picker.delete" + ), + path: mdiDelete, + action: () => this._deleteConfirm(automation), + warning: true, + }, + ]} + > + + `, }; return columns; } diff --git a/src/panels/config/automation/thingtalk/ha-thingtalk-placeholders.ts b/src/panels/config/automation/thingtalk/ha-thingtalk-placeholders.ts index 9731a96394..3be3fbe024 100644 --- a/src/panels/config/automation/thingtalk/ha-thingtalk-placeholders.ts +++ b/src/panels/config/automation/thingtalk/ha-thingtalk-placeholders.ts @@ -133,110 +133,107 @@ export class ThingTalkPlaceholders extends SubscribeMixin(LitElement) {
    ${this._error ? html`
    ${this._error}
    ` : ""} ${Object.entries(this.placeholders).map( - ([type, placeholders]) => - html` -

    - ${this.hass.localize( - `ui.panel.config.automation.editor.${type}s.name` - )}: -

    - ${placeholders.map((placeholder) => { - if (placeholder.fields.includes("device_id")) { - const extraInfo = getPath(this._extraInfo, [ - type, - placeholder.index, - ]); - return html` - - ${extraInfo && extraInfo.manualEntity - ? html` -

    - ${this.hass.localize( - `ui.panel.config.automation.thingtalk.link_devices.ambiguous_entities` - )} -

    - ${Object.keys(extraInfo.manualEntity).map( - (idx) => html` - { - const devId = - this._placeholderValues[type][ - placeholder.index - ][idx].device_id; - return this._deviceEntityLookup[ - devId - ].includes(entityState.entity_id); - }} - > - ` - )} - ` - : ""} - `; - } - if (placeholder.fields.includes("entity_id")) { - return html` - - `; - } + ([type, placeholders]) => html` +

    + ${this.hass.localize( + `ui.panel.config.automation.editor.${type}s.name` + )}: +

    + ${placeholders.map((placeholder) => { + if (placeholder.fields.includes("device_id")) { + const extraInfo = getPath(this._extraInfo, [ + type, + placeholder.index, + ]); return html` -
    - ${this.hass.localize( - `ui.panel.config.automation.thingtalk.link_devices.unknown_placeholder` - )}
    - ${placeholder.domains}
    - ${placeholder.fields.map( - (field) => html` ${field}
    ` + + > + ${extraInfo && extraInfo.manualEntity + ? html` +

    + ${this.hass.localize( + `ui.panel.config.automation.thingtalk.link_devices.ambiguous_entities` + )} +

    + ${Object.keys(extraInfo.manualEntity).map( + (idx) => html` + { + const devId = + this._placeholderValues[type][ + placeholder.index + ][idx].device_id; + return this._deviceEntityLookup[ + devId + ].includes(entityState.entity_id); + }} + > + ` + )} + ` + : ""} `; - })} - ` + } + if (placeholder.fields.includes("entity_id")) { + return html` + + `; + } + return html` +
    + ${this.hass.localize( + `ui.panel.config.automation.thingtalk.link_devices.unknown_placeholder` + )}
    + ${placeholder.domains}
    + ${placeholder.fields.map((field) => html` ${field}
    `)} +
    + `; + })} + ` )}
    diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-numeric_state.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-numeric_state.ts index 29cb0362cd..4f27495023 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-numeric_state.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-numeric_state.ts @@ -51,6 +51,8 @@ export class HaNumericStateTrigger extends LitElement { "effect", "entity_id", "entity_picture", + "event_type", + "event_types", "fan_mode", "fan_modes", "fan_speed_list", @@ -288,6 +290,10 @@ export class HaNumericStateTrigger extends LitElement { delete newTrigger.mode_above; delete newTrigger.mode_below; + if (newTrigger.value_template === "") { + delete newTrigger.value_template; + } + fireEvent(this, "value-changed", { value: newTrigger }); } diff --git a/src/panels/config/automation/trigger/types/ha-automation-trigger-state.ts b/src/panels/config/automation/trigger/types/ha-automation-trigger-state.ts index 61904a424f..4899fb19ee 100644 --- a/src/panels/config/automation/trigger/types/ha-automation-trigger-state.ts +++ b/src/panels/config/automation/trigger/types/ha-automation-trigger-state.ts @@ -76,6 +76,7 @@ export class HaStateTrigger extends LitElement implements TriggerElement { "effect_list", "entity_id", "entity_picture", + "event_types", "fan_modes", "fan_speed_list", "friendly_name", diff --git a/src/panels/config/blueprint/ha-blueprint-overview.ts b/src/panels/config/blueprint/ha-blueprint-overview.ts index 44fd7f79c8..c926a2c581 100644 --- a/src/panels/config/blueprint/ha-blueprint-overview.ts +++ b/src/panels/config/blueprint/ha-blueprint-overview.ts @@ -125,11 +125,10 @@ class HaBlueprintOverview extends LitElement { direction: "asc", grows: true, template: narrow - ? (name, entity: any) => - html` - ${name}
    -
    ${entity.path}
    - ` + ? (name, entity: any) => html` + ${name}
    +
    ${entity.path}
    + ` : undefined, }, type: { diff --git a/src/panels/config/cloud/register/cloud-register.ts b/src/panels/config/cloud/register/cloud-register.ts index 790ddcca5a..dfab49cfbe 100644 --- a/src/panels/config/cloud/register/cloud-register.ts +++ b/src/panels/config/cloud/register/cloud-register.ts @@ -148,7 +148,9 @@ export class CloudRegister extends LitElement { hw.board !== null - )?.name; + this._boardName = hardwareInfo?.hardware.find((hw) => hw.board !== null) + ?.name; } else if (isHassioLoaded) { const osData: HassioHassOSInfo = await fetchHassioHassOsInfo(this.hass); if (osData.board) { diff --git a/src/panels/config/devices/device-detail/ha-device-automation-card.ts b/src/panels/config/devices/device-detail/ha-device-automation-card.ts index 9bf3e433ea..7ea0ec1026 100644 --- a/src/panels/config/devices/device-detail/ha-device-automation-card.ts +++ b/src/panels/config/devices/device-detail/ha-device-automation-card.ts @@ -20,7 +20,7 @@ declare global { } export abstract class HaDeviceAutomationCard< - T extends DeviceAutomation + T extends DeviceAutomation, > extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; @@ -76,20 +76,19 @@ export abstract class HaDeviceAutomationCard<
    ${automations.map( - (automation, idx) => - html` - - ${this._localizeDeviceAutomation( - this.hass, - this.entityReg!, - automation - )} - - ` + (automation, idx) => html` + + ${this._localizeDeviceAutomation( + this.hass, + this.entityReg!, + automation + )} + + ` )} ${!this._showSecondary && automations.length < this.automations.length diff --git a/src/panels/config/devices/ha-config-device-page.ts b/src/panels/config/devices/ha-config-device-page.ts index 2cd52f253c..3c3f513507 100644 --- a/src/panels/config/devices/ha-config-device-page.ts +++ b/src/panels/config/devices/ha-config-device-page.ts @@ -207,16 +207,25 @@ export class HaConfigDevicePage extends LitElement { const result = groupBy(entities, (entry) => entry.entity_category ? entry.entity_category + : computeDomain(entry.entity_id) === "event" + ? "event" : SENSOR_ENTITIES.includes(computeDomain(entry.entity_id)) ? "sensor" : "control" ) as Record< | "control" + | "event" | "sensor" | NonNullable, EntityRegistryStateEntry[] >; - for (const key of ["control", "sensor", "diagnostic", "config"]) { + for (const key of [ + "config", + "control", + "diagnostic", + "event", + "sensor", + ]) { if (!(key in result)) { result[key] = []; } @@ -376,32 +385,30 @@ export class HaConfigDevicePage extends LitElement { const firstDeviceAction = actions.shift(); if (device.disabled_by) { - deviceInfo.push( - html` - - ${this.hass.localize( - "ui.panel.config.devices.enabled_cause", - "type", - this.hass.localize( - `ui.panel.config.devices.type.${device.entry_type || "device"}` - ), - "cause", - this.hass.localize( - `ui.panel.config.devices.disabled_by.${device.disabled_by}` - ) - )} - - ${device.disabled_by === "user" - ? html` -
    - - ${this.hass.localize("ui.common.enable")} - -
    - ` - : ""} - ` - ); + deviceInfo.push(html` + + ${this.hass.localize( + "ui.panel.config.devices.enabled_cause", + "type", + this.hass.localize( + `ui.panel.config.devices.type.${device.entry_type || "device"}` + ), + "cause", + this.hass.localize( + `ui.panel.config.devices.disabled_by.${device.disabled_by}` + ) + )} + + ${device.disabled_by === "user" + ? html` +
    + + ${this.hass.localize("ui.common.enable")} + +
    + ` + : ""} + `); } this._renderIntegrationInfo(device, integrations, deviceInfo); @@ -751,12 +758,11 @@ export class HaConfigDevicePage extends LitElement { ? html`
    ${this._deviceAlerts.map( - (alert) => - html` - - ${alert.text} - - ` + (alert) => html` + + ${alert.text} + + ` )}
    ` @@ -880,24 +886,25 @@ export class HaConfigDevicePage extends LitElement { ${!this.narrow ? [automationCard, sceneCard, scriptCard] : ""}
    - ${(["control", "sensor", "config", "diagnostic"] as const).map( - (category) => - // Make sure we render controls if no other cards will be rendered - entitiesByCategory[category].length > 0 || - (entities.length === 0 && category === "control") - ? html` - - - ` - : "" + ${( + ["control", "sensor", "event", "config", "diagnostic"] as const + ).map((category) => + // Make sure we render controls if no other cards will be rendered + entitiesByCategory[category].length > 0 || + (entities.length === 0 && category === "control") + ? html` + + + ` + : "" )}

    ${batteryValidation.map( - (result) => - html` - - ` + (result) => html` + + ` )}

    diff --git a/src/panels/config/energy/components/ha-energy-device-settings.ts b/src/panels/config/energy/components/ha-energy-device-settings.ts index 52012f4106..dc2df5472f 100644 --- a/src/panels/config/energy/components/ha-energy-device-settings.ts +++ b/src/panels/config/energy/components/ha-energy-device-settings.ts @@ -68,13 +68,12 @@ export class EnergyDeviceSettings extends LitElement { >

    ${this.validationResult?.device_consumption.map( - (result) => - html` - - ` + (result) => html` + + ` )}

    ${this.hass.localize( diff --git a/src/panels/config/energy/components/ha-energy-gas-settings.ts b/src/panels/config/energy/components/ha-energy-gas-settings.ts index 14f6653f05..135d686ebc 100644 --- a/src/panels/config/energy/components/ha-energy-gas-settings.ts +++ b/src/panels/config/energy/components/ha-energy-gas-settings.ts @@ -74,13 +74,12 @@ export class EnergyGasSettings extends LitElement { >

    ${gasValidation.map( - (result) => - html` - - ` + (result) => html` + + ` )}

    ${this.hass.localize("ui.panel.config.energy.gas.gas_consumption")} diff --git a/src/panels/config/energy/components/ha-energy-solar-settings.ts b/src/panels/config/energy/components/ha-energy-solar-settings.ts index 4fe65f0188..ccc7e492e7 100644 --- a/src/panels/config/energy/components/ha-energy-solar-settings.ts +++ b/src/panels/config/energy/components/ha-energy-solar-settings.ts @@ -79,13 +79,12 @@ export class EnergySolarSettings extends LitElement { >

    ${solarValidation.map( - (result) => - html` - - ` + (result) => html` + + ` )}

    diff --git a/src/panels/config/energy/components/ha-energy-water-settings.ts b/src/panels/config/energy/components/ha-energy-water-settings.ts index a997629695..278b3f747e 100644 --- a/src/panels/config/energy/components/ha-energy-water-settings.ts +++ b/src/panels/config/energy/components/ha-energy-water-settings.ts @@ -75,13 +75,12 @@ export class EnergyWaterSettings extends LitElement { >

    ${waterValidation.map( - (result) => - html` - - ` + (result) => html` + + ` )}

    ${this.hass.localize( diff --git a/src/panels/config/energy/dialogs/dialog-energy-solar-settings.ts b/src/panels/config/energy/dialogs/dialog-energy-solar-settings.ts index 2cc14377b5..dd05a30612 100644 --- a/src/panels/config/energy/dialogs/dialog-energy-solar-settings.ts +++ b/src/panels/config/energy/dialogs/dialog-energy-solar-settings.ts @@ -139,31 +139,32 @@ export class DialogEnergySolarSettings ${this._forecast ? html`
    ${this._configEntries?.map( - (entry) => html` + html` + ${entry.title} +
    `} > - ${entry.title} -

    `} - > - - - ` + + + ` )} ${this.hass.localize( diff --git a/src/panels/config/entities/editor-tabs/settings/entity-settings-helper-tab.ts b/src/panels/config/entities/editor-tabs/settings/entity-settings-helper-tab.ts index 26ba5b9639..dd42f8b34e 100644 --- a/src/panels/config/entities/editor-tabs/settings/entity-settings-helper-tab.ts +++ b/src/panels/config/entities/editor-tabs/settings/entity-settings-helper-tab.ts @@ -16,7 +16,6 @@ import { } from "../../../../../data/entity_registry"; import { HELPERS_CRUD } from "../../../../../data/helpers_crud"; import { showConfirmationDialog } from "../../../../../dialogs/generic/show-dialog-box"; -import { hideMoreInfoDialog } from "../../../../../dialogs/more-info/show-ha-more-info-dialog"; import { haStyle } from "../../../../../resources/styles"; import type { HomeAssistant } from "../../../../../types"; import type { Helper } from "../../../helpers/const"; @@ -151,7 +150,7 @@ export class EntityRegistrySettingsHelper extends LitElement { } const result = await this._registryEditor!.updateEntry(); if (result.close) { - hideMoreInfoDialog(this); + fireEvent(this, "close-dialog"); } } catch (err: any) { this._error = err.message || "Unknown error"; diff --git a/src/panels/config/entities/entity-registry-settings-editor.ts b/src/panels/config/entities/entity-registry-settings-editor.ts index 699fd8933a..940ea5de59 100644 --- a/src/panels/config/entities/entity-registry-settings-editor.ts +++ b/src/panels/config/entities/entity-registry-settings-editor.ts @@ -687,6 +687,10 @@ export class EntityRegistrySettingsEditor extends LitElement { required @input=${this._entityIdChanged} iconTrailing + autocapitalize="none" + autocomplete="off" + autocorrect="off" + input-spellcheck="false" > - html` - ${name}
    -
    - ${entity.entity_id} | - ${this.hass.localize(`component.${entity.platform}.title`) || - entity.platform} -
    - ` + ? (name, entity: EntityRow) => html` + ${name}
    +
    + ${entity.entity_id} | + ${this.hass.localize(`component.${entity.platform}.title`) || + entity.platform} +
    + ` : undefined, }, entity_id: { @@ -487,11 +483,6 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) { ]; } - public disconnectedCallback() { - super.disconnectedCallback(); - hideMoreInfoDialog(this); - } - protected render() { if (!this.hass || this._entities === undefined) { return html` `; diff --git a/src/panels/config/ha-panel-config.ts b/src/panels/config/ha-panel-config.ts index 7004f32a5f..2db32736be 100644 --- a/src/panels/config/ha-panel-config.ts +++ b/src/panels/config/ha-panel-config.ts @@ -574,6 +574,7 @@ class HaPanelConfig extends SubscribeMixin(HassRouterPage) { protected firstUpdated(changedProps: PropertyValues) { super.firstUpdated(changedProps); this.hass.loadBackendTranslation("title"); + this.hass.loadBackendTranslation("services"); if (isComponentLoaded(this.hass, "cloud")) { this._updateCloudStatus(); this.addEventListener("connection-status", (ev) => { diff --git a/src/panels/config/hardware/dialog-hardware-available.ts b/src/panels/config/hardware/dialog-hardware-available.ts index d60d801b19..817ee0db12 100644 --- a/src/panels/config/hardware/dialog-hardware-available.ts +++ b/src/panels/config/hardware/dialog-hardware-available.ts @@ -110,51 +110,50 @@ class DialogHardwareAvailable extends LitElement implements HassDialog {
    ${devices.map( - (device) => - html` - -
    - - ${this.hass.localize( - "ui.panel.config.hardware.available_hardware.subsystem" - )}: - - ${device.subsystem} -
    -
    - - ${this.hass.localize( - "ui.panel.config.hardware.available_hardware.device_path" - )}: - - ${device.dev_path} -
    - ${device.by_id - ? html` -
    - - ${this.hass.localize( - "ui.panel.config.hardware.available_hardware.id" - )}: - - ${device.by_id} -
    - ` - : ""} -
    - - ${this.hass.localize( - "ui.panel.config.hardware.available_hardware.attributes" - )}: - -
    ${dump(device.attributes, { indent: 2 })}
    -
    -
    - ` + (device) => html` + +
    + + ${this.hass.localize( + "ui.panel.config.hardware.available_hardware.subsystem" + )}: + + ${device.subsystem} +
    +
    + + ${this.hass.localize( + "ui.panel.config.hardware.available_hardware.device_path" + )}: + + ${device.dev_path} +
    + ${device.by_id + ? html` +
    + + ${this.hass.localize( + "ui.panel.config.hardware.available_hardware.id" + )}: + + ${device.by_id} +
    + ` + : ""} +
    + + ${this.hass.localize( + "ui.panel.config.hardware.available_hardware.attributes" + )}: + +
    ${dump(device.attributes, { indent: 2 })}
    +
    +
    + ` )} `; diff --git a/src/panels/config/helpers/forms/ha-counter-form.ts b/src/panels/config/helpers/forms/ha-counter-form.ts index 92c844af88..c2b03630ab 100644 --- a/src/panels/config/helpers/forms/ha-counter-form.ts +++ b/src/panels/config/helpers/forms/ha-counter-form.ts @@ -53,10 +53,11 @@ class HaCounterForm extends LitElement { } public focus() { - this.updateComplete.then(() => - ( - this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement - )?.focus() + this.updateComplete.then( + () => + ( + this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement + )?.focus() ); } diff --git a/src/panels/config/helpers/forms/ha-input_boolean-form.ts b/src/panels/config/helpers/forms/ha-input_boolean-form.ts index 82912b4552..870d83cf22 100644 --- a/src/panels/config/helpers/forms/ha-input_boolean-form.ts +++ b/src/panels/config/helpers/forms/ha-input_boolean-form.ts @@ -31,10 +31,11 @@ class HaInputBooleanForm extends LitElement { } public focus() { - this.updateComplete.then(() => - ( - this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement - )?.focus() + this.updateComplete.then( + () => + ( + this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement + )?.focus() ); } diff --git a/src/panels/config/helpers/forms/ha-input_button-form.ts b/src/panels/config/helpers/forms/ha-input_button-form.ts index a67b65d5d3..0b8ec14ede 100644 --- a/src/panels/config/helpers/forms/ha-input_button-form.ts +++ b/src/panels/config/helpers/forms/ha-input_button-form.ts @@ -31,10 +31,11 @@ class HaInputButtonForm extends LitElement { } public focus() { - this.updateComplete.then(() => - ( - this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement - )?.focus() + this.updateComplete.then( + () => + ( + this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement + )?.focus() ); } diff --git a/src/panels/config/helpers/forms/ha-input_datetime-form.ts b/src/panels/config/helpers/forms/ha-input_datetime-form.ts index 61e70d735a..c44fe057c8 100644 --- a/src/panels/config/helpers/forms/ha-input_datetime-form.ts +++ b/src/panels/config/helpers/forms/ha-input_datetime-form.ts @@ -45,10 +45,11 @@ class HaInputDateTimeForm extends LitElement { } public focus() { - this.updateComplete.then(() => - ( - this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement - )?.focus() + this.updateComplete.then( + () => + ( + this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement + )?.focus() ); } diff --git a/src/panels/config/helpers/forms/ha-input_number-form.ts b/src/panels/config/helpers/forms/ha-input_number-form.ts index f090713f72..0c83b7861c 100644 --- a/src/panels/config/helpers/forms/ha-input_number-form.ts +++ b/src/panels/config/helpers/forms/ha-input_number-form.ts @@ -60,10 +60,11 @@ class HaInputNumberForm extends LitElement { } public focus() { - this.updateComplete.then(() => - ( - this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement - )?.focus() + this.updateComplete.then( + () => + ( + this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement + )?.focus() ); } diff --git a/src/panels/config/helpers/forms/ha-input_select-form.ts b/src/panels/config/helpers/forms/ha-input_select-form.ts index 378c6aa179..55217382bd 100644 --- a/src/panels/config/helpers/forms/ha-input_select-form.ts +++ b/src/panels/config/helpers/forms/ha-input_select-form.ts @@ -43,10 +43,11 @@ class HaInputSelectForm extends LitElement { } public focus() { - this.updateComplete.then(() => - ( - this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement - )?.focus() + this.updateComplete.then( + () => + ( + this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement + )?.focus() ); } diff --git a/src/panels/config/helpers/forms/ha-input_text-form.ts b/src/panels/config/helpers/forms/ha-input_text-form.ts index d8ba12b444..90252e2ab0 100644 --- a/src/panels/config/helpers/forms/ha-input_text-form.ts +++ b/src/panels/config/helpers/forms/ha-input_text-form.ts @@ -50,10 +50,11 @@ class HaInputTextForm extends LitElement { } public focus() { - this.updateComplete.then(() => - ( - this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement - )?.focus() + this.updateComplete.then( + () => + ( + this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement + )?.focus() ); } diff --git a/src/panels/config/helpers/forms/ha-schedule-form.ts b/src/panels/config/helpers/forms/ha-schedule-form.ts index 1656fafb00..5a503eef1b 100644 --- a/src/panels/config/helpers/forms/ha-schedule-form.ts +++ b/src/panels/config/helpers/forms/ha-schedule-form.ts @@ -98,10 +98,11 @@ class HaScheduleForm extends LitElement { } public focus() { - this.updateComplete.then(() => - ( - this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement - )?.focus() + this.updateComplete.then( + () => + ( + this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement + )?.focus() ); } diff --git a/src/panels/config/helpers/forms/ha-timer-form.ts b/src/panels/config/helpers/forms/ha-timer-form.ts index 1d427ef7af..4108f7fa43 100644 --- a/src/panels/config/helpers/forms/ha-timer-form.ts +++ b/src/panels/config/helpers/forms/ha-timer-form.ts @@ -39,10 +39,11 @@ class HaTimerForm extends LitElement { } public focus() { - this.updateComplete.then(() => - ( - this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement - )?.focus() + this.updateComplete.then( + () => + ( + this.shadowRoot?.querySelector("[dialogInitialFocus]") as HTMLElement + )?.focus() ); } diff --git a/src/panels/config/helpers/ha-config-helpers.ts b/src/panels/config/helpers/ha-config-helpers.ts index 41d5f03441..55b9cb1bb7 100644 --- a/src/panels/config/helpers/ha-config-helpers.ts +++ b/src/panels/config/helpers/ha-config-helpers.ts @@ -96,13 +96,12 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) { filterable: true, grows: true, direction: "asc", - template: (name, item: any) => - html` - ${name} - ${narrow - ? html`
    ${item.entity_id}
    ` - : ""} - `, + template: (name, item: any) => html` + ${name} + ${narrow + ? html`
    ${item.entity_id}
    ` + : ""} + `, }, }; if (!narrow) { diff --git a/src/panels/config/integrations/dialog-add-integration.ts b/src/panels/config/integrations/dialog-add-integration.ts index 02935336c0..eed4036670 100644 --- a/src/panels/config/integrations/dialog-add-integration.ts +++ b/src/panels/config/integrations/dialog-add-integration.ts @@ -443,6 +443,7 @@ class AddIntegrationDialog extends LitElement { })} @click=${this._integrationPicked} .items=${integrations} + .keyFunction=${this._keyFunction} .renderItem=${this._renderRow} > @@ -450,6 +451,9 @@ class AddIntegrationDialog extends LitElement { : html``} `; } + private _keyFunction = (integration: IntegrationListItem) => + integration.domain; + private _renderRow = (integration: IntegrationListItem) => { if (!integration) { return nothing; diff --git a/src/panels/config/integrations/ha-config-integration-page.ts b/src/panels/config/integrations/ha-config-integration-page.ts index 45292826bc..6ec67086f8 100644 --- a/src/panels/config/integrations/ha-config-integration-page.ts +++ b/src/panels/config/integrations/ha-config-integration-page.ts @@ -135,6 +135,13 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) { window.location.hash.substring(1) ); + private _configPanel = memoizeOne( + (domain: string, panels: HomeAssistant["panels"]): string | undefined => + Object.values(panels).find( + (panel) => panel.config_panel_domain === domain + )?.url_path || integrationsWithPanel[domain] + ); + private _domainConfigEntries = memoizeOne( (domain: string, configEntries?: ConfigEntry[]): ConfigEntry[] => configEntries @@ -410,22 +417,23 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) { ${discoveryFlows.map( - (flow) => html` - ${flow.localized_title} - - ` + (flow) => + html` + ${flow.localized_title} + + ` )} ` @@ -619,7 +627,11 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) { } if (devicesLine.length === 0) { - devicesLine = ["No devices or entities"]; + devicesLine = [ + this.hass.localize( + "ui.panel.config.integrations.config_entry.no_devices_or_entities" + ), + ]; } else if (devicesLine.length === 2) { devicesLine = [ devicesLine[0], @@ -637,6 +649,8 @@ class HaConfigIntegrationPage extends SubscribeMixin(LitElement) { } } + const configPanel = this._configPanel(item.domain, this.hass.panels); + return html` ${this.hass.localize("ui.common.enable")} ` - : item.domain in integrationsWithPanel && + : configPanel && (item.domain !== "matter" || isDevVersion(this.hass.config.version)) ? html` ${this.hass.localize( "ui.panel.config.integrations.config_entry.configure" diff --git a/src/panels/config/integrations/ha-config-integrations-dashboard.ts b/src/panels/config/integrations/ha-config-integrations-dashboard.ts index 969c44bbbf..77e7ab18fd 100644 --- a/src/panels/config/integrations/ha-config-integrations-dashboard.ts +++ b/src/panels/config/integrations/ha-config-integrations-dashboard.ts @@ -150,7 +150,7 @@ class HaConfigIntegrationsDashboard extends SubscribeMixin(LitElement) { ): [ [string, ConfigEntryExtended[]][], ConfigEntryExtended[], - ConfigEntryExtended[] + ConfigEntryExtended[], ] => { let filteredConfigEntries: ConfigEntryExtended[]; const ignored: ConfigEntryExtended[] = []; @@ -383,16 +383,20 @@ class HaConfigIntegrationsDashboard extends SubscribeMixin(LitElement) { )}
    - ${ignoredConfigEntries.map( - (entry: ConfigEntryExtended) => html` - - ` - )} + ${ignoredConfigEntries.length > 0 + ? ignoredConfigEntries.map( + (entry: ConfigEntryExtended) => html` + + ` + ) + : html`${this.hass.localize( + "ui.panel.config.integrations.no_ignored_integrations" + )}`}
    ` : ""} ${configEntriesInProgress.length @@ -417,18 +421,29 @@ class HaConfigIntegrationsDashboard extends SubscribeMixin(LitElement) { ${this.hass.localize("ui.panel.config.integrations.disabled")}
    - ${disabledConfigEntries.map( - (entry: ConfigEntryExtended) => html` - - ` - )} + ${disabledConfigEntries.length > 0 + ? disabledConfigEntries.map( + (entry: ConfigEntryExtended) => html` + + ` + ) + : html`${this.hass.localize( + "ui.panel.config.integrations.no_disabled_integrations" + )}`}
    ` : ""} + ${configEntriesInProgress.length || + this._showDisabled || + this._showIgnored + ? html`

    + ${this.hass.localize("ui.panel.config.integrations.configured")} +

    ` + : ""}
    ${integrations.length ? integrations.map( diff --git a/src/panels/config/integrations/ha-domain-integrations.ts b/src/panels/config/integrations/ha-domain-integrations.ts index 0a96aa0856..ed4fc8c160 100644 --- a/src/panels/config/integrations/ha-domain-integrations.ts +++ b/src/panels/config/integrations/ha-domain-integrations.ts @@ -44,29 +44,30 @@ class HaDomainIntegrations extends LitElement { ${this.hass.localize("ui.panel.config.integrations.discovered")} ${this.flowsInProgress.map( - (flow) => html` - - ${localizeConfigFlowTitle(this.hass.localize, flow)} + html` - - ` + + ${localizeConfigFlowTitle(this.hass.localize, flow)} + + ` )}
  • ${this.integration && diff --git a/src/panels/config/integrations/integration-panels/thread/thread-config-panel.ts b/src/panels/config/integrations/integration-panels/thread/thread-config-panel.ts index 27defda51a..2fdea52d73 100644 --- a/src/panels/config/integrations/integration-panels/thread/thread-config-panel.ts +++ b/src/panels/config/integrations/integration-panels/thread/thread-config-panel.ts @@ -20,6 +20,7 @@ import { OTBRCreateNetwork, OTBRGetExtendedAddress, OTBRInfo, + OTBRSetChannel, OTBRSetNetwork, } from "../../../../../data/otbr"; import { @@ -200,6 +201,10 @@ export class ThreadConfigPanel extends SubscribeMixin(LitElement) { >${this.hass.localize( "ui.panel.config.thread.reset_border_router" )}${this.hass.localize( + "ui.panel.config.thread.change_channel" + )}${network.dataset?.preferred ? "" : html` 26) { + showAlertDialog(this, { + title: this.hass.localize( + "ui.panel.config.thread.change_channel_invalid" + ), + text: this.hass.localize("ui.panel.config.thread.change_channel_range"), + }); + return; + } + try { + const result = await OTBRSetChannel(this.hass, channel); + showAlertDialog(this, { + title: this.hass.localize( + "ui.panel.config.thread.change_channel_initiated_title" + ), + text: this.hass.localize( + "ui.panel.config.thread.change_channel_initiated_text", + { delay: Math.floor(result.delay / 60) } + ), + }); + } catch (err: any) { + if (err.code === "multiprotocol_enabled") { + showAlertDialog(this, { + title: this.hass.localize( + "ui.panel.config.thread.change_channel_multiprotocol_enabled_title" + ), + text: this.hass.localize( + "ui.panel.config.thread.change_channel_multiprotocol_enabled_text" + ), + }); + return; + } + showAlertDialog(this, { + title: "Error", + text: err.message || err, + }); + } + this._refresh(); + } + static styles = [ haStyle, css` diff --git a/src/panels/config/integrations/integration-panels/zha/dialog-zha-change-channel.ts b/src/panels/config/integrations/integration-panels/zha/dialog-zha-change-channel.ts index ab3f5b77d4..13e4bc0d46 100644 --- a/src/panels/config/integrations/integration-panels/zha/dialog-zha-change-channel.ts +++ b/src/panels/config/integrations/integration-panels/zha/dialog-zha-change-channel.ts @@ -45,7 +45,7 @@ class DialogZHAChangeChannel extends LitElement implements HassDialog { public async showDialog(params: ZHAChangeChannelDialogParams): Promise { this._params = params; - this._newChannel = params.currentChannel; + this._newChannel = "auto"; } public closeDialog(): void { diff --git a/src/panels/config/integrations/integration-panels/zha/zha-add-devices-page.ts b/src/panels/config/integrations/integration-panels/zha/zha-add-devices-page.ts index 31d30b88fd..f75b9607bb 100644 --- a/src/panels/config/integrations/integration-panels/zha/zha-add-devices-page.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-add-devices-page.ts @@ -10,7 +10,6 @@ import { } from "lit"; import { customElement, property, state } from "lit/decorators"; import "../../../../../components/ha-circular-progress"; -import "../../../../../components/ha-service-description"; import { DEVICE_MESSAGE_TYPES, LOG_OUTPUT, @@ -259,12 +258,6 @@ class ZHAAddDevicesPage extends LitElement { right: 0; color: var(--primary-color); } - ha-service-description { - margin-top: 16px; - margin-left: 16px; - display: block; - color: grey; - } .search-button { margin-top: 16px; margin-left: 16px; diff --git a/src/panels/config/integrations/integration-panels/zha/zha-config-dashboard.ts b/src/panels/config/integrations/integration-panels/zha/zha-config-dashboard.ts index 6fe1e65f6b..13b2f85c66 100644 --- a/src/panels/config/integrations/integration-panels/zha/zha-config-dashboard.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-config-dashboard.ts @@ -223,25 +223,26 @@ class ZHAConfigDashboard extends LitElement { ${this._configuration ? Object.entries(this._configuration.schemas).map( - ([section, schema]) => html` -
    - -
    -
    ` + ([section, schema]) => + html` +
    + +
    +
    ` ) : ""} diff --git a/src/panels/config/integrations/integration-panels/zha/zha-device-card.ts b/src/panels/config/integrations/integration-panels/zha/zha-device-card.ts index 7bbc64fa67..5d4f476491 100644 --- a/src/panels/config/integrations/integration-panels/zha/zha-device-card.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-device-card.ts @@ -11,7 +11,6 @@ import "../../../../../components/buttons/ha-call-service-button"; import "../../../../../components/entity/state-badge"; import "../../../../../components/ha-area-picker"; import "../../../../../components/ha-card"; -import "../../../../../components/ha-service-description"; import { updateDeviceRegistryEntry } from "../../../../../data/device_registry"; import { EntityRegistryEntry, diff --git a/src/panels/config/integrations/integration-panels/zha/zha-device-pairing-status-card.ts b/src/panels/config/integrations/integration-panels/zha/zha-device-pairing-status-card.ts index 42768533ce..c4a8668ebd 100644 --- a/src/panels/config/integrations/integration-panels/zha/zha-device-pairing-status-card.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-device-pairing-status-card.ts @@ -6,7 +6,6 @@ import "../../../../../components/buttons/ha-call-service-button"; import "../../../../../components/entity/state-badge"; import "../../../../../components/ha-area-picker"; import "../../../../../components/ha-card"; -import "../../../../../components/ha-service-description"; import { CONFIGURED, INCOMPLETE_PAIRING_STATUSES, diff --git a/src/panels/config/integrations/integration-panels/zha/zha-groups-dashboard.ts b/src/panels/config/integrations/integration-panels/zha/zha-groups-dashboard.ts index 0b756fe41d..b57fbcf6ea 100644 --- a/src/panels/config/integrations/integration-panels/zha/zha-groups-dashboard.ts +++ b/src/panels/config/integrations/integration-panels/zha/zha-groups-dashboard.ts @@ -94,8 +94,9 @@ export class ZHAGroupsDashboard extends LitElement { title: this.hass.localize("ui.panel.config.zha.groups.group_id"), type: "numeric", width: "15%", - template: (groupId: number) => - html` ${formatAsPaddedHex(groupId)} `, + template: (groupId: number) => html` + ${formatAsPaddedHex(groupId)} + `, sortable: true, }, members: { diff --git a/src/panels/config/integrations/integration-panels/zwave_js/dialog-zwave_js-add-node.ts b/src/panels/config/integrations/integration-panels/zwave_js/dialog-zwave_js-add-node.ts index d6a1b460a9..7ffc6554b2 100644 --- a/src/panels/config/integrations/integration-panels/zwave_js/dialog-zwave_js-add-node.ts +++ b/src/panels/config/integrations/integration-panels/zwave_js/dialog-zwave_js-add-node.ts @@ -228,27 +228,28 @@ class DialogZWaveJSAddNode extends LitElement { .sort() .reverse() .map( - (securityClass) => html`${this.hass.localize( - `ui.panel.config.zwave_js.security_classes.${SecurityClass[securityClass]}.title` - )} -
    - ${this.hass.localize( - `ui.panel.config.zwave_js.security_classes.${SecurityClass[securityClass]}.description` - )} -
    `} - > - + html`${this.hass.localize( + `ui.panel.config.zwave_js.security_classes.${SecurityClass[securityClass]}.title` + )} +
    + ${this.hass.localize( + `ui.panel.config.zwave_js.security_classes.${SecurityClass[securityClass]}.description` + )} +
    `} > -
    -
    ` + + + ` )}
    html`
    -

    - ${this.hass.localize( - "ui.panel.config.zwave_js.node_config.endpoint", - "endpoint", - endpoint - )} -

    - - ${configParamEntries - .sort(([_, paramA], [__, paramB]) => - paramA.property !== paramB.property - ? paramA.property - paramB.property - : paramA.property_key! - paramB.property_key! - ) - .map( - ([id, item]) => html` - ${this._generateConfigBox(id, item)} - ` + ([endpoint, configParamEntries]) => + html`
    +

    + ${this.hass.localize( + "ui.panel.config.zwave_js.node_config.endpoint", + "endpoint", + endpoint )} - -

    ` + + + ${configParamEntries + .sort(([_, paramA], [__, paramB]) => + paramA.property !== paramB.property + ? paramA.property - paramB.property + : paramA.property_key! - paramB.property_key! + ) + .map( + ([id, item]) => + html` + ${this._generateConfigBox(id, item)} + ` + )} + +
    ` )} diff --git a/src/panels/config/lovelace/dashboards/ha-config-lovelace-dashboards.ts b/src/panels/config/lovelace/dashboards/ha-config-lovelace-dashboards.ts index 3430181210..7af4aa2587 100644 --- a/src/panels/config/lovelace/dashboards/ha-config-lovelace-dashboards.ts +++ b/src/panels/config/lovelace/dashboards/ha-config-lovelace-dashboards.ts @@ -123,12 +123,11 @@ export class HaConfigLovelaceDashboards extends LitElement { sortable: true, filterable: true, width: "20%", - template: (mode) => - html` - ${this.hass.localize( - `ui.panel.config.lovelace.dashboards.conf_mode.${mode}` - ) || mode} - `, + template: (mode) => html` + ${this.hass.localize( + `ui.panel.config.lovelace.dashboards.conf_mode.${mode}` + ) || mode} + `, }; if (dashboards.some((dashboard) => dashboard.filename)) { columns.filename = { diff --git a/src/panels/config/lovelace/resources/ha-config-lovelace-resources.ts b/src/panels/config/lovelace/resources/ha-config-lovelace-resources.ts index 411d288fbe..1d9cc10c8c 100644 --- a/src/panels/config/lovelace/resources/ha-config-lovelace-resources.ts +++ b/src/panels/config/lovelace/resources/ha-config-lovelace-resources.ts @@ -58,12 +58,11 @@ export class HaConfigLovelaceRescources extends LitElement { sortable: true, filterable: true, width: "30%", - template: (type) => - html` - ${this.hass.localize( - `ui.panel.config.lovelace.resources.types.${type}` - ) || type} - `, + template: (type) => html` + ${this.hass.localize( + `ui.panel.config.lovelace.resources.types.${type}` + ) || type} + `, }, }) ); diff --git a/src/panels/config/network/dialog-ip-detail.ts b/src/panels/config/network/dialog-ip-detail.ts index 6d1d3e24a4..e998e9c059 100644 --- a/src/panels/config/network/dialog-ip-detail.ts +++ b/src/panels/config/network/dialog-ip-detail.ts @@ -41,20 +41,49 @@ class DialogIPDetail extends LitElement { @closed=${this.closeDialog} scrimClickAction escapeKeyAction - .heading=${createCloseHeading(this.hass, "IP Information")} + .heading=${createCloseHeading( + this.hass, + this.hass.localize("ui.dialogs.dialog-ip-detail.ip_information") + )} > ${ipv4 ? html`
    -

    IPv4

    +

    + ${this.hass.localize("ui.dialogs.dialog-ip-detail.ipv4")} +

    ${ipv4.address - ? html`
    IP Address: ${ipv4.address?.join(", ")}
    ` + ? html`
    + ${this.hass.localize( + "ui.dialogs.dialog-ip-detail.ip_address", + { address: ipv4.address?.join(", ") } + )} +
    ` + : ""} + ${ipv4.gateway + ? html`
    + ${this.hass.localize( + "ui.dialogs.dialog-ip-detail.gateway", + { gateway: ipv4.gateway } + )} +
    ` + : ""} + ${ipv4.method + ? html`
    + ${this.hass.localize( + "ui.dialogs.dialog-ip-detail.method", + { method: ipv4.method } + )} +
    ` : ""} - ${ipv4.gateway ? html`
    Gateway: ${ipv4.gateway}
    ` : ""} - ${ipv4.method ? html`
    Method: ${ipv4.method}
    ` : ""} ${ipv4.nameservers?.length ? html` -
    Name Servers: ${ipv4.nameservers?.join(", ")}
    +
    + ${this.hass.localize( + "ui.dialogs.dialog-ip-detail.nameservers", + { nameservers: ipv4.nameservers?.join(", ") } + )} +
    ` : ""}
    @@ -63,15 +92,41 @@ class DialogIPDetail extends LitElement { ${ipv6 ? html`
    -

    IPv6

    +

    + ${this.hass.localize("ui.dialogs.dialog-ip-detail.ipv6")} +

    ${ipv6.address - ? html`
    IP Address: ${ipv6.address?.join(", ")}
    ` + ? html`
    + ${this.hass.localize( + "ui.dialogs.dialog-ip-detail.ip_address", + { address: ipv6.address?.join(", ") } + )} +
    ` + : ""} + ${ipv6.gateway + ? html`
    + ${this.hass.localize( + "ui.dialogs.dialog-ip-detail.gateway", + { gateway: ipv6.gateway } + )} +
    ` + : ""} + ${ipv6.method + ? html`
    + ${this.hass.localize( + "ui.dialogs.dialog-ip-detail.method", + { method: ipv6.method } + )} +
    ` : ""} - ${ipv6.gateway ? html`
    Gateway: ${ipv6.gateway}
    ` : ""} - ${ipv6.method ? html`
    Method: ${ipv6.method}
    ` : ""} ${ipv6.nameservers?.length ? html` -
    Name Servers: ${ipv6.nameservers?.join(", ")}
    +
    + ${this.hass.localize( + "ui.dialogs.dialog-ip-detail.nameservers", + { nameservers: ipv6.nameservers?.join(", ") } + )} +
    ` : ""}
    diff --git a/src/panels/config/network/ha-config-network.ts b/src/panels/config/network/ha-config-network.ts index 0d799b281d..25952cd43e 100644 --- a/src/panels/config/network/ha-config-network.ts +++ b/src/panels/config/network/ha-config-network.ts @@ -40,7 +40,10 @@ class ConfigNetwork extends LitElement { } return html` - +
    ${this._error ? html` @@ -50,9 +53,9 @@ class ConfigNetwork extends LitElement { ` : ""}

    - Configure which network adapters integrations will use. Currently - this setting only affects multicast traffic. A restart is required - for these settings to apply. + ${this.hass.localize( + "ui.panel.config.network.network_adapter_info" + )}

    ap.ssid) .map( - (ap) => - html` - - ${ap.ssid} - - ${ap.mac} - - ${this.hass.localize( - "ui.panel.config.network.supervisor.signal_strength" - )}: - ${ap.signal} - - - ` + (ap) => html` + + ${ap.ssid} + + ${ap.mac} - + ${this.hass.localize( + "ui.panel.config.network.supervisor.signal_strength" + )}: + ${ap.signal} + + + ` )} ` @@ -254,7 +253,11 @@ export class HassioNetwork extends LitElement { .label=${"ui.common.menu"} .path=${mdiDotsVertical} > - IP Information + ${this.hass.localize( + "ui.panel.config.network.ip_information" + )}
    `; } diff --git a/src/panels/config/repairs/dialog-system-information.ts b/src/panels/config/repairs/dialog-system-information.ts index bc3b1e0181..c96ac4c574 100644 --- a/src/panels/config/repairs/dialog-system-information.ts +++ b/src/panels/config/repairs/dialog-system-information.ts @@ -305,13 +305,11 @@ class DialogSystemInformation extends LitElement { const sections: TemplateResult[] = []; if (!this._systemInfo) { - sections.push( - html` -
    - -
    - ` - ); + sections.push(html` +
    + +
    + `); } else { const domains = Object.keys(this._systemInfo).sort(sortKeys); for (const domain of domains) { @@ -371,24 +369,22 @@ class DialogSystemInformation extends LitElement { `); } if (domain !== "homeassistant") { - sections.push( - html` -
    - ` - ); + sections.push(html` +
    +

    ${domainToName(this.hass.localize, domain)}

    + ${!domainInfo.manage_url + ? "" + : html` + + + ${this.hass.localize( + "ui.panel.config.info.system_health.manage" + )} + + + `} +
    + `); } sections.push(html` diff --git a/src/panels/config/scene/ha-scene-dashboard.ts b/src/panels/config/scene/ha-scene-dashboard.ts index df9f6be040..3a7a7790b8 100644 --- a/src/panels/config/scene/ha-scene-dashboard.ts +++ b/src/panels/config/scene/ha-scene-dashboard.ts @@ -90,8 +90,9 @@ class HaSceneDashboard extends LitElement { "ui.panel.config.scene.picker.headers.state" ), type: "icon", - template: (_, scene) => - html` `, + template: (_, scene) => html` + + `, }, name: { title: this.hass.localize( @@ -151,50 +152,49 @@ class HaSceneDashboard extends LitElement { title: "", width: "72px", type: "overflow-menu", - template: (_: string, scene: any) => - html` - this._showInfo(scene), - }, - { - path: mdiPlay, - label: this.hass.localize( - "ui.panel.config.scene.picker.activate" - ), - action: () => this._activateScene(scene), - }, - { - divider: true, - }, - { - path: mdiContentDuplicate, - label: this.hass.localize( - "ui.panel.config.scene.picker.duplicate" - ), - action: () => this._duplicate(scene), - disabled: !scene.attributes.id, - }, - { - label: this.hass.localize( - "ui.panel.config.scene.picker.delete" - ), - path: mdiDelete, - action: () => this._deleteConfirm(scene), - warning: scene.attributes.id, - disabled: !scene.attributes.id, - }, - ]} - > - - `, + template: (_: string, scene: any) => html` + this._showInfo(scene), + }, + { + path: mdiPlay, + label: this.hass.localize( + "ui.panel.config.scene.picker.activate" + ), + action: () => this._activateScene(scene), + }, + { + divider: true, + }, + { + path: mdiContentDuplicate, + label: this.hass.localize( + "ui.panel.config.scene.picker.duplicate" + ), + action: () => this._duplicate(scene), + disabled: !scene.attributes.id, + }, + { + label: this.hass.localize( + "ui.panel.config.scene.picker.delete" + ), + path: mdiDelete, + action: () => this._deleteConfirm(scene), + warning: scene.attributes.id, + disabled: !scene.attributes.id, + }, + ]} + > + + `, }; return columns; diff --git a/src/panels/config/scene/ha-scene-editor.ts b/src/panels/config/scene/ha-scene-editor.ts index 4a93bb65e7..ffb3b25c42 100644 --- a/src/panels/config/scene/ha-scene-editor.ts +++ b/src/panels/config/scene/ha-scene-editor.ts @@ -324,43 +324,42 @@ export class HaSceneEditor extends SubscribeMixin( ${devices.map( - (device) => - html` - -

    - ${device.name} - -

    - ${device.entities.map((entityId) => { - const entityStateObj = this.hass.states[entityId]; - if (!entityStateObj) { - return nothing; - } - return html` - - - - ${computeStateName(entityStateObj)} - - - `; - })} -
    - ` + (device) => html` + +

    + ${device.name} + +

    + ${device.entities.map((entityId) => { + const entityStateObj = this.hass.states[entityId]; + if (!entityStateObj) { + return nothing; + } + return html` + + + + ${computeStateName(entityStateObj)} + + + `; + })} +
    + ` )} - html` - this._showInfo(script), - }, - { - path: mdiPlay, - label: this.hass.localize("ui.panel.config.script.picker.run"), - action: () => this._runScript(script), - }, - { - path: mdiTransitConnection, - label: this.hass.localize( - "ui.panel.config.script.picker.show_trace" - ), - action: () => this._showTrace(script), - }, - { - divider: true, - }, - { - path: mdiContentDuplicate, - label: this.hass.localize( - "ui.panel.config.script.picker.duplicate" - ), - action: () => this._duplicate(script), - }, - { - label: this.hass.localize( - "ui.panel.config.script.picker.delete" - ), - path: mdiDelete, - action: () => this._deleteConfirm(script), - warning: true, - }, - ]} - > - - `, + template: (_: string, script: any) => html` + this._showInfo(script), + }, + { + path: mdiPlay, + label: this.hass.localize("ui.panel.config.script.picker.run"), + action: () => this._runScript(script), + }, + { + path: mdiTransitConnection, + label: this.hass.localize( + "ui.panel.config.script.picker.show_trace" + ), + action: () => this._showTrace(script), + }, + { + divider: true, + }, + { + path: mdiContentDuplicate, + label: this.hass.localize( + "ui.panel.config.script.picker.duplicate" + ), + action: () => this._duplicate(script), + }, + { + label: this.hass.localize("ui.panel.config.script.picker.delete"), + path: mdiDelete, + action: () => this._deleteConfirm(script), + warning: true, + }, + ]} + > + + `, }; return columns; diff --git a/src/panels/config/tags/ha-config-tags.ts b/src/panels/config/tags/ha-config-tags.ts index e566aff75d..61a61c8af7 100644 --- a/src/panels/config/tags/ha-config-tags.ts +++ b/src/panels/config/tags/ha-config-tags.ts @@ -70,18 +70,19 @@ export class HaConfigTags extends SubscribeMixin(LitElement) { sortable: true, filterable: true, grows: true, - template: (name, tag: any) => html`${name} - ${narrow - ? html`
    - ${tag.last_scanned_datetime - ? html`` - : this.hass.localize("ui.panel.config.tag.never_scanned")} -
    ` - : ""}`, + template: (name, tag: any) => + html`${name} + ${narrow + ? html`
    + ${tag.last_scanned_datetime + ? html`` + : this.hass.localize("ui.panel.config.tag.never_scanned")} +
    ` + : ""}`, }, }; if (!narrow) { @@ -106,33 +107,38 @@ export class HaConfigTags extends SubscribeMixin(LitElement) { title: "", label: this.hass.localize("ui.panel.config.tag.headers.write"), type: "icon-button", - template: (_write, tag: any) => html` `, + template: (_write, tag: any) => + html` `, }; } columns.automation = { title: "", type: "icon-button", - template: (_automation, tag: any) => html` `, + template: (_automation, tag: any) => + html` `, }; columns.edit = { title: "", type: "icon-button", - template: (_settings, tag: any) => html` `, + template: (_settings, tag: any) => + html` `, }; return columns; } diff --git a/src/panels/config/users/ha-config-users.ts b/src/panels/config/users/ha-config-users.ts index 54c949f7d7..a125ef8b81 100644 --- a/src/panels/config/users/ha-config-users.ts +++ b/src/panels/config/users/ha-config-users.ts @@ -77,8 +77,9 @@ export class HaConfigUsers extends LitElement { width: "20%", direction: "asc", hidden: narrow, - template: (groupIds: User["group_ids"]) => - html` ${localize(`groups.${groupIds[0]}`)} `, + template: (groupIds: User["group_ids"]) => html` + ${localize(`groups.${groupIds[0]}`)} + `, }, is_active: { title: this.hass.localize( diff --git a/src/panels/config/voice-assistants/debug/assist-render-pipeline-run.ts b/src/panels/config/voice-assistants/debug/assist-render-pipeline-run.ts index f30d5cf5d7..14da1d1e7d 100644 --- a/src/panels/config/voice-assistants/debug/assist-render-pipeline-run.ts +++ b/src/panels/config/voice-assistants/debug/assist-render-pipeline-run.ts @@ -101,13 +101,12 @@ const renderProgress = ( const renderData = (data: Record, keys: Record) => Object.entries(keys).map( - ([key, label]) => - html` -
    -
    ${label}
    -
    ${data[key]}
    -
    - ` + ([key, label]) => html` +
    +
    ${label}
    +
    ${data[key]}
    +
    + ` ); const dataMinusKeysRender = ( diff --git a/src/panels/config/voice-assistants/ha-config-voice-assistants-expose.ts b/src/panels/config/voice-assistants/ha-config-voice-assistants-expose.ts index 98363e9bed..e6f171f367 100644 --- a/src/panels/config/voice-assistants/ha-config-voice-assistants-expose.ts +++ b/src/panels/config/voice-assistants/ha-config-voice-assistants-expose.ts @@ -150,11 +150,10 @@ export class VoiceAssistantsExpose extends LitElement { filterable: true, direction: "asc", grows: true, - template: (name, entry) => - html` - ${name}
    -
    ${entry.entity_id}
    - `, + template: (name, entry) => html` + ${name}
    +
    ${entry.entity_id}
    + `, }, area: { title: this.hass.localize( diff --git a/src/panels/developer-tools/assist/developer-tools-assist.ts b/src/panels/developer-tools/assist/developer-tools-assist.ts index 9080e13394..32d5dcfcd6 100644 --- a/src/panels/developer-tools/assist/developer-tools-assist.ts +++ b/src/panels/developer-tools/assist/developer-tools-assist.ts @@ -1,3 +1,4 @@ +import { mdiDownload } from "@mdi/js"; import { dump } from "js-yaml"; import { CSSResultGroup, LitElement, css, html, nothing } from "lit"; import { customElement, property, query, state } from "lit/decorators"; @@ -16,6 +17,7 @@ import { haStyle } from "../../../resources/styles"; import { HomeAssistant } from "../../../types"; import { formatLanguageCode } from "../../../common/language/format_language"; import { storage } from "../../../common/decorators/storage"; +import { fileDownload } from "../../../util/file_download"; type SentenceParsingResult = { sentence: string; @@ -146,6 +148,16 @@ class HaPanelDevAssist extends SubscribeMixin(LitElement) {
    + ${this._results.length + ? html` +
    + + + Download Results + +
    + ` + : ""} ${this._results.map((r) => { const { sentence, result, language } = r; const matched = result != null; @@ -182,6 +194,15 @@ class HaPanelDevAssist extends SubscribeMixin(LitElement) { `; } + private _download() { + fileDownload( + `data:text/plain;charset=utf-8,${encodeURIComponent( + JSON.stringify({ results: this._results }, null, 2) + )}`, + `intent_results.json` + ); + } + static get styles(): CSSResultGroup { return [ haStyle, @@ -208,6 +229,10 @@ class HaPanelDevAssist extends SubscribeMixin(LitElement) { .form { margin-bottom: 16px; } + .result-toolbar { + text-align: center; + margin-bottom: 16px; + } .result { margin-bottom: 16px; } diff --git a/src/panels/developer-tools/event/event-subscribe-card.ts b/src/panels/developer-tools/event/event-subscribe-card.ts index d1d7afc0aa..d6fc035474 100644 --- a/src/panels/developer-tools/event/event-subscribe-card.ts +++ b/src/panels/developer-tools/event/event-subscribe-card.ts @@ -70,25 +70,24 @@ class EventSubscribeCard extends LitElement { ${repeat( this._events, (event) => event.id, - (event) => - html` -
    - ${this.hass!.localize( - "ui.panel.developer-tools.tabs.events.event_fired", - "name", - event.id - )} - ${formatTime( - new Date(event.event.time_fired), - this.hass!.locale, - this.hass!.config - )}: - -
    - ` + (event) => html` +
    + ${this.hass!.localize( + "ui.panel.developer-tools.tabs.events.event_fired", + "name", + event.id + )} + ${formatTime( + new Date(event.event.time_fired), + this.hass!.locale, + this.hass!.config + )}: + +
    + ` )} diff --git a/src/panels/developer-tools/service/developer-tools-service.ts b/src/panels/developer-tools/service/developer-tools-service.ts index 66da2d5f0e..8ffd198e78 100644 --- a/src/panels/developer-tools/service/developer-tools-service.ts +++ b/src/panels/developer-tools/service/developer-tools-service.ts @@ -58,6 +58,9 @@ class HaPanelDevService extends LitElement { protected firstUpdated(params) { super.firstUpdated(params); + this.hass.loadBackendTranslation("services"); + this.hass.loadBackendTranslation("selector"); + const serviceParam = extractSearchParam("service"); if (serviceParam) { this._serviceData = { @@ -66,8 +69,8 @@ class HaPanelDevService extends LitElement { data: {}, }; if (this._yamlMode) { - this.updateComplete.then(() => - this._yamlEditor?.setValue(this._serviceData) + this.updateComplete.then( + () => this._yamlEditor?.setValue(this._serviceData) ); } } else if (!this._serviceData?.service) { @@ -79,8 +82,8 @@ class HaPanelDevService extends LitElement { data: {}, }; if (this._yamlMode) { - this.updateComplete.then(() => - this._yamlEditor?.setValue(this._serviceData) + this.updateComplete.then( + () => this._yamlEditor?.setValue(this._serviceData) ); } } @@ -95,6 +98,14 @@ class HaPanelDevService extends LitElement { const isValid = this._isValid(this._serviceData, fields, target); + const domain = this._serviceData?.service + ? computeDomain(this._serviceData?.service) + : undefined; + + const serviceName = this._serviceData?.service + ? computeObjectId(this._serviceData?.service) + : undefined; + return html`

    @@ -248,11 +259,20 @@ class HaPanelDevService extends LitElement { ? fields : this._filterSelectorFields(fields) ).map( - (field) => html`

    - - - - ` + (field) => + html` + + + + ` )}
    ${field.key}
    ${field.description}${field.example}
    ${field.key}
    + ${this.hass.localize( + `component.${domain}.services.${serviceName}.fields.${field.key}.description` + ) || field.description} + + ${this.hass.localize( + `component.${domain}.services.${serviceName}.fields.${field.key}.example` + ) || field.example} +
    ${this._yamlMode @@ -429,6 +449,14 @@ class HaPanelDevService extends LitElement { this.hass.services, this._serviceData?.service ); + const domain = this._serviceData?.service + ? computeDomain(this._serviceData?.service) + : undefined; + + const serviceName = this._serviceData?.service + ? computeObjectId(this._serviceData?.service) + : undefined; + const example = {}; fields.forEach((field) => { if (field.example) { @@ -436,7 +464,10 @@ class HaPanelDevService extends LitElement { try { value = load(field.example); } catch (err: any) { - value = field.example; + value = + this.hass.localize( + `component.${domain}.services.${serviceName}.fields.${field.key}.example` + ) || field.example; } example[field.key] = value; } diff --git a/src/panels/developer-tools/state/developer-tools-state.js b/src/panels/developer-tools/state/developer-tools-state.js index 1fe00ee0fd..214473610f 100644 --- a/src/panels/developer-tools/state/developer-tools-state.js +++ b/src/panels/developer-tools/state/developer-tools-state.js @@ -202,7 +202,7 @@ class HaPanelDevState extends EventsMixin(LocalizeMixin(PolymerElement)) { autocapitalize="none" autocomplete="off" autocorrect="off" - spellcheck="false" + input-spellcheck="false" value="[[_state]]" on-change="stateChanged" class="state-input" diff --git a/src/panels/developer-tools/statistics/developer-tools-statistics.ts b/src/panels/developer-tools/statistics/developer-tools-statistics.ts index 6fb023fbb6..797acff710 100644 --- a/src/panels/developer-tools/statistics/developer-tools-statistics.ts +++ b/src/panels/developer-tools/statistics/developer-tools-statistics.ts @@ -162,6 +162,7 @@ class HaPanelDevStatistics extends SubscribeMixin(LitElement) { protected render() { return html` - html` -
  • - ${this.hass.localize( - "ui.panel.developer-tools.tabs.templates.domain" - )}: ${domain} -
  • - ` + (domain) => html` +
  • + ${this.hass.localize( + "ui.panel.developer-tools.tabs.templates.domain" + )}: ${domain} +
  • + ` )} ${this._templateResult.listeners.entities .sort() .map( - (entity_id) => - html` -
  • - ${this.hass.localize( - "ui.panel.developer-tools.tabs.templates.entity" - )}: ${entity_id} -
  • - ` + (entity_id) => html` +
  • + ${this.hass.localize( + "ui.panel.developer-tools.tabs.templates.entity" + )}: ${entity_id} +
  • + ` )} ` diff --git a/src/panels/developer-tools/yaml_configuration/developer-yaml-config.ts b/src/panels/developer-tools/yaml_configuration/developer-yaml-config.ts index 8b67a7e7a5..50bc2e2d60 100644 --- a/src/panels/developer-tools/yaml_configuration/developer-yaml-config.ts +++ b/src/panels/developer-tools/yaml_configuration/developer-yaml-config.ts @@ -142,24 +142,23 @@ export class DeveloperYamlConfig extends LitElement {
    ${this._reloadableDomains.map( - (domain) => - html` -
    - ${this.hass.localize( - `ui.panel.developer-tools.tabs.yaml.section.reloading.${domain}` - ) || - this.hass.localize( - "ui.panel.developer-tools.tabs.yaml.section.reloading.reload", - "domain", - domainToName(this.hass.localize, domain) - )} - -
    - ` + (domain) => html` +
    + ${this.hass.localize( + `ui.panel.developer-tools.tabs.yaml.section.reloading.${domain}` + ) || + this.hass.localize( + "ui.panel.developer-tools.tabs.yaml.section.reloading.reload", + "domain", + domainToName(this.hass.localize, domain) + )} + +
    + ` )}
    diff --git a/src/panels/lovelace/cards/energy/hui-energy-distribution-card.ts b/src/panels/lovelace/cards/energy/hui-energy-distribution-card.ts index 378f6e7a5f..e621bdea72 100644 --- a/src/panels/lovelace/cards/energy/hui-energy-distribution-card.ts +++ b/src/panels/lovelace/cards/energy/hui-energy-distribution-card.ts @@ -446,8 +446,8 @@ class HuiEnergyDistrubutionCard cy="40" r="38" stroke-dasharray="${homeSolarCircumference} ${ - CIRCLE_CIRCUMFERENCE - homeSolarCircumference - }" + CIRCLE_CIRCUMFERENCE - homeSolarCircumference + }" shape-rendering="geometricPrecision" stroke-dashoffset="-${ CIRCLE_CIRCUMFERENCE - homeSolarCircumference @@ -461,8 +461,8 @@ class HuiEnergyDistrubutionCard cy="40" r="38" stroke-dasharray="${homeBatteryCircumference} ${ - CIRCLE_CIRCUMFERENCE - homeBatteryCircumference - }" + CIRCLE_CIRCUMFERENCE - homeBatteryCircumference + }" stroke-dashoffset="-${ CIRCLE_CIRCUMFERENCE - homeBatteryCircumference - @@ -478,8 +478,8 @@ class HuiEnergyDistrubutionCard cy="40" r="38" stroke-dasharray="${homeLowCarbonCircumference} ${ - CIRCLE_CIRCUMFERENCE - homeLowCarbonCircumference - }" + CIRCLE_CIRCUMFERENCE - homeLowCarbonCircumference + }" stroke-dashoffset="-${ CIRCLE_CIRCUMFERENCE - homeLowCarbonCircumference - @@ -611,8 +611,8 @@ class HuiEnergyDistrubutionCard id="return" class="return" d="M${hasBattery ? 45 : 47},0 v15 c0,${ - hasBattery ? "35 -10,30 -30,30" : "40 -10,35 -30,35" - } h-20" + hasBattery ? "35 -10,30 -30,30" : "40 -10,35 -30,35" + } h-20" vector-effect="non-scaling-stroke" > ` : ""} @@ -621,8 +621,8 @@ class HuiEnergyDistrubutionCard id="solar" class="solar" d="M${hasBattery ? 55 : 53},0 v15 c0,${ - hasBattery ? "35 10,30 30,30" : "40 10,35 30,35" - } h20" + hasBattery ? "35 10,30 30,30" : "40 10,35 30,35" + } h20" vector-effect="non-scaling-stroke" >` : ""} @@ -1024,7 +1024,9 @@ class HuiEnergyDistrubutionCard } .circle svg circle { animation: rotate-in 0.6s ease-in; - transition: stroke-dashoffset 0.4s, stroke-dasharray 0.4s; + transition: + stroke-dashoffset 0.4s, + stroke-dasharray 0.4s; fill: none; } @keyframes rotate-in { diff --git a/src/panels/lovelace/cards/energy/hui-energy-sources-table-card.ts b/src/panels/lovelace/cards/energy/hui-energy-sources-table-card.ts index a6570a4485..734a4067ae 100644 --- a/src/panels/lovelace/cards/energy/hui-energy-sources-table-card.ts +++ b/src/panels/lovelace/cards/energy/hui-energy-sources-table-card.ts @@ -452,217 +452,220 @@ export class HuiEnergySourcesTableCard ` : ""} ${types.grid?.map( - (source) => html`${source.flow_from.map((flow, idx) => { - const energy = - calculateStatisticSumGrowth( - this._data!.stats[flow.stat_energy_from] - ) || 0; - totalGrid += energy; - - const compareEnergy = - (compare && + (source) => + html`${source.flow_from.map((flow, idx) => { + const energy = calculateStatisticSumGrowth( - this._data!.statsCompare[flow.stat_energy_from] - )) || - 0; - totalGridCompare += compareEnergy; + this._data!.stats[flow.stat_energy_from] + ) || 0; + totalGrid += energy; - const cost_stat = - flow.stat_cost || - this._data!.info.cost_sensors[flow.stat_energy_from]; - const cost = cost_stat - ? calculateStatisticSumGrowth( - this._data!.stats[cost_stat] - ) || 0 - : null; - if (cost !== null) { - totalGridCost += cost; - } + const compareEnergy = + (compare && + calculateStatisticSumGrowth( + this._data!.statsCompare[flow.stat_energy_from] + )) || + 0; + totalGridCompare += compareEnergy; - const costCompare = - compare && cost_stat + const cost_stat = + flow.stat_cost || + this._data!.info.cost_sensors[flow.stat_energy_from]; + const cost = cost_stat ? calculateStatisticSumGrowth( - this._data!.statsCompare[cost_stat] + this._data!.stats[cost_stat] ) || 0 : null; - if (costCompare !== null) { - totalGridCostCompare += costCompare; - } + if (cost !== null) { + totalGridCost += cost; + } - const modifiedColor = - idx > 0 - ? this.hass.themes.darkMode - ? labBrighten(rgb2lab(hex2rgb(consumptionColor)), idx) - : labDarken(rgb2lab(hex2rgb(consumptionColor)), idx) - : undefined; - const color = modifiedColor - ? rgb2hex(lab2rgb(modifiedColor)) - : consumptionColor; + const costCompare = + compare && cost_stat + ? calculateStatisticSumGrowth( + this._data!.statsCompare[cost_stat] + ) || 0 + : null; + if (costCompare !== null) { + totalGridCostCompare += costCompare; + } - return html` - -
    - - - ${getStatisticLabel( - this.hass, - flow.stat_energy_from, - this._data?.statsMetadata[flow.stat_energy_from] - )} - - ${compare - ? html` 0 + ? this.hass.themes.darkMode + ? labBrighten(rgb2lab(hex2rgb(consumptionColor)), idx) + : labDarken(rgb2lab(hex2rgb(consumptionColor)), idx) + : undefined; + const color = modifiedColor + ? rgb2hex(lab2rgb(modifiedColor)) + : consumptionColor; + + return html` + +
    + + + ${getStatisticLabel( + this.hass, + flow.stat_energy_from, + this._data?.statsMetadata[flow.stat_energy_from] + )} + + ${compare + ? html` + ${formatNumber(compareEnergy, this.hass.locale)} + kWh + + ${showCosts + ? html` + ${costCompare !== null + ? formatNumber( + costCompare, + this.hass.locale, + { + style: "currency", + currency: this.hass.config.currency!, + } + ) + : ""} + ` + : ""}` + : ""} + + ${formatNumber(energy, this.hass.locale)} kWh + + ${showCosts + ? html` - ${formatNumber(compareEnergy, this.hass.locale)} kWh - - ${showCosts - ? html` - ${costCompare !== null - ? formatNumber( - costCompare, - this.hass.locale, - { - style: "currency", - currency: this.hass.config.currency!, - } - ) - : ""} - ` - : ""}` - : ""} - - ${formatNumber(energy, this.hass.locale)} kWh - - ${showCosts - ? html` - ${cost !== null - ? formatNumber(cost, this.hass.locale, { - style: "currency", - currency: this.hass.config.currency!, - }) - : ""} - ` - : ""} - `; - })} - ${source.flow_to.map((flow, idx) => { - const energy = - (calculateStatisticSumGrowth( - this._data!.stats[flow.stat_energy_to] - ) || 0) * -1; - totalGrid += energy; - const cost_stat = - flow.stat_compensation || - this._data!.info.cost_sensors[flow.stat_energy_to]; - const cost = cost_stat - ? (calculateStatisticSumGrowth( - this._data!.stats[cost_stat] - ) || 0) * -1 - : null; - if (cost !== null) { - totalGridCost += cost; - } - - const energyCompare = - ((compare && - calculateStatisticSumGrowth( - this._data!.statsCompare[flow.stat_energy_to] - )) || - 0) * -1; - totalGridCompare += energyCompare; - - const costCompare = - compare && cost_stat + ${cost !== null + ? formatNumber(cost, this.hass.locale, { + style: "currency", + currency: this.hass.config.currency!, + }) + : ""} + ` + : ""} + `; + })} + ${source.flow_to.map((flow, idx) => { + const energy = + (calculateStatisticSumGrowth( + this._data!.stats[flow.stat_energy_to] + ) || 0) * -1; + totalGrid += energy; + const cost_stat = + flow.stat_compensation || + this._data!.info.cost_sensors[flow.stat_energy_to]; + const cost = cost_stat ? (calculateStatisticSumGrowth( - this._data!.statsCompare[cost_stat] + this._data!.stats[cost_stat] ) || 0) * -1 : null; - if (costCompare !== null) { - totalGridCostCompare += costCompare; - } + if (cost !== null) { + totalGridCost += cost; + } - const modifiedColor = - idx > 0 - ? this.hass.themes.darkMode - ? labBrighten(rgb2lab(hex2rgb(returnColor)), idx) - : labDarken(rgb2lab(hex2rgb(returnColor)), idx) - : undefined; - const color = modifiedColor - ? rgb2hex(lab2rgb(modifiedColor)) - : returnColor; + const energyCompare = + ((compare && + calculateStatisticSumGrowth( + this._data!.statsCompare[flow.stat_energy_to] + )) || + 0) * -1; + totalGridCompare += energyCompare; - return html` - -
    - - - ${getStatisticLabel( - this.hass, - flow.stat_energy_to, - this._data?.statsMetadata[flow.stat_energy_to] - )} - - ${compare - ? html` 0 + ? this.hass.themes.darkMode + ? labBrighten(rgb2lab(hex2rgb(returnColor)), idx) + : labDarken(rgb2lab(hex2rgb(returnColor)), idx) + : undefined; + const color = modifiedColor + ? rgb2hex(lab2rgb(modifiedColor)) + : returnColor; + + return html` + +
    + + + ${getStatisticLabel( + this.hass, + flow.stat_energy_to, + this._data?.statsMetadata[flow.stat_energy_to] + )} + + ${compare + ? html` + ${formatNumber(energyCompare, this.hass.locale)} + kWh + + ${showCosts + ? html` + ${costCompare !== null + ? formatNumber( + costCompare, + this.hass.locale, + { + style: "currency", + currency: this.hass.config.currency!, + } + ) + : ""} + ` + : ""}` + : ""} + + ${formatNumber(energy, this.hass.locale)} kWh + + ${showCosts + ? html` - ${formatNumber(energyCompare, this.hass.locale)} kWh - - ${showCosts - ? html` - ${costCompare !== null - ? formatNumber( - costCompare, - this.hass.locale, - { - style: "currency", - currency: this.hass.config.currency!, - } - ) - : ""} - ` - : ""}` - : ""} - - ${formatNumber(energy, this.hass.locale)} kWh - - ${showCosts - ? html` - ${cost !== null - ? formatNumber(cost, this.hass.locale, { - style: "currency", - currency: this.hass.config.currency!, - }) - : ""} - ` - : ""} - `; - })}` + ${cost !== null + ? formatNumber(cost, this.hass.locale, { + style: "currency", + currency: this.hass.config.currency!, + }) + : ""} + ` + : ""} + `; + })}` )} ${types.grid ? html` diff --git a/src/panels/lovelace/cards/hui-humidifier-card.ts b/src/panels/lovelace/cards/hui-humidifier-card.ts index 57e9ee8ee5..3aae9d2bf5 100644 --- a/src/panels/lovelace/cards/hui-humidifier-card.ts +++ b/src/panels/lovelace/cards/hui-humidifier-card.ts @@ -100,7 +100,7 @@ export class HuiHumidifierCard extends LitElement implements LovelaceCard { stateObj.attributes.humidity !== null && Number.isFinite(Number(stateObj.attributes.humidity)) ? stateObj.attributes.humidity - : stateObj.attributes.min_humidity; + : null; const setHumidity = this._setHum ? this._setHum : targetHumidity; @@ -111,6 +111,7 @@ export class HuiHumidifierCard extends LitElement implements LovelaceCard { : html` - ${guard([this._uncheckedItems, this._renderEmptySortable], () => - this._renderEmptySortable - ? "" - : this._renderItems(this._uncheckedItems!) + ${guard( + [this._uncheckedItems, this._renderEmptySortable], + () => + this._renderEmptySortable + ? "" + : this._renderItems(this._uncheckedItems!) )}
    ` @@ -178,23 +180,22 @@ class HuiShoppingListCard ${repeat( this._checkedItems!, (item) => item.id, - (item) => - html` -
    - - -
    - ` + (item) => html` +
    + + +
    + ` )} ` : ""} @@ -207,35 +208,34 @@ class HuiShoppingListCard ${repeat( items, (item) => item.id, - (item) => - html` -
    - - - ${this._reordering - ? html` - - - ` - : ""} -
    - ` + (item) => html` +
    + + + ${this._reordering + ? html` + + + ` + : ""} +
    + ` )} `; } diff --git a/src/panels/lovelace/cards/hui-tile-card.ts b/src/panels/lovelace/cards/hui-tile-card.ts index 3471b6348b..f9b10c65a9 100644 --- a/src/panels/lovelace/cards/hui-tile-card.ts +++ b/src/panels/lovelace/cards/hui-tile-card.ts @@ -453,7 +453,9 @@ export class HuiTileCard extends LitElement implements LovelaceCard { height: 100%; z-index: 0; overflow: hidden; - transition: box-shadow 180ms ease-in-out, border-color 180ms ease-in-out; + transition: + box-shadow 180ms ease-in-out, + border-color 180ms ease-in-out; } ha-card.active { --tile-color: var(--state-icon-color); diff --git a/src/panels/lovelace/cards/hui-weather-forecast-card.ts b/src/panels/lovelace/cards/hui-weather-forecast-card.ts index 85f29fc0a4..b5ee99fc86 100644 --- a/src/panels/lovelace/cards/hui-weather-forecast-card.ts +++ b/src/panels/lovelace/cards/hui-weather-forecast-card.ts @@ -20,11 +20,13 @@ import "../../../components/ha-svg-icon"; import { UNAVAILABLE } from "../../../data/entity"; import { ActionHandlerEvent } from "../../../data/lovelace"; import { + getForecast, getSecondaryWeatherAttribute, getWeatherStateIcon, getWeatherUnit, getWind, - isForecastHourly, + subscribeForecast, + ForecastEvent, weatherAttrIcons, WeatherEntity, weatherSVGStyles, @@ -41,8 +43,6 @@ import type { LovelaceCard, LovelaceCardEditor } from "../types"; import type { WeatherForecastCardConfig } from "./types"; import { formatDateWeekdayShort } from "../../../common/datetime/format_date"; -const DAY_IN_MILLISECONDS = 86400000; - @customElement("hui-weather-forecast-card") class HuiWeatherForecastCard extends LitElement implements LovelaceCard { public static async getConfigElement(): Promise { @@ -72,13 +72,54 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard { @state() private _config?: WeatherForecastCardConfig; + @state() private _forecastEvent?: ForecastEvent; + + @state() private _subscribed?: Promise<() => void>; + @property({ type: Boolean, reflect: true, attribute: "veryverynarrow" }) private _veryVeryNarrow = false; private _resizeObserver?: ResizeObserver; + private _needForecastSubscription() { + return ( + this._config!.forecast_type && this._config!.forecast_type !== "legacy" + ); + } + + private _unsubscribeForecastEvents() { + if (this._subscribed) { + this._subscribed.then((unsub) => unsub()); + this._subscribed = undefined; + } + } + + private async _subscribeForecastEvents() { + this._unsubscribeForecastEvents(); + if ( + !this.isConnected || + !this.hass || + !this._config || + !this._needForecastSubscription() + ) { + return; + } + + this._subscribed = subscribeForecast( + this.hass!, + this._config!.entity, + this._config!.forecast_type as "daily" | "hourly" | "twice_daily", + (event) => { + this._forecastEvent = event; + } + ); + } + public connectedCallback(): void { super.connectedCallback(); + if (this.hasUpdated && this._config && this.hass) { + this._subscribeForecastEvents(); + } this.updateComplete.then(() => this._attachObserver()); } @@ -86,6 +127,7 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard { if (this._resizeObserver) { this._resizeObserver.disconnect(); } + this._unsubscribeForecastEvents(); } public getCardSize(): number { @@ -111,7 +153,10 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard { } protected shouldUpdate(changedProps: PropertyValues): boolean { - return hasConfigOrEntityChanged(this, changedProps); + return ( + hasConfigOrEntityChanged(this, changedProps) || + changedProps.has("forecastEvent") + ); } public willUpdate(): void { @@ -130,6 +175,10 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard { return; } + if (changedProps.has("_config") || !this._subscribed) { + this._subscribeForecastEvents(); + } + const oldHass = changedProps.get("hass") as HomeAssistant | undefined; const oldConfig = changedProps.get("_config") as | WeatherForecastCardConfig @@ -172,23 +221,19 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard { `; } + const forecastData = getForecast( + stateObj.attributes, + this._forecastEvent, + this._config?.forecast_type + ); const forecast = - this._config?.show_forecast !== false && - stateObj.attributes.forecast?.length - ? stateObj.attributes.forecast.slice(0, this._veryVeryNarrow ? 3 : 5) + this._config?.show_forecast !== false && forecastData?.forecast?.length + ? forecastData.forecast.slice(0, this._veryVeryNarrow ? 3 : 5) : undefined; const weather = !forecast || this._config?.show_current !== false; - const hourly = isForecastHourly(forecast); - let dayNight: boolean | undefined; - - if (hourly) { - const dateFirst = new Date(forecast![0].datetime); - const datelast = new Date(forecast![forecast!.length - 1].datetime); - const dayDiff = datelast.getTime() - dateFirst.getTime(); - - dayNight = dayDiff > DAY_IN_MILLISECONDS; - } + const hourly = forecastData?.type === "hourly"; + const dayNight = forecastData?.type === "twice_daily"; const weatherStateIcon = getWeatherStateIcon(stateObj.state, this); const name = this._config.name ?? computeStateName(stateObj); @@ -285,7 +330,11 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard { )} `} ` - : getSecondaryWeatherAttribute(this.hass, stateObj)} + : getSecondaryWeatherAttribute( + this.hass, + stateObj, + forecast! + )} @@ -308,7 +357,7 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard { { weekday: "short" } )}
    - ${item.daytime === undefined || item.daytime + ${item.is_daytime !== false ? this.hass!.localize( "ui.card.weather.day" ) @@ -340,7 +389,8 @@ class HuiWeatherForecastCard extends LitElement implements LovelaceCard { item.condition!, this, !( - item.daytime || item.daytime === undefined + item.is_daytime || + item.is_daytime === undefined ) )}
    diff --git a/src/panels/lovelace/cards/types.ts b/src/panels/lovelace/cards/types.ts index 082b6c4b53..0a7c8ee412 100644 --- a/src/panels/lovelace/cards/types.ts +++ b/src/panels/lovelace/cards/types.ts @@ -12,6 +12,7 @@ import { import { LovelaceHeaderFooterConfig } from "../header-footer/types"; import { HaDurationData } from "../../../components/ha-duration-input"; import { LovelaceTileFeatureConfig } from "../tile-features/types"; +import { ForecastType } from "../../../data/weather"; export interface AlarmPanelCardConfig extends LovelaceCardConfig { entity: string; @@ -444,6 +445,7 @@ export interface WeatherForecastCardConfig extends LovelaceCardConfig { name?: string; show_current?: boolean; show_forecast?: boolean; + forecast_type?: ForecastType; secondary_info_attribute?: keyof TranslationDict["ui"]["card"]["weather"]["attributes"]; theme?: string; tap_action?: ActionConfig; diff --git a/src/panels/lovelace/common/directives/action-handler-directive.ts b/src/panels/lovelace/common/directives/action-handler-directive.ts index f7c5bc2d74..1d2b3c87a5 100644 --- a/src/panels/lovelace/common/directives/action-handler-directive.ts +++ b/src/panels/lovelace/common/directives/action-handler-directive.ts @@ -21,7 +21,7 @@ const isTouch = // @ts-ignore navigator.msMaxTouchPoints > 0; -interface ActionHandler extends HTMLElement { +interface ActionHandlerType extends HTMLElement { holdTime: number; bind(element: Element, options?: ActionHandlerOptions): void; } @@ -43,7 +43,7 @@ declare global { } } -class ActionHandler extends HTMLElement implements ActionHandler { +class ActionHandler extends HTMLElement implements ActionHandlerType { public holdTime = 500; public ripple: Ripple; @@ -240,23 +240,23 @@ class ActionHandler extends HTMLElement implements ActionHandler { customElements.define("action-handler", ActionHandler); -const getActionHandler = (): ActionHandler => { +const getActionHandler = (): ActionHandlerType => { const body = document.body; if (body.querySelector("action-handler")) { - return body.querySelector("action-handler") as ActionHandler; + return body.querySelector("action-handler") as ActionHandlerType; } const actionhandler = document.createElement("action-handler"); body.appendChild(actionhandler); - return actionhandler as ActionHandler; + return actionhandler as ActionHandlerType; }; export const actionHandlerBind = ( element: ActionHandlerElement, options?: ActionHandlerOptions ) => { - const actionhandler: ActionHandler = getActionHandler(); + const actionhandler: ActionHandlerType = getActionHandler(); if (!actionhandler) { return; } diff --git a/src/panels/lovelace/common/graph/coordinates.ts b/src/panels/lovelace/common/graph/coordinates.ts index b63c61af05..56f5251965 100644 --- a/src/panels/lovelace/common/graph/coordinates.ts +++ b/src/panels/lovelace/common/graph/coordinates.ts @@ -119,6 +119,9 @@ export const coordinatesMinimalResponseCompressedState = ( detail: number, limits?: { min?: number; max?: number } ): number[][] | undefined => { + if (!history) { + return undefined; + } const numericHistory: NumericEntityHistoryState[] = history.map((item) => ({ state: Number(item.s), // With minimal response and compressed state, we don't have last_changed, diff --git a/src/panels/lovelace/common/handle-action.ts b/src/panels/lovelace/common/handle-action.ts index 83deadf5db..bd849bd428 100644 --- a/src/panels/lovelace/common/handle-action.ts +++ b/src/panels/lovelace/common/handle-action.ts @@ -60,9 +60,12 @@ export const handleAction = async ( const [domain, service] = actionConfig.service.split(".", 2); const serviceDomains = hass.services; if (domain in serviceDomains && service in serviceDomains[domain]) { - const localize = await hass.loadBackendTranslation("title"); + await hass.loadBackendTranslation("title"); + const localize = await hass.loadBackendTranslation("services"); serviceName = `${domainToName(localize, domain)}: ${ - serviceDomains[domain][service].name || service + localize(`component.${domain}.services.${serviceName}.name`) || + serviceDomains[domain][service].name || + service }`; } } @@ -161,8 +164,8 @@ export const handleAction = async ( } case "assist": { showVoiceCommandDialog(node, hass, { - start_listening: actionConfig.start_listening, - pipeline_id: actionConfig.pipeline_id, + start_listening: actionConfig.start_listening ?? false, + pipeline_id: actionConfig.pipeline_id ?? "last_used", }); break; } diff --git a/src/panels/lovelace/common/process-config-entities.ts b/src/panels/lovelace/common/process-config-entities.ts index 1d4519ea5f..49ce41ad27 100644 --- a/src/panels/lovelace/common/process-config-entities.ts +++ b/src/panels/lovelace/common/process-config-entities.ts @@ -3,7 +3,7 @@ import { isValidEntityId } from "../../../common/entity/valid_entity_id"; import { EntityConfig, LovelaceRowConfig } from "../entity-rows/types"; export const processConfigEntities = < - T extends EntityConfig | LovelaceRowConfig + T extends EntityConfig | LovelaceRowConfig, >( entities: Array, checkEntityId = true diff --git a/src/panels/lovelace/components/hui-action-editor.ts b/src/panels/lovelace/components/hui-action-editor.ts index 20d5e0f597..6ae48d59f1 100644 --- a/src/panels/lovelace/components/hui-action-editor.ts +++ b/src/panels/lovelace/components/hui-action-editor.ts @@ -38,7 +38,9 @@ const ASSIST_SCHEMA = [ { name: "pipeline_id", selector: { - assist_pipeline: {}, + assist_pipeline: { + include_last_used: true, + }, }, }, { diff --git a/src/panels/lovelace/components/hui-card-options.ts b/src/panels/lovelace/components/hui-card-options.ts index ec04f21acd..7e3a567839 100644 --- a/src/panels/lovelace/components/hui-card-options.ts +++ b/src/panels/lovelace/components/hui-card-options.ts @@ -1,7 +1,15 @@ import "@material/mwc-button"; import { ActionDetail } from "@material/mwc-list/mwc-list-foundation"; -import "@material/mwc-list/mwc-list-item"; -import { mdiArrowDown, mdiArrowUp, mdiDotsVertical } from "@mdi/js"; +import { + mdiContentCopy, + mdiContentCut, + mdiContentDuplicate, + mdiDelete, + mdiDotsVertical, + mdiFileMoveOutline, + mdiMinus, + mdiPlus, +} from "@mdi/js"; import deepClone from "deep-clone-simple"; import { CSSResultGroup, @@ -17,11 +25,13 @@ import { storage } from "../../../common/decorators/storage"; import { fireEvent } from "../../../common/dom/fire_event"; import "../../../components/ha-button-menu"; import "../../../components/ha-icon-button"; +import "../../../components/ha-list-item"; import { LovelaceCardConfig, saveConfig } from "../../../data/lovelace"; import { showAlertDialog, showPromptDialog, } from "../../../dialogs/generic/show-dialog-box"; +import { haStyle } from "../../../resources/styles"; import { HomeAssistant } from "../../../types"; import { showSaveSuccessToast } from "../../../util/toast-saved-success"; import { computeCardSize } from "../common/compute-card-size"; @@ -86,14 +96,12 @@ export class HuiCardOptions extends LitElement { ? html` ` : nothing} @@ -122,31 +132,51 @@ export class HuiCardOptions extends LitElement { )} .path=${mdiDotsVertical} > - + + ${this.hass!.localize( "ui.panel.lovelace.editor.edit_card.move" - )} - ${this.hass!.localize( + )} +
    + + + ${this.hass!.localize( "ui.panel.lovelace.editor.edit_card.duplicate" - )} - ${this.hass!.localize( + )} + + + + ${this.hass!.localize( "ui.panel.lovelace.editor.edit_card.copy" - )} - ${this.hass!.localize( - "ui.panel.lovelace.editor.edit_card.cut" - )} - + )} + + + + ${this.hass!.localize("ui.panel.lovelace.editor.edit_card.cut")} + +
  • + + ${this.hass!.localize( "ui.panel.lovelace.editor.edit_card.delete" - )} + )} + @@ -155,65 +185,64 @@ export class HuiCardOptions extends LitElement { } static get styles(): CSSResultGroup { - return css` - :host(:hover) { - outline: 2px solid var(--primary-color); - } + return [ + haStyle, + css` + :host(:hover) { + outline: 2px solid var(--primary-color); + } - :host(:not(.panel)) ::slotted(*) { - display: block; - } + :host(:not(.panel)) ::slotted(*) { + display: block; + } - :host(.panel) .card { - height: calc(100% - 59px); - } + :host(.panel) .card { + height: calc(100% - 59px); + } - ha-card { - border-top-right-radius: 0; - border-top-left-radius: 0; - } + ha-card { + border-top-right-radius: 0; + border-top-left-radius: 0; + } - .card-actions { - display: flex; - justify-content: space-between; - align-items: center; - } + .card-actions { + display: flex; + justify-content: space-between; + align-items: center; + } - .right { - display: flex; - align-items: center; - } + .right { + display: flex; + align-items: center; + } - .position-badge { - display: block; - width: 24px; - line-height: 24px; - box-sizing: border-box; - border-radius: 50%; - font-weight: 500; - text-align: center; - font-size: 14px; - background-color: var(--app-header-edit-background-color, #455a64); - color: var(--app-header-edit-text-color, white); - } + .position-badge { + display: block; + width: 24px; + line-height: 24px; + box-sizing: border-box; + border-radius: 50%; + font-weight: 500; + text-align: center; + font-size: 14px; + background-color: var(--app-header-edit-background-color, #455a64); + color: var(--app-header-edit-text-color, white); + } - ha-icon-button { - color: var(--primary-text-color); - } + ha-icon-button { + color: var(--primary-text-color); + } - ha-icon-button.move-arrow[disabled] { - color: var(--disabled-text-color); - } + ha-icon-button.move-arrow[disabled] { + color: var(--disabled-text-color); + } - mwc-list-item { - cursor: pointer; - white-space: nowrap; - } - - mwc-list-item.delete-item { - color: var(--error-color); - } - `; + ha-list-item { + cursor: pointer; + white-space: nowrap; + } + `, + ]; } private _handleAction(ev: CustomEvent) { @@ -262,7 +291,7 @@ export class HuiCardOptions extends LitElement { this._clipboard = deepClone(cardConfig); } - private _cardUp(): void { + private _decreaseCardPosiion(): void { const lovelace = this.lovelace!; const path = this.path!; lovelace.saveConfig( @@ -270,7 +299,7 @@ export class HuiCardOptions extends LitElement { ); } - private _cardDown(): void { + private _increaseCardPosition(): void { const lovelace = this.lovelace!; const path = this.path!; lovelace.saveConfig( diff --git a/src/panels/lovelace/components/hui-energy-period-selector.ts b/src/panels/lovelace/components/hui-energy-period-selector.ts index 9cd6666cd3..dd923698ff 100644 --- a/src/panels/lovelace/components/hui-energy-period-selector.ts +++ b/src/panels/lovelace/components/hui-energy-period-selector.ts @@ -343,7 +343,9 @@ export class HuiEnergyPeriodSelector extends SubscribeMixin(LitElement) { opacity: 0; pointer-events: none; content: ""; - transition: opacity 15ms linear, background-color 15ms linear; + transition: + opacity 15ms linear, + background-color 15ms linear; opacity: var(--mdc-icon-button-ripple-opacity, 0.12); } ha-icon-button.active::before { diff --git a/src/panels/lovelace/create-element/create-element-base.ts b/src/panels/lovelace/create-element/create-element-base.ts index 792b8fd2e3..a92d49ba8b 100644 --- a/src/panels/lovelace/create-element/create-element-base.ts +++ b/src/panels/lovelace/create-element/create-element-base.ts @@ -185,7 +185,7 @@ export const createLovelaceElement = ( }; export const tryCreateLovelaceElement = < - T extends keyof CreateElementConfigTypes + T extends keyof CreateElementConfigTypes, >( tagSuffix: T, config: CreateElementConfigTypes[T]["config"], @@ -246,7 +246,7 @@ export const tryCreateLovelaceElement = < }; export const getLovelaceElementClass = async < - T extends keyof CreateElementConfigTypes + T extends keyof CreateElementConfigTypes, >( type: string, tagSuffix: T, diff --git a/src/panels/lovelace/create-element/create-row-element.ts b/src/panels/lovelace/create-element/create-row-element.ts index 620ddb4660..3c79dc1bf8 100644 --- a/src/panels/lovelace/create-element/create-row-element.ts +++ b/src/panels/lovelace/create-element/create-row-element.ts @@ -1,3 +1,4 @@ +import "../entity-rows/hui-event-entity-row"; import "../entity-rows/hui-media-player-entity-row"; import "../entity-rows/hui-scene-entity-row"; import "../entity-rows/hui-script-entity-row"; @@ -29,6 +30,7 @@ const LAZY_LOAD_TYPES = { "cover-entity": () => import("../entity-rows/hui-cover-entity-row"), "date-entity": () => import("../entity-rows/hui-date-entity-row"), "datetime-entity": () => import("../entity-rows/hui-datetime-entity-row"), + "event-entity": () => import("../entity-rows/hui-event-entity-row"), "group-entity": () => import("../entity-rows/hui-group-entity-row"), "input-button-entity": () => import("../entity-rows/hui-input-button-entity-row"), @@ -65,6 +67,7 @@ const DOMAIN_TO_ELEMENT_TYPE = { cover: "cover", date: "date", datetime: "datetime", + event: "event", fan: "toggle", group: "group", humidifier: "humidifier", diff --git a/src/panels/lovelace/editor/card-editor/hui-card-picker.ts b/src/panels/lovelace/editor/card-editor/hui-card-picker.ts index 415b89b993..500a6a12b9 100644 --- a/src/panels/lovelace/editor/card-editor/hui-card-picker.ts +++ b/src/panels/lovelace/editor/card-editor/hui-card-picker.ts @@ -123,7 +123,7 @@ export class HuiCardPicker extends LitElement { })} >
    - ${this._clipboard + ${this._clipboard && !this._filter ? html` ${until( this._renderCardElement( @@ -402,6 +402,9 @@ export class HuiCardPicker extends LitElement { background: var(--primary-background-color, #fafafa); cursor: pointer; position: relative; + overflow: hidden; + border: var(--ha-card-border-width, 1px) solid + var(--ha-card-border-color, var(--divider-color)); } .card-header { @@ -451,8 +454,6 @@ export class HuiCardPicker extends LitElement { height: 100%; z-index: 1; box-sizing: border-box; - border: var(--ha-card-border-width, 1px) solid - var(--ha-card-border-color, var(--divider-color)); border-radius: var(--ha-card-border-radius, 12px); } diff --git a/src/panels/lovelace/editor/config-elements/hui-conditional-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-conditional-card-editor.ts index b2c8566af6..b63913d45b 100644 --- a/src/panels/lovelace/editor/config-elements/hui-conditional-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-conditional-card-editor.ts @@ -1,7 +1,7 @@ import "@material/mwc-list/mwc-list-item"; import "@material/mwc-tab-bar/mwc-tab-bar"; import "@material/mwc-tab/mwc-tab"; -import { mdiContentCopy } from "@mdi/js"; +import { mdiCodeBraces, mdiContentCopy, mdiListBoxOutline } from "@mdi/js"; import deepClone from "deep-clone-simple"; import type { MDCTabBarActivatedEvent } from "@material/tab-bar"; import { css, CSSResultGroup, html, LitElement, nothing } from "lit"; @@ -92,6 +92,8 @@ export class HuiConditionalCardEditor return nothing; } + const isGuiMode = !this._cardEditorEl || this._GUImode; + return html` - - ${this.hass!.localize( - !this._cardEditorEl || this._GUImode + .label=${this.hass!.localize( + isGuiMode ? "ui.panel.lovelace.editor.edit_card.show_code_editor" : "ui.panel.lovelace.editor.edit_card.show_visual_editor" )} - + .path=${isGuiMode ? mdiCodeBraces : mdiListBoxOutline} + >
    @@ -114,17 +118,17 @@ export class HuiStackCardEditor ${selected < numcards ? html`
    - - ${this.hass!.localize( - !this._cardEditorEl || this._GUImode + .label=${this.hass!.localize( + isGuiMode ? "ui.panel.lovelace.editor.edit_card.show_code_editor" : "ui.panel.lovelace.editor.edit_card.show_visual_editor" )} - + .path=${isGuiMode ? mdiCodeBraces : mdiListBoxOutline} + > - this._metaDatas?.some((metaData) => - statisticsMetaHasType(metaData, stat_type) - ) + : stat_types.filter( + (stat_type) => + this._metaDatas?.some((metaData) => + statisticsMetaHasType(metaData, stat_type) + ) ); const data = { chart_type: "line", diff --git a/src/panels/lovelace/editor/config-elements/hui-weather-forecast-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-weather-forecast-card-editor.ts index 2be07c183b..a758959aeb 100644 --- a/src/panels/lovelace/editor/config-elements/hui-weather-forecast-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-weather-forecast-card-editor.ts @@ -7,12 +7,14 @@ import type { LocalizeFunc } from "../../../../common/translations/localize"; import "../../../../components/ha-form/ha-form"; import type { SchemaUnion } from "../../../../components/ha-form/types"; import { UNAVAILABLE } from "../../../../data/entity"; -import type { WeatherEntity } from "../../../../data/weather"; +import type { ForecastType, WeatherEntity } from "../../../../data/weather"; +import { WeatherEntityFeature } from "../../../../data/weather"; import type { HomeAssistant } from "../../../../types"; import type { WeatherForecastCardConfig } from "../../cards/types"; import type { LovelaceCardEditor } from "../../types"; import { actionConfigStruct } from "../structs/action-struct"; import { baseLovelaceCardConfig } from "../structs/base-card-struct"; +import { supportsFeature } from "../../../../common/entity/supports-feature"; const cardConfigStruct = assign( baseLovelaceCardConfig, @@ -22,6 +24,7 @@ const cardConfigStruct = assign( theme: optional(string()), show_current: optional(boolean()), show_forecast: optional(boolean()), + forecast_type: optional(string()), secondary_info_attribute: optional(string()), tap_action: optional(actionConfigStruct), hold_action: optional(actionConfigStruct), @@ -44,7 +47,7 @@ export class HuiWeatherForecastCardEditor if ( /* cannot show forecast in case it is unavailable on the entity */ - (config.show_forecast === true && this._has_forecast === false) || + (config.show_forecast === true && this._hasForecast === false) || /* cannot hide both weather and forecast, need one of them */ (config.show_current === false && config.show_forecast === false) ) { @@ -53,20 +56,72 @@ export class HuiWeatherForecastCardEditor config: { ...config, show_current: true, show_forecast: false }, }); } + if ( + !config.forecast_type || + !this._forecastSupported(config.forecast_type) + ) { + let forecastType: string | undefined; + if (this._forecastSupported("daily")) { + forecastType = "daily"; + } else if (this._forecastSupported("hourly")) { + forecastType = "hourly"; + } else if (this._forecastSupported("twice_daily")) { + forecastType = "twice_daily"; + } else if (this._forecastSupported("legacy")) { + forecastType = "legacy"; + } + fireEvent(this, "config-changed", { + config: { ...config, forecast_type: forecastType }, + }); + } } - get _has_forecast(): boolean | undefined { + private get _stateObj(): WeatherEntity | undefined { if (this.hass && this._config) { - const stateObj = this.hass.states[this._config.entity] as WeatherEntity; - if (stateObj && stateObj.state !== UNAVAILABLE) { - return !!stateObj.attributes.forecast?.length; - } + return this.hass.states[this._config.entity] as WeatherEntity; } return undefined; } + private get _hasForecast(): boolean | undefined { + const stateObj = this._stateObj as WeatherEntity; + if (stateObj && stateObj.state !== UNAVAILABLE) { + return !!( + stateObj.attributes.forecast?.length || + stateObj.attributes.supported_features + ); + } + return undefined; + } + + private _forecastSupported(forecastType: ForecastType): boolean { + const stateObj = this._stateObj as WeatherEntity; + if (forecastType === "legacy") { + return !!stateObj.attributes.forecast?.length; + } + if (forecastType === "daily") { + return supportsFeature(stateObj, WeatherEntityFeature.FORECAST_DAILY); + } + if (forecastType === "hourly") { + return supportsFeature(stateObj, WeatherEntityFeature.FORECAST_HOURLY); + } + if (forecastType === "twice_daily") { + return supportsFeature( + stateObj, + WeatherEntityFeature.FORECAST_TWICE_DAILY + ); + } + return false; + } + private _schema = memoizeOne( - (localize: LocalizeFunc, hasForecast?: boolean) => + ( + localize: LocalizeFunc, + hasForecastLegacy?: boolean, + hasForecastDaily?: boolean, + hasForecastHourly?: boolean, + hasForecastTwiceDaily?: boolean + ) => [ { name: "entity", @@ -86,7 +141,54 @@ export class HuiWeatherForecastCardEditor { name: "theme", selector: { theme: {} } }, ], }, - ...(hasForecast + ...(!hasForecastLegacy && + (hasForecastDaily || hasForecastHourly || hasForecastTwiceDaily) + ? ([ + { + name: "forecast_type", + selector: { + select: { + options: [ + ...(hasForecastDaily + ? ([ + { + value: "daily", + label: localize( + "ui.panel.lovelace.editor.card.weather-forecast.daily" + ), + }, + ] as const) + : []), + ...(hasForecastHourly + ? ([ + { + value: "hourly", + label: localize( + "ui.panel.lovelace.editor.card.weather-forecast.hourly" + ), + }, + ] as const) + : []), + ...(hasForecastTwiceDaily + ? ([ + { + value: "twice_daily", + label: localize( + "ui.panel.lovelace.editor.card.weather-forecast.twice_daily" + ), + }, + ] as const) + : []), + ], + }, + }, + }, + ] as const) + : []), + ...(hasForecastDaily || + hasForecastHourly || + hasForecastTwiceDaily || + hasForecastLegacy ? ([ { name: "forecast", @@ -125,11 +227,17 @@ export class HuiWeatherForecastCardEditor return nothing; } - const schema = this._schema(this.hass.localize, this._has_forecast); + const schema = this._schema( + this.hass.localize, + this._forecastSupported("legacy"), + this._forecastSupported("daily"), + this._forecastSupported("hourly"), + this._forecastSupported("twice_daily") + ); const data: WeatherForecastCardConfig = { show_current: true, - show_forecast: this._has_forecast, + show_forecast: this._hasForecast, ...this._config, }; @@ -184,6 +292,10 @@ export class HuiWeatherForecastCardEditor )} (${this.hass!.localize( "ui.panel.lovelace.editor.card.config.optional" )})`; + case "forecast_type": + return this.hass!.localize( + "ui.panel.lovelace.editor.card.weather-forecast.forecast_type" + ); case "forecast": return this.hass!.localize( "ui.panel.lovelace.editor.card.weather-forecast.weather_to_show" diff --git a/src/panels/lovelace/editor/header-footer-editor/hui-dialog-create-headerfooter.ts b/src/panels/lovelace/editor/header-footer-editor/hui-dialog-create-headerfooter.ts index d1b5423e5e..092dd02134 100644 --- a/src/panels/lovelace/editor/header-footer-editor/hui-dialog-create-headerfooter.ts +++ b/src/panels/lovelace/editor/header-footer-editor/hui-dialog-create-headerfooter.ts @@ -56,26 +56,25 @@ export class HuiCreateDialogHeaderFooter >
    ${headerFooterElements.map( - (headerFooter, index) => - html` - - -
    - ${this.hass!.localize( - `ui.panel.lovelace.editor.header-footer.types.${headerFooter.type}.name` - )} -
    -
    - ` + (headerFooter, index) => html` + + +
    + ${this.hass!.localize( + `ui.panel.lovelace.editor.header-footer.types.${headerFooter.type}.name` + )} +
    +
    + ` )}
    diff --git a/src/panels/lovelace/editor/hui-element-editor.ts b/src/panels/lovelace/editor/hui-element-editor.ts index f711c63210..2d2b58f4a1 100644 --- a/src/panels/lovelace/editor/hui-element-editor.ts +++ b/src/panels/lovelace/editor/hui-element-editor.ts @@ -131,14 +131,16 @@ export abstract class HuiElementEditor extends LitElement { } } - fireEvent(this, "config-changed", { - config: this.value! as any, - error: this._errors?.join(", "), - guiModeAvailable: !( - this.hasWarning || - this.hasError || - this._guiSupported === false - ), + this.updateComplete.then(() => { + fireEvent(this, "config-changed", { + config: this.value! as any, + error: this._errors?.join(", "), + guiModeAvailable: !( + this.hasWarning || + this.hasError || + this._guiSupported === false + ), + }); }); } @@ -156,13 +158,15 @@ export abstract class HuiElementEditor extends LitElement { public set GUImode(guiMode: boolean) { this._guiMode = guiMode; - fireEvent(this as HTMLElement, "GUImode-changed", { - guiMode, - guiModeAvailable: !( - this.hasWarning || - this.hasError || - this._guiSupported === false - ), + this.updateComplete.then(() => { + fireEvent(this as HTMLElement, "GUImode-changed", { + guiMode, + guiModeAvailable: !( + this.hasWarning || + this.hasError || + this._guiSupported === false + ), + }); }); } diff --git a/src/panels/lovelace/editor/hui-sub-element-editor.ts b/src/panels/lovelace/editor/hui-sub-element-editor.ts index b47953a33a..dd1fd799d1 100644 --- a/src/panels/lovelace/editor/hui-sub-element-editor.ts +++ b/src/panels/lovelace/editor/hui-sub-element-editor.ts @@ -1,5 +1,5 @@ import "@material/mwc-button"; -import { mdiArrowLeft } from "@mdi/js"; +import { mdiArrowLeft, mdiCodeBraces, mdiListBoxOutline } from "@mdi/js"; import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property, query, state } from "lit/decorators"; import { fireEvent, HASSDomEvent } from "../../../common/dom/fire_event"; @@ -50,17 +50,17 @@ export class HuiSubElementEditor extends LitElement { )}
    - - ${this.hass.localize( + .disabled=${!this._guiModeAvailable} + .label=${this.hass!.localize( this._guiMode ? "ui.panel.lovelace.editor.edit_card.show_code_editor" : "ui.panel.lovelace.editor.edit_card.show_visual_editor" )} - + .path=${this._guiMode ? mdiCodeBraces : mdiListBoxOutline} + >
    ${this.config.type === "row" ? html` diff --git a/src/panels/lovelace/editor/view-editor/hui-dialog-edit-view.ts b/src/panels/lovelace/editor/view-editor/hui-dialog-edit-view.ts index 99d8c42f64..d873e8d5e1 100644 --- a/src/panels/lovelace/editor/view-editor/hui-dialog-edit-view.ts +++ b/src/panels/lovelace/editor/view-editor/hui-dialog-edit-view.ts @@ -21,7 +21,8 @@ import "../../../../components/ha-alert"; import "../../../../components/ha-circular-progress"; import "../../../../components/ha-dialog"; import "../../../../components/ha-dialog-header"; -import { HaYamlEditor } from "../../../../components/ha-yaml-editor"; +import "../../../../components/ha-yaml-editor"; +import type { HaYamlEditor } from "../../../../components/ha-yaml-editor"; import type { LovelaceBadgeConfig, LovelaceCardConfig, diff --git a/src/panels/lovelace/entity-rows/hui-event-entity-row.ts b/src/panels/lovelace/entity-rows/hui-event-entity-row.ts new file mode 100644 index 0000000000..35c98d1a0d --- /dev/null +++ b/src/panels/lovelace/entity-rows/hui-event-entity-row.ts @@ -0,0 +1,129 @@ +import { + css, + CSSResultGroup, + html, + LitElement, + PropertyValues, + nothing, +} from "lit"; +import { customElement, property, state } from "lit/decorators"; +import { computeStateDisplay } from "../../../common/entity/compute_state_display"; +import { computeAttributeValueDisplay } from "../../../common/entity/compute_attribute_display"; +import { isUnavailableState } from "../../../data/entity"; +import { ActionHandlerEvent } from "../../../data/lovelace"; +import { HomeAssistant } from "../../../types"; +import { EntitiesCardEntityConfig } from "../cards/types"; +import { actionHandler } from "../common/directives/action-handler-directive"; +import { handleAction } from "../common/handle-action"; +import { hasAction } from "../common/has-action"; +import { hasConfigOrEntityChanged } from "../common/has-changed"; +import "../components/hui-generic-entity-row"; +import "../components/hui-timestamp-display"; +import { createEntityNotFoundWarning } from "../components/hui-warning"; +import { TimestampRenderingFormat } from "../components/types"; +import { LovelaceRow } from "./types"; + +interface EventEntityConfig extends EntitiesCardEntityConfig { + format?: TimestampRenderingFormat; +} + +@customElement("hui-event-entity-row") +class HuiEventEntityRow extends LitElement implements LovelaceRow { + @property({ attribute: false }) public hass?: HomeAssistant; + + @state() private _config?: EventEntityConfig; + + public setConfig(config: EventEntityConfig): void { + if (!config) { + throw new Error("Invalid configuration"); + } + this._config = config; + } + + protected shouldUpdate(changedProps: PropertyValues): boolean { + return hasConfigOrEntityChanged(this, changedProps); + } + + protected render() { + if (!this._config || !this.hass) { + return nothing; + } + + const stateObj = this.hass.states[this._config.entity]; + + if (!stateObj) { + return html` + + ${createEntityNotFoundWarning(this.hass, this._config.entity)} + + `; + } + + return html` + +
    +
    + ${isUnavailableState(stateObj.state) + ? computeStateDisplay( + this.hass!.localize, + stateObj, + this.hass.locale, + this.hass.config, + this.hass.entities + ) + : computeAttributeValueDisplay( + this.hass!.localize, + stateObj, + this.hass.locale, + this.hass.config, + this.hass.entities, + "event_type" + )} +
    +
    + ${isUnavailableState(stateObj.state) + ? `` + : html` + + `} +
    +
    +
    + `; + } + + private _handleAction(ev: ActionHandlerEvent) { + handleAction(this, this.hass!, this._config!, ev.detail.action); + } + + static get styles(): CSSResultGroup { + return css` + div { + text-align: right; + } + .when { + color: var(--secondary-text-color); + } + .what { + color: var(--primary-text-color); + } + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-event-entity-row": HuiEventEntityRow; + } +} diff --git a/src/panels/lovelace/entity-rows/hui-media-player-entity-row.ts b/src/panels/lovelace/entity-rows/hui-media-player-entity-row.ts index f2f481ad46..ab2de02d9a 100644 --- a/src/panels/lovelace/entity-rows/hui-media-player-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-media-player-entity-row.ts @@ -24,10 +24,11 @@ import { customElement, property, state } from "lit/decorators"; import { computeStateDisplay } from "../../../common/entity/compute_state_display"; import { supportsFeature } from "../../../common/entity/supports-feature"; import { computeRTLDirection } from "../../../common/util/compute_rtl"; +import { stateActive } from "../../../common/entity/state_active"; import { debounce } from "../../../common/util/debounce"; import "../../../components/ha-icon-button"; import "../../../components/ha-slider"; -import { isUnavailableState, UNAVAILABLE, UNKNOWN } from "../../../data/entity"; +import { isUnavailableState } from "../../../data/entity"; import { computeMediaDescription, ControlButton, @@ -199,7 +200,7 @@ class HuiMediaPlayerEntityRow extends LitElement implements LovelaceRow { >
    ${supportsFeature(stateObj, MediaPlayerEntityFeature.TURN_ON) && - entityState === "off" && + !stateActive(stateObj) && !isUnavailableState(entityState) ? html` ${(supportsFeature(stateObj, MediaPlayerEntityFeature.VOLUME_SET) || supportsFeature(stateObj, MediaPlayerEntityFeature.VOLUME_BUTTONS)) && - ![UNAVAILABLE, UNKNOWN, "off"].includes(entityState) + stateActive(stateObj) ? html`
    @@ -330,7 +330,7 @@ class HuiMediaPlayerEntityRow extends LitElement implements LovelaceRow { this.hass!.callService( "media_player", - stateObj.state === "off" ? "turn_on" : "turn_off", + stateActive(stateObj) ? "turn_off" : "turn_on", { entity_id: this._config!.entity, } diff --git a/src/panels/lovelace/entity-rows/hui-select-entity-row.ts b/src/panels/lovelace/entity-rows/hui-select-entity-row.ts index 2d7d3c51e1..31b51927c1 100644 --- a/src/panels/lovelace/entity-rows/hui-select-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-select-entity-row.ts @@ -75,19 +75,18 @@ class HuiSelectEntityRow extends LitElement implements LovelaceRow { > ${stateObj.attributes.options ? stateObj.attributes.options.map( - (option) => - html` - - ${computeStateDisplay( - this.hass!.localize, - stateObj, - this.hass!.locale, - this.hass!.config, - this.hass!.entities, - option - )} - - ` + (option) => html` + + ${computeStateDisplay( + this.hass!.localize, + stateObj, + this.hass!.locale, + this.hass!.config, + this.hass!.entities, + option + )} + + ` ) : ""} diff --git a/src/panels/lovelace/entity-rows/hui-weather-entity-row.ts b/src/panels/lovelace/entity-rows/hui-weather-entity-row.ts index f8badf7b10..90351e76d6 100644 --- a/src/panels/lovelace/entity-rows/hui-weather-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-weather-entity-row.ts @@ -16,9 +16,13 @@ import "../../../components/entity/state-badge"; import { isUnavailableState } from "../../../data/entity"; import { ActionHandlerEvent } from "../../../data/lovelace"; import { + getDefaultForecastType, + getForecast, getSecondaryWeatherAttribute, getWeatherStateIcon, getWeatherUnit, + subscribeForecast, + ForecastEvent, WeatherEntity, weatherSVGStyles, } from "../../../data/weather"; @@ -38,6 +42,48 @@ class HuiWeatherEntityRow extends LitElement implements LovelaceRow { @state() private _config?: EntitiesCardEntityConfig; + @state() private _forecastEvent?: ForecastEvent; + + @state() private _subscribed?: Promise<() => void>; + + private _unsubscribeForecastEvents() { + if (this._subscribed) { + this._subscribed.then((unsub) => unsub()); + this._subscribed = undefined; + } + } + + private async _subscribeForecastEvents() { + this._unsubscribeForecastEvents(); + if (!this.hass || !this._config || !this.isConnected) { + return; + } + const stateObj = this.hass!.states[this._config!.entity]; + const forecastType = getDefaultForecastType(stateObj); + if (forecastType) { + this._subscribed = subscribeForecast( + this.hass!, + stateObj.entity_id, + forecastType, + (event) => { + this._forecastEvent = event; + } + ); + } + } + + public connectedCallback() { + super.connectedCallback(); + if (this.hasUpdated) { + this._subscribeForecastEvents(); + } + } + + public disconnectedCallback(): void { + super.disconnectedCallback(); + this._unsubscribeForecastEvents(); + } + public setConfig(config: EntitiesCardEntityConfig): void { if (!config?.entity) { throw new Error("Entity must be specified"); @@ -50,6 +96,13 @@ class HuiWeatherEntityRow extends LitElement implements LovelaceRow { return hasConfigOrEntityChanged(this, changedProps); } + protected updated(changedProps: PropertyValues): void { + super.updated(changedProps); + if (changedProps.has("_config") || !this._subscribed) { + this._subscribeForecastEvents(); + } + } + protected render() { if (!this.hass || !this._config) { return nothing; @@ -72,6 +125,9 @@ class HuiWeatherEntityRow extends LitElement implements LovelaceRow { const hasSecondary = this._config.secondary_info; const weatherStateIcon = getWeatherStateIcon(stateObj.state, this); + const forecastData = getForecast(stateObj.attributes, this._forecastEvent); + const forecast = forecastData?.forecast; + return html`
    - ${getSecondaryWeatherAttribute(this.hass!, stateObj)} + ${getSecondaryWeatherAttribute(this.hass!, stateObj, forecast!)}
    `; diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts index 0447b6f646..b023483ab9 100644 --- a/src/panels/lovelace/hui-root.ts +++ b/src/panels/lovelace/hui-root.ts @@ -567,7 +567,7 @@ class HUIRoot extends LitElement { if (searchParams.edit === "1") { this.lovelace!.setEditMode(true); } else if (searchParams.conversation === "1") { - showVoiceCommandDialog(this, this.hass); + this._showVoiceCommandDialog(); window.history.replaceState( null, "", @@ -793,7 +793,7 @@ class HUIRoot extends LitElement { } private _showVoiceCommandDialog(): void { - showVoiceCommandDialog(this, this.hass); + showVoiceCommandDialog(this, this.hass, { pipeline_id: "last_used" }); } private _handleEnableEditMode(ev: CustomEvent): void { diff --git a/src/panels/lovelace/strategies/get-strategy.ts b/src/panels/lovelace/strategies/get-strategy.ts index 4e13f6ef36..59ae47b141 100644 --- a/src/panels/lovelace/strategies/get-strategy.ts +++ b/src/panels/lovelace/strategies/get-strategy.ts @@ -32,7 +32,7 @@ const strategies: Record< }; const getLovelaceStrategy = async < - T extends LovelaceDashboardStrategy | LovelaceViewStrategy + T extends LovelaceDashboardStrategy | LovelaceViewStrategy, >( strategyType: string ): Promise => { diff --git a/src/panels/lovelace/tile-features/hui-vacuum-commands-tile-feature.ts b/src/panels/lovelace/tile-features/hui-vacuum-commands-tile-feature.ts index 3c4119511c..f4079030dd 100644 --- a/src/panels/lovelace/tile-features/hui-vacuum-commands-tile-feature.ts +++ b/src/panels/lovelace/tile-features/hui-vacuum-commands-tile-feature.ts @@ -63,6 +63,8 @@ export const VACUUM_COMMANDS_BUTTONS: Record< > = { start_pause: (stateObj) => { const startPauseOnly = + // This service is only available for old vacuum entities, new entities have the `STATE` feature + !supportsFeature(stateObj, VacuumEntityFeature.STATE) && !supportsFeature(stateObj, VacuumEntityFeature.START) && supportsFeature(stateObj, VacuumEntityFeature.PAUSE); diff --git a/src/panels/my/ha-panel-my.ts b/src/panels/my/ha-panel-my.ts index 6f2d35c099..9810837ccf 100644 --- a/src/panels/my/ha-panel-my.ts +++ b/src/panels/my/ha-panel-my.ts @@ -20,6 +20,9 @@ export const getMyRedirects = (hasSupervisor: boolean): Redirects => ({ application_credentials: { redirect: "/config/application_credentials", }, + developer_assist: { + redirect: "/developer-tools/assist", + }, developer_states: { redirect: "/developer-tools/state", }, @@ -48,6 +51,9 @@ export const getMyRedirects = (hasSupervisor: boolean): Redirects => ({ component: "calendar", redirect: "/calendar", }, + companion_app: { + redirect: "#external-app-configuration", + }, config: { redirect: "/config/dashboard", }, @@ -320,6 +326,15 @@ class HaPanelMy extends LitElement { return; } + if (this._redirect.redirect === "#external-app-configuration") { + if (this.hass.auth.external?.config.hasSettingsScreen) { + this.hass.auth.external!.fireMessage({ type: "config_screen/show" }); + return; + } + this._error = "not_app"; + return; + } + if ( this._redirect.component && !isComponentLoaded(this.hass, this._redirect.component) @@ -407,6 +422,18 @@ class HaPanelMy extends LitElement { >` ); break; + case "not_app": + error = this.hass.localize( + "ui.panel.my.not_app", + "link", + html`${this.hass.localize("ui.panel.my.download_app")}` + ); + break; default: error = this.hass.localize("ui.panel.my.error") || "Unknown error"; } diff --git a/src/panels/profile/ha-long-lived-access-tokens-card.ts b/src/panels/profile/ha-long-lived-access-tokens-card.ts index 5edcbfb34d..c622ad0d7e 100644 --- a/src/panels/profile/ha-long-lived-access-tokens-card.ts +++ b/src/panels/profile/ha-long-lived-access-tokens-card.ts @@ -61,23 +61,27 @@ class HaLongLivedTokens extends LitElement { )}

    ` : accessTokens!.map( - (token) => html` - ${token.client_name} -
    - ${this.hass.localize( - "ui.panel.profile.long_lived_access_tokens.created", - "date", - relativeTime(new Date(token.created_at), this.hass.locale) - )} -
    - -
    ` + (token) => + html` + ${token.client_name} +
    + ${this.hass.localize( + "ui.panel.profile.long_lived_access_tokens.created", + "date", + relativeTime( + new Date(token.created_at), + this.hass.locale + ) + )} +
    + +
    ` )}
    diff --git a/src/panels/profile/ha-mfa-modules-card.ts b/src/panels/profile/ha-mfa-modules-card.ts index c6fed2b149..ce3f94c0a2 100644 --- a/src/panels/profile/ha-mfa-modules-card.ts +++ b/src/panels/profile/ha-mfa-modules-card.ts @@ -17,21 +17,22 @@ class HaMfaModulesCard extends LitElement { return html` ${this.mfaModules.map( - (module) => html` - ${module.name} - ${module.id} - ${module.enabled - ? html`${this.hass.localize( - "ui.panel.profile.mfa.disable" - )}` - : html`${this.hass.localize( - "ui.panel.profile.mfa.enable" - )}`} - ` + (module) => + html` + ${module.name} + ${module.id} + ${module.enabled + ? html`${this.hass.localize( + "ui.panel.profile.mfa.disable" + )}` + : html`${this.hass.localize( + "ui.panel.profile.mfa.enable" + )}`} + ` )} `; diff --git a/src/panels/profile/ha-pick-theme-row.ts b/src/panels/profile/ha-pick-theme-row.ts index 1677ff7e15..725955fe98 100644 --- a/src/panels/profile/ha-pick-theme-row.ts +++ b/src/panels/profile/ha-pick-theme-row.ts @@ -23,8 +23,8 @@ import { import { HomeAssistant } from "../../types"; import { documentationUrl } from "../../util/documentation-url"; -const BACKEND_SELECTED_THEME = "Backend-selected"; -const DEFAULT_THEME = "default"; +const USE_DEFAULT_THEME = "__USE_DEFAULT_THEME__"; +const HOME_ASSISTANT_THEME = "default"; @customElement("ha-pick-theme-row") export class HaPickThemeRow extends LitElement { @@ -68,15 +68,15 @@ export class HaPickThemeRow extends LitElement { - - ${this.hass.localize("ui.panel.profile.themes.backend-selected")} + + ${this.hass.localize("ui.panel.profile.themes.use_default")} - - ${this.hass.localize("ui.panel.profile.themes.default")} + + Home Assistant ${this._themeNames.map( (theme) => html` @@ -85,7 +85,8 @@ export class HaPickThemeRow extends LitElement { )} - ${curTheme === DEFAULT_THEME || this._supportsModeSelection(curTheme) + ${curTheme === HOME_ASSISTANT_THEME || + this._supportsModeSelection(curTheme) ? html`
    - ${curTheme === DEFAULT_THEME + ${curTheme === HOME_ASSISTANT_THEME ? html`
    html` - ${this.hass.localize( - "ui.panel.profile.refresh_tokens.token_title", - { clientId: token.client_id } - )} - -
    - ${this.hass.localize( - "ui.panel.profile.refresh_tokens.created_at", - { - date: relativeTime( - new Date(token.created_at), - this.hass.locale - ), - } - )} -
    -
    - ${token.last_used_at - ? this.hass.localize( - "ui.panel.profile.refresh_tokens.last_used", - { - date: relativeTime( - new Date(token.last_used_at), - this.hass.locale - ), - location: token.last_used_ip, - } - ) - : this.hass.localize( - "ui.panel.profile.refresh_tokens.not_used" - )} -
    -
    - ${token.is_current - ? html` - ${this.hass.localize( - "ui.panel.profile.refresh_tokens.current_token_tooltip" + (token) => + html` + ${this.hass.localize( + "ui.panel.profile.refresh_tokens.token_title", + { clientId: token.client_id } + )} + +
    + ${this.hass.localize( + "ui.panel.profile.refresh_tokens.created_at", + { + date: relativeTime( + new Date(token.created_at), + this.hass.locale + ), + } + )} +
    +
    + ${token.last_used_at + ? this.hass.localize( + "ui.panel.profile.refresh_tokens.last_used", + { + date: relativeTime( + new Date(token.last_used_at), + this.hass.locale + ), + location: token.last_used_ip, + } + ) + : this.hass.localize( + "ui.panel.profile.refresh_tokens.not_used" )} - ` - : ""} - -
    -
    ` +
    +
    + ${token.is_current + ? html` + ${this.hass.localize( + "ui.panel.profile.refresh_tokens.current_token_tooltip" + )} + ` + : ""} + +
    +
    ` ) : ""}
    diff --git a/src/panels/shopping-list/ha-panel-shopping-list.ts b/src/panels/shopping-list/ha-panel-shopping-list.ts index 94f675a601..a9cfb23eaf 100644 --- a/src/panels/shopping-list/ha-panel-shopping-list.ts +++ b/src/panels/shopping-list/ha-panel-shopping-list.ts @@ -76,7 +76,7 @@ class PanelShoppingList extends LitElement { } private _showVoiceCommandDialog(): void { - showVoiceCommandDialog(this, this.hass); + showVoiceCommandDialog(this, this.hass, { pipeline_id: "last_used" }); } static get styles(): CSSResultGroup { diff --git a/src/resources/ha-style.ts b/src/resources/ha-style.ts index 4bdac11926..aefe6e6479 100644 --- a/src/resources/ha-style.ts +++ b/src/resources/ha-style.ts @@ -156,7 +156,7 @@ documentContainer.innerHTML = ` --state-device_tracker-active-color: var(--blue-color); --state-device_tracker-home-color: var(--green-color); --state-fan-active-color: var(--cyan-color); - --state-humidifier-active-color: var(--blue-color); + --state-humidifier-on-color: var(--blue-color); --state-light-active-color: var(--amber-color); --state-lock-jammed-color: var(--red-color); --state-lock-locked-color: var(--green-color); diff --git a/src/state-summary/state-card-content.js b/src/state-summary/state-card-content.js index b1669ae994..4171bd447a 100644 --- a/src/state-summary/state-card-content.js +++ b/src/state-summary/state-card-content.js @@ -8,6 +8,7 @@ import "./state-card-humidifier"; import "./state-card-configurator"; import "./state-card-cover"; import "./state-card-display"; +import "./state-card-event"; import "./state-card-input_button"; import "./state-card-input_number"; import "./state-card-input_select"; diff --git a/src/state-summary/state-card-event.ts b/src/state-summary/state-card-event.ts new file mode 100644 index 0000000000..20d590fb22 --- /dev/null +++ b/src/state-summary/state-card-event.ts @@ -0,0 +1,59 @@ +import { HassEntity } from "home-assistant-js-websocket"; +import { CSSResultGroup, html, LitElement } from "lit"; +import { customElement, property } from "lit/decorators"; +import "../components/entity/ha-entity-toggle"; +import "../components/entity/state-info"; +import { HomeAssistant } from "../types"; +import { isUnavailableState } from "../data/entity"; +import { computeAttributeValueDisplay } from "../common/entity/compute_attribute_display"; +import { computeStateDisplay } from "../common/entity/compute_state_display"; +import { haStyle } from "../resources/styles"; + +@customElement("state-card-event") +export class StateCardEvent extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property() public stateObj!: HassEntity; + + @property({ type: Boolean }) public inDialog = false; + + protected render() { + return html` +
    + +
    + ${isUnavailableState(this.stateObj.state) + ? computeStateDisplay( + this.hass!.localize, + this.stateObj, + this.hass.locale, + this.hass.config, + this.hass.entities + ) + : computeAttributeValueDisplay( + this.hass!.localize, + this.stateObj, + this.hass.locale, + this.hass.config, + this.hass.entities, + "event_type" + )} +
    +
    + `; + } + + static get styles(): CSSResultGroup { + return haStyle; + } +} + +declare global { + interface HTMLElementTagNameMap { + "state-card-event": StateCardEvent; + } +} diff --git a/src/state-summary/state-card-select.ts b/src/state-summary/state-card-select.ts index 354136c67e..4e6b48c9dc 100644 --- a/src/state-summary/state-card-select.ts +++ b/src/state-summary/state-card-select.ts @@ -29,19 +29,18 @@ class StateCardSelect extends LitElement { @closed=${stopPropagation} > ${this.stateObj.attributes.options.map( - (option) => - html` - - ${computeStateDisplay( - this.hass.localize, - this.stateObj, - this.hass.locale, - this.hass.config, - this.hass.entities, - option - )} - - ` + (option) => html` + + ${computeStateDisplay( + this.hass.localize, + this.stateObj, + this.hass.locale, + this.hass.config, + this.hass.entities, + option + )} + + ` )} `; diff --git a/src/state/connection-mixin.ts b/src/state/connection-mixin.ts index 8ba5091a02..ac5b27773f 100644 --- a/src/state/connection-mixin.ts +++ b/src/state/connection-mixin.ts @@ -123,9 +123,10 @@ export const connectionMixin = >( `${domain}/${service}` ) + ` ${ - err.message || err.error?.code === ERR_CONNECTION_LOST + err.message || + (err.error?.code === ERR_CONNECTION_LOST ? "connection lost" - : "unknown error" + : "unknown error") }`; fireEvent(this as any, "hass-notification", { message }); throw err; diff --git a/src/state/url-sync-mixin.ts b/src/state/url-sync-mixin.ts index 387bf8fd9b..70b908feac 100644 --- a/src/state/url-sync-mixin.ts +++ b/src/state/url-sync-mixin.ts @@ -19,7 +19,7 @@ export let historyPromise: Promise | undefined; let historyResolve: undefined | (() => void); export const urlSyncMixin = < - T extends Constructor + T extends Constructor, >( superClass: T ) => diff --git a/src/translations/en.json b/src/translations/en.json index b1729cba5c..8834f0583e 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -134,6 +134,9 @@ "state": "State", "mode": "Mode", "target_humidity_entity": "{name} target humidity", + "current_humidity_entity": "{name} current humidity", + "humidifying": "{name} humidifying", + "drying": "{name} drying", "on_entity": "{name} on" }, "light": { @@ -251,6 +254,9 @@ "day": "Day", "night": "Night", "forecast": "Forecast", + "forecast_daily": "Forecast daily", + "forecast_hourly": "Forecast hourly", + "forecast_twice_daily": "Forecast twice daily", "high": "High", "low": "Low" } @@ -280,6 +286,7 @@ "edit": "Edit", "submit": "Submit", "rename": "Rename", + "search": "[%key:ui::components::data-table::search%]", "ok": "OK", "yes": "Yes", "no": "No", @@ -353,7 +360,9 @@ "became_unavailable": "became unavailable", "became_unknown": "became unknown", "detected_tampering": "detected tampering", - "cleared_tampering": "cleared tampering" + "cleared_tampering": "cleared tampering", + "detected_event": "{event_type} event detected", + "detected_unknown_event": "detected an unknown event" } }, "entity": { @@ -394,12 +403,12 @@ }, "pipeline-picker": { "pipeline": "Assistant", - "preferred": "Preferred assistant ({preferred})" + "preferred": "Preferred assistant ({preferred})", + "last_used": "Last used assistant" }, "theme-picker": { "theme": "Theme", - "no_theme": "No theme", - "default": "[%key:ui::panel::profile::themes::default%]" + "no_theme": "No theme" }, "language-picker": { "language": "Language", @@ -1381,6 +1390,15 @@ "message_example": "Hello. How can I assist?", "message_placeholder": "Enter a sentence to speak.", "play": "Play" + }, + "dialog-ip-detail": { + "ip_information": "[%key:ui::panel::config::network::ip_information%]", + "ipv4": "IPv4", + "ipv6": "IPv6", + "ip_address": "IP Address: {address}", + "gateway": "Gateway: {gateway}", + "method": "Method: {method}", + "nameservers": "Name Servers: {nameservers}" } }, "duration": { @@ -1455,7 +1473,9 @@ "not_supported": "This redirect is not supported by your Home Assistant instance. Check the {link} for the supported redirects and the version they where introduced.", "component_not_loaded": "This redirect is not supported by your Home Assistant instance. You need the integration {integration} to use this redirect.", "no_supervisor": "This redirect is not supported by your Home Assistant installation. It needs either the Home Assistant Operating System or Home Assistant Supervised installation method. For more information, see the {docs_link}.", + "not_app": "This redirect only works from a mobile device that has the Home Assistant Companion app installed. {link}.", "documentation": "documentation", + "download_app": "Click here to download the app", "faq_link": "My Home Assistant FAQ", "error": "An unknown error occurred" }, @@ -2309,7 +2329,7 @@ } }, "event": { - "label": "Event", + "label": "Manual event", "event_type": "Event type", "event_data": "Event data", "context_users": "Limit to events triggered by", @@ -2620,18 +2640,18 @@ "continue_timeout": "[%key:ui::panel::config::automation::editor::actions::type::wait_template::continue_timeout%]", "description": { "wait_for_a_trigger": "Wait for a trigger", - "wait_for_triggers_with_name": "Wait for ''{triggers}''" + "wait_for_triggers": "Wait for {count} {count, plural,\n one {trigger}\n other {triggers}\n}" } }, "condition": { "label": "Condition" }, "event": { - "label": "Event", - "event": "[%key:ui::panel::config::automation::editor::triggers::type::event::label%]", + "label": "Manual event", + "event": "[%key:ui::panel::config::automation::editor::triggers::type::event::event_type%]", "event_data": "[%key:ui::panel::config::automation::editor::triggers::type::event::event_data%]", "description": { - "full": "Fire event {name}", + "full": "Manually fire event {name}", "template": "based on a template" } }, @@ -2678,8 +2698,8 @@ "description": { "full": "Repeat an action {chosenAction}", "count": "{count} {count, plural,\n one {time}\n other {times}\n}", - "while": "while ''{conditions}'' is true", - "until": "until ''{conditions}'' is true", + "while_count": "while {count} {count, plural,\n one {condition matches}\n other {conditions match}\n} ", + "until_count": "until {count} {count, plural,\n one {condition matches}\n other {conditions match}\n} ", "for_each": "for every item: {items}" } }, @@ -2690,7 +2710,9 @@ "option": "Option {number}", "add_option": "Add option", "remove_option": "Remove option", + "option_description_additional": " {numberOfAdditionalConditions, plural,\n one {and 1 more condition}\n other {and {numberOfAdditionalConditions} more conditions}}", "conditions": "Conditions", + "no_conditions": "[%key:ui::panel::config::devices::automation::conditions::no_conditions%]", "sequence": "Actions", "description": { "full": "Choose between {number} {number, plural,\n one {action}\n other{actions}\n}", @@ -2704,7 +2726,8 @@ "else": "Else", "add_else": "Add else", "description": { - "full": "Perform ''{action}'' if ''{conditions}''{hasElse, select, \n true { otherwise ''{elseAction}''} \n other {}\n } " + "if": "Conditionally execute an action", + "if_else": "Conditionally execute an action and default to another action" } }, "stop": { @@ -3196,6 +3219,7 @@ "entities": { "entities": "Entities", "control": "Controls", + "event": "Events", "sensor": "Sensors", "diagnostic": "Diagnostic", "config": "Configuration", @@ -3376,6 +3400,8 @@ "confirm_new": "Do you want to set up {integration}?", "add_integration": "Add integration", "no_integrations": "Seems like you don't have any integrations configured yet. Click on the button below to add your first integration!", + "no_disabled_integrations": "No disabled integrations", + "no_ignored_integrations": "No ignored integrations", "note_about_integrations": "No integrations matched your search, the integration you want to set up might not be available to set up via the UI yet.", "note_about_website_reference": "More are available on the ", "home_assistant_website": "Home Assistant website", @@ -3437,6 +3463,7 @@ "entities": "{count} {count, plural,\n one {entity}\n other {entities}\n}", "services": "{count} {count, plural,\n one {service}\n other {services}\n}", "entries": "{count} {count, plural,\n one {entry}\n other {entries}\n}", + "no_devices_or_entities": "No devices or entities", "rename": "Rename", "configure": "Configure", "system_options": "System options", @@ -3666,7 +3693,16 @@ "no_border_routers": "No border routers found", "border_routers": "{count} border {count, plural,\n one {router}\n other {routers}\n}", "managed_by_home_assistant": "Managed by Home Assistant", - "operational_dataset": "Operational dataset" + "operational_dataset": "Operational dataset", + "change_channel": "Change channel", + "change_channel_initiated_title": "Channel change in progress", + "change_channel_initiated_text": "The channel change has been initiated and will complete in {delay} minutes.", + "change_channel_invalid": "Invalid channel", + "change_channel_label": "Channel", + "change_channel_multiprotocol_enabled_title": "The Thread radio has multiprotocol enabled", + "change_channel_multiprotocol_enabled_text": "To change channel when the Thread radio has multiprotocol enabled, please use the hardware settings menu.", + "change_channel_range": "Channel must be in the range 11 to 26", + "change_channel_text": "Initiate a channel change for your Thread networks. This is an advanced operation and can leave your Thread networks inoperable if the new channel is congested. Depending on existing network conditions, many of your devices may not migrate to the new channel and will require re-joining before they start working again. Use with caution." }, "zha": { "common": { @@ -4186,7 +4222,10 @@ "description": "The name your instance will have on your network", "failed_to_set_hostname": "Setting hostname failed" } - } + }, + "network_adapter": "Network Adapter", + "network_adapter_info": "Configure which network adapters integrations will use. Currently this setting only affects multicast traffic. A restart is required for these settings to apply.", + "ip_information": "IP Information" }, "storage": { "caption": "Storage", @@ -4396,9 +4435,9 @@ "self_consumed_solar_could_not_calc": "Self-consumed solar energy couldn't be calculated" }, "self_sufficiency_gauge": { - "card_indicates_self_sufficiency_quota": "This card indicates how self-sufficient your home is.", - "self_sufficiency_quota": "Self-sufficiency quota", - "self_sufficiency_could_not_calc": "Self-sufficiency quota couldn't be calculated" + "card_indicates_self_sufficiency_quota": "This card indicates how much of the energy consumed by your home came from on-site sources (such as solar panels or batteries).", + "self_sufficiency_quota": "Self-sufficiency", + "self_sufficiency_could_not_calc": "Self-sufficiency couldn't be calculated" }, "grid_neutrality_gauge": { "energy_dependency": "This card indicates your net energy usage.", @@ -4544,16 +4583,16 @@ "add": "Add Card", "edit": "Edit", "clear": "Clear", - "delete": "Delete card", - "copy": "Copy card", - "cut": "Cut card", - "duplicate": "Duplicate card", + "delete": "Delete", + "copy": "Copy", + "cut": "Cut", + "duplicate": "Duplicate", "move": "Move to view", - "move_up": "Move card up", - "move_down": "Move card down", "move_before": "Move card before", "move_after": "Move card after", "change_position": "Change card position", + "decrease_position": "Decrease card position", + "increase_position": "Increase card position", "options": "More options", "search_cards": "Search cards" }, @@ -4941,7 +4980,12 @@ "weather_to_show": "Weather to Show", "show_both": "Show current Weather and Forecast", "show_only_current": "Show only current Weather", - "show_only_forecast": "Show only Forecast" + "show_only_forecast": "Show only Forecast", + "forecast_type": "Select forecast type", + "no_type": "No type", + "daily": "Daily", + "hourly": "Hourly", + "twice_daily": "Twice daily" } }, "view": { @@ -5172,8 +5216,7 @@ "primary_color": "Primary color", "accent_color": "Accent color", "reset": "Reset", - "backend-selected": "Use backend preferred theme", - "default": "Default" + "use_default": "Use default theme" }, "dashboard": { "header": "Dashboard", @@ -5567,10 +5610,16 @@ }, "core-config": { "intro": "Hello {name}, welcome to Home Assistant. How would you like to name your home?", - "intro_location": "We would like to know where you live. This information will help with displaying information and setting up sun-based automations. This data is never shared outside of your network.", - "intro_location_detect": "We can help you fill in this information by making a one-time request to an external service.", + "intro_core": "We will set up the basics together. You can always change this later in the settings.", + "intro_location": "Let's set up the location of your home so that you can display information such as the local weather and use sun-based or presence-based automations. This data is never shared outside of your network.", + "location_address": "Powered by {openstreetmap} ({osm_privacy_policy}).", + "osm_privacy_policy": "Privacy policy", + "title_location_detect": "Do you want us to detect your location?", + "intro_location_detect": "We can detect your location by making a one-time request to an external service.", + "intro_core_config": "We filled out some details about your location. Please check if they are correct and continue.", "location_name": "Name of your Home Assistant installation", "location_name_default": "Home", + "address_label": "Search address", "button_detect": "Detect", "finish": "Next" }, diff --git a/src/types.ts b/src/types.ts index 7dcfee537f..bfdf9768e2 100644 --- a/src/types.ts +++ b/src/types.ts @@ -120,6 +120,7 @@ export interface PanelInfo | null> { icon: string | null; title: string | null; url_path: string; + config_panel_domain?: string; } export interface Panels { diff --git a/yarn.lock b/yarn.lock index 955781a689..8ade02b4c4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -54,45 +54,45 @@ __metadata: languageName: node linkType: hard -"@babel/compat-data@npm:^7.17.7, @babel/compat-data@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/compat-data@npm:7.22.5" - checksum: eb1a47ebf79ae268b4a16903e977be52629339806e248455eb9973897c503a04b701f36a9de64e19750d6e081d0561e77a514c8dc470babbeba59ae94298ed18 +"@babel/compat-data@npm:^7.22.5, @babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.22.9": + version: 7.22.9 + resolution: "@babel/compat-data@npm:7.22.9" + checksum: bed77d9044ce948b4327b30dd0de0779fa9f3a7ed1f2d31638714ed00229fa71fc4d1617ae0eb1fad419338d3658d0e9a5a083297451e09e73e078d0347ff808 languageName: node linkType: hard -"@babel/core@npm:7.22.5, @babel/core@npm:^7.11.1, @babel/core@npm:^7.12.3": - version: 7.22.5 - resolution: "@babel/core@npm:7.22.5" +"@babel/core@npm:7.22.9, @babel/core@npm:^7.11.1, @babel/core@npm:^7.12.3": + version: 7.22.9 + resolution: "@babel/core@npm:7.22.9" dependencies: "@ampproject/remapping": ^2.2.0 "@babel/code-frame": ^7.22.5 - "@babel/generator": ^7.22.5 - "@babel/helper-compilation-targets": ^7.22.5 - "@babel/helper-module-transforms": ^7.22.5 - "@babel/helpers": ^7.22.5 - "@babel/parser": ^7.22.5 + "@babel/generator": ^7.22.9 + "@babel/helper-compilation-targets": ^7.22.9 + "@babel/helper-module-transforms": ^7.22.9 + "@babel/helpers": ^7.22.6 + "@babel/parser": ^7.22.7 "@babel/template": ^7.22.5 - "@babel/traverse": ^7.22.5 + "@babel/traverse": ^7.22.8 "@babel/types": ^7.22.5 convert-source-map: ^1.7.0 debug: ^4.1.0 gensync: ^1.0.0-beta.2 json5: ^2.2.2 - semver: ^6.3.0 - checksum: 173ae426958c90c7bbd7de622c6f13fcab8aef0fac3f138e2d47bc466d1cd1f86f71ca82ae0acb9032fd8794abed8efb56fea55c031396337eaec0d673b69d56 + semver: ^6.3.1 + checksum: 7bf069aeceb417902c4efdaefab1f7b94adb7dea694a9aed1bda2edf4135348a080820529b1a300c6f8605740a00ca00c19b2d5e74b5dd489d99d8c11d5e56d1 languageName: node linkType: hard -"@babel/generator@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/generator@npm:7.22.5" +"@babel/generator@npm:^7.22.7, @babel/generator@npm:^7.22.9": + version: 7.22.9 + resolution: "@babel/generator@npm:7.22.9" dependencies: "@babel/types": ^7.22.5 "@jridgewell/gen-mapping": ^0.3.2 "@jridgewell/trace-mapping": ^0.3.17 jsesc: ^2.5.1 - checksum: efa64da70ca88fe69f05520cf5feed6eba6d30a85d32237671488cc355fdc379fe2c3246382a861d49574c4c2f82a317584f8811e95eb024e365faff3232b49d + checksum: 7c9d2c58b8d5ac5e047421a6ab03ec2ff5d9a5ff2c2212130a0055e063ac349e0b19d435537d6886c999771aef394832e4f54cd9fc810100a7f23d982f6af06b languageName: node linkType: hard @@ -114,66 +114,65 @@ __metadata: languageName: node linkType: hard -"@babel/helper-compilation-targets@npm:^7.17.7, @babel/helper-compilation-targets@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-compilation-targets@npm:7.22.5" +"@babel/helper-compilation-targets@npm:^7.22.5, @babel/helper-compilation-targets@npm:^7.22.6, @babel/helper-compilation-targets@npm:^7.22.9": + version: 7.22.9 + resolution: "@babel/helper-compilation-targets@npm:7.22.9" dependencies: - "@babel/compat-data": ^7.22.5 + "@babel/compat-data": ^7.22.9 "@babel/helper-validator-option": ^7.22.5 - browserslist: ^4.21.3 + browserslist: ^4.21.9 lru-cache: ^5.1.1 - semver: ^6.3.0 + semver: ^6.3.1 peerDependencies: "@babel/core": ^7.0.0 - checksum: a479460615acffa0f4fd0a29b740eafb53a93694265207d23a6038ccd18d183a382cacca515e77b7c9b042c3ba80b0aca0da5f1f62215140e81660d2cf721b68 + checksum: ea0006c6a93759025f4a35a25228ae260538c9f15023e8aac2a6d45ca68aef4cf86cfc429b19af9a402cbdd54d5de74ad3fbcf6baa7e48184dc079f1a791e178 languageName: node linkType: hard -"@babel/helper-create-class-features-plugin@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-create-class-features-plugin@npm:7.22.5" +"@babel/helper-create-class-features-plugin@npm:^7.22.5, @babel/helper-create-class-features-plugin@npm:^7.22.6, @babel/helper-create-class-features-plugin@npm:^7.22.9": + version: 7.22.9 + resolution: "@babel/helper-create-class-features-plugin@npm:7.22.9" dependencies: "@babel/helper-annotate-as-pure": ^7.22.5 "@babel/helper-environment-visitor": ^7.22.5 "@babel/helper-function-name": ^7.22.5 "@babel/helper-member-expression-to-functions": ^7.22.5 "@babel/helper-optimise-call-expression": ^7.22.5 - "@babel/helper-replace-supers": ^7.22.5 + "@babel/helper-replace-supers": ^7.22.9 "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 - "@babel/helper-split-export-declaration": ^7.22.5 - semver: ^6.3.0 + "@babel/helper-split-export-declaration": ^7.22.6 + semver: ^6.3.1 peerDependencies: "@babel/core": ^7.0.0 - checksum: f1e91deae06dbee6dd956c0346bca600adfbc7955427795d9d8825f0439a3c3290c789ba2b4a02a1cdf6c1a1bd163dfa16d3d5e96b02a8efb639d2a774e88ed9 + checksum: 6c2436d1a5a3f1ff24628d78fa8c6d3120c40285aa3eda7815b1adbf8c5951e0dd73d368cf845825888fa3dc2f207dadce53309825598d7c67953e5ed9dd51d2 languageName: node linkType: hard "@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-create-regexp-features-plugin@npm:7.22.5" + version: 7.22.9 + resolution: "@babel/helper-create-regexp-features-plugin@npm:7.22.9" dependencies: "@babel/helper-annotate-as-pure": ^7.22.5 regexpu-core: ^5.3.1 - semver: ^6.3.0 + semver: ^6.3.1 peerDependencies: "@babel/core": ^7.0.0 - checksum: 94932145beeb1f91856be25fea8de30b4b81b63fbc7c5a207ed97a5ddc34cd1e9b04041ed28bd24ec09cdcfbb62e8d66f820e4fe864672afe0aa2f357c784e11 + checksum: 87cb48a7ee898ab205374274364c3adc70b87b08c7bd07f51019ae4562c0170d7148e654d591f825dee14b5fe11666a0e7966872dfdbfa0d1b94b861ecf0e4e1 languageName: node linkType: hard -"@babel/helper-define-polyfill-provider@npm:^0.4.0": - version: 0.4.0 - resolution: "@babel/helper-define-polyfill-provider@npm:0.4.0" +"@babel/helper-define-polyfill-provider@npm:^0.4.1": + version: 0.4.1 + resolution: "@babel/helper-define-polyfill-provider@npm:0.4.1" dependencies: - "@babel/helper-compilation-targets": ^7.17.7 - "@babel/helper-plugin-utils": ^7.16.7 + "@babel/helper-compilation-targets": ^7.22.6 + "@babel/helper-plugin-utils": ^7.22.5 debug: ^4.1.1 lodash.debounce: ^4.0.8 resolve: ^1.14.2 - semver: ^6.1.2 peerDependencies: "@babel/core": ^7.4.0-0 - checksum: 5dca4c5e78457c5ced366bea601efa4e8c69bf5d53b0fe540283897575c49b1b88191c8ef062110de9046e886703ed3270fcda3a87f0886cdbb549204d3ff63f + checksum: 712b440cdd343ac7c4617225f91b0a9db5a7b1c96356b720e011af64ad6c4da9c66889f8d2962a0a2ae2e4ccb6a9b4a210c4a3c8c8ff103846b3d93b61bc6634 languageName: node linkType: hard @@ -221,19 +220,18 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-transforms@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-module-transforms@npm:7.22.5" +"@babel/helper-module-transforms@npm:^7.22.5, @babel/helper-module-transforms@npm:^7.22.9": + version: 7.22.9 + resolution: "@babel/helper-module-transforms@npm:7.22.9" dependencies: "@babel/helper-environment-visitor": ^7.22.5 "@babel/helper-module-imports": ^7.22.5 "@babel/helper-simple-access": ^7.22.5 - "@babel/helper-split-export-declaration": ^7.22.5 + "@babel/helper-split-export-declaration": ^7.22.6 "@babel/helper-validator-identifier": ^7.22.5 - "@babel/template": ^7.22.5 - "@babel/traverse": ^7.22.5 - "@babel/types": ^7.22.5 - checksum: 8985dc0d971fd17c467e8b84fe0f50f3dd8610e33b6c86e5b3ca8e8859f9448bcc5c84e08a2a14285ef388351c0484797081c8f05a03770bf44fc27bf4900e68 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 2751f77660518cf4ff027514d6f4794f04598c6393be7b04b8e46c6e21606e11c19f3f57ab6129a9c21bacdf8b3ffe3af87bb401d972f34af2d0ffde02ac3001 languageName: node linkType: hard @@ -246,7 +244,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.16.7, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": +"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": version: 7.22.5 resolution: "@babel/helper-plugin-utils@npm:7.22.5" checksum: c0fc7227076b6041acd2f0e818145d2e8c41968cc52fb5ca70eed48e21b8fe6dd88a0a91cbddf4951e33647336eb5ae184747ca706817ca3bef5e9e905151ff5 @@ -254,30 +252,28 @@ __metadata: linkType: hard "@babel/helper-remap-async-to-generator@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-remap-async-to-generator@npm:7.22.5" + version: 7.22.9 + resolution: "@babel/helper-remap-async-to-generator@npm:7.22.9" dependencies: "@babel/helper-annotate-as-pure": ^7.22.5 "@babel/helper-environment-visitor": ^7.22.5 - "@babel/helper-wrap-function": ^7.22.5 - "@babel/types": ^7.22.5 + "@babel/helper-wrap-function": ^7.22.9 peerDependencies: "@babel/core": ^7.0.0 - checksum: 1e51dcff1c22e97ea3d22034b77788048eb6d8c6860325bd7a1046b7a7135730cefd93b5c96fd9839d76031095d5ffb6f0cd6ee90a5d69a4c7de980d7f4623d9 + checksum: 05538079447829b13512157491cc77f9cf1ea7e1680e15cff0682c3ed9ee162de0c4862ece20a6d6b2df28177a1520bcfe45993fbeccf2747a81795a7c3f6290 languageName: node linkType: hard -"@babel/helper-replace-supers@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-replace-supers@npm:7.22.5" +"@babel/helper-replace-supers@npm:^7.22.5, @babel/helper-replace-supers@npm:^7.22.9": + version: 7.22.9 + resolution: "@babel/helper-replace-supers@npm:7.22.9" dependencies: "@babel/helper-environment-visitor": ^7.22.5 "@babel/helper-member-expression-to-functions": ^7.22.5 "@babel/helper-optimise-call-expression": ^7.22.5 - "@babel/template": ^7.22.5 - "@babel/traverse": ^7.22.5 - "@babel/types": ^7.22.5 - checksum: af29deff6c6dc3fa2d1a517390716aa3f4d329855e8689f1d5c3cb07c1b898e614a5e175f1826bb58e9ff1480e6552885a71a9a0ba5161787aaafa2c79b216cc + peerDependencies: + "@babel/core": ^7.0.0 + checksum: d41471f56ff2616459d35a5df1900d5f0756ae78b1027040365325ef332d66e08e3be02a9489756d870887585ff222403a228546e93dd7019e19e59c0c0fe586 languageName: node linkType: hard @@ -299,12 +295,12 @@ __metadata: languageName: node linkType: hard -"@babel/helper-split-export-declaration@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-split-export-declaration@npm:7.22.5" +"@babel/helper-split-export-declaration@npm:^7.22.6": + version: 7.22.6 + resolution: "@babel/helper-split-export-declaration@npm:7.22.6" dependencies: "@babel/types": ^7.22.5 - checksum: d10e05a02f49c1f7c578cea63d2ac55356501bbf58856d97ac9bfde4957faee21ae97c7f566aa309e38a256eef58b58e5b670a7f568b362c00e93dfffe072650 + checksum: e141cace583b19d9195f9c2b8e17a3ae913b7ee9b8120246d0f9ca349ca6f03cb2c001fd5ec57488c544347c0bb584afec66c936511e447fd20a360e591ac921 languageName: node linkType: hard @@ -329,26 +325,25 @@ __metadata: languageName: node linkType: hard -"@babel/helper-wrap-function@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-wrap-function@npm:7.22.5" +"@babel/helper-wrap-function@npm:^7.22.9": + version: 7.22.9 + resolution: "@babel/helper-wrap-function@npm:7.22.9" dependencies: "@babel/helper-function-name": ^7.22.5 "@babel/template": ^7.22.5 - "@babel/traverse": ^7.22.5 "@babel/types": ^7.22.5 - checksum: a4ba2d7577ad3ce92fadaa341ffce3b0e4b389808099b07c80847f9be0852f4b42344612bc1b3d1b796ffb75be56d5957c5c56a1734f6aee5ccbb7cd9ab12691 + checksum: 037317dc06dac6593e388738ae1d3e43193bc1d31698f067c0ef3d4dc6f074dbed860ed42aa137b48a67aa7cb87336826c4bdc13189260481bcf67eb7256c789 languageName: node linkType: hard -"@babel/helpers@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helpers@npm:7.22.5" +"@babel/helpers@npm:^7.22.6": + version: 7.22.6 + resolution: "@babel/helpers@npm:7.22.6" dependencies: "@babel/template": ^7.22.5 - "@babel/traverse": ^7.22.5 + "@babel/traverse": ^7.22.6 "@babel/types": ^7.22.5 - checksum: a96e785029dff72f171190943df895ab0f76e17bf3881efd630bc5fae91215042d1c2e9ed730e8e4adf4da6f28b24bd1f54ed93b90ffbca34c197351872a084e + checksum: 5c1f33241fe7bf7709868c2105134a0a86dca26a0fbd508af10a89312b1f77ca38ebae43e50be3b208613c5eacca1559618af4ca236f0abc55d294800faeff30 languageName: node linkType: hard @@ -363,12 +358,12 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.18.4, @babel/parser@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/parser@npm:7.22.5" +"@babel/parser@npm:^7.18.4, @babel/parser@npm:^7.22.5, @babel/parser@npm:^7.22.7": + version: 7.22.7 + resolution: "@babel/parser@npm:7.22.7" bin: parser: ./bin/babel-parser.js - checksum: 470ebba516417ce8683b36e2eddd56dcfecb32c54b9bb507e28eb76b30d1c3e618fd0cfeee1f64d8357c2254514e1a19e32885cfb4e73149f4ae875436a6d59c + checksum: 02209ddbd445831ee8bf966fdf7c29d189ed4b14343a68eb2479d940e7e3846340d7cc6bd654a5f3d87d19dc84f49f50a58cf9363bee249dc5409ff3ba3dab54 languageName: node linkType: hard @@ -396,18 +391,18 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-proposal-decorators@npm:7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-proposal-decorators@npm:7.22.5" +"@babel/plugin-proposal-decorators@npm:7.22.7": + version: 7.22.7 + resolution: "@babel/plugin-proposal-decorators@npm:7.22.7" dependencies: - "@babel/helper-create-class-features-plugin": ^7.22.5 + "@babel/helper-create-class-features-plugin": ^7.22.6 "@babel/helper-plugin-utils": ^7.22.5 "@babel/helper-replace-supers": ^7.22.5 - "@babel/helper-split-export-declaration": ^7.22.5 + "@babel/helper-split-export-declaration": ^7.22.6 "@babel/plugin-syntax-decorators": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: b3807b92b6ffcaba7519a9b2bb59e4b5530873234cd170ff5727414939334fbcae17bbe523df846a103e2fc8ed2d2890d0d9408f073cfc1e90c28ab565c358e5 + checksum: d9d6f7cc8b3f1450963d3f26909af025836189b81e43c48ad455db5db2319beaf4ad2fda5aa12a1afcf856de11ecd5ee6894a9e906e8de8ee445c79102b50d26 languageName: node linkType: hard @@ -675,9 +670,9 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-async-generator-functions@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-async-generator-functions@npm:7.22.5" +"@babel/plugin-transform-async-generator-functions@npm:^7.22.7": + version: 7.22.7 + resolution: "@babel/plugin-transform-async-generator-functions@npm:7.22.7" dependencies: "@babel/helper-environment-visitor": ^7.22.5 "@babel/helper-plugin-utils": ^7.22.5 @@ -685,7 +680,7 @@ __metadata: "@babel/plugin-syntax-async-generators": ^7.8.4 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 32890b69ec5627eb46ee8e084bddc6b98d85b66cae5e015f3a23924611a759789d2ff836406605f5293b5c2bad306b20cb1f5b7a46ed549b07bfec634bcd31f9 + checksum: 57cd2cce3fb696dadf00e88f168683df69e900b92dadeae07429243c43bc21d5ccdc0c2db61cf5c37bd0fbd893fc455466bef6babe4aa5b79d9cb8ba89f40ae7 languageName: node linkType: hard @@ -749,22 +744,22 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-classes@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-classes@npm:7.22.5" +"@babel/plugin-transform-classes@npm:^7.22.6": + version: 7.22.6 + resolution: "@babel/plugin-transform-classes@npm:7.22.6" dependencies: "@babel/helper-annotate-as-pure": ^7.22.5 - "@babel/helper-compilation-targets": ^7.22.5 + "@babel/helper-compilation-targets": ^7.22.6 "@babel/helper-environment-visitor": ^7.22.5 "@babel/helper-function-name": ^7.22.5 "@babel/helper-optimise-call-expression": ^7.22.5 "@babel/helper-plugin-utils": ^7.22.5 "@babel/helper-replace-supers": ^7.22.5 - "@babel/helper-split-export-declaration": ^7.22.5 + "@babel/helper-split-export-declaration": ^7.22.6 globals: ^11.1.0 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 124b1b79180524cc9d08155cecde92c7f2ab0db02cbe0f8befa187ef3c7320909ce1a6d6daf5ce73e8330f9b40cf9991f424c6e572b8dddc1f14e2758fa80d20 + checksum: 8380e855c01033dbc7460d9acfbc1fc37c880350fa798c2de8c594ef818ade0e4c96173ec72f05f2a4549d8d37135e18cb62548352d51557b45a0fb4388d2f3f languageName: node linkType: hard @@ -1057,16 +1052,16 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-optional-chaining@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-optional-chaining@npm:7.22.5" +"@babel/plugin-transform-optional-chaining@npm:^7.22.5, @babel/plugin-transform-optional-chaining@npm:^7.22.6": + version: 7.22.6 + resolution: "@babel/plugin-transform-optional-chaining@npm:7.22.6" dependencies: "@babel/helper-plugin-utils": ^7.22.5 "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 "@babel/plugin-syntax-optional-chaining": ^7.8.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 57b9c05fb22ae881b8a334b184fc6ee966661ed5d1eb4eed8c2fb9a12e68150d90b229efcb1aa777e246999830844fee06d7365f8bb4bb262fdcd23876ff3ea2 + checksum: 9713f7920ed04090c149fc5ec024dd1638e8b97aa4ae3753b93072d84103b8de380afb96d6cf03e53b285420db4f705f3ac13149c6fd54f322b61dc19e33c54f languageName: node linkType: hard @@ -1141,19 +1136,19 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-runtime@npm:7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-runtime@npm:7.22.5" +"@babel/plugin-transform-runtime@npm:7.22.9": + version: 7.22.9 + resolution: "@babel/plugin-transform-runtime@npm:7.22.9" dependencies: "@babel/helper-module-imports": ^7.22.5 "@babel/helper-plugin-utils": ^7.22.5 - babel-plugin-polyfill-corejs2: ^0.4.3 - babel-plugin-polyfill-corejs3: ^0.8.1 - babel-plugin-polyfill-regenerator: ^0.5.0 - semver: ^6.3.0 + babel-plugin-polyfill-corejs2: ^0.4.4 + babel-plugin-polyfill-corejs3: ^0.8.2 + babel-plugin-polyfill-regenerator: ^0.5.1 + semver: ^6.3.1 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 52cf177045b5f61a6cfc36b45aa7629586dc00a28371a09ef03e877a627f520efd51817ad8cceabaaa25f266e069859b36a5ac5018afeaa7f37aafa9325df4d8 + checksum: 2fe5e41f83015ca174feda841d77aa9012fc855c907f9b360a11927f41b100537c8c83487771769147668e797eec26d5294e972b997f4759133cc43a22a43eec languageName: node linkType: hard @@ -1214,16 +1209,16 @@ __metadata: linkType: hard "@babel/plugin-transform-typescript@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-typescript@npm:7.22.5" + version: 7.22.9 + resolution: "@babel/plugin-transform-typescript@npm:7.22.9" dependencies: "@babel/helper-annotate-as-pure": ^7.22.5 - "@babel/helper-create-class-features-plugin": ^7.22.5 + "@babel/helper-create-class-features-plugin": ^7.22.9 "@babel/helper-plugin-utils": ^7.22.5 "@babel/plugin-syntax-typescript": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: d12f1ca1ef1f2a54432eb044d2999705d1205ebe211c2a7f05b12e8eb2d2a461fd7657b5486b2f2f1efe7c0c0dc8e80725b767073d40fe4ae059a7af057b05e4 + checksum: 6d1317a54d093b302599a4bee8ba9865d0de8b7b6ac1a0746c4316231d632f75b7f086e6e78acb9ac95ba12ba3b9da462dc9ca69370abb4603c4cc987f62e67e languageName: node linkType: hard @@ -1274,12 +1269,12 @@ __metadata: languageName: node linkType: hard -"@babel/preset-env@npm:7.22.5, @babel/preset-env@npm:^7.11.0": - version: 7.22.5 - resolution: "@babel/preset-env@npm:7.22.5" +"@babel/preset-env@npm:7.22.9, @babel/preset-env@npm:^7.11.0": + version: 7.22.9 + resolution: "@babel/preset-env@npm:7.22.9" dependencies: - "@babel/compat-data": ^7.22.5 - "@babel/helper-compilation-targets": ^7.22.5 + "@babel/compat-data": ^7.22.9 + "@babel/helper-compilation-targets": ^7.22.9 "@babel/helper-plugin-utils": ^7.22.5 "@babel/helper-validator-option": ^7.22.5 "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ^7.22.5 @@ -1304,13 +1299,13 @@ __metadata: "@babel/plugin-syntax-top-level-await": ^7.14.5 "@babel/plugin-syntax-unicode-sets-regex": ^7.18.6 "@babel/plugin-transform-arrow-functions": ^7.22.5 - "@babel/plugin-transform-async-generator-functions": ^7.22.5 + "@babel/plugin-transform-async-generator-functions": ^7.22.7 "@babel/plugin-transform-async-to-generator": ^7.22.5 "@babel/plugin-transform-block-scoped-functions": ^7.22.5 "@babel/plugin-transform-block-scoping": ^7.22.5 "@babel/plugin-transform-class-properties": ^7.22.5 "@babel/plugin-transform-class-static-block": ^7.22.5 - "@babel/plugin-transform-classes": ^7.22.5 + "@babel/plugin-transform-classes": ^7.22.6 "@babel/plugin-transform-computed-properties": ^7.22.5 "@babel/plugin-transform-destructuring": ^7.22.5 "@babel/plugin-transform-dotall-regex": ^7.22.5 @@ -1335,7 +1330,7 @@ __metadata: "@babel/plugin-transform-object-rest-spread": ^7.22.5 "@babel/plugin-transform-object-super": ^7.22.5 "@babel/plugin-transform-optional-catch-binding": ^7.22.5 - "@babel/plugin-transform-optional-chaining": ^7.22.5 + "@babel/plugin-transform-optional-chaining": ^7.22.6 "@babel/plugin-transform-parameters": ^7.22.5 "@babel/plugin-transform-private-methods": ^7.22.5 "@babel/plugin-transform-private-property-in-object": ^7.22.5 @@ -1353,14 +1348,14 @@ __metadata: "@babel/plugin-transform-unicode-sets-regex": ^7.22.5 "@babel/preset-modules": ^0.1.5 "@babel/types": ^7.22.5 - babel-plugin-polyfill-corejs2: ^0.4.3 - babel-plugin-polyfill-corejs3: ^0.8.1 - babel-plugin-polyfill-regenerator: ^0.5.0 - core-js-compat: ^3.30.2 - semver: ^6.3.0 + babel-plugin-polyfill-corejs2: ^0.4.4 + babel-plugin-polyfill-corejs3: ^0.8.2 + babel-plugin-polyfill-regenerator: ^0.5.1 + core-js-compat: ^3.31.0 + semver: ^6.3.1 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 6d9d09010ababef2ab48c8830770b2a8f45d6cce51db0924a98b0d95a5b1248a99ee07ee61cb5446d8b05b562db99a8af30b3ed194546419fb9b2889b8fd1ed3 + checksum: 6caa2897bbda30c6932aed0a03827deb1337c57108050c9f97dc9a857e1533c7125b168b6d70b9d191965bf05f9f233f0ad20303080505dff7ce39740aaa759d languageName: node linkType: hard @@ -1401,12 +1396,12 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:7.22.5, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.8.4": - version: 7.22.5 - resolution: "@babel/runtime@npm:7.22.5" +"@babel/runtime@npm:7.22.6, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.8.4": + version: 7.22.6 + resolution: "@babel/runtime@npm:7.22.6" dependencies: regenerator-runtime: ^0.13.11 - checksum: 12a50b7de2531beef38840d17af50c55a094253697600cee255311222390c68eed704829308d4fd305e1b3dfbce113272e428e9d9d45b1730e0fede997eaceb1 + checksum: e585338287c4514a713babf4fdb8fc2a67adcebab3e7723a739fc62c79cfda875b314c90fd25f827afb150d781af97bc16c85bfdbfa2889f06053879a1ddb597 languageName: node linkType: hard @@ -1421,21 +1416,21 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/traverse@npm:7.22.5" +"@babel/traverse@npm:^7.22.6, @babel/traverse@npm:^7.22.8": + version: 7.22.8 + resolution: "@babel/traverse@npm:7.22.8" dependencies: "@babel/code-frame": ^7.22.5 - "@babel/generator": ^7.22.5 + "@babel/generator": ^7.22.7 "@babel/helper-environment-visitor": ^7.22.5 "@babel/helper-function-name": ^7.22.5 "@babel/helper-hoist-variables": ^7.22.5 - "@babel/helper-split-export-declaration": ^7.22.5 - "@babel/parser": ^7.22.5 + "@babel/helper-split-export-declaration": ^7.22.6 + "@babel/parser": ^7.22.7 "@babel/types": ^7.22.5 debug: ^4.1.0 globals: ^11.1.0 - checksum: 560931422dc1761f2df723778dcb4e51ce0d02e560cf2caa49822921578f49189a5a7d053b78a32dca33e59be886a6b2200a6e24d4ae9b5086ca0ba803815694 + checksum: a381369bc3eedfd13ed5fef7b884657f1c29024ea7388198149f0edc34bd69ce3966e9f40188d15f56490a5e12ba250ccc485f2882b53d41b054fccefb233e33 languageName: node linkType: hard @@ -1457,9 +1452,9 @@ __metadata: languageName: node linkType: hard -"@codemirror/autocomplete@npm:6.8.1": - version: 6.8.1 - resolution: "@codemirror/autocomplete@npm:6.8.1" +"@codemirror/autocomplete@npm:6.9.0": + version: 6.9.0 + resolution: "@codemirror/autocomplete@npm:6.9.0" dependencies: "@codemirror/language": ^6.0.0 "@codemirror/state": ^6.0.0 @@ -1470,7 +1465,7 @@ __metadata: "@codemirror/state": ^6.0.0 "@codemirror/view": ^6.0.0 "@lezer/common": ^1.0.0 - checksum: 8599cd91defa3fea5276a7f9aff43ced323d9c4401dfb867e43608ba72ded48cb458256c5c784949a6332c0c20ba2fedac16a5708335cd809d269e4ea5076957 + checksum: a5f661944c75f40b02c90a193c9a459c0fd7e335c0ac5973420c19157dfb46010f573c2b70731591fe477e7a2ad10121ff3ae394a72d450946d7b886c28b0368 languageName: node linkType: hard @@ -1500,12 +1495,12 @@ __metadata: languageName: node linkType: hard -"@codemirror/legacy-modes@npm:6.3.2": - version: 6.3.2 - resolution: "@codemirror/legacy-modes@npm:6.3.2" +"@codemirror/legacy-modes@npm:6.3.3": + version: 6.3.3 + resolution: "@codemirror/legacy-modes@npm:6.3.3" dependencies: "@codemirror/language": ^6.0.0 - checksum: fa5f5477fb9e19267251e2ecd3de8c1a4c2512813555bb60111dce3951f2c3f6080a2985a573b7542534ba1d2c34115f7e39ee23fdf8f6f81db6f8ce447c1efc + checksum: 3cd32b0f011b0a193e0948e5901b625f38aa6d9a8b24344531d6e142eb6fbb3e6cb5969429102044f3d04fbe53c4deaebd9f659c05067a0b18d17766290c9e05 languageName: node linkType: hard @@ -1527,14 +1522,14 @@ __metadata: languageName: node linkType: hard -"@codemirror/view@npm:6.14.0, @codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.6.0": - version: 6.14.0 - resolution: "@codemirror/view@npm:6.14.0" +"@codemirror/view@npm:6.15.3, @codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.6.0": + version: 6.15.3 + resolution: "@codemirror/view@npm:6.15.3" dependencies: "@codemirror/state": ^6.1.4 style-mod: ^4.0.0 w3c-keyname: ^2.2.4 - checksum: f8fbb8e8cf1bc23de8cd64b1e645112d13f72cd2f1609fb9047d616908c2189ff518b89f21484371e7a37ba1804288452558e96488791f0c850f62b8e28dc163 + checksum: 048949b1b493a962904a7f77661a939f7c1893a7381022756a135f5dd8daf667f498be1b81da9c37c0e8de85b078ad987c2f75318385c520ed83c95da6313e95 languageName: node linkType: hard @@ -1554,7 +1549,7 @@ __metadata: languageName: node linkType: hard -"@eslint-community/eslint-utils@npm:^4.2.0": +"@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0": version: 4.4.0 resolution: "@eslint-community/eslint-utils@npm:4.4.0" dependencies: @@ -1565,7 +1560,7 @@ __metadata: languageName: node linkType: hard -"@eslint-community/regexpp@npm:^4.4.0": +"@eslint-community/regexpp@npm:^4.4.0, @eslint-community/regexpp@npm:^4.5.1": version: 4.5.1 resolution: "@eslint-community/regexpp@npm:4.5.1" checksum: 6d901166d64998d591fab4db1c2f872981ccd5f6fe066a1ad0a93d4e11855ecae6bfb76660869a469563e8882d4307228cebd41142adb409d182f2966771e57e @@ -2005,12 +2000,12 @@ __metadata: linkType: hard "@jridgewell/source-map@npm:^0.3.3": - version: 0.3.3 - resolution: "@jridgewell/source-map@npm:0.3.3" + version: 0.3.5 + resolution: "@jridgewell/source-map@npm:0.3.5" dependencies: "@jridgewell/gen-mapping": ^0.3.0 "@jridgewell/trace-mapping": ^0.3.9 - checksum: ae1302146339667da5cd6541260ecbef46ae06819a60f88da8f58b3e64682f787c09359933d050dea5d2173ea7fa40f40dd4d4e7a8d325c5892cccd99aaf8959 + checksum: 1ad4dec0bdafbade57920a50acec6634f88a0eb735851e0dda906fa9894e7f0549c492678aad1a10f8e144bfe87f238307bf2a914a1bc85b7781d345417e9f6f languageName: node linkType: hard @@ -2021,7 +2016,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.13": +"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.13, @jridgewell/sourcemap-codec@npm:^1.4.15": version: 1.4.15 resolution: "@jridgewell/sourcemap-codec@npm:1.4.15" checksum: b881c7e503db3fc7f3c1f35a1dd2655a188cc51a3612d76efc8a6eb74728bef5606e6758ee77423e564092b4a518aba569bbb21c9bac5ab7a35b0c6ae7e344c8 @@ -2071,11 +2066,11 @@ __metadata: linkType: hard "@lezer/lr@npm:^1.0.0": - version: 1.3.6 - resolution: "@lezer/lr@npm:1.3.6" + version: 1.3.9 + resolution: "@lezer/lr@npm:1.3.9" dependencies: "@lezer/common": ^1.0.0 - checksum: b2bbcfecc01bd9c801f3ee636ceda333adbbea1f274017cec6f315a23346e7a035a984f325d4f1cd14b157d74d28badda6f794514c29a0b078f7fb3357cdfc32 + checksum: d10982bae6c0b2f5a3ab8710a41dc689a4f9e81afafd3d2de4f0bec169f5c3fc9a321c0e90010a51682d41a6755ae90e1f3199134ff194b3ff4058ea5bcdf353 languageName: node linkType: hard @@ -2105,13 +2100,13 @@ __metadata: languageName: node linkType: hard -"@lit-labs/virtualizer@npm:2.0.3": - version: 2.0.3 - resolution: "@lit-labs/virtualizer@npm:2.0.3" +"@lit-labs/virtualizer@npm:2.0.4": + version: 2.0.4 + resolution: "@lit-labs/virtualizer@npm:2.0.4" dependencies: lit: ^2.7.0 tslib: ^2.0.3 - checksum: 594b89aca53210a6c0127c331fd05b795074df41aba086b63cb13ad5990e6962b86ca8403fe3a673e3bf46735e2def75d5412afe582702346fbd92a3331d34e1 + checksum: a830318c50a4bc404829ab5ca3b81fa1bd72cd63bd0195c3e224dfe16cdc0c54335cd6ced222310b4a8aed438ca9ef8481e29e030b7f1a784345ffd7503439a0 languageName: node linkType: hard @@ -3158,14 +3153,14 @@ __metadata: languageName: node linkType: hard -"@material/web@npm:=1.0.0-pre.12": - version: 1.0.0-pre.12 - resolution: "@material/web@npm:1.0.0-pre.12" +"@material/web@npm:=1.0.0-pre.13": + version: 1.0.0-pre.13 + resolution: "@material/web@npm:1.0.0-pre.13" dependencies: lit: ^2.7.4 safevalues: ^0.4.3 tslib: ^2.4.0 - checksum: 21132f90e004c84745bd9ba15aacc0ec74ee5c67e8dd610da14220cf0fa129882a82c409094b39226a82f9eaae0c1fbea9a6df07a6a056fc2ef5b771a14b078a + checksum: f477ea3a50991d90bfd1491d35b26393deab43a735053b873e50e53fa34e599c552acc19e3fcaebcb44cbabcf08529b6970ec11a552e2a93146fe0a230e3a4b3 languageName: node linkType: hard @@ -3183,6 +3178,15 @@ __metadata: languageName: node linkType: hard +"@nicolo-ribaudo/semver-v6@npm:^6.3.3": + version: 6.3.3 + resolution: "@nicolo-ribaudo/semver-v6@npm:6.3.3" + bin: + semver: bin/semver.js + checksum: 8290855b1591477d2298364541fda64fafd4acc110b387067a71c9b05f4105c0a4ac079857ae9cd107c42ee884e8724a406b5116f069575e02d7ab87a35a5272 + languageName: node + linkType: hard + "@nodelib/fs.scandir@npm:2.1.5": version: 2.1.5 resolution: "@nodelib/fs.scandir@npm:2.1.5" @@ -3219,70 +3223,59 @@ __metadata: languageName: node linkType: hard -"@octokit/auth-oauth-device@npm:5.0.2": - version: 5.0.2 - resolution: "@octokit/auth-oauth-device@npm:5.0.2" +"@octokit/auth-oauth-device@npm:6.0.0": + version: 6.0.0 + resolution: "@octokit/auth-oauth-device@npm:6.0.0" dependencies: - "@octokit/oauth-methods": ^3.0.1 - "@octokit/request": ^7.0.0 - "@octokit/types": ^10.0.0 + "@octokit/oauth-methods": ^4.0.0 + "@octokit/request": ^8.0.0 + "@octokit/types": ^11.0.0 universal-user-agent: ^6.0.0 - checksum: b625a2d7604351e52df46d3fdad04d1eb2ec68f80bce065047691ea83044967ef1e7dd0a70e9f8aab818d8c5ecf7f2550d2aa029ffdba85e0ff8c0ce2e25736a + checksum: ba6e46a42a68ca0e6d345b10de257b4e0764e6abeedfa3b7bd27bbe4336cbabf3dc081c97eb860939e4fbcb9827c62be5c4396023342db4717f254f06cdbba43 languageName: node linkType: hard -"@octokit/auth-token@npm:^3.0.0": - version: 3.0.4 - resolution: "@octokit/auth-token@npm:3.0.4" - checksum: 42f533a873d4192e6df406b3176141c1f95287423ebdc4cf23a38bb77ee00ccbc0e60e3fbd5874234fc2ed2e67bbc6035e3b0561dacc1d078adb5c4ced3579e3 +"@octokit/auth-token@npm:^4.0.0": + version: 4.0.0 + resolution: "@octokit/auth-token@npm:4.0.0" + checksum: d78f4dc48b214d374aeb39caec4fdbf5c1e4fd8b9fcb18f630b1fe2cbd5a880fca05445f32b4561f41262cb551746aeb0b49e89c95c6dd99299706684d0cae2f languageName: node linkType: hard -"@octokit/core@npm:^4.2.1": - version: 4.2.4 - resolution: "@octokit/core@npm:4.2.4" +"@octokit/core@npm:^5.0.0": + version: 5.0.0 + resolution: "@octokit/core@npm:5.0.0" dependencies: - "@octokit/auth-token": ^3.0.0 - "@octokit/graphql": ^5.0.0 - "@octokit/request": ^6.0.0 - "@octokit/request-error": ^3.0.0 - "@octokit/types": ^9.0.0 + "@octokit/auth-token": ^4.0.0 + "@octokit/graphql": ^7.0.0 + "@octokit/request": ^8.0.2 + "@octokit/request-error": ^5.0.0 + "@octokit/types": ^11.0.0 before-after-hook: ^2.2.0 universal-user-agent: ^6.0.0 - checksum: ac8ab47440a31b0228a034aacac6994b64d6b073ad5b688b4c5157fc5ee0d1af1c926e6087bf17fd7244ee9c5998839da89065a90819bde4a97cb77d4edf58a6 + checksum: 1a5d1112a2403d146aa1db7aaf81a31192ef6b0310a1e6f68c3e439fded22bd4b3a930f5071585e6ca0f2f5e7fc4a1aac68910525b71b03732c140e362d26a33 languageName: node linkType: hard -"@octokit/endpoint@npm:^7.0.0": - version: 7.0.6 - resolution: "@octokit/endpoint@npm:7.0.6" +"@octokit/endpoint@npm:^9.0.0": + version: 9.0.0 + resolution: "@octokit/endpoint@npm:9.0.0" dependencies: - "@octokit/types": ^9.0.0 + "@octokit/types": ^11.0.0 is-plain-object: ^5.0.0 universal-user-agent: ^6.0.0 - checksum: 7caebf30ceec50eb7f253341ed419df355232f03d4638a95c178ee96620400db7e4a5e15d89773fe14db19b8653d4ab4cc81b2e93ca0c760b4e0f7eb7ad80301 + checksum: 0e402c4d0fbe5b8053630cedb30dde5074bb6410828a05dc93d7e0fdd6c17f9a44b66586ef1a4e4ee0baa8d34ef7d6f535e2f04d9ea42909b7fc7ff55ce56a48 languageName: node linkType: hard -"@octokit/endpoint@npm:^8.0.0": - version: 8.0.1 - resolution: "@octokit/endpoint@npm:8.0.1" +"@octokit/graphql@npm:^7.0.0": + version: 7.0.1 + resolution: "@octokit/graphql@npm:7.0.1" dependencies: - "@octokit/types": ^10.0.0 - is-plain-object: ^5.0.0 + "@octokit/request": ^8.0.1 + "@octokit/types": ^11.0.0 universal-user-agent: ^6.0.0 - checksum: 0cff7c972d8304cb59c4cc28016c15bca05e6d7e9e2d9b00af88ce05bf9abdfdb17025f38080162a71ea15b21c740bcb5079361396f18a24bbe55134c504a581 - languageName: node - linkType: hard - -"@octokit/graphql@npm:^5.0.0": - version: 5.0.6 - resolution: "@octokit/graphql@npm:5.0.6" - dependencies: - "@octokit/request": ^6.0.0 - "@octokit/types": ^9.0.0 - universal-user-agent: ^6.0.0 - checksum: 7be545d348ef31dcab0a2478dd64d5746419a2f82f61459c774602bcf8a9b577989c18001f50b03f5f61a3d9e34203bdc021a4e4d75ff2d981e8c9c09cf8a65c + checksum: 7ee907987b1b8312c6f870c44455cbd3eed805bb1a4095038f4e7e62ee2e006bd766f2a71dfbe56b870cd8f7558309c602f00d3e252fe59578f4acf6249a4f17 languageName: node linkType: hard @@ -3293,16 +3286,16 @@ __metadata: languageName: node linkType: hard -"@octokit/oauth-methods@npm:^3.0.1": - version: 3.0.1 - resolution: "@octokit/oauth-methods@npm:3.0.1" +"@octokit/oauth-methods@npm:^4.0.0": + version: 4.0.0 + resolution: "@octokit/oauth-methods@npm:4.0.0" dependencies: "@octokit/oauth-authorization-url": ^6.0.2 - "@octokit/request": ^7.0.0 - "@octokit/request-error": ^4.0.1 - "@octokit/types": ^10.0.0 + "@octokit/request": ^8.0.2 + "@octokit/request-error": ^5.0.0 + "@octokit/types": ^11.0.0 btoa-lite: ^1.0.0 - checksum: ad327084f97d2f3be270d8957545dbd06c35df3e99d8e58702217beb7ac3574c361b49dfe28ba5d96b7f1911ac9c8e26ae07d6180a0598eef8b7fab4b0fe4ad5 + checksum: 623f3031f56f5bfd6f142f9215bf47ba418b2f7fd9eb72d3e68cdd2b2c81345021b692edd18ad055df85e71e35497002e1fc4816235ed520dd71e677885c99cc languageName: node linkType: hard @@ -3313,134 +3306,92 @@ __metadata: languageName: node linkType: hard -"@octokit/plugin-paginate-rest@npm:^6.1.2": - version: 6.1.2 - resolution: "@octokit/plugin-paginate-rest@npm:6.1.2" +"@octokit/plugin-paginate-rest@npm:^8.0.0": + version: 8.0.0 + resolution: "@octokit/plugin-paginate-rest@npm:8.0.0" dependencies: - "@octokit/tsconfig": ^1.0.2 - "@octokit/types": ^9.2.3 + "@octokit/types": ^11.0.0 peerDependencies: - "@octokit/core": ">=4" - checksum: a7b3e686c7cbd27ec07871cde6e0b1dc96337afbcef426bbe3067152a17b535abd480db1861ca28c88d93db5f7bfdbcadd0919ead19818c28a69d0e194038065 + "@octokit/core": ">=5" + checksum: b5d7cee50523862c6ce7be057f7200e14ee4dcded462f27304c822c960a37efa23ed51080ea879f5d1e56e78f74baa17d2ce32eed5d726794abc35755777e32c languageName: node linkType: hard -"@octokit/plugin-request-log@npm:^1.0.4": - version: 1.0.4 - resolution: "@octokit/plugin-request-log@npm:1.0.4" +"@octokit/plugin-request-log@npm:^4.0.0": + version: 4.0.0 + resolution: "@octokit/plugin-request-log@npm:4.0.0" peerDependencies: - "@octokit/core": ">=3" - checksum: 2086db00056aee0f8ebd79797b5b57149ae1014e757ea08985b71eec8c3d85dbb54533f4fd34b6b9ecaa760904ae6a7536be27d71e50a3782ab47809094bfc0c + "@octokit/core": ">=5" + checksum: 2a8a6619640942092009a9248ceeb163ce01c978e2d7b2a7eb8686bd09a04b783c4cd9071eebb16652d233587abcde449a02ce4feabc652f0a171615fb3e9946 languageName: node linkType: hard -"@octokit/plugin-rest-endpoint-methods@npm:^7.1.2": - version: 7.2.3 - resolution: "@octokit/plugin-rest-endpoint-methods@npm:7.2.3" +"@octokit/plugin-rest-endpoint-methods@npm:^9.0.0": + version: 9.0.0 + resolution: "@octokit/plugin-rest-endpoint-methods@npm:9.0.0" dependencies: - "@octokit/types": ^10.0.0 + "@octokit/types": ^11.0.0 peerDependencies: - "@octokit/core": ">=3" - checksum: 21dfb98514dbe900c29cddb13b335bbce43d613800c6b17eba3c1fd31d17e69c1960f3067f7bf864bb38fdd5043391f4a23edee42729d8c7fbabd00569a80336 + "@octokit/core": ">=5" + checksum: 8795cb29be042c839098886a03c2ec6051e3fd7a29f16f4f8a487aa2d85ceb00df8a4432499a43af550369bd730ce9b1b9d7eeff768745b80a3e67698ca9a5dd languageName: node linkType: hard -"@octokit/plugin-retry@npm:5.0.4": - version: 5.0.4 - resolution: "@octokit/plugin-retry@npm:5.0.4" +"@octokit/plugin-retry@npm:6.0.0": + version: 6.0.0 + resolution: "@octokit/plugin-retry@npm:6.0.0" dependencies: - "@octokit/request-error": ^4.0.1 - "@octokit/types": ^10.0.0 + "@octokit/request-error": ^5.0.0 + "@octokit/types": ^11.0.0 bottleneck: ^2.15.3 peerDependencies: - "@octokit/core": ">=3" - checksum: 0c5645613f7ff758ac126da11ba20b4d49e4067676e30808f5ee3ee471adbd2ccfdea2200adfa5a4663b207964b3d60987f4c5e8682fb275bf134b33f2ef5178 + "@octokit/core": ">=5" + checksum: 84c047309d6b3ad8d796cd6aca9a73c61ebea3894a01067ec6bd40d6ba9aaab779a1085749c04f90b25c0fc3a100c6553474d830e5c2e0dde4ffc42b5e0a2e89 languageName: node linkType: hard -"@octokit/request-error@npm:^3.0.0": - version: 3.0.3 - resolution: "@octokit/request-error@npm:3.0.3" +"@octokit/request-error@npm:^5.0.0": + version: 5.0.0 + resolution: "@octokit/request-error@npm:5.0.0" dependencies: - "@octokit/types": ^9.0.0 + "@octokit/types": ^11.0.0 deprecation: ^2.0.0 once: ^1.4.0 - checksum: 5db0b514732686b627e6ed9ef1ccdbc10501f1b271a9b31f784783f01beee70083d7edcfeb35fbd7e569fa31fdd6762b1ff6b46101700d2d97e7e48e749520d0 + checksum: 2012eca66f6b8fa4038b3bfe81d65a7134ec58e2caf45d229aca13b9653ab260abd95229bd1a8c11180ee0bcf738e2556831a85de28f39b175175653c3b79fdd languageName: node linkType: hard -"@octokit/request-error@npm:^4.0.1": - version: 4.0.2 - resolution: "@octokit/request-error@npm:4.0.2" +"@octokit/request@npm:^8.0.0, @octokit/request@npm:^8.0.1, @octokit/request@npm:^8.0.2": + version: 8.1.1 + resolution: "@octokit/request@npm:8.1.1" dependencies: - "@octokit/types": ^10.0.0 - deprecation: ^2.0.0 - once: ^1.4.0 - checksum: 9510078f718be08cf74e7b04b45f67aa545a388787192ff1cd3ca0d066499963d641bf1fea76ef47d2657a55f0cf3e612e46bbf4f33a96436415d30a2e3bb00a - languageName: node - linkType: hard - -"@octokit/request@npm:^6.0.0": - version: 6.2.8 - resolution: "@octokit/request@npm:6.2.8" - dependencies: - "@octokit/endpoint": ^7.0.0 - "@octokit/request-error": ^3.0.0 - "@octokit/types": ^9.0.0 - is-plain-object: ^5.0.0 - node-fetch: ^2.6.7 - universal-user-agent: ^6.0.0 - checksum: 3747106f50d7c462131ff995b13defdd78024b7becc40283f4ac9ea0af2391ff33a0bb476a05aa710346fe766d20254979079a1d6f626112015ba271fe38f3e2 - languageName: node - linkType: hard - -"@octokit/request@npm:^7.0.0": - version: 7.0.0 - resolution: "@octokit/request@npm:7.0.0" - dependencies: - "@octokit/endpoint": ^8.0.0 - "@octokit/request-error": ^4.0.1 - "@octokit/types": ^10.0.0 + "@octokit/endpoint": ^9.0.0 + "@octokit/request-error": ^5.0.0 + "@octokit/types": ^11.1.0 is-plain-object: ^5.0.0 universal-user-agent: ^6.0.0 - checksum: d3b8ac25c3702bb69c5b345f7a9f16b158209db7e244cc2d60dbcbfbaf1edec8252d78885de3607ee85eb86db7c1d2e07fa2515ba6e25cf2880440c0df5e918a + checksum: dec3ba2cba14739159cd8d1653ad8ac6d58095e4ac294d312d20ce2c63c60c3cad2e5499137244dba3d681fd5cd7f74b4b5d4df024a19c0ee1831204e5a3a894 languageName: node linkType: hard -"@octokit/rest@npm:19.0.13": - version: 19.0.13 - resolution: "@octokit/rest@npm:19.0.13" +"@octokit/rest@npm:20.0.1": + version: 20.0.1 + resolution: "@octokit/rest@npm:20.0.1" dependencies: - "@octokit/core": ^4.2.1 - "@octokit/plugin-paginate-rest": ^6.1.2 - "@octokit/plugin-request-log": ^1.0.4 - "@octokit/plugin-rest-endpoint-methods": ^7.1.2 - checksum: ca1553e3fe46efabffef60e68e4a228d4cc0f0d545daf7f019560f666d3e934c6f3a6402a42bbd786af4f3c0a6e69380776312f01b7d52998fe1bbdd1b068f69 + "@octokit/core": ^5.0.0 + "@octokit/plugin-paginate-rest": ^8.0.0 + "@octokit/plugin-request-log": ^4.0.0 + "@octokit/plugin-rest-endpoint-methods": ^9.0.0 + checksum: 9fb2e154a498e00598379b09d76cc7b67b3801e9c97d753f1a76e1163924188bf4cb1411ec152a038ae91e97b86d7146ff220b05adfb6e500e2300c87e14100a languageName: node linkType: hard -"@octokit/tsconfig@npm:^1.0.2": - version: 1.0.2 - resolution: "@octokit/tsconfig@npm:1.0.2" - checksum: 74d56f3e9f326a8dd63700e9a51a7c75487180629c7a68bbafee97c612fbf57af8347369bfa6610b9268a3e8b833c19c1e4beb03f26db9a9dce31f6f7a19b5b1 - languageName: node - linkType: hard - -"@octokit/types@npm:^10.0.0": - version: 10.0.0 - resolution: "@octokit/types@npm:10.0.0" +"@octokit/types@npm:^11.0.0, @octokit/types@npm:^11.1.0": + version: 11.1.0 + resolution: "@octokit/types@npm:11.1.0" dependencies: "@octokit/openapi-types": ^18.0.0 - checksum: 8aafba2ff0cd2435fb70c291bf75ed071c0fa8a865cf6169648732068a35dec7b85a345851f18920ec5f3e94ee0e954988485caac0da09ec3f6781cc44fe153a - languageName: node - linkType: hard - -"@octokit/types@npm:^9.0.0, @octokit/types@npm:^9.2.3": - version: 9.3.2 - resolution: "@octokit/types@npm:9.3.2" - dependencies: - "@octokit/openapi-types": ^18.0.0 - checksum: f55d096aaed3e04b8308d4422104fb888f355988056ba7b7ef0a4c397b8a3e54290d7827b06774dbe0c9ce55280b00db486286954f9c265aa6b03091026d9da8 + checksum: 72627a94ddaf7bc14db06572bcde67649aad608cd86548818380db9305f4c0ca9ca078a62dd883858a267e8ec8fd596a0fce416aa04197c439b9548efef609a7 languageName: node linkType: hard @@ -3895,9 +3846,9 @@ __metadata: languageName: node linkType: hard -"@rollup/plugin-commonjs@npm:25.0.2": - version: 25.0.2 - resolution: "@rollup/plugin-commonjs@npm:25.0.2" +"@rollup/plugin-commonjs@npm:25.0.3": + version: 25.0.3 + resolution: "@rollup/plugin-commonjs@npm:25.0.3" dependencies: "@rollup/pluginutils": ^5.0.1 commondir: ^1.0.1 @@ -3910,7 +3861,7 @@ __metadata: peerDependenciesMeta: rollup: optional: true - checksum: d8c4e22d264c5b9286f697653c2f9288149c0fe0169d49b83b5dc8b542f96cc0b9113da3f30d241f2f277513fbf3f8c207d95def5559eb3800190f1872add794 + checksum: 1b94218cc80364d218e5d526e9199620151fe8ac489abc293a75741af5ffb2bfa90da06cffc4a1b9a4091a6f8cda63a6f7c557881b12188f9e0a05f08c147fd0 languageName: node linkType: hard @@ -4152,12 +4103,12 @@ __metadata: linkType: hard "@types/chrome@npm:*": - version: 0.0.237 - resolution: "@types/chrome@npm:0.0.237" + version: 0.0.241 + resolution: "@types/chrome@npm:0.0.241" dependencies: "@types/filesystem": "*" "@types/har-format": "*" - checksum: 9dfb0070065ca4667ef2fa9ec45af2f604b9ba98b6429d38607c6bfcc8dc2178e83eea4eeedbe88a8299dfe9dda029c9341e454c4eff7b715b90e9d5fc7b990d + checksum: af6cf474ed120b046001c0edf50bb752191369d5205d0b2d1ebcb7548db6b87183a098ee7ab77db1a441eacbf36fbfc3cd5b04a9642a99180a13018ced400984 languageName: node linkType: hard @@ -4233,12 +4184,12 @@ __metadata: linkType: hard "@types/eslint@npm:*": - version: 8.40.2 - resolution: "@types/eslint@npm:8.40.2" + version: 8.44.0 + resolution: "@types/eslint@npm:8.44.0" dependencies: "@types/estree": "*" "@types/json-schema": "*" - checksum: a4780e45e677e3af21c44a900846996cb6d9ae8f71d51940942a047163ae93a05444392c005f491ed46aa169f3b25f8be125ab42c5d8bdb571154bf62a7c828a + checksum: 2655f409a4ecdd64bb9dd9eb6715e7a2ac30c0e7f902b414e10dbe9d6d497baa5a0f13105e1f7bd5ad7a913338e2ab4bed1faf192a7a0d27d1acd45ba79d3f69 languageName: node linkType: hard @@ -4373,7 +4324,7 @@ __metadata: languageName: node linkType: hard -"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9": +"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.12, @types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9": version: 7.0.12 resolution: "@types/json-schema@npm:7.0.12" checksum: 00239e97234eeb5ceefb0c1875d98ade6e922bfec39dd365ec6bd360b5c2f825e612ac4f6e5f1d13601b8b30f378f15e6faa805a3a732f4a1bbe61915163d293 @@ -4438,11 +4389,11 @@ __metadata: linkType: hard "@types/lodash-es@npm:^4.17.4": - version: 4.17.7 - resolution: "@types/lodash-es@npm:4.17.7" + version: 4.17.8 + resolution: "@types/lodash-es@npm:4.17.8" dependencies: "@types/lodash": "*" - checksum: 4b1f39fd1d921311c37a846c0e0df9d1fa23e27448a6ad1efd7574e703abd2b2fa5e8f3b5037146000f167ba231d0d01e52747d902654151b4ceeff9f2a9b380 + checksum: 36356169a1862e2a1b09cde3b11b3790ab2c2e477778d70f825b216479ea93bd1a960767dbefcd00d6604312170a1b15209f0fa1c35ddf8861bc233c9b0d3e56 languageName: node linkType: hard @@ -4453,10 +4404,10 @@ __metadata: languageName: node linkType: hard -"@types/luxon@npm:3.3.0": - version: 3.3.0 - resolution: "@types/luxon@npm:3.3.0" - checksum: f7e3a89fc3ca404fbc3ea538653ed6860bc28f570a8c4d6d24449b89b9b553b7d6ad6cc94a9e129c5b8c9a2b97f0c365b3017f811e59c4a859a9c219a1c918e0 +"@types/luxon@npm:3.3.1": + version: 3.3.1 + resolution: "@types/luxon@npm:3.3.1" + checksum: da8f6158edacae1430f3eca5f4ab4891200ffb34aa521ef6bae407a3c50b3854907098bc4535fb2a66a2779738f3c6c48fdfd86f01117a6f4844b18536cdb7c0 languageName: node linkType: hard @@ -4496,9 +4447,9 @@ __metadata: linkType: hard "@types/node@npm:*": - version: 20.3.1 - resolution: "@types/node@npm:20.3.1" - checksum: 63a393ab6d947be17320817b35d7277ef03728e231558166ed07ee30b09fd7c08861be4d746f10fdc63ca7912e8cd023939d4eab887ff6580ff704ff24ed810c + version: 20.4.2 + resolution: "@types/node@npm:20.4.2" + checksum: 99e544ea7560d51f01f95627fc40394c24a13da8f041121a0da13e4ef0a2aa332932eaf9a5e8d0e30d1c07106e96a183be392cbba62e8cf0bf6a085d5c0f4149 languageName: node linkType: hard @@ -4592,7 +4543,7 @@ __metadata: languageName: node linkType: hard -"@types/semver@npm:^7.3.12": +"@types/semver@npm:^7.5.0": version: 7.5.0 resolution: "@types/semver@npm:7.5.0" checksum: 0a64b9b9c7424d9a467658b18dd70d1d781c2d6f033096a6e05762d20ebbad23c1b69b0083b0484722aabf35640b78ccc3de26368bcae1129c87e9df028a22e2 @@ -4628,12 +4579,13 @@ __metadata: linkType: hard "@types/serve-static@npm:*, @types/serve-static@npm:^1.13.10": - version: 1.15.1 - resolution: "@types/serve-static@npm:1.15.1" + version: 1.15.2 + resolution: "@types/serve-static@npm:1.15.2" dependencies: + "@types/http-errors": "*" "@types/mime": "*" "@types/node": "*" - checksum: 2e078bdc1e458c7dfe69e9faa83cc69194b8896cce57cb745016580543c7ab5af07fdaa8ac1765eb79524208c81017546f66056f44d1204f812d72810613de36 + checksum: 15c261dbfc57890f7cc17c04d5b22b418dfa0330c912b46c5d8ae2064da5d6f844ef7f41b63c7f4bbf07675e97ebe6ac804b032635ec742ae45d6f1274259b3e languageName: node linkType: hard @@ -4695,247 +4647,249 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:5.60.1": - version: 5.60.1 - resolution: "@typescript-eslint/eslint-plugin@npm:5.60.1" +"@typescript-eslint/eslint-plugin@npm:6.1.0": + version: 6.1.0 + resolution: "@typescript-eslint/eslint-plugin@npm:6.1.0" dependencies: - "@eslint-community/regexpp": ^4.4.0 - "@typescript-eslint/scope-manager": 5.60.1 - "@typescript-eslint/type-utils": 5.60.1 - "@typescript-eslint/utils": 5.60.1 + "@eslint-community/regexpp": ^4.5.1 + "@typescript-eslint/scope-manager": 6.1.0 + "@typescript-eslint/type-utils": 6.1.0 + "@typescript-eslint/utils": 6.1.0 + "@typescript-eslint/visitor-keys": 6.1.0 debug: ^4.3.4 - grapheme-splitter: ^1.0.4 - ignore: ^5.2.0 + graphemer: ^1.4.0 + ignore: ^5.2.4 + natural-compare: ^1.4.0 natural-compare-lite: ^1.4.0 - semver: ^7.3.7 - tsutils: ^3.21.0 + semver: ^7.5.4 + ts-api-utils: ^1.0.1 peerDependencies: - "@typescript-eslint/parser": ^5.0.0 - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + "@typescript-eslint/parser": ^6.0.0 || ^6.0.0-alpha + eslint: ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 6ea3fdc64b216ee709318bfce1573cd8d90836150f0075aaa8755c347541af9ec026043e538a3264d28d1b32ff49b1fd7c6163826b8513f19f0957fefccf7752 + checksum: e1f05d8d49041b47cdbea8fc80f87f03dc0f7273deb2f34f73661831572fe62976ab3780972496428ce6fa31d3f53236a4c90cd9948d45f5004631edbfa3d42a languageName: node linkType: hard -"@typescript-eslint/parser@npm:5.60.1": - version: 5.60.1 - resolution: "@typescript-eslint/parser@npm:5.60.1" +"@typescript-eslint/parser@npm:6.1.0": + version: 6.1.0 + resolution: "@typescript-eslint/parser@npm:6.1.0" dependencies: - "@typescript-eslint/scope-manager": 5.60.1 - "@typescript-eslint/types": 5.60.1 - "@typescript-eslint/typescript-estree": 5.60.1 + "@typescript-eslint/scope-manager": 6.1.0 + "@typescript-eslint/types": 6.1.0 + "@typescript-eslint/typescript-estree": 6.1.0 + "@typescript-eslint/visitor-keys": 6.1.0 debug: ^4.3.4 peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + eslint: ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 08f1552ab0da178524a8de3654d2fb7c8ecb9efdad8e771c9cbf4af555c42e77d17b2c182d139a531cc76c3cabd091d1d25024c2c215cb809dca8b147c8a493c + checksum: dc59cda4396ca09e3aa2bd5b99d8ef9526df56567d4a9b953668102116db975dfb2426c3369560a2b02e083d49e43b4cebb252144d175e900096eb0b17f7ae3c languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:5.60.1": - version: 5.60.1 - resolution: "@typescript-eslint/scope-manager@npm:5.60.1" +"@typescript-eslint/scope-manager@npm:6.1.0": + version: 6.1.0 + resolution: "@typescript-eslint/scope-manager@npm:6.1.0" dependencies: - "@typescript-eslint/types": 5.60.1 - "@typescript-eslint/visitor-keys": 5.60.1 - checksum: 32c0786123f12fbb861aba3527471134a2e9978c7f712e0d7650080651870903482aed72a55f81deba9493118c1ca3c57edaaaa75d7acd9892818e3e9cc341ef + "@typescript-eslint/types": 6.1.0 + "@typescript-eslint/visitor-keys": 6.1.0 + checksum: 57c73b8713be79abebbcfef1d58f78a820ea88a5c37a44d2c9a76130216d9ee824134fae215dde794121cfaf1284370da77e1e5184ba71812aebb1a8cf39f325 languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:5.60.1": - version: 5.60.1 - resolution: "@typescript-eslint/type-utils@npm:5.60.1" +"@typescript-eslint/type-utils@npm:6.1.0": + version: 6.1.0 + resolution: "@typescript-eslint/type-utils@npm:6.1.0" dependencies: - "@typescript-eslint/typescript-estree": 5.60.1 - "@typescript-eslint/utils": 5.60.1 + "@typescript-eslint/typescript-estree": 6.1.0 + "@typescript-eslint/utils": 6.1.0 debug: ^4.3.4 - tsutils: ^3.21.0 + ts-api-utils: ^1.0.1 peerDependencies: - eslint: "*" + eslint: ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true - checksum: f8d5f87b5441d5c671f69631efd103f5f45e0cb7dbe0131a5b4234a5208ac845041219e8baaa3adc341e82a602165dd6fabf4fd06964d0109d0875425c8ac918 + checksum: 83b2ffcf3aa297b60deb2e9ddd946b9c15cc55d0727dfc8a3447e8e5402428f6ee3fc67fb9d5d8ade25da4069ca77e23777caf02bcacd2a1e75b66cfc4d76579 languageName: node linkType: hard -"@typescript-eslint/types@npm:5.60.1": - version: 5.60.1 - resolution: "@typescript-eslint/types@npm:5.60.1" - checksum: 766b6c857493b72a8f515e6a8e409476a317b7a7f0401fbcdf18f417839fca004dcaf06f58eb5ba00777e3ca9c68cd2f56fda79f3a8eb8a418095b5b1f625712 +"@typescript-eslint/types@npm:6.1.0": + version: 6.1.0 + resolution: "@typescript-eslint/types@npm:6.1.0" + checksum: c1f55ebfda7af5e63077beb65fe5a82de7ae7afb913a4ebfb023f2889d5ec06f75b6ebca6ee45d6d205508a52fa5a6bf5821182c3e7e4400ac9304083b88f139 languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:5.60.1": - version: 5.60.1 - resolution: "@typescript-eslint/typescript-estree@npm:5.60.1" +"@typescript-eslint/typescript-estree@npm:6.1.0": + version: 6.1.0 + resolution: "@typescript-eslint/typescript-estree@npm:6.1.0" dependencies: - "@typescript-eslint/types": 5.60.1 - "@typescript-eslint/visitor-keys": 5.60.1 + "@typescript-eslint/types": 6.1.0 + "@typescript-eslint/visitor-keys": 6.1.0 debug: ^4.3.4 globby: ^11.1.0 is-glob: ^4.0.3 - semver: ^7.3.7 - tsutils: ^3.21.0 + semver: ^7.5.4 + ts-api-utils: ^1.0.1 peerDependenciesMeta: typescript: optional: true - checksum: 5bb9d08c3cbc303fc64647878cae37283c4cfa9e3ed00da02ee25dc2e46798a1ad6964c9f04086f0134716671357e6569a65ea0ae75f0f3ff94ae67666385c6f + checksum: 42729b8952a78ff9fc7d3833e16de25f1a3502461ebe5d09a28fb4375c8e5978dde0dd1f8a7973bf7470ff9023cce84de82e968b02a09f54a0f753d21d9127e8 languageName: node linkType: hard -"@typescript-eslint/utils@npm:5.60.1": - version: 5.60.1 - resolution: "@typescript-eslint/utils@npm:5.60.1" +"@typescript-eslint/utils@npm:6.1.0": + version: 6.1.0 + resolution: "@typescript-eslint/utils@npm:6.1.0" dependencies: - "@eslint-community/eslint-utils": ^4.2.0 - "@types/json-schema": ^7.0.9 - "@types/semver": ^7.3.12 - "@typescript-eslint/scope-manager": 5.60.1 - "@typescript-eslint/types": 5.60.1 - "@typescript-eslint/typescript-estree": 5.60.1 - eslint-scope: ^5.1.1 - semver: ^7.3.7 + "@eslint-community/eslint-utils": ^4.4.0 + "@types/json-schema": ^7.0.12 + "@types/semver": ^7.5.0 + "@typescript-eslint/scope-manager": 6.1.0 + "@typescript-eslint/types": 6.1.0 + "@typescript-eslint/typescript-estree": 6.1.0 + semver: ^7.5.4 peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: 00c1adaa09d5d5be947e98962a78c21ed08c3ac46dd5ddd7b78f6102537d50afd4578a42a3e09a24dd51f5bc493f0b968627b4423647540164b2d2380afa9246 + eslint: ^7.0.0 || ^8.0.0 + checksum: eb47a6b56e142ca68231f0f43af68d4cf5161235943aaf19c268156e3e751e10dd8ea3e0e297a7c0796b9eb3c5268b3c659821b909799949b55a524707c82e13 languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:5.60.1": - version: 5.60.1 - resolution: "@typescript-eslint/visitor-keys@npm:5.60.1" +"@typescript-eslint/visitor-keys@npm:6.1.0": + version: 6.1.0 + resolution: "@typescript-eslint/visitor-keys@npm:6.1.0" dependencies: - "@typescript-eslint/types": 5.60.1 - eslint-visitor-keys: ^3.3.0 - checksum: 137f6a6f8efb398969087147b59f99f7d0deed044d89d7efce3631bb90bc32e3a13a5cee6a65e1c9830862c5c4402ac1a9b2c9e31fe46d1716602af2813bffae + "@typescript-eslint/types": 6.1.0 + eslint-visitor-keys: ^3.4.1 + checksum: 21c7c9b9a52325e3b67c0015deb99a1603b19703af7c002e87f32e2d8f9910813985877ee7b589dc9938d308e3d082cf97c8ca43c2c95b86a919c426d8913439 languageName: node linkType: hard -"@vaadin/a11y-base@npm:~24.1.2": - version: 24.1.2 - resolution: "@vaadin/a11y-base@npm:24.1.2" +"@vaadin/a11y-base@npm:~24.1.4": + version: 24.1.4 + resolution: "@vaadin/a11y-base@npm:24.1.4" dependencies: "@open-wc/dedupe-mixin": ^1.3.0 "@polymer/polymer": ^3.0.0 - "@vaadin/component-base": ~24.1.2 + "@vaadin/component-base": ~24.1.4 lit: ^2.0.0 - checksum: 66ce2a3f46a5cd7ba917018e09d39f7b97c611415edbc079dc0b309612d089fcb7aaaf28224c4f924c187664a651275c02698ffcb2fde6c19cdc9b8c562fff7f + checksum: 1b5ddc2af1418c530d12ac00cd1ad9f896ef118730157c901662906409806ef6a46d18be4daf9d883784727c8ce4186700c0fdfa3ccc521c58693e494be98cc0 languageName: node linkType: hard -"@vaadin/combo-box@npm:24.1.2": - version: 24.1.2 - resolution: "@vaadin/combo-box@npm:24.1.2" +"@vaadin/combo-box@npm:24.1.4": + version: 24.1.4 + resolution: "@vaadin/combo-box@npm:24.1.4" dependencies: "@open-wc/dedupe-mixin": ^1.3.0 "@polymer/polymer": ^3.0.0 - "@vaadin/a11y-base": ~24.1.2 - "@vaadin/component-base": ~24.1.2 - "@vaadin/field-base": ~24.1.2 - "@vaadin/input-container": ~24.1.2 - "@vaadin/item": ~24.1.2 - "@vaadin/lit-renderer": ~24.1.2 - "@vaadin/overlay": ~24.1.2 - "@vaadin/vaadin-lumo-styles": ~24.1.2 - "@vaadin/vaadin-material-styles": ~24.1.2 - "@vaadin/vaadin-themable-mixin": ~24.1.2 - checksum: 6f165bb337517c249d6796d8c42c3f24a4d58ad103de8fd983d2aa8cfa245f6082879713dc4ce4a69b1f163d0ec18737a8499e57880a23eb31cf9df974df9fd9 + "@vaadin/a11y-base": ~24.1.4 + "@vaadin/component-base": ~24.1.4 + "@vaadin/field-base": ~24.1.4 + "@vaadin/input-container": ~24.1.4 + "@vaadin/item": ~24.1.4 + "@vaadin/lit-renderer": ~24.1.4 + "@vaadin/overlay": ~24.1.4 + "@vaadin/vaadin-lumo-styles": ~24.1.4 + "@vaadin/vaadin-material-styles": ~24.1.4 + "@vaadin/vaadin-themable-mixin": ~24.1.4 + checksum: 598800430645af9c5da1b6195ee326827d0069c31219a3c48145c877f8c08e739b5c68261cd54f3b6d1e6d34cac33165f643744594ff1737731e8fa2f7b2a9e0 languageName: node linkType: hard -"@vaadin/component-base@npm:~24.1.2": - version: 24.1.2 - resolution: "@vaadin/component-base@npm:24.1.2" +"@vaadin/component-base@npm:~24.1.4": + version: 24.1.4 + resolution: "@vaadin/component-base@npm:24.1.4" dependencies: "@open-wc/dedupe-mixin": ^1.3.0 "@polymer/polymer": ^3.0.0 "@vaadin/vaadin-development-mode-detector": ^2.0.0 "@vaadin/vaadin-usage-statistics": ^2.1.0 lit: ^2.0.0 - checksum: 20299afe5c3247056d986b6bae2f680511e50ae47123ff41324c6110c5b77d6c61d7735475e19b4f3df52de57745ca567a5fdbaba2059883b8ffc444f9e2ac5e + checksum: dc0d4dfa898fb37103cc52e385dc98f14d074e4bc846f377ef391e24b14317c4cca939667aa4e67984815021d89706fc70183e62cbaa3cd98f5168d254492db2 languageName: node linkType: hard -"@vaadin/field-base@npm:~24.1.2": - version: 24.1.2 - resolution: "@vaadin/field-base@npm:24.1.2" +"@vaadin/field-base@npm:~24.1.4": + version: 24.1.4 + resolution: "@vaadin/field-base@npm:24.1.4" dependencies: "@open-wc/dedupe-mixin": ^1.3.0 "@polymer/polymer": ^3.0.0 - "@vaadin/a11y-base": ~24.1.2 - "@vaadin/component-base": ~24.1.2 + "@vaadin/a11y-base": ~24.1.4 + "@vaadin/component-base": ~24.1.4 lit: ^2.0.0 - checksum: 73112c1e524e8704d55ab3befaa0d6dcfa8e5c1621ea1e2bd7765cc88b2c567386cc75f2525b0900f7e9097e4fd90aa9e4eae5da3c79210ab9251a4d5f67ddb3 + checksum: 6767702f0b501a7463eb17d0254410d49ede194b9c46dbc784db1dc9aa454e4dd79094e1c6166f31ee6c913b3532eda4c12a9dbd7ef51ca6c5a407050b322788 languageName: node linkType: hard -"@vaadin/icon@npm:~24.1.2": - version: 24.1.2 - resolution: "@vaadin/icon@npm:24.1.2" +"@vaadin/icon@npm:~24.1.4": + version: 24.1.4 + resolution: "@vaadin/icon@npm:24.1.4" dependencies: "@polymer/polymer": ^3.0.0 - "@vaadin/component-base": ~24.1.2 - "@vaadin/vaadin-lumo-styles": ~24.1.2 - "@vaadin/vaadin-themable-mixin": ~24.1.2 + "@vaadin/component-base": ~24.1.4 + "@vaadin/vaadin-lumo-styles": ~24.1.4 + "@vaadin/vaadin-themable-mixin": ~24.1.4 lit: ^2.0.0 - checksum: 976c81e9d7377e0fdce562db1324d8e7a0b564244aaf724c96d799fd0391bf67bb24487afb5296e786e7ad50dd3ab06f68b6054239a4d0342e0c27468a80f5ba + checksum: 880476ab0ba49bfdc4402a3c3facedd17673dd2c5b85c8e0240ac780c5a889c8c7bc2297ec0479e1551c50dd1e7d01d68ca9c24eb140a1f2daa5d43782d8e747 languageName: node linkType: hard -"@vaadin/input-container@npm:~24.1.2": - version: 24.1.2 - resolution: "@vaadin/input-container@npm:24.1.2" +"@vaadin/input-container@npm:~24.1.4": + version: 24.1.4 + resolution: "@vaadin/input-container@npm:24.1.4" dependencies: "@polymer/polymer": ^3.0.0 - "@vaadin/component-base": ~24.1.2 - "@vaadin/vaadin-lumo-styles": ~24.1.2 - "@vaadin/vaadin-material-styles": ~24.1.2 - "@vaadin/vaadin-themable-mixin": ~24.1.2 - checksum: 42f4dbb673aca9c1aa03198d6a2ca69d09d053824e1270d3ba44eb752cd3ad69f10bd4ecca46abda6f0761e6e2f367828c1e717a85e5f9bd29c1abc3063da48f + "@vaadin/component-base": ~24.1.4 + "@vaadin/vaadin-lumo-styles": ~24.1.4 + "@vaadin/vaadin-material-styles": ~24.1.4 + "@vaadin/vaadin-themable-mixin": ~24.1.4 + checksum: 1851ac7a85bbaf02fbcbe3de99efe94aee2921873d5226b48d77a42d35cdf2d5f6f99b0a8bce9c559f90edfcb79efbe47e486db3bfe2991071af1f271d10a07d languageName: node linkType: hard -"@vaadin/item@npm:~24.1.2": - version: 24.1.2 - resolution: "@vaadin/item@npm:24.1.2" +"@vaadin/item@npm:~24.1.4": + version: 24.1.4 + resolution: "@vaadin/item@npm:24.1.4" dependencies: "@open-wc/dedupe-mixin": ^1.3.0 "@polymer/polymer": ^3.0.0 - "@vaadin/a11y-base": ~24.1.2 - "@vaadin/component-base": ~24.1.2 - "@vaadin/vaadin-lumo-styles": ~24.1.2 - "@vaadin/vaadin-material-styles": ~24.1.2 - "@vaadin/vaadin-themable-mixin": ~24.1.2 - checksum: 000364ba1977bf29f88e1cfcde33e8fa0500a85094e104a89ae8933aebea35b52bee6da7cfe95ef8f016c13ee3632882f3c92964771ad23227494dc0361d9e59 + "@vaadin/a11y-base": ~24.1.4 + "@vaadin/component-base": ~24.1.4 + "@vaadin/vaadin-lumo-styles": ~24.1.4 + "@vaadin/vaadin-material-styles": ~24.1.4 + "@vaadin/vaadin-themable-mixin": ~24.1.4 + checksum: 5694a54c156516a41be7c92f7486fe417b227caaa39186322720426d9586d87f17775faae11ec8d16d249826c9b0cf753ed7061b2d4b9ac2cbcb614ce4b35714 languageName: node linkType: hard -"@vaadin/lit-renderer@npm:~24.1.2": - version: 24.1.2 - resolution: "@vaadin/lit-renderer@npm:24.1.2" +"@vaadin/lit-renderer@npm:~24.1.4": + version: 24.1.4 + resolution: "@vaadin/lit-renderer@npm:24.1.4" dependencies: lit: ^2.0.0 - checksum: 702291d1fcb02b28f5f82501247726a0055dd7c5067ea124c62c582208536ba929d5c0d78cb174105ae12b95c8cd1ffb934409c58be7e46072aadffdc4d010f1 + checksum: ac69537651be8733de209333cbbdd1b5b6e17394d6869d7de8c6b06bd63952a478de1f72120dfe826a72073788094032f5284d8cdbe19de5edf57a836de476b0 languageName: node linkType: hard -"@vaadin/overlay@npm:~24.1.2": - version: 24.1.2 - resolution: "@vaadin/overlay@npm:24.1.2" +"@vaadin/overlay@npm:~24.1.4": + version: 24.1.4 + resolution: "@vaadin/overlay@npm:24.1.4" dependencies: "@open-wc/dedupe-mixin": ^1.3.0 "@polymer/polymer": ^3.0.0 - "@vaadin/a11y-base": ~24.1.2 - "@vaadin/component-base": ~24.1.2 - "@vaadin/vaadin-lumo-styles": ~24.1.2 - "@vaadin/vaadin-material-styles": ~24.1.2 - "@vaadin/vaadin-themable-mixin": ~24.1.2 - checksum: 228723c7928a940ddf957ce32249665ac713567b580217facdb3b77ab3604a65999f078e86d29300da46e7fb9621f98beffb4a23629a27be86297c47d24fba80 + "@vaadin/a11y-base": ~24.1.4 + "@vaadin/component-base": ~24.1.4 + "@vaadin/vaadin-lumo-styles": ~24.1.4 + "@vaadin/vaadin-material-styles": ~24.1.4 + "@vaadin/vaadin-themable-mixin": ~24.1.4 + checksum: 44a664cd249b66345240a1ab6cd9c466f7d43c496a13c6d30d2cfdc1e67550f4b8562d43b16d0b974a2dc61bbde5d10671a63f97b9171f71ca75cb4d7de684cf languageName: node linkType: hard @@ -4946,34 +4900,34 @@ __metadata: languageName: node linkType: hard -"@vaadin/vaadin-lumo-styles@npm:~24.1.2": - version: 24.1.2 - resolution: "@vaadin/vaadin-lumo-styles@npm:24.1.2" +"@vaadin/vaadin-lumo-styles@npm:~24.1.4": + version: 24.1.4 + resolution: "@vaadin/vaadin-lumo-styles@npm:24.1.4" dependencies: "@polymer/polymer": ^3.0.0 - "@vaadin/icon": ~24.1.2 - "@vaadin/vaadin-themable-mixin": ~24.1.2 - checksum: 1f389d3799e7411dd81b836e36a73f28fd471b98a3799a6d48297d968ca5f955142146152672522eb37c6ea52b4adcdf3874f5ae9e4a90efee0e4be0197c3c33 + "@vaadin/icon": ~24.1.4 + "@vaadin/vaadin-themable-mixin": ~24.1.4 + checksum: 358dfa2ca955d86119b675e4e32982a51be12327fd675cdf3601b79a9fc9c8388e31299e593aabc62bb72afb17ba3856b904dfbecd7408f82719c9ce015fd883 languageName: node linkType: hard -"@vaadin/vaadin-material-styles@npm:~24.1.2": - version: 24.1.2 - resolution: "@vaadin/vaadin-material-styles@npm:24.1.2" +"@vaadin/vaadin-material-styles@npm:~24.1.4": + version: 24.1.4 + resolution: "@vaadin/vaadin-material-styles@npm:24.1.4" dependencies: "@polymer/polymer": ^3.0.0 - "@vaadin/vaadin-themable-mixin": ~24.1.2 - checksum: 93662d887bc128fdaf1012efa9c361c0ac2397c748d20b6d21ec8c85eed0541aedcfeeb85c043456cea1e3867037662c8860772c2ab3eba2e25f083d777f229d + "@vaadin/vaadin-themable-mixin": ~24.1.4 + checksum: 0289b667dbf54d2a81ffb74dd1caeccefed7cd7e0d02163c31775ab03f5d8fb15647578c4744592d753a2657b47216f221468f19f497d920e21f443e84699bf4 languageName: node linkType: hard -"@vaadin/vaadin-themable-mixin@npm:24.1.2, @vaadin/vaadin-themable-mixin@npm:~24.1.2": - version: 24.1.2 - resolution: "@vaadin/vaadin-themable-mixin@npm:24.1.2" +"@vaadin/vaadin-themable-mixin@npm:24.1.4, @vaadin/vaadin-themable-mixin@npm:~24.1.4": + version: 24.1.4 + resolution: "@vaadin/vaadin-themable-mixin@npm:24.1.4" dependencies: "@open-wc/dedupe-mixin": ^1.3.0 lit: ^2.0.0 - checksum: 7019857bc05976e1032610bb5af74754339e65e6ad279808c245636f44187196931f21b7b35fe39370098ac745683611168abe9929cd0d40d9ddf1120c9b39fb + checksum: db2993360d741f50011c0ca3229afb67d6965bd2fcb4915108e8bd462071c82d5f0a60877e250db1611b5712cbb17d3ab97fef932f97c43b63cb15a0357646ea languageName: node linkType: hard @@ -5469,11 +5423,11 @@ __metadata: linkType: hard "acorn@npm:^8.5.0, acorn@npm:^8.7.1, acorn@npm:^8.8.2, acorn@npm:^8.9.0": - version: 8.9.0 - resolution: "acorn@npm:8.9.0" + version: 8.10.0 + resolution: "acorn@npm:8.10.0" bin: acorn: bin/acorn - checksum: 25dfb94952386ecfb847e61934de04a4e7c2dc21c2e700fc4e2ef27ce78cb717700c4c4f279cd630bb4774948633c3859fc16063ec8573bda4568e0a312e6744 + checksum: 538ba38af0cc9e5ef983aee196c4b8b4d87c0c94532334fa7e065b2c8a1f85863467bb774231aae91613fcda5e68740c15d97b1967ae3394d20faddddd8af61d languageName: node linkType: hard @@ -5776,11 +5730,11 @@ __metadata: linkType: hard "aria-query@npm:^5.1.3": - version: 5.2.1 - resolution: "aria-query@npm:5.2.1" + version: 5.3.0 + resolution: "aria-query@npm:5.3.0" dependencies: dequal: ^2.0.3 - checksum: fdb7a337d97acf4dae831e4c2c786233aca5ccb779a02c10fe65a65af9849f6e9868073593313ab52b7b0d9817e05cfb22a5cd43ecf22a8e7f2abea2268bdac9 + checksum: 305bd73c76756117b59aba121d08f413c7ff5e80fa1b98e217a3443fcddb9a232ee790e24e432b59ae7625aebcf4c47cb01c2cac872994f0b426f5bdfcd96ba9 languageName: node linkType: hard @@ -5987,6 +5941,20 @@ __metadata: languageName: node linkType: hard +"arraybuffer.prototype.slice@npm:^1.0.1": + version: 1.0.1 + resolution: "arraybuffer.prototype.slice@npm:1.0.1" + dependencies: + array-buffer-byte-length: ^1.0.0 + call-bind: ^1.0.2 + define-properties: ^1.2.0 + get-intrinsic: ^1.2.1 + is-array-buffer: ^3.0.2 + is-shared-array-buffer: ^1.0.2 + checksum: e3e9b2a3e988ebfeddce4c7e8f69df730c9e48cb04b0d40ff0874ce3d86b3d1339dd520ffde5e39c02610bc172ecfbd4bc93324b1cabd9554c44a56b131ce0ce + languageName: node + linkType: hard + "asap@npm:~2.0.6": version: 2.0.6 resolution: "asap@npm:2.0.6" @@ -6096,52 +6064,52 @@ __metadata: languageName: node linkType: hard -"babel-loader@npm:9.1.2": - version: 9.1.2 - resolution: "babel-loader@npm:9.1.2" +"babel-loader@npm:9.1.3": + version: 9.1.3 + resolution: "babel-loader@npm:9.1.3" dependencies: - find-cache-dir: ^3.3.2 + find-cache-dir: ^4.0.0 schema-utils: ^4.0.0 peerDependencies: "@babel/core": ^7.12.0 webpack: ">=5" - checksum: f0edb8e157f9806b810ba3f2c8ca8fa489d377ae5c2b7b00c2ace900a6925641ce4ec520b9c12f70e37b94aa5366e7003e0f6271b26821643e109966ce741cb7 + checksum: b168dde5b8cf11206513371a79f86bb3faa7c714e6ec9fffd420876b61f3d7f5f4b976431095ef6a14bc4d324505126deb91045fd41e312ba49f4deaa166fe28 languageName: node linkType: hard -"babel-plugin-polyfill-corejs2@npm:^0.4.3": - version: 0.4.3 - resolution: "babel-plugin-polyfill-corejs2@npm:0.4.3" +"babel-plugin-polyfill-corejs2@npm:^0.4.4": + version: 0.4.4 + resolution: "babel-plugin-polyfill-corejs2@npm:0.4.4" dependencies: - "@babel/compat-data": ^7.17.7 - "@babel/helper-define-polyfill-provider": ^0.4.0 - semver: ^6.1.1 + "@babel/compat-data": ^7.22.6 + "@babel/helper-define-polyfill-provider": ^0.4.1 + "@nicolo-ribaudo/semver-v6": ^6.3.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 09ba40b9f8ac66a733628b2f12722bb764bdcc4f9600b93d60f1994418a8f84bc4b1ed9ab07c9d288debbf6210413fdff0721a3a43bd89c7f77adf76b0310adc + checksum: 0273f3d74ccbf78086a3b14bb11b1fb94933830f51c576a24229d75b3b91c8b357c3a381d4ab3146abf9b052fa4c33ec9368dd010ada9ee355e1d03ff64e1ff0 languageName: node linkType: hard -"babel-plugin-polyfill-corejs3@npm:^0.8.1": - version: 0.8.1 - resolution: "babel-plugin-polyfill-corejs3@npm:0.8.1" +"babel-plugin-polyfill-corejs3@npm:^0.8.2": + version: 0.8.2 + resolution: "babel-plugin-polyfill-corejs3@npm:0.8.2" dependencies: - "@babel/helper-define-polyfill-provider": ^0.4.0 - core-js-compat: ^3.30.1 + "@babel/helper-define-polyfill-provider": ^0.4.1 + core-js-compat: ^3.31.0 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: c23a581973c141a4687126cf964981180ef27e3eb0b34b911161db4f5caf9ba7ff60bee0ebe46d650ba09e03a6a3ac2cd6a6ae5f4f5363a148470e5cd8447df2 + checksum: 0bc3e9e0114eba18f4fea8a9ff5a6016cae73b74cb091290c3f75fd7b9e34e712ee26f95b52d796f283970d7c6256fb01196e3608e8db03f620e3389d56d37c6 languageName: node linkType: hard -"babel-plugin-polyfill-regenerator@npm:^0.5.0": - version: 0.5.0 - resolution: "babel-plugin-polyfill-regenerator@npm:0.5.0" +"babel-plugin-polyfill-regenerator@npm:^0.5.1": + version: 0.5.1 + resolution: "babel-plugin-polyfill-regenerator@npm:0.5.1" dependencies: - "@babel/helper-define-polyfill-provider": ^0.4.0 + "@babel/helper-define-polyfill-provider": ^0.4.1 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: ef2bcffc7c9a5e4426fc2dbf89bf3a46999a8415c21cd741c3ab3cb4b5ab804aaa3d71ef733f0eda1bcc0b91d9d80f98d33983a66dab9b8bed166ec38f8f8ad1 + checksum: 85a56d28b34586fbe482225fb6a9592fc793a459c5eea987a3427fb723c7aa2f76916348a9fc5e9ca48754ebf6086cfbb9226f4cd0cf9c6257f94553622562ed languageName: node linkType: hard @@ -6371,7 +6339,7 @@ __metadata: languageName: node linkType: hard -"browserslist@npm:^4.14.5, browserslist@npm:^4.21.3, browserslist@npm:^4.21.5": +"browserslist@npm:^4.14.5, browserslist@npm:^4.21.9": version: 4.21.9 resolution: "browserslist@npm:4.21.9" dependencies: @@ -6549,9 +6517,9 @@ __metadata: linkType: hard "caniuse-lite@npm:^1.0.30001503": - version: 1.0.30001504 - resolution: "caniuse-lite@npm:1.0.30001504" - checksum: 0256f8ef2f5d6d1559198967d7325952e6451e79ff1b92d3d6ba1ec43efedf49fcd3fbb0735ebed0bfd96c6c6a49730e169535e273c60795d23ef25bd37e3e3d + version: 1.0.30001517 + resolution: "caniuse-lite@npm:1.0.30001517" + checksum: e4e87436ae1c4408cf4438aac22902b31eb03f3f5bad7f33bc518d12ffb35f3fd9395ccf7efc608ee046f90ce324ec6f7f26f8a8172b8c43c26a06ecee612a29 languageName: node linkType: hard @@ -6981,6 +6949,13 @@ __metadata: languageName: node linkType: hard +"common-path-prefix@npm:^3.0.0": + version: 3.0.0 + resolution: "common-path-prefix@npm:3.0.0" + checksum: fdb3c4f54e51e70d417ccd950c07f757582de800c0678ca388aedefefc84982039f346f9fd9a1252d08d2da9e9ef4019f580a1d1d3a10da031e4bb3c924c5818 + languageName: node + linkType: hard + "common-tags@npm:^1.8.0": version: 1.8.2 resolution: "common-tags@npm:1.8.2" @@ -7144,19 +7119,19 @@ __metadata: languageName: node linkType: hard -"core-js-compat@npm:^3.30.1, core-js-compat@npm:^3.30.2": - version: 3.31.0 - resolution: "core-js-compat@npm:3.31.0" +"core-js-compat@npm:^3.31.0": + version: 3.31.1 + resolution: "core-js-compat@npm:3.31.1" dependencies: - browserslist: ^4.21.5 - checksum: 5c76ac5e4ab39480391f93a5aef14a2cfa188cda7bd6a7b8532de1f8bc5d89099a5025b2640d2ef70a2928614792363dcbcf8bd254aa7b2e11b85aeed7ac460f + browserslist: ^4.21.9 + checksum: 9a16d6992621f4e099169297381a28d5712cdef7df1fa85352a7c285a5885d5d7a117ec2eae9ad715ed88c7cc774787a22cdb8aceababf6775fbc8b0cbeccdb7 languageName: node linkType: hard -"core-js@npm:3.31.0": - version: 3.31.0 - resolution: "core-js@npm:3.31.0" - checksum: f7cf9b3010f7ca99c026d95b61743baca1a85512742ed2b67e8f65a72ac4f4fe0b90b00057783e886bdd39d3a295f42f845d33e7cba3973ed263df978343ab79 +"core-js@npm:3.31.1": + version: 3.31.1 + resolution: "core-js@npm:3.31.1" + checksum: 14519213a63c55cf188bdd2f4dece54583feaf6b90e75d6c65e07f509cd487055bf64898aeda7c97c36029ac1ea2f2ed8e4b02281553f6a257e7143a32a14015 languageName: node linkType: hard @@ -7674,9 +7649,9 @@ __metadata: linkType: hard "electron-to-chromium@npm:^1.4.431": - version: 1.4.433 - resolution: "electron-to-chromium@npm:1.4.433" - checksum: 106e3bc2fb4ee5eddd4b141363900d5cd731c7579aa6bebd02509c52d6b598a1684aba1b75791e838dfa54dec0a40ddd17ea01199041ea46310aafb206395e43 + version: 1.4.465 + resolution: "electron-to-chromium@npm:1.4.465" + checksum: 1c8509d5bf15004ad88921845386b695744d0ea02beef8e1e8c6abdf673a4d51254395b8cd501a12c1043f732fca18d2981f636aac3cf789673a515424460ccd languageName: node linkType: hard @@ -7769,11 +7744,11 @@ __metadata: linkType: hard "envinfo@npm:^7.7.3": - version: 7.8.1 - resolution: "envinfo@npm:7.8.1" + version: 7.10.0 + resolution: "envinfo@npm:7.10.0" bin: envinfo: dist/cli.js - checksum: de736c98d6311c78523628ff127af138451b162e57af5293c1b984ca821d0aeb9c849537d2fde0434011bed33f6bca5310ca2aab8a51a3f28fc719e89045d648 + checksum: 05e81a5768c42cbd5c580dc3f274db3401facadd53e9bd52e2aa49dfbb5d8b26f6181c25a6652d79618a6994185bd2b1c137673101690b147f758e4e71d42f7d languageName: node linkType: hard @@ -7794,16 +7769,17 @@ __metadata: linkType: hard "es-abstract@npm:^1.19.0, es-abstract@npm:^1.20.4": - version: 1.21.2 - resolution: "es-abstract@npm:1.21.2" + version: 1.22.1 + resolution: "es-abstract@npm:1.22.1" dependencies: array-buffer-byte-length: ^1.0.0 + arraybuffer.prototype.slice: ^1.0.1 available-typed-arrays: ^1.0.5 call-bind: ^1.0.2 es-set-tostringtag: ^2.0.1 es-to-primitive: ^1.2.1 function.prototype.name: ^1.1.5 - get-intrinsic: ^1.2.0 + get-intrinsic: ^1.2.1 get-symbol-description: ^1.0.0 globalthis: ^1.0.3 gopd: ^1.0.1 @@ -7823,15 +7799,19 @@ __metadata: object-inspect: ^1.12.3 object-keys: ^1.1.1 object.assign: ^4.1.4 - regexp.prototype.flags: ^1.4.3 + regexp.prototype.flags: ^1.5.0 + safe-array-concat: ^1.0.0 safe-regex-test: ^1.0.0 string.prototype.trim: ^1.2.7 string.prototype.trimend: ^1.0.6 string.prototype.trimstart: ^1.0.6 + typed-array-buffer: ^1.0.0 + typed-array-byte-length: ^1.0.0 + typed-array-byte-offset: ^1.0.0 typed-array-length: ^1.0.4 unbox-primitive: ^1.0.2 - which-typed-array: ^1.1.9 - checksum: 037f55ee5e1cdf2e5edbab5524095a4f97144d95b94ea29e3611b77d852fd8c8a40e7ae7101fa6a759a9b9b1405f188c3c70928f2d3cd88d543a07fc0d5ad41a + which-typed-array: ^1.1.10 + checksum: 614e2c1c3717cb8d30b6128ef12ea110e06fd7d75ad77091ca1c5dbfb00da130e62e4bbbbbdda190eada098a22b27fe0f99ae5a1171dac2c8663b1e8be8a3a9b languageName: node linkType: hard @@ -7967,17 +7947,17 @@ __metadata: languageName: node linkType: hard -"eslint-config-airbnb-typescript@npm:17.0.0": - version: 17.0.0 - resolution: "eslint-config-airbnb-typescript@npm:17.0.0" +"eslint-config-airbnb-typescript@npm:17.1.0": + version: 17.1.0 + resolution: "eslint-config-airbnb-typescript@npm:17.1.0" dependencies: eslint-config-airbnb-base: ^15.0.0 peerDependencies: - "@typescript-eslint/eslint-plugin": ^5.13.0 - "@typescript-eslint/parser": ^5.0.0 + "@typescript-eslint/eslint-plugin": ^5.13.0 || ^6.0.0 + "@typescript-eslint/parser": ^5.0.0 || ^6.0.0 eslint: ^7.32.0 || ^8.2.0 eslint-plugin-import: ^2.25.3 - checksum: e598ae7bcc3629bbc847a749f8c1ad69e6ef111335b60d88bde91d1bb335077b06688868257fe2fcc95c3687a0d6e3e1f91e0534cc633f5a118239e52bb05a54 + checksum: cfd26a2782e322ebfdfbf9a64262332c7653f297c4a32d7b951079eb18bb9502a83d67b3f7ef2cc1c5374ae06098eb454ed010784b3416e7274839083022a08c languageName: node linkType: hard @@ -8107,18 +8087,18 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-unused-imports@npm:2.0.0": - version: 2.0.0 - resolution: "eslint-plugin-unused-imports@npm:2.0.0" +"eslint-plugin-unused-imports@npm:3.0.0": + version: 3.0.0 + resolution: "eslint-plugin-unused-imports@npm:3.0.0" dependencies: eslint-rule-composer: ^0.3.0 peerDependencies: - "@typescript-eslint/eslint-plugin": ^5.0.0 + "@typescript-eslint/eslint-plugin": ^6.0.0 eslint: ^8.0.0 peerDependenciesMeta: "@typescript-eslint/eslint-plugin": optional: true - checksum: 8aa1e03e75da2a62a354065e0cb8fe370118c6f8d9720a32fe8c1da937de6adb81a4fed7d0d391d115ac9453b49029fb19f970d180a2cf3dba451fd4c20f0dc4 + checksum: 51666f62cc8dccba2895ced83f3c1e0b78b68c357e17360e156c4db548bfdeda34cbd8725192fb4903f22d5069400fb22ded6039631df01ee82fd618dc307247 languageName: node linkType: hard @@ -8148,7 +8128,7 @@ __metadata: languageName: node linkType: hard -"eslint-scope@npm:5.1.1, eslint-scope@npm:^5.1.1": +"eslint-scope@npm:5.1.1": version: 5.1.1 resolution: "eslint-scope@npm:5.1.1" dependencies: @@ -8159,12 +8139,12 @@ __metadata: linkType: hard "eslint-scope@npm:^7.2.0": - version: 7.2.0 - resolution: "eslint-scope@npm:7.2.0" + version: 7.2.1 + resolution: "eslint-scope@npm:7.2.1" dependencies: esrecurse: ^4.3.0 estraverse: ^5.2.0 - checksum: 64591a2d8b244ade9c690b59ef238a11d5c721a98bcee9e9f445454f442d03d3e04eda88e95a4daec558220a99fa384309d9faae3d459bd40e7a81b4063980ae + checksum: dccda5c8909216f6261969b72c77b95e385f9086bed4bc09d8a6276df8439d8f986810fd9ac3bd02c94c0572cefc7fdbeae392c69df2e60712ab8263986522c5 languageName: node linkType: hard @@ -8175,9 +8155,9 @@ __metadata: languageName: node linkType: hard -"eslint@npm:8.44.0": - version: 8.44.0 - resolution: "eslint@npm:8.44.0" +"eslint@npm:8.45.0": + version: 8.45.0 + resolution: "eslint@npm:8.45.0" dependencies: "@eslint-community/eslint-utils": ^4.2.0 "@eslint-community/regexpp": ^4.4.0 @@ -8204,7 +8184,6 @@ __metadata: globals: ^13.19.0 graphemer: ^1.4.0 ignore: ^5.2.0 - import-fresh: ^3.0.0 imurmurhash: ^0.1.4 is-glob: ^4.0.0 is-path-inside: ^3.0.3 @@ -8216,22 +8195,21 @@ __metadata: natural-compare: ^1.4.0 optionator: ^0.9.3 strip-ansi: ^6.0.1 - strip-json-comments: ^3.1.0 text-table: ^0.2.0 bin: eslint: bin/eslint.js - checksum: d06309ce4aafb9d27d558c8e5e5aa5cba3bbec3ce8ceccbc7d4b7a35f2b67fd40189159155553270e2e6febeb69bd8a3b60d6241c8f5ddc2ef1702ccbd328501 + checksum: 3e6dcce5cc43c5e301662db88ee26d1d188b22c177b9f104d7eefd1191236980bd953b3670fe2fac287114b26d7c5420ab48407d7ea1c3a446d6313c000009da languageName: node linkType: hard "espree@npm:^9.6.0": - version: 9.6.0 - resolution: "espree@npm:9.6.0" + version: 9.6.1 + resolution: "espree@npm:9.6.1" dependencies: acorn: ^8.9.0 acorn-jsx: ^5.3.2 eslint-visitor-keys: ^3.4.1 - checksum: 1287979510efb052a6a97c73067ea5d0a40701b29adde87bbe2d3eb1667e39ca55e8129e20e2517fed3da570150e7ef470585228459a8f3e3755f45007a1c662 + checksum: eb8c149c7a2a77b3f33a5af80c10875c3abd65450f60b8af6db1bfcfa8f101e21c1e56a561c6dc13b848e18148d43469e7cd208506238554fb5395a9ea5a1ab9 languageName: node linkType: hard @@ -8525,16 +8503,16 @@ __metadata: languageName: node linkType: hard -"fast-glob@npm:^3.2.11, fast-glob@npm:^3.2.2, fast-glob@npm:^3.2.9": - version: 3.2.12 - resolution: "fast-glob@npm:3.2.12" +"fast-glob@npm:^3.2.11, fast-glob@npm:^3.2.2, fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.0": + version: 3.3.0 + resolution: "fast-glob@npm:3.3.0" dependencies: "@nodelib/fs.stat": ^2.0.2 "@nodelib/fs.walk": ^1.2.3 glob-parent: ^5.1.2 merge2: ^1.3.0 micromatch: ^4.0.4 - checksum: 0b1990f6ce831c7e28c4d505edcdaad8e27e88ab9fa65eedadb730438cfc7cde4910d6c975d6b7b8dc8a73da4773702ebcfcd6e3518e73938bb1383badfe01c2 + checksum: 20df62be28eb5426fe8e40e0d05601a63b1daceb7c3d87534afcad91bdcf1e4b1743cf2d5247d6e225b120b46df0b9053a032b2691ba34ee121e033acd81f547 languageName: node linkType: hard @@ -8665,14 +8643,13 @@ __metadata: languageName: node linkType: hard -"find-cache-dir@npm:^3.3.2": - version: 3.3.2 - resolution: "find-cache-dir@npm:3.3.2" +"find-cache-dir@npm:^4.0.0": + version: 4.0.0 + resolution: "find-cache-dir@npm:4.0.0" dependencies: - commondir: ^1.0.1 - make-dir: ^3.0.2 - pkg-dir: ^4.1.0 - checksum: 1e61c2e64f5c0b1c535bd85939ae73b0e5773142713273818cc0b393ee3555fb0fd44e1a5b161b8b6c3e03e98c2fcc9c227d784850a13a90a8ab576869576817 + common-path-prefix: ^3.0.0 + pkg-dir: ^7.0.0 + checksum: 52a456a80deeb27daa3af6e06059b63bdb9cc4af4d845fc6d6229887e505ba913cd56000349caa60bc3aa59dacdb5b4c37903d4ba34c75102d83cab330b70d2f languageName: node linkType: hard @@ -8722,6 +8699,16 @@ __metadata: languageName: node linkType: hard +"find-up@npm:^6.3.0": + version: 6.3.0 + resolution: "find-up@npm:6.3.0" + dependencies: + locate-path: ^7.1.0 + path-exists: ^5.0.0 + checksum: 9a21b7f9244a420e54c6df95b4f6fc3941efd3c3e5476f8274eb452f6a85706e7a6a90de71353ee4f091fcb4593271a6f92810a324ec542650398f928783c280 + languageName: node + linkType: hard + "findup-sync@npm:^2.0.0": version: 2.0.0 resolution: "findup-sync@npm:2.0.0" @@ -9059,7 +9046,7 @@ __metadata: languageName: node linkType: hard -"get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.0": +"get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.0, get-intrinsic@npm:^1.2.1": version: 1.2.1 resolution: "get-intrinsic@npm:1.2.1" dependencies: @@ -9180,18 +9167,18 @@ __metadata: languageName: node linkType: hard -"glob@npm:10.3.1, glob@npm:^10.2.2": - version: 10.3.1 - resolution: "glob@npm:10.3.1" +"glob@npm:10.3.3, glob@npm:^10.2.2": + version: 10.3.3 + resolution: "glob@npm:10.3.3" dependencies: foreground-child: ^3.1.0 jackspeak: ^2.0.3 minimatch: ^9.0.1 - minipass: ^5.0.0 || ^6.0.2 - path-scurry: ^1.10.0 + minipass: ^5.0.0 || ^6.0.2 || ^7.0.0 + path-scurry: ^1.10.1 bin: glob: dist/cjs/src/bin.js - checksum: 19c8c2805658b1002fecf0722cd609a33153d756a0d5260676bd0e9c5e6ef889ec9cce6d3dac0411aa90bce8de3d14f25b6f5589a3292582cccbfeddd0e98cc4 + checksum: 29190d3291f422da0cb40b77a72fc8d2c51a36524e99b8bf412548b7676a6627489528b57250429612b6eec2e6fe7826d328451d3e694a9d15e575389308ec53 languageName: node linkType: hard @@ -9310,15 +9297,15 @@ __metadata: linkType: hard "globby@npm:^13.1.2": - version: 13.2.0 - resolution: "globby@npm:13.2.0" + version: 13.2.2 + resolution: "globby@npm:13.2.2" dependencies: dir-glob: ^3.0.1 - fast-glob: ^3.2.11 - ignore: ^5.2.0 + fast-glob: ^3.3.0 + ignore: ^5.2.4 merge2: ^1.4.1 slash: ^4.0.0 - checksum: 0a3dd786571788adef1c894f22112834cff5bbe061ae6e0a01c5118c39d44b3f1937ef1dae3f8b9bc24756eba84a0923e565b1ad9a4ec52831d7e2a04c035e75 + checksum: f3d84ced58a901b4fcc29c846983108c426631fe47e94872868b65565495f7bee7b3defd68923bd480582771fd4bbe819217803a164a618ad76f1d22f666f41e languageName: node linkType: hard @@ -9331,10 +9318,10 @@ __metadata: languageName: node linkType: hard -"google-timezones-json@npm:1.1.0": - version: 1.1.0 - resolution: "google-timezones-json@npm:1.1.0" - checksum: 4abbf1b50a9c199fec4dbf7113803dbcb7c87794a4e52189dc0187e4c8a26a7dffd133bc4e2674e1f30f357e5f2060153effe267a013613c362cc098176dc8a0 +"google-timezones-json@npm:1.2.0": + version: 1.2.0 + resolution: "google-timezones-json@npm:1.2.0" + checksum: 2945d2ed900511cb5111c9066dd84a8330feed5166b195a854f9ac9550c9f9e2d10d62743e08a4571c6005a9a08045b2375c60dc9539c403830a0a25cd0d1690 languageName: node linkType: hard @@ -9354,13 +9341,6 @@ __metadata: languageName: node linkType: hard -"grapheme-splitter@npm:^1.0.4": - version: 1.0.4 - resolution: "grapheme-splitter@npm:1.0.4" - checksum: 0c22ec54dee1b05cd480f78cf14f732cb5b108edc073572c4ec205df4cd63f30f8db8025afc5debc8835a8ddeacf648a1c7992fe3dcd6ad38f9a476d84906620 - languageName: node - linkType: hard - "graphemer@npm:^1.4.0": version: 1.4.0 resolution: "graphemer@npm:1.4.0" @@ -9602,10 +9582,10 @@ __metadata: languageName: node linkType: hard -"hls.js@npm:1.4.7": - version: 1.4.7 - resolution: "hls.js@npm:1.4.7" - checksum: ca58d97d49048fa6f437b834b807d26f5b47750aae57a573f179155e63e39159aa304f3ef13504b42c19969984918b17557e9311a779b0b04641bd6b668b45db +"hls.js@npm:1.4.10": + version: 1.4.10 + resolution: "hls.js@npm:1.4.10" + checksum: c084000598fd7422b7445c7e313dc28133261579b5783bbb3881c7fcb609365d02157e3d3a74d0b41ac7440de405d1c69e64e14634370dc357c473d23e4afd44 languageName: node linkType: hard @@ -9613,20 +9593,20 @@ __metadata: version: 0.0.0-use.local resolution: "home-assistant-frontend@workspace:." dependencies: - "@babel/core": 7.22.5 - "@babel/plugin-proposal-decorators": 7.22.5 - "@babel/plugin-transform-runtime": 7.22.5 - "@babel/preset-env": 7.22.5 + "@babel/core": 7.22.9 + "@babel/plugin-proposal-decorators": 7.22.7 + "@babel/plugin-transform-runtime": 7.22.9 + "@babel/preset-env": 7.22.9 "@babel/preset-typescript": 7.22.5 - "@babel/runtime": 7.22.5 + "@babel/runtime": 7.22.6 "@braintree/sanitize-url": 6.0.2 - "@codemirror/autocomplete": 6.8.1 + "@codemirror/autocomplete": 6.9.0 "@codemirror/commands": 6.2.4 "@codemirror/language": 6.8.0 - "@codemirror/legacy-modes": 6.3.2 + "@codemirror/legacy-modes": 6.3.3 "@codemirror/search": 6.5.0 "@codemirror/state": 6.2.1 - "@codemirror/view": 6.14.0 + "@codemirror/view": 6.15.3 "@egjs/hammerjs": 2.0.17 "@formatjs/intl-datetimeformat": 6.10.0 "@formatjs/intl-displaynames": 6.5.0 @@ -9646,7 +9626,7 @@ __metadata: "@lezer/highlight": 1.1.6 "@lit-labs/context": 0.3.3 "@lit-labs/motion": 1.0.3 - "@lit-labs/virtualizer": 2.0.3 + "@lit-labs/virtualizer": 2.0.4 "@lrnwebcomponents/simple-tooltip": 7.0.11 "@material/chips": =14.0.0-canary.53b3cad2f.0 "@material/data-table": =14.0.0-canary.53b3cad2f.0 @@ -9673,12 +9653,12 @@ __metadata: "@material/mwc-top-app-bar": 0.27.0 "@material/mwc-top-app-bar-fixed": 0.27.0 "@material/top-app-bar": =14.0.0-canary.53b3cad2f.0 - "@material/web": =1.0.0-pre.12 + "@material/web": =1.0.0-pre.13 "@mdi/js": 7.2.96 "@mdi/svg": 7.2.96 - "@octokit/auth-oauth-device": 5.0.2 - "@octokit/plugin-retry": 5.0.4 - "@octokit/rest": 19.0.13 + "@octokit/auth-oauth-device": 6.0.0 + "@octokit/plugin-retry": 6.0.0 + "@octokit/rest": 20.0.1 "@open-wc/dev-server-hmr": 0.1.4 "@polymer/app-layout": 3.1.0 "@polymer/iron-flex-layout": 3.0.1 @@ -9692,7 +9672,7 @@ __metadata: "@polymer/paper-toast": 3.0.1 "@polymer/polymer": 3.5.1 "@rollup/plugin-babel": 6.0.3 - "@rollup/plugin-commonjs": 25.0.2 + "@rollup/plugin-commonjs": 25.0.3 "@rollup/plugin-json": 6.0.0 "@rollup/plugin-node-resolve": 15.1.0 "@rollup/plugin-replace": 5.0.2 @@ -9706,7 +9686,7 @@ __metadata: "@types/js-yaml": 4.0.5 "@types/leaflet": 1.9.3 "@types/leaflet-draw": 1.0.7 - "@types/luxon": 3.3.0 + "@types/luxon": 3.3.1 "@types/marked": 4.3.1 "@types/mocha": 10.0.1 "@types/qrcode": 1.5.1 @@ -9714,10 +9694,10 @@ __metadata: "@types/sortablejs": 1.15.1 "@types/tar": 6.1.5 "@types/webspeechapi": 0.0.29 - "@typescript-eslint/eslint-plugin": 5.60.1 - "@typescript-eslint/parser": 5.60.1 - "@vaadin/combo-box": 24.1.2 - "@vaadin/vaadin-themable-mixin": 24.1.2 + "@typescript-eslint/eslint-plugin": 6.1.0 + "@typescript-eslint/parser": 6.1.0 + "@vaadin/combo-box": 24.1.4 + "@vaadin/vaadin-themable-mixin": 24.1.4 "@vibrant/color": 3.2.1-alpha.1 "@vibrant/core": 3.2.1-alpha.1 "@vibrant/quantizer-mmcq": 3.2.1-alpha.1 @@ -9727,43 +9707,43 @@ __metadata: "@webcomponents/scoped-custom-element-registry": 0.0.9 "@webcomponents/webcomponentsjs": 2.8.0 app-datepicker: 5.1.1 - babel-loader: 9.1.2 + babel-loader: 9.1.3 babel-plugin-template-html-minifier: 4.1.0 chai: 4.3.7 chart.js: 3.3.2 comlink: 4.4.1 - core-js: 3.31.0 + core-js: 3.31.1 cropperjs: 1.5.13 date-fns: 2.30.0 date-fns-tz: 2.0.0 deep-clone-simple: 1.1.1 deep-freeze: 0.0.1 del: 7.0.0 - eslint: 8.44.0 + eslint: 8.45.0 eslint-config-airbnb-base: 15.0.0 - eslint-config-airbnb-typescript: 17.0.0 + eslint-config-airbnb-typescript: 17.1.0 eslint-config-prettier: 8.8.0 eslint-import-resolver-webpack: 0.13.2 eslint-plugin-disable: 2.0.3 eslint-plugin-import: 2.27.5 eslint-plugin-lit: 1.8.3 eslint-plugin-lit-a11y: 3.0.0 - eslint-plugin-unused-imports: 2.0.0 + eslint-plugin-unused-imports: 3.0.0 eslint-plugin-wc: 1.5.0 esprima: 4.0.1 fancy-log: 2.0.0 fs-extra: 11.1.1 fuse.js: 6.6.2 - glob: 10.3.1 - google-timezones-json: 1.1.0 + glob: 10.3.3 + google-timezones-json: 1.2.0 gulp: 4.0.2 gulp-flatmap: 1.0.2 gulp-json-transform: 0.4.8 gulp-merge-json: 2.1.2 gulp-rename: 2.0.0 gulp-zopfli-green: 6.0.1 - hls.js: 1.4.7 - home-assistant-js-websocket: 8.1.0 + hls.js: 1.4.10 + home-assistant-js-websocket: 8.2.0 html-minifier-terser: 7.2.0 husky: 8.0.3 idb-keyval: 6.2.1 @@ -9774,11 +9754,11 @@ __metadata: leaflet: 1.9.4 leaflet-draw: 1.0.4 lint-staged: 13.2.3 - lit: 2.7.5 + lit: 2.7.6 lit-analyzer: 2.0.0-pre.3 lodash.template: 4.5.0 luxon: 3.3.0 - magic-string: 0.30.0 + magic-string: 0.30.1 map-stream: 0.0.7 marked: 4.3.0 memoize-one: 6.0.0 @@ -9788,7 +9768,7 @@ __metadata: object-hash: 3.0.0 open: 9.1.0 pinst: 3.0.0 - prettier: 2.8.8 + prettier: 3.0.0 proxy-polyfill: 0.3.2 punycode: 2.3.0 qr-scanner: 1.4.2 @@ -9810,8 +9790,8 @@ __metadata: terser-webpack-plugin: 5.3.9 tinykeys: 2.1.0 ts-lit-plugin: 2.0.0-pre.1 - tsparticles-engine: 2.10.1 - tsparticles-preset-links: 2.10.1 + tsparticles-engine: 2.11.0 + tsparticles-preset-links: 2.11.0 typescript: 5.1.6 unfetch: 5.0.0 vinyl-buffer: 1.0.1 @@ -9820,7 +9800,7 @@ __metadata: vis-network: 9.1.6 vue: 2.7.14 vue2-daterange-picker: 0.6.8 - webpack: 5.88.1 + webpack: 5.88.2 webpack-cli: 5.1.4 webpack-dev-server: 4.15.1 webpack-manifest-plugin: 5.0.0 @@ -9837,10 +9817,10 @@ __metadata: languageName: unknown linkType: soft -"home-assistant-js-websocket@npm:8.1.0": - version: 8.1.0 - resolution: "home-assistant-js-websocket@npm:8.1.0" - checksum: 74f9afc5affe491921d7fd9e743c1a6841cb0409c2c5454fff266d14ea893f5be476cb85f584ff1836722de77cfe2777d4133890f00fc1983ad448eba50f6240 +"home-assistant-js-websocket@npm:8.2.0": + version: 8.2.0 + resolution: "home-assistant-js-websocket@npm:8.2.0" + checksum: 4eacdfe8d1bd35492ff77079779e2e0a1967b20a46b168752d8c037bf155fa5d2a8e898e7d1aee5514976d93589d26fe2d6c1975e4fcb039b0beff852564c64c languageName: node linkType: hard @@ -9873,9 +9853,9 @@ __metadata: linkType: hard "html-entities@npm:^2.3.2": - version: 2.3.6 - resolution: "html-entities@npm:2.3.6" - checksum: 559a88dc3a2059b1e8882940dcaf996ea9d8151b9a780409ff223a79dc1d42ee8bb19b3365064f241f2e2543b0f90612d63f9b8e36d14c4c7fbb73540a8f41cb + version: 2.4.0 + resolution: "html-entities@npm:2.4.0" + checksum: 25bea32642ce9ebd0eedc4d24381883ecb0335ccb8ac26379a0958b9b16652fdbaa725d70207ce54a51db24103436a698a8e454397d3ba8ad81460224751f1dc languageName: node linkType: hard @@ -10103,7 +10083,7 @@ __metadata: languageName: node linkType: hard -"ignore@npm:^5.2.0": +"ignore@npm:^5.2.0, ignore@npm:^5.2.4": version: 5.2.4 resolution: "ignore@npm:5.2.4" checksum: 3d4c309c6006e2621659311783eaea7ebcd41fe4ca1d78c91c473157ad6666a57a2df790fe0d07a12300d9aac2888204d7be8d59f9aaf665b1c7fcdb432517ef @@ -10126,7 +10106,7 @@ __metadata: languageName: node linkType: hard -"import-fresh@npm:^3.0.0, import-fresh@npm:^3.2.1": +"import-fresh@npm:^3.2.1": version: 3.3.0 resolution: "import-fresh@npm:3.3.0" dependencies: @@ -10764,15 +10744,11 @@ __metadata: linkType: hard "is-typed-array@npm:^1.1.10, is-typed-array@npm:^1.1.9": - version: 1.1.10 - resolution: "is-typed-array@npm:1.1.10" + version: 1.1.12 + resolution: "is-typed-array@npm:1.1.12" dependencies: - available-typed-arrays: ^1.0.5 - call-bind: ^1.0.2 - for-each: ^0.3.3 - gopd: ^1.0.1 - has-tostringtag: ^1.0.0 - checksum: aac6ecb59d4c56a1cdeb69b1f129154ef462bbffe434cb8a8235ca89b42f258b7ae94073c41b3cb7bce37f6a1733ad4499f07882d5d5093a7ba84dfc4ebb8017 + which-typed-array: ^1.1.11 + checksum: 4c89c4a3be07186caddadf92197b17fda663a9d259ea0d44a85f171558270d36059d1c386d34a12cba22dfade5aba497ce22778e866adc9406098c8fc4771796 languageName: node linkType: hard @@ -10854,6 +10830,13 @@ __metadata: languageName: node linkType: hard +"isarray@npm:^2.0.5": + version: 2.0.5 + resolution: "isarray@npm:2.0.5" + checksum: bd5bbe4104438c4196ba58a54650116007fa0262eccef13a4c55b2e09a5b36b59f1e75b9fcc49883dd9d4953892e6fc007eef9e9155648ceea036e184b0f930a + languageName: node + linkType: hard + "isbinaryfile@npm:^5.0.0": version: 5.0.0 resolution: "isbinaryfile@npm:5.0.0" @@ -11418,11 +11401,11 @@ __metadata: linkType: hard "lit-html@npm:^2.7.0": - version: 2.7.4 - resolution: "lit-html@npm:2.7.4" + version: 2.7.5 + resolution: "lit-html@npm:2.7.5" dependencies: "@types/trusted-types": ^2.0.2 - checksum: 3809d62d8b8e66c047a582fe62d430384c63af8c8444da4ca565b41d03e0295be2ce3eaa3c03b58d35a5d74fd8c98976585902204fc28006cfb9adf29fc1761e + checksum: 7a54399f78c02f21ee5584fd9ff21b3edad8416df0aca22964bc5b221f0b57ba74d7bd98ad076acea2403b53b2ea87cc3eb47ba8395f371a645e3d584f2c1e49 languageName: node linkType: hard @@ -11437,14 +11420,14 @@ __metadata: languageName: node linkType: hard -"lit@npm:2.7.5, lit@npm:^2.0.0, lit@npm:^2.0.0-rc.2, lit@npm:^2.2.1, lit@npm:^2.7.0, lit@npm:^2.7.4, lit@npm:^2.7.5": - version: 2.7.5 - resolution: "lit@npm:2.7.5" +"lit@npm:2.7.6, lit@npm:^2.0.0, lit@npm:^2.0.0-rc.2, lit@npm:^2.2.1, lit@npm:^2.7.0, lit@npm:^2.7.4, lit@npm:^2.7.5": + version: 2.7.6 + resolution: "lit@npm:2.7.6" dependencies: "@lit/reactive-element": ^1.6.0 lit-element: ^3.3.0 lit-html: ^2.7.0 - checksum: 61a3f87c57136618f47a30b36cdfb592fcba42dcfbdb104d2b5ca291148c2d9a32fcb713bb91090bd08d6897a00e73f8425da6e3626aa080eaf410a32397ae69 + checksum: 984a7fb9c0fa387f20177a07de22ea1c9cdc01a7dc7cb1c400d1df5b43a8956908460482a3259ea173555c6f0f13457d2ddc5c84d4c365007afd86e7ca58b384 languageName: node linkType: hard @@ -11502,6 +11485,15 @@ __metadata: languageName: node linkType: hard +"locate-path@npm:^7.1.0": + version: 7.2.0 + resolution: "locate-path@npm:7.2.0" + dependencies: + p-locate: ^6.0.0 + checksum: c1b653bdf29beaecb3d307dfb7c44d98a2a98a02ebe353c9ad055d1ac45d6ed4e1142563d222df9b9efebc2bcb7d4c792b507fad9e7150a04c29530b7db570f8 + languageName: node + linkType: hard + "lodash._reinterpolate@npm:^3.0.0": version: 3.0.0 resolution: "lodash._reinterpolate@npm:3.0.0" @@ -11670,12 +11662,12 @@ __metadata: languageName: node linkType: hard -"magic-string@npm:0.30.0": - version: 0.30.0 - resolution: "magic-string@npm:0.30.0" +"magic-string@npm:0.30.1": + version: 0.30.1 + resolution: "magic-string@npm:0.30.1" dependencies: - "@jridgewell/sourcemap-codec": ^1.4.13 - checksum: 7bdf22e27334d8a393858a16f5f840af63a7c05848c000fd714da5aa5eefa09a1bc01d8469362f25cc5c4a14ec01b46557b7fff8751365522acddf21e57c488d + "@jridgewell/sourcemap-codec": ^1.4.15 + checksum: 7bc7e4493e32a77068f3753bf8652d4ab44142122eb7fb9fa871af83bef2cd2c57518a6769701cd5d0379bd624a13bc8c72ca25ac5655b27e5a61adf1fd38db2 languageName: node linkType: hard @@ -11697,15 +11689,6 @@ __metadata: languageName: node linkType: hard -"make-dir@npm:^3.0.2": - version: 3.1.0 - resolution: "make-dir@npm:3.1.0" - dependencies: - semver: ^6.0.0 - checksum: 484200020ab5a1fdf12f393fe5f385fc8e4378824c940fba1729dcd198ae4ff24867bc7a5646331e50cead8abff5d9270c456314386e629acec6dff4b8016b78 - languageName: node - linkType: hard - "make-fetch-happen@npm:^11.0.3": version: 11.1.1 resolution: "make-fetch-happen@npm:11.1.1" @@ -11970,11 +11953,11 @@ __metadata: linkType: hard "minimatch@npm:^9.0.1": - version: 9.0.1 - resolution: "minimatch@npm:9.0.1" + version: 9.0.3 + resolution: "minimatch@npm:9.0.3" dependencies: brace-expansion: ^2.0.1 - checksum: 97f5f5284bb57dc65b9415dec7f17a0f6531a33572193991c60ff18450dcfad5c2dad24ffeaf60b5261dccd63aae58cc3306e2209d57e7f88c51295a532d8ec3 + checksum: 253487976bf485b612f16bf57463520a14f512662e592e95c571afdab1442a6a6864b6c88f248ce6fc4ff0b6de04ac7aa6c8bb51e868e99d1d65eb0658a708b5 languageName: node linkType: hard @@ -12059,10 +12042,10 @@ __metadata: languageName: node linkType: hard -"minipass@npm:^5.0.0 || ^6.0.2": - version: 6.0.2 - resolution: "minipass@npm:6.0.2" - checksum: d140b91f4ab2e5ce5a9b6c468c0e82223504acc89114c1a120d4495188b81fedf8cade72a9f4793642b4e66672f990f1e0d902dd858485216a07cd3c8a62fac9 +"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0": + version: 7.0.2 + resolution: "minipass@npm:7.0.2" + checksum: 46776de732eb7cef2c7404a15fb28c41f5c54a22be50d47b03c605bf21f5c18d61a173c0a20b49a97e7a65f78d887245066410642551e45fffe04e9ac9e325bc languageName: node linkType: hard @@ -12289,20 +12272,6 @@ __metadata: languageName: node linkType: hard -"node-fetch@npm:^2.6.7": - version: 2.6.11 - resolution: "node-fetch@npm:2.6.11" - dependencies: - whatwg-url: ^5.0.0 - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - checksum: 249d0666a9497553384d46b5ab296ba223521ac88fed4d8a17d6ee6c2efb0fc890f3e8091cafe7f9fba8151a5b8d925db2671543b3409a56c3cd522b468b47b3 - languageName: node - linkType: hard - "node-forge@npm:^1": version: 1.3.1 resolution: "node-forge@npm:1.3.1" @@ -12332,9 +12301,9 @@ __metadata: linkType: hard "node-releases@npm:^2.0.12": - version: 2.0.12 - resolution: "node-releases@npm:2.0.12" - checksum: b8c56db82c4642a0f443332b331a4396dae452a2ac5a65c8dbd93ef89ecb2fbb0da9d42ac5366d4764973febadca816cf7587dad492dce18d2a6b2af59cda260 + version: 2.0.13 + resolution: "node-releases@npm:2.0.13" + checksum: 17ec8f315dba62710cae71a8dad3cd0288ba943d2ece43504b3b1aa8625bf138637798ab470b1d9035b0545996f63000a8a926e0f6d35d0996424f8b6d36dda3 languageName: node linkType: hard @@ -12714,6 +12683,15 @@ __metadata: languageName: node linkType: hard +"p-limit@npm:^4.0.0": + version: 4.0.0 + resolution: "p-limit@npm:4.0.0" + dependencies: + yocto-queue: ^1.0.0 + checksum: 01d9d70695187788f984226e16c903475ec6a947ee7b21948d6f597bed788e3112cc7ec2e171c1d37125057a5f45f3da21d8653e04a3a793589e12e9e80e756b + languageName: node + linkType: hard + "p-locate@npm:^4.1.0": version: 4.1.0 resolution: "p-locate@npm:4.1.0" @@ -12732,6 +12710,15 @@ __metadata: languageName: node linkType: hard +"p-locate@npm:^6.0.0": + version: 6.0.0 + resolution: "p-locate@npm:6.0.0" + dependencies: + p-limit: ^4.0.0 + checksum: 2bfe5234efa5e7a4e74b30a5479a193fdd9236f8f6b4d2f3f69e3d286d9a7d7ab0c118a2a50142efcf4e41625def635bd9332d6cbf9cc65d85eb0718c579ab38 + languageName: node + linkType: hard + "p-map@npm:^4.0.0": version: 4.0.0 resolution: "p-map@npm:4.0.0" @@ -12944,6 +12931,13 @@ __metadata: languageName: node linkType: hard +"path-exists@npm:^5.0.0": + version: 5.0.0 + resolution: "path-exists@npm:5.0.0" + checksum: 8ca842868cab09423994596eb2c5ec2a971c17d1a3cb36dbf060592c730c725cd524b9067d7d2a1e031fef9ba7bd2ac6dc5ec9fb92aa693265f7be3987045254 + languageName: node + linkType: hard + "path-is-absolute@npm:1.0.1, path-is-absolute@npm:^1.0.0": version: 1.0.1 resolution: "path-is-absolute@npm:1.0.1" @@ -12995,13 +12989,13 @@ __metadata: languageName: node linkType: hard -"path-scurry@npm:^1.10.0": - version: 1.10.0 - resolution: "path-scurry@npm:1.10.0" +"path-scurry@npm:^1.10.1": + version: 1.10.1 + resolution: "path-scurry@npm:1.10.1" dependencies: lru-cache: ^9.1.1 || ^10.0.0 - minipass: ^5.0.0 || ^6.0.2 - checksum: 3b66a4a6ab66e45755b577c966ecf0da92d3e068b3c992d8f69aa2cc908ef4eda9358253e9b4f86cad43d3ad810ec445be164105975f5cb3fdab68459c59dc6e + minipass: ^5.0.0 || ^6.0.2 || ^7.0.0 + checksum: e2557cff3a8fb8bc07afdd6ab163a92587884f9969b05bbbaf6fe7379348bfb09af9ed292af12ed32398b15fb443e81692047b786d1eeb6d898a51eb17ed7d90 languageName: node linkType: hard @@ -13133,7 +13127,7 @@ __metadata: languageName: node linkType: hard -"pkg-dir@npm:^4.1.0, pkg-dir@npm:^4.2.0": +"pkg-dir@npm:^4.2.0": version: 4.2.0 resolution: "pkg-dir@npm:4.2.0" dependencies: @@ -13142,6 +13136,15 @@ __metadata: languageName: node linkType: hard +"pkg-dir@npm:^7.0.0": + version: 7.0.0 + resolution: "pkg-dir@npm:7.0.0" + dependencies: + find-up: ^6.3.0 + checksum: 94298b20a446bfbbd66604474de8a0cdd3b8d251225170970f15d9646f633e056c80520dd5b4c1d1050c9fed8f6a9e5054b141c93806439452efe72e57562c03 + languageName: node + linkType: hard + "plugin-error@npm:0.1.2": version: 0.1.2 resolution: "plugin-error@npm:0.1.2" @@ -13200,13 +13203,13 @@ __metadata: linkType: hard "postcss@npm:^8.4.14": - version: 8.4.24 - resolution: "postcss@npm:8.4.24" + version: 8.4.26 + resolution: "postcss@npm:8.4.26" dependencies: nanoid: ^3.3.6 picocolors: ^1.0.0 source-map-js: ^1.0.2 - checksum: 814e2126dacfea313588eda09cc99a9b4c26ec55c059188aa7a916d20d26d483483106dc5ff9e560731b59f45c5bb91b945dfadc670aed875cc90ddbbf4e787d + checksum: 1cf08ee10d58cbe98f94bf12ac49a5e5ed1588507d333d2642aacc24369ca987274e1f60ff4cbf0081f70d2ab18a5cd3a4a273f188d835b8e7f3ba381b184e57 languageName: node linkType: hard @@ -13224,12 +13227,12 @@ __metadata: languageName: node linkType: hard -"prettier@npm:2.8.8": - version: 2.8.8 - resolution: "prettier@npm:2.8.8" +"prettier@npm:3.0.0": + version: 3.0.0 + resolution: "prettier@npm:3.0.0" bin: - prettier: bin-prettier.js - checksum: b49e409431bf129dd89238d64299ba80717b57ff5a6d1c1a8b1a28b590d998a34e083fa13573bc732bb8d2305becb4c9a4407f8486c81fa7d55100eb08263cf8 + prettier: bin/prettier.cjs + checksum: 6a832876a1552dc58330d2467874e5a0b46b9ccbfc5d3531eb69d15684743e7f83dc9fbd202db6270446deba9c82b79d24383d09924c462b457136a759425e33 languageName: node linkType: hard @@ -13558,7 +13561,7 @@ __metadata: languageName: node linkType: hard -"regexp.prototype.flags@npm:^1.4.3": +"regexp.prototype.flags@npm:^1.4.3, regexp.prototype.flags@npm:^1.5.0": version: 1.5.0 resolution: "regexp.prototype.flags@npm:1.5.0" dependencies: @@ -13959,6 +13962,18 @@ __metadata: languageName: node linkType: hard +"safe-array-concat@npm:^1.0.0": + version: 1.0.0 + resolution: "safe-array-concat@npm:1.0.0" + dependencies: + call-bind: ^1.0.2 + get-intrinsic: ^1.2.0 + has-symbols: ^1.0.3 + isarray: ^2.0.5 + checksum: f43cb98fe3b566327d0c09284de2b15fb85ae964a89495c1b1a5d50c7c8ed484190f4e5e71aacc167e16231940079b326f2c0807aea633d47cc7322f40a6b57f + languageName: node + linkType: hard + "safe-buffer@npm:5.1.2, safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1": version: 5.1.2 resolution: "safe-buffer@npm:5.1.2" @@ -14063,31 +14078,31 @@ __metadata: linkType: hard "semver@npm:2 || 3 || 4 || 5, semver@npm:^5.7.1": - version: 5.7.1 - resolution: "semver@npm:5.7.1" + version: 5.7.2 + resolution: "semver@npm:5.7.2" bin: - semver: ./bin/semver - checksum: 57fd0acfd0bac382ee87cd52cd0aaa5af086a7dc8d60379dfe65fea491fb2489b6016400813930ecd61fd0952dae75c115287a1b16c234b1550887117744dfaf + semver: bin/semver + checksum: fb4ab5e0dd1c22ce0c937ea390b4a822147a9c53dbd2a9a0132f12fe382902beef4fbf12cf51bb955248d8d15874ce8cd89532569756384f994309825f10b686 languageName: node linkType: hard -"semver@npm:^6.0.0, semver@npm:^6.1.1, semver@npm:^6.1.2, semver@npm:^6.3.0": - version: 6.3.0 - resolution: "semver@npm:6.3.0" +"semver@npm:^6.3.0, semver@npm:^6.3.1": + version: 6.3.1 + resolution: "semver@npm:6.3.1" bin: - semver: ./bin/semver.js - checksum: 1b26ecf6db9e8292dd90df4e781d91875c0dcc1b1909e70f5d12959a23c7eebb8f01ea581c00783bbee72ceeaad9505797c381756326073850dc36ed284b21b9 + semver: bin/semver.js + checksum: ae47d06de28836adb9d3e25f22a92943477371292d9b665fb023fae278d345d508ca1958232af086d85e0155aee22e313e100971898bbb8d5d89b8b1d4054ca2 languageName: node linkType: hard -"semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7": - version: 7.5.2 - resolution: "semver@npm:7.5.2" +"semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.5.4": + version: 7.5.4 + resolution: "semver@npm:7.5.4" dependencies: lru-cache: ^6.0.0 bin: semver: bin/semver.js - checksum: 3fdf5d1e6f170fe8bcc41669e31787649af91af7f54f05c71d0865bb7aa27e8b92f68b3e6b582483e2c1c648008bc84249d2cd86301771fe5cbf7621d1fe5375 + checksum: 12d8ad952fa353b0995bf180cdac205a4068b759a140e5d3c608317098b3575ac2f1e09182206bf2eb26120e1c0ed8fb92c48c592f6099680de56bb071423ca3 languageName: node linkType: hard @@ -14845,7 +14860,7 @@ __metadata: languageName: node linkType: hard -"strip-json-comments@npm:3.1.1, strip-json-comments@npm:^3.1.0, strip-json-comments@npm:^3.1.1": +"strip-json-comments@npm:3.1.1, strip-json-comments@npm:^3.1.1": version: 3.1.1 resolution: "strip-json-comments@npm:3.1.1" checksum: 492f73e27268f9b1c122733f28ecb0e7e8d8a531a6662efbd08e22cccb3f9475e90a1b82cab06a392f6afae6d2de636f977e231296400d0ec5304ba70f166443 @@ -15027,8 +15042,8 @@ __metadata: linkType: hard "terser@npm:^5.0.0, terser@npm:^5.15.1, terser@npm:^5.16.8": - version: 5.18.0 - resolution: "terser@npm:5.18.0" + version: 5.19.1 + resolution: "terser@npm:5.19.1" dependencies: "@jridgewell/source-map": ^0.3.3 acorn: ^8.8.2 @@ -15036,7 +15051,7 @@ __metadata: source-map-support: ~0.5.20 bin: terser: bin/terser - checksum: d01eb9805a978b3338b68fd2d9e35c1cd4cad78ea093dc92c7b3c38965232f0af0f95e0c6d90920ecf600a74135c608aebae26302c036c01393a590e1918bb90 + checksum: 18657b2a282238a1ca9c825efa966f4dd043a33196b2f8a7a2cba406a2006e14f55295b9d9cf6380a18599b697e9579e4092c99b9f40c7871ceec01cc98e3606 languageName: node linkType: hard @@ -15236,10 +15251,12 @@ __metadata: languageName: node linkType: hard -"tr46@npm:~0.0.3": - version: 0.0.3 - resolution: "tr46@npm:0.0.3" - checksum: 726321c5eaf41b5002e17ffbd1fb7245999a073e8979085dacd47c4b4e8068ff5777142fc6726d6ca1fd2ff16921b48788b87225cbc57c72636f6efa8efbffe3 +"ts-api-utils@npm:^1.0.1": + version: 1.0.1 + resolution: "ts-api-utils@npm:1.0.1" + peerDependencies: + typescript: ">=4.2.0" + checksum: 78794fc7270d295b36c1ac613465b5dc7e7226907a533125b30f177efef9dd630d4e503b00be31b44335eb2ebf9e136ebe97353f8fc5d383885d5fead9d54c09 languageName: node linkType: hard @@ -15272,103 +15289,96 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^1.8.1": - version: 1.14.1 - resolution: "tslib@npm:1.14.1" - checksum: dbe628ef87f66691d5d2959b3e41b9ca0045c3ee3c7c7b906cc1e328b39f199bb1ad9e671c39025bd56122ac57dfbf7385a94843b1cc07c60a4db74795829acd - languageName: node - linkType: hard - "tslib@npm:^2.0.1, tslib@npm:^2.0.2, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.2.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0": - version: 2.5.3 - resolution: "tslib@npm:2.5.3" - checksum: 88902b309afaf83259131c1e13da1dceb0ad1682a213143a1346a649143924d78cf3760c448b84d796938fd76127183894f8d85cbb3bf9c4fddbfcc140c0003c + version: 2.6.0 + resolution: "tslib@npm:2.6.0" + checksum: c01066038f950016a18106ddeca4649b4d76caa76ec5a31e2a26e10586a59fceb4ee45e96719bf6c715648e7c14085a81fee5c62f7e9ebee68e77a5396e5538f languageName: node linkType: hard -"tsparticles-engine@npm:2.10.1, tsparticles-engine@npm:^2.10.1": - version: 2.10.1 - resolution: "tsparticles-engine@npm:2.10.1" - checksum: 5662c453b1e4c37c608435393a8c5ae03bd9b301dc488a3909bdddf321f38c486b6076d61641add3e2d8764c6e8eb28021e1b424da3240b6efa723c6e8bcbc43 +"tsparticles-engine@npm:2.11.0, tsparticles-engine@npm:^2.11.0": + version: 2.11.0 + resolution: "tsparticles-engine@npm:2.11.0" + checksum: 1aad1c3969b38dec5b468220eba7a1a26982fd8b13567f37970fe8d1cd6e7609da8622e8b16599b6359ecc681a33e9672a8a697e5ea9f146b15cc709b9fa78d9 languageName: node linkType: hard -"tsparticles-interaction-particles-links@npm:^2.10.1": - version: 2.10.1 - resolution: "tsparticles-interaction-particles-links@npm:2.10.1" +"tsparticles-interaction-particles-links@npm:^2.11.0": + version: 2.11.0 + resolution: "tsparticles-interaction-particles-links@npm:2.11.0" dependencies: - tsparticles-engine: ^2.10.1 - checksum: 994fcac1cfcae34409095437db7684cc9f74b4e084995da310ea7f1a63c0a97030cac8fde47a7a54b5e8644e26a3b72fb5e6d229e10758eb1e6fcf52800b8e83 + tsparticles-engine: ^2.11.0 + checksum: 38bfca50c5c8b55ef3cc55975a5be80479e283dbe04247f165635281f37f9b9fb6b884e5e996ca99e0da3725e4777100ddef2a04dab6216896649f48a89faf04 languageName: node linkType: hard -"tsparticles-move-base@npm:^2.10.1": - version: 2.10.1 - resolution: "tsparticles-move-base@npm:2.10.1" +"tsparticles-move-base@npm:^2.11.0": + version: 2.11.0 + resolution: "tsparticles-move-base@npm:2.11.0" dependencies: - tsparticles-engine: ^2.10.1 - checksum: 26fb88e7622dfbede4d0177d01645917b01611bf8be32508588e7d8d6e28fcaf58daf900095a7947382d59fe9fcd420563cc6fc6a50c67c9c7ea7236c601d9b7 + tsparticles-engine: ^2.11.0 + checksum: a049e1ecd23f8b3fd19b236040085e415765b299e919647acc18e43eb2b6d51176c97ae3095f313cd0959096638d6d6ad4337d5c9cff8d98d1b8dadbad02eaff languageName: node linkType: hard -"tsparticles-preset-links@npm:2.10.1": - version: 2.10.1 - resolution: "tsparticles-preset-links@npm:2.10.1" +"tsparticles-preset-links@npm:2.11.0": + version: 2.11.0 + resolution: "tsparticles-preset-links@npm:2.11.0" dependencies: - tsparticles-engine: ^2.10.1 - tsparticles-interaction-particles-links: ^2.10.1 - tsparticles-move-base: ^2.10.1 - tsparticles-shape-circle: ^2.10.1 - tsparticles-updater-color: ^2.10.1 - tsparticles-updater-opacity: ^2.10.1 - tsparticles-updater-out-modes: ^2.10.1 - tsparticles-updater-size: ^2.10.1 - checksum: 0678ad77ae9022f3ceac6b462ad4e049e2a0f5559b035690698609df081d7d6307fb93c38d07f3fe6e0f517635bd6a4831b705b7ba6fc33f79a22d4a3ddf65fe + tsparticles-engine: ^2.11.0 + tsparticles-interaction-particles-links: ^2.11.0 + tsparticles-move-base: ^2.11.0 + tsparticles-shape-circle: ^2.11.0 + tsparticles-updater-color: ^2.11.0 + tsparticles-updater-opacity: ^2.11.0 + tsparticles-updater-out-modes: ^2.11.0 + tsparticles-updater-size: ^2.11.0 + checksum: 4f50e70d25cce142fc1a692dc736819c3e42c6bf3c4d10eaf6667536750ed487ee8e6173914ade73fd26ea9cee0557e84e3bf305efc73fb6288803cd803a22a3 languageName: node linkType: hard -"tsparticles-shape-circle@npm:^2.10.1": - version: 2.10.1 - resolution: "tsparticles-shape-circle@npm:2.10.1" +"tsparticles-shape-circle@npm:^2.11.0": + version: 2.11.0 + resolution: "tsparticles-shape-circle@npm:2.11.0" dependencies: - tsparticles-engine: ^2.10.1 - checksum: 49c2a865745c6217b08006c11f134e64792e1d62abbc1dc6f2484165b6b13b6bd7205cd10171418697680e513bd3c8d128c7d9877c61540722250bb8e1693f02 + tsparticles-engine: ^2.11.0 + checksum: a83098b8d39b8ed89d1ced0f7b2e560d53b8d0f85f3993cd539b8a72d12d84cc9ef67ccc663ac580489129f33638c1791506c40d69ac0afcf8cb2e999688b2c1 languageName: node linkType: hard -"tsparticles-updater-color@npm:^2.10.1": - version: 2.10.1 - resolution: "tsparticles-updater-color@npm:2.10.1" +"tsparticles-updater-color@npm:^2.11.0": + version: 2.11.0 + resolution: "tsparticles-updater-color@npm:2.11.0" dependencies: - tsparticles-engine: ^2.10.1 - checksum: 6858b429fd59f244251584346d47748216774a9012a6ffb9a614f87ca83b957a6da2b0dffb1c9e5238c84c043c29a23eb828568baf4ddde76c73707a1a0652ba + tsparticles-engine: ^2.11.0 + checksum: bfbac9a31d1ccbc179c646016f45b6ca6990d1b23b654130e38ec8df95402241d20e18d8a5b061e66c82eef4380901ed964ccbe3143d5b8ff757bd91014134e6 languageName: node linkType: hard -"tsparticles-updater-opacity@npm:^2.10.1": - version: 2.10.1 - resolution: "tsparticles-updater-opacity@npm:2.10.1" +"tsparticles-updater-opacity@npm:^2.11.0": + version: 2.11.0 + resolution: "tsparticles-updater-opacity@npm:2.11.0" dependencies: - tsparticles-engine: ^2.10.1 - checksum: f5a418dfe922db99cd6ee75a7accb901eebb4e4f34ef411be46a1d88c8893816b4f8487f7b100a0a1cda749fdecf1d052efaae994a8639a464b6d6829ec9ee8b + tsparticles-engine: ^2.11.0 + checksum: e8bf67196b529fabc838140ffe2997c58e27ab569e70a9815b10db93e8d5496f4f07e04b600b832d1a22239970eca29b2619e30f00cb0f2cc0428bd73c3582f0 languageName: node linkType: hard -"tsparticles-updater-out-modes@npm:^2.10.1": - version: 2.10.1 - resolution: "tsparticles-updater-out-modes@npm:2.10.1" +"tsparticles-updater-out-modes@npm:^2.11.0": + version: 2.11.0 + resolution: "tsparticles-updater-out-modes@npm:2.11.0" dependencies: - tsparticles-engine: ^2.10.1 - checksum: 0f78d2aae5fa03f1af32dbe9eab326d6ef59b4e63226a84a5f8ce91efb1beecd13e0465068de9c9cd70ba830c212552fbe3b01fd21c674368ba39071af335e9b + tsparticles-engine: ^2.11.0 + checksum: 8f14fb9756c98e48d0d613b439bbb6c21d385b95cf78cebcc8077da15f42b2d9c219d7b51e9ed8f2643eb00a9871d2cdb91fc96922376827bf69171d030fc7ac languageName: node linkType: hard -"tsparticles-updater-size@npm:^2.10.1": - version: 2.10.1 - resolution: "tsparticles-updater-size@npm:2.10.1" +"tsparticles-updater-size@npm:^2.11.0": + version: 2.11.0 + resolution: "tsparticles-updater-size@npm:2.11.0" dependencies: - tsparticles-engine: ^2.10.1 - checksum: c77ce515aa765f4e069d232ca7407105d86c432042593fffdd6ae33948f84a654cba7e41c0aef00c2327ed3b5715ab07e057153b93afe5c7a2a5917eee786e85 + tsparticles-engine: ^2.11.0 + checksum: b14aecf4000441fe3e7f37cacd9f9074bb8fcd96b7ed0eb1be16274da8a843d005bca37949043867378138c6e65ccdd76c849ba2528a1c4cf92ad6488b4da7d8 languageName: node linkType: hard @@ -15379,17 +15389,6 @@ __metadata: languageName: node linkType: hard -"tsutils@npm:^3.21.0": - version: 3.21.0 - resolution: "tsutils@npm:3.21.0" - dependencies: - tslib: ^1.8.1 - peerDependencies: - typescript: ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - checksum: 1843f4c1b2e0f975e08c4c21caa4af4f7f65a12ac1b81b3b8489366826259323feb3fc7a243123453d2d1a02314205a7634e048d4a8009921da19f99755cdc48 - languageName: node - linkType: hard - "type-check@npm:^0.4.0, type-check@npm:~0.4.0": version: 0.4.0 resolution: "type-check@npm:0.4.0" @@ -15451,6 +15450,42 @@ __metadata: languageName: node linkType: hard +"typed-array-buffer@npm:^1.0.0": + version: 1.0.0 + resolution: "typed-array-buffer@npm:1.0.0" + dependencies: + call-bind: ^1.0.2 + get-intrinsic: ^1.2.1 + is-typed-array: ^1.1.10 + checksum: 3e0281c79b2a40cd97fe715db803884301993f4e8c18e8d79d75fd18f796e8cd203310fec8c7fdb5e6c09bedf0af4f6ab8b75eb3d3a85da69328f28a80456bd3 + languageName: node + linkType: hard + +"typed-array-byte-length@npm:^1.0.0": + version: 1.0.0 + resolution: "typed-array-byte-length@npm:1.0.0" + dependencies: + call-bind: ^1.0.2 + for-each: ^0.3.3 + has-proto: ^1.0.1 + is-typed-array: ^1.1.10 + checksum: b03db16458322b263d87a702ff25388293f1356326c8a678d7515767ef563ef80e1e67ce648b821ec13178dd628eb2afdc19f97001ceae7a31acf674c849af94 + languageName: node + linkType: hard + +"typed-array-byte-offset@npm:^1.0.0": + version: 1.0.0 + resolution: "typed-array-byte-offset@npm:1.0.0" + dependencies: + available-typed-arrays: ^1.0.5 + call-bind: ^1.0.2 + for-each: ^0.3.3 + has-proto: ^1.0.1 + is-typed-array: ^1.1.10 + checksum: 04f6f02d0e9a948a95fbfe0d5a70b002191fae0b8fe0fe3130a9b2336f043daf7a3dda56a31333c35a067a97e13f539949ab261ca0f3692c41603a46a94e960b + languageName: node + linkType: hard + "typed-array-length@npm:^1.0.4": version: 1.0.4 resolution: "typed-array-length@npm:1.0.4" @@ -16022,13 +16057,6 @@ __metadata: languageName: node linkType: hard -"webidl-conversions@npm:^3.0.0": - version: 3.0.1 - resolution: "webidl-conversions@npm:3.0.1" - checksum: c92a0a6ab95314bde9c32e1d0a6dfac83b578f8fa5f21e675bc2706ed6981bc26b7eb7e6a1fab158e5ce4adf9caa4a0aee49a52505d4d13c7be545f15021b17c - languageName: node - linkType: hard - "webidl-conversions@npm:^4.0.2": version: 4.0.2 resolution: "webidl-conversions@npm:4.0.2" @@ -16176,9 +16204,9 @@ __metadata: languageName: node linkType: hard -"webpack@npm:5.88.1": - version: 5.88.1 - resolution: "webpack@npm:5.88.1" +"webpack@npm:5.88.2": + version: 5.88.2 + resolution: "webpack@npm:5.88.2" dependencies: "@types/eslint-scope": ^3.7.3 "@types/estree": ^1.0.0 @@ -16209,7 +16237,7 @@ __metadata: optional: true bin: webpack: bin/webpack.js - checksum: 726e7e05ab2e7c142609a673dd6aa1a711ed97f349418a2a393d650c5ddad172d191257f60e1e37f6b2a77261571c202aabd5ce9240791a686774f0801cf5ec2 + checksum: 79476a782da31a21f6dd38fbbd06b68da93baf6a62f0d08ca99222367f3b8668f5a1f2086b7bb78e23172e31fa6df6fa7ab09b25e827866c4fc4dc2b30443ce2 languageName: node linkType: hard @@ -16262,16 +16290,6 @@ __metadata: languageName: node linkType: hard -"whatwg-url@npm:^5.0.0": - version: 5.0.0 - resolution: "whatwg-url@npm:5.0.0" - dependencies: - tr46: ~0.0.3 - webidl-conversions: ^3.0.0 - checksum: b8daed4ad3356cc4899048a15b2c143a9aed0dfae1f611ebd55073310c7b910f522ad75d727346ad64203d7e6c79ef25eafd465f4d12775ca44b90fa82ed9e2c - languageName: node - linkType: hard - "whatwg-url@npm:^7.0.0": version: 7.1.0 resolution: "whatwg-url@npm:7.1.0" @@ -16310,17 +16328,16 @@ __metadata: languageName: node linkType: hard -"which-typed-array@npm:^1.1.9": - version: 1.1.9 - resolution: "which-typed-array@npm:1.1.9" +"which-typed-array@npm:^1.1.10, which-typed-array@npm:^1.1.11": + version: 1.1.11 + resolution: "which-typed-array@npm:1.1.11" dependencies: available-typed-arrays: ^1.0.5 call-bind: ^1.0.2 for-each: ^0.3.3 gopd: ^1.0.1 has-tostringtag: ^1.0.0 - is-typed-array: ^1.1.10 - checksum: fe0178ca44c57699ca2c0e657b64eaa8d2db2372a4e2851184f568f98c478ae3dc3fdb5f7e46c384487046b0cf9e23241423242b277e03e8ba3dabc7c84c98ef + checksum: 711ffc8ef891ca6597b19539075ec3e08bb9b4c2ca1f78887e3c07a977ab91ac1421940505a197758fb5939aa9524976d0a5bbcac34d07ed6faa75cedbb17206 languageName: node linkType: hard @@ -16886,3 +16903,10 @@ __metadata: checksum: f77b3d8d00310def622123df93d4ee654fc6a0096182af8bd60679ddcdfb3474c56c6c7190817c84a2785648cdee9d721c0154eb45698c62176c322fb46fc700 languageName: node linkType: hard + +"yocto-queue@npm:^1.0.0": + version: 1.0.0 + resolution: "yocto-queue@npm:1.0.0" + checksum: 2cac84540f65c64ccc1683c267edce396b26b1e931aa429660aefac8fbe0188167b7aee815a3c22fa59a28a58d898d1a2b1825048f834d8d629f4c2a5d443801 + languageName: node + linkType: hard