mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-19 23:36:36 +00:00
commit
f6d6fd179f
8
.github/dependabot.yml
vendored
Normal file
8
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: weekly
|
||||||
|
time: "06:00"
|
||||||
|
open-pull-requests-limit: 10
|
16
.github/workflows/ci.yaml
vendored
16
.github/workflows/ci.yaml
vendored
@ -19,9 +19,9 @@ 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@v2
|
uses: actions/checkout@v3
|
||||||
- name: Set up Node ${{ env.NODE_VERSION }}
|
- name: Set up Node ${{ env.NODE_VERSION }}
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
cache: yarn
|
cache: yarn
|
||||||
@ -43,9 +43,9 @@ 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@v2
|
uses: actions/checkout@v3
|
||||||
- name: Set up Node ${{ env.NODE_VERSION }}
|
- name: Set up Node ${{ env.NODE_VERSION }}
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
cache: yarn
|
cache: yarn
|
||||||
@ -62,9 +62,9 @@ jobs:
|
|||||||
needs: [lint, test]
|
needs: [lint, test]
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
- name: Set up Node ${{ env.NODE_VERSION }}
|
- name: Set up Node ${{ env.NODE_VERSION }}
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
cache: yarn
|
cache: yarn
|
||||||
@ -81,9 +81,9 @@ jobs:
|
|||||||
needs: [lint, test]
|
needs: [lint, test]
|
||||||
steps:
|
steps:
|
||||||
- name: Check out files from GitHub
|
- name: Check out files from GitHub
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
- name: Set up Node ${{ env.NODE_VERSION }}
|
- name: Set up Node ${{ env.NODE_VERSION }}
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
cache: yarn
|
cache: yarn
|
||||||
|
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@v2
|
uses: actions/checkout@v3
|
||||||
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@v1
|
uses: github/codeql-action/init@v2
|
||||||
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@v1
|
uses: github/codeql-action/autobuild@v2
|
||||||
|
|
||||||
# ℹ️ 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@v1
|
uses: github/codeql-action/analyze@v2
|
||||||
|
4
.github/workflows/demo.yaml
vendored
4
.github/workflows/demo.yaml
vendored
@ -14,9 +14,9 @@ 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@v2
|
uses: actions/checkout@v3
|
||||||
- name: Set up Node ${{ env.NODE_VERSION }}
|
- name: Set up Node ${{ env.NODE_VERSION }}
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
cache: yarn
|
cache: yarn
|
||||||
|
2
.github/workflows/lock.yml
vendored
2
.github/workflows/lock.yml
vendored
@ -9,7 +9,7 @@ jobs:
|
|||||||
lock:
|
lock:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: dessant/lock-threads@v2.0.1
|
- uses: dessant/lock-threads@v3.0.0
|
||||||
with:
|
with:
|
||||||
github-token: ${{ github.token }}
|
github-token: ${{ github.token }}
|
||||||
issue-lock-inactive-days: "30"
|
issue-lock-inactive-days: "30"
|
||||||
|
63
.github/workflows/nightly.yaml
vendored
Normal file
63
.github/workflows/nightly.yaml
vendored
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
name: Nightly
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: "0 1 * * *"
|
||||||
|
|
||||||
|
env:
|
||||||
|
PYTHON_VERSION: 3.8
|
||||||
|
NODE_VERSION: 14
|
||||||
|
NODE_OPTIONS: --max_old_space_size=6144
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
actions: none
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
nightly:
|
||||||
|
name: Nightly
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- name: Checkout the repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Set up Python ${{ env.PYTHON_VERSION }}
|
||||||
|
uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: ${{ env.PYTHON_VERSION }}
|
||||||
|
|
||||||
|
- name: Set up Node ${{ env.NODE_VERSION }}
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
|
cache: yarn
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: yarn install
|
||||||
|
|
||||||
|
- name: Download translations
|
||||||
|
run: ./script/translations_download
|
||||||
|
env:
|
||||||
|
LOKALISE_TOKEN: ${{ secrets.LOKALISE_TOKEN }}
|
||||||
|
|
||||||
|
- name: Bump version
|
||||||
|
run: script/version_bump.js nightly
|
||||||
|
|
||||||
|
- name: Build nightly Python wheels
|
||||||
|
run: |
|
||||||
|
pip install build
|
||||||
|
yarn install
|
||||||
|
|
||||||
|
script/build_frontend
|
||||||
|
|
||||||
|
rm -rf dist home_assistant_frontend.egg-info
|
||||||
|
python3 -m build
|
||||||
|
|
||||||
|
- name: Upload build artifacts
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: wheels
|
||||||
|
path: dist/home_assistant_frontend*.whl
|
||||||
|
if-no-files-found: error
|
6
.github/workflows/release.yaml
vendored
6
.github/workflows/release.yaml
vendored
@ -24,18 +24,18 @@ 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@v2
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Verify version
|
- name: Verify version
|
||||||
uses: home-assistant/actions/helpers/verify-version@master
|
uses: home-assistant/actions/helpers/verify-version@master
|
||||||
|
|
||||||
- name: Set up Python ${{ env.PYTHON_VERSION }}
|
- name: Set up Python ${{ env.PYTHON_VERSION }}
|
||||||
uses: actions/setup-python@v2
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
python-version: ${{ env.PYTHON_VERSION }}
|
python-version: ${{ env.PYTHON_VERSION }}
|
||||||
|
|
||||||
- name: Set up Node ${{ env.NODE_VERSION }}
|
- name: Set up Node ${{ env.NODE_VERSION }}
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
cache: yarn
|
cache: yarn
|
||||||
|
2
.github/workflows/translations.yaml
vendored
2
.github/workflows/translations.yaml
vendored
@ -16,7 +16,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout the repository
|
- name: Checkout the repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Upload Translations
|
- name: Upload Translations
|
||||||
run: |
|
run: |
|
||||||
|
@ -27,7 +27,7 @@ module.exports = {
|
|||||||
version() {
|
version() {
|
||||||
const version = fs
|
const version = fs
|
||||||
.readFileSync(path.resolve(paths.polymer_dir, "pyproject.toml"), "utf8")
|
.readFileSync(path.resolve(paths.polymer_dir, "pyproject.toml"), "utf8")
|
||||||
.match(/version\W+=\W"(\d{8}\.\d)"/);
|
.match(/version\W+=\W"(\d{8}\.\d(?:\.dev)?)"/);
|
||||||
if (!version) {
|
if (!version) {
|
||||||
throw Error("Version not found");
|
throw Error("Version not found");
|
||||||
}
|
}
|
||||||
|
@ -797,7 +797,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
|
|||||||
attributes: {
|
attributes: {
|
||||||
battery_level: 34,
|
battery_level: 34,
|
||||||
on: true,
|
on: true,
|
||||||
friendly_name: "altan_motion_sensor",
|
friendly_name: "Porch motion sensor",
|
||||||
device_class: "motion",
|
device_class: "motion",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -818,7 +818,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
|
|||||||
attributes: {
|
attributes: {
|
||||||
battery_level: 74,
|
battery_level: 74,
|
||||||
on: true,
|
on: true,
|
||||||
friendly_name: "badrumssensor",
|
friendly_name: "Bathroom motion sensor",
|
||||||
device_class: "motion",
|
device_class: "motion",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -829,7 +829,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
|
|||||||
battery_level: 47,
|
battery_level: 47,
|
||||||
on: true,
|
on: true,
|
||||||
dark: true,
|
dark: true,
|
||||||
friendly_name: "R\u00f6relsesensor k\u00e4llaren 1",
|
friendly_name: "Basement motion sensor",
|
||||||
device_class: "motion",
|
device_class: "motion",
|
||||||
icon: "mdi:walk",
|
icon: "mdi:walk",
|
||||||
},
|
},
|
||||||
@ -863,7 +863,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
|
|||||||
attributes: {
|
attributes: {
|
||||||
battery_level: 60,
|
battery_level: 60,
|
||||||
on: true,
|
on: true,
|
||||||
friendly_name: "R\u00f6relsesensor skafferiet",
|
friendly_name: "Pantry motion sensor",
|
||||||
device_class: "motion",
|
device_class: "motion",
|
||||||
icon: "mdi:walk",
|
icon: "mdi:walk",
|
||||||
},
|
},
|
||||||
@ -875,7 +875,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
|
|||||||
battery_level: 60,
|
battery_level: 60,
|
||||||
on: true,
|
on: true,
|
||||||
dark: true,
|
dark: true,
|
||||||
friendly_name: "R\u00f6relsesensor k\u00e4llaren 2",
|
friendly_name: "Stair motion sensor",
|
||||||
device_class: "motion",
|
device_class: "motion",
|
||||||
icon: "mdi:walk",
|
icon: "mdi:walk",
|
||||||
},
|
},
|
||||||
@ -887,7 +887,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
|
|||||||
battery_level: 47,
|
battery_level: 47,
|
||||||
on: true,
|
on: true,
|
||||||
dark: true,
|
dark: true,
|
||||||
friendly_name: "B\u00e4nksensor",
|
friendly_name: "Bench sensor",
|
||||||
device_class: "motion",
|
device_class: "motion",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -277,7 +277,7 @@ export const demoLovelaceKernehed: DemoConfig["lovelace"] = () => ({
|
|||||||
],
|
],
|
||||||
show_header_toggle: false,
|
show_header_toggle: false,
|
||||||
type: "entities",
|
type: "entities",
|
||||||
title: "Bandbredd",
|
title: "Bandwidth",
|
||||||
},
|
},
|
||||||
// {
|
// {
|
||||||
// title: "Updater",
|
// title: "Updater",
|
||||||
|
@ -72,8 +72,8 @@
|
|||||||
"@material/mwc-textfield": "0.25.3",
|
"@material/mwc-textfield": "0.25.3",
|
||||||
"@material/mwc-top-app-bar-fixed": "^0.25.3",
|
"@material/mwc-top-app-bar-fixed": "^0.25.3",
|
||||||
"@material/top-app-bar": "14.0.0-canary.261f2db59.0",
|
"@material/top-app-bar": "14.0.0-canary.261f2db59.0",
|
||||||
"@mdi/js": "6.7.96",
|
"@mdi/js": "6.9.96",
|
||||||
"@mdi/svg": "6.7.96",
|
"@mdi/svg": "6.9.96",
|
||||||
"@polymer/app-layout": "^3.1.0",
|
"@polymer/app-layout": "^3.1.0",
|
||||||
"@polymer/iron-flex-layout": "^3.0.1",
|
"@polymer/iron-flex-layout": "^3.0.1",
|
||||||
"@polymer/iron-icon": "^3.0.1",
|
"@polymer/iron-icon": "^3.0.1",
|
||||||
|
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "home-assistant-frontend"
|
name = "home-assistant-frontend"
|
||||||
version = "20220630.0"
|
version = "20220705.0"
|
||||||
license = {text = "Apache-2.0"}
|
license = {text = "Apache-2.0"}
|
||||||
description = "The Home Assistant frontend"
|
description = "The Home Assistant frontend"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
@ -24,10 +24,15 @@ function auto(version) {
|
|||||||
return patch(version);
|
return patch(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function nightly() {
|
||||||
|
return `${today()}.dev`;
|
||||||
|
}
|
||||||
|
|
||||||
const methods = {
|
const methods = {
|
||||||
patch,
|
patch,
|
||||||
today,
|
today,
|
||||||
auto,
|
auto,
|
||||||
|
nightly,
|
||||||
};
|
};
|
||||||
|
|
||||||
async function main(args) {
|
async function main(args) {
|
||||||
@ -57,7 +62,11 @@ async function main(args) {
|
|||||||
console.log("Current version:", version);
|
console.log("Current version:", version);
|
||||||
console.log("New version:", newVersion);
|
console.log("New version:", newVersion);
|
||||||
|
|
||||||
fs.writeFileSync("pyproject.toml", setup.replace(version, newVersion), "utf-8");
|
fs.writeFileSync(
|
||||||
|
"pyproject.toml",
|
||||||
|
setup.replace(version, newVersion),
|
||||||
|
"utf-8"
|
||||||
|
);
|
||||||
|
|
||||||
if (!commit) {
|
if (!commit) {
|
||||||
return;
|
return;
|
||||||
|
@ -186,6 +186,7 @@ class StateHistoryCharts extends LitElement {
|
|||||||
line-height: 60px;
|
line-height: 60px;
|
||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
max-height: var(--history-max-height);
|
max-height: var(--history-max-height);
|
||||||
}
|
}
|
||||||
|
@ -209,7 +209,7 @@ export class HaCodeEditor extends ReactiveElement {
|
|||||||
private _entityCompletions(
|
private _entityCompletions(
|
||||||
context: CompletionContext
|
context: CompletionContext
|
||||||
): CompletionResult | null | Promise<CompletionResult | null> {
|
): CompletionResult | null | Promise<CompletionResult | null> {
|
||||||
const entityWord = context.matchBefore(/[a-z_]{3,}\./);
|
const entityWord = context.matchBefore(/[a-z_]{3,}\.\w*/);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!entityWord ||
|
!entityWord ||
|
||||||
@ -227,7 +227,7 @@ export class HaCodeEditor extends ReactiveElement {
|
|||||||
return {
|
return {
|
||||||
from: Number(entityWord.from),
|
from: Number(entityWord.from),
|
||||||
options: states,
|
options: states,
|
||||||
span: /^\w*.\w*$/,
|
span: /^[a-z_]{3,}\.\w*$/,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,7 +257,7 @@ export class HaCodeEditor extends ReactiveElement {
|
|||||||
private async _mdiCompletions(
|
private async _mdiCompletions(
|
||||||
context: CompletionContext
|
context: CompletionContext
|
||||||
): Promise<CompletionResult | null> {
|
): Promise<CompletionResult | null> {
|
||||||
const match = context.matchBefore(/mdi:/);
|
const match = context.matchBefore(/mdi:\S*/);
|
||||||
|
|
||||||
if (!match || (match.from === match.to && !context.explicit)) {
|
if (!match || (match.from === match.to && !context.explicit)) {
|
||||||
return null;
|
return null;
|
||||||
@ -268,7 +268,7 @@ export class HaCodeEditor extends ReactiveElement {
|
|||||||
return {
|
return {
|
||||||
from: Number(match.from),
|
from: Number(match.from),
|
||||||
options: iconItems,
|
options: iconItems,
|
||||||
span: /^\w*.\w*$/,
|
span: /^mdi:\S*$/,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,8 +42,8 @@ import "./entity/ha-entity-picker";
|
|||||||
import type { HaEntityPickerEntityFilterFunc } from "./entity/ha-entity-picker";
|
import type { HaEntityPickerEntityFilterFunc } from "./entity/ha-entity-picker";
|
||||||
import "./ha-area-picker";
|
import "./ha-area-picker";
|
||||||
import "./ha-icon-button";
|
import "./ha-icon-button";
|
||||||
import "./ha-svg-icon";
|
|
||||||
import "./ha-input-helper-text";
|
import "./ha-input-helper-text";
|
||||||
|
import "./ha-svg-icon";
|
||||||
|
|
||||||
@customElement("ha-target-picker")
|
@customElement("ha-target-picker")
|
||||||
export class HaTargetPicker extends SubscribeMixin(LitElement) {
|
export class HaTargetPicker extends SubscribeMixin(LitElement) {
|
||||||
@ -119,15 +119,26 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
|
|||||||
if (!this._areas || !this._devices || !this._entities) {
|
if (!this._areas || !this._devices || !this._entities) {
|
||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
return html`<div class=${this.horizontal ? "horizontal-container" : ""}>
|
return html`
|
||||||
${this.horizontal ? this._renderChips() : this._renderItems()}
|
${this.horizontal
|
||||||
${this._renderPicker()}
|
? html`
|
||||||
${this.horizontal ? this._renderItems() : this._renderChips()}
|
<div class="horizontal-container">
|
||||||
</div>`;
|
${this._renderChips()} ${this._renderPicker()}
|
||||||
|
</div>
|
||||||
|
${this._renderItems()}
|
||||||
|
`
|
||||||
|
: html`
|
||||||
|
<div>
|
||||||
|
${this._renderItems()} ${this._renderPicker()}
|
||||||
|
${this._renderChips()}
|
||||||
|
</div>
|
||||||
|
`}
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _renderItems() {
|
private _renderItems() {
|
||||||
return html`<div class="mdc-chip-set items">
|
return html`
|
||||||
|
<div class="mdc-chip-set items">
|
||||||
${this.value?.area_id
|
${this.value?.area_id
|
||||||
? ensureArray(this.value.area_id).map((area_id) => {
|
? ensureArray(this.value.area_id).map((area_id) => {
|
||||||
const area = this._areas![area_id];
|
const area = this._areas![area_id];
|
||||||
@ -163,11 +174,13 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
|
|||||||
);
|
);
|
||||||
})
|
})
|
||||||
: ""}
|
: ""}
|
||||||
</div>`;
|
</div>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _renderChips() {
|
private _renderChips() {
|
||||||
return html`<div class="mdc-chip-set">
|
return html`
|
||||||
|
<div class="mdc-chip-set">
|
||||||
<div
|
<div
|
||||||
class="mdc-chip area_id add"
|
class="mdc-chip area_id add"
|
||||||
.type=${"area_id"}
|
.type=${"area_id"}
|
||||||
@ -231,7 +244,8 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
|
|||||||
</div>
|
</div>
|
||||||
${this.helper
|
${this.helper
|
||||||
? html`<ha-input-helper-text>${this.helper}</ha-input-helper-text>`
|
? html`<ha-input-helper-text>${this.helper}</ha-input-helper-text>`
|
||||||
: ""} `;
|
: ""}
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _showPicker(ev) {
|
private async _showPicker(ev) {
|
||||||
@ -320,7 +334,8 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
|
|||||||
private _renderPicker() {
|
private _renderPicker() {
|
||||||
switch (this._addMode) {
|
switch (this._addMode) {
|
||||||
case "area_id":
|
case "area_id":
|
||||||
return html`<ha-area-picker
|
return html`
|
||||||
|
<ha-area-picker
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
id="input"
|
id="input"
|
||||||
.type=${"area_id"}
|
.type=${"area_id"}
|
||||||
@ -332,11 +347,12 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
|
|||||||
.entityFilter=${this.entityRegFilter}
|
.entityFilter=${this.entityRegFilter}
|
||||||
.includeDeviceClasses=${this.includeDeviceClasses}
|
.includeDeviceClasses=${this.includeDeviceClasses}
|
||||||
.includeDomains=${this.includeDomains}
|
.includeDomains=${this.includeDomains}
|
||||||
class=${this.horizontal ? "hidden-picker" : ""}
|
|
||||||
@value-changed=${this._targetPicked}
|
@value-changed=${this._targetPicked}
|
||||||
></ha-area-picker>`;
|
></ha-area-picker>
|
||||||
|
`;
|
||||||
case "device_id":
|
case "device_id":
|
||||||
return html`<ha-device-picker
|
return html`
|
||||||
|
<ha-device-picker
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
id="input"
|
id="input"
|
||||||
.type=${"device_id"}
|
.type=${"device_id"}
|
||||||
@ -347,11 +363,12 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
|
|||||||
.entityFilter=${this.entityRegFilter}
|
.entityFilter=${this.entityRegFilter}
|
||||||
.includeDeviceClasses=${this.includeDeviceClasses}
|
.includeDeviceClasses=${this.includeDeviceClasses}
|
||||||
.includeDomains=${this.includeDomains}
|
.includeDomains=${this.includeDomains}
|
||||||
class=${this.horizontal ? "hidden-picker" : ""}
|
|
||||||
@value-changed=${this._targetPicked}
|
@value-changed=${this._targetPicked}
|
||||||
></ha-device-picker>`;
|
></ha-device-picker>
|
||||||
|
`;
|
||||||
case "entity_id":
|
case "entity_id":
|
||||||
return html`<ha-entity-picker
|
return html`
|
||||||
|
<ha-entity-picker
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
id="input"
|
id="input"
|
||||||
.type=${"entity_id"}
|
.type=${"entity_id"}
|
||||||
@ -361,10 +378,10 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
|
|||||||
.entityFilter=${this.entityFilter}
|
.entityFilter=${this.entityFilter}
|
||||||
.includeDeviceClasses=${this.includeDeviceClasses}
|
.includeDeviceClasses=${this.includeDeviceClasses}
|
||||||
.includeDomains=${this.includeDomains}
|
.includeDomains=${this.includeDomains}
|
||||||
class=${this.horizontal ? "hidden-picker" : ""}
|
|
||||||
@value-changed=${this._targetPicked}
|
@value-changed=${this._targetPicked}
|
||||||
allow-custom-entity
|
allow-custom-entity
|
||||||
></ha-entity-picker>`;
|
></ha-entity-picker>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
@ -553,15 +570,11 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
|
|||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
return css`
|
return css`
|
||||||
${unsafeCSS(chipStyles)}
|
${unsafeCSS(chipStyles)}
|
||||||
.hidden-picker {
|
|
||||||
height: 0px;
|
|
||||||
display: inline-block;
|
|
||||||
overflow: hidden;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
.horizontal-container {
|
.horizontal-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
min-height: 56px;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
.mdc-chip {
|
.mdc-chip {
|
||||||
color: var(--primary-text-color);
|
color: var(--primary-text-color);
|
||||||
|
@ -124,7 +124,6 @@ class HaOnboarding extends litLocalizeLiteMixin(HassElement) {
|
|||||||
protected firstUpdated(changedProps: PropertyValues) {
|
protected firstUpdated(changedProps: PropertyValues) {
|
||||||
super.firstUpdated(changedProps);
|
super.firstUpdated(changedProps);
|
||||||
this._fetchOnboardingSteps();
|
this._fetchOnboardingSteps();
|
||||||
this._fetchInstallationType();
|
|
||||||
import("./onboarding-integrations");
|
import("./onboarding-integrations");
|
||||||
import("./onboarding-core-config");
|
import("./onboarding-core-config");
|
||||||
registerServiceWorker(this, false);
|
registerServiceWorker(this, false);
|
||||||
@ -215,6 +214,9 @@ class HaOnboarding extends litLocalizeLiteMixin(HassElement) {
|
|||||||
});
|
});
|
||||||
history.replaceState(null, "", location.pathname);
|
history.replaceState(null, "", location.pathname);
|
||||||
await this._connectHass(auth);
|
await this._connectHass(auth);
|
||||||
|
} else {
|
||||||
|
// User creating screen needs to know the installation type.
|
||||||
|
this._fetchInstallationType();
|
||||||
}
|
}
|
||||||
|
|
||||||
this._steps = steps;
|
this._steps = steps;
|
||||||
|
@ -378,6 +378,10 @@ class OnboardingCoreConfig extends LitElement {
|
|||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ha-locations-editor {
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
.flex {
|
.flex {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,13 @@ import { HomeAssistant } from "../types";
|
|||||||
import "./action-badge";
|
import "./action-badge";
|
||||||
import "./integration-badge";
|
import "./integration-badge";
|
||||||
|
|
||||||
const HIDDEN_DOMAINS = new Set(["hassio", "met", "radio_browser", "rpi_power"]);
|
const HIDDEN_DOMAINS = new Set([
|
||||||
|
"hassio",
|
||||||
|
"met",
|
||||||
|
"radio_browser",
|
||||||
|
"rpi_power",
|
||||||
|
"sun",
|
||||||
|
]);
|
||||||
|
|
||||||
@customElement("onboarding-integrations")
|
@customElement("onboarding-integrations")
|
||||||
class OnboardingIntegrations extends LitElement {
|
class OnboardingIntegrations extends LitElement {
|
||||||
@ -75,7 +81,10 @@ class OnboardingIntegrations extends LitElement {
|
|||||||
// Render discovered and existing entries together sorted by localized title.
|
// Render discovered and existing entries together sorted by localized title.
|
||||||
const entries: Array<[string, TemplateResult]> = this._entries.map(
|
const entries: Array<[string, TemplateResult]> = this._entries.map(
|
||||||
(entry) => {
|
(entry) => {
|
||||||
const title = domainToName(this.hass.localize, entry.domain);
|
const title =
|
||||||
|
entry.title ||
|
||||||
|
domainToName(this.hass.localize, entry.domain) ||
|
||||||
|
entry.domain;
|
||||||
return [
|
return [
|
||||||
title,
|
title,
|
||||||
html`
|
html`
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
import "@material/mwc-button";
|
import "@material/mwc-button";
|
||||||
import type { ActionDetail } from "@material/mwc-list";
|
|
||||||
import "@material/mwc-list/mwc-list-item";
|
import "@material/mwc-list/mwc-list-item";
|
||||||
import { mdiDotsVertical } from "@mdi/js";
|
|
||||||
import "@polymer/paper-item/paper-item-body";
|
import "@polymer/paper-item/paper-item-body";
|
||||||
import { css, html, LitElement, PropertyValues } from "lit";
|
import { css, html, LitElement, PropertyValues } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
@ -11,9 +9,7 @@ import { computeRTLDirection } from "../../../../common/util/compute_rtl";
|
|||||||
import { debounce } from "../../../../common/util/debounce";
|
import { debounce } from "../../../../common/util/debounce";
|
||||||
import "../../../../components/buttons/ha-call-api-button";
|
import "../../../../components/buttons/ha-call-api-button";
|
||||||
import "../../../../components/ha-alert";
|
import "../../../../components/ha-alert";
|
||||||
import "../../../../components/ha-button-menu";
|
|
||||||
import "../../../../components/ha-card";
|
import "../../../../components/ha-card";
|
||||||
import "../../../../components/ha-icon-button";
|
|
||||||
import {
|
import {
|
||||||
cloudLogout,
|
cloudLogout,
|
||||||
CloudStatusLoggedIn,
|
CloudStatusLoggedIn,
|
||||||
@ -23,6 +19,7 @@ import {
|
|||||||
import { showConfirmationDialog } from "../../../../dialogs/generic/show-dialog-box";
|
import { showConfirmationDialog } from "../../../../dialogs/generic/show-dialog-box";
|
||||||
import "../../../../layouts/hass-subpage";
|
import "../../../../layouts/hass-subpage";
|
||||||
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
|
||||||
|
import { haStyle } from "../../../../resources/styles";
|
||||||
import { HomeAssistant } from "../../../../types";
|
import { HomeAssistant } from "../../../../types";
|
||||||
import "../../ha-config-section";
|
import "../../ha-config-section";
|
||||||
import "./cloud-alexa-pref";
|
import "./cloud-alexa-pref";
|
||||||
@ -52,23 +49,6 @@ export class CloudAccount extends SubscribeMixin(LitElement) {
|
|||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
header="Home Assistant Cloud"
|
header="Home Assistant Cloud"
|
||||||
>
|
>
|
||||||
<ha-button-menu
|
|
||||||
slot="toolbar-icon"
|
|
||||||
corner="BOTTOM_START"
|
|
||||||
@action=${this._handleMenuAction}
|
|
||||||
activatable
|
|
||||||
>
|
|
||||||
<ha-icon-button
|
|
||||||
slot="trigger"
|
|
||||||
.label=${this.hass.localize("ui.common.menu")}
|
|
||||||
.path=${mdiDotsVertical}
|
|
||||||
></ha-icon-button>
|
|
||||||
|
|
||||||
<mwc-list-item>
|
|
||||||
${this.hass.localize("ui.panel.config.cloud.account.sign_out")}
|
|
||||||
</mwc-list-item>
|
|
||||||
</ha-button-menu>
|
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<ha-config-section .isWide=${this.isWide}>
|
<ha-config-section .isWide=${this.isWide}>
|
||||||
<span slot="header">Home Assistant Cloud</span>
|
<span slot="header">Home Assistant Cloud</span>
|
||||||
@ -156,6 +136,11 @@ export class CloudAccount extends SubscribeMixin(LitElement) {
|
|||||||
)}
|
)}
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
</a>
|
</a>
|
||||||
|
<mwc-button @click=${this._signOut} class="warning">
|
||||||
|
${this.hass.localize(
|
||||||
|
"ui.panel.config.cloud.account.sign_out"
|
||||||
|
)}
|
||||||
|
</mwc-button>
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
</ha-config-section>
|
</ha-config-section>
|
||||||
@ -279,9 +264,7 @@ export class CloudAccount extends SubscribeMixin(LitElement) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _handleMenuAction(ev: CustomEvent<ActionDetail>) {
|
private async _signOut() {
|
||||||
switch (ev.detail.index) {
|
|
||||||
case 0:
|
|
||||||
showConfirmationDialog(this, {
|
showConfirmationDialog(this, {
|
||||||
text: this.hass.localize(
|
text: this.hass.localize(
|
||||||
"ui.panel.config.cloud.account.sign_out_confirm"
|
"ui.panel.config.cloud.account.sign_out_confirm"
|
||||||
@ -291,7 +274,6 @@ export class CloudAccount extends SubscribeMixin(LitElement) {
|
|||||||
confirm: () => this._logoutFromCloud(),
|
confirm: () => this._logoutFromCloud(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private async _logoutFromCloud() {
|
private async _logoutFromCloud() {
|
||||||
await cloudLogout(this.hass);
|
await cloudLogout(this.hass);
|
||||||
@ -303,7 +285,9 @@ export class CloudAccount extends SubscribeMixin(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return css`
|
return [
|
||||||
|
haStyle,
|
||||||
|
css`
|
||||||
[slot="introduction"] {
|
[slot="introduction"] {
|
||||||
margin: -1em 0;
|
margin: -1em 0;
|
||||||
}
|
}
|
||||||
@ -320,9 +304,7 @@ export class CloudAccount extends SubscribeMixin(LitElement) {
|
|||||||
.card-actions {
|
.card-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row-reverse;
|
flex-direction: row-reverse;
|
||||||
}
|
justify-content: space-between;
|
||||||
.card-actions a {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
}
|
||||||
mwc-button {
|
mwc-button {
|
||||||
align-self: center;
|
align-self: center;
|
||||||
@ -334,10 +316,8 @@ export class CloudAccount extends SubscribeMixin(LitElement) {
|
|||||||
text-transform: capitalize;
|
text-transform: capitalize;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
a {
|
`,
|
||||||
color: var(--primary-color);
|
];
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,6 +185,10 @@ export class CloudTTSPref extends LitElement {
|
|||||||
right: auto;
|
right: auto;
|
||||||
left: 24px;
|
left: 24px;
|
||||||
}
|
}
|
||||||
|
.card-actions {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ import { getConfigEntries } from "../../../../../../data/config_entries";
|
|||||||
import { DeviceRegistryEntry } from "../../../../../../data/device_registry";
|
import { DeviceRegistryEntry } from "../../../../../../data/device_registry";
|
||||||
import {
|
import {
|
||||||
fetchZwaveIsAnyFirmwareUpdateInProgress,
|
fetchZwaveIsAnyFirmwareUpdateInProgress,
|
||||||
fetchZwaveNodeFirmwareUpdateCapabilities,
|
|
||||||
fetchZwaveNodeIsFirmwareUpdateInProgress,
|
fetchZwaveNodeIsFirmwareUpdateInProgress,
|
||||||
fetchZwaveNodeStatus,
|
fetchZwaveNodeStatus,
|
||||||
} from "../../../../../../data/zwave_js";
|
} from "../../../../../../data/zwave_js";
|
||||||
@ -87,20 +86,13 @@ export const getZwaveDeviceActions = async (
|
|||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [
|
const [isAnyFirmwareUpdateInProgress, isNodeFirmwareUpdateInProgress] =
|
||||||
firmwareUpdateCapabilities,
|
await Promise.all([
|
||||||
isAnyFirmwareUpdateInProgress,
|
|
||||||
isNodeFirmwareUpdateInProgress,
|
|
||||||
] = await Promise.all([
|
|
||||||
fetchZwaveNodeFirmwareUpdateCapabilities(hass, device.id),
|
|
||||||
fetchZwaveIsAnyFirmwareUpdateInProgress(hass, entryId),
|
fetchZwaveIsAnyFirmwareUpdateInProgress(hass, entryId),
|
||||||
fetchZwaveNodeIsFirmwareUpdateInProgress(hass, device.id),
|
fetchZwaveNodeIsFirmwareUpdateInProgress(hass, device.id),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (
|
if (!isAnyFirmwareUpdateInProgress || isNodeFirmwareUpdateInProgress) {
|
||||||
firmwareUpdateCapabilities.firmware_upgradable &&
|
|
||||||
(!isAnyFirmwareUpdateInProgress || isNodeFirmwareUpdateInProgress)
|
|
||||||
) {
|
|
||||||
actions.push({
|
actions.push({
|
||||||
label: hass.localize(
|
label: hass.localize(
|
||||||
"ui.panel.config.zwave_js.device_info.update_firmware"
|
"ui.panel.config.zwave_js.device_info.update_firmware"
|
||||||
@ -117,7 +109,6 @@ export const getZwaveDeviceActions = async (
|
|||||||
) {
|
) {
|
||||||
showZWaveJUpdateFirmwareNodeDialog(el, {
|
showZWaveJUpdateFirmwareNodeDialog(el, {
|
||||||
device,
|
device,
|
||||||
firmwareUpdateCapabilities,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -165,13 +165,6 @@ class HaConfigInfo extends LitElement {
|
|||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
</mwc-list>
|
</mwc-list>
|
||||||
<p class="config-path">
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.info.path_configuration",
|
|
||||||
"path",
|
|
||||||
hass.config.config_dir
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
${!customUiList.length
|
${!customUiList.length
|
||||||
? ""
|
? ""
|
||||||
: html`
|
: html`
|
||||||
@ -202,7 +195,7 @@ class HaConfigInfo extends LitElement {
|
|||||||
if (((window as any).CUSTOM_UI_LIST || []).length !== customUI.length) {
|
if (((window as any).CUSTOM_UI_LIST || []).length !== customUI.length) {
|
||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 2000);
|
||||||
|
|
||||||
if (isComponentLoaded(this.hass, "hassio")) {
|
if (isComponentLoaded(this.hass, "hassio")) {
|
||||||
this._loadSupervisorInfo();
|
this._loadSupervisorInfo();
|
||||||
@ -291,12 +284,6 @@ class HaConfigInfo extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.config-path {
|
|
||||||
color: var(--secondary-text-color);
|
|
||||||
text-align: center;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-ui {
|
.custom-ui {
|
||||||
color: var(--secondary-text-color);
|
color: var(--secondary-text-color);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -766,7 +766,6 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-right: 8px;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 56px;
|
height: 56px;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
|
@ -6,7 +6,6 @@ import "@material/mwc-linear-progress/mwc-linear-progress";
|
|||||||
import { mdiCheckCircle, mdiCloseCircle, mdiFileUpload } from "@mdi/js";
|
import { mdiCheckCircle, mdiCloseCircle, mdiFileUpload } from "@mdi/js";
|
||||||
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
import memoizeOne from "memoize-one";
|
|
||||||
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
import { UnsubscribeFunc } from "home-assistant-js-websocket";
|
||||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||||
import { createCloseHeading } from "../../../../../components/ha-dialog";
|
import { createCloseHeading } from "../../../../../components/ha-dialog";
|
||||||
@ -26,7 +25,6 @@ import {
|
|||||||
ZWaveJSNodeFirmwareUpdateFinishedMessage,
|
ZWaveJSNodeFirmwareUpdateFinishedMessage,
|
||||||
ZWaveJSNodeFirmwareUpdateProgressMessage,
|
ZWaveJSNodeFirmwareUpdateProgressMessage,
|
||||||
ZWaveJSNodeStatusUpdatedMessage,
|
ZWaveJSNodeStatusUpdatedMessage,
|
||||||
ZWaveJSNodeFirmwareUpdateCapabilities,
|
|
||||||
ZWaveJSNodeStatus,
|
ZWaveJSNodeStatus,
|
||||||
} from "../../../../../data/zwave_js";
|
} from "../../../../../data/zwave_js";
|
||||||
import { haStyleDialog } from "../../../../../resources/styles";
|
import { haStyleDialog } from "../../../../../resources/styles";
|
||||||
@ -66,12 +64,9 @@ class DialogZWaveJSUpdateFirmwareNode extends LitElement {
|
|||||||
|
|
||||||
private _deviceName?: string;
|
private _deviceName?: string;
|
||||||
|
|
||||||
private _firmwareUpdateCapabilities?: ZWaveJSNodeFirmwareUpdateCapabilities;
|
|
||||||
|
|
||||||
public showDialog(params: ZWaveJSUpdateFirmwareNodeDialogParams): void {
|
public showDialog(params: ZWaveJSUpdateFirmwareNodeDialogParams): void {
|
||||||
this._deviceName = computeDeviceName(params.device, this.hass!);
|
this._deviceName = computeDeviceName(params.device, this.hass!);
|
||||||
this.device = params.device;
|
this.device = params.device;
|
||||||
this._firmwareUpdateCapabilities = params.firmwareUpdateCapabilities;
|
|
||||||
this._fetchData();
|
this._fetchData();
|
||||||
this._subscribeNodeStatus();
|
this._subscribeNodeStatus();
|
||||||
}
|
}
|
||||||
@ -84,7 +79,6 @@ class DialogZWaveJSUpdateFirmwareNode extends LitElement {
|
|||||||
this._updateFinishedMessage =
|
this._updateFinishedMessage =
|
||||||
this._firmwareFile =
|
this._firmwareFile =
|
||||||
this._nodeStatus =
|
this._nodeStatus =
|
||||||
this._firmwareUpdateCapabilities =
|
|
||||||
undefined;
|
undefined;
|
||||||
this._firmwareTarget = 0;
|
this._firmwareTarget = 0;
|
||||||
this._uploading = this._updateInProgress = false;
|
this._uploading = this._updateInProgress = false;
|
||||||
@ -92,34 +86,21 @@ class DialogZWaveJSUpdateFirmwareNode extends LitElement {
|
|||||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||||
}
|
}
|
||||||
|
|
||||||
private _schema = memoizeOne(
|
|
||||||
(
|
|
||||||
firmwareUpdateCapabilities: ZWaveJSNodeFirmwareUpdateCapabilities
|
|
||||||
): HaFormIntegerSchema => {
|
|
||||||
if (!firmwareUpdateCapabilities.firmware_upgradable) {
|
|
||||||
// We should never get here, this is to pass type checks
|
|
||||||
throw new Error();
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
name: "firmware_target",
|
|
||||||
type: "integer",
|
|
||||||
valueMin: Math.min(...firmwareUpdateCapabilities.firmware_targets),
|
|
||||||
valueMax: Math.max(...firmwareUpdateCapabilities.firmware_targets),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
if (
|
if (
|
||||||
!this.device ||
|
!this.device ||
|
||||||
!this._nodeStatus ||
|
!this._nodeStatus ||
|
||||||
!this._firmwareUpdateCapabilities ||
|
|
||||||
!this._firmwareUpdateCapabilities.firmware_upgradable ||
|
|
||||||
this._updateInProgress === undefined
|
this._updateInProgress === undefined
|
||||||
) {
|
) {
|
||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const schema: HaFormIntegerSchema = {
|
||||||
|
name: "firmware_target",
|
||||||
|
type: "integer",
|
||||||
|
valueMin: 0,
|
||||||
|
};
|
||||||
|
|
||||||
const beginFirmwareUpdateHTML = html`<ha-file-upload
|
const beginFirmwareUpdateHTML = html`<ha-file-upload
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.uploading=${this._uploading}
|
.uploading=${this._uploading}
|
||||||
@ -130,8 +111,7 @@ class DialogZWaveJSUpdateFirmwareNode extends LitElement {
|
|||||||
)}
|
)}
|
||||||
@file-picked=${this._uploadFile}
|
@file-picked=${this._uploadFile}
|
||||||
></ha-file-upload>
|
></ha-file-upload>
|
||||||
${this._firmwareUpdateCapabilities.firmware_targets.length > 1
|
<p>
|
||||||
? html`<p>
|
|
||||||
${this.hass.localize(
|
${this.hass.localize(
|
||||||
"ui.panel.config.zwave_js.update_firmware.firmware_target_intro"
|
"ui.panel.config.zwave_js.update_firmware.firmware_target_intro"
|
||||||
)}
|
)}
|
||||||
@ -139,10 +119,9 @@ class DialogZWaveJSUpdateFirmwareNode extends LitElement {
|
|||||||
<ha-form
|
<ha-form
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.data=${{ firmware_target: this._firmwareTarget }}
|
.data=${{ firmware_target: this._firmwareTarget }}
|
||||||
.schema=${[this._schema(this._firmwareUpdateCapabilities)]}
|
.schema=${[schema]}
|
||||||
@value-changed=${this._firmwareTargetChanged}
|
@value-changed=${this._firmwareTargetChanged}
|
||||||
></ha-form>`
|
></ha-form>
|
||||||
: ""}
|
|
||||||
<mwc-button
|
<mwc-button
|
||||||
slot="primaryAction"
|
slot="primaryAction"
|
||||||
@click=${this._beginFirmwareUpdate}
|
@click=${this._beginFirmwareUpdate}
|
||||||
@ -285,12 +264,6 @@ class DialogZWaveJSUpdateFirmwareNode extends LitElement {
|
|||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
${beginFirmwareUpdateHTML}`}
|
${beginFirmwareUpdateHTML}`}
|
||||||
<p>
|
|
||||||
${this.hass.localize(
|
|
||||||
"ui.panel.config.zwave_js.update_firmware.finished_status.try_again"
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
${beginFirmwareUpdateHTML}
|
|
||||||
`}
|
`}
|
||||||
</ha-dialog>
|
</ha-dialog>
|
||||||
`;
|
`;
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
import { fireEvent } from "../../../../../common/dom/fire_event";
|
import { fireEvent } from "../../../../../common/dom/fire_event";
|
||||||
import { DeviceRegistryEntry } from "../../../../../data/device_registry";
|
import { DeviceRegistryEntry } from "../../../../../data/device_registry";
|
||||||
import { ZWaveJSNodeFirmwareUpdateCapabilities } from "../../../../../data/zwave_js";
|
|
||||||
|
|
||||||
export interface ZWaveJSUpdateFirmwareNodeDialogParams {
|
export interface ZWaveJSUpdateFirmwareNodeDialogParams {
|
||||||
device: DeviceRegistryEntry;
|
device: DeviceRegistryEntry;
|
||||||
firmwareUpdateCapabilities: ZWaveJSNodeFirmwareUpdateCapabilities;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const loadUpdateFirmwareNodeDialog = () =>
|
export const loadUpdateFirmwareNodeDialog = () =>
|
||||||
|
@ -107,6 +107,8 @@ export class HaSceneEditor extends SubscribeMixin(
|
|||||||
|
|
||||||
@state() private _entities: string[] = [];
|
@state() private _entities: string[] = [];
|
||||||
|
|
||||||
|
private _single_entities: string[] = [];
|
||||||
|
|
||||||
@state() private _devices: string[] = [];
|
@state() private _devices: string[] = [];
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
@ -121,7 +123,7 @@ export class HaSceneEditor extends SubscribeMixin(
|
|||||||
|
|
||||||
private _unsubscribeEvents?: () => void;
|
private _unsubscribeEvents?: () => void;
|
||||||
|
|
||||||
@state() private _deviceEntityLookup: DeviceEntitiesLookup = {};
|
private _deviceEntityLookup: DeviceEntitiesLookup = {};
|
||||||
|
|
||||||
private _activateContextId?: string;
|
private _activateContextId?: string;
|
||||||
|
|
||||||
@ -520,9 +522,11 @@ export class HaSceneEditor extends SubscribeMixin(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (changedProps.has("_entityRegistryEntries")) {
|
if (changedProps.has("_entityRegistryEntries")) {
|
||||||
|
this._deviceEntityLookup = {};
|
||||||
for (const entity of this._entityRegistryEntries) {
|
for (const entity of this._entityRegistryEntries) {
|
||||||
if (
|
if (
|
||||||
!entity.device_id ||
|
!entity.device_id ||
|
||||||
|
entity.entity_category ||
|
||||||
SCENE_IGNORED_DOMAINS.includes(computeDomain(entity.entity_id))
|
SCENE_IGNORED_DOMAINS.includes(computeDomain(entity.entity_id))
|
||||||
) {
|
) {
|
||||||
continue;
|
continue;
|
||||||
@ -530,13 +534,10 @@ export class HaSceneEditor extends SubscribeMixin(
|
|||||||
if (!(entity.device_id in this._deviceEntityLookup)) {
|
if (!(entity.device_id in this._deviceEntityLookup)) {
|
||||||
this._deviceEntityLookup[entity.device_id] = [];
|
this._deviceEntityLookup[entity.device_id] = [];
|
||||||
}
|
}
|
||||||
if (
|
|
||||||
!this._deviceEntityLookup[entity.device_id].includes(entity.entity_id)
|
|
||||||
) {
|
|
||||||
this._deviceEntityLookup[entity.device_id].push(entity.entity_id);
|
this._deviceEntityLookup[entity.device_id].push(entity.entity_id);
|
||||||
}
|
|
||||||
if (
|
if (
|
||||||
this._entities.includes(entity.entity_id) &&
|
this._entities.includes(entity.entity_id) &&
|
||||||
|
!this._single_entities.includes(entity.device_id) &&
|
||||||
!this._devices.includes(entity.device_id)
|
!this._devices.includes(entity.device_id)
|
||||||
) {
|
) {
|
||||||
this._devices = [...this._devices, entity.device_id];
|
this._devices = [...this._devices, entity.device_id];
|
||||||
@ -625,12 +626,24 @@ export class HaSceneEditor extends SubscribeMixin(
|
|||||||
private _initEntities(config: SceneConfig) {
|
private _initEntities(config: SceneConfig) {
|
||||||
this._entities = Object.keys(config.entities);
|
this._entities = Object.keys(config.entities);
|
||||||
this._entities.forEach((entity) => this._storeState(entity));
|
this._entities.forEach((entity) => this._storeState(entity));
|
||||||
|
this._single_entities = [];
|
||||||
|
|
||||||
const filteredEntityReg = this._entityRegistryEntries.filter((entityReg) =>
|
const filteredEntityReg = this._entityRegistryEntries.filter((entityReg) =>
|
||||||
this._entities.includes(entityReg.entity_id)
|
this._entities.includes(entityReg.entity_id)
|
||||||
);
|
);
|
||||||
const newDevices: string[] = [];
|
const newDevices: string[] = [];
|
||||||
|
|
||||||
|
if (config.metadata) {
|
||||||
|
Object.keys(config.entities).forEach((entity) => {
|
||||||
|
if (
|
||||||
|
!this._single_entities.includes(entity) &&
|
||||||
|
config.metadata![entity].entity_only
|
||||||
|
) {
|
||||||
|
this._single_entities.push(entity);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
for (const entityReg of filteredEntityReg) {
|
for (const entityReg of filteredEntityReg) {
|
||||||
if (!entityReg.device_id) {
|
if (!entityReg.device_id) {
|
||||||
continue;
|
continue;
|
||||||
@ -654,6 +667,7 @@ export class HaSceneEditor extends SubscribeMixin(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._entities = [...this._entities, entityId];
|
this._entities = [...this._entities, entityId];
|
||||||
|
this._single_entities.push(entityId);
|
||||||
this._storeState(entityId);
|
this._storeState(entityId);
|
||||||
this._dirty = true;
|
this._dirty = true;
|
||||||
}
|
}
|
||||||
@ -664,6 +678,9 @@ export class HaSceneEditor extends SubscribeMixin(
|
|||||||
this._entities = this._entities.filter(
|
this._entities = this._entities.filter(
|
||||||
(entityId) => entityId !== deleteEntityId
|
(entityId) => entityId !== deleteEntityId
|
||||||
);
|
);
|
||||||
|
this._single_entities = this._single_entities.filter(
|
||||||
|
(entityId) => entityId !== deleteEntityId
|
||||||
|
);
|
||||||
this._dirty = true;
|
this._dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -815,19 +832,15 @@ export class HaSceneEditor extends SubscribeMixin(
|
|||||||
private _calculateMetaData(): SceneMetaData {
|
private _calculateMetaData(): SceneMetaData {
|
||||||
const output: SceneMetaData = {};
|
const output: SceneMetaData = {};
|
||||||
|
|
||||||
for (const entityReg of this._entityRegistryEntries) {
|
for (const entityId of this._single_entities) {
|
||||||
if (!this._entities.includes(entityReg.entity_id)) {
|
const entityState = this._getCurrentState(entityId);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const entityState = this._getCurrentState(entityReg.entity_id);
|
|
||||||
|
|
||||||
if (!entityState) {
|
if (!entityState) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
output[entityReg.entity_id] = {
|
output[entityId] = {
|
||||||
entity_only: !this._devices.includes(entityReg.device_id!),
|
entity_only: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { mdiRefresh } from "@mdi/js";
|
import { mdiCollapseAll, mdiRefresh } from "@mdi/js";
|
||||||
import "@polymer/app-layout/app-header/app-header";
|
import "@polymer/app-layout/app-header/app-header";
|
||||||
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
import "@polymer/app-layout/app-toolbar/app-toolbar";
|
||||||
import {
|
import {
|
||||||
@ -10,9 +10,12 @@ import {
|
|||||||
startOfWeek,
|
startOfWeek,
|
||||||
startOfYesterday,
|
startOfYesterday,
|
||||||
} from "date-fns/esm";
|
} from "date-fns/esm";
|
||||||
|
import { UnsubscribeFunc } from "home-assistant-js-websocket/dist/types";
|
||||||
import { css, html, LitElement, PropertyValues } from "lit";
|
import { css, html, LitElement, PropertyValues } from "lit";
|
||||||
import { property, state } from "lit/decorators";
|
import { property, state } from "lit/decorators";
|
||||||
import { UnsubscribeFunc } from "home-assistant-js-websocket/dist/types";
|
import { LocalStorage } from "../../common/decorators/local-storage";
|
||||||
|
import { computeDomain } from "../../common/entity/compute_domain";
|
||||||
|
import { computeStateName } from "../../common/entity/compute_state_name";
|
||||||
import { navigate } from "../../common/navigate";
|
import { navigate } from "../../common/navigate";
|
||||||
import {
|
import {
|
||||||
createSearchParam,
|
createSearchParam,
|
||||||
@ -20,46 +23,62 @@ import {
|
|||||||
} from "../../common/url/search-params";
|
} from "../../common/url/search-params";
|
||||||
import { computeRTL } from "../../common/util/compute_rtl";
|
import { computeRTL } from "../../common/util/compute_rtl";
|
||||||
import "../../components/chart/state-history-charts";
|
import "../../components/chart/state-history-charts";
|
||||||
import "../../components/ha-target-picker";
|
|
||||||
import "../../components/ha-circular-progress";
|
import "../../components/ha-circular-progress";
|
||||||
import "../../components/ha-date-range-picker";
|
import "../../components/ha-date-range-picker";
|
||||||
import type { DateRangePickerRanges } from "../../components/ha-date-range-picker";
|
import type { DateRangePickerRanges } from "../../components/ha-date-range-picker";
|
||||||
import "../../components/ha-icon-button";
|
import "../../components/ha-icon-button";
|
||||||
import "../../components/ha-menu-button";
|
import "../../components/ha-menu-button";
|
||||||
import { computeHistory, fetchDateWS } from "../../data/history";
|
import "../../components/ha-target-picker";
|
||||||
import "../../layouts/ha-app-layout";
|
import {
|
||||||
import { haStyle } from "../../resources/styles";
|
DeviceRegistryEntry,
|
||||||
import { HomeAssistant } from "../../types";
|
subscribeDeviceRegistry,
|
||||||
|
} from "../../data/device_registry";
|
||||||
import {
|
import {
|
||||||
EntityRegistryEntry,
|
EntityRegistryEntry,
|
||||||
subscribeEntityRegistry,
|
subscribeEntityRegistry,
|
||||||
} from "../../data/entity_registry";
|
} from "../../data/entity_registry";
|
||||||
|
import { computeHistory, fetchDateWS } from "../../data/history";
|
||||||
|
import "../../layouts/ha-app-layout";
|
||||||
import { SubscribeMixin } from "../../mixins/subscribe-mixin";
|
import { SubscribeMixin } from "../../mixins/subscribe-mixin";
|
||||||
import { computeStateName } from "../../common/entity/compute_state_name";
|
import { haStyle } from "../../resources/styles";
|
||||||
import { computeDomain } from "../../common/entity/compute_domain";
|
import { HomeAssistant } from "../../types";
|
||||||
|
|
||||||
class HaPanelHistory extends SubscribeMixin(LitElement) {
|
class HaPanelHistory extends SubscribeMixin(LitElement) {
|
||||||
@property() hass!: HomeAssistant;
|
@property({ attribute: false }) hass!: HomeAssistant;
|
||||||
|
|
||||||
@property({ reflect: true, type: Boolean }) narrow!: boolean;
|
@property({ reflect: true, type: Boolean }) narrow!: boolean;
|
||||||
|
|
||||||
@property() _startDate: Date;
|
|
||||||
|
|
||||||
@property() _endDate: Date;
|
|
||||||
|
|
||||||
@property() _targetPickerValue?;
|
|
||||||
|
|
||||||
@property() _isLoading = false;
|
|
||||||
|
|
||||||
@property() _stateHistory?;
|
|
||||||
|
|
||||||
@property({ reflect: true, type: Boolean }) rtl = false;
|
@property({ reflect: true, type: Boolean }) rtl = false;
|
||||||
|
|
||||||
|
@state() private _startDate: Date;
|
||||||
|
|
||||||
|
@state() private _endDate: Date;
|
||||||
|
|
||||||
|
@LocalStorage("historyPickedValue", true, false) private _targetPickerValue?;
|
||||||
|
|
||||||
|
@state() private _isLoading = false;
|
||||||
|
|
||||||
|
@state() private _stateHistory?;
|
||||||
|
|
||||||
@state() private _ranges?: DateRangePickerRanges;
|
@state() private _ranges?: DateRangePickerRanges;
|
||||||
|
|
||||||
@state() private _entities?: EntityRegistryEntry[];
|
@state() private _devices?: { [deviceId: string]: DeviceRegistryEntry };
|
||||||
|
|
||||||
@state() private _stateEntities?: EntityRegistryEntry[];
|
@state() private _entities?: { [entityId: string]: EntityRegistryEntry };
|
||||||
|
|
||||||
|
@state() private _stateEntities?: { [entityId: string]: EntityRegistryEntry };
|
||||||
|
|
||||||
|
@state() private _deviceIdToEntities?: {
|
||||||
|
[deviceId: string]: EntityRegistryEntry[];
|
||||||
|
};
|
||||||
|
|
||||||
|
@state() private _areaIdToEntities?: {
|
||||||
|
[areaId: string]: EntityRegistryEntry[];
|
||||||
|
};
|
||||||
|
|
||||||
|
@state() private _areaIdToDevices?: {
|
||||||
|
[areaId: string]: DeviceRegistryEntry[];
|
||||||
|
};
|
||||||
|
|
||||||
public constructor() {
|
public constructor() {
|
||||||
super();
|
super();
|
||||||
@ -76,7 +95,52 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
|
|||||||
public hassSubscribe(): UnsubscribeFunc[] {
|
public hassSubscribe(): UnsubscribeFunc[] {
|
||||||
return [
|
return [
|
||||||
subscribeEntityRegistry(this.hass.connection!, (entities) => {
|
subscribeEntityRegistry(this.hass.connection!, (entities) => {
|
||||||
this._entities = entities;
|
this._entities = entities.reduce((accumulator, current) => {
|
||||||
|
accumulator[current.entity_id] = current;
|
||||||
|
return accumulator;
|
||||||
|
}, {});
|
||||||
|
this._deviceIdToEntities = entities.reduce((accumulator, current) => {
|
||||||
|
if (!current.device_id) {
|
||||||
|
return accumulator;
|
||||||
|
}
|
||||||
|
let found = accumulator[current.device_id];
|
||||||
|
if (found === undefined) {
|
||||||
|
found = [];
|
||||||
|
accumulator[current.device_id] = found;
|
||||||
|
}
|
||||||
|
found.push(current);
|
||||||
|
return accumulator;
|
||||||
|
}, {});
|
||||||
|
this._areaIdToEntities = entities.reduce((accumulator, current) => {
|
||||||
|
if (!current.area_id) {
|
||||||
|
return accumulator;
|
||||||
|
}
|
||||||
|
let found = accumulator[current.area_id];
|
||||||
|
if (found === undefined) {
|
||||||
|
found = [];
|
||||||
|
accumulator[current.area_id] = found;
|
||||||
|
}
|
||||||
|
found.push(current);
|
||||||
|
return accumulator;
|
||||||
|
}, {});
|
||||||
|
}),
|
||||||
|
subscribeDeviceRegistry(this.hass.connection!, (devices) => {
|
||||||
|
this._devices = devices.reduce((accumulator, current) => {
|
||||||
|
accumulator[current.id] = current;
|
||||||
|
return accumulator;
|
||||||
|
}, {});
|
||||||
|
this._areaIdToDevices = devices.reduce((accumulator, current) => {
|
||||||
|
if (!current.area_id) {
|
||||||
|
return accumulator;
|
||||||
|
}
|
||||||
|
let found = accumulator[current.area_id];
|
||||||
|
if (found === undefined) {
|
||||||
|
found = [];
|
||||||
|
accumulator[current.area_id] = found;
|
||||||
|
}
|
||||||
|
found.push(current);
|
||||||
|
return accumulator;
|
||||||
|
}, {});
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@ -91,8 +155,18 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
|
|||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
></ha-menu-button>
|
></ha-menu-button>
|
||||||
<div main-title>${this.hass.localize("panel.history")}</div>
|
<div main-title>${this.hass.localize("panel.history")}</div>
|
||||||
|
${this._targetPickerValue
|
||||||
|
? html`
|
||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
@click=${this._refreshHistory}
|
@click=${this._removeAll}
|
||||||
|
.disabled=${this._isLoading}
|
||||||
|
.path=${mdiCollapseAll}
|
||||||
|
.label=${this.hass.localize("ui.panel.history.remove_all")}
|
||||||
|
></ha-icon-button>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
<ha-icon-button
|
||||||
|
@click=${this._getHistory}
|
||||||
.disabled=${this._isLoading}
|
.disabled=${this._isLoading}
|
||||||
.path=${mdiRefresh}
|
.path=${mdiRefresh}
|
||||||
.label=${this.hass.localize("ui.common.refresh")}
|
.label=${this.hass.localize("ui.common.refresh")}
|
||||||
@ -125,6 +199,10 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
|
|||||||
alt=${this.hass.localize("ui.common.loading")}
|
alt=${this.hass.localize("ui.common.loading")}
|
||||||
></ha-circular-progress>
|
></ha-circular-progress>
|
||||||
</div>`
|
</div>`
|
||||||
|
: !this._targetPickerValue
|
||||||
|
? html`<div class="start-search">
|
||||||
|
${this.hass.localize("ui.panel.history.start_search")}
|
||||||
|
</div>`
|
||||||
: html`
|
: html`
|
||||||
<state-history-charts
|
<state-history-charts
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
@ -135,24 +213,6 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
|
|||||||
</state-history-charts>
|
</state-history-charts>
|
||||||
`}
|
`}
|
||||||
</div>
|
</div>
|
||||||
${this._isLoading
|
|
||||||
? html`<div class="progress-wrapper">
|
|
||||||
<ha-circular-progress
|
|
||||||
active
|
|
||||||
alt=${this.hass.localize("ui.common.loading")}
|
|
||||||
></ha-circular-progress>
|
|
||||||
</div>`
|
|
||||||
: html`
|
|
||||||
<state-history-charts
|
|
||||||
virtualize
|
|
||||||
.hass=${this.hass}
|
|
||||||
.historyData=${this._stateHistory}
|
|
||||||
.endTime=${this._endDate}
|
|
||||||
.narrow=${this.narrow}
|
|
||||||
no-single
|
|
||||||
>
|
|
||||||
</state-history-charts>
|
|
||||||
`}
|
|
||||||
</ha-app-layout>
|
</ha-app-layout>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@ -197,29 +257,38 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
|
|||||||
|
|
||||||
protected updated(changedProps: PropertyValues) {
|
protected updated(changedProps: PropertyValues) {
|
||||||
if (
|
if (
|
||||||
changedProps.has("_startDate") ||
|
this._targetPickerValue &&
|
||||||
|
(changedProps.has("_startDate") ||
|
||||||
changedProps.has("_endDate") ||
|
changedProps.has("_endDate") ||
|
||||||
changedProps.has("_targetPickerValue") ||
|
changedProps.has("_targetPickerValue") ||
|
||||||
changedProps.has("_entities")
|
(!this._stateHistory &&
|
||||||
|
(changedProps.has("_entities") ||
|
||||||
|
changedProps.has("_devices") ||
|
||||||
|
changedProps.has("_stateEntities") ||
|
||||||
|
changedProps.has("_deviceIdToEntities") ||
|
||||||
|
changedProps.has("_areaIdToEntities") ||
|
||||||
|
changedProps.has("_areaIdToDevices"))))
|
||||||
) {
|
) {
|
||||||
this._getHistory();
|
this._getHistory();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changedProps.has("hass") || changedProps.has("_entities")) {
|
if (!changedProps.has("hass") && !changedProps.has("_entities")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||||
if (!oldHass || oldHass.language !== this.hass.language) {
|
if (!oldHass || oldHass.language !== this.hass.language) {
|
||||||
this.rtl = computeRTL(this.hass);
|
this.rtl = computeRTL(this.hass);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._entities) {
|
if (this._entities) {
|
||||||
const stateEntities: EntityRegistryEntry[] = [];
|
const stateEntities: { [entityId: string]: EntityRegistryEntry } = {};
|
||||||
const regEntityIds = new Set(
|
const regEntityIds = new Set(Object.keys(this._entities));
|
||||||
this._entities.map((entity) => entity.entity_id)
|
|
||||||
);
|
|
||||||
for (const entityId of Object.keys(this.hass.states)) {
|
for (const entityId of Object.keys(this.hass.states)) {
|
||||||
if (regEntityIds.has(entityId)) {
|
if (regEntityIds.has(entityId)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
stateEntities.push({
|
stateEntities[entityId] = {
|
||||||
name: computeStateName(this.hass.states[entityId]),
|
name: computeStateName(this.hass.states[entityId]),
|
||||||
entity_id: entityId,
|
entity_id: entityId,
|
||||||
platform: computeDomain(entityId),
|
platform: computeDomain(entityId),
|
||||||
@ -230,29 +299,33 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
|
|||||||
device_id: null,
|
device_id: null,
|
||||||
icon: null,
|
icon: null,
|
||||||
entity_category: null,
|
entity_category: null,
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
this._stateEntities = stateEntities;
|
this._stateEntities = stateEntities;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private _refreshHistory() {
|
private _removeAll() {
|
||||||
this._getHistory();
|
this._targetPickerValue = undefined;
|
||||||
|
this._updatePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _getHistory() {
|
private async _getHistory() {
|
||||||
this._isLoading = true;
|
this._isLoading = true;
|
||||||
const entityIds = this._getEntityIds();
|
const entityIds = this._getEntityIds();
|
||||||
const dateHistory =
|
|
||||||
entityIds.length === 0
|
if (!entityIds.length) {
|
||||||
? {}
|
this._stateHistory = undefined;
|
||||||
: await fetchDateWS(
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dateHistory = await fetchDateWS(
|
||||||
this.hass,
|
this.hass,
|
||||||
this._startDate,
|
this._startDate,
|
||||||
this._endDate,
|
this._endDate,
|
||||||
entityIds
|
entityIds
|
||||||
);
|
);
|
||||||
|
|
||||||
this._stateHistory = computeHistory(
|
this._stateHistory = computeHistory(
|
||||||
this.hass,
|
this.hass,
|
||||||
dateHistory,
|
dateHistory,
|
||||||
@ -261,50 +334,90 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
|
|||||||
this._isLoading = false;
|
this._isLoading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _filterEntity(entity: EntityRegistryEntry): boolean {
|
|
||||||
const { area_id, device_id, entity_id } = this._targetPickerValue;
|
|
||||||
if (area_id !== undefined) {
|
|
||||||
if (typeof area_id === "string" && area_id === entity.area_id) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (Array.isArray(area_id) && area_id.includes(entity.area_id)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (device_id !== undefined) {
|
|
||||||
if (typeof device_id === "string" && device_id === entity.device_id) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (Array.isArray(device_id) && device_id.includes(entity.device_id)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (entity_id !== undefined) {
|
|
||||||
if (typeof entity_id === "string" && entity_id === entity.entity_id) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (Array.isArray(entity_id) && entity_id.includes(entity.entity_id)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _getEntityIds(): string[] {
|
private _getEntityIds(): string[] {
|
||||||
if (
|
if (
|
||||||
this._targetPickerValue === undefined ||
|
this._targetPickerValue === undefined ||
|
||||||
this._entities === undefined ||
|
this._entities === undefined ||
|
||||||
this._stateEntities === undefined
|
this._stateEntities === undefined ||
|
||||||
|
this._devices === undefined ||
|
||||||
|
this._deviceIdToEntities === undefined ||
|
||||||
|
this._areaIdToEntities === undefined ||
|
||||||
|
this._areaIdToDevices === undefined
|
||||||
) {
|
) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const entityIds = this._entities
|
const entityIds = new Set<string>();
|
||||||
.filter((entity) => this._filterEntity(entity))
|
let {
|
||||||
.map((entity) => entity.entity_id);
|
area_id: searchingAreaId,
|
||||||
const stateEntityIds = this._stateEntities
|
device_id: searchingDeviceId,
|
||||||
.filter((entity) => this._filterEntity(entity))
|
entity_id: searchingEntityId,
|
||||||
.map((entity) => entity.entity_id);
|
} = this._targetPickerValue;
|
||||||
return [...entityIds, ...stateEntityIds];
|
|
||||||
|
if (searchingAreaId !== undefined) {
|
||||||
|
searchingAreaId =
|
||||||
|
typeof searchingAreaId === "string"
|
||||||
|
? [searchingAreaId]
|
||||||
|
: searchingAreaId;
|
||||||
|
for (const singleSearchingAreaId of searchingAreaId) {
|
||||||
|
const foundEntities = this._areaIdToEntities[singleSearchingAreaId];
|
||||||
|
if (!foundEntities) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const foundEntity of foundEntities) {
|
||||||
|
if (foundEntity.entity_category === null) {
|
||||||
|
entityIds.add(foundEntity.entity_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const foundDevices = this._areaIdToDevices[singleSearchingAreaId];
|
||||||
|
if (foundDevices !== undefined) {
|
||||||
|
for (const foundDevice of foundDevices) {
|
||||||
|
const foundDeviceEntities =
|
||||||
|
this._deviceIdToEntities[foundDevice.id];
|
||||||
|
for (const foundDeviceEntity of foundDeviceEntities) {
|
||||||
|
if (
|
||||||
|
(!foundDeviceEntity.area_id ||
|
||||||
|
foundDeviceEntity.area_id === singleSearchingAreaId) &&
|
||||||
|
foundDeviceEntity.entity_category === null
|
||||||
|
) {
|
||||||
|
entityIds.add(foundDeviceEntity.entity_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (searchingDeviceId !== undefined) {
|
||||||
|
searchingDeviceId =
|
||||||
|
typeof searchingDeviceId === "string"
|
||||||
|
? [searchingDeviceId]
|
||||||
|
: searchingDeviceId;
|
||||||
|
for (const singleSearchingDeviceId of searchingDeviceId) {
|
||||||
|
const foundEntities = this._deviceIdToEntities[singleSearchingDeviceId];
|
||||||
|
if (!foundEntities) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const foundEntity of foundEntities) {
|
||||||
|
if (foundEntity.entity_category === null) {
|
||||||
|
entityIds.add(foundEntity.entity_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (searchingEntityId !== undefined) {
|
||||||
|
searchingEntityId =
|
||||||
|
typeof searchingEntityId === "string"
|
||||||
|
? [searchingEntityId]
|
||||||
|
: searchingEntityId;
|
||||||
|
for (const singleSearchingEntityId of searchingEntityId) {
|
||||||
|
entityIds.add(singleSearchingEntityId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [...entityIds];
|
||||||
}
|
}
|
||||||
|
|
||||||
private _dateRangeChanged(ev) {
|
private _dateRangeChanged(ev) {
|
||||||
@ -321,7 +434,6 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
|
|||||||
|
|
||||||
private _entitiesChanged(ev) {
|
private _entitiesChanged(ev) {
|
||||||
this._targetPickerValue = ev.detail.value;
|
this._targetPickerValue = ev.detail.value;
|
||||||
|
|
||||||
this._updatePath();
|
this._updatePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -389,7 +501,7 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
|
|||||||
|
|
||||||
.filters {
|
.filters {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: flex-end;
|
align-items: flex-start;
|
||||||
padding: 8px 16px 0;
|
padding: 8px 16px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -429,9 +541,21 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
|
|||||||
max-width: none;
|
max-width: none;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.start-search {
|
||||||
|
padding-top: 16px;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("ha-panel-history", HaPanelHistory);
|
customElements.define("ha-panel-history", HaPanelHistory);
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-panel-history": HaPanelHistory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1593,7 +1593,6 @@
|
|||||||
"copy_github": "For GitHub",
|
"copy_github": "For GitHub",
|
||||||
"description": "Version, loaded integrations and links to documentation",
|
"description": "Version, loaded integrations and links to documentation",
|
||||||
"home_assistant_logo": "Home Assistant logo",
|
"home_assistant_logo": "Home Assistant logo",
|
||||||
"path_configuration": "Path to configuration.yaml: {path}",
|
|
||||||
"developed_by": "Developed by a bunch of awesome people.",
|
"developed_by": "Developed by a bunch of awesome people.",
|
||||||
"license": "Published under the Apache 2.0 license",
|
"license": "Published under the Apache 2.0 license",
|
||||||
"source": "Source:",
|
"source": "Source:",
|
||||||
@ -4012,7 +4011,8 @@
|
|||||||
"month": "Month",
|
"month": "Month",
|
||||||
"year": "Year",
|
"year": "Year",
|
||||||
"previous": "Previous",
|
"previous": "Previous",
|
||||||
"next": "Next"
|
"next": "Next",
|
||||||
|
"compare": "Compare Data"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"reload_lovelace": "Reload UI"
|
"reload_lovelace": "Reload UI"
|
||||||
@ -4537,6 +4537,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"energy": {
|
"energy": {
|
||||||
|
"compare": {
|
||||||
|
"info": "You are comparing the period {start} with the period {end}"
|
||||||
|
},
|
||||||
"setup": {
|
"setup": {
|
||||||
"next": "Next",
|
"next": "Next",
|
||||||
"back": "Back",
|
"back": "Back",
|
||||||
@ -4556,6 +4559,11 @@
|
|||||||
"energy_sources_table_title": "Sources",
|
"energy_sources_table_title": "Sources",
|
||||||
"energy_devices_graph_title": "Monitor individual devices"
|
"energy_devices_graph_title": "Monitor individual devices"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"history": {
|
||||||
|
"start_search": "Start by selecting an area, device or entity above",
|
||||||
|
"add_all": "Add all entities",
|
||||||
|
"remove_all": "Remove all selections"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tips": {
|
"tips": {
|
||||||
|
20
yarn.lock
20
yarn.lock
@ -2975,17 +2975,17 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@mdi/js@npm:6.7.96":
|
"@mdi/js@npm:6.9.96":
|
||||||
version: 6.7.96
|
version: 6.9.96
|
||||||
resolution: "@mdi/js@npm:6.7.96"
|
resolution: "@mdi/js@npm:6.9.96"
|
||||||
checksum: 8c8f6acb8fd3f856a92ffe2405e258ee5aa84cf541fda1c0a564c9c8bbf935cf2b6a6100cf97d41e9ada1ccb59e4b138d4c712e075f759d7595e21ef1cff84b5
|
checksum: 94c43271585981e7ebf8cc5e3ead11915eea1339b79e849b351fbaae58e9626aaca0a8b031f0e80754d880ea6b08fd715906588f3cf980603bb5f6871bff12cc
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@mdi/svg@npm:6.7.96":
|
"@mdi/svg@npm:6.9.96":
|
||||||
version: 6.7.96
|
version: 6.9.96
|
||||||
resolution: "@mdi/svg@npm:6.7.96"
|
resolution: "@mdi/svg@npm:6.9.96"
|
||||||
checksum: 959332009b8833d0347e2dfac86028362a6d11996db850025b7da8c493d7fd341a14d8716ef775dd2ed0492158c77236bcf09adfc4ae77b31044a0a8a26fc74b
|
checksum: 3e45f9a6632b0aa22f02ab0023d44131e3aea308bae85160445fe1f8f0b6d61df5c01e2756d18bd1461f7314fbf7c00a397bf99670f55803d90de5fa8e3fe33e
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@ -9047,8 +9047,8 @@ fsevents@^1.2.7:
|
|||||||
"@material/mwc-textfield": 0.25.3
|
"@material/mwc-textfield": 0.25.3
|
||||||
"@material/mwc-top-app-bar-fixed": ^0.25.3
|
"@material/mwc-top-app-bar-fixed": ^0.25.3
|
||||||
"@material/top-app-bar": 14.0.0-canary.261f2db59.0
|
"@material/top-app-bar": 14.0.0-canary.261f2db59.0
|
||||||
"@mdi/js": 6.7.96
|
"@mdi/js": 6.9.96
|
||||||
"@mdi/svg": 6.7.96
|
"@mdi/svg": 6.9.96
|
||||||
"@open-wc/dev-server-hmr": ^0.0.2
|
"@open-wc/dev-server-hmr": ^0.0.2
|
||||||
"@polymer/app-layout": ^3.1.0
|
"@polymer/app-layout": ^3.1.0
|
||||||
"@polymer/iron-flex-layout": ^3.0.1
|
"@polymer/iron-flex-layout": ^3.0.1
|
||||||
|
Loading…
x
Reference in New Issue
Block a user