Merge pull request #10154 from home-assistant/dev

This commit is contained in:
Bram Kragten 2021-10-05 00:00:33 +02:00 committed by GitHub
commit 5e52bd905d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 308 additions and 95 deletions

View File

@ -107,6 +107,7 @@ export class DemoHaAlert extends LitElement {
protected render(): TemplateResult { protected render(): TemplateResult {
return html` return html`
<ha-card header="ha-alert demo"> <ha-card header="ha-alert demo">
<div class="card-content">
${alerts.map( ${alerts.map(
(alert) => html` (alert) => html`
<ha-alert <ha-alert
@ -120,6 +121,7 @@ export class DemoHaAlert extends LitElement {
</ha-alert> </ha-alert>
` `
)} )}
</div>
</ha-card> </ha-card>
`; `;
} }
@ -130,6 +132,10 @@ export class DemoHaAlert extends LitElement {
max-width: 600px; max-width: 600px;
margin: 24px auto; margin: 24px auto;
} }
ha-alert {
display: block;
margin: 24px 0;
}
.condition { .condition {
padding: 16px; padding: 16px;
display: flex; display: flex;

View File

@ -64,8 +64,8 @@
"@material/mwc-tab": "0.25.1", "@material/mwc-tab": "0.25.1",
"@material/mwc-tab-bar": "0.25.1", "@material/mwc-tab-bar": "0.25.1",
"@material/top-app-bar": "13.0.0-canary.65125b3a6.0", "@material/top-app-bar": "13.0.0-canary.65125b3a6.0",
"@mdi/js": "6.1.95", "@mdi/js": "6.2.95",
"@mdi/svg": "6.1.95", "@mdi/svg": "6.2.95",
"@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",
@ -108,7 +108,7 @@
"deep-freeze": "^0.0.1", "deep-freeze": "^0.0.1",
"fuse.js": "^6.0.0", "fuse.js": "^6.0.0",
"google-timezones-json": "^1.0.2", "google-timezones-json": "^1.0.2",
"hls.js": "^1.0.10", "hls.js": "^1.0.11",
"home-assistant-js-websocket": "^5.11.1", "home-assistant-js-websocket": "^5.11.1",
"idb-keyval": "^5.1.3", "idb-keyval": "^5.1.3",
"intl-messageformat": "^9.9.1", "intl-messageformat": "^9.9.1",

View File

@ -2,7 +2,7 @@ from setuptools import setup, find_packages
setup( setup(
name="home-assistant-frontend", name="home-assistant-frontend",
version="20211002.0", version="20211004.0",
description="The Home Assistant frontend", description="The Home Assistant frontend",
url="https://github.com/home-assistant/frontend", url="https://github.com/home-assistant/frontend",
author="The Home Assistant Authors", author="The Home Assistant Authors",

View File

@ -56,7 +56,11 @@ const getColor = (
entityState: HassEntity, entityState: HassEntity,
computedStyles: CSSStyleDeclaration computedStyles: CSSStyleDeclaration
) => { ) => {
if (invertOnOff(entityState)) { // Inversion is only valid for "on" or "off" state
if (
(stateString === "on" || stateString === "off") &&
invertOnOff(entityState)
) {
stateString = stateString === "on" ? "off" : "on"; stateString = stateString === "on" ? "off" : "on";
} }
if (stateColorMap.has(stateString)) { if (stateColorMap.has(stateString)) {

View File

@ -51,15 +51,11 @@ class HaAlert extends LitElement {
[this.alertType]: true, [this.alertType]: true,
})}" })}"
> >
<div class="icon"> <div class="icon ${this.title ? "" : "no-title"}">
<ha-svg-icon .path=${ALERT_ICONS[this.alertType]}></ha-svg-icon> <ha-svg-icon .path=${ALERT_ICONS[this.alertType]}></ha-svg-icon>
</div> </div>
<div class="content"> <div class="content">
<div <div class="main-content">
class="main-content ${classMap({
"no-title": !this.title,
})}"
>
${this.title ? html`<div class="title">${this.title}</div>` : ""} ${this.title ? html`<div class="title">${this.title}</div>` : ""}
<slot></slot> <slot></slot>
</div> </div>
@ -94,7 +90,7 @@ class HaAlert extends LitElement {
static styles = css` static styles = css`
.issue-type { .issue-type {
position: relative; position: relative;
padding: 4px; padding: 8px;
display: flex; display: flex;
margin: 4px 0; margin: 4px 0;
} }
@ -113,11 +109,16 @@ class HaAlert extends LitElement {
border-radius: 4px; border-radius: 4px;
} }
.icon { .icon {
margin: 4px 8px; margin-right: 8px;
width: 24px; width: 24px;
} }
.main-content.no-title { .icon.no-title {
margin-top: 6px; align-self: center;
}
.issue-type.rtl > .icon {
margin-right: 0px;
margin-left: 8px;
width: 24px;
} }
.issue-type.rtl > .content { .issue-type.rtl > .content {
flex-direction: row-reverse; flex-direction: row-reverse;
@ -126,24 +127,22 @@ class HaAlert extends LitElement {
.content { .content {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center;
width: 100%; width: 100%;
} }
.main-content { .main-content {
overflow-wrap: anywhere; overflow-wrap: anywhere;
} }
.title { .title {
margin-top: 2px;
font-weight: bold; font-weight: bold;
margin-top: 6px;
} }
mwc-button { mwc-button {
--mdc-theme-primary: var(--primary-text-color); --mdc-theme-primary: var(--primary-text-color);
} }
mwc-icon-button {
.action { --mdc-icon-button-size: 36px;
align-self: center;
} }
.issue-type.info > .icon { .issue-type.info > .icon {
color: var(--info-color); color: var(--info-color);
} }

View File

@ -12,6 +12,8 @@ import type {
HaFormStringSchema, HaFormStringSchema,
} from "./ha-form"; } from "./ha-form";
const MASKED_FIELDS = ["password", "secret", "token"];
@customElement("ha-form-string") @customElement("ha-form-string")
export class HaFormString extends LitElement implements HaFormElement { export class HaFormString extends LitElement implements HaFormElement {
@property() public schema!: HaFormStringSchema; @property() public schema!: HaFormStringSchema;
@ -33,7 +35,7 @@ export class HaFormString extends LitElement implements HaFormElement {
} }
protected render(): TemplateResult { protected render(): TemplateResult {
return this.schema.name.includes("password") return MASKED_FIELDS.some((field) => this.schema.name.includes(field))
? html` ? html`
<paper-input <paper-input
.type=${this._unmaskedPassword ? "text" : "password"} .type=${this._unmaskedPassword ? "text" : "password"}

View File

@ -77,18 +77,42 @@ export interface StatisticsMetaData {
} }
export type StatisticsValidationResult = export type StatisticsValidationResult =
| StatisticsValidationResultUnsupportedUnit | StatisticsValidationResultEntityNotRecorded
| StatisticsValidationResultUnitsChanged; | StatisticsValidationResultUnsupportedStateClass
| StatisticsValidationResultUnitsChanged
| StatisticsValidationResultUnsupportedUnitMetadata
| StatisticsValidationResultUnsupportedUnitState;
export interface StatisticsValidationResultUnsupportedUnit { export interface StatisticsValidationResultEntityNotRecorded {
type: "unsupported_unit"; type: "entity_not_recorded";
data: { statistic_id: string; device_class: string; state_unit: string }; data: { statistic_id: string };
}
export interface StatisticsValidationResultUnsupportedStateClass {
type: "unsupported_state_class";
data: { statistic_id: string; state_class: string };
} }
export interface StatisticsValidationResultUnitsChanged { export interface StatisticsValidationResultUnitsChanged {
type: "units_changed"; type: "units_changed";
data: { statistic_id: string; state_unit: string; metadata_unit: string }; data: { statistic_id: string; state_unit: string; metadata_unit: string };
} }
export interface StatisticsValidationResultUnsupportedUnitMetadata {
type: "unsupported_unit_metadata";
data: {
statistic_id: string;
device_class: string;
metadata_unit: string;
supported_unit: string;
};
}
export interface StatisticsValidationResultUnsupportedUnitState {
type: "unsupported_unit_state";
data: { statistic_id: string; device_class: string; metadata_unit: string };
}
export interface StatisticsValidationResults { export interface StatisticsValidationResults {
[statisticId: string]: StatisticsValidationResult[]; [statisticId: string]: StatisticsValidationResult[];
} }

View File

@ -59,7 +59,7 @@ declare global {
class HaOnboarding extends litLocalizeLiteMixin(HassElement) { class HaOnboarding extends litLocalizeLiteMixin(HassElement) {
@property({ attribute: false }) public hass?: HomeAssistant; @property({ attribute: false }) public hass?: HomeAssistant;
public translationFragment = "page-onboarding"; @property() public translationFragment = "page-onboarding";
@state() private _loading = false; @state() private _loading = false;

View File

@ -17,7 +17,15 @@ import { showAlertDialog } from "../../../dialogs/generic/show-dialog-box";
import { haStyle } from "../../../resources/styles"; import { haStyle } from "../../../resources/styles";
import { HomeAssistant } from "../../../types"; import { HomeAssistant } from "../../../types";
import { showFixStatisticsUnitsChangedDialog } from "./show-dialog-statistics-fix-units-changed"; import { showFixStatisticsUnitsChangedDialog } from "./show-dialog-statistics-fix-units-changed";
import { showFixStatisticsUnsupportedUnitMetadataDialog } from "./show-dialog-statistics-fix-unsupported-unit-meta";
const FIX_ISSUES_ORDER = {
entity_not_recorded: 1,
unsupported_unit_state: 2,
unsupported_state_class: 3,
units_changed: 4,
unsupported_unit_metadata: 5,
};
@customElement("developer-tools-statistics") @customElement("developer-tools-statistics")
class HaPanelDevStatistics extends LitElement { class HaPanelDevStatistics extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant; @property({ attribute: false }) public hass!: HomeAssistant;
@ -119,49 +127,116 @@ class HaPanelDevStatistics extends LitElement {
validateStatistics(this.hass), validateStatistics(this.hass),
]); ]);
this._data = statisticIds.map((statistic) => ({ const statsIds = new Set();
this._data = statisticIds.map((statistic) => {
statsIds.add(statistic.statistic_id);
return {
...statistic, ...statistic,
state: this.hass.states[statistic.statistic_id], state: this.hass.states[statistic.statistic_id],
issues: issues[statistic.statistic_id], issues: issues[statistic.statistic_id],
})); };
});
Object.keys(issues).forEach((statisticId) => {
if (!statsIds.has(statisticId)) {
this._data.push({
statistic_id: statisticId,
unit_of_measurement: "",
state: this.hass.states[statisticId],
issues: issues[statisticId],
});
}
});
} }
private _fixIssue(ev) { private _fixIssue(ev) {
const issue = ev.currentTarget.data[0] as StatisticsValidationResult; const issues = (ev.currentTarget.data as StatisticsValidationResult[]).sort(
if (issue.type === "unsupported_unit") { (itemA, itemB) =>
(FIX_ISSUES_ORDER[itemA.type] ?? 99) -
(FIX_ISSUES_ORDER[itemB.type] ?? 99)
);
const issue = issues[0];
switch (issue.type) {
case "entity_not_recorded":
showAlertDialog(this, {
title: "Entity not recorded",
text: html`State changes of this entity are not recorded, therefore,
we can not track long term statistics for it. <br /><br />You
probably excluded this entity, or have just included some
entities.<br /><br />See the
<a
href="https://www.home-assistant.io/integrations/recorder/#configure-filter"
target="_blank"
rel="noreferrer noopener"
>
recorder documentation</a
>
for more information.`,
});
break;
case "unsupported_state_class":
showAlertDialog(this, {
title: "Unsupported state class",
text: html`The state class of this entity, ${issue.data.state_class}
is not supported. <br />Statistics can not be generated until this
entity has a supported state class.<br /><br />If this state class
was provided by an integration, this is a bug. Please report an
issue.<br /><br />If you have set this state class yourself, please
correct it. The different state classes and when to use which can be
found in the
<a
href="https://developers.home-assistant.io/docs/core/entity/sensor/#long-term-statistics"
target="_blank"
rel="noreferrer noopener"
>
developer documentation</a
>.`,
});
break;
case "unsupported_unit_metadata":
showFixStatisticsUnsupportedUnitMetadataDialog(this, {
issue,
fixedCallback: () => {
this._validateStatistics();
},
});
break;
case "unsupported_unit_state":
showAlertDialog(this, { showAlertDialog(this, {
title: "Unsupported unit", title: "Unsupported unit",
text: html`The unit of your entity is not a supported unit for the text: html`The unit of your entity is not a supported unit for the
device class of the entity, ${issue.data.device_class}. device class of the entity, ${issue.data.device_class}.
<br />Statistics can not be generated until this entity has a <br />Statistics can not be generated until this entity has a
supported unit.<br /><br />If this unit was provided by an supported unit.<br /><br />If this unit was provided by an
integration, this is a bug. Please report an issue.<br /><br />If you integration, this is a bug. Please report an issue.<br /><br />If
have set this unit yourself, and want to have statistics generated, you have set this unit yourself, and want to have statistics
make sure the unit matched the device class. The supported units are generated, make sure the unit matches the device class. The
documented in the supported units are documented in the
<a <a
href="https://developers.home-assistant.io/docs/core/entity/sensor" href="https://developers.home-assistant.io/docs/core/entity/sensor/#available-device-classes"
target="_blank" target="_blank"
rel="noreferrer noopener"
> >
developer documentation</a developer documentation</a
>.`, >.`,
}); });
return; break;
} case "units_changed":
if (issue.type === "units_changed") {
showFixStatisticsUnitsChangedDialog(this, { showFixStatisticsUnitsChangedDialog(this, {
issue, issue,
fixedCallback: () => { fixedCallback: () => {
this._validateStatistics(); this._validateStatistics();
}, },
}); });
return; break;
} default:
showAlertDialog(this, { showAlertDialog(this, {
title: "Fix issue", title: "Fix issue",
text: "Fixing this issue is not supported yet.", text: "Fixing this issue is not supported yet.",
}); });
} }
}
static get styles(): CSSResultGroup { static get styles(): CSSResultGroup {
return [ return [

View File

@ -0,0 +1,79 @@
import "@material/mwc-button/mwc-button";
import { LitElement, TemplateResult, html, CSSResultGroup } from "lit";
import { customElement, property, state } from "lit/decorators";
import "../../../components/ha-dialog";
import { fireEvent } from "../../../common/dom/fire_event";
import { haStyle, haStyleDialog } from "../../../resources/styles";
import { HomeAssistant } from "../../../types";
import { updateStatisticsMetadata } from "../../../data/history";
import "../../../components/ha-formfield";
import "../../../components/ha-radio";
import { DialogStatisticsUnsupportedUnitMetaParams } from "./show-dialog-statistics-fix-unsupported-unit-meta";
@customElement("dialog-statistics-fix-unsupported-unit-meta")
export class DialogStatisticsFixUnsupportedUnitMetadata extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@state() private _params?: DialogStatisticsUnsupportedUnitMetaParams;
public showDialog(params: DialogStatisticsUnsupportedUnitMetaParams): void {
this._params = params;
}
public closeDialog(): void {
this._params = undefined;
fireEvent(this, "dialog-closed", { dialog: this.localName });
}
protected render(): TemplateResult | void {
if (!this._params) {
return html``;
}
return html`
<ha-dialog
open
@closed=${this.closeDialog}
heading="Unsupported unit in recorded statistics"
>
<p>
The unit of the statistics in your database for this entity is not a
supported unit for the device class of the entity,
${this._params.issue.data.device_class}. It should be
${this._params.issue.data.supported_unit}.
</p>
<p>
Do you want to update the unit of the history statistics to
${this._params.issue.data.supported_unit}?
</p>
<mwc-button slot="primaryAction" @click=${this._fixIssue}>
Fix
</mwc-button>
<mwc-button slot="secondaryAction" @click=${this.closeDialog}>
${this.hass.localize("ui.common.close")}
</mwc-button>
</ha-dialog>
`;
}
private async _fixIssue(): Promise<void> {
await updateStatisticsMetadata(
this.hass,
this._params!.issue.data.statistic_id,
this._params!.issue.data.supported_unit
);
this._params?.fixedCallback();
this.closeDialog();
}
static get styles(): CSSResultGroup {
return [haStyle, haStyleDialog];
}
}
declare global {
interface HTMLElementTagNameMap {
"dialog-statistics-fix-unsupported-unit-meta": DialogStatisticsFixUnsupportedUnitMetadata;
}
}

View File

@ -0,0 +1,21 @@
import { fireEvent } from "../../../common/dom/fire_event";
import { StatisticsValidationResultUnsupportedUnitMetadata } from "../../../data/history";
export const loadFixUnsupportedUnitMetaDialog = () =>
import("./dialog-statistics-fix-unsupported-unit-meta");
export interface DialogStatisticsUnsupportedUnitMetaParams {
issue: StatisticsValidationResultUnsupportedUnitMetadata;
fixedCallback: () => void;
}
export const showFixStatisticsUnsupportedUnitMetadataDialog = (
element: HTMLElement,
detailParams: DialogStatisticsUnsupportedUnitMetaParams
): void => {
fireEvent(element, "show-dialog", {
dialogTag: "dialog-statistics-fix-unsupported-unit-meta",
dialogImport: loadFixUnsupportedUnitMetaDialog,
dialogParams: detailParams,
});
};

View File

@ -3728,7 +3728,10 @@
"issue": "Issue", "issue": "Issue",
"issues": { "issues": {
"units_changed": "The unit of this entity changed from ''{metadata_unit}'' to ''{state_unit}''.", "units_changed": "The unit of this entity changed from ''{metadata_unit}'' to ''{state_unit}''.",
"unsupported_unit": "The unit (''{state_unit}'') of this entity doesn't match a unit of device class ''{device_class}''." "unsupported_unit_state": "The unit (''{state_unit}'') of this entity doesn't match a unit of device class ''{device_class}''.",
"unsupported_unit_metadata": "The unit (''{state_unit}'') of the recorded statistics doesn't match a unit of device class ''{device_class}''.",
"unsupported_state_class": "The state class ''{state_class}'' of this entity is not supported.",
"entity_not_recorded": "This entity is excluded from being recorded."
}, },
"fix_issue": { "fix_issue": {
"units_changed": { "units_changed": {

View File

@ -2783,17 +2783,17 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@mdi/js@npm:6.1.95": "@mdi/js@npm:6.2.95":
version: 6.1.95 version: 6.2.95
resolution: "@mdi/js@npm:6.1.95" resolution: "@mdi/js@npm:6.2.95"
checksum: 318899617da78956ae1e0650b83be65aa459f7fdb9f45212fe081776016e3b9881d1cf03458f65a5d86a99c3387caad0d87828808bca87e21db7e69706337016 checksum: 85f33d0bbb0665ef048dbcae8759eb7b17db35594f1e471c71946fb36ea8416d3c21b3a1013bb587c7293f2c84d97af6ed791a6904625abdae7ec96a75569e5e
languageName: node languageName: node
linkType: hard linkType: hard
"@mdi/svg@npm:6.1.95": "@mdi/svg@npm:6.2.95":
version: 6.1.95 version: 6.2.95
resolution: "@mdi/svg@npm:6.1.95" resolution: "@mdi/svg@npm:6.2.95"
checksum: 55e522e1758509f9a293600b0fdd6fd874aaefe8c4a404391fe11c178b24afd7a37601775af846776ac60899c03d74e39a5e061615bc65918bef8679b3dea968 checksum: c2f14e8b62ae4c31da84af44d13f02b050c9a7759e20f08c9088996b2cafea5ff372c89795d57e976d8a693034964dad8f65bc75eea02834d1d8784e2e22627e
languageName: node languageName: node
linkType: hard linkType: hard
@ -8915,10 +8915,10 @@ fsevents@^1.2.7:
languageName: node languageName: node
linkType: hard linkType: hard
"hls.js@npm:^1.0.10": "hls.js@npm:^1.0.11":
version: 1.0.10 version: 1.0.11
resolution: "hls.js@npm:1.0.10" resolution: "hls.js@npm:1.0.11"
checksum: 56fb2729a55a68a384e3fbba4a6146702533896ac467d556afeefa12c315d64d68c2a21673d345ebacf392172ad7e8429f597a12ed90d2506b77a3093d05e596 checksum: 0375871cf8ffef3374f44284028d235bb122dc5ee2a36b765124e8caca1ec97ba96738ef8de261fbdecf78669e7bf3fb8aee1070f239c7791add44fad50df180
languageName: node languageName: node
linkType: hard linkType: hard
@ -8982,8 +8982,8 @@ fsevents@^1.2.7:
"@material/mwc-tab": 0.25.1 "@material/mwc-tab": 0.25.1
"@material/mwc-tab-bar": 0.25.1 "@material/mwc-tab-bar": 0.25.1
"@material/top-app-bar": 13.0.0-canary.65125b3a6.0 "@material/top-app-bar": 13.0.0-canary.65125b3a6.0
"@mdi/js": 6.1.95 "@mdi/js": 6.2.95
"@mdi/svg": 6.1.95 "@mdi/svg": 6.2.95
"@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
@ -9067,7 +9067,7 @@ fsevents@^1.2.7:
gulp-merge-json: ^1.3.1 gulp-merge-json: ^1.3.1
gulp-rename: ^2.0.0 gulp-rename: ^2.0.0
gulp-zopfli-green: ^3.0.1 gulp-zopfli-green: ^3.0.1
hls.js: ^1.0.10 hls.js: ^1.0.11
home-assistant-js-websocket: ^5.11.1 home-assistant-js-websocket: ^5.11.1
html-minifier: ^4.0.0 html-minifier: ^4.0.0
husky: ^1.3.1 husky: ^1.3.1