Merge pull request #13099 from home-assistant/dev

Bump to 20220705.0
This commit is contained in:
Bram Kragten 2022-07-05 18:55:51 +02:00 committed by GitHub
commit f6d6fd179f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 611 additions and 425 deletions

8
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,8 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: weekly
time: "06:00"
open-pull-requests-limit: 10

View File

@ -19,9 +19,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Set up Node ${{ env.NODE_VERSION }}
uses: actions/setup-node@v2
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}
cache: yarn
@ -43,9 +43,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Set up Node ${{ env.NODE_VERSION }}
uses: actions/setup-node@v2
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}
cache: yarn
@ -62,9 +62,9 @@ jobs:
needs: [lint, test]
steps:
- name: Check out files from GitHub
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Set up Node ${{ env.NODE_VERSION }}
uses: actions/setup-node@v2
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}
cache: yarn
@ -81,9 +81,9 @@ jobs:
needs: [lint, test]
steps:
- name: Check out files from GitHub
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Set up Node ${{ env.NODE_VERSION }}
uses: actions/setup-node@v2
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}
cache: yarn

View File

@ -23,7 +23,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
@ -36,14 +36,14 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@ -57,4 +57,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v2

View File

@ -14,9 +14,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out files from GitHub
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Set up Node ${{ env.NODE_VERSION }}
uses: actions/setup-node@v2
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}
cache: yarn

View File

@ -9,7 +9,7 @@ jobs:
lock:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v2.0.1
- uses: dessant/lock-threads@v3.0.0
with:
github-token: ${{ github.token }}
issue-lock-inactive-days: "30"

63
.github/workflows/nightly.yaml vendored Normal file
View 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

View File

@ -24,18 +24,18 @@ jobs:
contents: write # Required to upload release assets
steps:
- name: Checkout the repository
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Verify version
uses: home-assistant/actions/helpers/verify-version@master
- name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@v2
uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Set up Node ${{ env.NODE_VERSION }}
uses: actions/setup-node@v2
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}
cache: yarn

View File

@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Upload Translations
run: |

View File

@ -27,7 +27,7 @@ module.exports = {
version() {
const version = fs
.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) {
throw Error("Version not found");
}

View File

@ -797,7 +797,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
attributes: {
battery_level: 34,
on: true,
friendly_name: "altan_motion_sensor",
friendly_name: "Porch motion sensor",
device_class: "motion",
},
},
@ -818,7 +818,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
attributes: {
battery_level: 74,
on: true,
friendly_name: "badrumssensor",
friendly_name: "Bathroom motion sensor",
device_class: "motion",
},
},
@ -829,7 +829,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
battery_level: 47,
on: true,
dark: true,
friendly_name: "R\u00f6relsesensor k\u00e4llaren 1",
friendly_name: "Basement motion sensor",
device_class: "motion",
icon: "mdi:walk",
},
@ -863,7 +863,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
attributes: {
battery_level: 60,
on: true,
friendly_name: "R\u00f6relsesensor skafferiet",
friendly_name: "Pantry motion sensor",
device_class: "motion",
icon: "mdi:walk",
},
@ -875,7 +875,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
battery_level: 60,
on: true,
dark: true,
friendly_name: "R\u00f6relsesensor k\u00e4llaren 2",
friendly_name: "Stair motion sensor",
device_class: "motion",
icon: "mdi:walk",
},
@ -887,7 +887,7 @@ export const demoEntitiesKernehed: DemoConfig["entities"] = () =>
battery_level: 47,
on: true,
dark: true,
friendly_name: "B\u00e4nksensor",
friendly_name: "Bench sensor",
device_class: "motion",
},
},

View File

@ -277,7 +277,7 @@ export const demoLovelaceKernehed: DemoConfig["lovelace"] = () => ({
],
show_header_toggle: false,
type: "entities",
title: "Bandbredd",
title: "Bandwidth",
},
// {
// title: "Updater",

View File

@ -72,8 +72,8 @@
"@material/mwc-textfield": "0.25.3",
"@material/mwc-top-app-bar-fixed": "^0.25.3",
"@material/top-app-bar": "14.0.0-canary.261f2db59.0",
"@mdi/js": "6.7.96",
"@mdi/svg": "6.7.96",
"@mdi/js": "6.9.96",
"@mdi/svg": "6.9.96",
"@polymer/app-layout": "^3.1.0",
"@polymer/iron-flex-layout": "^3.0.1",
"@polymer/iron-icon": "^3.0.1",

View File

@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "home-assistant-frontend"
version = "20220630.0"
version = "20220705.0"
license = {text = "Apache-2.0"}
description = "The Home Assistant frontend"
readme = "README.md"

View File

