mirror of
https://github.com/home-assistant/frontend.git
synced 2025-09-15 07:59:43 +00:00
Compare commits
7 Commits
expand-sec
...
target-sel
Author | SHA1 | Date | |
---|---|---|---|
![]() |
043849b057 | ||
![]() |
9a69566000 | ||
![]() |
9cdb57476a | ||
![]() |
f8d90d003e | ||
![]() |
f53ee52b0e | ||
![]() |
f8cc1531e5 | ||
![]() |
11f65ef0f7 |
8
.github/workflows/cast_deployment.yaml
vendored
8
.github/workflows/cast_deployment.yaml
vendored
@@ -21,12 +21,12 @@ jobs:
|
||||
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
||||
steps:
|
||||
- name: Check out files from GitHub
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@v5.0.0
|
||||
with:
|
||||
ref: dev
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
uses: actions/setup-node@v5.0.0
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
@@ -56,12 +56,12 @@ jobs:
|
||||
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
||||
steps:
|
||||
- name: Check out files from GitHub
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@v5.0.0
|
||||
with:
|
||||
ref: master
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
uses: actions/setup-node@v5.0.0
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
|
22
.github/workflows/ci.yaml
vendored
22
.github/workflows/ci.yaml
vendored
@@ -24,9 +24,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out files from GitHub
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@v5.0.0
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
uses: actions/setup-node@v5.0.0
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
- 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@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||
uses: actions/cache@v4.2.4
|
||||
with:
|
||||
path: |
|
||||
node_modules/.cache/prettier
|
||||
@@ -58,9 +58,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out files from GitHub
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@v5.0.0
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
uses: actions/setup-node@v5.0.0
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
@@ -76,9 +76,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out files from GitHub
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@v5.0.0
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
uses: actions/setup-node@v5.0.0
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
@@ -89,7 +89,7 @@ jobs:
|
||||
env:
|
||||
IS_TEST: "true"
|
||||
- name: Upload bundle stats
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
uses: actions/upload-artifact@v4.6.2
|
||||
with:
|
||||
name: frontend-bundle-stats
|
||||
path: build/stats/*.json
|
||||
@@ -100,9 +100,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out files from GitHub
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@v5.0.0
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
uses: actions/setup-node@v5.0.0
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
@@ -113,7 +113,7 @@ jobs:
|
||||
env:
|
||||
IS_TEST: "true"
|
||||
- name: Upload bundle stats
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
uses: actions/upload-artifact@v4.6.2
|
||||
with:
|
||||
name: supervisor-bundle-stats
|
||||
path: build/stats/*.json
|
||||
|
8
.github/workflows/codeql-analysis.yml
vendored
8
.github/workflows/codeql-analysis.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@v5.0.0
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
@@ -36,14 +36,14 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@2d92b76c45b91eb80fc44c74ce3fce0ee94e8f9d # v3.30.0
|
||||
uses: github/codeql-action/init@v3
|
||||
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@2d92b76c45b91eb80fc44c74ce3fce0ee94e8f9d # v3.30.0
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
@@ -57,4 +57,4 @@ jobs:
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@2d92b76c45b91eb80fc44c74ce3fce0ee94e8f9d # v3.30.0
|
||||
uses: github/codeql-action/analyze@v3
|
||||
|
8
.github/workflows/demo_deployment.yaml
vendored
8
.github/workflows/demo_deployment.yaml
vendored
@@ -22,12 +22,12 @@ jobs:
|
||||
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
||||
steps:
|
||||
- name: Check out files from GitHub
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@v5.0.0
|
||||
with:
|
||||
ref: dev
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
uses: actions/setup-node@v5.0.0
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
@@ -57,12 +57,12 @@ jobs:
|
||||
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
||||
steps:
|
||||
- name: Check out files from GitHub
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@v5.0.0
|
||||
with:
|
||||
ref: master
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
uses: actions/setup-node@v5.0.0
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
|
4
.github/workflows/design_deployment.yaml
vendored
4
.github/workflows/design_deployment.yaml
vendored
@@ -16,10 +16,10 @@ jobs:
|
||||
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
||||
steps:
|
||||
- name: Check out files from GitHub
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@v5.0.0
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
uses: actions/setup-node@v5.0.0
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
|
4
.github/workflows/design_preview.yaml
vendored
4
.github/workflows/design_preview.yaml
vendored
@@ -21,10 +21,10 @@ jobs:
|
||||
if: github.repository == 'home-assistant/frontend' && contains(github.event.pull_request.labels.*.name, 'needs design preview')
|
||||
steps:
|
||||
- name: Check out files from GitHub
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@v5.0.0
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
uses: actions/setup-node@v5.0.0
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
|
2
.github/workflows/labeler.yaml
vendored
2
.github/workflows/labeler.yaml
vendored
@@ -10,6 +10,6 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Apply labels
|
||||
uses: actions/labeler@634933edcd8ababfe52f92936142cc22ac488b1b # v6.0.1
|
||||
uses: actions/labeler@v6.0.1
|
||||
with:
|
||||
sync-labels: true
|
||||
|
2
.github/workflows/lock.yml
vendored
2
.github/workflows/lock.yml
vendored
@@ -9,7 +9,7 @@ jobs:
|
||||
lock:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/lock-threads@1bf7ec25051fe7c00bdd17e6a7cf3d7bfb7dc771 # v5.0.1
|
||||
- uses: dessant/lock-threads@v5.0.1
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
process-only: "issues, prs"
|
||||
|
10
.github/workflows/nightly.yaml
vendored
10
.github/workflows/nightly.yaml
vendored
@@ -20,15 +20,15 @@ jobs:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@v5.0.0
|
||||
|
||||
- name: Set up Python ${{ env.PYTHON_VERSION }}
|
||||
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
uses: actions/setup-node@v5.0.0
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
@@ -57,14 +57,14 @@ jobs:
|
||||
run: tar -czvf translations.tar.gz translations
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
uses: actions/upload-artifact@v4.6.2
|
||||
with:
|
||||
name: wheels
|
||||
path: dist/home_assistant_frontend*.whl
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload translations
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
uses: actions/upload-artifact@v4.6.2
|
||||
with:
|
||||
name: translations
|
||||
path: translations.tar.gz
|
||||
|
2
.github/workflows/relative-ci.yaml
vendored
2
.github/workflows/relative-ci.yaml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Send bundle stats and build information to RelativeCI
|
||||
uses: relative-ci/agent-action@1707825cbfcc7452b2913d273414705415ae64d4 # v3.0.1
|
||||
uses: relative-ci/agent-action@v3.0.1
|
||||
with:
|
||||
key: ${{ secrets[format('RELATIVE_CI_KEY_{0}_{1}', matrix.bundle, matrix.build)] }}
|
||||
token: ${{ github.token }}
|
||||
|
2
.github/workflows/release-drafter.yaml
vendored
2
.github/workflows/release-drafter.yaml
vendored
@@ -18,6 +18,6 @@ jobs:
|
||||
pull-requests: read
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: release-drafter/release-drafter@b1476f6e6eb133afa41ed8589daba6dc69b4d3f5 # v6.1.0
|
||||
- uses: release-drafter/release-drafter@v6.1.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
21
.github/workflows/release.yaml
vendored
21
.github/workflows/release.yaml
vendored
@@ -23,10 +23,10 @@ jobs:
|
||||
contents: write # Required to upload release assets
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@v5.0.0
|
||||
|
||||
- name: Set up Python ${{ env.PYTHON_VERSION }}
|
||||
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: ${{ env.PYTHON_VERSION }}
|
||||
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
uses: home-assistant/actions/helpers/verify-version@master
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
uses: actions/setup-node@v5.0.0
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
script/release
|
||||
|
||||
- name: Upload release assets
|
||||
uses: softprops/action-gh-release@6cbd405e2c4e67a21c47fa9e383d020e4e28b836 # v2.3.3
|
||||
uses: softprops/action-gh-release@v2.3.3
|
||||
with:
|
||||
files: |
|
||||
dist/*.whl
|
||||
@@ -73,7 +73,6 @@ jobs:
|
||||
version=$(echo "${{ github.ref }}" | awk -F"/" '{print $NF}' )
|
||||
echo "home-assistant-frontend==$version" > ./requirements.txt
|
||||
|
||||
# home-assistant/wheels doesn't support SHA pinning
|
||||
- name: Build wheels
|
||||
uses: home-assistant/wheels@2025.07.0
|
||||
with:
|
||||
@@ -91,9 +90,9 @@ jobs:
|
||||
contents: write # Required to upload release assets
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@v5.0.0
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
uses: actions/setup-node@v5.0.0
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
@@ -108,7 +107,7 @@ jobs:
|
||||
- name: Tar folder
|
||||
run: tar -czf landing-page/home_assistant_frontend_landingpage-${{ github.event.release.tag_name }}.tar.gz -C landing-page/dist .
|
||||
- name: Upload release asset
|
||||
uses: softprops/action-gh-release@6cbd405e2c4e67a21c47fa9e383d020e4e28b836 # v2.3.3
|
||||
uses: softprops/action-gh-release@v2.3.3
|
||||
with:
|
||||
files: landing-page/home_assistant_frontend_landingpage-${{ github.event.release.tag_name }}.tar.gz
|
||||
|
||||
@@ -120,9 +119,9 @@ jobs:
|
||||
contents: write # Required to upload release assets
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@v5.0.0
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
uses: actions/setup-node@v5.0.0
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: yarn
|
||||
@@ -137,6 +136,6 @@ jobs:
|
||||
- name: Tar folder
|
||||
run: tar -czf hassio/home_assistant_frontend_supervisor-${{ github.event.release.tag_name }}.tar.gz -C hassio/build .
|
||||
- name: Upload release asset
|
||||
uses: softprops/action-gh-release@6cbd405e2c4e67a21c47fa9e383d020e4e28b836 # v2.3.3
|
||||
uses: softprops/action-gh-release@v2.3.3
|
||||
with:
|
||||
files: hassio/home_assistant_frontend_supervisor-${{ github.event.release.tag_name }}.tar.gz
|
||||
|
2
.github/workflows/restrict-task-creation.yml
vendored
2
.github/workflows/restrict-task-creation.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
if: github.event.issue.type.name == 'Task'
|
||||
steps:
|
||||
- name: Check if user is authorized
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
script: |
|
||||
const issueAuthor = context.payload.issue.user.login;
|
||||
|
2
.github/workflows/stale.yml
vendored
2
.github/workflows/stale.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 90 days stale policy
|
||||
uses: actions/stale@3a9db7e6a41a89f618792c92c0e97cc736e1b13f # v10.0.0
|
||||
uses: actions/stale@v10.0.0
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
days-before-stale: 90
|
||||
|
2
.github/workflows/translations.yaml
vendored
2
.github/workflows/translations.yaml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@v5.0.0
|
||||
|
||||
- name: Upload Translations
|
||||
run: |
|
||||
|
@@ -6,23 +6,21 @@ A tooltip's target is its _first child element_, so you should only wrap one ele
|
||||
|
||||
Tooltips use `display: contents` so they won't interfere with how elements are positioned in a flex or grid layout.
|
||||
|
||||
<ha-button id="hover">Hover Me</ha-button>
|
||||
<ha-tooltip for="hover">
|
||||
This is a tooltip
|
||||
<ha-tooltip content="This is a tooltip">
|
||||
<ha-button>Hover Me</ha-button>
|
||||
</ha-tooltip>
|
||||
|
||||
```
|
||||
<ha-button id="hover">Hover Me</ha-button>
|
||||
<ha-tooltip for="hover">
|
||||
This is a tooltip
|
||||
<ha-tooltip content="This is a tooltip">
|
||||
<ha-button>Hover Me</ha-button>
|
||||
</ha-tooltip>
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
This element is based on webawesome `wa-tooltip` it only sets some css tokens and has a custom show/hide animation.
|
||||
This element is based on shoelace `sl-tooltip` it only sets some css tokens and has a custom show/hide animation.
|
||||
|
||||
<a href="https://webawesome.com/docs/components/tooltip/" target="_blank" rel="noopener noreferrer">Webawesome documentation</a>
|
||||
<a href="https://shoelace.style/components/tooltip" target="_blank" rel="noopener noreferrer">Shoelace documentation</a>
|
||||
|
||||
### HA style tokens
|
||||
|
||||
@@ -30,7 +28,7 @@ In your theme settings use this without the prefixed `--`.
|
||||
|
||||
- `--ha-tooltip-border-radius` (Default: 4px)
|
||||
- `--ha-tooltip-arrow-size` (Default: 8px)
|
||||
- `--wa-tooltip-font-family` (Default: `var(--ha-font-family-body)`)
|
||||
- `--sl-tooltip-font-family` (Default: `var(--ha-font-family-body)`)
|
||||
- `--ha-tooltip-font-size` (Default: `var(--ha-font-size-s)`)
|
||||
- `--wa-tooltip-font-weight` (Default: `var(--ha-font-weight-normal)`)
|
||||
- `--wa-tooltip-line-height` (Default: `var(--ha-line-height-condensed)`)
|
||||
- `--sl-tooltip-font-weight` (Default: `var(--ha-font-weight-normal)`)
|
||||
- `--sl-tooltip-line-height` (Default: `var(--ha-line-height-condensed)`)
|
||||
|
@@ -199,7 +199,6 @@ class HassioAddonConfig extends LitElement {
|
||||
<div class="card-content">
|
||||
${showForm
|
||||
? html`<ha-form
|
||||
.hass=${this.hass}
|
||||
.disabled=${this.disabled}
|
||||
.data=${this._options!}
|
||||
@value-changed=${this._configChanged}
|
||||
|
@@ -119,27 +119,26 @@ class HassioRepositoriesDialog extends LitElement {
|
||||
<div>${repo.url}</div>
|
||||
</div>
|
||||
<ha-tooltip
|
||||
.for="icon-button-${repo.slug}"
|
||||
class="delete"
|
||||
slot="end"
|
||||
>
|
||||
${this._dialogParams!.supervisor.localize(
|
||||
.content=${this._dialogParams!.supervisor.localize(
|
||||
usedRepositories.includes(repo.slug)
|
||||
? "dialog.repositories.used"
|
||||
: "dialog.repositories.remove"
|
||||
)}
|
||||
>
|
||||
<div>
|
||||
<ha-icon-button
|
||||
.disabled=${usedRepositories.includes(repo.slug)}
|
||||
.slug=${repo.slug}
|
||||
.path=${usedRepositories.includes(repo.slug)
|
||||
? mdiDeleteOff
|
||||
: mdiDelete}
|
||||
@click=${this._removeRepository}
|
||||
>
|
||||
</ha-icon-button>
|
||||
</div>
|
||||
</ha-tooltip>
|
||||
<div .id="icon-button-${repo.slug}">
|
||||
<ha-icon-button
|
||||
.disabled=${usedRepositories.includes(repo.slug)}
|
||||
.slug=${repo.slug}
|
||||
.path=${usedRepositories.includes(repo.slug)
|
||||
? mdiDeleteOff
|
||||
: mdiDelete}
|
||||
@click=${this._removeRepository}
|
||||
>
|
||||
</ha-icon-button>
|
||||
</div>
|
||||
</ha-md-list-item>
|
||||
`
|
||||
)
|
||||
|
@@ -3,7 +3,7 @@ import type { PropertyValues, TemplateResult } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../../src/common/dom/fire_event";
|
||||
import { goBack, navigate } from "../../../src/common/navigate";
|
||||
import { navigate } from "../../../src/common/navigate";
|
||||
import { extractSearchParam } from "../../../src/common/url/search-params";
|
||||
import { nextRender } from "../../../src/common/util/render-status";
|
||||
import "../../../src/components/ha-icon-button";
|
||||
@@ -193,7 +193,7 @@ class HassioIngressView extends LitElement {
|
||||
title: addon.name,
|
||||
});
|
||||
await nextRender();
|
||||
goBack();
|
||||
history.back();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -275,7 +275,7 @@ class HassioIngressView extends LitElement {
|
||||
title: addon.name,
|
||||
});
|
||||
await nextRender();
|
||||
goBack();
|
||||
history.back();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -2,7 +2,6 @@ import type { TemplateResult } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import type { Supervisor } from "../../../src/data/supervisor/supervisor";
|
||||
import { goBack } from "../../../src/common/navigate";
|
||||
import "../../../src/layouts/hass-subpage";
|
||||
import type { HomeAssistant, Route } from "../../../src/types";
|
||||
import "./update-available-card";
|
||||
@@ -36,7 +35,7 @@ class UpdateAvailableDashboard extends LitElement {
|
||||
}
|
||||
|
||||
private _updateComplete() {
|
||||
goBack();
|
||||
history.back();
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
|
13
package.json
13
package.json
@@ -51,7 +51,7 @@
|
||||
"@fullcalendar/list": "6.1.19",
|
||||
"@fullcalendar/luxon3": "6.1.19",
|
||||
"@fullcalendar/timegrid": "6.1.19",
|
||||
"@home-assistant/webawesome": "3.0.0-beta.4.ha.3",
|
||||
"@home-assistant/webawesome": "3.0.0-beta.4.ha.2",
|
||||
"@lezer/highlight": "1.2.1",
|
||||
"@lit-labs/motion": "1.0.9",
|
||||
"@lit-labs/observers": "2.0.6",
|
||||
@@ -84,6 +84,7 @@
|
||||
"@mdi/js": "7.4.47",
|
||||
"@mdi/svg": "7.4.47",
|
||||
"@replit/codemirror-indentation-markers": "6.5.3",
|
||||
"@shoelace-style/shoelace": "2.20.1",
|
||||
"@swc/helpers": "0.5.17",
|
||||
"@thomasloven/round-slider": "0.6.0",
|
||||
"@tsparticles/engine": "3.9.1",
|
||||
@@ -111,7 +112,7 @@
|
||||
"fuse.js": "7.1.0",
|
||||
"google-timezones-json": "1.2.0",
|
||||
"gulp-zopfli-green": "6.0.2",
|
||||
"hls.js": "1.6.12",
|
||||
"hls.js": "1.6.11",
|
||||
"home-assistant-js-websocket": "9.5.0",
|
||||
"idb-keyval": "6.2.2",
|
||||
"intl-messageformat": "10.7.16",
|
||||
@@ -135,7 +136,7 @@
|
||||
"stacktrace-js": "2.0.2",
|
||||
"superstruct": "2.0.2",
|
||||
"tinykeys": "3.0.0",
|
||||
"ua-parser-js": "2.0.5",
|
||||
"ua-parser-js": "2.0.4",
|
||||
"vue": "2.7.16",
|
||||
"vue2-daterange-picker": "0.6.8",
|
||||
"weekstart": "2.0.0",
|
||||
@@ -158,7 +159,7 @@
|
||||
"@octokit/plugin-retry": "8.0.1",
|
||||
"@octokit/rest": "22.0.0",
|
||||
"@rsdoctor/rspack-plugin": "1.2.3",
|
||||
"@rspack/core": "1.5.3",
|
||||
"@rspack/core": "1.5.2",
|
||||
"@rspack/dev-server": "1.1.4",
|
||||
"@types/babel__plugin-transform-runtime": "7.9.5",
|
||||
"@types/chromecast-caf-receiver": "6.0.24",
|
||||
@@ -217,7 +218,7 @@
|
||||
"terser-webpack-plugin": "5.3.14",
|
||||
"ts-lit-plugin": "2.0.2",
|
||||
"typescript": "5.9.2",
|
||||
"typescript-eslint": "8.43.0",
|
||||
"typescript-eslint": "8.42.0",
|
||||
"vite-tsconfig-paths": "5.1.4",
|
||||
"vitest": "3.2.4",
|
||||
"webpack-stats-plugin": "1.1.3",
|
||||
@@ -231,7 +232,7 @@
|
||||
"clean-css": "5.3.3",
|
||||
"@lit/reactive-element": "2.1.1",
|
||||
"@fullcalendar/daygrid": "6.1.19",
|
||||
"globals": "16.4.0",
|
||||
"globals": "16.3.0",
|
||||
"tslib": "2.8.1",
|
||||
"@material/mwc-list@^0.27.0": "patch:@material/mwc-list@npm%3A0.27.0#~/.yarn/patches/@material-mwc-list-npm-0.27.0-5344fc9de4.patch"
|
||||
},
|
||||
|
@@ -63,21 +63,3 @@ export const navigate = async (
|
||||
});
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Navigate back in history, with fallback to a default path if no history exists.
|
||||
* This prevents a user from getting stuck when they navigate directly to a page with no history.
|
||||
*/
|
||||
export const goBack = (fallbackPath?: string) => {
|
||||
const { history } = mainWindow;
|
||||
|
||||
// Check if we have history to go back to
|
||||
if (history.length > 1) {
|
||||
history.back();
|
||||
return;
|
||||
}
|
||||
|
||||
// No history available, navigate to fallback path
|
||||
const fallback = fallbackPath || "/";
|
||||
navigate(fallback, { replace: true });
|
||||
};
|
||||
|
@@ -12,8 +12,9 @@ class HaDataTableIcon extends LitElement {
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<ha-tooltip for="svg-icon">${this.tooltip}</ha-tooltip>
|
||||
<ha-svg-icon id="svg-icon" .path=${this.path}></ha-svg-icon>
|
||||
<ha-tooltip .content=${this.tooltip}>
|
||||
<ha-svg-icon .path=${this.path}></ha-svg-icon>
|
||||
</ha-tooltip>
|
||||
`;
|
||||
}
|
||||
|
||||
|
@@ -36,38 +36,39 @@ class StateInfo extends LitElement {
|
||||
</div>
|
||||
${this.inDialog
|
||||
? html`<div class="time-ago">
|
||||
<ha-tooltip for="relative-time">
|
||||
<div class="row">
|
||||
<span class="column-name">
|
||||
${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.last_changed"
|
||||
)}:
|
||||
</span>
|
||||
<ha-relative-time
|
||||
.hass=${this.hass}
|
||||
.datetime=${this.stateObj.last_changed}
|
||||
capitalize
|
||||
></ha-relative-time>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span>
|
||||
${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.last_updated"
|
||||
)}:
|
||||
</span>
|
||||
<ha-relative-time
|
||||
.hass=${this.hass}
|
||||
.datetime=${this.stateObj.last_updated}
|
||||
capitalize
|
||||
></ha-relative-time>
|
||||
<ha-tooltip>
|
||||
<ha-relative-time
|
||||
.hass=${this.hass}
|
||||
.datetime=${this.stateObj.last_changed}
|
||||
capitalize
|
||||
></ha-relative-time>
|
||||
<div slot="content">
|
||||
<div class="row">
|
||||
<span class="column-name">
|
||||
${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.last_changed"
|
||||
)}:
|
||||
</span>
|
||||
<ha-relative-time
|
||||
.hass=${this.hass}
|
||||
.datetime=${this.stateObj.last_changed}
|
||||
capitalize
|
||||
></ha-relative-time>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span>
|
||||
${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.last_updated"
|
||||
)}:
|
||||
</span>
|
||||
<ha-relative-time
|
||||
.hass=${this.hass}
|
||||
.datetime=${this.stateObj.last_updated}
|
||||
capitalize
|
||||
></ha-relative-time>
|
||||
</div>
|
||||
</div>
|
||||
</ha-tooltip>
|
||||
<ha-relative-time
|
||||
id="relative-time"
|
||||
.hass=${this.hass}
|
||||
.datetime=${this.stateObj.last_changed}
|
||||
capitalize
|
||||
></ha-relative-time>
|
||||
</div>`
|
||||
: html`<div class="extra-info"><slot></slot></div>`}
|
||||
</div>`;
|
||||
|
@@ -67,19 +67,20 @@ export class HaAnalytics extends LitElement {
|
||||
)}
|
||||
</span>
|
||||
<span>
|
||||
<ha-switch
|
||||
.id="switch-${preference}"
|
||||
@change=${this._handleRowClick}
|
||||
.checked=${this.analytics?.preferences[preference]}
|
||||
.preference=${preference}
|
||||
name=${preference}
|
||||
?disabled=${baseEnabled}
|
||||
>
|
||||
</ha-switch>
|
||||
<ha-tooltip .for="switch-${preference}" placement="right">
|
||||
${this.localize(
|
||||
<ha-tooltip
|
||||
content=${this.localize(
|
||||
`ui.panel.${this.translationKeyPanel}.analytics.need_base_enabled`
|
||||
)}
|
||||
placement="right"
|
||||
?disabled=${baseEnabled}
|
||||
>
|
||||
<ha-switch
|
||||
@change=${this._handleRowClick}
|
||||
.checked=${this.analytics?.preferences[preference]}
|
||||
.preference=${preference}
|
||||
name=${preference}
|
||||
>
|
||||
</ha-switch>
|
||||
</ha-tooltip>
|
||||
</span>
|
||||
</ha-settings-row>
|
||||
|
@@ -83,6 +83,15 @@ export class HaAutomationRow extends LitElement {
|
||||
!(ev.ctrlKey || ev.metaKey) &&
|
||||
!ev.shiftKey &&
|
||||
(ev.key === "ArrowUp" || ev.key === "ArrowDown")
|
||||
) &&
|
||||
!(
|
||||
(ev.ctrlKey || ev.metaKey) &&
|
||||
!ev.shiftKey &&
|
||||
!ev.altKey &&
|
||||
(ev.key === "c" ||
|
||||
ev.key === "x" ||
|
||||
ev.key === "Delete" ||
|
||||
ev.key === "Backspace")
|
||||
)
|
||||
) {
|
||||
return;
|
||||
@@ -103,6 +112,22 @@ export class HaAutomationRow extends LitElement {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ev.ctrlKey || ev.metaKey) {
|
||||
if (ev.key === "c") {
|
||||
fireEvent(this, "copy-row");
|
||||
return;
|
||||
}
|
||||
if (ev.key === "x") {
|
||||
fireEvent(this, "cut-row");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ev.key === "Delete" || ev.key === "Backspace") {
|
||||
fireEvent(this, "delete-row");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.click();
|
||||
}
|
||||
|
||||
|
@@ -1,62 +1,262 @@
|
||||
import { css, html, LitElement, type PropertyValues } from "lit";
|
||||
import "@home-assistant/webawesome/dist/components/drawer/drawer";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, query, state } from "lit/decorators";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import { fireEvent } from "../common/dom/fire_event";
|
||||
|
||||
export const BOTTOM_SHEET_ANIMATION_DURATION_MS = 300;
|
||||
const ANIMATION_DURATION_MS = 300;
|
||||
|
||||
/**
|
||||
* A bottom sheet component that slides up from the bottom of the screen.
|
||||
*
|
||||
* The bottom sheet provides a draggable interface that allows users to resize
|
||||
* the sheet by dragging the handle at the top. It supports both mouse and touch
|
||||
* interactions and automatically closes when dragged below a 20% of screen height.
|
||||
*
|
||||
* @fires bottom-sheet-closed - Fired when the bottom sheet is closed
|
||||
*
|
||||
* @cssprop --ha-bottom-sheet-border-width - Border width for the sheet
|
||||
* @cssprop --ha-bottom-sheet-border-style - Border style for the sheet
|
||||
* @cssprop --ha-bottom-sheet-border-color - Border color for the sheet
|
||||
*/
|
||||
@customElement("ha-bottom-sheet")
|
||||
export class HaBottomSheet extends LitElement {
|
||||
@property({ type: Boolean }) public open = false;
|
||||
@query("dialog") private _dialog!: HTMLDialogElement;
|
||||
|
||||
@state() private _drawerOpen = false;
|
||||
private _dragging = false;
|
||||
|
||||
private _handleAfterHide() {
|
||||
this.open = false;
|
||||
const ev = new Event("closed", {
|
||||
bubbles: true,
|
||||
composed: true,
|
||||
});
|
||||
this.dispatchEvent(ev);
|
||||
private _dragStartY = 0;
|
||||
|
||||
private _initialSize = 0;
|
||||
|
||||
@state() private _dialogMaxViewpointHeight = 70;
|
||||
|
||||
@state() private _dialogMinViewpointHeight = 55;
|
||||
|
||||
@state() private _dialogViewportHeight?: number;
|
||||
|
||||
render() {
|
||||
return html`<dialog
|
||||
open
|
||||
@transitionend=${this._handleTransitionEnd}
|
||||
style=${styleMap({
|
||||
height: this._dialogViewportHeight
|
||||
? `${this._dialogViewportHeight}vh`
|
||||
: "auto",
|
||||
maxHeight: `${this._dialogMaxViewpointHeight}vh`,
|
||||
minHeight: `${this._dialogMinViewpointHeight}vh`,
|
||||
})}
|
||||
>
|
||||
<div class="handle-wrapper">
|
||||
<div
|
||||
@mousedown=${this._handleMouseDown}
|
||||
@touchstart=${this._handleTouchStart}
|
||||
class="handle"
|
||||
></div>
|
||||
</div>
|
||||
<slot></slot>
|
||||
</dialog>`;
|
||||
}
|
||||
|
||||
protected updated(changedProperties: PropertyValues): void {
|
||||
super.updated(changedProperties);
|
||||
if (changedProperties.has("open")) {
|
||||
this._drawerOpen = this.open;
|
||||
protected firstUpdated(changedProperties) {
|
||||
super.firstUpdated(changedProperties);
|
||||
this._openSheet();
|
||||
}
|
||||
|
||||
private _openSheet() {
|
||||
requestAnimationFrame(() => {
|
||||
// trigger opening animation
|
||||
this._dialog.classList.add("show");
|
||||
});
|
||||
}
|
||||
|
||||
public closeSheet() {
|
||||
requestAnimationFrame(() => {
|
||||
this._dialog.classList.remove("show");
|
||||
});
|
||||
}
|
||||
|
||||
private _handleTransitionEnd() {
|
||||
if (this._dialog.classList.contains("show")) {
|
||||
// after show animation is done
|
||||
// - set the height to the natural height, to prevent content shift when switch content
|
||||
// - set max height to 90vh, so it opens at max 70vh but can be resized to 90vh
|
||||
this._dialogViewportHeight =
|
||||
(this._dialog.offsetHeight / window.innerHeight) * 100;
|
||||
this._dialogMaxViewpointHeight = 90;
|
||||
this._dialogMinViewpointHeight = 20;
|
||||
} else {
|
||||
// after close animation is done close dialog element and fire closed event
|
||||
this._dialog.close();
|
||||
fireEvent(this, "bottom-sheet-closed");
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<wa-drawer
|
||||
placement="bottom"
|
||||
.open=${this._drawerOpen}
|
||||
@wa-after-hide=${this._handleAfterHide}
|
||||
without-header
|
||||
>
|
||||
<slot></slot>
|
||||
</wa-drawer>
|
||||
`;
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
|
||||
// register event listeners for drag handling
|
||||
document.addEventListener("mousemove", this._handleMouseMove);
|
||||
document.addEventListener("mouseup", this._handleMouseUp);
|
||||
document.addEventListener("touchmove", this._handleTouchMove, {
|
||||
passive: false,
|
||||
});
|
||||
document.addEventListener("touchend", this._handleTouchEnd);
|
||||
document.addEventListener("touchcancel", this._handleTouchEnd);
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
|
||||
// unregister event listeners for drag handling
|
||||
document.removeEventListener("mousemove", this._handleMouseMove);
|
||||
document.removeEventListener("mouseup", this._handleMouseUp);
|
||||
document.removeEventListener("touchmove", this._handleTouchMove);
|
||||
document.removeEventListener("touchend", this._handleTouchEnd);
|
||||
document.removeEventListener("touchcancel", this._handleTouchEnd);
|
||||
}
|
||||
|
||||
private _handleMouseDown = (ev: MouseEvent) => {
|
||||
this._startDrag(ev.clientY);
|
||||
};
|
||||
|
||||
private _handleTouchStart = (ev: TouchEvent) => {
|
||||
// Prevent the browser from interpreting this as a scroll/PTR gesture.
|
||||
ev.preventDefault();
|
||||
this._startDrag(ev.touches[0].clientY);
|
||||
};
|
||||
|
||||
private _startDrag(clientY: number) {
|
||||
this._dragging = true;
|
||||
this._dragStartY = clientY;
|
||||
this._initialSize = (this._dialog.offsetHeight / window.innerHeight) * 100;
|
||||
document.body.style.setProperty("cursor", "grabbing");
|
||||
}
|
||||
|
||||
private _handleMouseMove = (ev: MouseEvent) => {
|
||||
if (!this._dragging) {
|
||||
return;
|
||||
}
|
||||
this._updateSize(ev.clientY);
|
||||
};
|
||||
|
||||
private _handleTouchMove = (ev: TouchEvent) => {
|
||||
if (!this._dragging) {
|
||||
return;
|
||||
}
|
||||
ev.preventDefault(); // Prevent scrolling
|
||||
this._updateSize(ev.touches[0].clientY);
|
||||
};
|
||||
|
||||
private _updateSize(clientY: number) {
|
||||
const deltaY = this._dragStartY - clientY;
|
||||
const viewportHeight = window.innerHeight;
|
||||
const deltaVh = (deltaY / viewportHeight) * 100;
|
||||
|
||||
// Calculate new size and clamp between 10vh and 90vh
|
||||
let newSize = this._initialSize + deltaVh;
|
||||
newSize = Math.max(10, Math.min(90, newSize));
|
||||
|
||||
// on drag down and below 20vh
|
||||
if (newSize < 20 && deltaY < 0) {
|
||||
this._endDrag();
|
||||
this.closeSheet();
|
||||
return;
|
||||
}
|
||||
|
||||
this._dialogViewportHeight = newSize;
|
||||
}
|
||||
|
||||
private _handleMouseUp = () => {
|
||||
this._endDrag();
|
||||
};
|
||||
|
||||
private _handleTouchEnd = () => {
|
||||
this._endDrag();
|
||||
};
|
||||
|
||||
private _endDrag() {
|
||||
if (!this._dragging) {
|
||||
return;
|
||||
}
|
||||
this._dragging = false;
|
||||
document.body.style.removeProperty("cursor");
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
wa-drawer {
|
||||
--wa-color-surface-raised: var(
|
||||
.handle-wrapper {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
padding-bottom: 2px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: grab;
|
||||
touch-action: none;
|
||||
}
|
||||
.handle-wrapper .handle {
|
||||
height: 20px;
|
||||
width: 200px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 7;
|
||||
padding-bottom: 76px;
|
||||
}
|
||||
.handle-wrapper .handle::after {
|
||||
content: "";
|
||||
border-radius: 8px;
|
||||
height: 4px;
|
||||
background: var(--divider-color, #e0e0e0);
|
||||
width: 80px;
|
||||
}
|
||||
.handle-wrapper .handle:active::after {
|
||||
cursor: grabbing;
|
||||
}
|
||||
dialog {
|
||||
height: auto;
|
||||
max-height: 70vh;
|
||||
min-height: 30vh;
|
||||
background-color: var(
|
||||
--ha-dialog-surface-background,
|
||||
var(--mdc-theme-surface, #fff)
|
||||
);
|
||||
--spacing: 0;
|
||||
--size: auto;
|
||||
--show-duration: ${BOTTOM_SHEET_ANIMATION_DURATION_MS}ms;
|
||||
--hide-duration: ${BOTTOM_SHEET_ANIMATION_DURATION_MS}ms;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
top: 0;
|
||||
inset-inline-start: 0;
|
||||
position: fixed;
|
||||
width: calc(100% - 4px);
|
||||
max-width: 100%;
|
||||
border: none;
|
||||
box-shadow: var(--wa-shadow-l);
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
top: auto;
|
||||
inset-inline-end: auto;
|
||||
bottom: 0;
|
||||
inset-inline-start: 0;
|
||||
box-shadow: 0px -8px 16px rgba(0, 0, 0, 0.2);
|
||||
border-top-left-radius: var(
|
||||
--ha-dialog-border-radius,
|
||||
var(--ha-border-radius-2xl)
|
||||
);
|
||||
border-top-right-radius: var(
|
||||
--ha-dialog-border-radius,
|
||||
var(--ha-border-radius-2xl)
|
||||
);
|
||||
transform: translateY(100%);
|
||||
transition: transform ${ANIMATION_DURATION_MS}ms ease;
|
||||
border-top-width: var(--ha-bottom-sheet-border-width);
|
||||
border-right-width: var(--ha-bottom-sheet-border-width);
|
||||
border-left-width: var(--ha-bottom-sheet-border-width);
|
||||
border-bottom-width: 0;
|
||||
border-style: var(--ha-bottom-sheet-border-style);
|
||||
border-color: var(--ha-bottom-sheet-border-color);
|
||||
}
|
||||
wa-drawer::part(dialog) {
|
||||
border-top-left-radius: var(--ha-border-radius-lg);
|
||||
border-top-right-radius: var(--ha-border-radius-lg);
|
||||
max-height: 90vh;
|
||||
}
|
||||
wa-drawer::part(body) {
|
||||
padding-bottom: var(--safe-area-inset-bottom);
|
||||
|
||||
dialog.show {
|
||||
transform: translateY(0);
|
||||
}
|
||||
`;
|
||||
}
|
||||
@@ -65,4 +265,8 @@ declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-bottom-sheet": HaBottomSheet;
|
||||
}
|
||||
|
||||
interface HASSDomEvents {
|
||||
"bottom-sheet-closed": undefined;
|
||||
}
|
||||
}
|
||||
|
@@ -57,8 +57,6 @@ export class HaButton extends Button {
|
||||
|
||||
font-size: var(--ha-font-size-m);
|
||||
line-height: 1;
|
||||
|
||||
transition: background-color 0.15s ease-in-out;
|
||||
}
|
||||
|
||||
:host([size="small"]) .button {
|
||||
|
@@ -49,6 +49,7 @@ export class HaExpansionPanel extends LitElement {
|
||||
tabindex=${this.noCollapse ? -1 : 0}
|
||||
aria-expanded=${this.expanded}
|
||||
aria-controls="sect1"
|
||||
part="summary"
|
||||
>
|
||||
${this.leftChevron ? chevronIcon : nothing}
|
||||
<slot name="leading-icon"></slot>
|
||||
|
@@ -25,9 +25,8 @@ export class HaHelpTooltip extends LitElement {
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<ha-svg-icon id="svg-icon" .path=${mdiHelpCircle}></ha-svg-icon>
|
||||
<ha-tooltip for="svg-icon" .placement=${this.position}>
|
||||
${this.label}
|
||||
<ha-tooltip .placement=${this.position} .content=${this.label}>
|
||||
<ha-svg-icon .path=${mdiHelpCircle}></ha-svg-icon>
|
||||
</ha-tooltip>
|
||||
`;
|
||||
}
|
||||
|
@@ -74,16 +74,16 @@ export class HaIconOverflowMenu extends LitElement {
|
||||
: item.divider
|
||||
? html`<div role="separator"></div>`
|
||||
: html`<ha-tooltip
|
||||
.disabled=${!item.tooltip}
|
||||
.for="icon-button-${item.label}"
|
||||
>${item.tooltip ?? ""} </ha-tooltip
|
||||
><ha-icon-button
|
||||
.id="icon-button-${item.label}"
|
||||
.disabled=${!item.tooltip}
|
||||
.content=${item.tooltip ?? ""}
|
||||
>
|
||||
<ha-icon-button
|
||||
@click=${item.action}
|
||||
.label=${item.label}
|
||||
.path=${item.path}
|
||||
?disabled=${item.disabled}
|
||||
></ha-icon-button> `
|
||||
></ha-icon-button>
|
||||
</ha-tooltip>`
|
||||
)}
|
||||
`}
|
||||
`;
|
||||
|
@@ -1,271 +0,0 @@
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, query, state } from "lit/decorators";
|
||||
import { styleMap } from "lit/directives/style-map";
|
||||
import { fireEvent } from "../common/dom/fire_event";
|
||||
import { BOTTOM_SHEET_ANIMATION_DURATION_MS } from "./ha-bottom-sheet";
|
||||
|
||||
/**
|
||||
* A bottom sheet component that slides up from the bottom of the screen.
|
||||
*
|
||||
* The bottom sheet provides a draggable interface that allows users to resize
|
||||
* the sheet by dragging the handle at the top. It supports both mouse and touch
|
||||
* interactions and automatically closes when dragged below a 20% of screen height.
|
||||
*
|
||||
* @fires bottom-sheet-closed - Fired when the bottom sheet is closed
|
||||
*
|
||||
* @cssprop --ha-bottom-sheet-border-width - Border width for the sheet
|
||||
* @cssprop --ha-bottom-sheet-border-style - Border style for the sheet
|
||||
* @cssprop --ha-bottom-sheet-border-color - Border color for the sheet
|
||||
*/
|
||||
@customElement("ha-resizable-bottom-sheet")
|
||||
export class HaResizableBottomSheet extends LitElement {
|
||||
@query("dialog") private _dialog!: HTMLDialogElement;
|
||||
|
||||
private _dragging = false;
|
||||
|
||||
private _dragStartY = 0;
|
||||
|
||||
private _initialSize = 0;
|
||||
|
||||
@state() private _dialogMaxViewpointHeight = 70;
|
||||
|
||||
@state() private _dialogMinViewpointHeight = 55;
|
||||
|
||||
@state() private _dialogViewportHeight?: number;
|
||||
|
||||
render() {
|
||||
return html`<dialog
|
||||
open
|
||||
@transitionend=${this._handleTransitionEnd}
|
||||
style=${styleMap({
|
||||
height: this._dialogViewportHeight
|
||||
? `${this._dialogViewportHeight}vh`
|
||||
: "auto",
|
||||
maxHeight: `${this._dialogMaxViewpointHeight}vh`,
|
||||
minHeight: `${this._dialogMinViewpointHeight}vh`,
|
||||
})}
|
||||
>
|
||||
<div class="handle-wrapper">
|
||||
<div
|
||||
@mousedown=${this._handleMouseDown}
|
||||
@touchstart=${this._handleTouchStart}
|
||||
class="handle"
|
||||
></div>
|
||||
</div>
|
||||
<slot></slot>
|
||||
</dialog>`;
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProperties) {
|
||||
super.firstUpdated(changedProperties);
|
||||
this._openSheet();
|
||||
}
|
||||
|
||||
private _openSheet() {
|
||||
requestAnimationFrame(() => {
|
||||
// trigger opening animation
|
||||
this._dialog.classList.add("show");
|
||||
});
|
||||
}
|
||||
|
||||
public closeSheet() {
|
||||
requestAnimationFrame(() => {
|
||||
this._dialog.classList.remove("show");
|
||||
});
|
||||
}
|
||||
|
||||
private _handleTransitionEnd() {
|
||||
if (this._dialog.classList.contains("show")) {
|
||||
// after show animation is done
|
||||
// - set the height to the natural height, to prevent content shift when switch content
|
||||
// - set max height to 90vh, so it opens at max 70vh but can be resized to 90vh
|
||||
this._dialogViewportHeight =
|
||||
(this._dialog.offsetHeight / window.innerHeight) * 100;
|
||||
this._dialogMaxViewpointHeight = 90;
|
||||
this._dialogMinViewpointHeight = 20;
|
||||
} else {
|
||||
// after close animation is done close dialog element and fire closed event
|
||||
this._dialog.close();
|
||||
fireEvent(this, "bottom-sheet-closed");
|
||||
}
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
|
||||
// register event listeners for drag handling
|
||||
document.addEventListener("mousemove", this._handleMouseMove);
|
||||
document.addEventListener("mouseup", this._handleMouseUp);
|
||||
document.addEventListener("touchmove", this._handleTouchMove, {
|
||||
passive: false,
|
||||
});
|
||||
document.addEventListener("touchend", this._handleTouchEnd);
|
||||
document.addEventListener("touchcancel", this._handleTouchEnd);
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
|
||||
// unregister event listeners for drag handling
|
||||
document.removeEventListener("mousemove", this._handleMouseMove);
|
||||
document.removeEventListener("mouseup", this._handleMouseUp);
|
||||
document.removeEventListener("touchmove", this._handleTouchMove);
|
||||
document.removeEventListener("touchend", this._handleTouchEnd);
|
||||
document.removeEventListener("touchcancel", this._handleTouchEnd);
|
||||
}
|
||||
|
||||
private _handleMouseDown = (ev: MouseEvent) => {
|
||||
this._startDrag(ev.clientY);
|
||||
};
|
||||
|
||||
private _handleTouchStart = (ev: TouchEvent) => {
|
||||
// Prevent the browser from interpreting this as a scroll/PTR gesture.
|
||||
ev.preventDefault();
|
||||
this._startDrag(ev.touches[0].clientY);
|
||||
};
|
||||
|
||||
private _startDrag(clientY: number) {
|
||||
this._dragging = true;
|
||||
this._dragStartY = clientY;
|
||||
this._initialSize = (this._dialog.offsetHeight / window.innerHeight) * 100;
|
||||
document.body.style.setProperty("cursor", "grabbing");
|
||||
}
|
||||
|
||||
private _handleMouseMove = (ev: MouseEvent) => {
|
||||
if (!this._dragging) {
|
||||
return;
|
||||
}
|
||||
this._updateSize(ev.clientY);
|
||||
};
|
||||
|
||||
private _handleTouchMove = (ev: TouchEvent) => {
|
||||
if (!this._dragging) {
|
||||
return;
|
||||
}
|
||||
ev.preventDefault(); // Prevent scrolling
|
||||
this._updateSize(ev.touches[0].clientY);
|
||||
};
|
||||
|
||||
private _updateSize(clientY: number) {
|
||||
const deltaY = this._dragStartY - clientY;
|
||||
const viewportHeight = window.innerHeight;
|
||||
const deltaVh = (deltaY / viewportHeight) * 100;
|
||||
|
||||
// Calculate new size and clamp between 10vh and 90vh
|
||||
let newSize = this._initialSize + deltaVh;
|
||||
newSize = Math.max(10, Math.min(90, newSize));
|
||||
|
||||
// on drag down and below 20vh
|
||||
if (newSize < 20 && deltaY < 0) {
|
||||
this._endDrag();
|
||||
this.closeSheet();
|
||||
return;
|
||||
}
|
||||
|
||||
this._dialogViewportHeight = newSize;
|
||||
}
|
||||
|
||||
private _handleMouseUp = () => {
|
||||
this._endDrag();
|
||||
};
|
||||
|
||||
private _handleTouchEnd = () => {
|
||||
this._endDrag();
|
||||
};
|
||||
|
||||
private _endDrag() {
|
||||
if (!this._dragging) {
|
||||
return;
|
||||
}
|
||||
this._dragging = false;
|
||||
document.body.style.removeProperty("cursor");
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
.handle-wrapper {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
padding-bottom: 2px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: grab;
|
||||
touch-action: none;
|
||||
}
|
||||
.handle-wrapper .handle {
|
||||
height: 20px;
|
||||
width: 200px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 7;
|
||||
padding-bottom: 76px;
|
||||
}
|
||||
.handle-wrapper .handle::after {
|
||||
content: "";
|
||||
border-radius: 8px;
|
||||
height: 4px;
|
||||
background: var(--divider-color, #e0e0e0);
|
||||
width: 80px;
|
||||
}
|
||||
.handle-wrapper .handle:active::after {
|
||||
cursor: grabbing;
|
||||
}
|
||||
dialog {
|
||||
height: auto;
|
||||
max-height: 70vh;
|
||||
min-height: 30vh;
|
||||
background-color: var(
|
||||
--ha-dialog-surface-background,
|
||||
var(--mdc-theme-surface, #fff)
|
||||
);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
top: 0;
|
||||
inset-inline-start: 0;
|
||||
position: fixed;
|
||||
width: calc(100% - 4px);
|
||||
max-width: 100%;
|
||||
border: none;
|
||||
box-shadow: var(--wa-shadow-l);
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
top: auto;
|
||||
inset-inline-end: auto;
|
||||
bottom: 0;
|
||||
inset-inline-start: 0;
|
||||
box-shadow: 0px -8px 16px rgba(0, 0, 0, 0.2);
|
||||
border-top-left-radius: var(
|
||||
--ha-dialog-border-radius,
|
||||
var(--ha-border-radius-2xl)
|
||||
);
|
||||
border-top-right-radius: var(
|
||||
--ha-dialog-border-radius,
|
||||
var(--ha-border-radius-2xl)
|
||||
);
|
||||
transform: translateY(100%);
|
||||
transition: transform ${BOTTOM_SHEET_ANIMATION_DURATION_MS}ms ease;
|
||||
border-top-width: var(--ha-bottom-sheet-border-width);
|
||||
border-right-width: var(--ha-bottom-sheet-border-width);
|
||||
border-left-width: var(--ha-bottom-sheet-border-width);
|
||||
border-bottom-width: 0;
|
||||
border-style: var(--ha-bottom-sheet-border-style);
|
||||
border-color: var(--ha-bottom-sheet-border-color);
|
||||
}
|
||||
|
||||
dialog.show {
|
||||
transform: translateY(0);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-resizable-bottom-sheet": HaResizableBottomSheet;
|
||||
}
|
||||
|
||||
interface HASSDomEvents {
|
||||
"bottom-sheet-closed": undefined;
|
||||
}
|
||||
}
|
@@ -1,39 +1,16 @@
|
||||
// @ts-ignore
|
||||
import chipStyles from "@material/chips/dist/mdc.chips.min.css";
|
||||
import "@material/mwc-menu/mwc-menu-surface";
|
||||
import {
|
||||
mdiClose,
|
||||
mdiDevices,
|
||||
mdiHome,
|
||||
mdiLabel,
|
||||
mdiPlus,
|
||||
mdiTextureBox,
|
||||
mdiUnfoldMoreVertical,
|
||||
} from "@mdi/js";
|
||||
import { mdiPlus } from "@mdi/js";
|
||||
import type { ComboBoxLightOpenedChangedEvent } from "@vaadin/combo-box/vaadin-combo-box-light";
|
||||
import type {
|
||||
HassEntity,
|
||||
HassServiceTarget,
|
||||
UnsubscribeFunc,
|
||||
} from "home-assistant-js-websocket";
|
||||
import type { HassServiceTarget } from "home-assistant-js-websocket";
|
||||
import type { CSSResultGroup } from "lit";
|
||||
import { LitElement, css, html, nothing, unsafeCSS } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { ensureArray } from "../common/array/ensure-array";
|
||||
import { computeCssColor } from "../common/color/compute-color";
|
||||
import { hex2rgb } from "../common/color/convert-color";
|
||||
import { fireEvent } from "../common/dom/fire_event";
|
||||
import { stopPropagation } from "../common/dom/stop_propagation";
|
||||
import { computeDeviceNameDisplay } from "../common/entity/compute_device_name";
|
||||
import { computeDomain } from "../common/entity/compute_domain";
|
||||
import { computeStateName } from "../common/entity/compute_state_name";
|
||||
import { isValidEntityId } from "../common/entity/valid_entity_id";
|
||||
import type { AreaRegistryEntry } from "../data/area_registry";
|
||||
import type { DeviceRegistryEntry } from "../data/device_registry";
|
||||
import type { EntityRegistryDisplayEntry } from "../data/entity_registry";
|
||||
import type { LabelRegistryEntry } from "../data/label_registry";
|
||||
import { subscribeLabelRegistry } from "../data/label_registry";
|
||||
import { SubscribeMixin } from "../mixins/subscribe-mixin";
|
||||
import type { HomeAssistant } from "../types";
|
||||
import "./device/ha-device-picker";
|
||||
@@ -41,12 +18,13 @@ import type { HaDevicePickerDeviceFilterFunc } from "./device/ha-device-picker";
|
||||
import "./entity/ha-entity-picker";
|
||||
import type { HaEntityPickerEntityFilterFunc } from "./entity/ha-entity-picker";
|
||||
import "./ha-area-floor-picker";
|
||||
import { floorDefaultIconPath } from "./ha-floor-icon";
|
||||
import "./ha-icon-button";
|
||||
import "./ha-input-helper-text";
|
||||
import "./ha-label-picker";
|
||||
import "./ha-svg-icon";
|
||||
import "./ha-tooltip";
|
||||
import "./target-picker/ha-target-picker-item-group";
|
||||
import type { TargetType } from "./target-picker/ha-target-picker-item-row";
|
||||
|
||||
@customElement("ha-target-picker")
|
||||
export class HaTargetPicker extends SubscribeMixin(LitElement) {
|
||||
@@ -58,6 +36,8 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
|
||||
|
||||
@property() public helper?: string;
|
||||
|
||||
@property({ type: Boolean }) public compact = false;
|
||||
|
||||
@property({ attribute: false, type: Array }) public createDomains?: string[];
|
||||
|
||||
/**
|
||||
@@ -96,18 +76,8 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
|
||||
|
||||
@query(".add-container", true) private _addContainer?: HTMLDivElement;
|
||||
|
||||
@state() private _labels?: LabelRegistryEntry[];
|
||||
|
||||
private _opened = false;
|
||||
|
||||
protected hassSubscribe(): (UnsubscribeFunc | Promise<UnsubscribeFunc>)[] {
|
||||
return [
|
||||
subscribeLabelRegistry(this.hass.connection, (labels) => {
|
||||
this._labels = labels;
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (this.addOnTop) {
|
||||
return html` ${this._renderChips()} ${this._renderItems()} `;
|
||||
@@ -116,87 +86,68 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
|
||||
}
|
||||
|
||||
private _renderItems() {
|
||||
if (
|
||||
!this.value?.floor_id &&
|
||||
!this.value?.area_id &&
|
||||
!this.value?.device_id &&
|
||||
!this.value?.entity_id &&
|
||||
!this.value?.label_id
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
return html`
|
||||
<div class="mdc-chip-set items">
|
||||
${this.value?.floor_id
|
||||
? ensureArray(this.value.floor_id).map((floor_id) => {
|
||||
const floor = this.hass.floors[floor_id];
|
||||
return this._renderChip(
|
||||
"floor_id",
|
||||
floor_id,
|
||||
floor?.name || floor_id,
|
||||
undefined,
|
||||
floor?.icon,
|
||||
floor ? floorDefaultIconPath(floor) : mdiHome
|
||||
);
|
||||
})
|
||||
: ""}
|
||||
${this.value?.area_id
|
||||
? ensureArray(this.value.area_id).map((area_id) => {
|
||||
const area = this.hass.areas![area_id];
|
||||
return this._renderChip(
|
||||
"area_id",
|
||||
area_id,
|
||||
area?.name || area_id,
|
||||
undefined,
|
||||
area?.icon,
|
||||
mdiTextureBox
|
||||
);
|
||||
})
|
||||
<div class="item-groups">
|
||||
${this.value?.floor_id || this.value?.area_id
|
||||
? html`
|
||||
<ha-target-picker-item-group
|
||||
@remove-target-item=${this._handleRemove}
|
||||
type="area"
|
||||
.hass=${this.hass}
|
||||
.items=${{
|
||||
floor: ensureArray(this.value?.floor_id),
|
||||
area: ensureArray(this.value?.area_id),
|
||||
}}
|
||||
.collapsed=${this.compact}
|
||||
>
|
||||
</ha-target-picker-item-group>
|
||||
`
|
||||
: nothing}
|
||||
${this.value?.device_id
|
||||
? ensureArray(this.value.device_id).map((device_id) => {
|
||||
const device = this.hass.devices![device_id];
|
||||
return this._renderChip(
|
||||
"device_id",
|
||||
device_id,
|
||||
device
|
||||
? computeDeviceNameDisplay(device, this.hass)
|
||||
: device_id,
|
||||
undefined,
|
||||
undefined,
|
||||
mdiDevices
|
||||
);
|
||||
})
|
||||
? html`
|
||||
<ha-target-picker-item-group
|
||||
@remove-target-item=${this._handleRemove}
|
||||
type="device"
|
||||
.hass=${this.hass}
|
||||
.items=${{ device: ensureArray(this.value?.device_id) }}
|
||||
.collapsed=${this.compact}
|
||||
>
|
||||
</ha-target-picker-item-group>
|
||||
`
|
||||
: nothing}
|
||||
${this.value?.entity_id
|
||||
? ensureArray(this.value.entity_id).map((entity_id) => {
|
||||
const entity = this.hass.states[entity_id];
|
||||
return this._renderChip(
|
||||
"entity_id",
|
||||
entity_id,
|
||||
entity ? computeStateName(entity) : entity_id,
|
||||
entity
|
||||
);
|
||||
})
|
||||
? html`
|
||||
<ha-target-picker-item-group
|
||||
@remove-target-item=${this._handleRemove}
|
||||
type="entity"
|
||||
.hass=${this.hass}
|
||||
.items=${{ entity: ensureArray(this.value?.entity_id) }}
|
||||
.collapsed=${this.compact}
|
||||
>
|
||||
</ha-target-picker-item-group>
|
||||
`
|
||||
: nothing}
|
||||
${this.value?.label_id
|
||||
? ensureArray(this.value.label_id).map((label_id) => {
|
||||
const label = this._labels?.find(
|
||||
(lbl) => lbl.label_id === label_id
|
||||
);
|
||||
let color = label?.color
|
||||
? computeCssColor(label.color)
|
||||
: undefined;
|
||||
if (color?.startsWith("var(")) {
|
||||
const computedStyles = getComputedStyle(this);
|
||||
color = computedStyles.getPropertyValue(
|
||||
color.substring(4, color.length - 1)
|
||||
);
|
||||
}
|
||||
if (color?.startsWith("#")) {
|
||||
color = hex2rgb(color).join(",");
|
||||
}
|
||||
return this._renderChip(
|
||||
"label_id",
|
||||
label_id,
|
||||
label ? label.name : label_id,
|
||||
undefined,
|
||||
label?.icon,
|
||||
mdiLabel,
|
||||
color
|
||||
);
|
||||
})
|
||||
? html`
|
||||
<ha-target-picker-item-group
|
||||
@remove-target-item=${this._handleRemove}
|
||||
type="label"
|
||||
.hass=${this.hass}
|
||||
.items=${{ label: ensureArray(this.value?.label_id) }}
|
||||
.collapsed=${this.compact}
|
||||
>
|
||||
</ha-target-picker-item-group>
|
||||
`
|
||||
: nothing}
|
||||
</div>
|
||||
`;
|
||||
@@ -299,85 +250,6 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
|
||||
this._addMode = ev.currentTarget.type;
|
||||
}
|
||||
|
||||
private _renderChip(
|
||||
type: "floor_id" | "area_id" | "device_id" | "entity_id" | "label_id",
|
||||
id: string,
|
||||
name: string,
|
||||
entityState?: HassEntity,
|
||||
icon?: string | null,
|
||||
fallbackIconPath?: string,
|
||||
color?: string
|
||||
) {
|
||||
return html`
|
||||
<div
|
||||
class="mdc-chip ${classMap({
|
||||
[type]: true,
|
||||
})}"
|
||||
style=${color
|
||||
? `--color: rgb(${color}); --background-color: rgba(${color}, .5)`
|
||||
: ""}
|
||||
>
|
||||
${icon
|
||||
? html`<ha-icon
|
||||
class="mdc-chip__icon mdc-chip__icon--leading"
|
||||
.icon=${icon}
|
||||
></ha-icon>`
|
||||
: fallbackIconPath
|
||||
? html`<ha-svg-icon
|
||||
class="mdc-chip__icon mdc-chip__icon--leading"
|
||||
.path=${fallbackIconPath}
|
||||
></ha-svg-icon>`
|
||||
: ""}
|
||||
${entityState
|
||||
? html`<ha-state-icon
|
||||
class="mdc-chip__icon mdc-chip__icon--leading"
|
||||
.hass=${this.hass}
|
||||
.stateObj=${entityState}
|
||||
></ha-state-icon>`
|
||||
: ""}
|
||||
<span role="gridcell">
|
||||
<span role="button" tabindex="0" class="mdc-chip__primary-action">
|
||||
<span class="mdc-chip__text">${name}</span>
|
||||
</span>
|
||||
</span>
|
||||
${type === "entity_id"
|
||||
? ""
|
||||
: html`<span role="gridcell">
|
||||
<ha-tooltip .for="expand-${id}"
|
||||
>${this.hass.localize(
|
||||
`ui.components.target-picker.expand_${type}`
|
||||
)}
|
||||
</ha-tooltip>
|
||||
<ha-icon-button
|
||||
class="expand-btn mdc-chip__icon mdc-chip__icon--trailing"
|
||||
.label=${this.hass.localize(
|
||||
"ui.components.target-picker.expand"
|
||||
)}
|
||||
.path=${mdiUnfoldMoreVertical}
|
||||
hide-title
|
||||
.id="expand-${id}"
|
||||
.type=${type}
|
||||
@click=${this._handleExpand}
|
||||
></ha-icon-button>
|
||||
</span>`}
|
||||
<span role="gridcell">
|
||||
<ha-tooltip .for="remove-${id}">
|
||||
${this.hass.localize(`ui.components.target-picker.remove_${type}`)}
|
||||
</ha-tooltip>
|
||||
<ha-icon-button
|
||||
class="mdc-chip__icon mdc-chip__icon--trailing"
|
||||
.label=${this.hass.localize("ui.components.target-picker.remove")}
|
||||
.path=${mdiClose}
|
||||
hide-title
|
||||
.id="remove-${id}"
|
||||
.type=${type}
|
||||
@click=${this._handleRemove}
|
||||
></ha-icon-button>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private _renderPicker() {
|
||||
if (!this._addMode) {
|
||||
return nothing;
|
||||
@@ -520,130 +392,31 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
|
||||
});
|
||||
}
|
||||
|
||||
private _handleExpand(ev) {
|
||||
const target = ev.currentTarget as any;
|
||||
const newAreas: string[] = [];
|
||||
const newDevices: string[] = [];
|
||||
const newEntities: string[] = [];
|
||||
|
||||
if (target.type === "floor_id") {
|
||||
Object.values(this.hass.areas).forEach((area) => {
|
||||
if (
|
||||
area.floor_id === target.id &&
|
||||
!this.value!.area_id?.includes(area.area_id) &&
|
||||
this._areaMeetsFilter(area)
|
||||
) {
|
||||
newAreas.push(area.area_id);
|
||||
}
|
||||
});
|
||||
} else if (target.type === "area_id") {
|
||||
Object.values(this.hass.devices).forEach((device) => {
|
||||
if (
|
||||
device.area_id === target.id &&
|
||||
!this.value!.device_id?.includes(device.id) &&
|
||||
this._deviceMeetsFilter(device)
|
||||
) {
|
||||
newDevices.push(device.id);
|
||||
}
|
||||
});
|
||||
Object.values(this.hass.entities).forEach((entity) => {
|
||||
if (
|
||||
entity.area_id === target.id &&
|
||||
!this.value!.entity_id?.includes(entity.entity_id) &&
|
||||
this._entityRegMeetsFilter(entity)
|
||||
) {
|
||||
newEntities.push(entity.entity_id);
|
||||
}
|
||||
});
|
||||
} else if (target.type === "device_id") {
|
||||
Object.values(this.hass.entities).forEach((entity) => {
|
||||
if (
|
||||
entity.device_id === target.id &&
|
||||
!this.value!.entity_id?.includes(entity.entity_id) &&
|
||||
this._entityRegMeetsFilter(entity)
|
||||
) {
|
||||
newEntities.push(entity.entity_id);
|
||||
}
|
||||
});
|
||||
} else if (target.type === "label_id") {
|
||||
Object.values(this.hass.areas).forEach((area) => {
|
||||
if (
|
||||
area.labels.includes(target.id) &&
|
||||
!this.value!.area_id?.includes(area.area_id) &&
|
||||
this._areaMeetsFilter(area)
|
||||
) {
|
||||
newAreas.push(area.area_id);
|
||||
}
|
||||
});
|
||||
Object.values(this.hass.devices).forEach((device) => {
|
||||
if (
|
||||
device.labels.includes(target.id) &&
|
||||
!this.value!.device_id?.includes(device.id) &&
|
||||
this._deviceMeetsFilter(device)
|
||||
) {
|
||||
newDevices.push(device.id);
|
||||
}
|
||||
});
|
||||
Object.values(this.hass.entities).forEach((entity) => {
|
||||
if (
|
||||
entity.labels.includes(target.id) &&
|
||||
!this.value!.entity_id?.includes(entity.entity_id) &&
|
||||
this._entityRegMeetsFilter(entity, true)
|
||||
) {
|
||||
newEntities.push(entity.entity_id);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
let value = this.value;
|
||||
if (newEntities.length) {
|
||||
value = this._addItems(value, "entity_id", newEntities);
|
||||
}
|
||||
if (newDevices.length) {
|
||||
value = this._addItems(value, "device_id", newDevices);
|
||||
}
|
||||
if (newAreas.length) {
|
||||
value = this._addItems(value, "area_id", newAreas);
|
||||
}
|
||||
value = this._removeItem(value, target.type, target.id);
|
||||
fireEvent(this, "value-changed", { value });
|
||||
}
|
||||
|
||||
private _handleRemove(ev) {
|
||||
const target = ev.currentTarget as any;
|
||||
const { type, id } = ev.detail;
|
||||
fireEvent(this, "value-changed", {
|
||||
value: this._removeItem(this.value, target.type, target.id),
|
||||
value: this._removeItem(this.value, type, id),
|
||||
});
|
||||
}
|
||||
|
||||
private _addItems(
|
||||
value: this["value"],
|
||||
type: string,
|
||||
ids: string[]
|
||||
): this["value"] {
|
||||
return {
|
||||
...value,
|
||||
[type]: value![type] ? ensureArray(value![type])!.concat(ids) : ids,
|
||||
};
|
||||
}
|
||||
|
||||
private _removeItem(
|
||||
value: this["value"],
|
||||
type: string,
|
||||
type: TargetType,
|
||||
id: string
|
||||
): this["value"] {
|
||||
const newVal = ensureArray(value![type])!.filter(
|
||||
const typeId = `${type}_id`;
|
||||
|
||||
const newVal = ensureArray(value![typeId])!.filter(
|
||||
(val) => String(val) !== id
|
||||
);
|
||||
if (newVal.length) {
|
||||
return {
|
||||
...value,
|
||||
[type]: newVal,
|
||||
[typeId]: newVal,
|
||||
};
|
||||
}
|
||||
const val = { ...value }!;
|
||||
delete val[type];
|
||||
delete val[typeId];
|
||||
if (Object.keys(val).length) {
|
||||
return val;
|
||||
}
|
||||
@@ -675,83 +448,6 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
|
||||
ev.preventDefault();
|
||||
}
|
||||
|
||||
private _areaMeetsFilter(area: AreaRegistryEntry): boolean {
|
||||
const areaDevices = Object.values(this.hass.devices).filter(
|
||||
(device) => device.area_id === area.area_id
|
||||
);
|
||||
|
||||
if (areaDevices.some((device) => this._deviceMeetsFilter(device))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const areaEntities = Object.values(this.hass.entities).filter(
|
||||
(entity) => entity.area_id === area.area_id
|
||||
);
|
||||
|
||||
if (areaEntities.some((entity) => this._entityRegMeetsFilter(entity))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private _deviceMeetsFilter(device: DeviceRegistryEntry): boolean {
|
||||
const devEntities = Object.values(this.hass.entities).filter(
|
||||
(entity) => entity.device_id === device.id
|
||||
);
|
||||
|
||||
if (!devEntities.some((entity) => this._entityRegMeetsFilter(entity))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.deviceFilter) {
|
||||
if (!this.deviceFilter(device)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private _entityRegMeetsFilter(
|
||||
entity: EntityRegistryDisplayEntry,
|
||||
includeSecondary = false
|
||||
): boolean {
|
||||
if (entity.hidden || (entity.entity_category && !includeSecondary)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
this.includeDomains &&
|
||||
!this.includeDomains.includes(computeDomain(entity.entity_id))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if (this.includeDeviceClasses) {
|
||||
const stateObj = this.hass.states[entity.entity_id];
|
||||
if (!stateObj) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
!stateObj.attributes.device_class ||
|
||||
!this.includeDeviceClasses!.includes(stateObj.attributes.device_class)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.entityFilter) {
|
||||
const stateObj = this.hass.states[entity.entity_id];
|
||||
if (!stateObj) {
|
||||
return false;
|
||||
}
|
||||
if (!this.entityFilter!(stateObj)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return css`
|
||||
${unsafeCSS(chipStyles)}
|
||||
@@ -810,41 +506,6 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
|
||||
margin-inline-end: 0;
|
||||
margin-inline-start: initial;
|
||||
}
|
||||
.mdc-chip.area_id:not(.add),
|
||||
.mdc-chip.floor_id:not(.add) {
|
||||
border: 1px solid #fed6a4;
|
||||
background: var(--card-background-color);
|
||||
}
|
||||
.mdc-chip.area_id:not(.add) .mdc-chip__icon--leading,
|
||||
.mdc-chip.area_id.add,
|
||||
.mdc-chip.floor_id:not(.add) .mdc-chip__icon--leading,
|
||||
.mdc-chip.floor_id.add {
|
||||
background: #fed6a4;
|
||||
}
|
||||
.mdc-chip.device_id:not(.add) {
|
||||
border: 1px solid #a8e1fb;
|
||||
background: var(--card-background-color);
|
||||
}
|
||||
.mdc-chip.device_id:not(.add) .mdc-chip__icon--leading,
|
||||
.mdc-chip.device_id.add {
|
||||
background: #a8e1fb;
|
||||
}
|
||||
.mdc-chip.entity_id:not(.add) {
|
||||
border: 1px solid #d2e7b9;
|
||||
background: var(--card-background-color);
|
||||
}
|
||||
.mdc-chip.entity_id:not(.add) .mdc-chip__icon--leading,
|
||||
.mdc-chip.entity_id.add {
|
||||
background: #d2e7b9;
|
||||
}
|
||||
.mdc-chip.label_id:not(.add) {
|
||||
border: 1px solid var(--color, #e0e0e0);
|
||||
background: var(--card-background-color);
|
||||
}
|
||||
.mdc-chip.label_id:not(.add) .mdc-chip__icon--leading,
|
||||
.mdc-chip.label_id.add {
|
||||
background: var(--background-color, #e0e0e0);
|
||||
}
|
||||
.mdc-chip:hover {
|
||||
z-index: 5;
|
||||
}
|
||||
@@ -864,6 +525,12 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
|
||||
ha-tooltip {
|
||||
--ha-tooltip-arrow-size: 0;
|
||||
}
|
||||
|
||||
.item-groups {
|
||||
overflow: hidden;
|
||||
border: 2px solid var(--divider-color);
|
||||
border-radius: var(--ha-border-radius-lg);
|
||||
}
|
||||
`;
|
||||
}
|
||||
}
|
||||
@@ -872,4 +539,12 @@ declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-target-picker": HaTargetPicker;
|
||||
}
|
||||
|
||||
interface HASSDomEvents {
|
||||
"remove-target-item": {
|
||||
type: string;
|
||||
id: string;
|
||||
};
|
||||
"remove-target-group": string;
|
||||
}
|
||||
}
|
||||
|
@@ -1,47 +1,50 @@
|
||||
import Tooltip from "@home-assistant/webawesome/dist/components/tooltip/tooltip";
|
||||
import SlTooltip from "@shoelace-style/shoelace/dist/components/tooltip/tooltip.component";
|
||||
import styles from "@shoelace-style/shoelace/dist/components/tooltip/tooltip.styles";
|
||||
import { css } from "lit";
|
||||
import type { CSSResultGroup } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { customElement } from "lit/decorators";
|
||||
import { setDefaultAnimation } from "@shoelace-style/shoelace/dist/utilities/animation-registry";
|
||||
|
||||
setDefaultAnimation("tooltip.show", {
|
||||
keyframes: [{ opacity: 0 }, { opacity: 1 }],
|
||||
options: { duration: 150, easing: "ease" },
|
||||
});
|
||||
|
||||
setDefaultAnimation("tooltip.hide", {
|
||||
keyframes: [{ opacity: 1 }, { opacity: 0 }],
|
||||
options: { duration: 400, easing: "ease" },
|
||||
});
|
||||
|
||||
@customElement("ha-tooltip")
|
||||
export class HaTooltip extends Tooltip {
|
||||
/** The amount of time to wait before showing the tooltip when the user mouses in. */
|
||||
@property({ attribute: "show-delay", type: Number }) showDelay = 150;
|
||||
|
||||
/** The amount of time to wait before hiding the tooltip when the user mouses out.. */
|
||||
@property({ attribute: "hide-delay", type: Number }) hideDelay = 400;
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
Tooltip.styles,
|
||||
css`
|
||||
:host {
|
||||
--wa-tooltip-background-color: var(--secondary-background-color);
|
||||
--wa-tooltip-color: var(--primary-text-color);
|
||||
--wa-tooltip-font-family: var(
|
||||
--ha-tooltip-font-family,
|
||||
var(--ha-font-family-body)
|
||||
);
|
||||
--wa-tooltip-font-size: var(
|
||||
--ha-tooltip-font-size,
|
||||
var(--ha-font-size-s)
|
||||
);
|
||||
--wa-tooltip-font-weight: var(
|
||||
--ha-tooltip-font-weight,
|
||||
var(--ha-font-weight-normal)
|
||||
);
|
||||
--wa-tooltip-line-height: var(
|
||||
--ha-tooltip-line-height,
|
||||
var(--ha-line-height-condensed)
|
||||
);
|
||||
--wa-tooltip-padding: 8px;
|
||||
--wa-tooltip-border-radius: var(--ha-tooltip-border-radius, 4px);
|
||||
--wa-tooltip-arrow-size: var(--ha-tooltip-arrow-size, 8px);
|
||||
--wa-z-index-tooltip: var(--ha-tooltip-z-index, 1000);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
export class HaTooltip extends SlTooltip {
|
||||
static override styles = [
|
||||
styles,
|
||||
css`
|
||||
:host {
|
||||
--sl-tooltip-background-color: var(--secondary-background-color);
|
||||
--sl-tooltip-color: var(--primary-text-color);
|
||||
--sl-tooltip-font-family: var(
|
||||
--ha-tooltip-font-family,
|
||||
var(--ha-font-family-body)
|
||||
);
|
||||
--sl-tooltip-font-size: var(
|
||||
--ha-tooltip-font-size,
|
||||
var(--ha-font-size-s)
|
||||
);
|
||||
--sl-tooltip-font-weight: var(
|
||||
--ha-tooltip-font-weight,
|
||||
var(--ha-font-weight-normal)
|
||||
);
|
||||
--sl-tooltip-line-height: var(
|
||||
--ha-tooltip-line-height,
|
||||
var(--ha-line-height-condensed)
|
||||
);
|
||||
--sl-tooltip-padding: 8px;
|
||||
--sl-tooltip-border-radius: var(--ha-tooltip-border-radius, 4px);
|
||||
--sl-tooltip-arrow-size: var(--ha-tooltip-arrow-size, 8px);
|
||||
--sl-z-index-tooltip: var(--ha-tooltip-z-index, 1000);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@@ -642,10 +642,9 @@ export class HaMediaPlayerBrowse extends LitElement {
|
||||
`
|
||||
: ""}
|
||||
</div>
|
||||
<ha-tooltip .for="grid-${child.title}" distance="-4">
|
||||
${child.title}
|
||||
<ha-tooltip distance="-4" .content=${child.title}>
|
||||
<div class="title">${child.title}</div>
|
||||
</ha-tooltip>
|
||||
<div .id="grid-${child.title}" class="title">${child.title}</div>
|
||||
</ha-card>
|
||||
</div>
|
||||
`;
|
||||
|
78
src/components/target-picker/ha-target-picker-item-group.ts
Normal file
78
src/components/target-picker/ha-target-picker-item-group.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
import "../ha-expansion-panel";
|
||||
import "../ha-md-list";
|
||||
import "./ha-target-picker-item-row";
|
||||
|
||||
@customElement("ha-target-picker-item-group")
|
||||
export class HaTargetPickerItemGroup extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property() public type!: "entity" | "device" | "area" | "label";
|
||||
|
||||
@property({ attribute: false }) public items!: Partial<
|
||||
Record<"entity" | "device" | "area" | "label" | "floor", string[]>
|
||||
>;
|
||||
|
||||
@property({ type: Boolean }) public collapsed = false;
|
||||
|
||||
protected render() {
|
||||
let count = 0;
|
||||
Object.values(this.items).forEach((items) => {
|
||||
if (items) {
|
||||
count += items.length;
|
||||
}
|
||||
});
|
||||
|
||||
return html`<ha-expansion-panel .expanded=${!this.collapsed} left-chevron>
|
||||
<div slot="header" class="heading">
|
||||
${this.hass.localize(
|
||||
`ui.components.target-picker.selected.${this.type}`,
|
||||
{
|
||||
count,
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
<ha-md-list>
|
||||
${Object.entries(this.items).map(([type, items]) =>
|
||||
items
|
||||
? items.map(
|
||||
(item) =>
|
||||
html`<ha-target-picker-item-row
|
||||
.hass=${this.hass}
|
||||
.type=${type as "entity" | "device" | "area" | "label"}
|
||||
.itemId=${item}
|
||||
></ha-target-picker-item-row>`
|
||||
)
|
||||
: nothing
|
||||
)}
|
||||
</ha-md-list>
|
||||
</ha-expansion-panel>`;
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
display: block;
|
||||
--expansion-panel-content-padding: 0;
|
||||
}
|
||||
ha-expansion-panel::part(summary) {
|
||||
background-color: var(--ha-color-fill-neutral-quiet-resting);
|
||||
padding: 4px 8px;
|
||||
font-weight: var(--ha-font-weight-bold);
|
||||
color: var(--secondary-text-color);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
min-height: unset;
|
||||
}
|
||||
ha-md-list {
|
||||
padding: 0;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-target-picker-item-group": HaTargetPickerItemGroup;
|
||||
}
|
||||
}
|
478
src/components/target-picker/ha-target-picker-item-row.ts
Normal file
478
src/components/target-picker/ha-target-picker-item-row.ts
Normal file
@@ -0,0 +1,478 @@
|
||||
import { consume } from "@lit/context";
|
||||
import {
|
||||
mdiChevronDown,
|
||||
mdiClose,
|
||||
mdiDevices,
|
||||
mdiHome,
|
||||
mdiLabel,
|
||||
mdiTextureBox,
|
||||
} from "@mdi/js";
|
||||
import { css, html, LitElement, nothing, type PropertyValues } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { computeAreaName } from "../../common/entity/compute_area_name";
|
||||
import {
|
||||
computeDeviceName,
|
||||
computeDeviceNameDisplay,
|
||||
} from "../../common/entity/compute_device_name";
|
||||
import { computeDomain } from "../../common/entity/compute_domain";
|
||||
import { computeEntityName } from "../../common/entity/compute_entity_name";
|
||||
import { getEntityContext } from "../../common/entity/context/get_entity_context";
|
||||
import { computeRTL } from "../../common/util/compute_rtl";
|
||||
import { getConfigEntry } from "../../data/config_entries";
|
||||
import { labelsContext } from "../../data/context";
|
||||
import { domainToName } from "../../data/integration";
|
||||
import type { LabelRegistryEntry } from "../../data/label_registry";
|
||||
import {
|
||||
extractFromTarget,
|
||||
type ExtractFromTargetResult,
|
||||
} from "../../data/target";
|
||||
import type { HomeAssistant } from "../../types";
|
||||
import { brandsUrl } from "../../util/brands-url";
|
||||
import { floorDefaultIconPath } from "../ha-floor-icon";
|
||||
import "../ha-icon-button";
|
||||
import "../ha-md-list";
|
||||
import type { HaMdList } from "../ha-md-list";
|
||||
import "../ha-md-list-item";
|
||||
import type { HaMdListItem } from "../ha-md-list-item";
|
||||
import "../ha-state-icon";
|
||||
import "../ha-svg-icon";
|
||||
|
||||
export type TargetType = "entity" | "device" | "area" | "label" | "floor";
|
||||
|
||||
@customElement("ha-target-picker-item-row")
|
||||
export class HaTargetPickerItemRow extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ reflect: true }) public type!: TargetType;
|
||||
|
||||
@property({ attribute: "item-id" }) public itemId!: string;
|
||||
|
||||
@property({ type: Boolean, attribute: "sub-entry", reflect: true })
|
||||
public subEntry = false;
|
||||
|
||||
@property({ attribute: false })
|
||||
public parentEntries?: ExtractFromTargetResult;
|
||||
|
||||
@state() private _expanded = false;
|
||||
|
||||
@state() private _iconImg?: string;
|
||||
|
||||
@state() private _domainName?: string;
|
||||
|
||||
@state() private _entries?: ExtractFromTargetResult;
|
||||
|
||||
@state()
|
||||
@consume({ context: labelsContext, subscribe: true })
|
||||
_labelRegistry!: LabelRegistryEntry[];
|
||||
|
||||
@query("ha-md-list-item") public item?: HaMdListItem;
|
||||
|
||||
@query("ha-md-list") public list?: HaMdList;
|
||||
|
||||
@query("ha-target-picker-item-row") public itemRow?: HaTargetPickerItemRow;
|
||||
|
||||
protected willUpdate(changedProps: PropertyValues) {
|
||||
if (!this.subEntry && changedProps.has("itemId")) {
|
||||
this._updateItemData();
|
||||
this._expanded = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected render() {
|
||||
const { name, context, iconPath, fallbackIconPath, stateObject } =
|
||||
this._itemData(this.type, this.itemId);
|
||||
|
||||
const showDevices = ["floor", "area", "label"].includes(this.type);
|
||||
const showEntities = this.type !== "entity";
|
||||
|
||||
const entries = this.parentEntries || this._entries;
|
||||
|
||||
// Don't show sub entries that have no entities
|
||||
if (
|
||||
this.subEntry &&
|
||||
this.type !== "entity" &&
|
||||
(!entries || entries.referenced_entities.length === 0)
|
||||
) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
return html`
|
||||
<ha-md-list-item
|
||||
.disabled=${entries?.referenced_entities.length === 0}
|
||||
.type=${this.type === "entity" ? "text" : "button"}
|
||||
@click=${this._toggleExpand}
|
||||
>
|
||||
${this.type !== "entity"
|
||||
? html`<ha-svg-icon
|
||||
class="expand-button ${entries?.referenced_entities.length &&
|
||||
this._expanded
|
||||
? "expanded"
|
||||
: ""}"
|
||||
.path=${mdiChevronDown}
|
||||
slot="start"
|
||||
></ha-svg-icon>`
|
||||
: nothing}
|
||||
${iconPath
|
||||
? html`<ha-icon slot="start" .icon=${iconPath}></ha-icon>`
|
||||
: this._iconImg
|
||||
? html`<img
|
||||
slot="start"
|
||||
alt=${this._domainName || ""}
|
||||
crossorigin="anonymous"
|
||||
referrerpolicy="no-referrer"
|
||||
src=${this._iconImg}
|
||||
/>`
|
||||
: fallbackIconPath
|
||||
? html`<ha-svg-icon
|
||||
slot="start"
|
||||
.path=${fallbackIconPath}
|
||||
></ha-svg-icon>`
|
||||
: stateObject
|
||||
? html`
|
||||
<ha-state-icon
|
||||
.hass=${this.hass}
|
||||
.stateObj=${stateObject}
|
||||
slot="start"
|
||||
>
|
||||
</ha-state-icon>
|
||||
`
|
||||
: nothing}
|
||||
<div slot="headline">${name}</div>
|
||||
${context && !this.subEntry
|
||||
? html`<span slot="supporting-text">${context}</span>`
|
||||
: nothing}
|
||||
${showEntities || showDevices || this._domainName
|
||||
? html`
|
||||
<div slot="end" class="summary">
|
||||
${showEntities
|
||||
? html`<span class="main"
|
||||
>${this.hass.localize(
|
||||
"ui.components.target-picker.entities_count",
|
||||
{
|
||||
count: entries?.referenced_entities.length,
|
||||
}
|
||||
)}</span
|
||||
>`
|
||||
: nothing}
|
||||
${showDevices
|
||||
? html`<span class="secondary"
|
||||
>${this.hass.localize(
|
||||
"ui.components.target-picker.devices_count",
|
||||
{
|
||||
count: entries?.referenced_devices.length,
|
||||
}
|
||||
)}</span
|
||||
>`
|
||||
: nothing}
|
||||
${this._domainName && !showDevices
|
||||
? html`<span class="secondary domain"
|
||||
>${this._domainName}</span
|
||||
>`
|
||||
: nothing}
|
||||
</div>
|
||||
`
|
||||
: nothing}
|
||||
${!this.subEntry
|
||||
? html`
|
||||
<ha-icon-button
|
||||
.path=${mdiClose}
|
||||
slot="end"
|
||||
@click=${this._removeItem}
|
||||
></ha-icon-button>
|
||||
`
|
||||
: nothing}
|
||||
</ha-md-list-item>
|
||||
${this._expanded && entries && entries.referenced_entities
|
||||
? this._renderEntries()
|
||||
: nothing}
|
||||
`;
|
||||
}
|
||||
|
||||
private _renderEntries() {
|
||||
const entries = this.parentEntries || this._entries;
|
||||
|
||||
let nextType =
|
||||
this.type === "floor"
|
||||
? "area"
|
||||
: this.type === "area"
|
||||
? "device"
|
||||
: "entity";
|
||||
|
||||
if (this.type === "label") {
|
||||
if (entries?.referenced_areas.length) {
|
||||
nextType = "area";
|
||||
} else if (entries?.referenced_devices.length) {
|
||||
nextType = "device";
|
||||
}
|
||||
}
|
||||
|
||||
const rows1 =
|
||||
(nextType === "area"
|
||||
? entries?.referenced_areas
|
||||
: nextType === "device"
|
||||
? entries?.referenced_devices
|
||||
: entries?.referenced_entities) || [];
|
||||
|
||||
const rows1Entries =
|
||||
nextType === "entity"
|
||||
? undefined
|
||||
: rows1.map((rowItem) => {
|
||||
const nextEntries = {
|
||||
missing_areas: [] as string[],
|
||||
missing_devices: [] as string[],
|
||||
missing_floors: [] as string[],
|
||||
missing_labels: [] as string[],
|
||||
referenced_areas: [] as string[],
|
||||
referenced_devices: [] as string[],
|
||||
referenced_entities: [] as string[],
|
||||
};
|
||||
|
||||
if (nextType === "area") {
|
||||
nextEntries.referenced_devices =
|
||||
entries?.referenced_devices.filter(
|
||||
(device_id) =>
|
||||
this.hass.devices?.[device_id]?.area_id === rowItem &&
|
||||
entries?.referenced_entities.some(
|
||||
(entity_id) =>
|
||||
this.hass.entities?.[entity_id]?.device_id === device_id
|
||||
)
|
||||
) || ([] as string[]);
|
||||
|
||||
nextEntries.referenced_entities =
|
||||
entries?.referenced_entities.filter((entity_id) => {
|
||||
const entity = this.hass.entities[entity_id];
|
||||
return (
|
||||
entity.area_id === rowItem ||
|
||||
!entity.device_id ||
|
||||
nextEntries.referenced_devices.includes(entity.device_id)
|
||||
);
|
||||
}) || ([] as string[]);
|
||||
|
||||
return nextEntries;
|
||||
}
|
||||
|
||||
nextEntries.referenced_entities =
|
||||
entries?.referenced_entities.filter(
|
||||
(entity_id) =>
|
||||
this.hass.entities?.[entity_id]?.device_id === rowItem
|
||||
) || ([] as string[]);
|
||||
|
||||
return nextEntries;
|
||||
});
|
||||
|
||||
const rows2 =
|
||||
nextType === "device" && entries
|
||||
? entries.referenced_entities.filter(
|
||||
(entity_id) => this.hass.entities[entity_id].area_id === this.itemId
|
||||
)
|
||||
: [];
|
||||
|
||||
return html`
|
||||
<ha-md-list class="entries">
|
||||
${rows1.map(
|
||||
(itemId, index) => html`
|
||||
<ha-target-picker-item-row
|
||||
sub-entry
|
||||
.hass=${this.hass}
|
||||
.type=${nextType}
|
||||
.itemId=${itemId}
|
||||
.parentEntries=${rows1Entries?.[index]}
|
||||
></ha-target-picker-item-row>
|
||||
`
|
||||
)}
|
||||
${rows2.map(
|
||||
(itemId) => html`
|
||||
<ha-target-picker-item-row
|
||||
sub-entry
|
||||
.hass=${this.hass}
|
||||
type="entity"
|
||||
.itemId=${itemId}
|
||||
></ha-target-picker-item-row>
|
||||
`
|
||||
)}
|
||||
</ha-md-list>
|
||||
`;
|
||||
}
|
||||
|
||||
private async _updateItemData() {
|
||||
try {
|
||||
this._entries = await extractFromTarget(this.hass, {
|
||||
[`${this.type}_id`]: [this.itemId],
|
||||
});
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error("Failed to extract target", e);
|
||||
}
|
||||
}
|
||||
|
||||
private _itemData = memoizeOne((type: TargetType, item: string) => {
|
||||
if (type === "floor") {
|
||||
const floor = this.hass.floors?.[item];
|
||||
return {
|
||||
name: floor?.name || item,
|
||||
iconPath: floor?.icon,
|
||||
fallbackIconPath: floor ? floorDefaultIconPath(floor) : mdiHome,
|
||||
};
|
||||
}
|
||||
if (type === "area") {
|
||||
const area = this.hass.areas?.[item];
|
||||
return {
|
||||
name: area?.name || item,
|
||||
context: area.floor_id && this.hass.floors?.[area.floor_id]?.name,
|
||||
iconPath: area?.icon,
|
||||
fallbackIconPath: mdiTextureBox,
|
||||
};
|
||||
}
|
||||
if (type === "device") {
|
||||
const device = this.hass.devices?.[item];
|
||||
|
||||
if (device.primary_config_entry) {
|
||||
this._getDeviceDomain(device.primary_config_entry);
|
||||
}
|
||||
|
||||
return {
|
||||
name: device ? computeDeviceNameDisplay(device, this.hass) : item,
|
||||
context: device?.area_id && this.hass.areas?.[device.area_id]?.name,
|
||||
fallbackIconPath: mdiDevices,
|
||||
};
|
||||
}
|
||||
if (type === "entity") {
|
||||
this._setDomainName(computeDomain(item));
|
||||
|
||||
const stateObject = this.hass.states[item];
|
||||
const entityName = computeEntityName(stateObject, this.hass);
|
||||
const { area, device } = getEntityContext(stateObject, this.hass);
|
||||
const deviceName = device ? computeDeviceName(device) : undefined;
|
||||
const areaName = area ? computeAreaName(area) : undefined;
|
||||
const context = [areaName, entityName ? deviceName : undefined]
|
||||
.filter(Boolean)
|
||||
.join(computeRTL(this.hass) ? " ◂ " : " ▸ ");
|
||||
return {
|
||||
name: entityName || deviceName || item,
|
||||
context,
|
||||
stateObject,
|
||||
};
|
||||
}
|
||||
|
||||
// type label
|
||||
const label = this._labelRegistry.find((lab) => lab.label_id === item);
|
||||
return {
|
||||
name: label?.name || item,
|
||||
iconPath: label?.icon,
|
||||
fallbackIconPath: mdiLabel,
|
||||
};
|
||||
});
|
||||
|
||||
private _setDomainName(domain: string) {
|
||||
this._domainName = domainToName(this.hass.localize, domain);
|
||||
}
|
||||
|
||||
private _removeItem(ev) {
|
||||
ev.stopPropagation();
|
||||
fireEvent(this, "remove-target-item", {
|
||||
type: this.type,
|
||||
id: this.itemId,
|
||||
});
|
||||
}
|
||||
|
||||
private async _getDeviceDomain(configEntryId: string) {
|
||||
try {
|
||||
const data = await getConfigEntry(this.hass, configEntryId);
|
||||
const domain = data.config_entry.domain;
|
||||
this._iconImg = brandsUrl({
|
||||
domain: domain,
|
||||
type: "icon",
|
||||
darkOptimized: this.hass.themes?.darkMode,
|
||||
});
|
||||
|
||||
this._setDomainName(domain);
|
||||
} catch {
|
||||
// failed to load config entry -> ignore
|
||||
}
|
||||
}
|
||||
|
||||
private _toggleExpand() {
|
||||
const entries = this.parentEntries || this._entries;
|
||||
|
||||
if (
|
||||
this.type === "entity" ||
|
||||
!entries ||
|
||||
entries.referenced_entities.length === 0
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this._expanded = !this._expanded;
|
||||
}
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
--md-list-item-top-space: 0;
|
||||
--md-list-item-bottom-space: 0;
|
||||
--md-list-item-leading-space: 8px;
|
||||
--md-list-item-trailing-space: 8px;
|
||||
--md-list-item-two-line-container-height: 56px;
|
||||
}
|
||||
|
||||
state-badge {
|
||||
color: var(--ha-color-on-neutral-quiet);
|
||||
}
|
||||
img {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
.expand-button {
|
||||
transition: transform 150ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
.expand-button.expanded {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
ha-icon-button {
|
||||
--mdc-icon-button-size: 32px;
|
||||
}
|
||||
.summary {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
line-height: var(--ha-line-height-condensed);
|
||||
}
|
||||
:host([sub-entry]) .summary {
|
||||
margin-right: 48px;
|
||||
}
|
||||
.summary .main {
|
||||
font-weight: var(--ha-font-weight-medium);
|
||||
}
|
||||
.summary .secondary {
|
||||
font-size: var(--ha-font-size-s);
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.summary .secondary.domain {
|
||||
font-family: var(--ha-font-family-code);
|
||||
}
|
||||
|
||||
@media all and (max-width: 870px) {
|
||||
:host([sub-entry]) .summary {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.entries {
|
||||
padding: 0;
|
||||
padding-left: 40px;
|
||||
overflow: hidden;
|
||||
transition: height 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
border-bottom: 1px solid var(--ha-color-border-neutral-quiet);
|
||||
}
|
||||
|
||||
:host([sub-entry]) .entries {
|
||||
border-bottom: none;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"ha-target-picker-item-row": HaTargetPickerItemRow;
|
||||
}
|
||||
}
|
21
src/data/target.ts
Normal file
21
src/data/target.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import type { HassServiceTarget } from "home-assistant-js-websocket";
|
||||
import type { HomeAssistant } from "../types";
|
||||
|
||||
export interface ExtractFromTargetResult {
|
||||
missing_areas: string[];
|
||||
missing_devices: string[];
|
||||
missing_floors: string[];
|
||||
missing_labels: string[];
|
||||
referenced_areas: string[];
|
||||
referenced_devices: string[];
|
||||
referenced_entities: string[];
|
||||
}
|
||||
|
||||
export const extractFromTarget = async (
|
||||
hass: HomeAssistant,
|
||||
target: HassServiceTarget
|
||||
) =>
|
||||
hass.callWS<ExtractFromTargetResult>({
|
||||
type: "extract_from_target",
|
||||
target,
|
||||
});
|
@@ -1,7 +1,6 @@
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import "../../components/ha-bottom-sheet";
|
||||
import { createCloseHeading } from "../../components/ha-dialog";
|
||||
import "../../components/ha-icon";
|
||||
import "../../components/ha-md-list";
|
||||
@@ -41,54 +40,6 @@ export class ListItemsDialog
|
||||
return nothing;
|
||||
}
|
||||
|
||||
const content = html`
|
||||
<div class="container">
|
||||
<ha-md-list>
|
||||
${this._params.items.map(
|
||||
(item) => html`
|
||||
<ha-md-list-item
|
||||
type="button"
|
||||
@click=${this._itemClicked}
|
||||
.item=${item}
|
||||
>
|
||||
${item.iconPath
|
||||
? html`
|
||||
<ha-svg-icon
|
||||
.path=${item.iconPath}
|
||||
slot="start"
|
||||
class="item-icon"
|
||||
></ha-svg-icon>
|
||||
`
|
||||
: item.icon
|
||||
? html`
|
||||
<ha-icon
|
||||
icon=${item.icon}
|
||||
slot="start"
|
||||
class="item-icon"
|
||||
></ha-icon>
|
||||
`
|
||||
: nothing}
|
||||
<span class="headline">${item.label}</span>
|
||||
${item.description
|
||||
? html`
|
||||
<span class="supporting-text">${item.description}</span>
|
||||
`
|
||||
: nothing}
|
||||
</ha-md-list-item>
|
||||
`
|
||||
)}
|
||||
</ha-md-list>
|
||||
</div>
|
||||
`;
|
||||
|
||||
if (this._params.mode === "bottom-sheet") {
|
||||
return html`
|
||||
<ha-bottom-sheet placement="bottom" open @closed=${this._dialogClosed}>
|
||||
${content}
|
||||
</ha-bottom-sheet>
|
||||
`;
|
||||
}
|
||||
|
||||
return html`
|
||||
<ha-dialog
|
||||
open
|
||||
@@ -96,7 +47,43 @@ export class ListItemsDialog
|
||||
@closed=${this._dialogClosed}
|
||||
hideActions
|
||||
>
|
||||
${content}
|
||||
<div class="container">
|
||||
<ha-md-list>
|
||||
${this._params.items.map(
|
||||
(item) => html`
|
||||
<ha-md-list-item
|
||||
type="button"
|
||||
@click=${this._itemClicked}
|
||||
.item=${item}
|
||||
>
|
||||
${item.iconPath
|
||||
? html`
|
||||
<ha-svg-icon
|
||||
.path=${item.iconPath}
|
||||
slot="start"
|
||||
class="item-icon"
|
||||
></ha-svg-icon>
|
||||
`
|
||||
: item.icon
|
||||
? html`
|
||||
<ha-icon
|
||||
icon=${item.icon}
|
||||
slot="start"
|
||||
class="item-icon"
|
||||
></ha-icon>
|
||||
`
|
||||
: nothing}
|
||||
<span class="headline">${item.label}</span>
|
||||
${item.description
|
||||
? html`
|
||||
<span class="supporting-text">${item.description}</span>
|
||||
`
|
||||
: nothing}
|
||||
</ha-md-list-item>
|
||||
`
|
||||
)}
|
||||
</ha-md-list>
|
||||
</div>
|
||||
</ha-dialog>
|
||||
`;
|
||||
}
|
||||
|
@@ -11,7 +11,6 @@ interface ListItem {
|
||||
export interface ListItemsDialogParams {
|
||||
title?: string;
|
||||
items: ListItem[];
|
||||
mode?: "dialog" | "bottom-sheet";
|
||||
}
|
||||
|
||||
export const showListItemsDialog = (
|
||||
|
@@ -166,36 +166,37 @@ class MoreInfoWeather extends LitElement {
|
||||
${this.hass.formatEntityState(this.stateObj)}
|
||||
</div>
|
||||
<div class="time-ago">
|
||||
<ha-relative-time
|
||||
id="relative-time"
|
||||
.hass=${this.hass}
|
||||
.datetime=${this.stateObj.last_changed}
|
||||
capitalize
|
||||
></ha-relative-time>
|
||||
<ha-tooltip for="relative-time">
|
||||
<div class="row">
|
||||
<span class="column-name">
|
||||
${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.last_changed"
|
||||
)}:
|
||||
</span>
|
||||
<ha-relative-time
|
||||
.hass=${this.hass}
|
||||
.datetime=${this.stateObj.last_changed}
|
||||
capitalize
|
||||
></ha-relative-time>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span>
|
||||
${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.last_updated"
|
||||
)}:
|
||||
</span>
|
||||
<ha-relative-time
|
||||
.hass=${this.hass}
|
||||
.datetime=${this.stateObj.last_updated}
|
||||
capitalize
|
||||
></ha-relative-time>
|
||||
<ha-tooltip>
|
||||
<ha-relative-time
|
||||
.hass=${this.hass}
|
||||
.datetime=${this.stateObj.last_changed}
|
||||
capitalize
|
||||
></ha-relative-time>
|
||||
<div slot="content">
|
||||
<div class="row">
|
||||
<span class="column-name">
|
||||
${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.last_changed"
|
||||
)}:
|
||||
</span>
|
||||
<ha-relative-time
|
||||
.hass=${this.hass}
|
||||
.datetime=${this.stateObj.last_changed}
|
||||
capitalize
|
||||
></ha-relative-time>
|
||||
</div>
|
||||
<div class="row">
|
||||
<span>
|
||||
${this.hass.localize(
|
||||
"ui.dialogs.more_info_control.last_updated"
|
||||
)}:
|
||||
</span>
|
||||
<ha-relative-time
|
||||
.hass=${this.hass}
|
||||
.datetime=${this.stateObj.last_updated}
|
||||
capitalize
|
||||
></ha-relative-time>
|
||||
</div>
|
||||
</div>
|
||||
</ha-tooltip>
|
||||
</div>
|
||||
|
@@ -28,14 +28,15 @@ export class HuiPersistentNotificationItem extends LitElement {
|
||||
|
||||
<div class="time">
|
||||
<span>
|
||||
<ha-relative-time
|
||||
id="relative-time"
|
||||
.hass=${this.hass}
|
||||
.datetime=${this.notification.created_at}
|
||||
capitalize
|
||||
></ha-relative-time>
|
||||
<ha-tooltip for="relative-time" placement="bottom">
|
||||
${this._computeTooltip(this.hass, this.notification)}
|
||||
<ha-tooltip
|
||||
.content=${this._computeTooltip(this.hass, this.notification)}
|
||||
placement="bottom"
|
||||
>
|
||||
<ha-relative-time
|
||||
.hass=${this.hass}
|
||||
.datetime=${this.notification.created_at}
|
||||
capitalize
|
||||
></ha-relative-time>
|
||||
</ha-tooltip>
|
||||
</span>
|
||||
</div>
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import type { CSSResultGroup, TemplateResult } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { goBack } from "../common/navigate";
|
||||
import "../components/ha-icon-button-arrow-prev";
|
||||
import "../components/ha-button";
|
||||
import "../components/ha-menu-button";
|
||||
@@ -51,7 +50,7 @@ class HassErrorScreen extends LitElement {
|
||||
}
|
||||
|
||||
private _handleBack(): void {
|
||||
goBack();
|
||||
history.back();
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
|
@@ -1,7 +1,6 @@
|
||||
import type { CSSResultGroup, TemplateResult } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import { goBack } from "../common/navigate";
|
||||
import "../components/ha-spinner";
|
||||
import "../components/ha-icon-button-arrow-prev";
|
||||
import "../components/ha-menu-button";
|
||||
@@ -50,7 +49,7 @@ class HassLoadingScreen extends LitElement {
|
||||
}
|
||||
|
||||
private _handleBack() {
|
||||
goBack();
|
||||
history.back();
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
|
@@ -2,7 +2,6 @@ import type { CSSResultGroup, TemplateResult } from "lit";
|
||||
import { css, html, LitElement } from "lit";
|
||||
import { customElement, eventOptions, property } from "lit/decorators";
|
||||
import { restoreScroll } from "../common/decorators/restore-scroll";
|
||||
import { goBack } from "../common/navigate";
|
||||
import "../components/ha-icon-button-arrow-prev";
|
||||
import "../components/ha-menu-button";
|
||||
import type { HomeAssistant } from "../types";
|
||||
@@ -79,7 +78,7 @@ class HassSubpage extends LitElement {
|
||||
this.backCallback();
|
||||
return;
|
||||
}
|
||||
goBack();
|
||||
history.back();
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
|
@@ -4,7 +4,6 @@ import { customElement, eventOptions, property, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { canShowPage } from "../common/config/can_show_page";
|
||||
import { goBack } from "../common/navigate";
|
||||
import { restoreScroll } from "../common/decorators/restore-scroll";
|
||||
import type { LocalizeFunc } from "../common/translations/localize";
|
||||
import "../components/ha-icon-button-arrow-prev";
|
||||
@@ -206,7 +205,7 @@ class HassTabsSubpage extends LitElement {
|
||||
this.backCallback();
|
||||
return;
|
||||
}
|
||||
goBack();
|
||||
history.back();
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
|
@@ -7,7 +7,6 @@ import { customElement, property, state } from "lit/decorators";
|
||||
import { ifDefined } from "lit/directives/if-defined";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||
import { goBack } from "../../../common/navigate";
|
||||
import { computeDeviceNameDisplay } from "../../../common/entity/compute_device_name";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||
@@ -51,7 +50,6 @@ import {
|
||||
loadAreaRegistryDetailDialog,
|
||||
showAreaRegistryDetailDialog,
|
||||
} from "./show-dialog-area-registry-detail";
|
||||
import { slugify } from "../../../common/string/slugify";
|
||||
|
||||
declare interface NameAndEntity<EntityType extends HassEntity> {
|
||||
name: string;
|
||||
@@ -550,14 +548,11 @@ class HaConfigAreaPage extends LitElement {
|
||||
|
||||
private _renderScene(name: string, entityState: SceneEntity) {
|
||||
return html`<ha-tooltip
|
||||
.for="scene-${slugify(entityState.entity_id)}"
|
||||
.distance=${-4}
|
||||
.disabled=${!!entityState.attributes.id}
|
||||
>
|
||||
${this.hass.localize("ui.panel.config.devices.cant_edit")}
|
||||
</ha-tooltip>
|
||||
.distance=${-4}
|
||||
.disabled=${!!entityState.attributes.id}
|
||||
.content=${this.hass.localize("ui.panel.config.devices.cant_edit")}
|
||||
>
|
||||
<a
|
||||
.id="scene-${slugify(entityState.entity_id)}"
|
||||
href=${ifDefined(
|
||||
entityState.attributes.id
|
||||
? `/config/scene/edit/${entityState.attributes.id}`
|
||||
@@ -568,12 +563,17 @@ class HaConfigAreaPage extends LitElement {
|
||||
<span>${name}</span>
|
||||
<ha-icon-next slot="meta"></ha-icon-next>
|
||||
</ha-list-item>
|
||||
</a> `;
|
||||
</a>
|
||||
</ha-tooltip>`;
|
||||
}
|
||||
|
||||
private _renderAutomation(name: string, entityState: AutomationEntity) {
|
||||
return html`<a
|
||||
id="automation-${slugify(entityState.entity_id)}"
|
||||
return html`<ha-tooltip
|
||||
.disabled=${!!entityState.attributes.id}
|
||||
.distance=${-4}
|
||||
.content=${this.hass.localize("ui.panel.config.devices.cant_edit")}
|
||||
>
|
||||
<a
|
||||
href=${ifDefined(
|
||||
entityState.attributes.id
|
||||
? `/config/automation/edit/${encodeURIComponent(entityState.attributes.id)}`
|
||||
@@ -585,12 +585,7 @@ class HaConfigAreaPage extends LitElement {
|
||||
<ha-icon-next slot="meta"></ha-icon-next>
|
||||
</ha-list-item>
|
||||
</a>
|
||||
<ha-tooltip
|
||||
for="automation-${slugify(entityState.entity_id)}"
|
||||
.disabled=${!!entityState.attributes.id}
|
||||
.distance=${-4}
|
||||
>${this.hass.localize("ui.panel.config.devices.cant_edit")}
|
||||
</ha-tooltip>`;
|
||||
</ha-tooltip>`;
|
||||
}
|
||||
|
||||
private _renderScript(name: string, entityState: ScriptEntity) {
|
||||
@@ -648,7 +643,7 @@ class HaConfigAreaPage extends LitElement {
|
||||
destructive: true,
|
||||
confirm: async () => {
|
||||
await deleteAreaRegistryEntry(this.hass!, area!.area_id);
|
||||
afterNextRender(() => goBack("/config"));
|
||||
afterNextRender(() => history.back());
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@@ -258,16 +258,14 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
|
||||
${type !== "condition" &&
|
||||
(this.action as NonConditionAction).continue_on_error === true
|
||||
? html`<ha-svg-icon
|
||||
id="svg-icon"
|
||||
slot="icons"
|
||||
.path=${mdiAlertCircleCheck}
|
||||
></ha-svg-icon>
|
||||
<ha-tooltip for="svg-icon">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.continue_on_error"
|
||||
)}
|
||||
</ha-tooltip>`
|
||||
? html`<ha-tooltip
|
||||
slot="icons"
|
||||
.content=${this.hass.localize(
|
||||
"ui.panel.config.automation.editor.actions.continue_on_error"
|
||||
)}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiAlertCircleCheck}></ha-svg-icon>
|
||||
</ha-tooltip>`
|
||||
: nothing}
|
||||
${!this.optionsInSidebar
|
||||
? html`<ha-md-button-menu
|
||||
@@ -462,6 +460,9 @@ export default class HaAutomationActionRow extends LitElement {
|
||||
.sortSelected=${this.sortSelected}
|
||||
@click=${this._toggleSidebar}
|
||||
@toggle-collapsed=${this._toggleCollapse}
|
||||
@copy-row=${this._copyAction}
|
||||
@cut-row=${this._cutAction}
|
||||
@delete-row=${this._onDelete}
|
||||
>${this._renderRow()}</ha-automation-row
|
||||
>`
|
||||
: html`
|
||||
|
@@ -369,6 +369,9 @@ export default class HaAutomationConditionRow extends LitElement {
|
||||
.sortSelected=${this.sortSelected}
|
||||
@click=${this._toggleSidebar}
|
||||
@toggle-collapsed=${this._toggleCollapse}
|
||||
@copy-row=${this._copyCondition}
|
||||
@cut-row=${this._cutCondition}
|
||||
@delete-row=${this._onDelete}
|
||||
>${this._renderRow()}</ha-automation-row
|
||||
>`
|
||||
: html`
|
||||
|
@@ -24,7 +24,7 @@ import { property, query, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { transform } from "../../../common/decorators/transform";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { goBack, navigate } from "../../../common/navigate";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import { promiseTimeout } from "../../../common/util/promise-timeout";
|
||||
import { afterNextRender } from "../../../common/util/render-status";
|
||||
import "../../../components/ha-button";
|
||||
@@ -702,7 +702,7 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
{ err_no: err.status_code }
|
||||
),
|
||||
});
|
||||
goBack("/config");
|
||||
history.back();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -853,7 +853,7 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
private _backTapped = async () => {
|
||||
const result = await this._confirmUnsavedChanged();
|
||||
if (result) {
|
||||
afterNextRender(() => goBack("/config"));
|
||||
afterNextRender(() => history.back());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -941,7 +941,7 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
||||
private async _delete() {
|
||||
if (this.automationId) {
|
||||
await deleteAutomation(this.hass, this.automationId);
|
||||
goBack("/config");
|
||||
history.back();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, query, state } from "lit/decorators";
|
||||
import "../../../components/ha-resizable-bottom-sheet";
|
||||
import type { HaResizableBottomSheet } from "../../../components/ha-resizable-bottom-sheet";
|
||||
import "../../../components/ha-bottom-sheet";
|
||||
import type { HaBottomSheet } from "../../../components/ha-bottom-sheet";
|
||||
import {
|
||||
isCondition,
|
||||
isScriptField,
|
||||
@@ -37,8 +37,7 @@ export default class HaAutomationSidebar extends LitElement {
|
||||
|
||||
@state() private _yamlMode = false;
|
||||
|
||||
@query("ha-resizable-bottom-sheet")
|
||||
private _bottomSheetElement?: HaResizableBottomSheet;
|
||||
@query("ha-bottom-sheet") private _bottomSheetElement?: HaBottomSheet;
|
||||
|
||||
private _renderContent() {
|
||||
// get config type
|
||||
@@ -148,9 +147,9 @@ export default class HaAutomationSidebar extends LitElement {
|
||||
|
||||
if (this.narrow) {
|
||||
return html`
|
||||
<ha-resizable-bottom-sheet @bottom-sheet-closed=${this._closeSidebar}>
|
||||
<ha-bottom-sheet @bottom-sheet-closed=${this._closeSidebar}>
|
||||
${this._renderContent()}
|
||||
</ha-resizable-bottom-sheet>
|
||||
</ha-bottom-sheet>
|
||||
`;
|
||||
}
|
||||
|
||||
|
@@ -254,7 +254,4 @@ export const sidebarEditorStyles = css`
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
ha-md-menu-item {
|
||||
--mdc-icon-size: 24px;
|
||||
}
|
||||
`;
|
||||
|
@@ -358,6 +358,9 @@ export default class HaAutomationTriggerRow extends LitElement {
|
||||
.highlight=${this.highlight}
|
||||
.sortSelected=${this.sortSelected}
|
||||
@click=${this._toggleSidebar}
|
||||
@copy-row=${this._copyTrigger}
|
||||
@cut-row=${this._cutTrigger}
|
||||
@delete-row=${this._onDelete}
|
||||
>${this._selected
|
||||
? "selected"
|
||||
: nothing}${this._renderRow()}</ha-automation-row
|
||||
|
@@ -5,7 +5,7 @@ import {
|
||||
mdiGroup,
|
||||
mdiPlus,
|
||||
} from "@mdi/js";
|
||||
import { goBack, navigate } from "../../../../../../common/navigate";
|
||||
import { navigate } from "../../../../../../common/navigate";
|
||||
import type { DeviceRegistryEntry } from "../../../../../../data/device_registry";
|
||||
import { fetchZHADevice } from "../../../../../../data/zha";
|
||||
import { showConfirmationDialog } from "../../../../../../dialogs/generic/show-dialog-box";
|
||||
@@ -102,7 +102,7 @@ export const getZHADeviceActions = async (
|
||||
ieee: zhaDevice.ieee,
|
||||
});
|
||||
|
||||
goBack("/config");
|
||||
history.back();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@@ -89,7 +89,6 @@ import {
|
||||
loadDeviceRegistryDetailDialog,
|
||||
showDeviceRegistryDetailDialog,
|
||||
} from "./device-registry-detail/show-dialog-device-registry-detail";
|
||||
import { slugify } from "../../../common/string/slugify";
|
||||
|
||||
export interface EntityRegistryStateEntry extends EntityRegistryEntry {
|
||||
stateName?: string | null;
|
||||
@@ -556,21 +555,16 @@ export class HaConfigDevicePage extends LitElement {
|
||||
</a>
|
||||
`
|
||||
: html`
|
||||
<ha-list-item
|
||||
.id="scene-${slugify(entityState.entity_id)}"
|
||||
hasMeta
|
||||
.scene=${entityState}
|
||||
>
|
||||
${computeStateName(entityState)}
|
||||
<ha-icon-next slot="meta"></ha-icon-next>
|
||||
</ha-list-item>
|
||||
<ha-tooltip
|
||||
.for="scene-${slugify(entityState.entity_id)}"
|
||||
placement="left"
|
||||
>
|
||||
${this.hass.localize(
|
||||
.content=${this.hass.localize(
|
||||
"ui.panel.config.devices.cant_edit"
|
||||
)}
|
||||
>
|
||||
<ha-list-item hasMeta .scene=${entityState}>
|
||||
${computeStateName(entityState)}
|
||||
<ha-icon-next slot="meta"></ha-icon-next>
|
||||
</ha-list-item>
|
||||
</ha-tooltip>
|
||||
`;
|
||||
})}
|
||||
|
@@ -671,14 +671,13 @@ export class HaConfigDeviceDashboard extends SubscribeMixin(LitElement) {
|
||||
tabindex="0"
|
||||
style="display:inline-block; position: relative;"
|
||||
>
|
||||
<ha-svg-icon
|
||||
.id="svg-icon-${device.id}"
|
||||
.path=${mdiCancel}
|
||||
></ha-svg-icon>
|
||||
<ha-tooltip .for="svg-icon-${device.id}" placement="left">
|
||||
${this.hass.localize(
|
||||
<ha-tooltip
|
||||
placement="left"
|
||||
.content=${this.hass.localize(
|
||||
"ui.panel.config.entities.picker.status.disabled"
|
||||
)}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiCancel}></ha-svg-icon>
|
||||
</ha-tooltip>
|
||||
</div>
|
||||
`
|
||||
|
@@ -114,7 +114,6 @@ import { isHelperDomain } from "../helpers/const";
|
||||
import "../integrations/ha-integration-overflow-menu";
|
||||
import { showAddIntegrationDialog } from "../integrations/show-add-integration-dialog";
|
||||
import { showLabelDetailDialog } from "../labels/show-dialog-label-detail";
|
||||
import { slugify } from "../../../common/string/slugify";
|
||||
|
||||
export interface StateEntity
|
||||
extends Omit<EntityRegistryEntry, "id" | "unique_id"> {
|
||||
@@ -393,27 +392,9 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
||||
tabindex="0"
|
||||
style="display:inline-block; position: relative;"
|
||||
>
|
||||
<ha-svg-icon
|
||||
.id="status-icon-${slugify(entry.entity_id)}"
|
||||
style=${styleMap({
|
||||
color: entry.unavailable ? "var(--error-color)" : "",
|
||||
})}
|
||||
.path=${entry.restored
|
||||
? mdiRestoreAlert
|
||||
: entry.unavailable
|
||||
? mdiAlertCircle
|
||||
: entry.disabled_by
|
||||
? mdiCancel
|
||||
: entry.hidden_by
|
||||
? mdiEyeOff
|
||||
: mdiPencilOff}
|
||||
></ha-svg-icon>
|
||||
|
||||
<ha-tooltip
|
||||
.for="status-icon-${slugify(entry.entity_id)}"
|
||||
placement="left"
|
||||
>
|
||||
${entry.restored
|
||||
.content=${entry.restored
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.entities.picker.status.not_provided"
|
||||
)
|
||||
@@ -432,6 +413,21 @@ export class HaConfigEntities extends SubscribeMixin(LitElement) {
|
||||
: this.hass.localize(
|
||||
"ui.panel.config.entities.picker.status.unmanageable"
|
||||
)}
|
||||
>
|
||||
<ha-svg-icon
|
||||
style=${styleMap({
|
||||
color: entry.unavailable ? "var(--error-color)" : "",
|
||||
})}
|
||||
.path=${entry.restored
|
||||
? mdiRestoreAlert
|
||||
: entry.unavailable
|
||||
? mdiAlertCircle
|
||||
: entry.disabled_by
|
||||
? mdiCancel
|
||||
: entry.hidden_by
|
||||
? mdiEyeOff
|
||||
: mdiPencilOff}
|
||||
></ha-svg-icon>
|
||||
</ha-tooltip>
|
||||
</div>
|
||||
`
|
||||
|
@@ -236,18 +236,17 @@ export class DialogHelperDetail extends LitElement {
|
||||
<span class="item-text"> ${label} </span>
|
||||
${isLoaded
|
||||
? html`<ha-icon-next slot="meta"></ha-icon-next>`
|
||||
: html` <ha-svg-icon
|
||||
slot="meta"
|
||||
.id="icon-${domain}"
|
||||
path=${mdiAlertOutline}
|
||||
@click=${stopPropagation}
|
||||
></ha-svg-icon>
|
||||
<ha-tooltip .for="icon-${domain}">
|
||||
${this.hass.localize(
|
||||
"ui.dialogs.helper_settings.platform_not_loaded",
|
||||
{ platform: domain }
|
||||
)}
|
||||
</ha-tooltip>`}
|
||||
: html`<ha-tooltip
|
||||
hoist
|
||||
slot="meta"
|
||||
.content=${this.hass.localize(
|
||||
"ui.dialogs.helper_settings.platform_not_loaded",
|
||||
{ platform: domain }
|
||||
)}
|
||||
@click=${stopPropagation}
|
||||
>
|
||||
<ha-svg-icon path=${mdiAlertOutline}></ha-svg-icon>
|
||||
</ha-tooltip>`}
|
||||
</ha-list-item>
|
||||
`;
|
||||
})}
|
||||
|
@@ -110,7 +110,6 @@ import { renderConfigEntryError } from "../integrations/ha-config-integration-pa
|
||||
import { showLabelDetailDialog } from "../labels/show-dialog-label-detail";
|
||||
import { isHelperDomain } from "./const";
|
||||
import { showHelperDetailDialog } from "./show-dialog-helper-detail";
|
||||
import { slugify } from "../../../common/string/slugify";
|
||||
|
||||
interface HelperItem {
|
||||
id: string;
|
||||
@@ -362,16 +361,13 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
||||
tabindex="0"
|
||||
style="display:inline-block; position: relative;"
|
||||
>
|
||||
<ha-svg-icon
|
||||
.id="icon-edit-${slugify(helper.entity_id)}"
|
||||
.path=${mdiPencilOff}
|
||||
></ha-svg-icon>
|
||||
<ha-tooltip
|
||||
.for="icon-edit-${slugify(helper.entity_id)}"
|
||||
placement="left"
|
||||
>${this.hass.localize(
|
||||
.content=${this.hass.localize(
|
||||
"ui.panel.config.entities.picker.status.unmanageable"
|
||||
)}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiPencilOff}></ha-svg-icon>
|
||||
</ha-tooltip>
|
||||
</div>
|
||||
`
|
||||
|
@@ -159,32 +159,29 @@ export class HaIntegrationCard extends LitElement {
|
||||
? "overwrites"
|
||||
: "custom"}"
|
||||
>
|
||||
<ha-svg-icon
|
||||
id="icon-custom"
|
||||
.path=${mdiPackageVariant}
|
||||
></ha-svg-icon>
|
||||
<ha-tooltip
|
||||
for="icon-custom"
|
||||
hoist
|
||||
.placement=${computeRTL(this.hass) ? "right" : "left"}
|
||||
>
|
||||
${this.hass.localize(
|
||||
.content=${this.hass.localize(
|
||||
this.manifest.overwrites_built_in
|
||||
? "ui.panel.config.integrations.config_entry.custom_overwrites_core"
|
||||
: "ui.panel.config.integrations.config_entry.custom_integration"
|
||||
)}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiPackageVariant}></ha-svg-icon>
|
||||
</ha-tooltip>
|
||||
</span>`
|
||||
: nothing}
|
||||
${this.manifest && this.manifest.iot_class?.startsWith("cloud_")
|
||||
? html`<div class="icon cloud">
|
||||
<ha-svg-icon id="icon-cloud" .path=${mdiWeb}></ha-svg-icon>
|
||||
<ha-tooltip
|
||||
for="icon-cloud"
|
||||
hoist
|
||||
.placement=${computeRTL(this.hass) ? "right" : "left"}
|
||||
>
|
||||
${this.hass.localize(
|
||||
.content=${this.hass.localize(
|
||||
"ui.panel.config.integrations.config_entry.depends_on_cloud"
|
||||
)}
|
||||
>
|
||||
<ha-svg-icon .path=${mdiWeb}></ha-svg-icon>
|
||||
</ha-tooltip>
|
||||
</div>`
|
||||
: nothing}
|
||||
@@ -192,18 +189,15 @@ export class HaIntegrationCard extends LitElement {
|
||||
!this.manifest?.config_flow &&
|
||||
!this.items.every((itm) => itm.source === "system")
|
||||
? html`<div class="icon yaml">
|
||||
<ha-svg-icon
|
||||
id="icon-yaml"
|
||||
.path=${mdiFileCodeOutline}
|
||||
></ha-svg-icon>
|
||||
<ha-tooltip
|
||||
for="icon-yaml"
|
||||
hoist
|
||||
.placement=${computeRTL(this.hass) ? "right" : "left"}
|
||||
>
|
||||
${this.hass.localize(
|
||||
.content=${this.hass.localize(
|
||||
"ui.panel.config.integrations.config_entry.no_config_flow"
|
||||
)}
|
||||
</ha-tooltip>
|
||||
>
|
||||
<ha-svg-icon .path=${mdiFileCodeOutline}></ha-svg-icon
|
||||
></ha-tooltip>
|
||||
</div>`
|
||||
: nothing}
|
||||
</div>
|
||||
|
@@ -74,45 +74,45 @@ export class HaIntegrationListItem extends ListItemBase {
|
||||
}
|
||||
return html`<span class="mdc-deprecated-list-item__meta material-icons">
|
||||
${this.integration.cloud
|
||||
? html` <ha-svg-icon id="icon-cloud" .path=${mdiWeb}></ha-svg-icon>
|
||||
<ha-tooltip for="icon-cloud" placement="left"
|
||||
>${this.hass.localize(
|
||||
"ui.panel.config.integrations.config_entry.depends_on_cloud"
|
||||
)}
|
||||
</ha-tooltip>`
|
||||
? html`<ha-tooltip
|
||||
placement="left"
|
||||
.content=${this.hass.localize(
|
||||
"ui.panel.config.integrations.config_entry.depends_on_cloud"
|
||||
)}
|
||||
><ha-svg-icon .path=${mdiWeb}></ha-svg-icon
|
||||
></ha-tooltip>`
|
||||
: nothing}
|
||||
${!this.integration.is_built_in
|
||||
? html`<span
|
||||
class=${this.integration.overwrites_built_in
|
||||
? "overwrites"
|
||||
: "custom"}
|
||||
>
|
||||
<ha-svg-icon
|
||||
id="icon-custom"
|
||||
.path=${mdiPackageVariant}
|
||||
></ha-svg-icon>
|
||||
<ha-tooltip for="icon-custom" placement="left"
|
||||
>${this.hass.localize(
|
||||
><ha-tooltip
|
||||
placement="left"
|
||||
.content=${this.hass.localize(
|
||||
this.integration.overwrites_built_in
|
||||
? "ui.panel.config.integrations.config_entry.custom_overwrites_core"
|
||||
: "ui.panel.config.integrations.config_entry.custom_integration"
|
||||
)}</ha-tooltip
|
||||
></span
|
||||
>`
|
||||
)}
|
||||
><ha-svg-icon
|
||||
.path=${mdiPackageVariant}
|
||||
></ha-svg-icon></ha-tooltip
|
||||
></span>`
|
||||
: nothing}
|
||||
${!this.integration.config_flow &&
|
||||
!this.integration.integrations &&
|
||||
!this.integration.iot_standards
|
||||
? html` <ha-svg-icon
|
||||
id="icon-yaml"
|
||||
? html`<ha-tooltip
|
||||
placement="left"
|
||||
.content=${this.hass.localize(
|
||||
"ui.panel.config.integrations.config_entry.yaml_only"
|
||||
)}
|
||||
>
|
||||
<ha-svg-icon
|
||||
.path=${mdiFileCodeOutline}
|
||||
class="open-in-new"
|
||||
></ha-svg-icon>
|
||||
<ha-tooltip for="icon-yaml" placement="left">
|
||||
${this.hass.localize(
|
||||
"ui.panel.config.integrations.config_entry.yaml_only"
|
||||
)}
|
||||
</ha-tooltip>`
|
||||
</ha-tooltip>`
|
||||
: html`<ha-icon-next></ha-icon-next>`}
|
||||
</span>`;
|
||||
}
|
||||
|
@@ -307,18 +307,14 @@ class DialogZHAReconfigureDevice extends LitElement {
|
||||
`
|
||||
: html`
|
||||
<span class="stage">
|
||||
<ha-svg-icon
|
||||
.id="svg-icon-${clusterStatus
|
||||
.cluster.name}"
|
||||
.path=${mdiCloseCircle}
|
||||
class="failed"
|
||||
></ha-svg-icon>
|
||||
<ha-tooltip
|
||||
.for="svg-icon-${clusterStatus
|
||||
.cluster.name}"
|
||||
placement="top"
|
||||
.content=${attribute.status}
|
||||
>
|
||||
${attribute.status}
|
||||
<ha-svg-icon
|
||||
.path=${mdiCloseCircle}
|
||||
class="failed"
|
||||
></ha-svg-icon>
|
||||
</ha-tooltip>
|
||||
</span>
|
||||
`}
|
||||
|
@@ -21,7 +21,6 @@ import "../../../../../components/ha-list-item";
|
||||
import "../../../../../components/ha-progress-ring";
|
||||
import "../../../../../components/ha-spinner";
|
||||
import "../../../../../components/ha-svg-icon";
|
||||
import { goBack } from "../../../../../common/navigate";
|
||||
import type { ConfigEntry } from "../../../../../data/config_entries";
|
||||
import {
|
||||
ERROR_STATES,
|
||||
@@ -619,7 +618,7 @@ class ZWaveJSConfigDashboard extends SubscribeMixin(LitElement) {
|
||||
}
|
||||
|
||||
private _handleBack(): void {
|
||||
goBack("/config");
|
||||
history.back();
|
||||
}
|
||||
|
||||
private _fetchData = async () => {
|
||||
|
@@ -367,7 +367,6 @@ class ZWaveJSNodeConfig extends LitElement {
|
||||
return html`
|
||||
${labelAndDescription}
|
||||
<ha-select
|
||||
fixedMenuPosition
|
||||
.disabled=${!item.metadata.writeable}
|
||||
.value=${item.value?.toString()}
|
||||
.key=${id}
|
||||
|
@@ -156,18 +156,16 @@ export class HaConfigLovelaceDashboards extends LitElement {
|
||||
${dashboard.title}
|
||||
${dashboard.default
|
||||
? html`
|
||||
<ha-svg-icon
|
||||
.id="default-icon-${dashboard.title}"
|
||||
style="padding-left: 10px; padding-inline-start: 10px; padding-inline-end: initial; direction: var(--direction);"
|
||||
.path=${mdiCheckCircleOutline}
|
||||
></ha-svg-icon>
|
||||
<ha-tooltip
|
||||
.for="default-icon-${dashboard.title}"
|
||||
placement="right"
|
||||
>
|
||||
${this.hass.localize(
|
||||
.content=${this.hass.localize(
|
||||
`ui.panel.config.lovelace.dashboards.default_dashboard`
|
||||
)}
|
||||
placement="right"
|
||||
>
|
||||
<ha-svg-icon
|
||||
style="padding-left: 10px; padding-inline-start: 10px; padding-inline-end: initial; direction: var(--direction);"
|
||||
.path=${mdiCheckCircleOutline}
|
||||
></ha-svg-icon>
|
||||
</ha-tooltip>
|
||||
`
|
||||
: nothing}
|
||||
|
@@ -106,7 +106,6 @@ import { showAssignCategoryDialog } from "../category/show-dialog-assign-categor
|
||||
import { showCategoryRegistryDetailDialog } from "../category/show-dialog-category-registry-detail";
|
||||
import { configSections } from "../ha-panel-config";
|
||||
import { showLabelDetailDialog } from "../labels/show-dialog-label-detail";
|
||||
import { slugify } from "../../../common/string/slugify";
|
||||
|
||||
type SceneItem = SceneEntity & {
|
||||
name: string;
|
||||
@@ -319,18 +318,16 @@ class HaSceneDashboard extends SubscribeMixin(LitElement) {
|
||||
template: (scene) =>
|
||||
!scene.attributes.id
|
||||
? html`
|
||||
<ha-svg-icon
|
||||
.id="svg-icon-${slugify(scene.entity_id)}"
|
||||
.path=${mdiPencilOff}
|
||||
style="color: var(--secondary-text-color)"
|
||||
></ha-svg-icon>
|
||||
<ha-tooltip
|
||||
.for="svg-icon-${slugify(scene.entity_id)}"
|
||||
placement="left"
|
||||
>
|
||||
${this.hass.localize(
|
||||
.content=${this.hass.localize(
|
||||
"ui.panel.config.scene.picker.only_editable"
|
||||
)}
|
||||
>
|
||||
<ha-svg-icon
|
||||
.path=${mdiPencilOff}
|
||||
style="color: var(--secondary-text-color)"
|
||||
></ha-svg-icon>
|
||||
</ha-tooltip>
|
||||
`
|
||||
: nothing,
|
||||
|
@@ -24,7 +24,7 @@ import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { computeDeviceNameDisplay } from "../../../common/entity/compute_device_name";
|
||||
import { computeDomain } from "../../../common/entity/compute_domain";
|
||||
import { computeStateName } from "../../../common/entity/compute_state_name";
|
||||
import { goBack, navigate } from "../../../common/navigate";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import { computeRTL } from "../../../common/util/compute_rtl";
|
||||
import { afterNextRender } from "../../../common/util/render-status";
|
||||
import "../../../components/device/ha-device-picker";
|
||||
@@ -806,7 +806,7 @@ export class HaSceneEditor extends PreventUnsavedMixin(
|
||||
{ err_no: err.status_code }
|
||||
),
|
||||
});
|
||||
goBack("/config");
|
||||
history.back();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -988,7 +988,7 @@ export class HaSceneEditor extends PreventUnsavedMixin(
|
||||
if (this._mode === "live") {
|
||||
applyScene(this.hass, this._storedStates);
|
||||
}
|
||||
afterNextRender(() => goBack("/config"));
|
||||
afterNextRender(() => history.back());
|
||||
}
|
||||
|
||||
private _deleteTapped(): void {
|
||||
@@ -1012,7 +1012,7 @@ export class HaSceneEditor extends PreventUnsavedMixin(
|
||||
if (this._mode === "live") {
|
||||
applyScene(this.hass, this._storedStates);
|
||||
}
|
||||
goBack("/config");
|
||||
history.back();
|
||||
}
|
||||
|
||||
private async _confirmUnsavedChanged(): Promise<boolean> {
|
||||
|
@@ -21,7 +21,7 @@ import { LitElement, css, html, nothing } from "lit";
|
||||
import { property, query, state } from "lit/decorators";
|
||||
import { classMap } from "lit/directives/class-map";
|
||||
import { fireEvent } from "../../../common/dom/fire_event";
|
||||
import { goBack, navigate } from "../../../common/navigate";
|
||||
import { navigate } from "../../../common/navigate";
|
||||
import { slugify } from "../../../common/string/slugify";
|
||||
import { promiseTimeout } from "../../../common/util/promise-timeout";
|
||||
import { afterNextRender } from "../../../common/util/render-status";
|
||||
@@ -596,7 +596,7 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
{ err_no: resp.status_code || resp.code }
|
||||
)
|
||||
);
|
||||
goBack("/config");
|
||||
history.back();
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -762,7 +762,7 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
private _backTapped = async () => {
|
||||
const result = await this._confirmUnsavedChanged();
|
||||
if (result) {
|
||||
afterNextRender(() => goBack("/config"));
|
||||
afterNextRender(() => history.back());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -852,7 +852,7 @@ export class HaScriptEditor extends SubscribeMixin(
|
||||
|
||||
private async _delete() {
|
||||
await deleteScript(this.hass, this.scriptId!);
|
||||
goBack("/config");
|
||||
history.back();
|
||||
}
|
||||
|
||||
private async _switchUiMode() {
|
||||
|
@@ -25,47 +25,48 @@ export class VoiceAssistantExposeAssistantIcon extends LitElement {
|
||||
if (!this.assistant || !voiceAssistants[this.assistant]) return nothing;
|
||||
|
||||
return html`
|
||||
<div class="container" id="container">
|
||||
<img
|
||||
class="logo"
|
||||
style=${styleMap({
|
||||
filter: this.manual ? "grayscale(100%)" : undefined,
|
||||
})}
|
||||
alt=${voiceAssistants[this.assistant].name}
|
||||
src=${brandsUrl({
|
||||
domain: voiceAssistants[this.assistant].domain,
|
||||
type: "icon",
|
||||
darkOptimized: this.hass.themes?.darkMode,
|
||||
})}
|
||||
crossorigin="anonymous"
|
||||
referrerpolicy="no-referrer"
|
||||
slot="prefix"
|
||||
/>
|
||||
${this.unsupported
|
||||
? html`
|
||||
<ha-svg-icon
|
||||
.path=${mdiAlertCircle}
|
||||
class="unsupported"
|
||||
></ha-svg-icon>
|
||||
`
|
||||
: nothing}
|
||||
</div>
|
||||
<ha-tooltip
|
||||
for="container"
|
||||
placement="left"
|
||||
.disabled=${!this.unsupported && !this.manual}
|
||||
placement="left"
|
||||
>
|
||||
${this.unsupported
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.voice_assistants.expose.not_supported"
|
||||
)
|
||||
: ""}
|
||||
${this.unsupported && this.manual ? html`<br />` : nothing}
|
||||
${this.manual
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.voice_assistants.expose.manually_configured"
|
||||
)
|
||||
: nothing}
|
||||
<div class="container">
|
||||
<img
|
||||
class="logo"
|
||||
style=${styleMap({
|
||||
filter: this.manual ? "grayscale(100%)" : undefined,
|
||||
})}
|
||||
alt=${voiceAssistants[this.assistant].name}
|
||||
src=${brandsUrl({
|
||||
domain: voiceAssistants[this.assistant].domain,
|
||||
type: "icon",
|
||||
darkOptimized: this.hass.themes?.darkMode,
|
||||
})}
|
||||
crossorigin="anonymous"
|
||||
referrerpolicy="no-referrer"
|
||||
slot="prefix"
|
||||
/>
|
||||
${this.unsupported
|
||||
? html`
|
||||
<ha-svg-icon
|
||||
.path=${mdiAlertCircle}
|
||||
class="unsupported"
|
||||
></ha-svg-icon>
|
||||
`
|
||||
: nothing}
|
||||
</div>
|
||||
<span slot="content">
|
||||
${this.unsupported
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.voice_assistants.expose.not_supported"
|
||||
)
|
||||
: ""}
|
||||
${this.unsupported && this.manual ? html`<br />` : nothing}
|
||||
${this.manual
|
||||
? this.hass.localize(
|
||||
"ui.panel.config.voice_assistants.expose.manually_configured"
|
||||
)
|
||||
: nothing}
|
||||
</span>
|
||||
</ha-tooltip>
|
||||
`;
|
||||
}
|
||||
|
@@ -607,32 +607,34 @@ export class VoiceAssistantsExpose extends LitElement {
|
||||
>
|
||||
`
|
||||
: html`
|
||||
<ha-icon-button
|
||||
id="expose-button"
|
||||
@click=${this._exposeSelected}
|
||||
.path=${mdiPlusBoxMultiple}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.voice_assistants.expose.expose"
|
||||
)}
|
||||
></ha-icon-button>
|
||||
<ha-tooltip for="expose-button" placement="left">
|
||||
${this.hass.localize(
|
||||
<ha-tooltip
|
||||
.content=${this.hass.localize(
|
||||
"ui.panel.config.voice_assistants.expose.expose"
|
||||
)}
|
||||
placement="left"
|
||||
>
|
||||
<ha-icon-button
|
||||
@click=${this._exposeSelected}
|
||||
.path=${mdiPlusBoxMultiple}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.voice_assistants.expose.expose"
|
||||
)}
|
||||
></ha-icon-button>
|
||||
</ha-tooltip>
|
||||
<ha-tooltip for="unexpose-button" placement="left">
|
||||
${this.hass.localize(
|
||||
<ha-tooltip
|
||||
content=${this.hass.localize(
|
||||
"ui.panel.config.voice_assistants.expose.unexpose"
|
||||
)}
|
||||
placement="left"
|
||||
>
|
||||
<ha-icon-button
|
||||
@click=${this._unexposeSelected}
|
||||
.path=${mdiCloseBoxMultiple}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.voice_assistants.expose.unexpose"
|
||||
)}
|
||||
></ha-icon-button>
|
||||
</ha-tooltip>
|
||||
<ha-icon-button
|
||||
id="unexpose-button"
|
||||
@click=${this._unexposeSelected}
|
||||
.path=${mdiCloseBoxMultiple}
|
||||
.label=${this.hass.localize(
|
||||
"ui.panel.config.voice_assistants.expose.unexpose"
|
||||
)}
|
||||
></ha-icon-button>
|
||||
`}
|
||||
</div>
|
||||
`
|
||||
|
@@ -46,7 +46,6 @@ import "../ha-config-section";
|
||||
import { configSections } from "../ha-panel-config";
|
||||
import { showHomeZoneDetailDialog } from "./show-dialog-home-zone-detail";
|
||||
import { showZoneDetailDialog } from "./show-dialog-zone-detail";
|
||||
import { slugify } from "../../../common/string/slugify";
|
||||
|
||||
@customElement("ha-config-zone")
|
||||
export class HaConfigZone extends SubscribeMixin(LitElement) {
|
||||
@@ -201,8 +200,17 @@ export class HaConfigZone extends SubscribeMixin(LitElement) {
|
||||
stateObject.entity_id === "zone.home" &&
|
||||
!this._canEditCore
|
||||
? nothing
|
||||
: html`<ha-icon-button
|
||||
.id="zone-${slugify(stateObject.entity_id)}"
|
||||
: html`<ha-tooltip
|
||||
slot="meta"
|
||||
placement="left"
|
||||
.content=${hass.localize(
|
||||
"ui.panel.config.zone.configured_in_yaml"
|
||||
)}
|
||||
.disabled=${stateObject.entity_id === "zone.home"}
|
||||
hoist
|
||||
>
|
||||
<ha-icon-button
|
||||
.id=${!this.narrow ? stateObject.entity_id : ""}
|
||||
.entityId=${stateObject.entity_id}
|
||||
.noEdit=${stateObject.entity_id !== "zone.home" ||
|
||||
!this._canEditCore}
|
||||
@@ -214,18 +222,8 @@ export class HaConfigZone extends SubscribeMixin(LitElement) {
|
||||
name: hass.config.location_name,
|
||||
})}
|
||||
@click=${this._editHomeZone}
|
||||
slot="meta"
|
||||
></ha-icon-button>
|
||||
<ha-tooltip
|
||||
.for="zone-${slugify(stateObject.entity_id)}"
|
||||
placement="left"
|
||||
.disabled=${stateObject.entity_id === "zone.home"}
|
||||
hoist
|
||||
>
|
||||
${hass.localize(
|
||||
"ui.panel.config.zone.configured_in_yaml"
|
||||
)}
|
||||
</ha-tooltip>`}
|
||||
</ha-tooltip>`}
|
||||
</ha-list-item>
|
||||
`
|
||||
)}
|
||||
|
@@ -13,7 +13,7 @@ import "../lovelace/components/hui-energy-period-selector";
|
||||
import type { Lovelace } from "../lovelace/types";
|
||||
import "../lovelace/views/hui-view";
|
||||
import "../lovelace/views/hui-view-container";
|
||||
import { goBack, navigate } from "../../common/navigate";
|
||||
import { navigate } from "../../common/navigate";
|
||||
import type {
|
||||
GridSourceTypeEnergyPreference,
|
||||
SolarSourceTypeEnergyPreference,
|
||||
@@ -70,7 +70,7 @@ class PanelEnergy extends LitElement {
|
||||
|
||||
private _back(ev) {
|
||||
ev.stopPropagation();
|
||||
goBack();
|
||||
history.back();
|
||||
}
|
||||
|
||||
protected render(): TemplateResult {
|
||||
|
@@ -17,7 +17,7 @@ import memoizeOne from "memoize-one";
|
||||
import { ensureArray } from "../../common/array/ensure-array";
|
||||
import { storage } from "../../common/decorators/storage";
|
||||
import { computeDomain } from "../../common/entity/compute_domain";
|
||||
import { goBack, navigate } from "../../common/navigate";
|
||||
import { navigate } from "../../common/navigate";
|
||||
import { constructUrlCurrentPath } from "../../common/url/construct-url";
|
||||
import {
|
||||
createSearchParam,
|
||||
@@ -114,7 +114,7 @@ class HaPanelHistory extends LitElement {
|
||||
}
|
||||
|
||||
private _goBack(): void {
|
||||
goBack();
|
||||
history.back();
|
||||
}
|
||||
|
||||
protected render() {
|
||||
@@ -182,6 +182,7 @@ class HaPanelHistory extends LitElement {
|
||||
.disabled=${this._isLoading}
|
||||
add-on-top
|
||||
@value-changed=${this._targetsChanged}
|
||||
compact
|
||||
></ha-target-picker>
|
||||
</div>
|
||||
${this._isLoading
|
||||
|
@@ -4,7 +4,7 @@ import { css, html, LitElement } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
import type { HassServiceTarget } from "home-assistant-js-websocket";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { goBack, navigate } from "../../common/navigate";
|
||||
import { navigate } from "../../common/navigate";
|
||||
import { constructUrlCurrentPath } from "../../common/url/construct-url";
|
||||
import {
|
||||
createSearchParam,
|
||||
@@ -60,7 +60,7 @@ export class HaPanelLogbook extends LitElement {
|
||||
}
|
||||
|
||||
private _goBack(): void {
|
||||
goBack();
|
||||
history.back();
|
||||
}
|
||||
|
||||
protected render() {
|
||||
@@ -104,6 +104,7 @@ export class HaPanelLogbook extends LitElement {
|
||||
.value=${this._targetPickerValue}
|
||||
add-on-top
|
||||
@value-changed=${this._targetsChanged}
|
||||
compact
|
||||
></ha-target-picker>
|
||||
</div>
|
||||
|
||||
|
@@ -133,12 +133,14 @@ class HuiEnergyCarbonGaugeCard
|
||||
"--gauge-color": this._computeSeverity(value),
|
||||
})}
|
||||
></ha-gauge>
|
||||
|
||||
<ha-svg-icon id="info" .path=${mdiInformation}></ha-svg-icon>
|
||||
<ha-tooltip for="info" placement="left">
|
||||
${this.hass.localize(
|
||||
<ha-tooltip
|
||||
.content=${this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.carbon_consumed_gauge.card_indicates_energy_used"
|
||||
)}
|
||||
placement="left"
|
||||
hoist
|
||||
>
|
||||
<ha-svg-icon .path=${mdiInformation}></ha-svg-icon>
|
||||
</ha-tooltip>
|
||||
<div class="name">
|
||||
${this.hass.localize(
|
||||
|
@@ -114,15 +114,17 @@ class HuiEnergyGridGaugeCard
|
||||
label="kWh"
|
||||
needle
|
||||
></ha-gauge>
|
||||
<ha-svg-icon id="info" .path=${mdiInformation}></ha-svg-icon>
|
||||
<ha-tooltip for="info" placement="left">
|
||||
${this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.grid_neutrality_gauge.energy_dependency"
|
||||
)}
|
||||
<br /><br />
|
||||
${this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.grid_neutrality_gauge.color_explain"
|
||||
)}
|
||||
<ha-tooltip placement="left" hoist>
|
||||
<span slot="content">
|
||||
${this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.grid_neutrality_gauge.energy_dependency"
|
||||
)}
|
||||
<br /><br />
|
||||
${this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.grid_neutrality_gauge.color_explain"
|
||||
)}
|
||||
</span>
|
||||
<ha-svg-icon .path=${mdiInformation}></ha-svg-icon>
|
||||
</ha-tooltip>
|
||||
<div class="name">
|
||||
${returnedToGrid! >= consumedFromGrid!
|
||||
|
@@ -110,11 +110,14 @@ class HuiEnergySelfSufficiencyGaugeCard
|
||||
"--gauge-color": this._computeSeverity(value),
|
||||
})}
|
||||
></ha-gauge>
|
||||
<ha-svg-icon id="info" .path=${mdiInformation}></ha-svg-icon>
|
||||
<ha-tooltip for="info" placement="left">
|
||||
${this.hass.localize(
|
||||
<ha-tooltip
|
||||
placement="left"
|
||||
.content=${this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.self_sufficiency_gauge.card_indicates_self_sufficiency_quota"
|
||||
)}
|
||||
hoist
|
||||
>
|
||||
<ha-svg-icon .path=${mdiInformation}></ha-svg-icon>
|
||||
</ha-tooltip>
|
||||
<div class="name">
|
||||
${this.hass.localize(
|
||||
|
@@ -102,15 +102,17 @@ class HuiEnergySolarGaugeCard
|
||||
"--gauge-color": this._computeSeverity(value),
|
||||
})}
|
||||
></ha-gauge>
|
||||
<ha-svg-icon id="info" .path=${mdiInformation}></ha-svg-icon>
|
||||
<ha-tooltip for="info" placement="left">
|
||||
${this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.solar_consumed_gauge.card_indicates_solar_energy_used"
|
||||
)}
|
||||
<br /><br />
|
||||
${this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.solar_consumed_gauge.card_indicates_solar_energy_used_charge_home_bat"
|
||||
)}
|
||||
<ha-tooltip placement="left" hoist>
|
||||
<span slot="content">
|
||||
${this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.solar_consumed_gauge.card_indicates_solar_energy_used"
|
||||
)}
|
||||
<br /><br />
|
||||
${this.hass.localize(
|
||||
"ui.panel.lovelace.cards.energy.solar_consumed_gauge.card_indicates_solar_energy_used_charge_home_bat"
|
||||
)}
|
||||
</span>
|
||||
<ha-svg-icon .path=${mdiInformation}></ha-svg-icon>
|
||||
</ha-tooltip>
|
||||
<div class="name">
|
||||
${this.hass.localize(
|
||||
@@ -174,6 +176,10 @@ class HuiEnergySolarGaugeCard
|
||||
top: 4px;
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
|
||||
ha-tooltip::part(base__popup) {
|
||||
margin-top: 4px;
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
|
@@ -1,152 +0,0 @@
|
||||
import { mdiDelete, mdiDrag, mdiPencil } from "@mdi/js";
|
||||
import type { CSSResultGroup, TemplateResult } from "lit";
|
||||
import { LitElement, css, html } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import "../../../components/ha-button-menu";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-list-item";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { deleteSection } from "../editor/config-util";
|
||||
import { findLovelaceContainer } from "../editor/lovelace-path";
|
||||
import { showEditSectionDialog } from "../editor/section-editor/show-edit-section-dialog";
|
||||
import type { Lovelace } from "../types";
|
||||
|
||||
@customElement("hui-section-edit-mode")
|
||||
export class HuiSectionEditMode extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public lovelace!: Lovelace;
|
||||
|
||||
@property({ attribute: false, type: Number }) public index!: number;
|
||||
|
||||
@property({ attribute: false, type: Number }) public viewIndex!: number;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<div class="section-header">
|
||||
<div class="section-actions">
|
||||
<ha-svg-icon
|
||||
aria-hidden="true"
|
||||
class="handle"
|
||||
.path=${mdiDrag}
|
||||
></ha-svg-icon>
|
||||
<ha-icon-button
|
||||
.label=${this.hass.localize("ui.common.edit")}
|
||||
@click=${this._editSection}
|
||||
.path=${mdiPencil}
|
||||
></ha-icon-button>
|
||||
<ha-icon-button
|
||||
.label=${this.hass.localize("ui.common.delete")}
|
||||
@click=${this._deleteSection}
|
||||
.path=${mdiDelete}
|
||||
></ha-icon-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section-wrapper">
|
||||
<slot></slot>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private async _editSection(ev) {
|
||||
ev.stopPropagation();
|
||||
showEditSectionDialog(this, {
|
||||
lovelace: this.lovelace!,
|
||||
lovelaceConfig: this.lovelace!.config,
|
||||
saveConfig: (newConfig) => {
|
||||
this.lovelace!.saveConfig(newConfig);
|
||||
},
|
||||
viewIndex: this.viewIndex,
|
||||
sectionIndex: this.index,
|
||||
});
|
||||
}
|
||||
|
||||
private async _deleteSection(ev) {
|
||||
ev.stopPropagation();
|
||||
const path = [this.viewIndex, this.index] as [number, number];
|
||||
|
||||
const section = findLovelaceContainer(this.lovelace!.config, path);
|
||||
|
||||
const cardCount = "cards" in section && section.cards?.length;
|
||||
|
||||
if (cardCount) {
|
||||
const confirm = await showConfirmationDialog(this, {
|
||||
title: this.hass.localize(
|
||||
"ui.panel.lovelace.editor.delete_section.title"
|
||||
),
|
||||
text: this.hass.localize(
|
||||
`ui.panel.lovelace.editor.delete_section.text`
|
||||
),
|
||||
confirmText: this.hass.localize("ui.common.delete"),
|
||||
destructive: true,
|
||||
});
|
||||
|
||||
if (!confirm) return;
|
||||
}
|
||||
|
||||
const newConfig = deleteSection(
|
||||
this.lovelace!.config,
|
||||
this.viewIndex,
|
||||
this.index
|
||||
);
|
||||
this.lovelace!.saveConfig(newConfig);
|
||||
}
|
||||
|
||||
static get styles(): CSSResultGroup {
|
||||
return [
|
||||
haStyle,
|
||||
css`
|
||||
.section-header {
|
||||
position: relative;
|
||||
height: 34px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.section-actions {
|
||||
position: absolute;
|
||||
height: 36px;
|
||||
bottom: -2px;
|
||||
right: 0;
|
||||
inset-inline-end: 0;
|
||||
inset-inline-start: initial;
|
||||
opacity: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
border-radius: var(--ha-card-border-radius, 12px);
|
||||
border-bottom-left-radius: 0px;
|
||||
border-bottom-right-radius: 0px;
|
||||
background: var(--secondary-background-color);
|
||||
--mdc-icon-button-size: 36px;
|
||||
--mdc-icon-size: 20px;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
|
||||
.handle {
|
||||
cursor: grab;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.section-wrapper {
|
||||
padding: 8px;
|
||||
border-radius: var(--ha-card-border-radius, 12px);
|
||||
border-start-end-radius: 0;
|
||||
border: 2px dashed var(--divider-color);
|
||||
min-height: var(--row-height);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"hui-section-edit-mode": HuiSectionEditMode;
|
||||
}
|
||||
}
|
@@ -26,7 +26,7 @@ import memoizeOne from "memoize-one";
|
||||
import { isComponentLoaded } from "../../common/config/is_component_loaded";
|
||||
import { fireEvent } from "../../common/dom/fire_event";
|
||||
import { shouldHandleRequestSelectedEvent } from "../../common/mwc/handle-request-selected-event";
|
||||
import { goBack, navigate } from "../../common/navigate";
|
||||
import { navigate } from "../../common/navigate";
|
||||
import type { LocalizeKeys } from "../../common/translations/localize";
|
||||
import { constructUrlCurrentPath } from "../../common/url/construct-url";
|
||||
import {
|
||||
@@ -47,7 +47,6 @@ import "../../components/ha-menu-button";
|
||||
import "../../components/ha-svg-icon";
|
||||
import "../../components/ha-tab-group";
|
||||
import "../../components/ha-tab-group-tab";
|
||||
import "../../components/ha-tooltip";
|
||||
import { createAreaRegistryEntry } from "../../data/area_registry";
|
||||
import type { LovelacePanelConfig } from "../../data/lovelace";
|
||||
import type { LovelaceConfig } from "../../data/lovelace/config/types";
|
||||
@@ -230,10 +229,10 @@ class HUIRoot extends LitElement {
|
||||
},
|
||||
{
|
||||
icon: mdiSofa,
|
||||
key: "ui.panel.lovelace.menu.create_area",
|
||||
key: "ui.panel.lovelace.menu.add_area",
|
||||
visible: true,
|
||||
action: this._createArea,
|
||||
overflowAction: this._handleCreateArea,
|
||||
action: this._addArea,
|
||||
overflowAction: this._handleAddArea,
|
||||
},
|
||||
{
|
||||
icon: mdiAccount,
|
||||
@@ -308,7 +307,7 @@ class HUIRoot extends LitElement {
|
||||
(i) => i.visible && (!i.overflow || overflowCanPromote)
|
||||
);
|
||||
|
||||
buttonItems.forEach((item, index) => {
|
||||
buttonItems.forEach((item) => {
|
||||
const label = [this.hass!.localize(item.key), item.suffix].join(" ");
|
||||
const button = item.subItems
|
||||
? html`
|
||||
@@ -342,14 +341,11 @@ class HUIRoot extends LitElement {
|
||||
</ha-button-menu>
|
||||
`
|
||||
: html`
|
||||
<ha-icon-button
|
||||
slot="actionItems"
|
||||
.id="button-${index}"
|
||||
.path=${item.icon}
|
||||
@click=${item.buttonAction}
|
||||
></ha-icon-button>
|
||||
<ha-tooltip placement="bottom" .for="button-${index}">
|
||||
${label}
|
||||
<ha-tooltip slot="actionItems" placement="bottom" .content=${label}>
|
||||
<ha-icon-button
|
||||
.path=${item.icon}
|
||||
@click=${item.buttonAction}
|
||||
></ha-icon-button>
|
||||
</ha-tooltip>
|
||||
`;
|
||||
result.push(button);
|
||||
@@ -366,7 +362,6 @@ class HUIRoot extends LitElement {
|
||||
}
|
||||
showListItemsDialog(this, {
|
||||
title: title,
|
||||
mode: this.narrow ? "bottom-sheet" : "dialog",
|
||||
items: i.subItems!.map((si) => ({
|
||||
iconPath: si.icon,
|
||||
label: this.hass!.localize(si.key),
|
||||
@@ -804,7 +799,7 @@ class HUIRoot extends LitElement {
|
||||
if (curViewConfig?.back_path != null) {
|
||||
navigate(curViewConfig.back_path, { replace: true });
|
||||
} else if (history.length > 1) {
|
||||
goBack();
|
||||
history.back();
|
||||
} else if (!views[0].subview) {
|
||||
navigate(this.route!.prefix, { replace: true });
|
||||
} else {
|
||||
@@ -838,14 +833,14 @@ class HUIRoot extends LitElement {
|
||||
showNewAutomationDialog(this, { mode: "automation" });
|
||||
};
|
||||
|
||||
private _handleCreateArea(ev: CustomEvent<RequestSelectedDetail>): void {
|
||||
private _handleAddArea(ev: CustomEvent<RequestSelectedDetail>): void {
|
||||
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||
return;
|
||||
}
|
||||
this._createArea();
|
||||
this._addArea();
|
||||
}
|
||||
|
||||
private _createArea = async () => {
|
||||
private _addArea = async () => {
|
||||
await this.hass.loadFragmentTranslation("config");
|
||||
showAreaRegistryDetailDialog(this, {
|
||||
createEntry: async (values) => {
|
||||
@@ -855,15 +850,13 @@ class HUIRoot extends LitElement {
|
||||
}
|
||||
showToast(this, {
|
||||
message: this.hass.localize(
|
||||
"ui.panel.lovelace.menu.create_area_success"
|
||||
"ui.panel.lovelace.menu.add_area_success"
|
||||
),
|
||||
action: {
|
||||
action: () => {
|
||||
navigate(`/config/areas/area/${area.area_id}`);
|
||||
},
|
||||
text: this.hass.localize(
|
||||
"ui.panel.lovelace.menu.create_area_action"
|
||||
),
|
||||
text: this.hass.localize("ui.panel.lovelace.menu.add_area_action"),
|
||||
},
|
||||
});
|
||||
},
|
||||
|
@@ -99,7 +99,12 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
|
||||
@item-removed=${this._cardRemoved}
|
||||
invert-swap
|
||||
>
|
||||
<div class="container">
|
||||
<div
|
||||
class="container ${classMap({
|
||||
"edit-mode": editMode,
|
||||
"import-only": this.importOnly,
|
||||
})}"
|
||||
>
|
||||
${repeat(
|
||||
cardsConfig,
|
||||
(cardConfig) => this._getKey(cardConfig),
|
||||
@@ -233,6 +238,19 @@ export class GridSection extends LitElement implements LovelaceSectionElement {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.container.edit-mode {
|
||||
padding: 8px;
|
||||
border-radius: var(--ha-card-border-radius, 12px);
|
||||
border-start-end-radius: 0;
|
||||
border: 2px dashed var(--divider-color);
|
||||
min-height: var(--row-height);
|
||||
}
|
||||
|
||||
.container.import-only {
|
||||
border: none;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.card {
|
||||
border-radius: var(--ha-card-border-radius, 12px);
|
||||
position: relative;
|
||||
|
@@ -66,34 +66,9 @@ export const HOME_SUMMARIES_FILTERS: Record<HomeSummary, EntityFilter[]> = {
|
||||
},
|
||||
{
|
||||
domain: "binary_sensor",
|
||||
device_class: [
|
||||
// Locks
|
||||
"lock",
|
||||
// Openings
|
||||
"door",
|
||||
"window",
|
||||
"garage_door",
|
||||
"opening",
|
||||
// Humans
|
||||
"motion",
|
||||
"presence",
|
||||
"occupancy",
|
||||
// Safety
|
||||
"carbon_monoxide",
|
||||
"gas",
|
||||
"moisture",
|
||||
"safety",
|
||||
"smoke",
|
||||
"tamper",
|
||||
],
|
||||
device_class: ["door", "garage_door", "motion"],
|
||||
entity_category: "none",
|
||||
},
|
||||
// We also want the tamper sensors when they are diagnostic
|
||||
{
|
||||
domain: "binary_sensor",
|
||||
device_class: ["tamper"],
|
||||
entity_category: "diagnostic",
|
||||
},
|
||||
],
|
||||
media_players: [{ domain: "media_player", entity_category: "none" }],
|
||||
};
|
||||
|
@@ -1,5 +1,11 @@
|
||||
import { ResizeController } from "@lit-labs/observers/resize-controller";
|
||||
import { mdiEyeOff, mdiViewGridPlus } from "@mdi/js";
|
||||
import {
|
||||
mdiDelete,
|
||||
mdiDrag,
|
||||
mdiEyeOff,
|
||||
mdiPencil,
|
||||
mdiViewGridPlus,
|
||||
} from "@mdi/js";
|
||||
import type { PropertyValues } from "lit";
|
||||
import { css, html, LitElement, nothing } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators";
|
||||
@@ -16,21 +22,28 @@ import type { LovelaceViewElement } from "../../../data/lovelace";
|
||||
import type { LovelaceCardConfig } from "../../../data/lovelace/config/card";
|
||||
import type { LovelaceSectionConfig } from "../../../data/lovelace/config/section";
|
||||
import type { LovelaceViewConfig } from "../../../data/lovelace/config/view";
|
||||
import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import type { HuiBadge } from "../badges/hui-badge";
|
||||
import "./hui-view-header";
|
||||
import type { HuiCard } from "../cards/hui-card";
|
||||
import "../components/hui-badge-edit-mode";
|
||||
import "../components/hui-section-edit-mode";
|
||||
import { addSection, moveCard, moveSection } from "../editor/config-util";
|
||||
import {
|
||||
addSection,
|
||||
deleteSection,
|
||||
moveCard,
|
||||
moveSection,
|
||||
} from "../editor/config-util";
|
||||
import type { LovelaceCardPath } from "../editor/lovelace-path";
|
||||
import {
|
||||
findLovelaceContainer,
|
||||
findLovelaceItems,
|
||||
getLovelaceContainerPath,
|
||||
parseLovelaceCardPath,
|
||||
} from "../editor/lovelace-path";
|
||||
import { showEditSectionDialog } from "../editor/section-editor/show-edit-section-dialog";
|
||||
import type { HuiSection } from "../sections/hui-section";
|
||||
import type { Lovelace } from "../types";
|
||||
import "./hui-view-header";
|
||||
|
||||
export const DEFAULT_MAX_COLUMNS = 4;
|
||||
|
||||
@@ -192,19 +205,41 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
})}
|
||||
>
|
||||
${
|
||||
editMode
|
||||
this.lovelace?.editMode
|
||||
? html`
|
||||
<hui-section-edit-mode
|
||||
.hass=${this.hass}
|
||||
.lovelace=${this.lovelace}
|
||||
.index=${idx}
|
||||
.viewIndex=${this.index}
|
||||
>
|
||||
${section}
|
||||
</hui-section-edit-mode>
|
||||
<div class="section-header">
|
||||
${editMode
|
||||
? html`
|
||||
<div class="section-actions">
|
||||
<ha-svg-icon
|
||||
aria-hidden="true"
|
||||
class="handle"
|
||||
.path=${mdiDrag}
|
||||
></ha-svg-icon>
|
||||
<ha-icon-button
|
||||
.label=${this.hass.localize(
|
||||
"ui.common.edit"
|
||||
)}
|
||||
@click=${this._editSection}
|
||||
.index=${idx}
|
||||
.path=${mdiPencil}
|
||||
></ha-icon-button>
|
||||
<ha-icon-button
|
||||
.label=${this.hass.localize(
|
||||
"ui.common.delete"
|
||||
)}
|
||||
@click=${this._deleteSection}
|
||||
.index=${idx}
|
||||
.path=${mdiDelete}
|
||||
></ha-icon-button>
|
||||
</div>
|
||||
`
|
||||
: nothing}
|
||||
</div>
|
||||
`
|
||||
: section
|
||||
: nothing
|
||||
}
|
||||
${section}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -340,6 +375,48 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
this.lovelace!.saveConfig(newConfig);
|
||||
}
|
||||
|
||||
private async _editSection(ev) {
|
||||
const index = ev.currentTarget.index;
|
||||
|
||||
showEditSectionDialog(this, {
|
||||
lovelace: this.lovelace!,
|
||||
lovelaceConfig: this.lovelace!.config,
|
||||
saveConfig: (newConfig) => {
|
||||
this.lovelace!.saveConfig(newConfig);
|
||||
},
|
||||
viewIndex: this.index!,
|
||||
sectionIndex: index,
|
||||
});
|
||||
}
|
||||
|
||||
private async _deleteSection(ev) {
|
||||
const index = ev.currentTarget.index;
|
||||
|
||||
const path = [this.index!, index] as [number, number];
|
||||
|
||||
const section = findLovelaceContainer(this.lovelace!.config, path);
|
||||
|
||||
const cardCount = "cards" in section && section.cards?.length;
|
||||
|
||||
if (cardCount) {
|
||||
const confirm = await showConfirmationDialog(this, {
|
||||
title: this.hass.localize(
|
||||
"ui.panel.lovelace.editor.delete_section.title"
|
||||
),
|
||||
text: this.hass.localize(
|
||||
`ui.panel.lovelace.editor.delete_section.text`
|
||||
),
|
||||
confirmText: this.hass.localize("ui.common.delete"),
|
||||
destructive: true,
|
||||
});
|
||||
|
||||
if (!confirm) return;
|
||||
}
|
||||
|
||||
const newConfig = deleteSection(this.lovelace!.config, this.index!, index);
|
||||
this.lovelace!.saveConfig(newConfig);
|
||||
}
|
||||
|
||||
private _sectionMoved(ev: CustomEvent) {
|
||||
ev.stopPropagation();
|
||||
const { oldIndex, newIndex } = ev.detail;
|
||||
@@ -409,6 +486,11 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
grid-auto-flow: row dense;
|
||||
}
|
||||
|
||||
.handle {
|
||||
cursor: grab;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.create-section-container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
@@ -492,6 +574,35 @@ export class SectionsView extends LitElement implements LovelaceViewElement {
|
||||
);
|
||||
}
|
||||
|
||||
.section-header {
|
||||
position: relative;
|
||||
height: 34px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.section-actions {
|
||||
position: absolute;
|
||||
height: 36px;
|
||||
bottom: -2px;
|
||||
right: 0;
|
||||
inset-inline-end: 0;
|
||||
inset-inline-start: initial;
|
||||
opacity: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
border-radius: var(--ha-card-border-radius, 12px);
|
||||
border-bottom-left-radius: 0px;
|
||||
border-bottom-right-radius: 0px;
|
||||
background: var(--secondary-background-color);
|
||||
--mdc-icon-button-size: 36px;
|
||||
--mdc-icon-size: 20px;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
|
||||
.imported-cards {
|
||||
--column-span: var(--column-count);
|
||||
--row-span: 1;
|
||||
|
@@ -661,20 +661,35 @@
|
||||
},
|
||||
"target-picker": {
|
||||
"expand": "Expand",
|
||||
"collapse": "Collapse",
|
||||
"expand_floor_id": "Split this floor into separate areas.",
|
||||
"expand_area_id": "Split this area into separate devices and entities.",
|
||||
"expand_device_id": "Split this device into separate entities.",
|
||||
"expand_label_id": "Split this label into separate areas, devices and entities.",
|
||||
"remove": "Remove",
|
||||
"remove_floor_id": "Remove floor",
|
||||
"remove_floors": "Remove floors",
|
||||
"remove_area_id": "Remove area",
|
||||
"remove_areas": "Remove areas",
|
||||
"remove_device_id": "Remove device",
|
||||
"remove_devices": "Remove devices",
|
||||
"remove_entity_id": "Remove entity",
|
||||
"remove_entitys": "Remove entities",
|
||||
"remove_label_id": "Remove label",
|
||||
"remove_labels": "Remove labels",
|
||||
"add_area_id": "Choose area",
|
||||
"add_device_id": "Choose device",
|
||||
"add_entity_id": "Choose entity",
|
||||
"add_label_id": "Choose label"
|
||||
"add_label_id": "Choose label",
|
||||
"devices_count": "{count} {count, plural,\n one {device}\n other {devices}\n}",
|
||||
"entities_count": "{count} {count, plural,\n one {entity}\n other {entities}\n}",
|
||||
"selected": {
|
||||
"entity": "Entities: {count}",
|
||||
"device": "Devices: {count}",
|
||||
"area": "Areas: {count}",
|
||||
"label": "Labels: {count}",
|
||||
"floor": "Floors: {count}"
|
||||
}
|
||||
},
|
||||
"subpage-data-table": {
|
||||
"filters": "Filters",
|
||||
@@ -2461,7 +2476,7 @@
|
||||
"local_backup_location": {
|
||||
"title": "Change default local backup location",
|
||||
"description": "Change the default location where local backups are stored on your Home Assistant instance.",
|
||||
"note": "This location will be used when you create a backup using the Supervisor actions in an automation for example.",
|
||||
"note": "This location will be used when you create a backup using the supervisor actions in an automation for example.",
|
||||
"options": {
|
||||
"default_backup_mount": {
|
||||
"name": "Default location"
|
||||
@@ -2893,8 +2908,8 @@
|
||||
"description": "Creates a backup of your add-on and its data. That way you can keep around the previous version of the add-on, so you can always roll back to it if needed.",
|
||||
"local_only": "This backup is only saved on this system.",
|
||||
"retention_description": "Prevent your system from filling up with old versions.",
|
||||
"error_load": "Error loading Supervisor update config: {error}",
|
||||
"error_save": "Error saving Supervisor update config: {error}"
|
||||
"error_load": "Error loading supervisor update config: {error}",
|
||||
"error_save": "Error saving supervisor update config: {error}"
|
||||
}
|
||||
},
|
||||
"details": {
|
||||
@@ -5550,7 +5565,7 @@
|
||||
},
|
||||
"custom_integration": "Custom integration",
|
||||
"legacy_integration": "Legacy integration",
|
||||
"custom_overwrites_core": "Custom integration that replaces a Core component",
|
||||
"custom_overwrites_core": "Custom integration that replaces a core component",
|
||||
"depends_on_cloud": "Requires Internet",
|
||||
"yaml_only": "This integration cannot be set up from the UI",
|
||||
"no_config_flow": "This integration was not set up from the UI",
|
||||
@@ -7059,9 +7074,9 @@
|
||||
"add": "Add to Home Assistant",
|
||||
"add_device": "Add device",
|
||||
"create_automation": "Create automation",
|
||||
"create_area": "Create area",
|
||||
"create_area_success": "Area created",
|
||||
"create_area_action": "View area",
|
||||
"add_area": "Add area",
|
||||
"add_area_success": "Area added",
|
||||
"add_area_action": "View area",
|
||||
"add_person_success": "Person added",
|
||||
"add_person_action": "View persons",
|
||||
"add_person": "Add person"
|
||||
@@ -8889,13 +8904,13 @@
|
||||
"title": "Entity is not recorded",
|
||||
"info_text_1": "State changes of ''{name}'' ({statistic_id}) are not recorded, therefore, we cannot track long term statistics for it.",
|
||||
"info_text_2": "You probably excluded this entity, or have just included some entities.",
|
||||
"info_text_3_link": "See the Recorder documentation for more information."
|
||||
"info_text_3_link": "See the recorder documentation for more information."
|
||||
},
|
||||
"entity_no_longer_recorded": {
|
||||
"title": "Entity is no longer recorded",
|
||||
"info_text_1": "We have generated statistics for ''{name}'' ({statistic_id}) in the past, but state changes of this entity are no longer recorded, therefore, we cannot track long term statistics for it anymore.",
|
||||
"info_text_2": "You probably excluded this entity, or have just included some entities.",
|
||||
"info_text_3_link": "See the Recorder documentation for more information.",
|
||||
"info_text_3_link": "See the recorder documentation for more information.",
|
||||
"info_text_4": "If you no longer wish to keep the long term statistics recorded in the past, you may delete them now."
|
||||
},
|
||||
"state_class_removed": {
|
||||
@@ -9744,7 +9759,7 @@
|
||||
"remote_download_text": "You are accessing Home Assistant via remote access. Downloading backups over the Nabu Casa URL will take some time. If you are at home, cancel this dialog and enter your local URL, such as 'http://homeassistant.local:8123'",
|
||||
"restore_start_failed": "Failed to start restore. Unknown error.",
|
||||
"no_backup_found": "No backup found.",
|
||||
"restore_no_home_assistant": "Backup does not contain Home Assistant data. To restore Home Assistant you need a backup of Home Assistant Core.",
|
||||
"restore_no_home_assistant": "Backup does not contain Home Assistant data. To restore Home Assistant you need a backup of Home Assistant core.",
|
||||
"unnamed_backup": "Unnamed backup"
|
||||
},
|
||||
"dialog": {
|
||||
|
327
yarn.lock
327
yarn.lock
@@ -1644,7 +1644,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@floating-ui/dom@npm:^1.6.13":
|
||||
"@floating-ui/dom@npm:^1.6.12, @floating-ui/dom@npm:^1.6.13":
|
||||
version: 1.7.3
|
||||
resolution: "@floating-ui/dom@npm:1.7.3"
|
||||
dependencies:
|
||||
@@ -1905,9 +1905,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@home-assistant/webawesome@npm:3.0.0-beta.4.ha.3":
|
||||
version: 3.0.0-beta.4.ha.3
|
||||
resolution: "@home-assistant/webawesome@npm:3.0.0-beta.4.ha.3"
|
||||
"@home-assistant/webawesome@npm:3.0.0-beta.4.ha.2":
|
||||
version: 3.0.0-beta.4.ha.2
|
||||
resolution: "@home-assistant/webawesome@npm:3.0.0-beta.4.ha.2"
|
||||
dependencies:
|
||||
"@ctrl/tinycolor": "npm:^4.1.0"
|
||||
"@floating-ui/dom": "npm:^1.6.13"
|
||||
@@ -1919,7 +1919,7 @@ __metadata:
|
||||
nanoid: "npm:^5.1.5"
|
||||
qr-creator: "npm:^1.0.0"
|
||||
style-observer: "npm:^0.0.7"
|
||||
checksum: 10/b9241821ed471ccbad86b0ea4697a2d41395f05fdc26f46e5edbc7f6b5eeab5d248251ef702326312ded00d5bf850ce0dcdcf7cd5e2e542b9d9cb9a84f3726da
|
||||
checksum: 10/0ac66d43050571e2b86bb7b0181d428aa2a064e25745075b207a8fe96d873398eaead663172130dfe8d9ac0be575028f8f9f6b9f8a9cd12f81c8c82e9f60a0e9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -2326,7 +2326,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@lit/react@npm:^1.0.8":
|
||||
"@lit/react@npm:^1.0.6, @lit/react@npm:^1.0.8":
|
||||
version: 1.0.8
|
||||
resolution: "@lit/react@npm:1.0.8"
|
||||
peerDependencies:
|
||||
@@ -4000,92 +4000,92 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rspack/binding-darwin-arm64@npm:1.5.3":
|
||||
version: 1.5.3
|
||||
resolution: "@rspack/binding-darwin-arm64@npm:1.5.3"
|
||||
"@rspack/binding-darwin-arm64@npm:1.5.2":
|
||||
version: 1.5.2
|
||||
resolution: "@rspack/binding-darwin-arm64@npm:1.5.2"
|
||||
conditions: os=darwin & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rspack/binding-darwin-x64@npm:1.5.3":
|
||||
version: 1.5.3
|
||||
resolution: "@rspack/binding-darwin-x64@npm:1.5.3"
|
||||
"@rspack/binding-darwin-x64@npm:1.5.2":
|
||||
version: 1.5.2
|
||||
resolution: "@rspack/binding-darwin-x64@npm:1.5.2"
|
||||
conditions: os=darwin & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rspack/binding-linux-arm64-gnu@npm:1.5.3":
|
||||
version: 1.5.3
|
||||
resolution: "@rspack/binding-linux-arm64-gnu@npm:1.5.3"
|
||||
"@rspack/binding-linux-arm64-gnu@npm:1.5.2":
|
||||
version: 1.5.2
|
||||
resolution: "@rspack/binding-linux-arm64-gnu@npm:1.5.2"
|
||||
conditions: os=linux & cpu=arm64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rspack/binding-linux-arm64-musl@npm:1.5.3":
|
||||
version: 1.5.3
|
||||
resolution: "@rspack/binding-linux-arm64-musl@npm:1.5.3"
|
||||
"@rspack/binding-linux-arm64-musl@npm:1.5.2":
|
||||
version: 1.5.2
|
||||
resolution: "@rspack/binding-linux-arm64-musl@npm:1.5.2"
|
||||
conditions: os=linux & cpu=arm64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rspack/binding-linux-x64-gnu@npm:1.5.3":
|
||||
version: 1.5.3
|
||||
resolution: "@rspack/binding-linux-x64-gnu@npm:1.5.3"
|
||||
"@rspack/binding-linux-x64-gnu@npm:1.5.2":
|
||||
version: 1.5.2
|
||||
resolution: "@rspack/binding-linux-x64-gnu@npm:1.5.2"
|
||||
conditions: os=linux & cpu=x64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rspack/binding-linux-x64-musl@npm:1.5.3":
|
||||
version: 1.5.3
|
||||
resolution: "@rspack/binding-linux-x64-musl@npm:1.5.3"
|
||||
"@rspack/binding-linux-x64-musl@npm:1.5.2":
|
||||
version: 1.5.2
|
||||
resolution: "@rspack/binding-linux-x64-musl@npm:1.5.2"
|
||||
conditions: os=linux & cpu=x64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rspack/binding-wasm32-wasi@npm:1.5.3":
|
||||
version: 1.5.3
|
||||
resolution: "@rspack/binding-wasm32-wasi@npm:1.5.3"
|
||||
"@rspack/binding-wasm32-wasi@npm:1.5.2":
|
||||
version: 1.5.2
|
||||
resolution: "@rspack/binding-wasm32-wasi@npm:1.5.2"
|
||||
dependencies:
|
||||
"@napi-rs/wasm-runtime": "npm:^1.0.1"
|
||||
conditions: cpu=wasm32
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rspack/binding-win32-arm64-msvc@npm:1.5.3":
|
||||
version: 1.5.3
|
||||
resolution: "@rspack/binding-win32-arm64-msvc@npm:1.5.3"
|
||||
"@rspack/binding-win32-arm64-msvc@npm:1.5.2":
|
||||
version: 1.5.2
|
||||
resolution: "@rspack/binding-win32-arm64-msvc@npm:1.5.2"
|
||||
conditions: os=win32 & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rspack/binding-win32-ia32-msvc@npm:1.5.3":
|
||||
version: 1.5.3
|
||||
resolution: "@rspack/binding-win32-ia32-msvc@npm:1.5.3"
|
||||
"@rspack/binding-win32-ia32-msvc@npm:1.5.2":
|
||||
version: 1.5.2
|
||||
resolution: "@rspack/binding-win32-ia32-msvc@npm:1.5.2"
|
||||
conditions: os=win32 & cpu=ia32
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rspack/binding-win32-x64-msvc@npm:1.5.3":
|
||||
version: 1.5.3
|
||||
resolution: "@rspack/binding-win32-x64-msvc@npm:1.5.3"
|
||||
"@rspack/binding-win32-x64-msvc@npm:1.5.2":
|
||||
version: 1.5.2
|
||||
resolution: "@rspack/binding-win32-x64-msvc@npm:1.5.2"
|
||||
conditions: os=win32 & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rspack/binding@npm:1.5.3":
|
||||
version: 1.5.3
|
||||
resolution: "@rspack/binding@npm:1.5.3"
|
||||
"@rspack/binding@npm:1.5.2":
|
||||
version: 1.5.2
|
||||
resolution: "@rspack/binding@npm:1.5.2"
|
||||
dependencies:
|
||||
"@rspack/binding-darwin-arm64": "npm:1.5.3"
|
||||
"@rspack/binding-darwin-x64": "npm:1.5.3"
|
||||
"@rspack/binding-linux-arm64-gnu": "npm:1.5.3"
|
||||
"@rspack/binding-linux-arm64-musl": "npm:1.5.3"
|
||||
"@rspack/binding-linux-x64-gnu": "npm:1.5.3"
|
||||
"@rspack/binding-linux-x64-musl": "npm:1.5.3"
|
||||
"@rspack/binding-wasm32-wasi": "npm:1.5.3"
|
||||
"@rspack/binding-win32-arm64-msvc": "npm:1.5.3"
|
||||
"@rspack/binding-win32-ia32-msvc": "npm:1.5.3"
|
||||
"@rspack/binding-win32-x64-msvc": "npm:1.5.3"
|
||||
"@rspack/binding-darwin-arm64": "npm:1.5.2"
|
||||
"@rspack/binding-darwin-x64": "npm:1.5.2"
|
||||
"@rspack/binding-linux-arm64-gnu": "npm:1.5.2"
|
||||
"@rspack/binding-linux-arm64-musl": "npm:1.5.2"
|
||||
"@rspack/binding-linux-x64-gnu": "npm:1.5.2"
|
||||
"@rspack/binding-linux-x64-musl": "npm:1.5.2"
|
||||
"@rspack/binding-wasm32-wasi": "npm:1.5.2"
|
||||
"@rspack/binding-win32-arm64-msvc": "npm:1.5.2"
|
||||
"@rspack/binding-win32-ia32-msvc": "npm:1.5.2"
|
||||
"@rspack/binding-win32-x64-msvc": "npm:1.5.2"
|
||||
dependenciesMeta:
|
||||
"@rspack/binding-darwin-arm64":
|
||||
optional: true
|
||||
@@ -4107,23 +4107,23 @@ __metadata:
|
||||
optional: true
|
||||
"@rspack/binding-win32-x64-msvc":
|
||||
optional: true
|
||||
checksum: 10/900fbc0d611cdbd3040e7b4f1d3680b77ec92086f126d3840d303604a06425dc20597d5435a49cfd98b479039f39b604c31588e4843f4905ee762cb93d622a36
|
||||
checksum: 10/71c41c6c878445ea561b7a02d9f75ec13ce170f5d63053debd72dee82a07d23c491a55526cfe9e0aceb5ee1154a07bbe69121deb2821d1a3ac5021eea75d9114
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rspack/core@npm:1.5.3":
|
||||
version: 1.5.3
|
||||
resolution: "@rspack/core@npm:1.5.3"
|
||||
"@rspack/core@npm:1.5.2":
|
||||
version: 1.5.2
|
||||
resolution: "@rspack/core@npm:1.5.2"
|
||||
dependencies:
|
||||
"@module-federation/runtime-tools": "npm:0.18.0"
|
||||
"@rspack/binding": "npm:1.5.3"
|
||||
"@rspack/binding": "npm:1.5.2"
|
||||
"@rspack/lite-tapable": "npm:1.0.1"
|
||||
peerDependencies:
|
||||
"@swc/helpers": ">=0.5.1"
|
||||
peerDependenciesMeta:
|
||||
"@swc/helpers":
|
||||
optional: true
|
||||
checksum: 10/1e8839b81c2f83951ac128ae11cfc62c366bb068fa7b64a96425e0236f30a64816b04ecb49a9cd5e5a1f0db5afeb00526eb7cfdfce30c51e545e3a5c4e7719d5
|
||||
checksum: 10/e72023c8eea0ed351d950a28b6897ca7143ad749a65380ab855e12f96f8ce692ab044c14acf9b030bca740b722c197ad3075eaadac4fe480389e3131c519ac0e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -4170,6 +4170,22 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@shoelace-style/shoelace@npm:2.20.1":
|
||||
version: 2.20.1
|
||||
resolution: "@shoelace-style/shoelace@npm:2.20.1"
|
||||
dependencies:
|
||||
"@ctrl/tinycolor": "npm:^4.1.0"
|
||||
"@floating-ui/dom": "npm:^1.6.12"
|
||||
"@lit/react": "npm:^1.0.6"
|
||||
"@shoelace-style/animations": "npm:^1.2.0"
|
||||
"@shoelace-style/localize": "npm:^3.2.1"
|
||||
composed-offset-position: "npm:^0.0.6"
|
||||
lit: "npm:^3.2.1"
|
||||
qr-creator: "npm:^1.0.0"
|
||||
checksum: 10/c3aabeac03d5fd5bc43799783562ab09c92bae98efbc43a931c7dcec608acc393771b6ed0da3f29e08570bb9d9a9e3bff7637cbf6f79ba7aa439f6641da4eb7c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@sindresorhus/merge-streams@npm:^2.1.0":
|
||||
version: 2.3.0
|
||||
resolution: "@sindresorhus/merge-streams@npm:2.3.0"
|
||||
@@ -4752,6 +4768,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/node-fetch@npm:^2.6.12":
|
||||
version: 2.6.13
|
||||
resolution: "@types/node-fetch@npm:2.6.13"
|
||||
dependencies:
|
||||
"@types/node": "npm:*"
|
||||
form-data: "npm:^4.0.4"
|
||||
checksum: 10/944d52214791ebba482ca1393a4f0d62b0dbac5f7343ff42c128b75d5356d8bcefd4df77771b55c1acd19d118e16e9bd5d2792819c51bc13402d1c87c0975435
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/node-forge@npm:^1.3.0":
|
||||
version: 1.3.14
|
||||
resolution: "@types/node-forge@npm:1.3.14"
|
||||
@@ -4948,106 +4974,106 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/eslint-plugin@npm:8.43.0":
|
||||
version: 8.43.0
|
||||
resolution: "@typescript-eslint/eslint-plugin@npm:8.43.0"
|
||||
"@typescript-eslint/eslint-plugin@npm:8.42.0":
|
||||
version: 8.42.0
|
||||
resolution: "@typescript-eslint/eslint-plugin@npm:8.42.0"
|
||||
dependencies:
|
||||
"@eslint-community/regexpp": "npm:^4.10.0"
|
||||
"@typescript-eslint/scope-manager": "npm:8.43.0"
|
||||
"@typescript-eslint/type-utils": "npm:8.43.0"
|
||||
"@typescript-eslint/utils": "npm:8.43.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.43.0"
|
||||
"@typescript-eslint/scope-manager": "npm:8.42.0"
|
||||
"@typescript-eslint/type-utils": "npm:8.42.0"
|
||||
"@typescript-eslint/utils": "npm:8.42.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.42.0"
|
||||
graphemer: "npm:^1.4.0"
|
||||
ignore: "npm:^7.0.0"
|
||||
natural-compare: "npm:^1.4.0"
|
||||
ts-api-utils: "npm:^2.1.0"
|
||||
peerDependencies:
|
||||
"@typescript-eslint/parser": ^8.43.0
|
||||
"@typescript-eslint/parser": ^8.42.0
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/0e9d31f6c7d69f152c8ff32ca501f03834b44945f4587419e26f821841dd1c2705db5648f1bef68985f8c8d7300ca63b9c6dee4e0e756f337f96f60372c7b1f7
|
||||
checksum: 10/fb5b0e0785f9fa9d5ef88e78ff189334b2d1c558efd7b5063508d50275224a8aa38d4af0478228b90d6be6620289384a8d814f05e0af8c952c204515c0f3514e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/parser@npm:8.43.0":
|
||||
version: 8.43.0
|
||||
resolution: "@typescript-eslint/parser@npm:8.43.0"
|
||||
"@typescript-eslint/parser@npm:8.42.0":
|
||||
version: 8.42.0
|
||||
resolution: "@typescript-eslint/parser@npm:8.42.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/scope-manager": "npm:8.43.0"
|
||||
"@typescript-eslint/types": "npm:8.43.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.43.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.43.0"
|
||||
"@typescript-eslint/scope-manager": "npm:8.42.0"
|
||||
"@typescript-eslint/types": "npm:8.42.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.42.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.42.0"
|
||||
debug: "npm:^4.3.4"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/cb3bd8bd48627cd502bb3cc5bb444e32c99d47ac41c092c457fcf0109f4a67491a42537abee51eee13498345f5dbd00dd11ccbf7a1d782a81d5ec9ee3e5df3ad
|
||||
checksum: 10/25eb2d08c118742dc01c2aa279ea4ba2d277e2d9a042ffd4f9bda9e94d7ff2aa90b63aad1204a82617a5c63ddd3dd553d927944cd9c8345826484d0d523cf7ad
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/project-service@npm:8.43.0":
|
||||
version: 8.43.0
|
||||
resolution: "@typescript-eslint/project-service@npm:8.43.0"
|
||||
"@typescript-eslint/project-service@npm:8.42.0":
|
||||
version: 8.42.0
|
||||
resolution: "@typescript-eslint/project-service@npm:8.42.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/tsconfig-utils": "npm:^8.43.0"
|
||||
"@typescript-eslint/types": "npm:^8.43.0"
|
||||
"@typescript-eslint/tsconfig-utils": "npm:^8.42.0"
|
||||
"@typescript-eslint/types": "npm:^8.42.0"
|
||||
debug: "npm:^4.3.4"
|
||||
peerDependencies:
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/ab22f5d6b72dc4f46e7e0e01df549702b60c51941072a4a2a803f006134cad49687a4444f423db1d0d9e84c57f84dbc1458b5db6866b39a292412db96c756846
|
||||
checksum: 10/3e91fd4b4d60edd6fe3e108e8e75947de8aa060aab1de63c23017e8afeca72ef405faa6fcdd17e8aa0023261a81135d095072dc31343c57395e50450258d9fa5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/scope-manager@npm:8.43.0":
|
||||
version: 8.43.0
|
||||
resolution: "@typescript-eslint/scope-manager@npm:8.43.0"
|
||||
"@typescript-eslint/scope-manager@npm:8.42.0":
|
||||
version: 8.42.0
|
||||
resolution: "@typescript-eslint/scope-manager@npm:8.42.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/types": "npm:8.43.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.43.0"
|
||||
checksum: 10/a975ae96bdc019510e1dedd672f1877e6389837774d221240d37196610b307dc59f845f33e23dfff9a96de6e2c3b75e5571a8acc145238408c1e06286efc9de2
|
||||
"@typescript-eslint/types": "npm:8.42.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.42.0"
|
||||
checksum: 10/81be2d908a9d2d83bc9fe5e9219b04277b9fa466bfa7faf45dc076e4b33b39db2fb99b34b8832e329c7db48ddfdc7b78f6c92b564cd6eec99e124d3feaad8645
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/tsconfig-utils@npm:8.43.0, @typescript-eslint/tsconfig-utils@npm:^8.43.0":
|
||||
version: 8.43.0
|
||||
resolution: "@typescript-eslint/tsconfig-utils@npm:8.43.0"
|
||||
"@typescript-eslint/tsconfig-utils@npm:8.42.0, @typescript-eslint/tsconfig-utils@npm:^8.42.0":
|
||||
version: 8.42.0
|
||||
resolution: "@typescript-eslint/tsconfig-utils@npm:8.42.0"
|
||||
peerDependencies:
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/20cb7b553eba44a8c4b4af2d0cabbcff248494b8c87243be7fcd1bb00846344f0bbc5b2353027d8e9053ee3e0c3b491cbf1c024f9f60b7e370220e7b0620b96f
|
||||
checksum: 10/927aa127983a62ddcbfbcd18806fd278e0bf18fade3cca658946f9ff4915e6a5c5cc85926afaa490512c88dd2950b2059f22b50b6d1f4461c9dbd755a4c71c1c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/type-utils@npm:8.43.0":
|
||||
version: 8.43.0
|
||||
resolution: "@typescript-eslint/type-utils@npm:8.43.0"
|
||||
"@typescript-eslint/type-utils@npm:8.42.0":
|
||||
version: 8.42.0
|
||||
resolution: "@typescript-eslint/type-utils@npm:8.42.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/types": "npm:8.43.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.43.0"
|
||||
"@typescript-eslint/utils": "npm:8.43.0"
|
||||
"@typescript-eslint/types": "npm:8.42.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.42.0"
|
||||
"@typescript-eslint/utils": "npm:8.42.0"
|
||||
debug: "npm:^4.3.4"
|
||||
ts-api-utils: "npm:^2.1.0"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/b82184ba5079b95cc7775ddda3f40a994b0594375c0e5597d89db0e74e4e8d0e4b8a29fea646c6ed126af04729a7caa1052c0726e8f170a4106802486879a00b
|
||||
checksum: 10/8d876bbd23c956b604d973c49720060c251f4d8cab255f1fd04826a9a1e3ab7c1310400d49d9ec6cdac3288d7a23cd9fb48d42777651ba53c02b5e1a34efd6e9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/types@npm:8.43.0, @typescript-eslint/types@npm:^8.43.0":
|
||||
version: 8.43.0
|
||||
resolution: "@typescript-eslint/types@npm:8.43.0"
|
||||
checksum: 10/f2c3b3f9cfb680dcf52b686b978176ea095dfb16db3c720149784f40a34c73c861fc57a707b64658bc0409d54ecd0e0d23d5bc41ba7d3b94db47772e2609062a
|
||||
"@typescript-eslint/types@npm:8.42.0, @typescript-eslint/types@npm:^8.42.0":
|
||||
version: 8.42.0
|
||||
resolution: "@typescript-eslint/types@npm:8.42.0"
|
||||
checksum: 10/7c39a35e5bb7083070872edc797ea60a3d6ceff0e3bdf85701919b71da83a51963562053a4b35c9e2a2b08c138fb595e14bc0b5c450e671a26059b58f8d8b4f4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/typescript-estree@npm:8.43.0":
|
||||
version: 8.43.0
|
||||
resolution: "@typescript-eslint/typescript-estree@npm:8.43.0"
|
||||
"@typescript-eslint/typescript-estree@npm:8.42.0":
|
||||
version: 8.42.0
|
||||
resolution: "@typescript-eslint/typescript-estree@npm:8.42.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/project-service": "npm:8.43.0"
|
||||
"@typescript-eslint/tsconfig-utils": "npm:8.43.0"
|
||||
"@typescript-eslint/types": "npm:8.43.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.43.0"
|
||||
"@typescript-eslint/project-service": "npm:8.42.0"
|
||||
"@typescript-eslint/tsconfig-utils": "npm:8.42.0"
|
||||
"@typescript-eslint/types": "npm:8.42.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.42.0"
|
||||
debug: "npm:^4.3.4"
|
||||
fast-glob: "npm:^3.3.2"
|
||||
is-glob: "npm:^4.0.3"
|
||||
@@ -5056,32 +5082,32 @@ __metadata:
|
||||
ts-api-utils: "npm:^2.1.0"
|
||||
peerDependencies:
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/d2a054b6279107150e9c15569e18c861a89e504caa0a14716a2c73a09174814a993748ff637941757e3e9af033a7eeed511c8dcf17f25d3b3322245af35fd1d0
|
||||
checksum: 10/9bb5df97a2ac31e6e3ee6941e10702498a76d23235ba28a23d93e09aa75a2cbcd40dc74935d86706c8e2e55e1a8b6a34bb9fb234461920ed3d8a5abed68ba36b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/utils@npm:8.43.0":
|
||||
version: 8.43.0
|
||||
resolution: "@typescript-eslint/utils@npm:8.43.0"
|
||||
"@typescript-eslint/utils@npm:8.42.0":
|
||||
version: 8.42.0
|
||||
resolution: "@typescript-eslint/utils@npm:8.42.0"
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils": "npm:^4.7.0"
|
||||
"@typescript-eslint/scope-manager": "npm:8.43.0"
|
||||
"@typescript-eslint/types": "npm:8.43.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.43.0"
|
||||
"@typescript-eslint/scope-manager": "npm:8.42.0"
|
||||
"@typescript-eslint/types": "npm:8.42.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.42.0"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/2c04182084bf3ba391198c723635ce50557ec73b1ebcc7970f0281c345db92aebdbbd1202e9bb3152b3c62a61b043907dde385bb44fce33841c52257c18b0064
|
||||
checksum: 10/41c6c0d01c414c94d7109e21deee73b416547b3be26240d0237a3004c6198f146afefc75feee5333bc957ece6a0856518750655e794fd68c96feec1001edbfe8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/visitor-keys@npm:8.43.0":
|
||||
version: 8.43.0
|
||||
resolution: "@typescript-eslint/visitor-keys@npm:8.43.0"
|
||||
"@typescript-eslint/visitor-keys@npm:8.42.0":
|
||||
version: 8.42.0
|
||||
resolution: "@typescript-eslint/visitor-keys@npm:8.42.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/types": "npm:8.43.0"
|
||||
"@typescript-eslint/types": "npm:8.42.0"
|
||||
eslint-visitor-keys: "npm:^4.2.1"
|
||||
checksum: 10/d694425dd8592b9452640a82d638f4161ac880a8825f1cd6ce41b227bacff3a2e9106238344cbb85cb432593caf892bf4dcca0b73dcc884449ba88ee0ebec94a
|
||||
checksum: 10/ef3aeabf7b01eb72e176053a4fe7a4c4f0769a9f58d1f7a920c97d365305b950c402ad34227209781996ae187652ccf0f47c31015f992c502b5fa898a9d44bd5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -9022,10 +9048,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"globals@npm:16.4.0":
|
||||
version: 16.4.0
|
||||
resolution: "globals@npm:16.4.0"
|
||||
checksum: 10/1627a9f42fb4c82d7af6a0c8b6cd616e00110908304d5f1ddcdf325998f3aed45a4b29d8a1e47870f328817805263e31e4f1673f00022b9c2b210552767921cf
|
||||
"globals@npm:16.3.0":
|
||||
version: 16.3.0
|
||||
resolution: "globals@npm:16.3.0"
|
||||
checksum: 10/accb0939d993a1c461df8d961ce9911a9a96120929e0a61057ae8e75b7df0a8bf8089da0f4e3a476db0211156416fbd26e222a56f74b389a140b34481c0a72b0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -9267,10 +9293,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"hls.js@npm:1.6.12":
|
||||
version: 1.6.12
|
||||
resolution: "hls.js@npm:1.6.12"
|
||||
checksum: 10/b0f23fcda44c6a4dc16dc501b3a17829417133079fefb7463a1e3d22ae9da24cb970e9e45165e4223b1e6b3a3d0f253ca680dcc9daf2e27d3d8153390ed3b9be
|
||||
"hls.js@npm:1.6.11":
|
||||
version: 1.6.11
|
||||
resolution: "hls.js@npm:1.6.11"
|
||||
checksum: 10/a7fb6407bd9729186fcdff14fb37d98d24ddfdce69e30165179a1af4c66fc83252bd85ee9199df91220ca5573fed7529b861d40fe86d93b4c06dc89ccc33382a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -9308,7 +9334,7 @@ __metadata:
|
||||
"@fullcalendar/list": "npm:6.1.19"
|
||||
"@fullcalendar/luxon3": "npm:6.1.19"
|
||||
"@fullcalendar/timegrid": "npm:6.1.19"
|
||||
"@home-assistant/webawesome": "npm:3.0.0-beta.4.ha.3"
|
||||
"@home-assistant/webawesome": "npm:3.0.0-beta.4.ha.2"
|
||||
"@lezer/highlight": "npm:1.2.1"
|
||||
"@lit-labs/motion": "npm:1.0.9"
|
||||
"@lit-labs/observers": "npm:2.0.6"
|
||||
@@ -9346,8 +9372,9 @@ __metadata:
|
||||
"@octokit/rest": "npm:22.0.0"
|
||||
"@replit/codemirror-indentation-markers": "npm:6.5.3"
|
||||
"@rsdoctor/rspack-plugin": "npm:1.2.3"
|
||||
"@rspack/core": "npm:1.5.3"
|
||||
"@rspack/core": "npm:1.5.2"
|
||||
"@rspack/dev-server": "npm:1.1.4"
|
||||
"@shoelace-style/shoelace": "npm:2.20.1"
|
||||
"@swc/helpers": "npm:0.5.17"
|
||||
"@thomasloven/round-slider": "npm:0.6.0"
|
||||
"@tsparticles/engine": "npm:3.9.1"
|
||||
@@ -9414,7 +9441,7 @@ __metadata:
|
||||
gulp-json-transform: "npm:0.5.0"
|
||||
gulp-rename: "npm:2.1.0"
|
||||
gulp-zopfli-green: "npm:6.0.2"
|
||||
hls.js: "npm:1.6.12"
|
||||
hls.js: "npm:1.6.11"
|
||||
home-assistant-js-websocket: "npm:9.5.0"
|
||||
html-minifier-terser: "npm:7.2.0"
|
||||
husky: "npm:9.1.7"
|
||||
@@ -9456,8 +9483,8 @@ __metadata:
|
||||
tinykeys: "npm:3.0.0"
|
||||
ts-lit-plugin: "npm:2.0.2"
|
||||
typescript: "npm:5.9.2"
|
||||
typescript-eslint: "npm:8.43.0"
|
||||
ua-parser-js: "npm:2.0.5"
|
||||
typescript-eslint: "npm:8.42.0"
|
||||
ua-parser-js: "npm:2.0.4"
|
||||
vite-tsconfig-paths: "npm:5.1.4"
|
||||
vitest: "npm:3.2.4"
|
||||
vue: "npm:2.7.16"
|
||||
@@ -11500,7 +11527,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"node-fetch@npm:^2.6.1":
|
||||
"node-fetch@npm:^2.6.1, node-fetch@npm:^2.7.0":
|
||||
version: 2.7.0
|
||||
resolution: "node-fetch@npm:2.7.0"
|
||||
dependencies:
|
||||
@@ -14488,18 +14515,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"typescript-eslint@npm:8.43.0":
|
||||
version: 8.43.0
|
||||
resolution: "typescript-eslint@npm:8.43.0"
|
||||
"typescript-eslint@npm:8.42.0":
|
||||
version: 8.42.0
|
||||
resolution: "typescript-eslint@npm:8.42.0"
|
||||
dependencies:
|
||||
"@typescript-eslint/eslint-plugin": "npm:8.43.0"
|
||||
"@typescript-eslint/parser": "npm:8.43.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.43.0"
|
||||
"@typescript-eslint/utils": "npm:8.43.0"
|
||||
"@typescript-eslint/eslint-plugin": "npm:8.42.0"
|
||||
"@typescript-eslint/parser": "npm:8.42.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.42.0"
|
||||
"@typescript-eslint/utils": "npm:8.42.0"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <6.0.0"
|
||||
checksum: 10/51bd655f43aa6363932dee0d290fb26752875afdf6360a9940bc1c744b67ef82a1715392a65490ba4aa8a0490ad0ae0eb8903d831949f68af6a4e89e01a85b1c
|
||||
checksum: 10/7f71501823b2c1e87e89ff00d6d8eb40c7514630dbb6b7b44c4dd830c95709357270763df2d711a8ea7bb0b58bd69534f15b01db4550dc6e745df8fec8f6a3ae
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -14550,17 +14577,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ua-parser-js@npm:2.0.5":
|
||||
version: 2.0.5
|
||||
resolution: "ua-parser-js@npm:2.0.5"
|
||||
"ua-parser-js@npm:2.0.4":
|
||||
version: 2.0.4
|
||||
resolution: "ua-parser-js@npm:2.0.4"
|
||||
dependencies:
|
||||
"@types/node-fetch": "npm:^2.6.12"
|
||||
detect-europe-js: "npm:^0.1.2"
|
||||
is-standalone-pwa: "npm:^0.1.1"
|
||||
node-fetch: "npm:^2.7.0"
|
||||
ua-is-frozen: "npm:^0.1.2"
|
||||
undici: "npm:^7.12.0"
|
||||
bin:
|
||||
ua-parser-js: script/cli.js
|
||||
checksum: 10/e946cb1c85bfcd0f2d30c7d5e1b605e340bb458432e7e87fc4aa1b2f90117e4220521d4e0bc7dd8c2a5cadd0935dedb5ac434b70efdc0007221288c1d98b3cd5
|
||||
checksum: 10/eb3a57cd4aea6c42d2d766761ccf38cdc4576075646dec611efc336f0d1e640896ec4ca084142a1fedbf25c589e093e2cad50c49a22d089e234029ecb9b8d2e4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -14623,13 +14651,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"undici@npm:^7.12.0":
|
||||
version: 7.16.0
|
||||
resolution: "undici@npm:7.16.0"
|
||||
checksum: 10/2bb71672b23d3dc0f56f1b7fb6c936e4487a350db46eaafc03f2f9107f99cdf8e51ecdd32e589e2381ef47a64b6369cfb31f328b2c3ea663023aa47bc5258b9e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"unicode-canonical-property-names-ecmascript@npm:^2.0.0":
|
||||
version: 2.0.1
|
||||
resolution: "unicode-canonical-property-names-ecmascript@npm:2.0.1"
|
||||
|
Reference in New Issue
Block a user