diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 207b186d35..411ffee836 100755 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,7 +1,7 @@ { "recommendations": [ "dbaeumer.vscode-eslint", - "eg2.tslint", + "ms-vscode.vscode-typescript-tslint-plugin", "esbenp.prettier-vscode", "bierner.lit-html", "runem.lit-plugin" diff --git a/setup.py b/setup.py index 65ef259734..a1add8ada4 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup( name="home-assistant-frontend", - version="20190216.0", + version="20190218.0", description="The Home Assistant frontend", url="https://github.com/home-assistant/home-assistant-polymer", author="The Home Assistant Authors", diff --git a/src/cards/ha-persistent_notification-card.js b/src/cards/ha-persistent_notification-card.js index bea39bbf97..95cf52845f 100644 --- a/src/cards/ha-persistent_notification-card.js +++ b/src/cards/ha-persistent_notification-card.js @@ -40,7 +40,6 @@ class HaPersistentNotificationCard extends LocalizeMixin(PolymerElement) { } mwc-button { margin: 8px; - font-weight: 500; } diff --git a/src/components/ha-sidebar.ts b/src/components/ha-sidebar.ts index 82cf0585ab..6e6d5fc658 100644 --- a/src/components/ha-sidebar.ts +++ b/src/components/ha-sidebar.ts @@ -83,7 +83,7 @@ class HaSidebar extends LitElement { ${hass.user ? html` - + ` : ""} diff --git a/src/components/ha-vacuum-state.js b/src/components/ha-vacuum-state.js index 5dc82224dd..556dac2619 100644 --- a/src/components/ha-vacuum-state.js +++ b/src/components/ha-vacuum-state.js @@ -39,8 +39,6 @@ class HaVacuumState extends LocalizeMixin(PolymerElement) { return html`
diff --git a/src/panels/config/config-entries/ha-config-entries-dashboard.js b/src/panels/config/config-entries/ha-config-entries-dashboard.js index c89e5f3b7f..276e8eb74e 100644 --- a/src/panels/config/config-entries/ha-config-entries-dashboard.js +++ b/src/panels/config/config-entries/ha-config-entries-dashboard.js @@ -30,8 +30,6 @@ class HaConfigManagerDashboard extends LocalizeMixin( return html` + static get styles(): CSSResult { + return css` + ha-card { + --base-unit: 50px; + height: calc(var(--base-unit) * 3); + position: relative; + cursor: pointer; + } + .container { + width: calc(var(--base-unit) * 4); + height: calc(var(--base-unit) * 2); + position: absolute; + top: calc(var(--base-unit) * 1.5); + left: 50%; + overflow: hidden; + text-align: center; + transform: translate(-50%, -50%); + } + .gauge-a { + z-index: 1; + position: absolute; + background-color: var(--primary-background-color); + width: calc(var(--base-unit) * 4); + height: calc(var(--base-unit) * 2); + top: 0%; + border-radius: calc(var(--base-unit) * 2.5) calc(var(--base-unit) * 2.5) + 0px 0px; + } + .gauge-b { + z-index: 3; + position: absolute; + background-color: var(--paper-card-background-color); + width: calc(var(--base-unit) * 2.5); + height: calc(var(--base-unit) * 1.25); + top: calc(var(--base-unit) * 0.75); + margin-left: calc(var(--base-unit) * 0.75); + margin-right: auto; + border-radius: calc(var(--base-unit) * 2.5) calc(var(--base-unit) * 2.5) + 0px 0px; + } + .gauge-c { + z-index: 2; + position: absolute; + background-color: var(--label-badge-blue); + width: calc(var(--base-unit) * 4); + height: calc(var(--base-unit) * 2); + top: calc(var(--base-unit) * 2); + margin-left: auto; + margin-right: auto; + border-radius: 0px 0px calc(var(--base-unit) * 2) + calc(var(--base-unit) * 2); + transform-origin: center top; + } + .init .gauge-c { + transition: all 1.3s ease-in-out; + } + .gauge-data { + z-index: 4; + color: var(--primary-text-color); + line-height: calc(var(--base-unit) * 0.3); + position: absolute; + width: calc(var(--base-unit) * 4); + height: calc(var(--base-unit) * 2.1); + top: calc(var(--base-unit) * 1.2); + margin-left: auto; + margin-right: auto; + } + .init .gauge-data { + transition: all 1s ease-out; + } + .gauge-data #percent { + font-size: calc(var(--base-unit) * 0.55); + } + .gauge-data #name { + padding-top: calc(var(--base-unit) * 0.15); + font-size: calc(var(--base-unit) * 0.3); + } `; } } diff --git a/src/panels/lovelace/cards/hui-glance-card.ts b/src/panels/lovelace/cards/hui-glance-card.ts index 81e448d056..820ca06f48 100644 --- a/src/panels/lovelace/cards/hui-glance-card.ts +++ b/src/panels/lovelace/cards/hui-glance-card.ts @@ -13,6 +13,7 @@ import { LovelaceCardConfig, ActionConfig } from "../../../data/lovelace"; import { longPress } from "../common/directives/long-press-directive"; import { EntityConfig } from "../entity-rows/types"; import { processConfigEntities } from "../common/process-config-entities"; +import { handleClick } from "../common/handle-click"; import computeStateDisplay from "../../../common/entity/compute_state_display"; import computeStateName from "../../../common/entity/compute_state_name"; @@ -21,7 +22,7 @@ import applyThemesOnElement from "../../../common/dom/apply_themes_on_element"; import "../../../components/entity/state-badge"; import "../../../components/ha-card"; import "../../../components/ha-icon"; -import { handleClick } from "../common/handle-click"; +import "../components/hui-warning"; export interface ConfigEntity extends EntityConfig { tap_action?: ActionConfig; @@ -176,10 +177,6 @@ export class HuiGlanceCard extends LitElement implements LovelaceCard { state-badge { margin: 8px 0; } - .not-found { - background-color: yellow; - text-align: center; - } `; } @@ -189,10 +186,13 @@ export class HuiGlanceCard extends LitElement implements LovelaceCard { if (!stateObj) { return html` -
-
${entityConf.entity}
- Entity Not Available -
+ ${this.hass!.localize( + "ui.panel.lovelace.warning.entity_not_found", + "entity", + entityConf.entity + )} `; } diff --git a/src/panels/lovelace/cards/hui-light-card.ts b/src/panels/lovelace/cards/hui-light-card.ts index 785eb339e2..7e30776ef1 100644 --- a/src/panels/lovelace/cards/hui-light-card.ts +++ b/src/panels/lovelace/cards/hui-light-card.ts @@ -22,6 +22,7 @@ import applyThemesOnElement from "../../../common/dom/apply_themes_on_element"; import "../../../components/ha-card"; import "../../../components/ha-icon"; +import "../components/hui-warning"; const lightConfig = { radius: 80, @@ -78,41 +79,45 @@ export class HuiLightCard extends LitElement implements LovelaceCard { const stateObj = this.hass.states[this._config!.entity] as LightEntity; + if (!stateObj) { + return html` + ${this.hass.localize( + "ui.panel.lovelace.warning.entity_not_found", + "entity", + this._config.entity + )} + `; + } + return html` ${this.renderStyle()} - ${!stateObj - ? html` -
- Entity not available: ${this._config.entity} -
- ` - : html` - -
-
-
- -
-
- ${this._config.name || computeStateName(stateObj)} -
-
-
- `} + +
+
+
+ +
+
+ ${this._config.name || computeStateName(stateObj)} +
+
+
`; } @@ -272,11 +277,6 @@ export class HuiLightCard extends LitElement implements LovelaceCard { .show_brightness { opacity: 1; } - .not-found { - flex: 1; - background-color: yellow; - padding: 8px; - } .more-info { position: absolute; cursor: pointer; diff --git a/src/panels/lovelace/cards/hui-picture-entity-card.ts b/src/panels/lovelace/cards/hui-picture-entity-card.ts index b3a20c9523..9fa618a6a0 100644 --- a/src/panels/lovelace/cards/hui-picture-entity-card.ts +++ b/src/panels/lovelace/cards/hui-picture-entity-card.ts @@ -8,6 +8,7 @@ import { classMap } from "lit-html/directives/class-map"; import "../../../components/ha-card"; import "../components/hui-image"; +import "../components/hui-warning"; import computeDomain from "../../../common/entity/compute_domain"; import computeStateDisplay from "../../../common/entity/compute_state_display"; @@ -19,10 +20,6 @@ import { LovelaceCardConfig, ActionConfig } from "../../../data/lovelace"; import { LovelaceCard } from "../types"; import { handleClick } from "../common/handle-click"; import { UNAVAILABLE } from "../../../data/entity"; -import { - createErrorCardElement, - createErrorCardConfig, -} from "./hui-error-card"; interface Config extends LovelaceCardConfig { entity: string; @@ -76,12 +73,13 @@ class HuiPictureEntityCard extends LitElement implements LovelaceCard { if (!stateObj) { return html` - ${createErrorCardElement( - createErrorCardConfig( - `Entity not found: ${this._config.entity}`, - this._config - ) - )} + ${this.hass.localize( + "ui.panel.lovelace.warning.entity_not_found", + "entity", + this._config.entity + )} `; } diff --git a/src/panels/lovelace/cards/hui-sensor-card.ts b/src/panels/lovelace/cards/hui-sensor-card.ts index 6bc8630dcf..8dbdab4fea 100644 --- a/src/panels/lovelace/cards/hui-sensor-card.ts +++ b/src/panels/lovelace/cards/hui-sensor-card.ts @@ -12,6 +12,7 @@ import { LovelaceCard, LovelaceCardEditor } from "../types"; import { LovelaceCardConfig } from "../../../data/lovelace"; import { HomeAssistant } from "../../../types"; import { fireEvent } from "../../../common/dom/fire_event"; +import { fetchRecent } from "../../../data/history"; import applyThemesOnElement from "../../../common/dom/apply_themes_on_element"; import computeStateName from "../../../common/entity/compute_state_name"; @@ -19,7 +20,7 @@ import stateIcon from "../../../common/entity/state_icon"; import "../../../components/ha-card"; import "../../../components/ha-icon"; -import { fetchRecent } from "../../../data/history"; +import "../components/hui-warning"; const midPoint = ( _Ax: number, @@ -199,15 +200,27 @@ class HuiSensorCard extends LitElement implements LovelaceCard { const stateObj = this.hass.states[this._config.entity]; + if (!stateObj) { + return html` + ${this.hass.localize( + "ui.panel.lovelace.warning.entity_not_found", + "entity", + this._config.entity + )} + `; + } + let graph; if (stateObj && this._config.graph === "line") { if (!stateObj.attributes.unit_of_measurement) { - graph = html` -
- Entity: ${this._config.entity} - Has no Unit of Measurement and - therefore can not display a line graph. -
+ return html` + Entity: ${this._config.entity} - Has no Unit of Measurement and + therefore can not display a line graph. `; } else if (!this._history) { graph = svg` @@ -233,34 +246,26 @@ class HuiSensorCard extends LitElement implements LovelaceCard { return html` ${this.renderStyle()} - ${!stateObj - ? html` -
- Entity not available: ${this._config.entity} -
- ` - : html` -
-
- -
-
- ${this._config.name || computeStateName(stateObj)} -
-
-
- ${stateObj.state} - ${this._config.unit || - stateObj.attributes.unit_of_measurement} -
-
${graph}
- `} +
+
+ +
+
+ ${this._config.name || computeStateName(stateObj)} +
+
+
+ ${stateObj.state} + ${this._config.unit || + stateObj.attributes.unit_of_measurement} +
+
${graph}
`; } @@ -399,11 +404,6 @@ class HuiSensorCard extends LitElement implements LovelaceCard { align-self: flex-end; margin: auto 8px; } - .not-found { - flex: 1; - background-color: yellow; - padding: 8px; - } `; } diff --git a/src/panels/lovelace/cards/hui-thermostat-card.ts b/src/panels/lovelace/cards/hui-thermostat-card.ts index 8ddd773838..21c5d70614 100644 --- a/src/panels/lovelace/cards/hui-thermostat-card.ts +++ b/src/panels/lovelace/cards/hui-thermostat-card.ts @@ -10,6 +10,7 @@ import "@polymer/paper-icon-button/paper-icon-button"; import "../../../components/ha-card"; import "../../../components/ha-icon"; +import "../components/hui-warning"; import applyThemesOnElement from "../../../common/dom/apply_themes_on_element"; import computeStateName from "../../../common/entity/compute_state_name"; @@ -102,16 +103,19 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard { return html``; } const stateObj = this.hass.states[this._config.entity] as ClimateEntity; + if (!stateObj) { return html` - ${this.renderStyle()} - -
- Entity not available: ${this._config.entity} -
-
+ ${this.hass.localize( + "ui.panel.lovelace.warning.entity_not_found", + "entity", + this._config.entity + )} `; } + const mode = modeIcons[stateObj.attributes.operation_mode || ""] ? stateObj.attributes.operation_mode! : "unknown-mode"; @@ -280,7 +284,10 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard { ); } else { sliderValue = stateObj.attributes.temperature; - uiValue = "" + stateObj.attributes.temperature; + uiValue = + stateObj.attributes.temperature !== null + ? String(stateObj.attributes.temperature) + : ""; } return [sliderValue, uiValue]; @@ -384,11 +391,6 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard { --idle-color: #8a8a8a; --unknown-color: #bac; } - .not-found { - flex: 1; - background-color: yellow; - padding: 8px; - } #root { position: relative; overflow: hidden; diff --git a/src/panels/lovelace/components/hui-generic-entity-row.ts b/src/panels/lovelace/components/hui-generic-entity-row.ts index d9916ffe69..03ecc5ef08 100644 --- a/src/panels/lovelace/components/hui-generic-entity-row.ts +++ b/src/panels/lovelace/components/hui-generic-entity-row.ts @@ -1,7 +1,3 @@ -import "../../../components/entity/state-badge"; -import "../../../components/ha-relative-time"; -import "../../../components/ha-icon"; - import computeStateName from "../../../common/entity/compute_state_name"; import { LitElement, @@ -11,10 +7,16 @@ import { PropertyValues, property, } from "lit-element"; + import { HomeAssistant } from "../../../types"; import { EntitiesCardEntityConfig } from "../cards/hui-entities-card"; import { computeRTL } from "../../../common/util/compute_rtl"; +import "../../../components/entity/state-badge"; +import "../../../components/ha-relative-time"; +import "../../../components/ha-icon"; +import "../components/hui-warning"; + class HuiGenericEntityRow extends LitElement { @property() public hass?: HomeAssistant; @property() public config?: EntitiesCardEntityConfig; @@ -30,7 +32,13 @@ class HuiGenericEntityRow extends LitElement { if (!stateObj) { return html` -
Entity not available: [[config.entity]]
+ ${this.hass.localize( + "ui.panel.lovelace.warning.entity_not_found", + "entity", + this.config.entity + )} `; } @@ -107,11 +115,6 @@ class HuiGenericEntityRow extends LitElement { display: block; color: var(--secondary-text-color); } - .not-found { - flex: 1; - background-color: yellow; - padding: 8px; - } state-badge { flex: 0 0 40px; } diff --git a/src/panels/lovelace/components/hui-image.ts b/src/panels/lovelace/components/hui-image.ts index cdc7b06aa1..04a12f34d8 100644 --- a/src/panels/lovelace/components/hui-image.ts +++ b/src/panels/lovelace/components/hui-image.ts @@ -167,15 +167,14 @@ class HuiImage extends LitElement { if (!this.hass || !this.cameraImage) { return; } - if (this._cameraImageSrc) { - URL.revokeObjectURL(this._cameraImageSrc); - this._cameraImageSrc = undefined; - } try { const { content_type: contentType, content } = await fetchThumbnail( this.hass, this.cameraImage ); + if (this._cameraImageSrc) { + URL.revokeObjectURL(this._cameraImageSrc); + } this._cameraImageSrc = URL.createObjectURL( b64toBlob(content, contentType) ); diff --git a/src/panels/lovelace/components/hui-warning.ts b/src/panels/lovelace/components/hui-warning.ts new file mode 100644 index 0000000000..7bbbe1af67 --- /dev/null +++ b/src/panels/lovelace/components/hui-warning.ts @@ -0,0 +1,34 @@ +import { + html, + LitElement, + TemplateResult, + CSSResult, + css, + customElement, +} from "lit-element"; + +@customElement("hui-warning") +export class HuiWarning extends LitElement { + protected render(): TemplateResult | void { + return html` + + `; + } + + static get styles(): CSSResult { + return css` + :host { + display: block; + color: black; + background-color: #fce588; + padding: 8px; + } + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-warning": HuiWarning; + } +} diff --git a/src/panels/lovelace/components/notifications/hui-notifications-button.js b/src/panels/lovelace/components/notifications/hui-notifications-button.js deleted file mode 100644 index 6ecf1ec920..0000000000 --- a/src/panels/lovelace/components/notifications/hui-notifications-button.js +++ /dev/null @@ -1,68 +0,0 @@ -import "@material/mwc-button"; -import "@polymer/paper-icon-button/paper-icon-button"; -import "@polymer/app-layout/app-toolbar/app-toolbar"; - -import { html } from "@polymer/polymer/lib/utils/html-tag"; -import { PolymerElement } from "@polymer/polymer/polymer-element"; - -import EventsMixin from "../../../../mixins/events-mixin"; - -/* - * @appliesMixin EventsMixin - */ -export class HuiNotificationsButton extends EventsMixin(PolymerElement) { - static get template() { - return html` - - - - `; - } - - static get properties() { - return { - open: { - type: Boolean, - notify: true, - }, - notifications: { - type: Array, - value: [], - }, - }; - } - - _clicked() { - this.open = true; - } - - _hasNotifications(notifications) { - return notifications.length > 0; - } -} -customElements.define("hui-notifications-button", HuiNotificationsButton); diff --git a/src/panels/lovelace/components/notifications/hui-notifications-button.ts b/src/panels/lovelace/components/notifications/hui-notifications-button.ts new file mode 100644 index 0000000000..c56d2931a1 --- /dev/null +++ b/src/panels/lovelace/components/notifications/hui-notifications-button.ts @@ -0,0 +1,80 @@ +import { + html, + LitElement, + TemplateResult, + css, + CSSResult, + property, +} from "lit-element"; +import "@polymer/paper-icon-button/paper-icon-button"; +import { fireEvent } from "../../../../common/dom/fire_event"; + +declare global { + // tslint:disable-next-line + interface HASSDomEvents { + "opened-changed": { value: boolean }; + } +} + +class HuiNotificationsButton extends LitElement { + @property() public notifications?: string[]; + @property() public opened?: boolean; + + protected render(): TemplateResult | void { + return html` + + ${this.notifications && this.notifications.length > 0 + ? html` + +
${this.notifications.length}
+
+ ` + : ""} + `; + } + + static get styles(): CSSResult[] { + return [ + css` + :host { + position: relative; + } + + .indicator { + position: absolute; + top: 0px; + right: -3px; + width: 20px; + height: 20px; + border-radius: 50%; + background: var(--accent-color); + pointer-events: none; + z-index: 1; + } + + .indicator > div { + right: 7px; + top: 3px; + position: absolute; + font-size: 0.55em; + } + `, + ]; + } + + private _clicked() { + this.opened = true; + fireEvent(this, "opened-changed", { value: this.opened }); + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-notifications-button": HuiNotificationsButton; + } +} + +customElements.define("hui-notifications-button", HuiNotificationsButton); diff --git a/src/panels/lovelace/entity-rows/hui-climate-entity-row.ts b/src/panels/lovelace/entity-rows/hui-climate-entity-row.ts index d452445d78..9487294b76 100644 --- a/src/panels/lovelace/entity-rows/hui-climate-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-climate-entity-row.ts @@ -1,21 +1,22 @@ -import { html, LitElement, TemplateResult } from "lit-element"; +import { + html, + LitElement, + TemplateResult, + property, + css, + CSSResult, +} from "lit-element"; import "../../../components/ha-climate-state"; import "../components/hui-generic-entity-row"; +import "../components/hui-warning"; import { HomeAssistant } from "../../../types"; import { EntityRow, EntityConfig } from "./types"; class HuiClimateEntityRow extends LitElement implements EntityRow { - public hass?: HomeAssistant; - private _config?: EntityConfig; - - static get properties() { - return { - hass: {}, - _config: {}, - }; - } + @property() public hass?: HomeAssistant; + @property() private _config?: EntityConfig; public setConfig(config: EntityConfig): void { if (!config || !config.entity) { @@ -34,14 +35,17 @@ class HuiClimateEntityRow extends LitElement implements EntityRow { if (!stateObj) { return html` - + ${this.hass.localize( + "ui.panel.lovelace.warning.entity_not_found", + "entity", + this._config.entity + )} `; } return html` - ${this.renderStyle()} - ha-climate-state { - text-align: right; - } - + static get styles(): CSSResult { + return css` + ha-climate-state { + text-align: right; + } `; } } diff --git a/src/panels/lovelace/entity-rows/hui-cover-entity-row.ts b/src/panels/lovelace/entity-rows/hui-cover-entity-row.ts index 2920416d91..148c1614c2 100644 --- a/src/panels/lovelace/entity-rows/hui-cover-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-cover-entity-row.ts @@ -1,29 +1,24 @@ import { html, LitElement, - PropertyDeclarations, TemplateResult, + property, + css, + CSSResult, } from "lit-element"; import "../components/hui-generic-entity-row"; import "../../../components/ha-cover-controls"; import "../../../components/ha-cover-tilt-controls"; -import "./hui-error-entity-row"; +import "../components/hui-warning"; import { isTiltOnly } from "../../../util/cover-model"; import { HomeAssistant } from "../../../types"; import { EntityRow, EntityConfig } from "./types"; class HuiCoverEntityRow extends LitElement implements EntityRow { - public hass?: HomeAssistant; - private _config?: EntityConfig; - - static get properties(): PropertyDeclarations { - return { - hass: {}, - _config: {}, - }; - } + @property() public hass?: HomeAssistant; + @property() private _config?: EntityConfig; public setConfig(config: EntityConfig): void { if (!config) { @@ -41,14 +36,17 @@ class HuiCoverEntityRow extends LitElement implements EntityRow { if (!stateObj) { return html` - + ${this.hass.localize( + "ui.panel.lovelace.warning.entity_not_found", + "entity", + this._config.entity + )} `; } return html` - ${this.renderStyle()} ${isTiltOnly(stateObj) ? html` @@ -67,14 +65,12 @@ class HuiCoverEntityRow extends LitElement implements EntityRow { `; } - private renderStyle(): TemplateResult { - return html` - + static get styles(): CSSResult { + return css` + ha-cover-controls, + ha-cover-tilt-controls { + margin-right: -0.57em; + } `; } } diff --git a/src/panels/lovelace/entity-rows/hui-error-entity-row.ts b/src/panels/lovelace/entity-rows/hui-error-entity-row.ts deleted file mode 100644 index fc0265eddb..0000000000 --- a/src/panels/lovelace/entity-rows/hui-error-entity-row.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { html, LitElement, TemplateResult } from "lit-element"; - -class HuiErrorEntityRow extends LitElement { - public entity?: string; - public error?: string; - - static get properties() { - return { - error: {}, - entity: {}, - }; - } - - protected render(): TemplateResult | void { - return html` - ${this.renderStyle()} ${this.error || "Entity not available"}: - ${this.entity || ""} - `; - } - - private renderStyle(): TemplateResult { - return html` - - `; - } -} - -declare global { - interface HTMLElementTagNameMap { - "hui-error-entity-row": HuiErrorEntityRow; - } -} - -customElements.define("hui-error-entity-row", HuiErrorEntityRow); diff --git a/src/panels/lovelace/entity-rows/hui-group-entity-row.ts b/src/panels/lovelace/entity-rows/hui-group-entity-row.ts index e8afa8acc6..e422037ca6 100644 --- a/src/panels/lovelace/entity-rows/hui-group-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-group-entity-row.ts @@ -1,13 +1,8 @@ -import { - html, - LitElement, - PropertyDeclarations, - TemplateResult, -} from "lit-element"; +import { html, LitElement, TemplateResult, property } from "lit-element"; import "../components/hui-generic-entity-row"; import "../../../components/entity/ha-entity-toggle"; -import "./hui-error-entity-row"; +import "../components/hui-warning"; import computeStateDisplay from "../../../common/entity/compute_state_display"; import { DOMAINS_TOGGLE } from "../../../common/const"; @@ -15,15 +10,8 @@ import { HomeAssistant } from "../../../types"; import { EntityRow, EntityConfig } from "./types"; class HuiGroupEntityRow extends LitElement implements EntityRow { - public hass?: HomeAssistant; - private _config?: EntityConfig; - - static get properties(): PropertyDeclarations { - return { - hass: {}, - _config: {}, - }; - } + @property() public hass?: HomeAssistant; + @property() private _config?: EntityConfig; public setConfig(config: EntityConfig): void { if (!config) { @@ -41,9 +29,13 @@ class HuiGroupEntityRow extends LitElement implements EntityRow { if (!stateObj) { return html` - + ${this.hass.localize( + "ui.panel.lovelace.warning.entity_not_found", + "entity", + this._config.entity + )} `; } diff --git a/src/panels/lovelace/entity-rows/hui-input-select-entity-row.ts b/src/panels/lovelace/entity-rows/hui-input-select-entity-row.ts index 2ee0010b2b..77c056524c 100644 --- a/src/panels/lovelace/entity-rows/hui-input-select-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-input-select-entity-row.ts @@ -1,8 +1,10 @@ import { html, LitElement, - PropertyDeclarations, TemplateResult, + property, + css, + CSSResult, } from "lit-element"; import { repeat } from "lit-html/directives/repeat"; import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; @@ -10,7 +12,7 @@ import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; import "../../../components/entity/state-badge"; -import "./hui-error-entity-row"; +import "../components/hui-warning"; import computeStateName from "../../../common/entity/compute_state_name"; import { HomeAssistant } from "../../../types"; @@ -18,15 +20,8 @@ import { EntityRow, EntityConfig } from "./types"; import { setOption } from "../../../data/input-select"; class HuiInputSelectEntityRow extends LitElement implements EntityRow { - public hass?: HomeAssistant; - private _config?: EntityConfig; - - static get properties(): PropertyDeclarations { - return { - hass: {}, - _config: {}, - }; - } + @property() public hass?: HomeAssistant; + @property() private _config?: EntityConfig; public setConfig(config: EntityConfig): void { if (!config || !config.entity) { @@ -45,14 +40,17 @@ class HuiInputSelectEntityRow extends LitElement implements EntityRow { if (!stateObj) { return html` - + ${this.hass.localize( + "ui.panel.lovelace.warning.entity_not_found", + "entity", + this._config.entity + )} `; } return html` - ${this.renderStyle()} - :host { - display: flex; - align-items: center; - } - paper-dropdown-menu { - margin-left: 16px; - flex: 1; - } - + static get styles(): CSSResult { + return css` + :host { + display: flex; + align-items: center; + } + paper-dropdown-menu { + margin-left: 16px; + flex: 1; + } `; } diff --git a/src/panels/lovelace/entity-rows/hui-input-text-entity-row.ts b/src/panels/lovelace/entity-rows/hui-input-text-entity-row.ts index 9aae5b482d..1456bb9492 100644 --- a/src/panels/lovelace/entity-rows/hui-input-text-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-input-text-entity-row.ts @@ -1,28 +1,16 @@ -import { - html, - LitElement, - PropertyDeclarations, - TemplateResult, -} from "lit-element"; +import { html, LitElement, TemplateResult, property } from "lit-element"; import { PaperInputElement } from "@polymer/paper-input/paper-input"; import "../components/hui-generic-entity-row"; -import "./hui-error-entity-row"; +import "../components/hui-warning"; import { HomeAssistant } from "../../../types"; import { EntityRow, EntityConfig } from "./types"; import { setValue } from "../../../data/input_text"; class HuiInputTextEntityRow extends LitElement implements EntityRow { - public hass?: HomeAssistant; - private _config?: EntityConfig; - - static get properties(): PropertyDeclarations { - return { - hass: {}, - _config: {}, - }; - } + @property() public hass?: HomeAssistant; + @property() private _config?: EntityConfig; public setConfig(config: EntityConfig): void { if (!config) { @@ -40,9 +28,13 @@ class HuiInputTextEntityRow extends LitElement implements EntityRow { if (!stateObj) { return html` - + ${this.hass.localize( + "ui.panel.lovelace.warning.entity_not_found", + "entity", + this._config.entity + )} `; } diff --git a/src/panels/lovelace/entity-rows/hui-lock-entity-row.ts b/src/panels/lovelace/entity-rows/hui-lock-entity-row.ts index 420185b4d8..15c0acbf5c 100644 --- a/src/panels/lovelace/entity-rows/hui-lock-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-lock-entity-row.ts @@ -1,26 +1,21 @@ import { html, LitElement, - PropertyDeclarations, TemplateResult, + property, + css, + CSSResult, } from "lit-element"; import "../components/hui-generic-entity-row"; -import "./hui-error-entity-row"; +import "../components/hui-warning"; import { HomeAssistant } from "../../../types"; import { EntityRow, EntityConfig } from "./types"; class HuiLockEntityRow extends LitElement implements EntityRow { - public hass?: HomeAssistant; - private _config?: EntityConfig; - - static get properties(): PropertyDeclarations { - return { - hass: {}, - _config: {}, - }; - } + @property() public hass?: HomeAssistant; + @property() private _config?: EntityConfig; public setConfig(config: EntityConfig): void { if (!config) { @@ -38,14 +33,17 @@ class HuiLockEntityRow extends LitElement implements EntityRow { if (!stateObj) { return html` - + ${this.hass.localize( + "ui.panel.lovelace.warning.entity_not_found", + "entity", + this._config.entity + )} `; } return html` - ${this.renderStyle()} ${stateObj.state === "locked" @@ -56,15 +54,11 @@ class HuiLockEntityRow extends LitElement implements EntityRow { `; } - protected renderStyle(): TemplateResult { - return html` - + static get styles(): CSSResult { + return css` + mwc-button { + margin-right: -0.57em; + } `; } diff --git a/src/panels/lovelace/entity-rows/hui-media-player-entity-row.ts b/src/panels/lovelace/entity-rows/hui-media-player-entity-row.ts index 12e419828e..3defa48446 100644 --- a/src/panels/lovelace/entity-rows/hui-media-player-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-media-player-entity-row.ts @@ -1,7 +1,15 @@ -import { html, LitElement, TemplateResult } from "lit-element"; +import { + html, + LitElement, + TemplateResult, + css, + CSSResult, + property, +} from "lit-element"; import "@polymer/paper-icon-button/paper-icon-button"; import "../components/hui-generic-entity-row"; +import "../components/hui-warning"; import { EntityRow, EntityConfig } from "./types"; import { HomeAssistant } from "../../../types"; @@ -15,15 +23,8 @@ import { } from "../../../data/media-player"; class HuiMediaPlayerEntityRow extends LitElement implements EntityRow { - public hass?: HomeAssistant; - private _config?: EntityConfig; - - static get properties() { - return { - hass: {}, - _config: {}, - }; - } + @property() public hass?: HomeAssistant; + @property() private _config?: EntityConfig; public setConfig(config: EntityConfig): void { if (!config || !config.entity) { @@ -42,14 +43,17 @@ class HuiMediaPlayerEntityRow extends LitElement implements EntityRow { if (!stateObj) { return html` - + ${this.hass.localize( + "ui.panel.lovelace.warning.entity_not_found", + "entity", + this._config.entity + )} `; } return html` - ${this.renderStyle()} - .controls { - white-space: nowrap; - } - + static get styles(): CSSResult { + return css` + .controls { + white-space: nowrap; + } `; } diff --git a/src/panels/lovelace/entity-rows/hui-scene-entity-row.ts b/src/panels/lovelace/entity-rows/hui-scene-entity-row.ts index 045dba7df9..4a11a1f6a3 100644 --- a/src/panels/lovelace/entity-rows/hui-scene-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-scene-entity-row.ts @@ -1,27 +1,22 @@ import { html, LitElement, - PropertyDeclarations, TemplateResult, + CSSResult, + css, + property, } from "lit-element"; import "../components/hui-generic-entity-row"; import "../../../components/entity/ha-entity-toggle"; -import "./hui-error-entity-row"; +import "../components/hui-warning"; import { HomeAssistant } from "../../../types"; import { EntityRow, EntityConfig } from "./types"; class HuiSceneEntityRow extends LitElement implements EntityRow { - public hass?: HomeAssistant; - private _config?: EntityConfig; - - static get properties(): PropertyDeclarations { - return { - hass: {}, - _config: {}, - }; - } + @property() public hass?: HomeAssistant; + @property() private _config?: EntityConfig; public setConfig(config: EntityConfig): void { if (!config) { @@ -39,14 +34,17 @@ class HuiSceneEntityRow extends LitElement implements EntityRow { if (!stateObj) { return html` - + ${this.hass.localize( + "ui.panel.lovelace.warning.entity_not_found", + "entity", + this._config.entity + )} `; } return html` - ${this.renderStyle()} ${stateObj.attributes.can_cancel ? html` @@ -64,15 +62,11 @@ class HuiSceneEntityRow extends LitElement implements EntityRow { `; } - protected renderStyle(): TemplateResult { - return html` - + static get styles(): CSSResult { + return css` + mwc-button { + margin-right: -0.57em; + } `; } diff --git a/src/panels/lovelace/entity-rows/hui-script-entity-row.ts b/src/panels/lovelace/entity-rows/hui-script-entity-row.ts index 3a31251d14..b0465abf11 100644 --- a/src/panels/lovelace/entity-rows/hui-script-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-script-entity-row.ts @@ -1,27 +1,22 @@ import { html, LitElement, - PropertyDeclarations, TemplateResult, + property, + CSSResult, + css, } from "lit-element"; import "../components/hui-generic-entity-row"; import "../../../components/entity/ha-entity-toggle"; -import "./hui-error-entity-row"; +import "../components/hui-warning"; import { HomeAssistant } from "../../../types"; import { EntityRow, EntityConfig } from "./types"; class HuiScriptEntityRow extends LitElement implements EntityRow { - public hass?: HomeAssistant; - private _config?: EntityConfig; - - static get properties(): PropertyDeclarations { - return { - hass: {}, - _config: {}, - }; - } + @property() public hass?: HomeAssistant; + @property() private _config?: EntityConfig; public setConfig(config: EntityConfig): void { if (!config) { @@ -39,14 +34,17 @@ class HuiScriptEntityRow extends LitElement implements EntityRow { if (!stateObj) { return html` - + ${this.hass.localize( + "ui.panel.lovelace.warning.entity_not_found", + "entity", + this._config.entity + )} `; } return html` - ${this.renderStyle()} ${stateObj.attributes.can_cancel ? html` @@ -64,15 +62,11 @@ class HuiScriptEntityRow extends LitElement implements EntityRow { `; } - protected renderStyle(): TemplateResult { - return html` - + static get styles(): CSSResult { + return css` + mwc-button { + margin-right: -0.57em; + } `; } diff --git a/src/panels/lovelace/entity-rows/hui-sensor-entity-row.ts b/src/panels/lovelace/entity-rows/hui-sensor-entity-row.ts index ac4a261a55..4c65f99cf0 100644 --- a/src/panels/lovelace/entity-rows/hui-sensor-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-sensor-entity-row.ts @@ -1,13 +1,15 @@ import { html, LitElement, - PropertyDeclarations, TemplateResult, + property, + CSSResult, + css, } from "lit-element"; import "../components/hui-generic-entity-row"; import "../components/hui-timestamp-display"; -import "./hui-error-entity-row"; +import "../components/hui-warning"; import { HomeAssistant } from "../../../types"; import { EntityRow, EntityConfig } from "./types"; @@ -19,15 +21,8 @@ interface SensorEntityConfig extends EntityConfig { } class HuiSensorEntityRow extends LitElement implements EntityRow { - public hass?: HomeAssistant; - private _config?: SensorEntityConfig; - - static get properties(): PropertyDeclarations { - return { - hass: {}, - _config: {}, - }; - } + @property() public hass?: HomeAssistant; + @property() private _config?: SensorEntityConfig; public setConfig(config: SensorEntityConfig): void { if (!config) { @@ -45,14 +40,17 @@ class HuiSensorEntityRow extends LitElement implements EntityRow { if (!stateObj) { return html` - + ${this.hass.localize( + "ui.panel.lovelace.warning.entity_not_found", + "entity", + this._config.entity + )} `; } return html` - ${this.renderStyle()}
${stateObj.attributes.device_class === "timestamp" @@ -73,13 +71,11 @@ class HuiSensorEntityRow extends LitElement implements EntityRow { `; } - private renderStyle(): TemplateResult { - return html` - + static get styles(): CSSResult { + return css` + div { + text-align: right; + } `; } } diff --git a/src/panels/lovelace/entity-rows/hui-text-entity-row.ts b/src/panels/lovelace/entity-rows/hui-text-entity-row.ts index e30bdf27e5..5fd9f2f442 100644 --- a/src/panels/lovelace/entity-rows/hui-text-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-text-entity-row.ts @@ -1,27 +1,22 @@ import { html, LitElement, - PropertyDeclarations, TemplateResult, + property, + CSSResult, + css, } from "lit-element"; import "../components/hui-generic-entity-row"; -import "./hui-error-entity-row"; +import "../components/hui-warning"; import computeStateDisplay from "../../../common/entity/compute_state_display"; import { HomeAssistant } from "../../../types"; import { EntityRow, EntityConfig } from "./types"; class HuiTextEntityRow extends LitElement implements EntityRow { - public hass?: HomeAssistant; - private _config?: EntityConfig; - - static get properties(): PropertyDeclarations { - return { - hass: {}, - _config: {}, - }; - } + @property() public hass?: HomeAssistant; + @property() private _config?: EntityConfig; public setConfig(config: EntityConfig): void { if (!config) { @@ -39,14 +34,17 @@ class HuiTextEntityRow extends LitElement implements EntityRow { if (!stateObj) { return html` - + ${this.hass.localize( + "ui.panel.lovelace.warning.entity_not_found", + "entity", + this._config.entity + )} `; } return html` - ${this.renderStyle()}
${computeStateDisplay( @@ -59,13 +57,11 @@ class HuiTextEntityRow extends LitElement implements EntityRow { `; } - private renderStyle(): TemplateResult { - return html` - + static get styles(): CSSResult { + return css` + div { + text-align: right; + } `; } } diff --git a/src/panels/lovelace/entity-rows/hui-timer-entity-row.js b/src/panels/lovelace/entity-rows/hui-timer-entity-row.js deleted file mode 100644 index fbcfd143d5..0000000000 --- a/src/panels/lovelace/entity-rows/hui-timer-entity-row.js +++ /dev/null @@ -1,98 +0,0 @@ -import { html } from "@polymer/polymer/lib/utils/html-tag"; -import { PolymerElement } from "@polymer/polymer/polymer-element"; - -import "../components/hui-generic-entity-row"; - -import timerTimeRemaining from "../../../common/entity/timer_time_remaining"; -import secondsToDuration from "../../../common/datetime/seconds_to_duration"; - -class HuiTimerEntityRow extends PolymerElement { - static get template() { - return html` - - ${this.timerControlTemplate} - - `; - } - - static get timerControlTemplate() { - return html` -
[[_computeDisplay(_stateObj, _timeRemaining)]]
- `; - } - - static get properties() { - return { - hass: Object, - _config: Object, - _stateObj: { - type: Object, - computed: "_computeStateObj(hass.states, _config.entity)", - observer: "_stateObjChanged", - }, - _timeRemaining: Number, - }; - } - - disconnectedCallback() { - super.disconnectedCallback(); - this._clearInterval(); - } - - _stateObjChanged(stateObj) { - if (stateObj) { - this._startInterval(stateObj); - } else { - this._clearInterval(); - } - } - - _clearInterval() { - if (this._updateRemaining) { - clearInterval(this._updateRemaining); - this._updateRemaining = null; - } - } - - _startInterval(stateObj) { - this._clearInterval(); - this._calculateRemaining(stateObj); - - if (stateObj.state === "active") { - this._updateRemaining = setInterval( - () => this._calculateRemaining(this._stateObj), - 1000 - ); - } - } - - _calculateRemaining(stateObj) { - this._timeRemaining = timerTimeRemaining(stateObj); - } - - _computeDisplay(stateObj, time) { - if (!stateObj) return null; - - if (stateObj.state === "idle" || time === 0) return stateObj.state; - - let display = secondsToDuration(time); - - if (stateObj.state === "paused") { - display += " (paused)"; - } - - return display; - } - - _computeStateObj(states, entityId) { - return states && entityId in states ? states[entityId] : null; - } - - setConfig(config) { - if (!config || !config.entity) { - throw new Error("Entity not configured."); - } - this._config = config; - } -} -customElements.define("hui-timer-entity-row", HuiTimerEntityRow); diff --git a/src/panels/lovelace/entity-rows/hui-timer-entity-row.ts b/src/panels/lovelace/entity-rows/hui-timer-entity-row.ts new file mode 100644 index 0000000000..7e7383961d --- /dev/null +++ b/src/panels/lovelace/entity-rows/hui-timer-entity-row.ts @@ -0,0 +1,128 @@ +import { + html, + LitElement, + TemplateResult, + property, + PropertyValues, +} from "lit-element"; + +import "../components/hui-generic-entity-row"; +import "../components/hui-warning"; + +import timerTimeRemaining from "../../../common/entity/timer_time_remaining"; +import secondsToDuration from "../../../common/datetime/seconds_to_duration"; +import { HomeAssistant } from "../../../types"; +import { EntityConfig } from "./types"; +import { HassEntity } from "home-assistant-js-websocket"; + +class HuiTimerEntityRow extends LitElement { + @property() public hass?: HomeAssistant; + @property() private _config?: EntityConfig; + @property() private _timeRemaining?: number; + private _interval?: number; + + public setConfig(config: EntityConfig): void { + if (!config) { + throw new Error("Configuration error"); + } + this._config = config; + } + + public disconnectedCallback(): void { + super.disconnectedCallback(); + this._clearInterval(); + } + + protected render(): TemplateResult | void { + if (!this._config || !this.hass) { + return html``; + } + + const stateObj = this.hass.states[this._config.entity]; + + if (!stateObj) { + return html` + ${this.hass.localize( + "ui.panel.lovelace.warning.entity_not_found", + "entity", + this._config.entity + )} + `; + } + + return html` + +
${this._computeDisplay(stateObj)}
+
+ `; + } + + protected updated(changedProps: PropertyValues) { + super.updated(changedProps); + + if (changedProps.has("hass")) { + const stateObj = this.hass!.states[this._config!.entity]; + const oldHass = changedProps.get("hass") as this["hass"]; + const oldStateObj = oldHass + ? oldHass.states[this._config!.entity] + : undefined; + + if (oldStateObj !== stateObj) { + this._startInterval(stateObj); + } else if (!stateObj) { + this._clearInterval(); + } + } + } + + private _clearInterval(): void { + if (this._interval) { + window.clearInterval(this._interval); + this._interval = undefined; + } + } + + private _startInterval(stateObj: HassEntity): void { + this._clearInterval(); + this._calculateRemaining(stateObj); + + if (stateObj.state === "active") { + this._interval = window.setInterval( + () => this._calculateRemaining(stateObj), + 1000 + ); + } + } + + private _calculateRemaining(stateObj: HassEntity): void { + this._timeRemaining = timerTimeRemaining(stateObj); + } + + private _computeDisplay(stateObj: HassEntity): string | null { + if (!stateObj) { + return null; + } + + if (stateObj.state === "idle" || this._timeRemaining === 0) { + return this.hass!.localize("state.timer." + stateObj.state); + } + + let display = secondsToDuration(this._timeRemaining || 0); + + if (stateObj.state === "paused") { + display += ` (${this.hass!.localize("state.timer.paused")})`; + } + + return display; + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-timer-entity-row": HuiTimerEntityRow; + } +} + +customElements.define("hui-timer-entity-row", HuiTimerEntityRow); diff --git a/src/panels/lovelace/entity-rows/hui-toggle-entity-row.ts b/src/panels/lovelace/entity-rows/hui-toggle-entity-row.ts index f5a7848835..e91a47e460 100644 --- a/src/panels/lovelace/entity-rows/hui-toggle-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-toggle-entity-row.ts @@ -7,7 +7,7 @@ import { import "../components/hui-generic-entity-row"; import "../../../components/entity/ha-entity-toggle"; -import "./hui-error-entity-row"; +import "../components/hui-warning"; import computeStateDisplay from "../../../common/entity/compute_state_display"; import { HomeAssistant } from "../../../types"; @@ -40,9 +40,13 @@ class HuiToggleEntityRow extends LitElement implements EntityRow { if (!stateObj) { return html` - + ${this.hass.localize( + "ui.panel.lovelace.warning.entity_not_found", + "entity", + this._config.entity + )} `; } diff --git a/src/panels/lovelace/ha-panel-lovelace.ts b/src/panels/lovelace/ha-panel-lovelace.ts index ff7b39ab10..1b9d3edbd0 100644 --- a/src/panels/lovelace/ha-panel-lovelace.ts +++ b/src/panels/lovelace/ha-panel-lovelace.ts @@ -73,12 +73,6 @@ class LovelacePanel extends LitElement { if (state === "error") { return html` - ${this.config.title || "Home Assistant"}
diff --git a/src/panels/profile/ha-mfa-modules-card.js b/src/panels/profile/ha-mfa-modules-card.js index bae240bbf5..f791f200ef 100644 --- a/src/panels/profile/ha-mfa-modules-card.js +++ b/src/panels/profile/ha-mfa-modules-card.js @@ -37,8 +37,6 @@ class HaMfaModulesCard extends EventsMixin(LocalizeMixin(PolymerElement)) { margin: 16px auto; } mwc-button { - color: var(--primary-color); - font-weight: 500; margin-right: -0.57em; } diff --git a/src/state-summary/state-card-configurator.js b/src/state-summary/state-card-configurator.js index daacf85736..5cc66cf4f5 100644 --- a/src/state-summary/state-card-configurator.js +++ b/src/state-summary/state-card-configurator.js @@ -16,8 +16,6 @@ class StateCardConfigurator extends LocalizeMixin(PolymerElement) {