@ -24,10 +24,15 @@ function auto(version) {
return patch(version);
}
function nightly() {
return `${today()}.dev`;
}
const methods = {
patch,
today,
auto,
nightly,
};
async function main(args) {
@ -57,7 +62,11 @@ async function main(args) {
console.log("Current version:", version);
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) {
return;

View File

@ -186,6 +186,7 @@ class StateHistoryCharts extends LitElement {
line-height: 60px;
color: var(--secondary-text-color);
}
.container {
max-height: var(--history-max-height);
}

View File

@ -209,7 +209,7 @@ export class HaCodeEditor extends ReactiveElement {
private _entityCompletions(
context: CompletionContext
): CompletionResult | null | Promise<CompletionResult | null> {
const entityWord = context.matchBefore(/[a-z_]{3,}\./);
const entityWord = context.matchBefore(/[a-z_]{3,}\.\w*/);
if (
!entityWord ||
@ -227,7 +227,7 @@ export class HaCodeEditor extends ReactiveElement {
return {
from: Number(entityWord.from),
options: states,
span: /^\w*.\w*$/,
span: /^[a-z_]{3,}\.\w*$/,
};
}
@ -257,7 +257,7 @@ export class HaCodeEditor extends ReactiveElement {
private async _mdiCompletions(
context: CompletionContext
): Promise<CompletionResult | null> {
const match = context.matchBefore(/mdi:/);
const match = context.matchBefore(/mdi:\S*/);
if (!match || (match.from === match.to && !context.explicit)) {
return null;
@ -268,7 +268,7 @@ export class HaCodeEditor extends ReactiveElement {
return {
from: Number(match.from),
options: iconItems,
span: /^\w*.\w*$/,
span: /^mdi:\S*$/,
};
}

View File

@ -42,8 +42,8 @@ import "./entity/ha-entity-picker";
import type { HaEntityPickerEntityFilterFunc } from "./entity/ha-entity-picker";
import "./ha-area-picker";
import "./ha-icon-button";
import "./ha-svg-icon";
import "./ha-input-helper-text";
import "./ha-svg-icon";
@customElement("ha-target-picker")
export class HaTargetPicker extends SubscribeMixin(LitElement) {
@ -119,55 +119,68 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
if (!this._areas || !this._devices || !this._entities) {
return html``;
}
return html`<div class=${this.horizontal ? "horizontal-container" : ""}>
${this.horizontal ? this._renderChips() : this._renderItems()}
${this._renderPicker()}
${this.horizontal ? this._renderItems() : this._renderChips()}
</div>`;
return html`
${this.horizontal
? html`
<div class="horizontal-container">
${this._renderChips()} ${this._renderPicker()}
</div>
${this._renderItems()}
`
: html`
<div>
${this._renderItems()} ${this._renderPicker()}
${this._renderChips()}
</div>
`}
`;
}
private _renderItems() {
return html`<div class="mdc-chip-set items">
${this.value?.area_id
? ensureArray(this.value.area_id).map((area_id) => {
const area = this._areas![area_id];
return this._renderChip(
"area_id",
area_id,
area?.name || area_id,
undefined,
mdiSofa
);
})
: ""}
${this.value?.device_id
? ensureArray(this.value.device_id).map((device_id) => {
const device = this._devices![device_id];
return this._renderChip(
"device_id",
device_id,
device ? computeDeviceName(device, this.hass) : device_id,
undefined,
mdiDevices
);
})
: ""}
${this.value?.entity_id
? ensureArray(this.value.entity_id).map((entity_id) => {
const entity = this.hass.states[entity_id];
return this._renderChip(
"entity_id",
entity_id,
entity ? computeStateName(entity) : entity_id,
entity
);
})
: ""}
</div>`;
return html`
<div class="mdc-chip-set items">
${this.value?.area_id
? ensureArray(this.value.area_id).map((area_id) => {
const area = this._areas![area_id];
return this._renderChip(
"area_id",
area_id,
area?.name || area_id,
undefined,
mdiSofa
);
})
: ""}
${this.value?.device_id
? ensureArray(this.value.device_id).map((device_id) => {
const device = this._devices![device_id];
return this._renderChip(
"device_id",
device_id,
device ? computeDeviceName(device, this.hass) : device_id,
undefined,
mdiDevices
);
})
: ""}
${this.value?.entity_id
? ensureArray(this.value.entity_id).map((entity_id) => {
const entity = this.hass.states[entity_id];
return this._renderChip(
"entity_id",
entity_id,
entity ? computeStateName(entity) : entity_id,
entity
);
})
: ""}
</div>
`;
}
private _renderChips() {
return html`<div class="mdc-chip-set">
return html`
<div class="mdc-chip-set">
<div
class="mdc-chip area_id add"
.type=${"area_id"}
@ -231,7 +244,8 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
</div>
${this.helper
? html`<ha-input-helper-text>${this.helper}</ha-input-helper-text>`
: ""} `;
: ""}
`;
}
private async _showPicker(ev) {
@ -320,51 +334,54 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
private _renderPicker() {
switch (this._addMode) {
case "area_id":
return html`<ha-area-picker
.hass=${this.hass}
id="input"
.type=${"area_id"}
.label=${this.hass.localize(
"ui.components.target-picker.add_area_id"
)}
no-add
.deviceFilter=${this.deviceFilter}
.entityFilter=${this.entityRegFilter}
.includeDeviceClasses=${this.includeDeviceClasses}
.includeDomains=${this.includeDomains}
class=${this.horizontal ? "hidden-picker" : ""}
@value-changed=${this._targetPicked}
></ha-area-picker>`;
return html`
<ha-area-picker
.hass=${this.hass}
id="input"
.type=${"area_id"}
.label=${this.hass.localize(
"ui.components.target-picker.add_area_id"
)}
no-add
.deviceFilter=${this.deviceFilter}
.entityFilter=${this.entityRegFilter}
.includeDeviceClasses=${this.includeDeviceClasses}
.includeDomains=${this.includeDomains}
@value-changed=${this._targetPicked}
></ha-area-picker>
`;
case "device_id":
return html`<ha-device-picker
.hass=${this.hass}
id="input"
.type=${"device_id"}
.label=${this.hass.localize(
"ui.components.target-picker.add_device_id"
)}
.deviceFilter=${this.deviceFilter}
.entityFilter=${this.entityRegFilter}
.includeDeviceClasses=${this.includeDeviceClasses}
.includeDomains=${this.includeDomains}
class=${this.horizontal ? "hidden-picker" : ""}
@value-changed=${this._targetPicked}
></ha-device-picker>`;
return html`
<ha-device-picker
.hass=${this.hass}
id="input"
.type=${"device_id"}
.label=${this.hass.localize(
"ui.components.target-picker.add_device_id"
)}
.deviceFilter=${this.deviceFilter}
.entityFilter=${this.entityRegFilter}
.includeDeviceClasses=${this.includeDeviceClasses}
.includeDomains=${this.includeDomains}
@value-changed=${this._targetPicked}
></ha-device-picker>
`;
case "entity_id":
return html`<ha-entity-picker
.hass=${this.hass}
id="input"
.type=${"entity_id"}
.label=${this.hass.localize(
"ui.components.target-picker.add_entity_id"
)}
.entityFilter=${this.entityFilter}
.includeDeviceClasses=${this.includeDeviceClasses}
.includeDomains=${this.includeDomains}
class=${this.horizontal ? "hidden-picker" : ""}
@value-changed=${this._targetPicked}
allow-custom-entity
></ha-entity-picker>`;
return html`
<ha-entity-picker
.hass=${this.hass}
id="input"
.type=${"entity_id"}
.label=${this.hass.localize(
"ui.components.target-picker.add_entity_id"
)}
.entityFilter=${this.entityFilter}
.includeDeviceClasses=${this.includeDeviceClasses}
.includeDomains=${this.includeDomains}
@value-changed=${this._targetPicked}
allow-custom-entity
></ha-entity-picker>
`;
}
return html``;
}
@ -553,15 +570,11 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
static get styles(): CSSResultGroup {
return css`
${unsafeCSS(chipStyles)}
.hidden-picker {
height: 0px;
display: inline-block;
overflow: hidden;
position: absolute;
}
.horizontal-container {
display: flex;
flex-wrap: wrap;
min-height: 56px;
align-items: center;
}
.mdc-chip {
color: var(--primary-text-color);

View File

@ -124,7 +124,6 @@ class HaOnboarding extends litLocalizeLiteMixin(HassElement) {
protected firstUpdated(changedProps: PropertyValues) {
super.firstUpdated(changedProps);
this._fetchOnboardingSteps();
this._fetchInstallationType();
import("./onboarding-integrations");
import("./onboarding-core-config");
registerServiceWorker(this, false);
@ -215,6 +214,9 @@ class HaOnboarding extends litLocalizeLiteMixin(HassElement) {
});
history.replaceState(null, "", location.pathname);
await this._connectHass(auth);
} else {
// User creating screen needs to know the installation type.
this._fetchInstallationType();
}
this._steps = steps;

View File

@ -378,6 +378,10 @@ class OnboardingCoreConfig extends LitElement {
color: var(--secondary-text-color);
}
ha-locations-editor {
height: 200px;
}
.flex {
flex: 1;
}

View File

@ -30,7 +30,13 @@ import { HomeAssistant } from "../types";
import "./action-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")
class OnboardingIntegrations extends LitElement {
@ -75,7 +81,10 @@ class OnboardingIntegrations extends LitElement {
// Render discovered and existing entries together sorted by localized title.
const entries: Array<[string, TemplateResult]> = this._entries.map(
(entry) => {
const title = domainToName(this.hass.localize, entry.domain);
const title =
entry.title ||
domainToName(this.hass.localize, entry.domain) ||
entry.domain;
return [
title,
html`

View File

@ -1,7 +1,5 @@
import "@material/mwc-button";
import type { ActionDetail } from "@material/mwc-list";
import "@material/mwc-list/mwc-list-item";
import { mdiDotsVertical } from "@mdi/js";
import "@polymer/paper-item/paper-item-body";
import { css, html, LitElement, PropertyValues } from "lit";
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 "../../../../components/buttons/ha-call-api-button";
import "../../../../components/ha-alert";
import "../../../../components/ha-button-menu";
import "../../../../components/ha-card";
import "../../../../components/ha-icon-button";
import {
cloudLogout,
CloudStatusLoggedIn,
@ -23,6 +19,7 @@ import {
import { showConfirmationDialog } from "../../../../dialogs/generic/show-dialog-box";
import "../../../../layouts/hass-subpage";
import { SubscribeMixin } from "../../../../mixins/subscribe-mixin";
import { haStyle } from "../../../../resources/styles";
import { HomeAssistant } from "../../../../types";
import "../../ha-config-section";
import "./cloud-alexa-pref";
@ -52,23 +49,6 @@ export class CloudAccount extends SubscribeMixin(LitElement) {
.narrow=${this.narrow}
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">
<ha-config-section .isWide=${this.isWide}>
<span slot="header">Home Assistant Cloud</span>
@ -156,6 +136,11 @@ export class CloudAccount extends SubscribeMixin(LitElement) {
)}
</mwc-button>
</a>
<mwc-button @click=${this._signOut} class="warning">
${this.hass.localize(
"ui.panel.config.cloud.account.sign_out"
)}
</mwc-button>
</div>
</ha-card>
</ha-config-section>
@ -279,18 +264,15 @@ export class CloudAccount extends SubscribeMixin(LitElement) {
}
}
private async _handleMenuAction(ev: CustomEvent<ActionDetail>) {
switch (ev.detail.index) {
case 0:
showConfirmationDialog(this, {
text: this.hass.localize(
"ui.panel.config.cloud.account.sign_out_confirm"
),
confirmText: this.hass!.localize("ui.common.yes"),
dismissText: this.hass!.localize("ui.common.no"),
confirm: () => this._logoutFromCloud(),
});
}
private async _signOut() {
showConfirmationDialog(this, {
text: this.hass.localize(
"ui.panel.config.cloud.account.sign_out_confirm"
),
confirmText: this.hass!.localize("ui.common.yes"),
dismissText: this.hass!.localize("ui.common.no"),
confirm: () => this._logoutFromCloud(),
});
}
private async _logoutFromCloud() {
@ -303,41 +285,39 @@ export class CloudAccount extends SubscribeMixin(LitElement) {
}
static get styles() {
return css`
[slot="introduction"] {
margin: -1em 0;
}
[slot="introduction"] a {
color: var(--primary-color);
}
.content {
padding-bottom: 24px;
}
.account-row {
display: flex;
padding: 0 16px;
}
.card-actions {
display: flex;
flex-direction: row-reverse;
}
.card-actions a {
text-decoration: none;
}
mwc-button {
align-self: center;
}
.wrap {
white-space: normal;
}
.status {
text-transform: capitalize;
padding: 16px;
}
a {
color: var(--primary-color);
}
`;
return [
haStyle,
css`
[slot="introduction"] {
margin: -1em 0;
}
[slot="introduction"] a {
color: var(--primary-color);
}
.content {
padding-bottom: 24px;
}
.account-row {
display: flex;
padding: 0 16px;
}
.card-actions {
display: flex;
flex-direction: row-reverse;
justify-content: space-between;
}
mwc-button {
align-self: center;
}
.wrap {
white-space: normal;
}
.status {
text-transform: capitalize;
padding: 16px;
}
`,
];
}
}

View File

@ -185,6 +185,10 @@ export class CloudTTSPref extends LitElement {
right: auto;
left: 24px;
}
.card-actions {
display: flex;
flex-direction: row-reverse;
}
`;
}
}

View File

@ -2,7 +2,6 @@ import { getConfigEntries } from "../../../../../../data/config_entries";
import { DeviceRegistryEntry } from "../../../../../../data/device_registry";
import {
fetchZwaveIsAnyFirmwareUpdateInProgress,
fetchZwaveNodeFirmwareUpdateCapabilities,
fetchZwaveNodeIsFirmwareUpdateInProgress,
fetchZwaveNodeStatus,
} from "../../../../../../data/zwave_js";
@ -87,20 +86,13 @@ export const getZwaveDeviceActions = async (
return actions;
}
const [
firmwareUpdateCapabilities,
isAnyFirmwareUpdateInProgress,
isNodeFirmwareUpdateInProgress,
] = await Promise.all([
fetchZwaveNodeFirmwareUpdateCapabilities(hass, device.id),
fetchZwaveIsAnyFirmwareUpdateInProgress(hass, entryId),
fetchZwaveNodeIsFirmwareUpdateInProgress(hass, device.id),
]);
const [isAnyFirmwareUpdateInProgress, isNodeFirmwareUpdateInProgress] =
await Promise.all([
fetchZwaveIsAnyFirmwareUpdateInProgress(hass, entryId),
fetchZwaveNodeIsFirmwareUpdateInProgress(hass, device.id),
]);
if (
firmwareUpdateCapabilities.firmware_upgradable &&
(!isAnyFirmwareUpdateInProgress || isNodeFirmwareUpdateInProgress)
) {
if (!isAnyFirmwareUpdateInProgress || isNodeFirmwareUpdateInProgress) {
actions.push({
label: hass.localize(
"ui.panel.config.zwave_js.device_info.update_firmware"
@ -117,7 +109,6 @@ export const getZwaveDeviceActions = async (
) {
showZWaveJUpdateFirmwareNodeDialog(el, {
device,
firmwareUpdateCapabilities,
});
}
},

View File

@ -165,13 +165,6 @@ class HaConfigInfo extends LitElement {
`
)}
</mwc-list>
<p class="config-path">
${this.hass.localize(
"ui.panel.config.info.path_configuration",
"path",
hass.config.config_dir
)}
</p>
${!customUiList.length
? ""
: html`
@ -202,7 +195,7 @@ class HaConfigInfo extends LitElement {
if (((window as any).CUSTOM_UI_LIST || []).length !== customUI.length) {
this.requestUpdate();
}
}, 1000);
}, 2000);
if (isComponentLoaded(this.hass, "hassio")) {
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 {
color: var(--secondary-text-color);
text-align: center;

View File

@ -766,7 +766,6 @@ class HaConfigIntegrations extends SubscribeMixin(LitElement) {
display: flex;
justify-content: flex-end;
width: 100%;
margin-right: 8px;
align-items: center;
height: 56px;
position: sticky;

View File

@ -6,7 +6,6 @@ import "@material/mwc-linear-progress/mwc-linear-progress";
import { mdiCheckCircle, mdiCloseCircle, mdiFileUpload } from "@mdi/js";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { UnsubscribeFunc } from "home-assistant-js-websocket";
import { fireEvent } from "../../../../../common/dom/fire_event";
import { createCloseHeading } from "../../../../../components/ha-dialog";
@ -26,7 +25,6 @@ import {
ZWaveJSNodeFirmwareUpdateFinishedMessage,
ZWaveJSNodeFirmwareUpdateProgressMessage,
ZWaveJSNodeStatusUpdatedMessage,
ZWaveJSNodeFirmwareUpdateCapabilities,
ZWaveJSNodeStatus,
} from "../../../../../data/zwave_js";
import { haStyleDialog } from "../../../../../resources/styles";
@ -66,12 +64,9 @@ class DialogZWaveJSUpdateFirmwareNode extends LitElement {
private _deviceName?: string;
private _firmwareUpdateCapabilities?: ZWaveJSNodeFirmwareUpdateCapabilities;
public showDialog(params: ZWaveJSUpdateFirmwareNodeDialogParams): void {
this._deviceName = computeDeviceName(params.device, this.hass!);
this.device = params.device;
this._firmwareUpdateCapabilities = params.firmwareUpdateCapabilities;
this._fetchData();
this._subscribeNodeStatus();
}
@ -84,7 +79,6 @@ class DialogZWaveJSUpdateFirmwareNode extends LitElement {
this._updateFinishedMessage =
this._firmwareFile =
this._nodeStatus =
this._firmwareUpdateCapabilities =
undefined;
this._firmwareTarget = 0;
this._uploading = this._updateInProgress = false;
@ -92,34 +86,21 @@ class DialogZWaveJSUpdateFirmwareNode extends LitElement {
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 {
if (
!this.device ||
!this._nodeStatus ||
!this._firmwareUpdateCapabilities ||
!this._firmwareUpdateCapabilities.firmware_upgradable ||
this._updateInProgress === undefined
) {
return html``;
}
const schema: HaFormIntegerSchema = {
name: "firmware_target",
type: "integer",
valueMin: 0,
};
const beginFirmwareUpdateHTML = html`<ha-file-upload
.hass=${this.hass}
.uploading=${this._uploading}
@ -130,19 +111,17 @@ class DialogZWaveJSUpdateFirmwareNode extends LitElement {
)}
@file-picked=${this._uploadFile}
></ha-file-upload>
${this._firmwareUpdateCapabilities.firmware_targets.length > 1
? html`<p>
${this.hass.localize(
"ui.panel.config.zwave_js.update_firmware.firmware_target_intro"
)}
</p>
<ha-form
.hass=${this.hass}
.data=${{ firmware_target: this._firmwareTarget }}
.schema=${[this._schema(this._firmwareUpdateCapabilities)]}
@value-changed=${this._firmwareTargetChanged}
></ha-form>`
: ""}
<p>
${this.hass.localize(
"ui.panel.config.zwave_js.update_firmware.firmware_target_intro"
)}
</p>
<ha-form
.hass=${this.hass}
.data=${{ firmware_target: this._firmwareTarget }}
.schema=${[schema]}
@value-changed=${this._firmwareTargetChanged}
></ha-form>
<mwc-button
slot="primaryAction"
@click=${this._beginFirmwareUpdate}
@ -285,12 +264,6 @@ class DialogZWaveJSUpdateFirmwareNode extends LitElement {
)}
</p>
${beginFirmwareUpdateHTML}`}
<p>
${this.hass.localize(
"ui.panel.config.zwave_js.update_firmware.finished_status.try_again"
)}
</p>
${beginFirmwareUpdateHTML}
`}
</ha-dialog>
`;

View File

@ -1,10 +1,8 @@
import { fireEvent } from "../../../../../common/dom/fire_event";
import { DeviceRegistryEntry } from "../../../../../data/device_registry";
import { ZWaveJSNodeFirmwareUpdateCapabilities } from "../../../../../data/zwave_js";
export interface ZWaveJSUpdateFirmwareNodeDialogParams {
device: DeviceRegistryEntry;
firmwareUpdateCapabilities: ZWaveJSNodeFirmwareUpdateCapabilities;
}
export const loadUpdateFirmwareNodeDialog = () =>

View File

@ -107,6 +107,8 @@ export class HaSceneEditor extends SubscribeMixin(
@state() private _entities: string[] = [];
private _single_entities: string[] = [];
@state() private _devices: string[] = [];
@state()
@ -121,7 +123,7 @@ export class HaSceneEditor extends SubscribeMixin(
private _unsubscribeEvents?: () => void;
@state() private _deviceEntityLookup: DeviceEntitiesLookup = {};
private _deviceEntityLookup: DeviceEntitiesLookup = {};
private _activateContextId?: string;
@ -520,9 +522,11 @@ export class HaSceneEditor extends SubscribeMixin(
}
if (changedProps.has("_entityRegistryEntries")) {
this._deviceEntityLookup = {};
for (const entity of this._entityRegistryEntries) {
if (
!entity.device_id ||
entity.entity_category ||
SCENE_IGNORED_DOMAINS.includes(computeDomain(entity.entity_id))
) {
continue;
@ -530,13 +534,10 @@ export class HaSceneEditor extends SubscribeMixin(
if (!(entity.device_id in this._deviceEntityLookup)) {
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 (
this._entities.includes(entity.entity_id) &&
!this._single_entities.includes(entity.device_id) &&
!this._devices.includes(entity.device_id)
) {
this._devices = [...this._devices, entity.device_id];
@ -625,12 +626,24 @@ export class HaSceneEditor extends SubscribeMixin(
private _initEntities(config: SceneConfig) {
this._entities = Object.keys(config.entities);
this._entities.forEach((entity) => this._storeState(entity));
this._single_entities = [];
const filteredEntityReg = this._entityRegistryEntries.filter((entityReg) =>
this._entities.includes(entityReg.entity_id)
);
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) {
if (!entityReg.device_id) {
continue;
@ -654,6 +667,7 @@ export class HaSceneEditor extends SubscribeMixin(
return;
}
this._entities = [...this._entities, entityId];
this._single_entities.push(entityId);
this._storeState(entityId);
this._dirty = true;
}
@ -664,6 +678,9 @@ export class HaSceneEditor extends SubscribeMixin(
this._entities = this._entities.filter(
(entityId) => entityId !== deleteEntityId
);
this._single_entities = this._single_entities.filter(
(entityId) => entityId !== deleteEntityId
);
this._dirty = true;
}
@ -815,19 +832,15 @@ export class HaSceneEditor extends SubscribeMixin(
private _calculateMetaData(): SceneMetaData {
const output: SceneMetaData = {};
for (const entityReg of this._entityRegistryEntries) {
if (!this._entities.includes(entityReg.entity_id)) {
continue;
}
const entityState = this._getCurrentState(entityReg.entity_id);
for (const entityId of this._single_entities) {
const entityState = this._getCurrentState(entityId);
if (!entityState) {
continue;
}
output[entityReg.entity_id] = {
entity_only: !this._devices.includes(entityReg.device_id!),
output[entityId] = {
entity_only: true,
};
}

View File

@ -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-toolbar/app-toolbar";
import {
@ -10,9 +10,12 @@ import {
startOfWeek,
startOfYesterday,
} from "date-fns/esm";
import { UnsubscribeFunc } from "home-assistant-js-websocket/dist/types";
import { css, html, LitElement, PropertyValues } from "lit";
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 {
createSearchParam,
@ -20,46 +23,62 @@ import {
} from "../../common/url/search-params";
import { computeRTL } from "../../common/util/compute_rtl";
import "../../components/chart/state-history-charts";
import "../../components/ha-target-picker";
import "../../components/ha-circular-progress";
import "../../components/ha-date-range-picker";
import type { DateRangePickerRanges } from "../../components/ha-date-range-picker";
import "../../components/ha-icon-button";
import "../../components/ha-menu-button";
import { computeHistory, fetchDateWS } from "../../data/history";
import "../../layouts/ha-app-layout";
import { haStyle } from "../../resources/styles";
import { HomeAssistant } from "../../types";
import "../../components/ha-target-picker";
import {
DeviceRegistryEntry,
subscribeDeviceRegistry,
} from "../../data/device_registry";
import {
EntityRegistryEntry,
subscribeEntityRegistry,
} from "../../data/entity_registry";
import { computeHistory, fetchDateWS } from "../../data/history";
import "../../layouts/ha-app-layout";
import { SubscribeMixin } from "../../mixins/subscribe-mixin";
import { computeStateName } from "../../common/entity/compute_state_name";
import { computeDomain } from "../../common/entity/compute_domain";
import { haStyle } from "../../resources/styles";
import { HomeAssistant } from "../../types";
class HaPanelHistory extends SubscribeMixin(LitElement) {
@property() hass!: HomeAssistant;
@property({ attribute: false }) hass!: HomeAssistant;
@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;
@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 _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() {
super();
@ -76,7 +95,52 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
public hassSubscribe(): UnsubscribeFunc[] {
return [
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}
></ha-menu-button>
<div main-title>${this.hass.localize("panel.history")}</div>
${this._targetPickerValue
? html`
<ha-icon-button
@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._refreshHistory}
@click=${this._getHistory}
.disabled=${this._isLoading}
.path=${mdiRefresh}
.label=${this.hass.localize("ui.common.refresh")}
@ -125,6 +199,10 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
alt=${this.hass.localize("ui.common.loading")}
></ha-circular-progress>
</div>`
: !this._targetPickerValue
? html`<div class="start-search">
${this.hass.localize("ui.panel.history.start_search")}
</div>`
: html`
<state-history-charts
.hass=${this.hass}
@ -135,24 +213,6 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
</state-history-charts>
`}
</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>
`;
}
@ -197,62 +257,75 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
protected updated(changedProps: PropertyValues) {
if (
changedProps.has("_startDate") ||
changedProps.has("_endDate") ||
changedProps.has("_targetPickerValue") ||
changedProps.has("_entities")
this._targetPickerValue &&
(changedProps.has("_startDate") ||
changedProps.has("_endDate") ||
changedProps.has("_targetPickerValue") ||
(!this._stateHistory &&
(changedProps.has("_entities") ||
changedProps.has("_devices") ||
changedProps.has("_stateEntities") ||
changedProps.has("_deviceIdToEntities") ||
changedProps.has("_areaIdToEntities") ||
changedProps.has("_areaIdToDevices"))))
) {
this._getHistory();
}
if (changedProps.has("hass") || changedProps.has("_entities")) {
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
if (!oldHass || oldHass.language !== this.hass.language) {
this.rtl = computeRTL(this.hass);
}
if (this._entities) {
const stateEntities: EntityRegistryEntry[] = [];
const regEntityIds = new Set(
this._entities.map((entity) => entity.entity_id)
);
for (const entityId of Object.keys(this.hass.states)) {
if (regEntityIds.has(entityId)) {
continue;
}
stateEntities.push({
name: computeStateName(this.hass.states[entityId]),
entity_id: entityId,
platform: computeDomain(entityId),
disabled_by: null,
hidden_by: null,
area_id: null,
config_entry_id: null,
device_id: null,
icon: null,
entity_category: null,
});
if (!changedProps.has("hass") && !changedProps.has("_entities")) {
return;
}
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
if (!oldHass || oldHass.language !== this.hass.language) {
this.rtl = computeRTL(this.hass);
}
if (this._entities) {
const stateEntities: { [entityId: string]: EntityRegistryEntry } = {};
const regEntityIds = new Set(Object.keys(this._entities));
for (const entityId of Object.keys(this.hass.states)) {
if (regEntityIds.has(entityId)) {
continue;
}
this._stateEntities = stateEntities;
stateEntities[entityId] = {
name: computeStateName(this.hass.states[entityId]),
entity_id: entityId,
platform: computeDomain(entityId),
disabled_by: null,
hidden_by: null,
area_id: null,
config_entry_id: null,
device_id: null,
icon: null,
entity_category: null,
};
}
this._stateEntities = stateEntities;
}
}
private _refreshHistory() {
this._getHistory();
private _removeAll() {
this._targetPickerValue = undefined;
this._updatePath();
}
private async _getHistory() {
this._isLoading = true;
const entityIds = this._getEntityIds();
const dateHistory =
entityIds.length === 0
? {}
: await fetchDateWS(
this.hass,
this._startDate,
this._endDate,
entityIds
);
if (!entityIds.length) {
this._stateHistory = undefined;
return;
}
const dateHistory = await fetchDateWS(
this.hass,
this._startDate,
this._endDate,
entityIds
);
this._stateHistory = computeHistory(
this.hass,
dateHistory,
@ -261,50 +334,90 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
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[] {
if (
this._targetPickerValue === undefined ||
this._entities === undefined ||
this._stateEntities === undefined
this._stateEntities === undefined ||
this._devices === undefined ||
this._deviceIdToEntities === undefined ||
this._areaIdToEntities === undefined ||
this._areaIdToDevices === undefined
) {
return [];
}
const entityIds = this._entities
.filter((entity) => this._filterEntity(entity))
.map((entity) => entity.entity_id);
const stateEntityIds = this._stateEntities
.filter((entity) => this._filterEntity(entity))
.map((entity) => entity.entity_id);
return [...entityIds, ...stateEntityIds];
const entityIds = new Set<string>();
let {
area_id: searchingAreaId,
device_id: searchingDeviceId,
entity_id: searchingEntityId,
} = this._targetPickerValue;
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) {
@ -321,7 +434,6 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
private _entitiesChanged(ev) {
this._targetPickerValue = ev.detail.value;
this._updatePath();
}
@ -389,7 +501,7 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
.filters {
display: flex;
align-items: flex-end;
align-items: flex-start;
padding: 8px 16px 0;
}
@ -429,9 +541,21 @@ class HaPanelHistory extends SubscribeMixin(LitElement) {
max-width: none;
width: 100%;
}
.start-search {
padding-top: 16px;
text-align: center;
color: var(--secondary-text-color);
}
`,
];
}
}
customElements.define("ha-panel-history", HaPanelHistory);
declare global {
interface HTMLElementTagNameMap {
"ha-panel-history": HaPanelHistory;
}
}

View File

@ -1593,7 +1593,6 @@
"copy_github": "For GitHub",
"description": "Version, loaded integrations and links to documentation",
"home_assistant_logo": "Home Assistant logo",
"path_configuration": "Path to configuration.yaml: {path}",
"developed_by": "Developed by a bunch of awesome people.",
"license": "Published under the Apache 2.0 license",
"source": "Source:",
@ -4012,7 +4011,8 @@
"month": "Month",
"year": "Year",
"previous": "Previous",
"next": "Next"
"next": "Next",
"compare": "Compare Data"
}
},
"reload_lovelace": "Reload UI"
@ -4537,6 +4537,9 @@
}
},
"energy": {
"compare": {
"info": "You are comparing the period {start} with the period {end}"
},
"setup": {
"next": "Next",
"back": "Back",
@ -4556,6 +4559,11 @@
"energy_sources_table_title": "Sources",
"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": {

View File

@ -2975,17 +2975,17 @@ __metadata:
languageName: node
linkType: hard
"@mdi/js@npm:6.7.96":
version: 6.7.96
resolution: "@mdi/js@npm:6.7.96"
checksum: 8c8f6acb8fd3f856a92ffe2405e258ee5aa84cf541fda1c0a564c9c8bbf935cf2b6a6100cf97d41e9ada1ccb59e4b138d4c712e075f759d7595e21ef1cff84b5
"@mdi/js@npm:6.9.96":
version: 6.9.96
resolution: "@mdi/js@npm:6.9.96"
checksum: 94c43271585981e7ebf8cc5e3ead11915eea1339b79e849b351fbaae58e9626aaca0a8b031f0e80754d880ea6b08fd715906588f3cf980603bb5f6871bff12cc
languageName: node
linkType: hard
"@mdi/svg@npm:6.7.96":
version: 6.7.96
resolution: "@mdi/svg@npm:6.7.96"
checksum: 959332009b8833d0347e2dfac86028362a6d11996db850025b7da8c493d7fd341a14d8716ef775dd2ed0492158c77236bcf09adfc4ae77b31044a0a8a26fc74b
"@mdi/svg@npm:6.9.96":
version: 6.9.96
resolution: "@mdi/svg@npm:6.9.96"
checksum: 3e45f9a6632b0aa22f02ab0023d44131e3aea308bae85160445fe1f8f0b6d61df5c01e2756d18bd1461f7314fbf7c00a397bf99670f55803d90de5fa8e3fe33e
languageName: node
linkType: hard
@ -9047,8 +9047,8 @@ fsevents@^1.2.7:
"@material/mwc-textfield": 0.25.3
"@material/mwc-top-app-bar-fixed": ^0.25.3
"@material/top-app-bar": 14.0.0-canary.261f2db59.0
"@mdi/js": 6.7.96
"@mdi/svg": 6.7.96
"@mdi/js": 6.9.96
"@mdi/svg": 6.9.96
"@open-wc/dev-server-hmr": ^0.0.2
"@polymer/app-layout": ^3.1.0
"@polymer/iron-flex-layout": ^3.0.1