mirror of
https://github.com/home-assistant/frontend.git
synced 2025-11-30 05:07:19 +00:00
Compare commits
5 Commits
helpers-en
...
ha-icon-pi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4d77c2b60a | ||
|
|
e4b4c809c9 | ||
|
|
0c51b100b6 | ||
|
|
017bc712b0 | ||
|
|
b034f57384 |
4
.github/workflows/cast_deployment.yaml
vendored
4
.github/workflows/cast_deployment.yaml
vendored
@@ -21,7 +21,7 @@ jobs:
|
|||||||
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
with:
|
with:
|
||||||
ref: dev
|
ref: dev
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ jobs:
|
|||||||
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
with:
|
with:
|
||||||
ref: master
|
ref: master
|
||||||
|
|
||||||
|
|||||||
8
.github/workflows/ci.yaml
vendored
8
.github/workflows/ci.yaml
vendored
@@ -24,7 +24,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
with:
|
with:
|
||||||
@@ -58,7 +58,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
with:
|
with:
|
||||||
@@ -76,7 +76,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
with:
|
with:
|
||||||
@@ -100,7 +100,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
with:
|
with:
|
||||||
|
|||||||
8
.github/workflows/codeql-analysis.yml
vendored
8
.github/workflows/codeql-analysis.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
with:
|
with:
|
||||||
# We must fetch at least the immediate parents so that if this is
|
# We must fetch at least the immediate parents so that if this is
|
||||||
# a pull request then we can checkout the head.
|
# a pull request then we can checkout the head.
|
||||||
@@ -36,14 +36,14 @@ jobs:
|
|||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@e12f0178983d466f2f6028f5cc7a6d786fd97f4b # v4.31.4
|
uses: github/codeql-action/init@014f16e7ab1402f30e7c3329d33797e7948572db # v4.31.3
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
|
|
||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
# 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)
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@e12f0178983d466f2f6028f5cc7a6d786fd97f4b # v4.31.4
|
uses: github/codeql-action/autobuild@014f16e7ab1402f30e7c3329d33797e7948572db # v4.31.3
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
# 📚 https://git.io/JvXDl
|
# 📚 https://git.io/JvXDl
|
||||||
@@ -57,4 +57,4 @@ jobs:
|
|||||||
# make release
|
# make release
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@e12f0178983d466f2f6028f5cc7a6d786fd97f4b # v4.31.4
|
uses: github/codeql-action/analyze@014f16e7ab1402f30e7c3329d33797e7948572db # v4.31.3
|
||||||
|
|||||||
4
.github/workflows/demo_deployment.yaml
vendored
4
.github/workflows/demo_deployment.yaml
vendored
@@ -22,7 +22,7 @@ jobs:
|
|||||||
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
with:
|
with:
|
||||||
ref: dev
|
ref: dev
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ jobs:
|
|||||||
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
with:
|
with:
|
||||||
ref: master
|
ref: master
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/design_deployment.yaml
vendored
2
.github/workflows/design_deployment.yaml
vendored
@@ -16,7 +16,7 @@ jobs:
|
|||||||
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
url: ${{ steps.deploy.outputs.NETLIFY_LIVE_URL || steps.deploy.outputs.NETLIFY_URL }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
|
|||||||
2
.github/workflows/design_preview.yaml
vendored
2
.github/workflows/design_preview.yaml
vendored
@@ -21,7 +21,7 @@ jobs:
|
|||||||
if: github.repository == 'home-assistant/frontend' && contains(github.event.pull_request.labels.*.name, 'needs design preview')
|
if: github.repository == 'home-assistant/frontend' && contains(github.event.pull_request.labels.*.name, 'needs design preview')
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
|
|||||||
2
.github/workflows/nightly.yaml
vendored
2
.github/workflows/nightly.yaml
vendored
@@ -20,7 +20,7 @@ jobs:
|
|||||||
contents: write
|
contents: write
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
|
||||||
- name: Set up Python ${{ env.PYTHON_VERSION }}
|
- name: Set up Python ${{ env.PYTHON_VERSION }}
|
||||||
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6
|
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6
|
||||||
|
|||||||
6
.github/workflows/release.yaml
vendored
6
.github/workflows/release.yaml
vendored
@@ -23,7 +23,7 @@ jobs:
|
|||||||
contents: write # Required to upload release assets
|
contents: write # Required to upload release assets
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
|
||||||
- name: Set up Python ${{ env.PYTHON_VERSION }}
|
- name: Set up Python ${{ env.PYTHON_VERSION }}
|
||||||
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
|
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
|
||||||
@@ -91,7 +91,7 @@ jobs:
|
|||||||
contents: write # Required to upload release assets
|
contents: write # Required to upload release assets
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
with:
|
with:
|
||||||
@@ -120,7 +120,7 @@ jobs:
|
|||||||
contents: write # Required to upload release assets
|
contents: write # Required to upload release assets
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
|
||||||
with:
|
with:
|
||||||
|
|||||||
2
.github/workflows/translations.yaml
vendored
2
.github/workflows/translations.yaml
vendored
@@ -14,7 +14,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||||
|
|
||||||
- name: Upload Translations
|
- name: Upload Translations
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ A compact, accessible dropdown menu for choosing actions or settings. `ha-dropdo
|
|||||||
### Example usage (composition)
|
### Example usage (composition)
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<ha-dropdown>
|
<ha-dropdown open>
|
||||||
<ha-button slot="trigger" with-caret>Dropdown</ha-button>
|
<ha-button slot="trigger" with-caret>Dropdown</ha-button>
|
||||||
|
|
||||||
<ha-dropdown-item>
|
<ha-dropdown-item>
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export class DemoHaDropdown extends LitElement {
|
|||||||
<div class=${mode}>
|
<div class=${mode}>
|
||||||
<ha-card header="ha-button in ${mode}">
|
<ha-card header="ha-button in ${mode}">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<ha-dropdown>
|
<ha-dropdown open>
|
||||||
<ha-button slot="trigger" with-caret>Dropdown</ha-button>
|
<ha-button slot="trigger" with-caret>Dropdown</ha-button>
|
||||||
|
|
||||||
<ha-dropdown-item>
|
<ha-dropdown-item>
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
import { genClientId } from "home-assistant-js-websocket";
|
import { genClientId } from "home-assistant-js-websocket";
|
||||||
import type { PropertyValues } from "lit";
|
import type { PropertyValues } from "lit";
|
||||||
import { html, LitElement, nothing } from "lit";
|
import { html, LitElement, nothing } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
|
||||||
import { keyed } from "lit/directives/keyed";
|
import { keyed } from "lit/directives/keyed";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import type { LocalizeFunc } from "../common/translations/localize";
|
import type { LocalizeFunc } from "../common/translations/localize";
|
||||||
import "../components/ha-alert";
|
import "../components/ha-alert";
|
||||||
import "../components/ha-button";
|
import "../components/ha-button";
|
||||||
@@ -59,8 +59,7 @@ export class HaAuthFlow extends LitElement {
|
|||||||
willUpdate(changedProps: PropertyValues) {
|
willUpdate(changedProps: PropertyValues) {
|
||||||
super.willUpdate(changedProps);
|
super.willUpdate(changedProps);
|
||||||
|
|
||||||
if (!this.hasUpdated && this.clientId === genClientId()) {
|
if (!this.hasUpdated) {
|
||||||
// Preselect store token when logging in to own instance
|
|
||||||
this._storeToken = this.initStoreToken;
|
this._storeToken = this.initStoreToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,9 +117,6 @@ export class HaAuthFlow extends LitElement {
|
|||||||
display: block;
|
display: block;
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
.action ha-button {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
<form>${this._renderForm()}</form>
|
<form>${this._renderForm()}</form>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -597,15 +597,10 @@ export class HaChartBase extends LitElement {
|
|||||||
aria: { show: true },
|
aria: { show: true },
|
||||||
dataZoom: this._getDataZoomConfig(),
|
dataZoom: this._getDataZoomConfig(),
|
||||||
toolbox: {
|
toolbox: {
|
||||||
top: Number.MAX_SAFE_INTEGER,
|
top: Infinity,
|
||||||
left: Number.MAX_SAFE_INTEGER,
|
left: Infinity,
|
||||||
feature: {
|
feature: {
|
||||||
dataZoom: {
|
dataZoom: { show: true, yAxisIndex: false, filterMode: "none" },
|
||||||
show: true,
|
|
||||||
yAxisIndex: false,
|
|
||||||
filterMode: "none",
|
|
||||||
showTitle: false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
iconStyle: { opacity: 0 },
|
iconStyle: { opacity: 0 },
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -129,6 +129,10 @@ export class HaGenericPicker extends LitElement {
|
|||||||
// helper to set new value after closing picker, to avoid flicker
|
// helper to set new value after closing picker, to avoid flicker
|
||||||
private _newValue?: string;
|
private _newValue?: string;
|
||||||
|
|
||||||
|
@property({ attribute: "error-message" }) public errorMessage?: string;
|
||||||
|
|
||||||
|
@property({ type: Boolean, reflect: true }) public invalid = false;
|
||||||
|
|
||||||
private _unsubscribeTinyKeys?: () => void;
|
private _unsubscribeTinyKeys?: () => void;
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
@@ -163,6 +167,8 @@ export class HaGenericPicker extends LitElement {
|
|||||||
.value=${this.value}
|
.value=${this.value}
|
||||||
.required=${this.required}
|
.required=${this.required}
|
||||||
.disabled=${this.disabled}
|
.disabled=${this.disabled}
|
||||||
|
.errorMessage=${this.errorMessage}
|
||||||
|
.invalid=${this.invalid}
|
||||||
.hideClearIcon=${this.hideClearIcon}
|
.hideClearIcon=${this.hideClearIcon}
|
||||||
.valueRenderer=${this.valueRenderer}
|
.valueRenderer=${this.valueRenderer}
|
||||||
>
|
>
|
||||||
@@ -234,11 +240,16 @@ export class HaGenericPicker extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _renderHelper() {
|
private _renderHelper() {
|
||||||
return this.helper
|
const showError = this.invalid && this.errorMessage;
|
||||||
? html`<ha-input-helper-text .disabled=${this.disabled}
|
const showHelper = !showError && this.helper;
|
||||||
>${this.helper}</ha-input-helper-text
|
|
||||||
>`
|
if (!showError && !showHelper) {
|
||||||
: nothing;
|
return nothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`<ha-input-helper-text .disabled=${this.disabled}>
|
||||||
|
${showError ? this.errorMessage : this.helper}
|
||||||
|
</ha-input-helper-text>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _dialogOpened = () => {
|
private _dialogOpened = () => {
|
||||||
@@ -337,6 +348,9 @@ export class HaGenericPicker extends LitElement {
|
|||||||
display: block;
|
display: block;
|
||||||
margin: var(--ha-space-2) 0 0;
|
margin: var(--ha-space-2) 0 0;
|
||||||
}
|
}
|
||||||
|
:host([invalid]) ha-input-helper-text {
|
||||||
|
color: var(--mdc-theme-error, var(--error-color, #b00020));
|
||||||
|
}
|
||||||
|
|
||||||
wa-popover {
|
wa-popover {
|
||||||
--wa-space-l: var(--ha-space-0);
|
--wa-space-l: var(--ha-space-0);
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
import type { ComboBoxLitRenderer } from "@vaadin/combo-box/lit";
|
import type { RenderItemFunction } from "@lit-labs/virtualizer/virtualize";
|
||||||
import type {
|
|
||||||
ComboBoxDataProviderCallback,
|
|
||||||
ComboBoxDataProviderParams,
|
|
||||||
} from "@vaadin/combo-box/vaadin-combo-box-light";
|
|
||||||
import type { TemplateResult } from "lit";
|
import type { TemplateResult } from "lit";
|
||||||
import { LitElement, css, html } from "lit";
|
import { LitElement, css, html } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
@@ -10,9 +6,10 @@ import memoizeOne from "memoize-one";
|
|||||||
import { fireEvent } from "../common/dom/fire_event";
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
import { customIcons } from "../data/custom_icons";
|
import { customIcons } from "../data/custom_icons";
|
||||||
import type { HomeAssistant, ValueChangedEvent } from "../types";
|
import type { HomeAssistant, ValueChangedEvent } from "../types";
|
||||||
import "./ha-combo-box";
|
|
||||||
import "./ha-icon";
|
|
||||||
import "./ha-combo-box-item";
|
import "./ha-combo-box-item";
|
||||||
|
import "./ha-generic-picker";
|
||||||
|
import "./ha-icon";
|
||||||
|
import type { PickerComboBoxItem } from "./ha-picker-combo-box";
|
||||||
|
|
||||||
interface IconItem {
|
interface IconItem {
|
||||||
icon: string;
|
icon: string;
|
||||||
@@ -21,7 +18,7 @@ interface IconItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface RankedIcon {
|
interface RankedIcon {
|
||||||
icon: string;
|
item: PickerComboBoxItem;
|
||||||
rank: number;
|
rank: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,13 +64,18 @@ const loadCustomIconItems = async (iconsetPrefix: string) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const rowRenderer: ComboBoxLitRenderer<IconItem | RankedIcon> = (item) => html`
|
const rowRenderer: RenderItemFunction<PickerComboBoxItem> = (item) => html`
|
||||||
<ha-combo-box-item type="button">
|
<ha-combo-box-item type="button">
|
||||||
<ha-icon .icon=${item.icon} slot="start"></ha-icon>
|
<ha-icon .icon=${item.id} slot="start"></ha-icon>
|
||||||
${item.icon}
|
${item.id}
|
||||||
</ha-combo-box-item>
|
</ha-combo-box-item>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const valueRenderer = (value: string) => html`
|
||||||
|
<ha-icon .icon=${value} slot="start"></ha-icon>
|
||||||
|
<span slot="headline">${value}</span>
|
||||||
|
`;
|
||||||
|
|
||||||
@customElement("ha-icon-picker")
|
@customElement("ha-icon-picker")
|
||||||
export class HaIconPicker extends LitElement {
|
export class HaIconPicker extends LitElement {
|
||||||
@property({ attribute: false }) public hass?: HomeAssistant;
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||||
@@ -96,13 +98,11 @@ export class HaIconPicker extends LitElement {
|
|||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<ha-combo-box
|
<ha-generic-picker
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
item-value-path="icon"
|
|
||||||
item-label-path="icon"
|
|
||||||
.value=${this._value}
|
.value=${this._value}
|
||||||
allow-custom-value
|
allow-custom-value
|
||||||
.dataProvider=${ICONS_LOADED ? this._iconProvider : undefined}
|
.getItems=${this._getItems}
|
||||||
.label=${this.label}
|
.label=${this.label}
|
||||||
.helper=${this.helper}
|
.helper=${this.helper}
|
||||||
.disabled=${this.disabled}
|
.disabled=${this.disabled}
|
||||||
@@ -110,69 +110,85 @@ export class HaIconPicker extends LitElement {
|
|||||||
.placeholder=${this.placeholder}
|
.placeholder=${this.placeholder}
|
||||||
.errorMessage=${this.errorMessage}
|
.errorMessage=${this.errorMessage}
|
||||||
.invalid=${this.invalid}
|
.invalid=${this.invalid}
|
||||||
.renderer=${rowRenderer}
|
.rowRenderer=${rowRenderer}
|
||||||
icon
|
.valueRenderer=${valueRenderer}
|
||||||
@opened-changed=${this._openedChanged}
|
.searchFn=${this._filterIcons}
|
||||||
|
.notFoundLabel=${this.hass?.localize(
|
||||||
|
"ui.components.icon-picker.no_match"
|
||||||
|
)}
|
||||||
|
popover-placement="bottom-start"
|
||||||
@value-changed=${this._valueChanged}
|
@value-changed=${this._valueChanged}
|
||||||
>
|
>
|
||||||
${this._value || this.placeholder
|
</ha-generic-picker>
|
||||||
? html`
|
|
||||||
<ha-icon .icon=${this._value || this.placeholder} slot="icon">
|
|
||||||
</ha-icon>
|
|
||||||
`
|
|
||||||
: html`<slot slot="icon" name="fallback"></slot>`}
|
|
||||||
</ha-combo-box>
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter can take a significant chunk of frame (up to 3-5 ms)
|
// Filter can take a significant chunk of frame (up to 3-5 ms)
|
||||||
private _filterIcons = memoizeOne(
|
private _filterIcons = memoizeOne(
|
||||||
(filter: string, iconItems: IconItem[] = ICONS) => {
|
(filter: string, items: PickerComboBoxItem[]): PickerComboBoxItem[] => {
|
||||||
if (!filter) {
|
if (!filter) {
|
||||||
return iconItems;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
const filteredItems: RankedIcon[] = [];
|
const filteredItems: RankedIcon[] = [];
|
||||||
const addIcon = (icon: string, rank: number) =>
|
const addIcon = (item: PickerComboBoxItem, rank: number) =>
|
||||||
filteredItems.push({ icon, rank });
|
filteredItems.push({ item, rank });
|
||||||
|
|
||||||
// Filter and rank such that exact matches rank higher, and prefer icon name matches over keywords
|
// Filter and rank such that exact matches rank higher, and prefer icon name matches over keywords
|
||||||
for (const item of iconItems) {
|
for (const item of items) {
|
||||||
if (item.parts.has(filter)) {
|
const iconName = item.id.split(":")[1] || item.id;
|
||||||
addIcon(item.icon, 1);
|
const parts = iconName.split("-");
|
||||||
} else if (item.keywords.includes(filter)) {
|
const keywords = item.search_labels?.slice(1) || [];
|
||||||
addIcon(item.icon, 2);
|
|
||||||
} else if (item.icon.includes(filter)) {
|
if (parts.includes(filter)) {
|
||||||
addIcon(item.icon, 3);
|
addIcon(item, 1);
|
||||||
} else if (item.keywords.some((word) => word.includes(filter))) {
|
} else if (keywords.includes(filter)) {
|
||||||
addIcon(item.icon, 4);
|
addIcon(item, 2);
|
||||||
|
} else if (item.id.includes(filter)) {
|
||||||
|
addIcon(item, 3);
|
||||||
|
} else if (keywords.some((word) => word.includes(filter))) {
|
||||||
|
addIcon(item, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow preview for custom icon not in list
|
// Allow preview for custom icon not in list
|
||||||
if (filteredItems.length === 0) {
|
if (filteredItems.length === 0) {
|
||||||
addIcon(filter, 0);
|
addIcon(
|
||||||
|
{
|
||||||
|
id: filter,
|
||||||
|
primary: filter,
|
||||||
|
icon: filter,
|
||||||
|
search_labels: [filter],
|
||||||
|
sorting_label: filter,
|
||||||
|
},
|
||||||
|
0
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return filteredItems.sort((itemA, itemB) => itemA.rank - itemB.rank);
|
return filteredItems
|
||||||
|
.sort((itemA, itemB) => itemA.rank - itemB.rank)
|
||||||
|
.map((item) => item.item);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
private _iconProvider = (
|
private _getItems = (): PickerComboBoxItem[] =>
|
||||||
params: ComboBoxDataProviderParams,
|
ICONS.map((icon: IconItem) => ({
|
||||||
callback: ComboBoxDataProviderCallback<IconItem | RankedIcon>
|
id: icon.icon,
|
||||||
) => {
|
primary: icon.icon,
|
||||||
const filteredItems = this._filterIcons(params.filter.toLowerCase(), ICONS);
|
icon: icon.icon,
|
||||||
const iStart = params.page * params.pageSize;
|
search_labels: [
|
||||||
const iEnd = iStart + params.pageSize;
|
icon.icon.split(":")[1] || icon.icon,
|
||||||
callback(filteredItems.slice(iStart, iEnd), filteredItems.length);
|
...Array.from(icon.parts),
|
||||||
};
|
...icon.keywords,
|
||||||
|
],
|
||||||
|
sorting_label: icon.icon,
|
||||||
|
}));
|
||||||
|
|
||||||
private async _openedChanged(ev: ValueChangedEvent<boolean>) {
|
protected firstUpdated() {
|
||||||
const opened = ev.detail.value;
|
if (!ICONS_LOADED) {
|
||||||
if (opened && !ICONS_LOADED) {
|
loadIcons().then(() => {
|
||||||
await loadIcons();
|
|
||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,15 +215,9 @@ export class HaIconPicker extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static styles = css`
|
static styles = css`
|
||||||
*[slot="icon"] {
|
ha-generic-picker {
|
||||||
color: var(--primary-text-color);
|
width: 100%;
|
||||||
position: relative;
|
display: block;
|
||||||
bottom: 2px;
|
|
||||||
}
|
|
||||||
*[slot="prefix"] {
|
|
||||||
margin-right: 8px;
|
|
||||||
margin-inline-end: 8px;
|
|
||||||
margin-inline-start: initial;
|
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,10 @@ export class HaPickerField extends LitElement {
|
|||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
public valueRenderer?: PickerValueRenderer;
|
public valueRenderer?: PickerValueRenderer;
|
||||||
|
|
||||||
|
@property({ attribute: "error-message" }) public errorMessage?: string;
|
||||||
|
|
||||||
|
@property({ type: Boolean, reflect: true }) public invalid = false;
|
||||||
|
|
||||||
@query("ha-combo-box-item", true) public item!: HaComboBoxItem;
|
@query("ha-combo-box-item", true) public item!: HaComboBoxItem;
|
||||||
|
|
||||||
public async focus() {
|
public async focus() {
|
||||||
@@ -142,6 +146,11 @@ export class HaPickerField extends LitElement {
|
|||||||
background-color: var(--mdc-theme-primary);
|
background-color: var(--mdc-theme-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:host([invalid]) ha-combo-box-item:after {
|
||||||
|
height: 2px;
|
||||||
|
background-color: var(--mdc-theme-error, var(--error-color, #b00020));
|
||||||
|
}
|
||||||
|
|
||||||
.clear {
|
.clear {
|
||||||
margin: 0 -8px;
|
margin: 0 -8px;
|
||||||
--mdc-icon-button-size: 32px;
|
--mdc-icon-button-size: 32px;
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import {
|
|||||||
import { formatTime } from "../common/datetime/format_time";
|
import { formatTime } from "../common/datetime/format_time";
|
||||||
import type { LocalizeFunc } from "../common/translations/localize";
|
import type { LocalizeFunc } from "../common/translations/localize";
|
||||||
import type { HomeAssistant } from "../types";
|
import type { HomeAssistant } from "../types";
|
||||||
import { documentationUrl } from "../util/documentation-url";
|
|
||||||
import { fileDownload } from "../util/file_download";
|
import { fileDownload } from "../util/file_download";
|
||||||
import { handleFetchPromise } from "../util/hass-call-api";
|
import { handleFetchPromise } from "../util/hass-call-api";
|
||||||
import type { BackupManagerState, ManagerStateEvent } from "./backup_manager";
|
import type { BackupManagerState, ManagerStateEvent } from "./backup_manager";
|
||||||
@@ -415,7 +414,7 @@ ${hass.auth.data.hassUrl}
|
|||||||
${hass.localize("ui.panel.config.backup.emergency_kit_file.encryption_key")}
|
${hass.localize("ui.panel.config.backup.emergency_kit_file.encryption_key")}
|
||||||
${encryptionKey}
|
${encryptionKey}
|
||||||
|
|
||||||
${hass.localize("ui.panel.config.backup.emergency_kit_file.more_info", { link: documentationUrl(hass, "/more-info/backup-emergency-kit") })}`);
|
${hass.localize("ui.panel.config.backup.emergency_kit_file.more_info", { link: "https://www.home-assistant.io/more-info/backup-emergency-kit" })}`);
|
||||||
|
|
||||||
export const geneateEmergencyKitFileName = (
|
export const geneateEmergencyKitFileName = (
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import type { Connection } from "home-assistant-js-websocket";
|
|||||||
export interface CoreFrontendUserData {
|
export interface CoreFrontendUserData {
|
||||||
showAdvanced?: boolean;
|
showAdvanced?: boolean;
|
||||||
showEntityIdPicker?: boolean;
|
showEntityIdPicker?: boolean;
|
||||||
default_panel?: string;
|
defaultPanel?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SidebarFrontendUserData {
|
export interface SidebarFrontendUserData {
|
||||||
@@ -12,11 +12,7 @@ export interface SidebarFrontendUserData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface CoreFrontendSystemData {
|
export interface CoreFrontendSystemData {
|
||||||
default_panel?: string;
|
defaultPanel?: string;
|
||||||
}
|
|
||||||
|
|
||||||
export interface HomeFrontendSystemData {
|
|
||||||
favorite_entities?: string[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
@@ -26,7 +22,6 @@ declare global {
|
|||||||
}
|
}
|
||||||
interface FrontendSystemData {
|
interface FrontendSystemData {
|
||||||
core: CoreFrontendSystemData;
|
core: CoreFrontendSystemData;
|
||||||
home: HomeFrontendSystemData;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ export const getLegacyDefaultPanelUrlPath = (): string | null => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getDefaultPanelUrlPath = (hass: HomeAssistant): string =>
|
export const getDefaultPanelUrlPath = (hass: HomeAssistant): string =>
|
||||||
hass.userData?.default_panel ||
|
hass.userData?.defaultPanel ||
|
||||||
hass.systemData?.default_panel ||
|
hass.systemData?.defaultPanel ||
|
||||||
getLegacyDefaultPanelUrlPath() ||
|
getLegacyDefaultPanelUrlPath() ||
|
||||||
DEFAULT_PANEL;
|
DEFAULT_PANEL;
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import type {
|
|||||||
import { showToast } from "../../util/toast";
|
import { showToast } from "../../util/toast";
|
||||||
|
|
||||||
import type { HomeAssistant } from "../../types";
|
import type { HomeAssistant } from "../../types";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
|
||||||
|
|
||||||
@customElement("ha-more-info-add-to")
|
@customElement("ha-more-info-add-to")
|
||||||
export class HaMoreInfoAddTo extends LitElement {
|
export class HaMoreInfoAddTo extends LitElement {
|
||||||
@@ -52,7 +51,6 @@ export class HaMoreInfoAddTo extends LitElement {
|
|||||||
app_payload: action.app_payload,
|
app_payload: action.app_payload,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
fireEvent(this, "add-to-action-selected");
|
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
showToast(this, {
|
showToast(this, {
|
||||||
message: this.hass.localize(
|
message: this.hass.localize(
|
||||||
@@ -151,8 +149,4 @@ declare global {
|
|||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
"ha-more-info-add-to": HaMoreInfoAddTo;
|
"ha-more-info-add-to": HaMoreInfoAddTo;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HASSDomEvents {
|
|
||||||
"add-to-action-selected": undefined;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -645,7 +645,6 @@ export class MoreInfoDialog extends LitElement {
|
|||||||
<ha-more-info-add-to
|
<ha-more-info-add-to
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.entityId=${entityId}
|
.entityId=${entityId}
|
||||||
@add-to-action-selected=${this._goBack}
|
|
||||||
></ha-more-info-add-to>
|
></ha-more-info-add-to>
|
||||||
`
|
`
|
||||||
: nothing
|
: nothing
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { atLeastVersion } from "../common/config/version";
|
|||||||
import { applyThemesOnElement } from "../common/dom/apply_themes_on_element";
|
import { applyThemesOnElement } from "../common/dom/apply_themes_on_element";
|
||||||
import "../components/ha-card";
|
import "../components/ha-card";
|
||||||
import { haStyle } from "../resources/styles";
|
import { haStyle } from "../resources/styles";
|
||||||
import { documentationUrl } from "../util/documentation-url";
|
|
||||||
import type { HomeAssistant } from "../types";
|
import type { HomeAssistant } from "../types";
|
||||||
import "./hass-subpage";
|
import "./hass-subpage";
|
||||||
|
|
||||||
@@ -58,7 +57,7 @@ class SupervisorErrorScreen extends LitElement {
|
|||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
href=${documentationUrl(this.hass, "/help/")}
|
href="https://www.home-assistant.io/help/"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { LitElement, css, html, nothing } from "lit";
|
|||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import type { LocalizeFunc } from "../common/translations/localize";
|
import type { LocalizeFunc } from "../common/translations/localize";
|
||||||
import "../components/ha-card";
|
import "../components/ha-card";
|
||||||
import { documentationUrl } from "../util/documentation-url";
|
|
||||||
import type { HomeAssistant } from "../types";
|
import type { HomeAssistant } from "../types";
|
||||||
import { showAppDialog } from "./dialogs/show-app-dialog";
|
import { showAppDialog } from "./dialogs/show-app-dialog";
|
||||||
import { showCommunityDialog } from "./dialogs/show-community-dialog";
|
import { showCommunityDialog } from "./dialogs/show-community-dialog";
|
||||||
@@ -23,10 +22,7 @@ class OnboardingWelcomeLinks extends LitElement {
|
|||||||
return html`<a
|
return html`<a
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer noopener"
|
rel="noreferrer noopener"
|
||||||
href=${documentationUrl(
|
href="https://www.home-assistant.io/blog/2016/01/19/perfect-home-automation/"
|
||||||
this.hass,
|
|
||||||
"/blog/2016/01/19/perfect-home-automation/"
|
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
<onboarding-welcome-link
|
<onboarding-welcome-link
|
||||||
noninteractive
|
noninteractive
|
||||||
|
|||||||
@@ -188,7 +188,6 @@ export default class HaAutomationSidebar extends LitElement {
|
|||||||
class="handle ${this._resizing ? "resizing" : ""}"
|
class="handle ${this._resizing ? "resizing" : ""}"
|
||||||
@mousedown=${this._handleMouseDown}
|
@mousedown=${this._handleMouseDown}
|
||||||
@touchstart=${this._handleMouseDown}
|
@touchstart=${this._handleMouseDown}
|
||||||
@dblclick=${this._handleDoubleClick}
|
|
||||||
@focus=${this._startKeyboardResizing}
|
@focus=${this._startKeyboardResizing}
|
||||||
@blur=${this._stopKeyboardResizing}
|
@blur=${this._stopKeyboardResizing}
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
@@ -259,17 +258,6 @@ export default class HaAutomationSidebar extends LitElement {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
private _handleDoubleClick = (ev: MouseEvent) => {
|
|
||||||
ev.preventDefault();
|
|
||||||
ev.stopPropagation();
|
|
||||||
this._unregisterResizeHandlers();
|
|
||||||
this._tinykeysUnsub?.();
|
|
||||||
this._tinykeysUnsub = undefined;
|
|
||||||
this._resizing = false;
|
|
||||||
document.body.style.removeProperty("cursor");
|
|
||||||
fireEvent(this, "sidebar-reset-size");
|
|
||||||
};
|
|
||||||
|
|
||||||
private _startResizing(clientX: number) {
|
private _startResizing(clientX: number) {
|
||||||
// register event listeners for drag handling
|
// register event listeners for drag handling
|
||||||
document.addEventListener("mousemove", this._handleMouseMove);
|
document.addEventListener("mousemove", this._handleMouseMove);
|
||||||
@@ -434,6 +422,5 @@ declare global {
|
|||||||
deltaInPx: number;
|
deltaInPx: number;
|
||||||
};
|
};
|
||||||
"sidebar-resizing-stopped": undefined;
|
"sidebar-resizing-stopped": undefined;
|
||||||
"sidebar-reset-size": undefined;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -317,7 +317,6 @@ export class HaManualAutomationEditor extends LitElement {
|
|||||||
@value-changed=${this._sidebarConfigChanged}
|
@value-changed=${this._sidebarConfigChanged}
|
||||||
@sidebar-resized=${this._resizeSidebar}
|
@sidebar-resized=${this._resizeSidebar}
|
||||||
@sidebar-resizing-stopped=${this._stopResizeSidebar}
|
@sidebar-resizing-stopped=${this._stopResizeSidebar}
|
||||||
@sidebar-reset-size=${this._resetSidebarWidth}
|
|
||||||
></ha-automation-sidebar>
|
></ha-automation-sidebar>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -701,16 +700,6 @@ export class HaManualAutomationEditor extends LitElement {
|
|||||||
this._prevSidebarWidthPx = undefined;
|
this._prevSidebarWidthPx = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _resetSidebarWidth(ev: Event) {
|
|
||||||
ev.stopPropagation();
|
|
||||||
this._prevSidebarWidthPx = undefined;
|
|
||||||
this._sidebarWidthPx = SIDEBAR_DEFAULT_WIDTH;
|
|
||||||
this.style.setProperty(
|
|
||||||
"--sidebar-dynamic-width",
|
|
||||||
`${this._sidebarWidthPx}px`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return [
|
return [
|
||||||
saveFabStyles,
|
saveFabStyles,
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { mdiClose, mdiOpenInNew } from "@mdi/js";
|
|||||||
import { css, html, LitElement, nothing } from "lit";
|
import { css, html, LitElement, nothing } from "lit";
|
||||||
import { customElement, property, query, state } from "lit/decorators";
|
import { customElement, property, query, state } from "lit/decorators";
|
||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
import { documentationUrl } from "../../../util/documentation-url";
|
|
||||||
import "../../../components/ha-alert";
|
import "../../../components/ha-alert";
|
||||||
import "../../../components/ha-button";
|
import "../../../components/ha-button";
|
||||||
import "../../../components/ha-code-editor";
|
import "../../../components/ha-code-editor";
|
||||||
@@ -141,7 +140,7 @@ class DialogImportBlueprint extends LitElement {
|
|||||||
<ha-button
|
<ha-button
|
||||||
size="small"
|
size="small"
|
||||||
appearance="plain"
|
appearance="plain"
|
||||||
href=${documentationUrl(this.hass, "/get-blueprints")}
|
href="https://www.home-assistant.io/get-blueprints"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer noopener"
|
rel="noreferrer noopener"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ import {
|
|||||||
} from "../../../data/blueprint";
|
} from "../../../data/blueprint";
|
||||||
import { showScriptEditor } from "../../../data/script";
|
import { showScriptEditor } from "../../../data/script";
|
||||||
import { findRelated } from "../../../data/search";
|
import { findRelated } from "../../../data/search";
|
||||||
import "../../../components/chips/ha-assist-chip";
|
|
||||||
import {
|
import {
|
||||||
showAlertDialog,
|
showAlertDialog,
|
||||||
showConfirmationDialog,
|
showConfirmationDialog,
|
||||||
@@ -61,7 +60,6 @@ type BlueprintMetaDataPath = BlueprintMetaData & {
|
|||||||
error: boolean;
|
error: boolean;
|
||||||
type: "automation" | "script";
|
type: "automation" | "script";
|
||||||
fullpath: string;
|
fullpath: string;
|
||||||
usageCount?: number;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const createNewFunctions = {
|
const createNewFunctions = {
|
||||||
@@ -130,20 +128,14 @@ class HaBlueprintOverview extends LitElement {
|
|||||||
})
|
})
|
||||||
private _filter = "";
|
private _filter = "";
|
||||||
|
|
||||||
@state() private _usageCounts: Record<string, number> = {};
|
|
||||||
|
|
||||||
private _usageCountRequest = 0;
|
|
||||||
|
|
||||||
private _processedBlueprints = memoizeOne(
|
private _processedBlueprints = memoizeOne(
|
||||||
(
|
(
|
||||||
blueprints: Record<string, Blueprints>,
|
blueprints: Record<string, Blueprints>,
|
||||||
localize: LocalizeFunc,
|
localize: LocalizeFunc
|
||||||
usageCounts: Record<string, number>
|
|
||||||
): BlueprintMetaDataPath[] => {
|
): BlueprintMetaDataPath[] => {
|
||||||
const result: any[] = [];
|
const result: any[] = [];
|
||||||
Object.entries(blueprints).forEach(([type, typeBlueprints]) =>
|
Object.entries(blueprints).forEach(([type, typeBlueprints]) =>
|
||||||
Object.entries(typeBlueprints).forEach(([path, blueprint]) => {
|
Object.entries(typeBlueprints).forEach(([path, blueprint]) => {
|
||||||
const fullpath = `${type}/${path}`;
|
|
||||||
if ("error" in blueprint) {
|
if ("error" in blueprint) {
|
||||||
result.push({
|
result.push({
|
||||||
name: blueprint.error,
|
name: blueprint.error,
|
||||||
@@ -153,8 +145,7 @@ class HaBlueprintOverview extends LitElement {
|
|||||||
),
|
),
|
||||||
error: true,
|
error: true,
|
||||||
path,
|
path,
|
||||||
fullpath,
|
fullpath: `${type}/${path}`,
|
||||||
usageCount: 0,
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
result.push({
|
result.push({
|
||||||
@@ -165,8 +156,7 @@ class HaBlueprintOverview extends LitElement {
|
|||||||
),
|
),
|
||||||
error: false,
|
error: false,
|
||||||
path,
|
path,
|
||||||
fullpath,
|
fullpath: `${type}/${path}`,
|
||||||
usageCount: usageCounts[fullpath] || 0,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -199,34 +189,6 @@ class HaBlueprintOverview extends LitElement {
|
|||||||
filterable: true,
|
filterable: true,
|
||||||
flex: 2,
|
flex: 2,
|
||||||
},
|
},
|
||||||
usage_count: {
|
|
||||||
title: localize(
|
|
||||||
"ui.panel.config.blueprint.overview.headers.usage_count"
|
|
||||||
),
|
|
||||||
sortable: true,
|
|
||||||
valueColumn: "usageCount",
|
|
||||||
type: "numeric",
|
|
||||||
minWidth: "100px",
|
|
||||||
maxWidth: "120px",
|
|
||||||
template: (blueprint) => {
|
|
||||||
const count = blueprint.usageCount ?? 0;
|
|
||||||
return html`
|
|
||||||
<ha-assist-chip
|
|
||||||
filled
|
|
||||||
.active=${count > 0}
|
|
||||||
label=${String(count)}
|
|
||||||
title=${blueprint.error
|
|
||||||
? String(count)
|
|
||||||
: this.hass.localize(
|
|
||||||
`ui.panel.config.blueprint.overview.view_${blueprint.type}`
|
|
||||||
)}
|
|
||||||
?disabled=${blueprint.error}
|
|
||||||
data-fullpath=${blueprint.fullpath}
|
|
||||||
@click=${this._handleUsageClick}
|
|
||||||
></ha-assist-chip>
|
|
||||||
`;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
fullpath: {
|
fullpath: {
|
||||||
title: "fullpath",
|
title: "fullpath",
|
||||||
hidden: true,
|
hidden: true,
|
||||||
@@ -304,7 +266,6 @@ class HaBlueprintOverview extends LitElement {
|
|||||||
|
|
||||||
protected firstUpdated(changedProps: PropertyValues) {
|
protected firstUpdated(changedProps: PropertyValues) {
|
||||||
super.firstUpdated(changedProps);
|
super.firstUpdated(changedProps);
|
||||||
this._loadUsageCounts();
|
|
||||||
if (this.route.path === "/import") {
|
if (this.route.path === "/import") {
|
||||||
const url = extractSearchParam("blueprint_url");
|
const url = extractSearchParam("blueprint_url");
|
||||||
navigate("/config/blueprint/dashboard", { replace: true });
|
navigate("/config/blueprint/dashboard", { replace: true });
|
||||||
@@ -314,13 +275,6 @@ class HaBlueprintOverview extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected updated(changedProps: PropertyValues) {
|
|
||||||
super.updated(changedProps);
|
|
||||||
if (changedProps.has("blueprints")) {
|
|
||||||
this._loadUsageCounts();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<hass-tabs-subpage-data-table
|
<hass-tabs-subpage-data-table
|
||||||
@@ -330,11 +284,7 @@ class HaBlueprintOverview extends LitElement {
|
|||||||
.route=${this.route}
|
.route=${this.route}
|
||||||
.tabs=${configSections.automations}
|
.tabs=${configSections.automations}
|
||||||
.columns=${this._columns(this.hass.localize)}
|
.columns=${this._columns(this.hass.localize)}
|
||||||
.data=${this._processedBlueprints(
|
.data=${this._processedBlueprints(this.blueprints, this.hass.localize)}
|
||||||
this.blueprints,
|
|
||||||
this.hass.localize,
|
|
||||||
this._usageCounts
|
|
||||||
)}
|
|
||||||
id="fullpath"
|
id="fullpath"
|
||||||
.noDataText=${this.hass.localize(
|
.noDataText=${this.hass.localize(
|
||||||
"ui.panel.config.blueprint.overview.no_blueprints"
|
"ui.panel.config.blueprint.overview.no_blueprints"
|
||||||
@@ -349,7 +299,7 @@ class HaBlueprintOverview extends LitElement {
|
|||||||
>
|
>
|
||||||
<ha-button
|
<ha-button
|
||||||
appearance="plain"
|
appearance="plain"
|
||||||
href=${documentationUrl(this.hass, "/get-blueprints")}
|
href="https://www.home-assistant.io/get-blueprints"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer noopener"
|
rel="noreferrer noopener"
|
||||||
size="small"
|
size="small"
|
||||||
@@ -430,51 +380,10 @@ class HaBlueprintOverview extends LitElement {
|
|||||||
fireEvent(this, "reload-blueprints");
|
fireEvent(this, "reload-blueprints");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _loadUsageCounts() {
|
|
||||||
if (!this.blueprints) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const request = ++this._usageCountRequest;
|
|
||||||
const usageCounts: Record<string, number> = {};
|
|
||||||
|
|
||||||
const blueprintList = this._processedBlueprints(
|
|
||||||
this.blueprints,
|
|
||||||
this.hass.localize,
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
|
|
||||||
await Promise.all(
|
|
||||||
blueprintList.map(async (blueprint) => {
|
|
||||||
if (blueprint.error) {
|
|
||||||
usageCounts[blueprint.fullpath] = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const related = await findRelated(
|
|
||||||
this.hass,
|
|
||||||
`${blueprint.domain}_blueprint`,
|
|
||||||
blueprint.path
|
|
||||||
);
|
|
||||||
const count =
|
|
||||||
(related.automation?.length || 0) + (related.script?.length || 0);
|
|
||||||
usageCounts[blueprint.fullpath] = count;
|
|
||||||
} catch (_err) {
|
|
||||||
usageCounts[blueprint.fullpath] = 0;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
if (request === this._usageCountRequest) {
|
|
||||||
this._usageCounts = usageCounts;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _handleRowClicked(ev: HASSDomEvent<RowClickedEvent>) {
|
private _handleRowClicked(ev: HASSDomEvent<RowClickedEvent>) {
|
||||||
const blueprint = this._processedBlueprints(
|
const blueprint = this._processedBlueprints(
|
||||||
this.blueprints,
|
this.blueprints,
|
||||||
this.hass.localize,
|
this.hass.localize
|
||||||
this._usageCounts
|
|
||||||
).find((b) => b.fullpath === ev.detail.id)!;
|
).find((b) => b.fullpath === ev.detail.id)!;
|
||||||
if (blueprint.error) {
|
if (blueprint.error) {
|
||||||
showAlertDialog(this, {
|
showAlertDialog(this, {
|
||||||
@@ -488,25 +397,6 @@ class HaBlueprintOverview extends LitElement {
|
|||||||
this._createNew(blueprint);
|
this._createNew(blueprint);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleUsageClick = (ev: Event) => {
|
|
||||||
ev.stopPropagation();
|
|
||||||
ev.preventDefault();
|
|
||||||
const target = ev.currentTarget as HTMLElement | null;
|
|
||||||
const fullpath = target?.dataset.fullpath;
|
|
||||||
if (!fullpath) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const blueprint = this._processedBlueprints(
|
|
||||||
this.blueprints,
|
|
||||||
this.hass.localize,
|
|
||||||
this._usageCounts
|
|
||||||
).find((item) => item.fullpath === fullpath);
|
|
||||||
if (!blueprint || blueprint.error) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._showUsed(blueprint);
|
|
||||||
};
|
|
||||||
|
|
||||||
private _showUsed = (blueprint: BlueprintMetaDataPath) => {
|
private _showUsed = (blueprint: BlueprintMetaDataPath) => {
|
||||||
navigate(
|
navigate(
|
||||||
`/config/${blueprint.domain}/dashboard?blueprint=${encodeURIComponent(
|
`/config/${blueprint.domain}/dashboard?blueprint=${encodeURIComponent(
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ import { mdiDotsVertical, mdiDownload } from "@mdi/js";
|
|||||||
import type { TemplateResult } from "lit";
|
import type { TemplateResult } from "lit";
|
||||||
import { css, html, LitElement, nothing } from "lit";
|
import { css, html, LitElement, nothing } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
|
import "../../../components/ha-button-menu";
|
||||||
import "../../../components/ha-icon-button";
|
import "../../../components/ha-icon-button";
|
||||||
|
import "../../../components/ha-list-item";
|
||||||
import "../../../components/ha-svg-icon";
|
import "../../../components/ha-svg-icon";
|
||||||
import { getSignedPath } from "../../../data/auth";
|
import { getSignedPath } from "../../../data/auth";
|
||||||
import "../../../layouts/hass-subpage";
|
import "../../../layouts/hass-subpage";
|
||||||
@@ -12,8 +14,6 @@ import {
|
|||||||
downloadFileSupported,
|
downloadFileSupported,
|
||||||
fileDownload,
|
fileDownload,
|
||||||
} from "../../../util/file_download";
|
} from "../../../util/file_download";
|
||||||
import "../../../components/ha-dropdown-item";
|
|
||||||
import "../../../components/ha-dropdown";
|
|
||||||
|
|
||||||
@customElement("ha-config-section-analytics")
|
@customElement("ha-config-section-analytics")
|
||||||
class HaConfigSectionAnalytics extends LitElement {
|
class HaConfigSectionAnalytics extends LitElement {
|
||||||
@@ -33,19 +33,22 @@ class HaConfigSectionAnalytics extends LitElement {
|
|||||||
>
|
>
|
||||||
${downloadFileSupported(this.hass)
|
${downloadFileSupported(this.hass)
|
||||||
? html`
|
? html`
|
||||||
<ha-dropdown
|
<ha-button-menu
|
||||||
@wa-select=${this._handleOverflowAction}
|
@action=${this._handleOverflowAction}
|
||||||
slot="toolbar-icon"
|
slot="toolbar-icon"
|
||||||
>
|
>
|
||||||
<ha-icon-button slot="trigger" .path=${mdiDotsVertical}>
|
<ha-icon-button slot="trigger" .path=${mdiDotsVertical}>
|
||||||
</ha-icon-button>
|
</ha-icon-button>
|
||||||
<ha-dropdown-item .value=${"download_device_info"}>
|
<ha-list-item graphic="icon">
|
||||||
<ha-svg-icon slot="icon" .path=${mdiDownload}></ha-svg-icon>
|
<ha-svg-icon
|
||||||
|
slot="graphic"
|
||||||
|
.path=${mdiDownload}
|
||||||
|
></ha-svg-icon>
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
"ui.panel.config.analytics.download_device_info"
|
"ui.panel.config.analytics.download_device_info"
|
||||||
)}
|
)}
|
||||||
</ha-dropdown-item>
|
</ha-list-item>
|
||||||
</ha-dropdown>
|
</ha-button-menu>
|
||||||
`
|
`
|
||||||
: nothing}
|
: nothing}
|
||||||
<div class="content">
|
<div class="content">
|
||||||
@@ -55,17 +58,10 @@ class HaConfigSectionAnalytics extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _handleOverflowAction(
|
private async _handleOverflowAction(): Promise<void> {
|
||||||
ev: CustomEvent<{ item: { value: string } }>
|
const signedPath = await getSignedPath(this.hass, "/api/analytics/devices");
|
||||||
): Promise<void> {
|
|
||||||
if (ev.detail.item.value === "download_device_info") {
|
|
||||||
const signedPath = await getSignedPath(
|
|
||||||
this.hass,
|
|
||||||
"/api/analytics/devices"
|
|
||||||
);
|
|
||||||
fileDownload(signedPath.path);
|
fileDownload(signedPath.path);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static styles = css`
|
static styles = css`
|
||||||
.content {
|
.content {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import type { RequestSelectedDetail } from "@material/mwc-list/mwc-list-item";
|
||||||
import { mdiDotsVertical, mdiRefresh } from "@mdi/js";
|
import { mdiDotsVertical, mdiRefresh } from "@mdi/js";
|
||||||
import type { HassEntities } from "home-assistant-js-websocket";
|
import type { HassEntities } from "home-assistant-js-websocket";
|
||||||
import type { TemplateResult } from "lit";
|
import type { TemplateResult } from "lit";
|
||||||
@@ -5,9 +6,13 @@ import { LitElement, css, html } from "lit";
|
|||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import memoizeOne from "memoize-one";
|
import memoizeOne from "memoize-one";
|
||||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||||
|
import { shouldHandleRequestSelectedEvent } from "../../../common/mwc/handle-request-selected-event";
|
||||||
import "../../../components/ha-alert";
|
import "../../../components/ha-alert";
|
||||||
import "../../../components/ha-bar";
|
import "../../../components/ha-bar";
|
||||||
|
import "../../../components/ha-button-menu";
|
||||||
import "../../../components/ha-card";
|
import "../../../components/ha-card";
|
||||||
|
import "../../../components/ha-check-list-item";
|
||||||
|
import "../../../components/ha-list-item";
|
||||||
import "../../../components/ha-metric";
|
import "../../../components/ha-metric";
|
||||||
import { extractApiErrorMessage } from "../../../data/hassio/common";
|
import { extractApiErrorMessage } from "../../../data/hassio/common";
|
||||||
import type {
|
import type {
|
||||||
@@ -28,9 +33,6 @@ import "../../../layouts/hass-subpage";
|
|||||||
import type { HomeAssistant } from "../../../types";
|
import type { HomeAssistant } from "../../../types";
|
||||||
import "../dashboard/ha-config-updates";
|
import "../dashboard/ha-config-updates";
|
||||||
import { showJoinBetaDialog } from "./updates/show-dialog-join-beta";
|
import { showJoinBetaDialog } from "./updates/show-dialog-join-beta";
|
||||||
import "../../../components/ha-dropdown";
|
|
||||||
import "../../../components/ha-dropdown-item";
|
|
||||||
import "@home-assistant/webawesome/dist/components/divider/divider";
|
|
||||||
|
|
||||||
@customElement("ha-config-section-updates")
|
@customElement("ha-config-section-updates")
|
||||||
class HaConfigSectionUpdates extends LitElement {
|
class HaConfigSectionUpdates extends LitElement {
|
||||||
@@ -71,25 +73,24 @@ class HaConfigSectionUpdates extends LitElement {
|
|||||||
.path=${mdiRefresh}
|
.path=${mdiRefresh}
|
||||||
@click=${this._checkUpdates}
|
@click=${this._checkUpdates}
|
||||||
></ha-icon-button>
|
></ha-icon-button>
|
||||||
<ha-dropdown @wa-select=${this._handleOverflowAction}>
|
<ha-button-menu multi>
|
||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
slot="trigger"
|
slot="trigger"
|
||||||
.label=${this.hass.localize("ui.common.menu")}
|
.label=${this.hass.localize("ui.common.menu")}
|
||||||
.path=${mdiDotsVertical}
|
.path=${mdiDotsVertical}
|
||||||
></ha-icon-button>
|
></ha-icon-button>
|
||||||
|
<ha-check-list-item
|
||||||
<ha-dropdown-item
|
left
|
||||||
type="checkbox"
|
@request-selected=${this._toggleSkipped}
|
||||||
value="show_skipped"
|
.selected=${this._showSkipped}
|
||||||
.checked=${this._showSkipped}
|
|
||||||
>
|
>
|
||||||
${this.hass.localize("ui.panel.config.updates.show_skipped")}
|
${this.hass.localize("ui.panel.config.updates.show_skipped")}
|
||||||
</ha-dropdown-item>
|
</ha-check-list-item>
|
||||||
${this._supervisorInfo
|
${this._supervisorInfo
|
||||||
? html`
|
? html`
|
||||||
<wa-divider></wa-divider>
|
<li divider role="separator"></li>
|
||||||
<ha-dropdown-item
|
<ha-list-item
|
||||||
value="toggle_beta"
|
@request-selected=${this._toggleBeta}
|
||||||
.disabled=${this._supervisorInfo.channel === "dev"}
|
.disabled=${this._supervisorInfo.channel === "dev"}
|
||||||
>
|
>
|
||||||
${this._supervisorInfo.channel === "stable"
|
${this._supervisorInfo.channel === "stable"
|
||||||
@@ -97,10 +98,10 @@ class HaConfigSectionUpdates extends LitElement {
|
|||||||
: this.hass.localize(
|
: this.hass.localize(
|
||||||
"ui.panel.config.updates.leave_beta"
|
"ui.panel.config.updates.leave_beta"
|
||||||
)}
|
)}
|
||||||
</ha-dropdown-item>
|
</ha-list-item>
|
||||||
`
|
`
|
||||||
: ""}
|
: ""}
|
||||||
</ha-dropdown>
|
</ha-button-menu>
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<ha-card outlined>
|
<ha-card outlined>
|
||||||
@@ -132,10 +133,21 @@ class HaConfigSectionUpdates extends LitElement {
|
|||||||
this._supervisorInfo = await fetchHassioSupervisorInfo(this.hass);
|
this._supervisorInfo = await fetchHassioSupervisorInfo(this.hass);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _handleOverflowAction(
|
private _toggleSkipped(ev: CustomEvent<RequestSelectedDetail>): void {
|
||||||
ev: CustomEvent<{ item: { value: string } }>
|
if (ev.detail.source !== "property") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._showSkipped = !this._showSkipped;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _toggleBeta(
|
||||||
|
ev: CustomEvent<RequestSelectedDetail>
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (ev.detail.item.value === "toggle_beta") {
|
if (!shouldHandleRequestSelectedEvent(ev)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this._supervisorInfo!.channel === "stable") {
|
if (this._supervisorInfo!.channel === "stable") {
|
||||||
showJoinBetaDialog(this, {
|
showJoinBetaDialog(this, {
|
||||||
join: async () => this._setChannel("beta"),
|
join: async () => this._setChannel("beta"),
|
||||||
@@ -143,9 +155,6 @@ class HaConfigSectionUpdates extends LitElement {
|
|||||||
} else {
|
} else {
|
||||||
this._setChannel("stable");
|
this._setChannel("stable");
|
||||||
}
|
}
|
||||||
} else if (ev.detail.item.value === "show_skipped") {
|
|
||||||
this._showSkipped = !this._showSkipped;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _setChannel(
|
private async _setChannel(
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { css, html, LitElement, nothing } from "lit";
|
|||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
import "../../../../components/ha-alert";
|
import "../../../../components/ha-alert";
|
||||||
import type { EnergyValidationIssue } from "../../../../data/energy";
|
import type { EnergyValidationIssue } from "../../../../data/energy";
|
||||||
import { documentationUrl } from "../../../../util/documentation-url";
|
|
||||||
import type { HomeAssistant } from "../../../../types";
|
import type { HomeAssistant } from "../../../../types";
|
||||||
|
|
||||||
@customElement("ha-energy-validation-result")
|
@customElement("ha-energy-validation-result")
|
||||||
@@ -30,10 +29,7 @@ class EnergyValidationMessage extends LitElement {
|
|||||||
)}
|
)}
|
||||||
${issue.type === "recorder_untracked"
|
${issue.type === "recorder_untracked"
|
||||||
? html`(<a
|
? html`(<a
|
||||||
href=${documentationUrl(
|
href="https://www.home-assistant.io/integrations/recorder#configure-filter"
|
||||||
this.hass,
|
|
||||||
"/integrations/recorder#configure-filter"
|
|
||||||
)}
|
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>${this.hass.localize("ui.panel.config.common.learn_more")}</a
|
>${this.hass.localize("ui.panel.config.common.learn_more")}</a
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import {
|
|||||||
mdiCancel,
|
mdiCancel,
|
||||||
mdiChevronRight,
|
mdiChevronRight,
|
||||||
mdiCog,
|
mdiCog,
|
||||||
mdiDelete,
|
|
||||||
mdiDotsVertical,
|
mdiDotsVertical,
|
||||||
mdiMenuDown,
|
mdiMenuDown,
|
||||||
mdiPencilOff,
|
mdiPencilOff,
|
||||||
@@ -25,10 +24,6 @@ import { computeCssColor } from "../../../common/color/compute-color";
|
|||||||
import { storage } from "../../../common/decorators/storage";
|
import { storage } from "../../../common/decorators/storage";
|
||||||
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
import type { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||||
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
import { computeStateDomain } from "../../../common/entity/compute_state_domain";
|
||||||
import {
|
|
||||||
DEFAULT_ENTITY_NAME,
|
|
||||||
type EntityNameItem,
|
|
||||||
} from "../../../common/entity/compute_entity_name_display";
|
|
||||||
import { navigate } from "../../../common/navigate";
|
import { navigate } from "../../../common/navigate";
|
||||||
import type {
|
import type {
|
||||||
LocalizeFunc,
|
LocalizeFunc,
|
||||||
@@ -114,11 +109,10 @@ import { configSections } from "../ha-panel-config";
|
|||||||
import "../integrations/ha-integration-overflow-menu";
|
import "../integrations/ha-integration-overflow-menu";
|
||||||
import { renderConfigEntryError } from "../integrations/ha-config-integration-page";
|
import { renderConfigEntryError } from "../integrations/ha-config-integration-page";
|
||||||
import { showLabelDetailDialog } from "../labels/show-dialog-label-detail";
|
import { showLabelDetailDialog } from "../labels/show-dialog-label-detail";
|
||||||
import { isHelperDomain, type HelperDomain } from "./const";
|
import { isHelperDomain } from "./const";
|
||||||
import { showHelperDetailDialog } from "./show-dialog-helper-detail";
|
import { showHelperDetailDialog } from "./show-dialog-helper-detail";
|
||||||
import { slugify } from "../../../common/string/slugify";
|
import { slugify } from "../../../common/string/slugify";
|
||||||
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
import { isComponentLoaded } from "../../../common/config/is_component_loaded";
|
||||||
import { HELPERS_CRUD } from "../../../data/helpers_crud";
|
|
||||||
import {
|
import {
|
||||||
fetchDiagnosticHandlers,
|
fetchDiagnosticHandlers,
|
||||||
getConfigEntryDiagnosticsDownloadUrl,
|
getConfigEntryDiagnosticsDownloadUrl,
|
||||||
@@ -126,11 +120,6 @@ import {
|
|||||||
import { getSignedPath } from "../../../data/auth";
|
import { getSignedPath } from "../../../data/auth";
|
||||||
import { fileDownload } from "../../../util/file_download";
|
import { fileDownload } from "../../../util/file_download";
|
||||||
|
|
||||||
const HELPER_ENTITY_NAME: EntityNameItem[] = [
|
|
||||||
{ type: "area" },
|
|
||||||
...DEFAULT_ENTITY_NAME,
|
|
||||||
];
|
|
||||||
|
|
||||||
interface HelperItem {
|
interface HelperItem {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
@@ -462,19 +451,6 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
...(helper.editable && helper.entity
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
divider: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: mdiDelete,
|
|
||||||
label: this.hass.localize("ui.common.delete"),
|
|
||||||
warning: true,
|
|
||||||
action: () => this._deleteHelper(helper),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: []),
|
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
</ha-icon-overflow-menu>
|
</ha-icon-overflow-menu>
|
||||||
@@ -514,7 +490,7 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
id: entityState.entity_id,
|
id: entityState.entity_id,
|
||||||
name: this._formatHelperName(entityState),
|
name: entityState.attributes.friendly_name || "",
|
||||||
entity_id: entityState.entity_id,
|
entity_id: entityState.entity_id,
|
||||||
editable:
|
editable:
|
||||||
configEntry !== undefined || entityState.attributes.editable,
|
configEntry !== undefined || entityState.attributes.editable,
|
||||||
@@ -593,14 +569,6 @@ export class HaConfigHelpers extends SubscribeMixin(LitElement) {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
private _formatHelperName(stateObj: HassEntity): string {
|
|
||||||
const formatted =
|
|
||||||
this.hass.formatEntityName(stateObj, HELPER_ENTITY_NAME) || "";
|
|
||||||
return (
|
|
||||||
formatted || stateObj.attributes.friendly_name || stateObj.entity_id || ""
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _labelsForEntity(entityId: string): string[] {
|
private _labelsForEntity(entityId: string): string[] {
|
||||||
return (
|
return (
|
||||||
this.hass.entities[entityId]?.labels ||
|
this.hass.entities[entityId]?.labels ||
|
||||||
@@ -1312,62 +1280,6 @@ ${rejected
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _deleteHelper(helper: HelperItem) {
|
|
||||||
if (!helper.entity_id) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const confirmed = await showConfirmationDialog(this, {
|
|
||||||
title: this.hass.localize(
|
|
||||||
"ui.panel.config.helpers.picker.delete_confirm_title"
|
|
||||||
),
|
|
||||||
text: this.hass.localize(
|
|
||||||
"ui.panel.config.helpers.picker.delete_confirm_text",
|
|
||||||
{ name: helper.name }
|
|
||||||
),
|
|
||||||
confirmText: this.hass.localize("ui.common.delete"),
|
|
||||||
dismissText: this.hass.localize("ui.common.cancel"),
|
|
||||||
destructive: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!confirmed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// For old-style helpers (input_boolean, etc.), use HELPERS_CRUD
|
|
||||||
if (isHelperDomain(helper.type)) {
|
|
||||||
const entityReg = this._entityReg.find(
|
|
||||||
(e) => e.entity_id === helper.entity_id
|
|
||||||
);
|
|
||||||
if (
|
|
||||||
!entityReg?.unique_id ||
|
|
||||||
!isComponentLoaded(this.hass, helper.type)
|
|
||||||
) {
|
|
||||||
throw new Error(
|
|
||||||
this.hass.localize("ui.panel.config.helpers.picker.delete_failed")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
await HELPERS_CRUD[helper.type as HelperDomain].delete(
|
|
||||||
this.hass,
|
|
||||||
entityReg.unique_id
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For config entry-based helpers, delete the config entry
|
|
||||||
if (helper.configEntry) {
|
|
||||||
await deleteConfigEntry(this.hass, helper.configEntry.entry_id);
|
|
||||||
}
|
|
||||||
} catch (err: any) {
|
|
||||||
showAlertDialog(this, {
|
|
||||||
text:
|
|
||||||
err.message ||
|
|
||||||
this.hass.localize("ui.panel.config.helpers.picker.delete_failed"),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _createHelper() {
|
private _createHelper() {
|
||||||
showHelperDetailDialog(this, {});
|
showHelperDetailDialog(this, {});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,4 @@
|
|||||||
import {
|
import { mdiBookshelf, mdiCog, mdiDotsVertical, mdiOpenInNew } from "@mdi/js";
|
||||||
mdiBookshelf,
|
|
||||||
mdiCog,
|
|
||||||
mdiDelete,
|
|
||||||
mdiDotsVertical,
|
|
||||||
mdiOpenInNew,
|
|
||||||
} from "@mdi/js";
|
|
||||||
import type { TemplateResult } from "lit";
|
import type { TemplateResult } from "lit";
|
||||||
import { LitElement, css, html } from "lit";
|
import { LitElement, css, html } from "lit";
|
||||||
import { customElement, property } from "lit/decorators";
|
import { customElement, property } from "lit/decorators";
|
||||||
@@ -13,11 +7,6 @@ import { fireEvent } from "../../../common/dom/fire_event";
|
|||||||
import "../../../components/ha-button";
|
import "../../../components/ha-button";
|
||||||
import "../../../components/ha-button-menu";
|
import "../../../components/ha-button-menu";
|
||||||
import "../../../components/ha-list-item";
|
import "../../../components/ha-list-item";
|
||||||
import {
|
|
||||||
deleteApplicationCredential,
|
|
||||||
fetchApplicationCredentialsConfigEntry,
|
|
||||||
} from "../../../data/application_credential";
|
|
||||||
import { deleteConfigEntry } from "../../../data/config_entries";
|
|
||||||
import {
|
import {
|
||||||
ATTENTION_SOURCES,
|
ATTENTION_SOURCES,
|
||||||
DISCOVERY_SOURCES,
|
DISCOVERY_SOURCES,
|
||||||
@@ -26,10 +15,7 @@ import {
|
|||||||
} from "../../../data/config_flow";
|
} from "../../../data/config_flow";
|
||||||
import type { IntegrationManifest } from "../../../data/integration";
|
import type { IntegrationManifest } from "../../../data/integration";
|
||||||
import { showConfigFlowDialog } from "../../../dialogs/config-flow/show-dialog-config-flow";
|
import { showConfigFlowDialog } from "../../../dialogs/config-flow/show-dialog-config-flow";
|
||||||
import {
|
import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
|
||||||
showAlertDialog,
|
|
||||||
showConfirmationDialog,
|
|
||||||
} from "../../../dialogs/generic/show-dialog-box";
|
|
||||||
import type { HomeAssistant } from "../../../types";
|
import type { HomeAssistant } from "../../../types";
|
||||||
import { documentationUrl } from "../../../util/documentation-url";
|
import { documentationUrl } from "../../../util/documentation-url";
|
||||||
import type { DataEntryFlowProgressExtended } from "./ha-config-integrations";
|
import type { DataEntryFlowProgressExtended } from "./ha-config-integrations";
|
||||||
@@ -74,7 +60,7 @@ export class HaConfigFlowCard extends LitElement {
|
|||||||
: "ui.common.add"
|
: "ui.common.add"
|
||||||
)}
|
)}
|
||||||
</ha-button>
|
</ha-button>
|
||||||
${this.flow.context.configuration_url || this.manifest || attention
|
${this.flow.context.configuration_url || this.manifest
|
||||||
? html`<ha-button-menu slot="header-button">
|
? html`<ha-button-menu slot="header-button">
|
||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
slot="trigger"
|
slot="trigger"
|
||||||
@@ -132,22 +118,6 @@ export class HaConfigFlowCard extends LitElement {
|
|||||||
</ha-list-item>
|
</ha-list-item>
|
||||||
</a>`
|
</a>`
|
||||||
: ""}
|
: ""}
|
||||||
${attention
|
|
||||||
? html`<ha-list-item
|
|
||||||
class="warning"
|
|
||||||
graphic="icon"
|
|
||||||
@click=${this._handleDelete}
|
|
||||||
>
|
|
||||||
<ha-svg-icon
|
|
||||||
class="warning"
|
|
||||||
slot="graphic"
|
|
||||||
.path=${mdiDelete}
|
|
||||||
></ha-svg-icon>
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.integrations.config_entry.delete"
|
|
||||||
)}
|
|
||||||
</ha-list-item>`
|
|
||||||
: ""}
|
|
||||||
</ha-button-menu>`
|
</ha-button-menu>`
|
||||||
: ""}
|
: ""}
|
||||||
</ha-integration-action-card>
|
</ha-integration-action-card>
|
||||||
@@ -205,109 +175,6 @@ export class HaConfigFlowCard extends LitElement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return an application credentials id for this config entry to prompt the
|
|
||||||
// user for removal. This is best effort so we don't stop overall removal
|
|
||||||
// if the integration isn't loaded or there is some other error.
|
|
||||||
private async _fetchApplicationCredentials(entryId: string) {
|
|
||||||
try {
|
|
||||||
return (await fetchApplicationCredentialsConfigEntry(this.hass, entryId))
|
|
||||||
.application_credentials_id;
|
|
||||||
} catch (_err: any) {
|
|
||||||
// We won't prompt the user to remove credentials
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _removeApplicationCredential(applicationCredentialsId: string) {
|
|
||||||
const confirmed = await showConfirmationDialog(this, {
|
|
||||||
title: this.hass.localize(
|
|
||||||
"ui.panel.config.integrations.config_entry.application_credentials.delete_title"
|
|
||||||
),
|
|
||||||
text: html`${this.hass.localize(
|
|
||||||
"ui.panel.config.integrations.config_entry.application_credentials.delete_prompt"
|
|
||||||
)},
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.integrations.config_entry.application_credentials.delete_detail"
|
|
||||||
)}
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<a
|
|
||||||
href="https://www.home-assistant.io/integrations/application_credentials"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.integrations.config_entry.application_credentials.learn_more"
|
|
||||||
)}
|
|
||||||
</a>`,
|
|
||||||
confirmText: this.hass.localize("ui.common.delete"),
|
|
||||||
dismissText: this.hass.localize("ui.common.cancel"),
|
|
||||||
destructive: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!confirmed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await deleteApplicationCredential(this.hass, applicationCredentialsId);
|
|
||||||
} catch (err: any) {
|
|
||||||
showAlertDialog(this, {
|
|
||||||
title: this.hass.localize(
|
|
||||||
"ui.panel.config.integrations.config_entry.application_credentials.delete_error_title"
|
|
||||||
),
|
|
||||||
text: err.message,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _handleDelete() {
|
|
||||||
const entryId = this.flow.context.entry_id;
|
|
||||||
|
|
||||||
if (!entryId) {
|
|
||||||
// This shouldn't happen for reauth flows, but handle gracefully
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const applicationCredentialsId =
|
|
||||||
await this._fetchApplicationCredentials(entryId);
|
|
||||||
|
|
||||||
const confirmed = await showConfirmationDialog(this, {
|
|
||||||
title: this.hass.localize(
|
|
||||||
"ui.panel.config.integrations.config_entry.delete_confirm_title",
|
|
||||||
{ title: localizeConfigFlowTitle(this.hass.localize, this.flow) }
|
|
||||||
),
|
|
||||||
text: this.hass.localize(
|
|
||||||
"ui.panel.config.integrations.config_entry.delete_confirm_text"
|
|
||||||
),
|
|
||||||
confirmText: this.hass!.localize("ui.common.delete"),
|
|
||||||
dismissText: this.hass!.localize("ui.common.cancel"),
|
|
||||||
destructive: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!confirmed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await deleteConfigEntry(this.hass, entryId);
|
|
||||||
|
|
||||||
if (result.require_restart) {
|
|
||||||
showAlertDialog(this, {
|
|
||||||
text: this.hass.localize(
|
|
||||||
"ui.panel.config.integrations.config_entry.restart_confirm"
|
|
||||||
),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (applicationCredentialsId) {
|
|
||||||
this._removeApplicationCredential(applicationCredentialsId);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._handleFlowUpdated();
|
|
||||||
}
|
|
||||||
|
|
||||||
static styles = css`
|
static styles = css`
|
||||||
a {
|
a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
@@ -324,9 +191,6 @@ export class HaConfigFlowCard extends LitElement {
|
|||||||
--mdc-theme-primary: var(--error-color);
|
--mdc-theme-primary: var(--error-color);
|
||||||
--ha-card-border-color: var(--error-color);
|
--ha-card-border-color: var(--error-color);
|
||||||
}
|
}
|
||||||
.warning {
|
|
||||||
--mdc-theme-text-primary-on-background: var(--error-color);
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -295,7 +295,7 @@ export class ZHANetworkVisualizationPage extends LitElement {
|
|||||||
color:
|
color:
|
||||||
route.route_status === "Active"
|
route.route_status === "Active"
|
||||||
? primaryColor
|
? primaryColor
|
||||||
: style.getPropertyValue("--dark-primary-color"),
|
: style.getPropertyValue("--disabled-color"),
|
||||||
type: ["Child", "Parent"].includes(neighbor.relationship)
|
type: ["Child", "Parent"].includes(neighbor.relationship)
|
||||||
? "solid"
|
? "solid"
|
||||||
: "dotted",
|
: "dotted",
|
||||||
@@ -335,7 +335,7 @@ export class ZHANetworkVisualizationPage extends LitElement {
|
|||||||
symbolSize: 5,
|
symbolSize: 5,
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
width: 1,
|
width: 1,
|
||||||
color: style.getPropertyValue("--dark-primary-color"),
|
color: style.getPropertyValue("--disabled-color"),
|
||||||
type: "dotted",
|
type: "dotted",
|
||||||
},
|
},
|
||||||
ignoreForceLayout: true,
|
ignoreForceLayout: true,
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import type { HomeAssistant } from "../../../types";
|
|||||||
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
|
import { SubscribeMixin } from "../../../mixins/subscribe-mixin";
|
||||||
import { brandsUrl } from "../../../util/brands-url";
|
import { brandsUrl } from "../../../util/brands-url";
|
||||||
import { showToast } from "../../../util/toast";
|
import { showToast } from "../../../util/toast";
|
||||||
import { documentationUrl } from "../../../util/documentation-url";
|
|
||||||
import { haStyle } from "../../../resources/styles";
|
import { haStyle } from "../../../resources/styles";
|
||||||
import { showLabsPreviewFeatureEnableDialog } from "./show-dialog-labs-preview-feature-enable";
|
import { showLabsPreviewFeatureEnableDialog } from "./show-dialog-labs-preview-feature-enable";
|
||||||
import {
|
import {
|
||||||
@@ -101,7 +100,7 @@ class HaConfigLabs extends SubscribeMixin(LitElement) {
|
|||||||
? html`
|
? html`
|
||||||
<a
|
<a
|
||||||
slot="toolbar-icon"
|
slot="toolbar-icon"
|
||||||
href=${documentationUrl(this.hass, "/integrations/labs/")}
|
href="https://www.home-assistant.io/integrations/labs/"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
.title=${this.hass.localize("ui.common.help")}
|
.title=${this.hass.localize("ui.common.help")}
|
||||||
@@ -125,7 +124,7 @@ class HaConfigLabs extends SubscribeMixin(LitElement) {
|
|||||||
"ui.panel.config.labs.empty.description"
|
"ui.panel.config.labs.empty.description"
|
||||||
)}
|
)}
|
||||||
<a
|
<a
|
||||||
href=${documentationUrl(this.hass, "/integrations/labs/")}
|
href="https://www.home-assistant.io/integrations/labs/"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ export class DialogLovelaceDashboardDetail extends LitElement {
|
|||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
const defaultPanelUrlPath =
|
const defaultPanelUrlPath =
|
||||||
this.hass.systemData?.default_panel || DEFAULT_PANEL;
|
this.hass.systemData?.defaultPanel || DEFAULT_PANEL;
|
||||||
const titleInvalid = !this._data.title || !this._data.title.trim();
|
const titleInvalid = !this._data.title || !this._data.title.trim();
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
@@ -260,7 +260,7 @@ export class DialogLovelaceDashboardDetail extends LitElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultPanel = this.hass.systemData?.default_panel || DEFAULT_PANEL;
|
const defaultPanel = this.hass.systemData?.defaultPanel || DEFAULT_PANEL;
|
||||||
// Add warning dialog to saying that this will change the default dashboard for all users
|
// Add warning dialog to saying that this will change the default dashboard for all users
|
||||||
const confirm = await showConfirmationDialog(this, {
|
const confirm = await showConfirmationDialog(this, {
|
||||||
title: this.hass.localize(
|
title: this.hass.localize(
|
||||||
@@ -284,7 +284,7 @@ export class DialogLovelaceDashboardDetail extends LitElement {
|
|||||||
|
|
||||||
saveFrontendSystemData(this.hass.connection, "core", {
|
saveFrontendSystemData(this.hass.connection, "core", {
|
||||||
...this.hass.systemData,
|
...this.hass.systemData,
|
||||||
default_panel: urlPath === defaultPanel ? undefined : urlPath,
|
defaultPanel: urlPath === defaultPanel ? undefined : urlPath,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,20 +309,7 @@ export class DialogLovelaceDashboardDetail extends LitElement {
|
|||||||
}
|
}
|
||||||
this.closeDialog();
|
this.closeDialog();
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
let localizedErrorMessage: string | undefined;
|
this._error = { base: err?.message || "Unknown error" };
|
||||||
if (err?.translation_domain && err?.translation_key) {
|
|
||||||
const localize = await this.hass.loadBackendTranslation(
|
|
||||||
"exceptions",
|
|
||||||
err.translation_domain
|
|
||||||
);
|
|
||||||
localizedErrorMessage = localize(
|
|
||||||
`component.${err.translation_domain}.exceptions.${err.translation_key}.message`,
|
|
||||||
err.translation_placeholders
|
|
||||||
);
|
|
||||||
}
|
|
||||||
this._error = {
|
|
||||||
base: localizedErrorMessage || err?.message || "Unknown error",
|
|
||||||
};
|
|
||||||
} finally {
|
} finally {
|
||||||
this._submitting = false;
|
this._submitting = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -404,7 +404,7 @@ export class HaConfigLovelaceDashboards extends LitElement {
|
|||||||
return html` <hass-loading-screen></hass-loading-screen> `;
|
return html` <hass-loading-screen></hass-loading-screen> `;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultPanel = this.hass.systemData?.default_panel || DEFAULT_PANEL;
|
const defaultPanel = this.hass.systemData?.defaultPanel || DEFAULT_PANEL;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<hass-tabs-subpage-data-table
|
<hass-tabs-subpage-data-table
|
||||||
|
|||||||
@@ -270,7 +270,6 @@ export class HaManualScriptEditor extends LitElement {
|
|||||||
@value-changed=${this._sidebarConfigChanged}
|
@value-changed=${this._sidebarConfigChanged}
|
||||||
@sidebar-resized=${this._resizeSidebar}
|
@sidebar-resized=${this._resizeSidebar}
|
||||||
@sidebar-resizing-stopped=${this._stopResizeSidebar}
|
@sidebar-resizing-stopped=${this._stopResizeSidebar}
|
||||||
@sidebar-reset-size=${this._resetSidebarWidth}
|
|
||||||
></ha-automation-sidebar>
|
></ha-automation-sidebar>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -619,16 +618,6 @@ export class HaManualScriptEditor extends LitElement {
|
|||||||
this._prevSidebarWidthPx = undefined;
|
this._prevSidebarWidthPx = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _resetSidebarWidth(ev: Event) {
|
|
||||||
ev.stopPropagation();
|
|
||||||
this._prevSidebarWidthPx = undefined;
|
|
||||||
this._sidebarWidthPx = SIDEBAR_DEFAULT_WIDTH;
|
|
||||||
this.style.setProperty(
|
|
||||||
"--sidebar-dynamic-width",
|
|
||||||
`${this._sidebarWidthPx}px`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return [
|
return [
|
||||||
saveFabStyles,
|
saveFabStyles,
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import type { CSSResultGroup } from "lit";
|
|||||||
import { LitElement, css, html, nothing } from "lit";
|
import { LitElement, css, html, nothing } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
import { fireEvent } from "../../../common/dom/fire_event";
|
||||||
import { documentationUrl } from "../../../util/documentation-url";
|
|
||||||
import "../../../components/ha-alert";
|
import "../../../components/ha-alert";
|
||||||
import "../../../components/ha-button";
|
import "../../../components/ha-button";
|
||||||
import { createCloseHeading } from "../../../components/ha-dialog";
|
import { createCloseHeading } from "../../../components/ha-dialog";
|
||||||
@@ -15,6 +14,8 @@ import { haStyleDialog } from "../../../resources/styles";
|
|||||||
import type { HomeAssistant } from "../../../types";
|
import type { HomeAssistant } from "../../../types";
|
||||||
import type { TagDetailDialogParams } from "./show-dialog-tag-detail";
|
import type { TagDetailDialogParams } from "./show-dialog-tag-detail";
|
||||||
|
|
||||||
|
const TAG_BASE = "https://www.home-assistant.io/tag/";
|
||||||
|
|
||||||
@customElement("dialog-tag-detail")
|
@customElement("dialog-tag-detail")
|
||||||
class DialogTagDetail
|
class DialogTagDetail
|
||||||
extends LitElement
|
extends LitElement
|
||||||
@@ -121,7 +122,7 @@ class DialogTagDetail
|
|||||||
</div>
|
</div>
|
||||||
<div id="qr">
|
<div id="qr">
|
||||||
<ha-qr-code
|
<ha-qr-code
|
||||||
.data=${`${documentationUrl(this.hass, "/tag/")}${this._params!.entry!.id}`}
|
.data=${`${TAG_BASE}${this._params!.entry!.id}`}
|
||||||
center-image="/static/icons/favicon-192x192.png"
|
center-image="/static/icons/favicon-192x192.png"
|
||||||
error-correction-level="quartile"
|
error-correction-level="quartile"
|
||||||
scale="5"
|
scale="5"
|
||||||
|
|||||||
@@ -1,151 +0,0 @@
|
|||||||
import { css, html, LitElement, nothing } from "lit";
|
|
||||||
import { customElement, property, state } from "lit/decorators";
|
|
||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
|
||||||
import "../../../components/entity/ha-entities-picker";
|
|
||||||
import "../../../components/ha-button";
|
|
||||||
import "../../../components/ha-dialog-footer";
|
|
||||||
import "../../../components/ha-wa-dialog";
|
|
||||||
import type { HomeFrontendSystemData } from "../../../data/frontend";
|
|
||||||
import type { HassDialog } from "../../../dialogs/make-dialog-manager";
|
|
||||||
import { haStyleDialog } from "../../../resources/styles";
|
|
||||||
import type { HomeAssistant } from "../../../types";
|
|
||||||
import type { EditHomeDialogParams } from "./show-dialog-edit-home";
|
|
||||||
|
|
||||||
@customElement("dialog-edit-home")
|
|
||||||
export class DialogEditHome
|
|
||||||
extends LitElement
|
|
||||||
implements HassDialog<EditHomeDialogParams>
|
|
||||||
{
|
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
|
||||||
|
|
||||||
@state() private _params?: EditHomeDialogParams;
|
|
||||||
|
|
||||||
@state() private _config?: HomeFrontendSystemData;
|
|
||||||
|
|
||||||
@state() private _open = false;
|
|
||||||
|
|
||||||
@state() private _submitting = false;
|
|
||||||
|
|
||||||
public showDialog(params: EditHomeDialogParams): void {
|
|
||||||
this._params = params;
|
|
||||||
this._config = { ...params.config };
|
|
||||||
this._open = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public closeDialog(): boolean {
|
|
||||||
this._open = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _dialogClosed(): void {
|
|
||||||
this._params = undefined;
|
|
||||||
this._config = undefined;
|
|
||||||
this._submitting = false;
|
|
||||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render() {
|
|
||||||
if (!this._params) {
|
|
||||||
return nothing;
|
|
||||||
}
|
|
||||||
|
|
||||||
return html`
|
|
||||||
<ha-wa-dialog
|
|
||||||
.hass=${this.hass}
|
|
||||||
.open=${this._open}
|
|
||||||
.headerTitle=${this.hass.localize("ui.panel.home.editor.title")}
|
|
||||||
@closed=${this._dialogClosed}
|
|
||||||
>
|
|
||||||
<p class="description">
|
|
||||||
${this.hass.localize("ui.panel.home.editor.description")}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<ha-entities-picker
|
|
||||||
autofocus
|
|
||||||
.hass=${this.hass}
|
|
||||||
.value=${this._config?.favorite_entities || []}
|
|
||||||
.label=${this.hass.localize(
|
|
||||||
"ui.panel.lovelace.editor.strategy.home.favorite_entities"
|
|
||||||
)}
|
|
||||||
.placeholder=${this.hass.localize(
|
|
||||||
"ui.panel.lovelace.editor.strategy.home.add_favorite_entity"
|
|
||||||
)}
|
|
||||||
.helper=${this.hass.localize(
|
|
||||||
"ui.panel.home.editor.favorite_entities_helper"
|
|
||||||
)}
|
|
||||||
reorder
|
|
||||||
allow-custom-entity
|
|
||||||
@value-changed=${this._favoriteEntitiesChanged}
|
|
||||||
></ha-entities-picker>
|
|
||||||
|
|
||||||
<ha-dialog-footer slot="footer">
|
|
||||||
<ha-button
|
|
||||||
appearance="plain"
|
|
||||||
slot="secondaryAction"
|
|
||||||
@click=${this.closeDialog}
|
|
||||||
.disabled=${this._submitting}
|
|
||||||
>
|
|
||||||
${this.hass.localize("ui.common.cancel")}
|
|
||||||
</ha-button>
|
|
||||||
<ha-button
|
|
||||||
slot="primaryAction"
|
|
||||||
@click=${this._save}
|
|
||||||
.disabled=${this._submitting}
|
|
||||||
>
|
|
||||||
${this.hass.localize("ui.common.save")}
|
|
||||||
</ha-button>
|
|
||||||
</ha-dialog-footer>
|
|
||||||
</ha-wa-dialog>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _favoriteEntitiesChanged(ev: CustomEvent): void {
|
|
||||||
const entities = ev.detail.value as string[];
|
|
||||||
this._config = {
|
|
||||||
...this._config,
|
|
||||||
favorite_entities: entities.length > 0 ? entities : undefined,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _save(): Promise<void> {
|
|
||||||
if (!this._params || !this._config) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._submitting = true;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await this._params.saveConfig(this._config);
|
|
||||||
this.closeDialog();
|
|
||||||
} catch (err: any) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.error("Failed to save home configuration:", err);
|
|
||||||
} finally {
|
|
||||||
this._submitting = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static styles = [
|
|
||||||
haStyleDialog,
|
|
||||||
css`
|
|
||||||
ha-wa-dialog {
|
|
||||||
--dialog-content-padding: var(--ha-space-6);
|
|
||||||
}
|
|
||||||
|
|
||||||
.description {
|
|
||||||
margin: 0 0 var(--ha-space-4) 0;
|
|
||||||
color: var(--secondary-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-entities-picker {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"dialog-edit-home": DialogEditHome;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
import { fireEvent } from "../../../common/dom/fire_event";
|
|
||||||
import type { HomeFrontendSystemData } from "../../../data/frontend";
|
|
||||||
|
|
||||||
export interface EditHomeDialogParams {
|
|
||||||
config: HomeFrontendSystemData;
|
|
||||||
saveConfig: (config: HomeFrontendSystemData) => Promise<void>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const loadEditHomeDialog = () => import("./dialog-edit-home");
|
|
||||||
|
|
||||||
export const showEditHomeDialog = (
|
|
||||||
element: HTMLElement,
|
|
||||||
params: EditHomeDialogParams
|
|
||||||
): void => {
|
|
||||||
fireEvent(element, "show-dialog", {
|
|
||||||
dialogTag: "dialog-edit-home",
|
|
||||||
dialogImport: loadEditHomeDialog,
|
|
||||||
dialogParams: params,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -3,18 +3,18 @@ import { LitElement, css, html, nothing } from "lit";
|
|||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import { debounce } from "../../common/util/debounce";
|
import { debounce } from "../../common/util/debounce";
|
||||||
import { deepEqual } from "../../common/util/deep-equal";
|
import { deepEqual } from "../../common/util/deep-equal";
|
||||||
import {
|
|
||||||
fetchFrontendSystemData,
|
|
||||||
saveFrontendSystemData,
|
|
||||||
type HomeFrontendSystemData,
|
|
||||||
} from "../../data/frontend";
|
|
||||||
import type { LovelaceDashboardStrategyConfig } from "../../data/lovelace/config/types";
|
import type { LovelaceDashboardStrategyConfig } from "../../data/lovelace/config/types";
|
||||||
import type { HomeAssistant, PanelInfo, Route } from "../../types";
|
import type { HomeAssistant, PanelInfo, Route } from "../../types";
|
||||||
import { showToast } from "../../util/toast";
|
|
||||||
import "../lovelace/hui-root";
|
import "../lovelace/hui-root";
|
||||||
import { generateLovelaceDashboardStrategy } from "../lovelace/strategies/get-strategy";
|
import { generateLovelaceDashboardStrategy } from "../lovelace/strategies/get-strategy";
|
||||||
import type { Lovelace } from "../lovelace/types";
|
import type { Lovelace } from "../lovelace/types";
|
||||||
import { showEditHomeDialog } from "./dialogs/show-dialog-edit-home";
|
import { showAlertDialog } from "../lovelace/custom-card-helpers";
|
||||||
|
|
||||||
|
const HOME_LOVELACE_CONFIG: LovelaceDashboardStrategyConfig = {
|
||||||
|
strategy: {
|
||||||
|
type: "home",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
@customElement("ha-panel-home")
|
@customElement("ha-panel-home")
|
||||||
class PanelHome extends LitElement {
|
class PanelHome extends LitElement {
|
||||||
@@ -28,14 +28,12 @@ class PanelHome extends LitElement {
|
|||||||
|
|
||||||
@state() private _lovelace?: Lovelace;
|
@state() private _lovelace?: Lovelace;
|
||||||
|
|
||||||
@state() private _config: FrontendSystemData["home"] = {};
|
|
||||||
|
|
||||||
public willUpdate(changedProps: PropertyValues) {
|
public willUpdate(changedProps: PropertyValues) {
|
||||||
super.willUpdate(changedProps);
|
super.willUpdate(changedProps);
|
||||||
// Initial setup
|
// Initial setup
|
||||||
if (!this.hasUpdated) {
|
if (!this.hasUpdated) {
|
||||||
this.hass.loadFragmentTranslation("lovelace");
|
this.hass.loadFragmentTranslation("lovelace");
|
||||||
this._loadConfig();
|
this._setLovelace();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,28 +95,9 @@ class PanelHome extends LitElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _loadConfig() {
|
|
||||||
try {
|
|
||||||
const data = await fetchFrontendSystemData(this.hass.connection, "home");
|
|
||||||
this._config = data || {};
|
|
||||||
} catch (err) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.error("Failed to load favorites:", err);
|
|
||||||
this._config = {};
|
|
||||||
}
|
|
||||||
this._setLovelace();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _setLovelace() {
|
private async _setLovelace() {
|
||||||
const strategyConfig: LovelaceDashboardStrategyConfig = {
|
|
||||||
strategy: {
|
|
||||||
type: "home",
|
|
||||||
favorite_entities: this._config.favorite_entities,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const config = await generateLovelaceDashboardStrategy(
|
const config = await generateLovelaceDashboardStrategy(
|
||||||
strategyConfig,
|
HOME_LOVELACE_CONFIG,
|
||||||
this.hass
|
this.hass
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -142,34 +121,15 @@ class PanelHome extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _setEditMode = () => {
|
private _setEditMode = () => {
|
||||||
showEditHomeDialog(this, {
|
// For now, we just show an alert that edit mode is not supported.
|
||||||
config: this._config,
|
// This will be expanded in the future.
|
||||||
saveConfig: async (config) => {
|
showAlertDialog(this, {
|
||||||
await this._saveConfig(config);
|
title: "Edit mode not available",
|
||||||
},
|
text: "The Home panel does not support edit mode.",
|
||||||
|
confirmText: this.hass.localize("ui.common.ok"),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
private async _saveConfig(config: HomeFrontendSystemData): Promise<void> {
|
|
||||||
try {
|
|
||||||
await saveFrontendSystemData(this.hass.connection, "home", config);
|
|
||||||
this._config = config || {};
|
|
||||||
} catch (err: any) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.error("Failed to save home configuration:", err);
|
|
||||||
showToast(this, {
|
|
||||||
message: this.hass.localize("ui.panel.home.editor.save_failed"),
|
|
||||||
duration: 0,
|
|
||||||
dismissable: true,
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
showToast(this, {
|
|
||||||
message: this.hass.localize("ui.common.successfully_saved"),
|
|
||||||
});
|
|
||||||
this._setLovelace();
|
|
||||||
}
|
|
||||||
|
|
||||||
static readonly styles: CSSResultGroup = css`
|
static readonly styles: CSSResultGroup = css`
|
||||||
:host {
|
:host {
|
||||||
display: block;
|
display: block;
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import "../../components/ha-settings-row";
|
|||||||
import "../../components/ha-switch";
|
import "../../components/ha-switch";
|
||||||
import type { CoreFrontendUserData } from "../../data/frontend";
|
import type { CoreFrontendUserData } from "../../data/frontend";
|
||||||
import { saveFrontendUserData } from "../../data/frontend";
|
import { saveFrontendUserData } from "../../data/frontend";
|
||||||
import { documentationUrl } from "../../util/documentation-url";
|
|
||||||
import type { HomeAssistant } from "../../types";
|
import type { HomeAssistant } from "../../types";
|
||||||
|
|
||||||
@customElement("ha-advanced-mode-row")
|
@customElement("ha-advanced-mode-row")
|
||||||
@@ -32,10 +31,7 @@ class AdvancedModeRow extends LitElement {
|
|||||||
<span slot="description">
|
<span slot="description">
|
||||||
${this.hass.localize("ui.panel.profile.advanced_mode.description")}
|
${this.hass.localize("ui.panel.profile.advanced_mode.description")}
|
||||||
<a
|
<a
|
||||||
href=${documentationUrl(
|
href="https://www.home-assistant.io/blog/2019/07/17/release-96/#advanced-mode"
|
||||||
this.hass,
|
|
||||||
"/blog/2019/07/17/release-96/#advanced-mode"
|
|
||||||
)}
|
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
>${this.hass.localize("ui.panel.profile.advanced_mode.link_promo")}
|
>${this.hass.localize("ui.panel.profile.advanced_mode.link_promo")}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class HaPickDashboardRow extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
const value = this.hass.userData?.default_panel || USE_SYSTEM_VALUE;
|
const value = this.hass.userData?.defaultPanel || USE_SYSTEM_VALUE;
|
||||||
return html`
|
return html`
|
||||||
<ha-settings-row .narrow=${this.narrow}>
|
<ha-settings-row .narrow=${this.narrow}>
|
||||||
<span slot="heading">
|
<span slot="heading">
|
||||||
@@ -84,12 +84,12 @@ class HaPickDashboardRow extends LitElement {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const urlPath = value === USE_SYSTEM_VALUE ? undefined : value;
|
const urlPath = value === USE_SYSTEM_VALUE ? undefined : value;
|
||||||
if (urlPath === this.hass.userData?.default_panel) {
|
if (urlPath === this.hass.userData?.defaultPanel) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
saveFrontendUserData(this.hass.connection, "core", {
|
saveFrontendUserData(this.hass.connection, "core", {
|
||||||
...this.hass.userData,
|
...this.hass.userData,
|
||||||
default_panel: urlPath,
|
defaultPanel: urlPath,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -767,6 +767,9 @@
|
|||||||
"no_match": "No languages found for {term}",
|
"no_match": "No languages found for {term}",
|
||||||
"no_languages": "No languages available"
|
"no_languages": "No languages available"
|
||||||
},
|
},
|
||||||
|
"icon-picker": {
|
||||||
|
"no_match": "No matching icons found"
|
||||||
|
},
|
||||||
"tts-picker": {
|
"tts-picker": {
|
||||||
"tts": "Text-to-speech",
|
"tts": "Text-to-speech",
|
||||||
"none": "None"
|
"none": "None"
|
||||||
@@ -2220,14 +2223,6 @@
|
|||||||
"migrate_to_user_data": "This will change the sidebar on all the devices you are logged in to. To create a sidebar per device, you should use a different user for that device."
|
"migrate_to_user_data": "This will change the sidebar on all the devices you are logged in to. To create a sidebar per device, you should use a different user for that device."
|
||||||
},
|
},
|
||||||
"panel": {
|
"panel": {
|
||||||
"home": {
|
|
||||||
"editor": {
|
|
||||||
"title": "Edit home page",
|
|
||||||
"description": "Configure your home page display preferences.",
|
|
||||||
"favorite_entities_helper": "Display your favorite entities. Home Assistant will still suggest based on commonly used up to 8 slots.",
|
|
||||||
"save_failed": "Failed to save home page configuration"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"my": {
|
"my": {
|
||||||
"not_supported": "This redirect is not supported by your Home Assistant instance. Check the {link} for the supported redirects and the version they where introduced.",
|
"not_supported": "This redirect is not supported by your Home Assistant instance. Check the {link} for the supported redirects and the version they where introduced.",
|
||||||
"component_not_loaded": "This redirect is not supported by your Home Assistant instance. You need the integration {integration} to use this redirect.",
|
"component_not_loaded": "This redirect is not supported by your Home Assistant instance. You need the integration {integration} to use this redirect.",
|
||||||
@@ -3265,10 +3260,7 @@
|
|||||||
"create_helper": "Create helper",
|
"create_helper": "Create helper",
|
||||||
"no_helpers": "Looks like you don't have any helpers yet!",
|
"no_helpers": "Looks like you don't have any helpers yet!",
|
||||||
"search": "Search {number} {number, plural,\n one {helper}\n other {helpers}\n}",
|
"search": "Search {number} {number, plural,\n one {helper}\n other {helpers}\n}",
|
||||||
"error_information": "Error information",
|
"error_information": "Error information"
|
||||||
"delete_confirm_title": "Delete helper?",
|
|
||||||
"delete_confirm_text": "Are you sure you want to delete {name}?",
|
|
||||||
"delete_failed": "Failed to delete helper"
|
|
||||||
},
|
},
|
||||||
"dialog": {
|
"dialog": {
|
||||||
"create": "Create",
|
"create": "Create",
|
||||||
@@ -4796,8 +4788,7 @@
|
|||||||
"headers": {
|
"headers": {
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"type": "Type",
|
"type": "Type",
|
||||||
"file_name": "File name",
|
"file_name": "File name"
|
||||||
"usage_count": "In use"
|
|
||||||
},
|
},
|
||||||
"types": {
|
"types": {
|
||||||
"automation": "Automation",
|
"automation": "Automation",
|
||||||
|
|||||||
Reference in New Issue
Block a user