diff --git a/gallery/src/demos/demo-util-long-press.ts b/gallery/src/demos/demo-util-long-press.ts index 9e790fed50..96247b202b 100644 --- a/gallery/src/demos/demo-util-long-press.ts +++ b/gallery/src/demos/demo-util-long-press.ts @@ -1,12 +1,11 @@ -import { html, LitElement } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { html, LitElement, TemplateResult } from "lit-element"; import "@polymer/paper-button/paper-button"; import "../../../src/components/ha-card"; import { longPress } from "../../../src/panels/lovelace/common/directives/long-press-directive"; export class DemoUtilLongPress extends LitElement { - public render(): TemplateResult { + protected render(): TemplateResult | void { return html` ${this.renderStyle()} ${ diff --git a/package.json b/package.json index 732dcc03b3..0d99d08d7d 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,6 @@ "author": "Paulus Schoutsen (http://paulusschoutsen.nl)", "license": "Apache-2.0", "dependencies": { - "@material/mwc-ripple": "^0.3.1", "@mdi/svg": "^3.0.39", "@polymer/app-layout": "^3.0.1", "@polymer/app-localize-behavior": "^3.0.1", @@ -35,7 +34,6 @@ "@polymer/iron-media-query": "^3.0.1", "@polymer/iron-pages": "^3.0.1", "@polymer/iron-resizable-behavior": "^3.0.1", - "@polymer/lit-element": "0.6.2", "@polymer/neon-animation": "^3.0.1", "@polymer/paper-button": "^3.0.1", "@polymer/paper-card": "^3.0.1", @@ -78,7 +76,8 @@ "jquery": "^3.3.1", "js-yaml": "^3.12.0", "leaflet": "^1.3.4", - "lit-html": "0.12.0", + "lit-element": "2.0.0-rc.2", + "lit-html": "1.0.0-rc.2", "marked": "^0.5.0", "mdn-polyfills": "^5.12.0", "moment": "^2.22.2", @@ -158,9 +157,7 @@ "@webcomponents/shadycss": "^1.6.0", "@vaadin/vaadin-overlay": "3.2.2", "@vaadin/vaadin-lumo-styles": "1.3.0", - "fecha": "https://github.com/taylorhakes/fecha/archive/5e8fe08d982647fdb19fb403459838b02647813c.tar.gz", - "lit-html": "0.12.0", - "@polymer/lit-element": "0.6.2" + "fecha": "https://github.com/taylorhakes/fecha/archive/5e8fe08d982647fdb19fb403459838b02647813c.tar.gz" }, "main": "src/home-assistant.js", "husky": { diff --git a/script/version_bump.js b/script/version_bump.js index 73ee8fb634..e38ff4dae6 100755 --- a/script/version_bump.js +++ b/script/version_bump.js @@ -10,9 +10,10 @@ function patch(version) { function today() { const now = new Date(); - return `${now.getFullYear()}${now.getMonth() + 1}${String( - now.getDate() - ).padStart(2, "0")}.0`; + return `${now.getFullYear()}${String(now.getMonth() + 1).padStart( + 2, + "0" + )}${String(now.getDate()).padStart(2, "0")}.0`; } const methods = { @@ -51,4 +52,4 @@ async function main(args) { console.log(stdout); } -main(process.argv.slice(2)); +main(process.argv.slice(2)).catch(console.error); diff --git a/setup.py b/setup.py index 9fd8600663..74901e8bc5 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup( name="home-assistant-frontend", - version="20190109.1", + version="20190116.0", description="The Home Assistant frontend", url="https://github.com/home-assistant/home-assistant-polymer", author="The Home Assistant Authors", diff --git a/src/auth/ha-authorize.ts b/src/auth/ha-authorize.ts index e93a992959..5a85beac68 100644 --- a/src/auth/ha-authorize.ts +++ b/src/auth/ha-authorize.ts @@ -1,5 +1,5 @@ import { litLocalizeLiteMixin } from "../mixins/lit-localize-lite-mixin"; -import { LitElement, html, PropertyDeclarations } from "@polymer/lit-element"; +import { LitElement, html, PropertyDeclarations } from "lit-element"; import "./ha-auth-flow"; import { AuthProvider } from "../data/auth"; @@ -50,7 +50,7 @@ class HaAuthorize extends litLocalizeLiteMixin(LitElement) { }; } - public render() { + protected render() { if (!this._authProviders) { return html`

[[localize('ui.panel.page-authorize.initializing')]]

diff --git a/src/common/const.ts b/src/common/const.ts index c9dcab53b9..b422818aab 100644 --- a/src/common/const.ts +++ b/src/common/const.ts @@ -8,7 +8,7 @@ export const DEFAULT_DOMAIN_ICON = "hass:bookmark"; /** Panel to show when no panel is picked. */ -export const DEFAULT_PANEL = "states"; +export const DEFAULT_PANEL = "lovelace"; /** Domains that have a state card. */ export const DOMAINS_WITH_CARD = [ diff --git a/src/components/buttons/ha-call-api-button.js b/src/components/buttons/ha-call-api-button.js index 792d7d719c..59c7c8e748 100644 --- a/src/components/buttons/ha-call-api-button.js +++ b/src/components/buttons/ha-call-api-button.js @@ -1,4 +1,4 @@ -import { LitElement, html } from "@polymer/lit-element"; +import { LitElement, html } from "lit-element"; import "./ha-progress-button"; import { fireEvent } from "../../common/dom/fire_event"; diff --git a/src/components/entity/ha-state-label-badge.ts b/src/components/entity/ha-state-label-badge.ts index db59a82ea6..09a16a8681 100644 --- a/src/components/entity/ha-state-label-badge.ts +++ b/src/components/entity/ha-state-label-badge.ts @@ -3,10 +3,10 @@ import { html, PropertyValues, PropertyDeclarations, -} from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; + TemplateResult, +} from "lit-element"; import { HassEntity } from "home-assistant-js-websocket"; -import { classMap } from "lit-html/directives/classMap"; +import { classMap } from "lit-html/directives/class-map"; import computeStateDomain from "../../common/entity/compute_state_domain"; import computeStateName from "../../common/entity/compute_state_name"; @@ -41,7 +41,7 @@ export class HaStateLabelBadge extends hassLocalizeLitMixin(LitElement) { this.clearInterval(); } - protected render(): TemplateResult { + protected render(): TemplateResult | void { const state = this.state; if (!state) { diff --git a/src/components/ha-label-badge.ts b/src/components/ha-label-badge.ts index f29778a0f0..1cf25ec4e0 100644 --- a/src/components/ha-label-badge.ts +++ b/src/components/ha-label-badge.ts @@ -1,10 +1,13 @@ import { + html, LitElement, PropertyDeclarations, PropertyValues, -} from "@polymer/lit-element"; -import { TemplateResult, html } from "lit-html"; -import { classMap } from "lit-html/directives/classMap"; + TemplateResult, + CSSResult, + css, +} from "lit-element"; +import { classMap } from "lit-html/directives/class-map"; import "./ha-icon"; class HaLabelBadge extends LitElement { @@ -24,9 +27,8 @@ class HaLabelBadge extends LitElement { }; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { return html` - ${this.renderStyle()}
+ static get styles(): CSSResult[] { + return [ + css` .badge-container { display: inline-block; text-align: center; @@ -148,8 +150,8 @@ class HaLabelBadge extends LitElement { text-overflow: ellipsis; line-height: normal; } - - `; + `, + ]; } protected updated(changedProperties: PropertyValues): void { diff --git a/src/components/ha-push-notifications-toggle.js b/src/components/ha-push-notifications-toggle.js index e024cc4c01..d5078f6978 100644 --- a/src/components/ha-push-notifications-toggle.js +++ b/src/components/ha-push-notifications-toggle.js @@ -20,6 +20,7 @@ class HaPushNotificationsToggle extends EventsMixin(PolymerElement) { `; } @@ -35,7 +36,6 @@ class HaPushNotificationsToggle extends EventsMixin(PolymerElement) { type: Boolean, value: "Notification" in window && Notification.permission === "granted", - observer: "handlePushChange", }, loading: { type: Boolean, @@ -63,12 +63,12 @@ class HaPushNotificationsToggle extends EventsMixin(PolymerElement) { } } - handlePushChange(pushChecked) { + handlePushChange(event) { // Somehow this is triggered on Safari on page load causing // it to get into a loop and crash the page. if (!pushSupported) return; - if (pushChecked) { + if (event.target.checked) { this.subscribePushNotifications(); } else { this.unsubscribePushNotifications(); @@ -77,10 +77,9 @@ class HaPushNotificationsToggle extends EventsMixin(PolymerElement) { async subscribePushNotifications() { const reg = await navigator.serviceWorker.ready; + let sub; try { - const sub = await reg.pushManager.subscribe({ userVisibleOnly: true }); - let browserName; if (navigator.userAgent.toLowerCase().indexOf("firefox") > -1) { browserName = "firefox"; @@ -88,12 +87,24 @@ class HaPushNotificationsToggle extends EventsMixin(PolymerElement) { browserName = "chrome"; } + const name = prompt("What should this device be called ?"); + if (name == null) { + this.pushChecked = false; + return; + } + + sub = await reg.pushManager.subscribe({ userVisibleOnly: true }); + await this.hass.callApi("POST", "notify.html5", { subscription: sub, browser: browserName, + name, }); } catch (err) { const message = err.message || "Notification registration failed."; + if (sub) { + await sub.unsubscribe(); + } // eslint-disable-next-line console.error(err); diff --git a/src/components/ha-slider.js b/src/components/ha-slider.js index d49ed51015..386f9dd28a 100644 --- a/src/components/ha-slider.js +++ b/src/components/ha-slider.js @@ -1,8 +1,28 @@ import "@polymer/paper-slider"; const PaperSliderClass = customElements.get("paper-slider"); +let subTemplate; class HaSlider extends PaperSliderClass { + static get template() { + if (!subTemplate) { + subTemplate = PaperSliderClass.template.cloneNode(true); + + const superStyle = subTemplate.content.querySelector("style"); + + // append style to add mirroring of pin in RTL + superStyle.appendChild( + document.createTextNode(` + :host([dir="rtl"]) #sliderContainer.pin.expand > .slider-knob > .slider-knob-inner::after { + -webkit-transform: scale(1) translate(0, -17px) scaleX(-1) !important; + transform: scale(1) translate(0, -17px) scaleX(-1) !important; + } + `) + ); + } + return subTemplate; + } + _calcStep(value) { if (!this.step) { return parseFloat(value); diff --git a/src/components/state-history-chart-timeline.js b/src/components/state-history-chart-timeline.js index df144e22bb..3fcc9a5902 100644 --- a/src/components/state-history-chart-timeline.js +++ b/src/components/state-history-chart-timeline.js @@ -20,6 +20,10 @@ class StateHistoryChartTimeline extends LocalizeMixin(PolymerElement) { :host([rendered]) { opacity: 1; } + + ha-chart-base { + direction: ltr; + } { yaxe.maxWidth = yaxe.chart.width * 0.18; }, + position: this.hass.translationMetadata.translations[ + this.hass.selectedLanguage || this.hass.language + ].isRTL + ? "right" + : "left", }, ], }, diff --git a/src/data/alarm_control_panel.ts b/src/data/alarm_control_panel.ts index 58f33c601d..05897b0cb3 100644 --- a/src/data/alarm_control_panel.ts +++ b/src/data/alarm_control_panel.ts @@ -1,5 +1,8 @@ import { HomeAssistant } from "../types"; +export const FORMAT_TEXT = "text"; +export const FORMAT_NUMBER = "number"; + export const callAlarmAction = ( hass: HomeAssistant, entity: string, diff --git a/src/data/zha.ts b/src/data/zha.ts new file mode 100644 index 0000000000..f5a67dbb12 --- /dev/null +++ b/src/data/zha.ts @@ -0,0 +1,104 @@ +import { HassEntity } from "home-assistant-js-websocket"; +import { HomeAssistant } from "../types"; + +export interface ZHADeviceEntity extends HassEntity { + device_info?: { + identifiers: any[]; + }; +} + +export interface ZHAEntities { + [key: string]: HassEntity[]; +} + +export interface Attribute { + name: string; + id: number; +} + +export interface Cluster { + name: string; + id: number; + type: string; +} + +export interface Command { + name: string; + id: number; + type: string; +} + +export interface ReadAttributeServiceData { + entity_id: string; + cluster_id: number; + cluster_type: string; + attribute: number; + manufacturer: number; +} + +export const reconfigureNode = ( + hass: HomeAssistant, + ieeeAddress: string +): Promise => + hass.callWS({ + type: "zha/nodes/reconfigure", + ieee: ieeeAddress, + }); + +export const fetchAttributesForCluster = ( + hass: HomeAssistant, + entityId: string, + ieeeAddress: string, + clusterId: number, + clusterType: string +): Promise => + hass.callWS({ + type: "zha/entities/clusters/attributes", + entity_id: entityId, + ieee: ieeeAddress, + cluster_id: clusterId, + cluster_type: clusterType, + }); + +export const readAttributeValue = ( + hass: HomeAssistant, + data: ReadAttributeServiceData +): Promise => { + return hass.callWS({ + ...data, + type: "zha/entities/clusters/attributes/value", + }); +}; + +export const fetchCommandsForCluster = ( + hass: HomeAssistant, + entityId: string, + ieeeAddress: string, + clusterId: number, + clusterType: string +): Promise => + hass.callWS({ + type: "zha/entities/clusters/commands", + entity_id: entityId, + ieee: ieeeAddress, + cluster_id: clusterId, + cluster_type: clusterType, + }); + +export const fetchClustersForZhaNode = ( + hass: HomeAssistant, + entityId: string, + ieeeAddress: string +): Promise => + hass.callWS({ + type: "zha/entities/clusters", + entity_id: entityId, + ieee: ieeeAddress, + }); + +export const fetchEntitiesForZhaNode = ( + hass: HomeAssistant +): Promise => + hass.callWS({ + type: "zha/entities", + }); diff --git a/src/entrypoints/service-worker-hass.js b/src/entrypoints/service-worker-hass.js index 8ad475d80e..a19a3cef40 100644 --- a/src/entrypoints/service-worker-hass.js +++ b/src/entrypoints/service-worker-hass.js @@ -72,6 +72,18 @@ function initPushNotifications() { var data; if (event.data) { data = event.data.json(); + if (data.dismiss) { + event.waitUntil( + self.registration + .getNotifications({ tag: data.tag }) + .then(function(notifications) { + for (const n of notifications) { + n.close(); + } + }) + ); + return; + } event.waitUntil( self.registration .showNotification(data.title, data) @@ -96,7 +108,11 @@ function initPushNotifications() { event.notification.close(); - if (!event.notification.data || !event.notification.data.url) { + if ( + event.action || + !event.notification.data || + !event.notification.data.url + ) { return; } diff --git a/src/layouts/app/dialog-manager-mixin.ts b/src/layouts/app/dialog-manager-mixin.ts index 90295c3866..3bd480f3a1 100644 --- a/src/layouts/app/dialog-manager-mixin.ts +++ b/src/layouts/app/dialog-manager-mixin.ts @@ -1,5 +1,5 @@ import { PolymerElement } from "@polymer/polymer"; -import { Constructor } from "@polymer/lit-element"; +import { Constructor } from "lit-element"; import { HASSDomEvent, ValidHassDomEvent } from "../../common/dom/fire_event"; interface RegisterDialogParams { diff --git a/src/layouts/app/home-assistant.js b/src/layouts/app/home-assistant.js index 2cd729b534..04801a95ef 100644 --- a/src/layouts/app/home-assistant.js +++ b/src/layouts/app/home-assistant.js @@ -4,7 +4,7 @@ import "@polymer/iron-flex-layout/iron-flex-layout-classes"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; import { afterNextRender } from "@polymer/polymer/lib/utils/render-status"; -import { html as litHtml, LitElement } from "@polymer/lit-element"; +import { html as litHtml, LitElement } from "lit-element"; import "../home-assistant-main"; import "../ha-init-page"; @@ -95,7 +95,11 @@ class HomeAssistant extends ext(PolymerElement, [ } computePanelUrl(routeData) { - return (routeData && routeData.panel) || DEFAULT_PANEL; + return ( + (routeData && routeData.panel) || + localStorage.defaultPage || + DEFAULT_PANEL + ); } panelUrlChanged(newPanelUrl) { diff --git a/src/mixins/lit-localize-lite-mixin.ts b/src/mixins/lit-localize-lite-mixin.ts index 4c6f4a25e5..393cdb875c 100644 --- a/src/mixins/lit-localize-lite-mixin.ts +++ b/src/mixins/lit-localize-lite-mixin.ts @@ -3,7 +3,7 @@ import { LitElement, PropertyDeclarations, PropertyValues, -} from "@polymer/lit-element"; +} from "lit-element"; import { HomeAssistant } from "../types"; import { getActiveTranslation } from "../util/hass-translation"; import { LocalizeFunc, LocalizeMixin } from "./localize-base-mixin"; diff --git a/src/mixins/lit-localize-mixin.ts b/src/mixins/lit-localize-mixin.ts index e16a739f46..742a60b76d 100644 --- a/src/mixins/lit-localize-mixin.ts +++ b/src/mixins/lit-localize-mixin.ts @@ -3,7 +3,7 @@ import { LitElement, PropertyDeclarations, PropertyValues, -} from "@polymer/lit-element"; +} from "lit-element"; import { HomeAssistant } from "../types"; import { localizeBaseMixin, diff --git a/src/panels/config/cloud/cloud-alexa-pref.ts b/src/panels/config/cloud/cloud-alexa-pref.ts index 149084acc8..91b48d9927 100644 --- a/src/panels/config/cloud/cloud-alexa-pref.ts +++ b/src/panels/config/cloud/cloud-alexa-pref.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "@polymer/paper-button/paper-button"; import "@polymer/paper-card/paper-card"; import "@polymer/paper-toggle-button/paper-toggle-button"; @@ -23,7 +27,7 @@ export class CloudAlexaPref extends LitElement { }; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this.cloudStatus) { return html``; } diff --git a/src/panels/config/cloud/cloud-exposed-entities.ts b/src/panels/config/cloud/cloud-exposed-entities.ts index fd47f759b0..7e6c79bd10 100644 --- a/src/panels/config/cloud/cloud-exposed-entities.ts +++ b/src/panels/config/cloud/cloud-exposed-entities.ts @@ -3,8 +3,8 @@ import { LitElement, PropertyDeclarations, PropertyValues, -} from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; + TemplateResult, +} from "lit-element"; import { repeat } from "lit-html/directives/repeat"; import "@polymer/paper-tooltip/paper-tooltip"; import { HassEntityBase } from "home-assistant-js-websocket"; @@ -34,7 +34,7 @@ export class CloudExposedEntities extends LitElement { }; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._filterFunc) { return html``; } diff --git a/src/panels/config/cloud/cloud-google-pref.ts b/src/panels/config/cloud/cloud-google-pref.ts index 015c5155c2..f724b1903d 100644 --- a/src/panels/config/cloud/cloud-google-pref.ts +++ b/src/panels/config/cloud/cloud-google-pref.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "@polymer/paper-button/paper-button"; import "@polymer/paper-card/paper-card"; import "@polymer/paper-toggle-button/paper-toggle-button"; @@ -24,7 +28,7 @@ export class CloudGooglePref extends LitElement { }; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this.cloudStatus) { return html``; } diff --git a/src/panels/config/cloud/cloud-webhook-manage-dialog.ts b/src/panels/config/cloud/cloud-webhook-manage-dialog.ts index 610f916f24..9b6baa4309 100644 --- a/src/panels/config/cloud/cloud-webhook-manage-dialog.ts +++ b/src/panels/config/cloud/cloud-webhook-manage-dialog.ts @@ -1,4 +1,10 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; +import { + html, + LitElement, + PropertyDeclarations, + css, + CSSResult, +} from "lit-element"; import "@polymer/paper-button/paper-button"; import "@polymer/paper-input/paper-input"; @@ -10,10 +16,9 @@ import { PaperDialogElement } from "@polymer/paper-dialog/paper-dialog"; // tslint:disable-next-line import { PaperInputElement } from "@polymer/paper-input/paper-input"; -import { buttonLink } from "../../../resources/ha-style"; - import { HomeAssistant } from "../../../types"; import { WebhookDialogParams } from "./types"; +import { haStyle } from "../../../resources/ha-style"; const inputLabel = "Public URL – Click to copy to clipboard"; @@ -44,7 +49,6 @@ export class CloudWebhookManageDialog extends LitElement { ? "https://www.home-assistant.io/docs/automation/trigger/#webhook-trigger" : `https://www.home-assistant.io/components/${webhook.domain}/`; return html` - ${this._renderStyle()}

Webhook for ${webhook.name}

@@ -112,24 +116,25 @@ export class CloudWebhookManageDialog extends LitElement { this._paperInput.label = inputLabel; } - private _renderStyle() { - return html` - - `; + `, + ]; } } diff --git a/src/panels/config/cloud/cloud-webhooks.ts b/src/panels/config/cloud/cloud-webhooks.ts index e89b6123a9..5d866a91f8 100644 --- a/src/panels/config/cloud/cloud-webhooks.ts +++ b/src/panels/config/cloud/cloud-webhooks.ts @@ -3,7 +3,7 @@ import { LitElement, PropertyDeclarations, PropertyValues, -} from "@polymer/lit-element"; +} from "lit-element"; import "@polymer/paper-toggle-button/paper-toggle-button"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-item/paper-item-body"; diff --git a/src/panels/config/js/trigger/time_pattern.js b/src/panels/config/js/trigger/time_pattern.js new file mode 100644 index 0000000000..1dda842275 --- /dev/null +++ b/src/panels/config/js/trigger/time_pattern.js @@ -0,0 +1,52 @@ +import { h, Component } from "preact"; + +import "@polymer/paper-input/paper-input"; + +import { onChangeEvent } from "../../../../common/preact/event"; + +export default class TimePatternTrigger extends Component { + constructor() { + super(); + + this.onChange = onChangeEvent.bind(this, "trigger"); + } + + /* eslint-disable camelcase */ + render({ trigger, localize }) { + const { hours, minutes, seconds } = trigger; + return ( +
+ + + +
+ ); + } +} + +TimePatternTrigger.defaultConfig = { + hours: "", + minutes: "", + seconds: "", +}; diff --git a/src/panels/config/js/trigger/trigger_edit.js b/src/panels/config/js/trigger/trigger_edit.js index fc65420014..12de1c3dd3 100644 --- a/src/panels/config/js/trigger/trigger_edit.js +++ b/src/panels/config/js/trigger/trigger_edit.js @@ -8,6 +8,7 @@ import EventTrigger from "./event"; import HassTrigger from "./homeassistant"; import MQTTTrigger from "./mqtt"; import NumericStateTrigger from "./numeric_state"; +import TimePatternTrigger from "./time_pattern"; import StateTrigger from "./state"; import SunTrigger from "./sun"; import TemplateTrigger from "./template"; @@ -24,6 +25,7 @@ const TYPES = { sun: SunTrigger, template: TemplateTrigger, time: TimeTrigger, + time_pattern: TimePatternTrigger, webhook: WebhookTrigger, zone: ZoneTrigger, }; diff --git a/src/panels/config/zha/ha-config-zha.ts b/src/panels/config/zha/ha-config-zha.ts index 488c45c43f..a8b70fe340 100755 --- a/src/panels/config/zha/ha-config-zha.ts +++ b/src/panels/config/zha/ha-config-zha.ts @@ -1,51 +1,119 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; import "@polymer/app-layout/app-header/app-header"; import "@polymer/app-layout/app-toolbar/app-toolbar"; -import "@polymer/paper-icon-button/paper-icon-button"; import "@polymer/iron-flex-layout/iron-flex-layout-classes"; -import { HomeAssistant } from "../../../types"; - +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; +import "@polymer/paper-icon-button/paper-icon-button"; +import { HassEntity } from "home-assistant-js-websocket"; +import { HASSDomEvent } from "../../../common/dom/fire_event"; +import { Cluster } from "../../../data/zha"; import "../../../layouts/ha-app-layout"; import "../../../resources/ha-style"; - +import { HomeAssistant } from "../../../types"; +import { + ZHAClusterSelectedParams, + ZHAEntitySelectedParams, + ZHANodeSelectedParams, +} from "./types"; +import "./zha-cluster-attributes"; +import "./zha-cluster-commands"; import "./zha-network"; +import "./zha-node"; export class HaConfigZha extends LitElement { public hass?: HomeAssistant; public isWide?: boolean; private _haStyle?: DocumentFragment; private _ironFlex?: DocumentFragment; + private _selectedNode?: HassEntity; + private _selectedCluster?: Cluster; + private _selectedEntity?: HassEntity; static get properties(): PropertyDeclarations { return { hass: {}, isWide: {}, + _selectedCluster: {}, + _selectedEntity: {}, + _selectedNode: {}, }; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { return html` ${this.renderStyle()} - - + + +
Zigbee Home Automation
+ + + ${ + this._selectedCluster + ? html` + + + + ` + : "" + }
`; } + private _onClusterSelected( + selectedClusterEvent: HASSDomEvent + ): void { + this._selectedCluster = selectedClusterEvent.detail.cluster; + } + + private _onNodeSelected( + selectedNodeEvent: HASSDomEvent + ): void { + this._selectedNode = selectedNodeEvent.detail.node; + this._selectedCluster = undefined; + this._selectedEntity = undefined; + } + + private _onEntitySelected( + selectedEntityEvent: HASSDomEvent + ): void { + this._selectedEntity = selectedEntityEvent.detail.entity; + } + private renderStyle(): TemplateResult { if (!this._haStyle) { this._haStyle = document.importNode( diff --git a/src/panels/config/zha/types.ts b/src/panels/config/zha/types.ts new file mode 100644 index 0000000000..23bc9f74d7 --- /dev/null +++ b/src/panels/config/zha/types.ts @@ -0,0 +1,50 @@ +import { HassEntity } from "home-assistant-js-websocket"; +import { ZHADeviceEntity, Cluster } from "../../../data/zha"; + +export interface PickerTarget extends EventTarget { + selected: number; +} + +export interface ItemSelectedEvent { + target?: PickerTarget; +} + +export interface ChangeEvent { + detail?: { + value?: any; + }; + target?: EventTarget; +} + +export interface SetAttributeServiceData { + entity_id: string; + cluster_id: number; + cluster_type: string; + attribute: number; + value: any; + manufacturer: number; +} + +export interface IssueCommandServiceData { + entity_id: string; + cluster_id: number; + cluster_type: string; + command: number; + command_type: string; +} + +export interface ZHAEntitySelectedParams { + entity: HassEntity; +} + +export interface ZHANodeSelectedParams { + node: ZHADeviceEntity; +} + +export interface ZHAClusterSelectedParams { + cluster: Cluster; +} + +export interface NodeServiceData { + ieee_address: string; +} diff --git a/src/panels/config/zha/zha-cluster-attributes.ts b/src/panels/config/zha/zha-cluster-attributes.ts new file mode 100644 index 0000000000..146801bd42 --- /dev/null +++ b/src/panels/config/zha/zha-cluster-attributes.ts @@ -0,0 +1,329 @@ +import "@polymer/iron-flex-layout/iron-flex-layout-classes"; +import { + html, + LitElement, + PropertyDeclarations, + PropertyValues, + TemplateResult, +} from "lit-element"; +import "@polymer/paper-button/paper-button"; +import "@polymer/paper-card/paper-card"; +import "@polymer/paper-icon-button/paper-icon-button"; +import { HassEntity } from "home-assistant-js-websocket"; +import "../../../components/buttons/ha-call-service-button"; +import "../../../components/ha-service-description"; +import { + Attribute, + Cluster, + fetchAttributesForCluster, + ReadAttributeServiceData, + readAttributeValue, + ZHADeviceEntity, +} from "../../../data/zha"; +import "../../../resources/ha-style"; +import { HomeAssistant } from "../../../types"; +import "../ha-config-section"; +import { + ChangeEvent, + ItemSelectedEvent, + SetAttributeServiceData, +} from "./types"; + +export class ZHAClusterAttributes extends LitElement { + public hass?: HomeAssistant; + public isWide?: boolean; + public showHelp: boolean; + public selectedNode?: HassEntity; + public selectedEntity?: ZHADeviceEntity; + public selectedCluster?: Cluster; + private _haStyle?: DocumentFragment; + private _ironFlex?: DocumentFragment; + private _attributes: Attribute[]; + private _selectedAttributeIndex: number; + private _attributeValue?: any; + private _manufacturerCodeOverride?: string | number; + private _setAttributeServiceData?: SetAttributeServiceData; + + constructor() { + super(); + this.showHelp = false; + this._selectedAttributeIndex = -1; + this._attributes = []; + this._attributeValue = ""; + } + + static get properties(): PropertyDeclarations { + return { + hass: {}, + isWide: {}, + showHelp: {}, + selectedNode: {}, + selectedEntity: {}, + selectedCluster: {}, + _attributes: {}, + _selectedAttributeIndex: {}, + _attributeValue: {}, + _manufacturerCodeOverride: {}, + _setAttributeServiceData: {}, + }; + } + + protected updated(changedProperties: PropertyValues): void { + if (changedProperties.has("selectedCluster")) { + this._attributes = []; + this._selectedAttributeIndex = -1; + this._attributeValue = ""; + this._fetchAttributesForCluster(); + } + super.update(changedProperties); + } + + protected render(): TemplateResult | void { + return html` + ${this.renderStyle()} + +
+ Cluster Attributes + + +
+ View and edit cluster attributes. + + +
+ + + ${ + this._attributes.map( + (entry) => html` + ${entry.name + " (id: " + entry.id + ")"} + ` + ) + } + + +
+ ${ + this.showHelp + ? html` +
+ Select an attribute to view or set its value +
+ ` + : "" + } + ${ + this._selectedAttributeIndex !== -1 + ? this._renderAttributeInteractions() + : "" + } +
+
+ `; + } + + private _renderAttributeInteractions(): TemplateResult { + return html` +
+ +
+
+ +
+
+ Get Zigbee Attribute + Set Zigbee Attribute + ${ + this.showHelp + ? html` + + ` + : "" + } +
+ `; + } + + private async _fetchAttributesForCluster(): Promise { + if (this.selectedEntity && this.selectedCluster && this.hass) { + this._attributes = await fetchAttributesForCluster( + this.hass, + this.selectedEntity!.entity_id, + this.selectedEntity!.device_info!.identifiers[0][1], + this.selectedCluster!.id, + this.selectedCluster!.type + ); + } + } + + private _computeReadAttributeServiceData(): + | ReadAttributeServiceData + | undefined { + if (!this.selectedEntity || !this.selectedCluster || !this.selectedNode) { + return; + } + return { + entity_id: this.selectedEntity!.entity_id, + cluster_id: this.selectedCluster!.id, + cluster_type: this.selectedCluster!.type, + attribute: this._attributes[this._selectedAttributeIndex].id, + manufacturer: this._manufacturerCodeOverride + ? parseInt(this._manufacturerCodeOverride as string, 10) + : this.selectedNode!.attributes.manufacturer_code, + }; + } + + private _computeSetAttributeServiceData(): + | SetAttributeServiceData + | undefined { + if (!this.selectedEntity || !this.selectedCluster || !this.selectedNode) { + return; + } + return { + entity_id: this.selectedEntity!.entity_id, + cluster_id: this.selectedCluster!.id, + cluster_type: this.selectedCluster!.type, + attribute: this._attributes[this._selectedAttributeIndex].id, + value: this._attributeValue, + manufacturer: this._manufacturerCodeOverride + ? parseInt(this._manufacturerCodeOverride as string, 10) + : this.selectedNode!.attributes.manufacturer_code, + }; + } + + private _onAttributeValueChanged(value: ChangeEvent): void { + this._attributeValue = value.detail!.value; + this._setAttributeServiceData = this._computeSetAttributeServiceData(); + } + + private _onManufacturerCodeOverrideChanged(value: ChangeEvent): void { + this._manufacturerCodeOverride = value.detail!.value; + this._setAttributeServiceData = this._computeSetAttributeServiceData(); + } + + private async _onGetZigbeeAttributeClick(): Promise { + const data = this._computeReadAttributeServiceData(); + if (data && this.hass) { + this._attributeValue = await readAttributeValue(this.hass, data); + } + } + + private _onHelpTap(): void { + this.showHelp = !this.showHelp; + } + + private _selectedAttributeChanged(event: ItemSelectedEvent): void { + this._selectedAttributeIndex = event.target!.selected; + this._attributeValue = ""; + } + + private renderStyle(): TemplateResult { + if (!this._haStyle) { + this._haStyle = document.importNode( + (document.getElementById("ha-style")! + .children[0] as HTMLTemplateElement).content, + true + ); + } + if (!this._ironFlex) { + this._ironFlex = document.importNode( + (document.getElementById("iron-flex")! + .children[0] as HTMLTemplateElement).content, + true + ); + } + return html` + ${this._ironFlex} ${this._haStyle} + + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "zha-cluster-attributes": ZHAClusterAttributes; + } +} + +customElements.define("zha-cluster-attributes", ZHAClusterAttributes); diff --git a/src/panels/config/zha/zha-cluster-commands.ts b/src/panels/config/zha/zha-cluster-commands.ts new file mode 100644 index 0000000000..30e506e1c8 --- /dev/null +++ b/src/panels/config/zha/zha-cluster-commands.ts @@ -0,0 +1,282 @@ +import "@polymer/iron-flex-layout/iron-flex-layout-classes"; +import { + html, + LitElement, + PropertyDeclarations, + PropertyValues, + TemplateResult, +} from "lit-element"; +import "@polymer/paper-card/paper-card"; +import { HassEntity } from "home-assistant-js-websocket"; +import "../../../components/buttons/ha-call-service-button"; +import "../../../components/ha-service-description"; +import { + Cluster, + Command, + fetchCommandsForCluster, + ZHADeviceEntity, +} from "../../../data/zha"; +import "../../../resources/ha-style"; +import { HomeAssistant } from "../../../types"; +import "../ha-config-section"; +import { + ChangeEvent, + IssueCommandServiceData, + ItemSelectedEvent, +} from "./types"; + +export class ZHAClusterCommands extends LitElement { + public hass?: HomeAssistant; + public isWide?: boolean; + public selectedNode?: HassEntity; + public selectedEntity?: ZHADeviceEntity; + public selectedCluster?: Cluster; + private _showHelp: boolean; + private _haStyle?: DocumentFragment; + private _ironFlex?: DocumentFragment; + private _commands: Command[]; + private _selectedCommandIndex: number; + private _manufacturerCodeOverride?: number; + private _issueClusterCommandServiceData?: IssueCommandServiceData; + + constructor() { + super(); + this._showHelp = false; + this._selectedCommandIndex = -1; + this._commands = []; + } + + static get properties(): PropertyDeclarations { + return { + hass: {}, + isWide: {}, + selectedNode: {}, + selectedEntity: {}, + selectedCluster: {}, + _showHelp: {}, + _commands: {}, + _selectedCommandIndex: {}, + _manufacturerCodeOverride: {}, + _issueClusterCommandServiceData: {}, + }; + } + + protected updated(changedProperties: PropertyValues): void { + if (changedProperties.has("selectedCluster")) { + this._commands = []; + this._selectedCommandIndex = -1; + this._fetchCommandsForCluster(); + } + super.update(changedProperties); + } + + protected render(): TemplateResult | void { + return html` + ${this.renderStyle()} + +
+ Cluster Commands + + +
+ View and issue cluster commands. + + +
+ + + ${ + this._commands.map( + (entry) => html` + ${entry.name + " (id: " + entry.id + ")"} + ` + ) + } + + +
+ ${ + this._showHelp + ? html` +
Select a command to interact with
+ ` + : "" + } + ${ + this._selectedCommandIndex !== -1 + ? html` +
+ +
+
+ Issue Zigbee Command + ${ + this._showHelp + ? html` + + ` + : "" + } +
+ ` + : "" + } +
+
+ `; + } + + private async _fetchCommandsForCluster(): Promise { + if (this.selectedEntity && this.selectedCluster && this.hass) { + this._commands = await fetchCommandsForCluster( + this.hass, + this.selectedEntity!.entity_id, + this.selectedEntity!.device_info!.identifiers[0][1], + this.selectedCluster!.id, + this.selectedCluster!.type + ); + } + } + + private _computeIssueClusterCommandServiceData(): + | IssueCommandServiceData + | undefined { + if (!this.selectedEntity || !this.selectedCluster) { + return; + } + return { + entity_id: this.selectedEntity!.entity_id, + cluster_id: this.selectedCluster!.id, + cluster_type: this.selectedCluster!.type, + command: this._commands[this._selectedCommandIndex].id, + command_type: this._commands[this._selectedCommandIndex].type, + }; + } + + private _onManufacturerCodeOverrideChanged(value: ChangeEvent): void { + this._manufacturerCodeOverride = value.detail!.value; + this._issueClusterCommandServiceData = this._computeIssueClusterCommandServiceData(); + } + + private _onHelpTap(): void { + this._showHelp = !this._showHelp; + } + + private _selectedCommandChanged(event: ItemSelectedEvent): void { + this._selectedCommandIndex = event.target!.selected; + this._issueClusterCommandServiceData = this._computeIssueClusterCommandServiceData(); + } + + private renderStyle(): TemplateResult { + if (!this._haStyle) { + this._haStyle = document.importNode( + (document.getElementById("ha-style")! + .children[0] as HTMLTemplateElement).content, + true + ); + } + if (!this._ironFlex) { + this._ironFlex = document.importNode( + (document.getElementById("iron-flex")! + .children[0] as HTMLTemplateElement).content, + true + ); + } + return html` + ${this._ironFlex} ${this._haStyle} + + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "zha-cluster-commands": ZHAClusterCommands; + } +} + +customElements.define("zha-cluster-commands", ZHAClusterCommands); diff --git a/src/panels/config/zha/zha-clusters.ts b/src/panels/config/zha/zha-clusters.ts new file mode 100644 index 0000000000..bf00ffdddd --- /dev/null +++ b/src/panels/config/zha/zha-clusters.ts @@ -0,0 +1,165 @@ +import "@polymer/iron-flex-layout/iron-flex-layout-classes"; +import { + html, + LitElement, + PropertyDeclarations, + PropertyValues, + TemplateResult, +} from "lit-element"; +import "@polymer/paper-card/paper-card"; +import { fireEvent } from "../../../common/dom/fire_event"; +import "../../../components/buttons/ha-call-service-button"; +import "../../../components/ha-service-description"; +import { + Cluster, + fetchClustersForZhaNode, + ZHADeviceEntity, +} from "../../../data/zha"; +import "../../../resources/ha-style"; +import { HomeAssistant } from "../../../types"; +import "../ha-config-section"; +import { ItemSelectedEvent } from "./types"; + +declare global { + // for fire event + interface HASSDomEvents { + "zha-cluster-selected": { + cluster?: Cluster; + }; + } +} + +const computeClusterKey = (cluster: Cluster): string => { + return `${cluster.name} (id: ${cluster.id}, type: ${cluster.type})`; +}; + +export class ZHAClusters extends LitElement { + public hass?: HomeAssistant; + public isWide?: boolean; + public showHelp: boolean; + public selectedEntity?: ZHADeviceEntity; + private _selectedClusterIndex: number; + private _clusters: Cluster[]; + private _haStyle?: DocumentFragment; + private _ironFlex?: DocumentFragment; + + constructor() { + super(); + this.showHelp = false; + this._selectedClusterIndex = -1; + this._clusters = []; + } + + static get properties(): PropertyDeclarations { + return { + hass: {}, + isWide: {}, + showHelp: {}, + selectedEntity: {}, + _selectedClusterIndex: {}, + _clusters: {}, + }; + } + + protected updated(changedProperties: PropertyValues): void { + if (changedProperties.has("selectedEntity")) { + this._clusters = []; + this._selectedClusterIndex = -1; + fireEvent(this, "zha-cluster-selected", { + cluster: undefined, + }); + this._fetchClustersForZhaNode(); + } + super.update(changedProperties); + } + + protected render(): TemplateResult | void { + return html` + ${this._renderStyle()} +
+ + + ${ + this._clusters.map( + (entry) => html` + ${computeClusterKey(entry)} + ` + ) + } + + +
+ ${ + this.showHelp + ? html` +
+ Select cluster to view attributes and commands +
+ ` + : "" + } + `; + } + + private async _fetchClustersForZhaNode(): Promise { + if (this.hass) { + this._clusters = await fetchClustersForZhaNode( + this.hass, + this.selectedEntity!.entity_id, + this.selectedEntity!.device_info!.identifiers[0][1] + ); + } + } + + private _selectedClusterChanged(event: ItemSelectedEvent): void { + this._selectedClusterIndex = event.target!.selected; + fireEvent(this, "zha-cluster-selected", { + cluster: this._clusters[this._selectedClusterIndex], + }); + } + + private _renderStyle(): TemplateResult { + if (!this._haStyle) { + this._haStyle = document.importNode( + (document.getElementById("ha-style")! + .children[0] as HTMLTemplateElement).content, + true + ); + } + if (!this._ironFlex) { + this._ironFlex = document.importNode( + (document.getElementById("iron-flex")! + .children[0] as HTMLTemplateElement).content, + true + ); + } + return html` + ${this._ironFlex} ${this._haStyle} + + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "zha-cluster": ZHAClusters; + } +} + +customElements.define("zha-clusters", ZHAClusters); diff --git a/src/panels/config/zha/zha-entities.ts b/src/panels/config/zha/zha-entities.ts new file mode 100644 index 0000000000..561adf50ad --- /dev/null +++ b/src/panels/config/zha/zha-entities.ts @@ -0,0 +1,177 @@ +import "@polymer/iron-flex-layout/iron-flex-layout-classes"; +import { + html, + LitElement, + PropertyDeclarations, + PropertyValues, + TemplateResult, +} from "lit-element"; +import "@polymer/paper-button/paper-button"; +import "@polymer/paper-item/paper-item"; +import "@polymer/paper-listbox/paper-listbox"; +import { HassEntity } from "home-assistant-js-websocket"; +import { fireEvent } from "../../../common/dom/fire_event"; +import { fetchEntitiesForZhaNode } from "../../../data/zha"; +import "../../../resources/ha-style"; +import { HomeAssistant } from "../../../types"; +import { ItemSelectedEvent } from "./types"; + +declare global { + // for fire event + interface HASSDomEvents { + "zha-entity-selected": { + entity?: HassEntity; + }; + } +} + +export class ZHAEntities extends LitElement { + public hass?: HomeAssistant; + public showHelp?: boolean; + public selectedNode?: HassEntity; + private _selectedEntityIndex: number; + private _entities: HassEntity[]; + private _haStyle?: DocumentFragment; + private _ironFlex?: DocumentFragment; + + constructor() { + super(); + this._entities = []; + this._selectedEntityIndex = -1; + } + + static get properties(): PropertyDeclarations { + return { + hass: {}, + showHelp: {}, + selectedNode: {}, + _selectedEntityIndex: {}, + _entities: {}, + }; + } + + protected updated(changedProperties: PropertyValues): void { + if (changedProperties.has("selectedNode")) { + this._entities = []; + this._selectedEntityIndex = -1; + fireEvent(this, "zha-entity-selected", { + entity: undefined, + }); + this._fetchEntitiesForZhaNode(); + } + super.update(changedProperties); + } + + protected render(): TemplateResult | void { + return html` + ${this._renderStyle()} +
+ + + ${ + this._entities.map( + (entry) => html` + ${entry.entity_id} + ` + ) + } + + +
+ ${ + this.showHelp + ? html` +
+ Select entity to view per-entity options +
+ ` + : "" + } + ${ + this._selectedEntityIndex !== -1 + ? html` +
+ Entity Information +
+ ` + : "" + } + `; + } + + private async _fetchEntitiesForZhaNode(): Promise { + if (this.hass) { + const fetchedEntities = await fetchEntitiesForZhaNode(this.hass); + this._entities = fetchedEntities[this.selectedNode!.attributes.ieee]; + } + } + + private _selectedEntityChanged(event: ItemSelectedEvent): void { + this._selectedEntityIndex = event.target!.selected; + fireEvent(this, "zha-entity-selected", { + entity: this._entities[this._selectedEntityIndex], + }); + } + + private _showEntityInformation(): void { + fireEvent(this, "hass-more-info", { + entityId: this._entities[this._selectedEntityIndex].entity_id, + }); + } + + private _renderStyle(): TemplateResult { + if (!this._haStyle) { + this._haStyle = document.importNode( + (document.getElementById("ha-style")! + .children[0] as HTMLTemplateElement).content, + true + ); + } + if (!this._ironFlex) { + this._ironFlex = document.importNode( + (document.getElementById("iron-flex")! + .children[0] as HTMLTemplateElement).content, + true + ); + } + return html` + ${this._ironFlex} ${this._haStyle} + + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "zha-entities": ZHAEntities; + } +} + +customElements.define("zha-entities", ZHAEntities); diff --git a/src/panels/config/zha/zha-network.ts b/src/panels/config/zha/zha-network.ts index 79c6e2f9e9..1bd65f6859 100644 --- a/src/panels/config/zha/zha-network.ts +++ b/src/panels/config/zha/zha-network.ts @@ -1,42 +1,45 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; -import "@polymer/paper-button/paper-button"; -import "@polymer/paper-icon-button/paper-icon-button"; -import "@polymer/paper-card/paper-card"; import "@polymer/iron-flex-layout/iron-flex-layout-classes"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; +import "@polymer/paper-button/paper-button"; +import "@polymer/paper-card/paper-card"; +import "@polymer/paper-icon-button/paper-icon-button"; import "../../../components/buttons/ha-call-service-button"; import "../../../components/ha-service-description"; -import "../ha-config-section"; - -import { HomeAssistant } from "../../../types"; import "../../../resources/ha-style"; +import { HomeAssistant } from "../../../types"; +import "../ha-config-section"; export class ZHANetwork extends LitElement { public hass?: HomeAssistant; public isWide?: boolean; - public showDescription: boolean; + private _showHelp: boolean; private _haStyle?: DocumentFragment; private _ironFlex?: DocumentFragment; constructor() { super(); - this.showDescription = false; + this._showHelp = false; } static get properties(): PropertyDeclarations { return { hass: {}, isWide: {}, - showDescription: {}, + _showHelp: {}, }; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { return html` ${this.renderStyle()} - +
- Zigbee Home Automation network management + Network Management @@ -49,7 +52,7 @@ export class ZHANetwork extends LitElement { this.hass }" domain="zha" service="permit">Permit ${ - this.showDescription + this._showHelp ? html` +
+ Node Management + +
+ + Run ZHA commands that affect a single node. Pick a node to see a list + of available commands.

Note: Sleepy (battery powered) + devices need to be awake when executing commands against them. You can + generally wake a sleepy device by triggering it.

Some + devices such as Xiaomi sensors have a wake up button that you can + press at ~5 second intervals that keep devices awake while you + interact with them. +
+ +
+ + + ${ + this._nodes.map( + (entry) => html` + ${this._computeSelectCaption(entry)} + ` + ) + } + + +
+ ${ + this._showHelp + ? html` +
+ Select node to view per-node options +
+ ` + : "" + } + ${this._selectedNodeIndex !== -1 ? this._renderNodeActions() : ""} + ${this._selectedNodeIndex !== -1 ? this._renderEntities() : ""} + ${this._selectedEntity ? this._renderClusters() : ""} +
+ + `; + } + + private _renderNodeActions(): TemplateResult { + return html` +
+ Node Information + Reconfigure Node + ${ + this._showHelp + ? html` + + ` + : "" + } + Remove Node + ${ + this._showHelp + ? html` + + ` + : "" + } +
+ `; + } + + private _renderEntities(): TemplateResult { + return html` + + `; + } + + private _renderClusters(): TemplateResult { + return html` + + `; + } + + private _onHelpTap(): void { + this._showHelp = !this._showHelp; + } + + private _selectedNodeChanged(event: ItemSelectedEvent): void { + this._selectedNodeIndex = event!.target!.selected; + this._selectedNode = this._nodes[this._selectedNodeIndex]; + this._selectedEntity = undefined; + fireEvent(this, "zha-node-selected", { node: this._selectedNode }); + this._serviceData = this._computeNodeServiceData(); + } + + private async _onReconfigureNodeClick(): Promise { + if (this.hass) { + await reconfigureNode(this.hass, this._selectedNode!.attributes.ieee); + } + } + + private _showNodeInformation(): void { + fireEvent(this, "hass-more-info", { + entityId: this._selectedNode!.entity_id, + }); + } + + private _computeNodeServiceData(): NodeServiceData { + return { + ieee_address: this._selectedNode!.attributes.ieee, + }; + } + + private _computeSelectCaption(stateObj: HassEntity): string { + return ( + computeStateName(stateObj) + " (Node:" + stateObj.attributes.ieee + ")" + ); + } + + private _computeNodes(hass?: HomeAssistant): HassEntity[] { + if (hass) { + return Object.keys(hass.states) + .map((key) => hass.states[key]) + .filter((ent) => ent.entity_id.match("zha[.]")) + .sort(sortByName); + } else { + return []; + } + } + + private _onEntitySelected( + entitySelectedEvent: HASSDomEvent + ): void { + this._selectedEntity = entitySelectedEvent.detail.entity; + } + + private renderStyle(): TemplateResult { + if (!this._haStyle) { + this._haStyle = document.importNode( + (document.getElementById("ha-style")! + .children[0] as HTMLTemplateElement).content, + true + ); + } + if (!this._ironFlex) { + this._ironFlex = document.importNode( + (document.getElementById("iron-flex")! + .children[0] as HTMLTemplateElement).content, + true + ); + } + return html` + ${this._ironFlex} ${this._haStyle} + + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "zha-node": ZHANode; + } +} + +customElements.define("zha-node", ZHANode); diff --git a/src/panels/dev-info/ha-panel-dev-info.js b/src/panels/dev-info/ha-panel-dev-info.js index 0bf12ed769..799cc8e810 100644 --- a/src/panels/dev-info/ha-panel-dev-info.js +++ b/src/panels/dev-info/ha-panel-dev-info.js @@ -20,7 +20,7 @@ import formatTime from "../../common/datetime/format_time"; import EventsMixin from "../../mixins/events-mixin"; import LocalizeMixin from "../../mixins/localize-mixin"; -const OPT_IN_PANEL = "lovelace"; +const OPT_IN_PANEL = "states"; let registeredDialog = false; class HaPanelDevInfo extends EventsMixin(LocalizeMixin(PolymerElement)) { @@ -167,7 +167,7 @@ class HaPanelDevInfo extends EventsMixin(LocalizeMixin(PolymerElement)) {

- Try out the new Lovelace UI + [[_nonDefaultLinkText()]]

[[_defaultPageText()]]
@@ -366,6 +366,26 @@ class HaPanelDevInfo extends EventsMixin(LocalizeMixin(PolymerElement)) { }); } + _nonDefaultLink() { + if ( + localStorage.defaultPage === OPT_IN_PANEL && + OPT_IN_PANEL === "states" + ) { + return "/lovelace"; + } + return "/states"; + } + + _nonDefaultLinkText() { + if ( + localStorage.defaultPage === OPT_IN_PANEL && + OPT_IN_PANEL === "states" + ) { + return "Go to the Lovelace UI"; + } + return "Go to the states UI"; + } + _defaultPageText() { return `>> ${ localStorage.defaultPage === OPT_IN_PANEL ? "Remove" : "Set" diff --git a/src/panels/lovelace/cards/hui-alarm-panel-card.ts b/src/panels/lovelace/cards/hui-alarm-panel-card.ts index 2f560f22a8..832d3ca9cd 100644 --- a/src/panels/lovelace/cards/hui-alarm-panel-card.ts +++ b/src/panels/lovelace/cards/hui-alarm-panel-card.ts @@ -3,14 +3,17 @@ import { LitElement, PropertyValues, PropertyDeclarations, -} from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; -import { classMap } from "lit-html/directives/classMap"; + TemplateResult, +} from "lit-element"; +import { classMap } from "lit-html/directives/class-map"; import { LovelaceCard } from "../types"; import { HomeAssistant } from "../../../types"; import { LovelaceCardConfig } from "../../../data/lovelace"; -import { callAlarmAction } from "../../../data/alarm_control_panel"; +import { + callAlarmAction, + FORMAT_NUMBER, +} from "../../../data/alarm_control_panel"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; import "../../../components/ha-card"; @@ -97,7 +100,7 @@ class HuiAlarmPanelCard extends hassLocalizeLitMixin(LitElement) return true; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._config || !this.hass) { return html``; } @@ -150,7 +153,7 @@ class HuiAlarmPanelCard extends hassLocalizeLitMixin(LitElement) ` } ${ - stateObj.attributes.code_format !== "Number" + stateObj.attributes.code_format !== FORMAT_NUMBER ? html`` : html`
@@ -206,7 +209,7 @@ class HuiAlarmPanelCard extends hassLocalizeLitMixin(LitElement) private _handleActionClick(e: MouseEvent): void { callAlarmAction( this.hass!, - this._config!.entity_id, + this._config!.entity, (e.currentTarget! as any).action, this._code! ); diff --git a/src/panels/lovelace/cards/hui-entities-card.ts b/src/panels/lovelace/cards/hui-entities-card.ts index 13e36603f6..98b919c4f2 100644 --- a/src/panels/lovelace/cards/hui-entities-card.ts +++ b/src/panels/lovelace/cards/hui-entities-card.ts @@ -3,8 +3,8 @@ import { LitElement, PropertyDeclarations, PropertyValues, -} from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; + TemplateResult, +} from "lit-element"; import "../../../components/ha-card"; import "../components/hui-entities-toggle"; @@ -21,7 +21,7 @@ import { createRowElement } from "../common/create-row-element"; import computeDomain from "../../../common/entity/compute_domain"; import applyThemesOnElement from "../../../common/dom/apply_themes_on_element"; -export interface ConfigEntity extends EntityConfig { +export interface EntitiesCardEntityConfig extends EntityConfig { type?: string; secondary_info?: "entity-id" | "last-changed"; action_name?: string; @@ -30,10 +30,10 @@ export interface ConfigEntity extends EntityConfig { url?: string; } -export interface Config extends LovelaceCardConfig { +export interface EntitiesCardConfig extends LovelaceCardConfig { show_header_toggle?: boolean; title?: string; - entities: ConfigEntity[]; + entities: EntitiesCardEntityConfig[]; theme?: string; } @@ -49,8 +49,8 @@ class HuiEntitiesCard extends hassLocalizeLitMixin(LitElement) } protected _hass?: HomeAssistant; - protected _config?: Config; - protected _configEntities?: ConfigEntity[]; + protected _config?: EntitiesCardConfig; + protected _configEntities?: EntitiesCardEntityConfig[]; set hass(hass: HomeAssistant) { this._hass = hass; @@ -81,7 +81,7 @@ class HuiEntitiesCard extends hassLocalizeLitMixin(LitElement) return (this._config.title ? 1 : 0) + this._config.entities.length; } - public setConfig(config: Config): void { + public setConfig(config: EntitiesCardConfig): void { const entities = processConfigEntities(config.entities); this._config = { theme: "default", ...config }; @@ -95,7 +95,7 @@ class HuiEntitiesCard extends hassLocalizeLitMixin(LitElement) } } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._config || !this._hass) { return html``; } @@ -171,7 +171,7 @@ class HuiEntitiesCard extends hassLocalizeLitMixin(LitElement) `; } - private renderEntity(entityConf: ConfigEntity): TemplateResult { + private renderEntity(entityConf: EntitiesCardEntityConfig): TemplateResult { const element = createRowElement(entityConf); if (this._hass) { element.hass = this._hass; @@ -189,7 +189,7 @@ class HuiEntitiesCard extends hassLocalizeLitMixin(LitElement) `; } - private _handleClick(entityConf: ConfigEntity): void { + private _handleClick(entityConf: EntitiesCardEntityConfig): void { const entityId = entityConf.entity; fireEvent(this, "hass-more-info", { entityId }); } diff --git a/src/panels/lovelace/cards/hui-entity-button-card.ts b/src/panels/lovelace/cards/hui-entity-button-card.ts index 31c826c77c..992899a830 100644 --- a/src/panels/lovelace/cards/hui-entity-button-card.ts +++ b/src/panels/lovelace/cards/hui-entity-button-card.ts @@ -3,10 +3,10 @@ import { LitElement, PropertyDeclarations, PropertyValues, -} from "@polymer/lit-element"; + TemplateResult, +} from "lit-element"; import { HassEntity } from "home-assistant-js-websocket"; -import { TemplateResult } from "lit-html"; -import { styleMap } from "lit-html/directives/styleMap"; +import { styleMap } from "lit-html/directives/style-map"; import "../../../components/ha-card"; @@ -82,7 +82,7 @@ class HuiEntityButtonCard extends hassLocalizeLitMixin(LitElement) return true; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._config || !this.hass) { return html``; } diff --git a/src/panels/lovelace/cards/hui-error-card.ts b/src/panels/lovelace/cards/hui-error-card.ts index 59981fc7fb..95d535061b 100644 --- a/src/panels/lovelace/cards/hui-error-card.ts +++ b/src/panels/lovelace/cards/hui-error-card.ts @@ -1,8 +1,7 @@ -import { html, LitElement } from "@polymer/lit-element"; +import { html, LitElement, TemplateResult } from "lit-element"; import { LovelaceCard } from "../types"; import { LovelaceCardConfig } from "../../../data/lovelace"; -import { TemplateResult } from "lit-html"; import { HomeAssistant } from "../../../types"; interface Config extends LovelaceCardConfig { @@ -40,7 +39,7 @@ export class HuiErrorCard extends LitElement implements LovelaceCard { this._config = config; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._config) { return html``; } diff --git a/src/panels/lovelace/cards/hui-gauge-card.ts b/src/panels/lovelace/cards/hui-gauge-card.ts index 27c1f1bb28..7432154e8e 100644 --- a/src/panels/lovelace/cards/hui-gauge-card.ts +++ b/src/panels/lovelace/cards/hui-gauge-card.ts @@ -3,9 +3,9 @@ import { LitElement, PropertyDeclarations, PropertyValues, -} from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; -import { styleMap } from "lit-html/directives/styleMap"; + TemplateResult, +} from "lit-element"; +import { styleMap } from "lit-html/directives/style-map"; import "../../../components/ha-card"; import { LovelaceCardConfig } from "../../../data/lovelace"; @@ -56,6 +56,7 @@ class HuiGaugeCard extends LitElement implements LovelaceCard { public hass?: HomeAssistant; private _config?: Config; + private _updated?: boolean; static get properties(): PropertyDeclarations { return { @@ -78,7 +79,12 @@ class HuiGaugeCard extends LitElement implements LovelaceCard { this._config = { min: 0, max: 100, theme: "default", ...config }; } - protected render(): TemplateResult { + public connectedCallback(): void { + super.connectedCallback(); + this._setBaseUnit(); + } + + protected render(): TemplateResult | void { if (!this._config || !this.hass) { return html``; } @@ -148,12 +154,8 @@ class HuiGaugeCard extends LitElement implements LovelaceCard { } protected firstUpdated(): void { - (this.shadowRoot!.querySelector( - "ha-card" - )! as HTMLElement).style.setProperty( - "--base-unit", - this._computeBaseUnit() - ); + this._updated = true; + this._setBaseUnit(); } protected updated(changedProps: PropertyValues): void { @@ -169,6 +171,19 @@ class HuiGaugeCard extends LitElement implements LovelaceCard { } } + private _setBaseUnit(): void { + if (!this.isConnected || !this._updated) { + return; + } + const baseUnit = this._computeBaseUnit(); + if (baseUnit === "0px") { + return; + } + (this.shadowRoot!.querySelector( + "ha-card" + )! as HTMLElement).style.setProperty("--base-unit", baseUnit); + } + private _computeSeverity(numberValue: number): string { const sections = this._config!.severity; diff --git a/src/panels/lovelace/cards/hui-glance-card.ts b/src/panels/lovelace/cards/hui-glance-card.ts index 7d07f62b49..76f3f767f7 100644 --- a/src/panels/lovelace/cards/hui-glance-card.ts +++ b/src/panels/lovelace/cards/hui-glance-card.ts @@ -3,9 +3,9 @@ import { LitElement, PropertyValues, PropertyDeclarations, -} from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; -import { classMap } from "lit-html/directives/classMap"; + TemplateResult, +} from "lit-element"; +import { classMap } from "lit-html/directives/class-map"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; import { HomeAssistant } from "../../../types"; @@ -114,7 +114,7 @@ export class HuiGlanceCard extends hassLocalizeLitMixin(LitElement) return true; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._config || !this.hass) { return html``; } diff --git a/src/panels/lovelace/cards/hui-horizontal-stack-card.ts b/src/panels/lovelace/cards/hui-horizontal-stack-card.ts index 39d5acf1ec..e1427fbe1d 100644 --- a/src/panels/lovelace/cards/hui-horizontal-stack-card.ts +++ b/src/panels/lovelace/cards/hui-horizontal-stack-card.ts @@ -1,5 +1,4 @@ -import { html } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { html, TemplateResult } from "lit-element"; import { computeCardSize } from "../common/compute-card-size"; import { HuiStackCard } from "./hui-stack-card"; diff --git a/src/panels/lovelace/cards/hui-iframe-card.ts b/src/panels/lovelace/cards/hui-iframe-card.ts index 0b43162179..b07b0a0795 100644 --- a/src/panels/lovelace/cards/hui-iframe-card.ts +++ b/src/panels/lovelace/cards/hui-iframe-card.ts @@ -1,11 +1,15 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "../../../components/ha-card"; import { LovelaceCard, LovelaceCardEditor } from "../types"; import { LovelaceCardConfig } from "../../../data/lovelace"; -import { TemplateResult } from "lit-html"; -import { styleMap } from "lit-html/directives/styleMap"; +import { styleMap } from "lit-html/directives/style-map"; export interface Config extends LovelaceCardConfig { aspect_ratio?: string; @@ -31,7 +35,13 @@ export class HuiIframeCard extends LitElement implements LovelaceCard { } public getCardSize(): number { - return 1 + this.offsetHeight / 50; + if (!this._config) { + return 3; + } + const aspectRatio = this._config.aspect_ratio + ? Number(this._config.aspect_ratio.replace("%", "")) + : 50; + return 1 + aspectRatio / 25; } public setConfig(config: Config): void { @@ -42,7 +52,7 @@ export class HuiIframeCard extends LitElement implements LovelaceCard { this._config = config; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._config) { return html``; } @@ -75,7 +85,6 @@ export class HuiIframeCard extends LitElement implements LovelaceCard { #root { width: 100%; position: relative; - padding-top: ${this._config!.aspect_ratio || "50%"}; } iframe { position: absolute; diff --git a/src/panels/lovelace/cards/hui-light-card.ts b/src/panels/lovelace/cards/hui-light-card.ts index 22e58e4ca8..90df1b1534 100644 --- a/src/panels/lovelace/cards/hui-light-card.ts +++ b/src/panels/lovelace/cards/hui-light-card.ts @@ -3,11 +3,11 @@ import { LitElement, PropertyValues, PropertyDeclarations, -} from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; + TemplateResult, +} from "lit-element"; import { fireEvent } from "../../../common/dom/fire_event"; -import { styleMap } from "lit-html/directives/styleMap"; +import { styleMap } from "lit-html/directives/style-map"; import { HomeAssistant, LightEntity } from "../../../types"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; import { LovelaceCard, LovelaceCardEditor } from "../types"; @@ -82,7 +82,7 @@ export class HuiLightCard extends hassLocalizeLitMixin(LitElement) this._config = { theme: "default", ...config }; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this.hass || !this._config) { return html``; } diff --git a/src/panels/lovelace/cards/hui-map-card.js b/src/panels/lovelace/cards/hui-map-card.js index a77a0afc01..a64eadd606 100644 --- a/src/panels/lovelace/cards/hui-map-card.js +++ b/src/panels/lovelace/cards/hui-map-card.js @@ -247,7 +247,10 @@ class HuiMapCard extends PolymerElement { const stateObj = this.hass.states[entityId]; if ( computeStateDomain(stateObj) === "geo_location" && - this._configGeoLocationSources.includes(stateObj.attributes.source) + (this._configGeoLocationSources.includes( + stateObj.attributes.source + ) || + this._configGeoLocationSources.includes("all")) ) { allEntities.push(entityId); } diff --git a/src/panels/lovelace/cards/hui-markdown-card.ts b/src/panels/lovelace/cards/hui-markdown-card.ts index e61be9c63c..8e714a0131 100644 --- a/src/panels/lovelace/cards/hui-markdown-card.ts +++ b/src/panels/lovelace/cards/hui-markdown-card.ts @@ -1,12 +1,16 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { classMap } from "lit-html/directives/classMap"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; +import { classMap } from "lit-html/directives/class-map"; import "../../../components/ha-card"; import "../../../components/ha-markdown"; import { LovelaceCard, LovelaceCardEditor } from "../types"; import { LovelaceCardConfig } from "../../../data/lovelace"; -import { TemplateResult } from "lit-html"; export interface Config extends LovelaceCardConfig { content: string; @@ -42,7 +46,7 @@ export class HuiMarkdownCard extends LitElement implements LovelaceCard { this._config = config; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._config) { return html``; } diff --git a/src/panels/lovelace/cards/hui-picture-card.ts b/src/panels/lovelace/cards/hui-picture-card.ts index b0799b6eb9..24435ad518 100644 --- a/src/panels/lovelace/cards/hui-picture-card.ts +++ b/src/panels/lovelace/cards/hui-picture-card.ts @@ -1,12 +1,16 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "../../../components/ha-card"; import { LovelaceCard, LovelaceCardEditor } from "../types"; import { LovelaceCardConfig, ActionConfig } from "../../../data/lovelace"; import { HomeAssistant } from "../../../types"; -import { TemplateResult } from "lit-html"; -import { classMap } from "lit-html/directives/classMap"; +import { classMap } from "lit-html/directives/class-map"; import { handleClick } from "../common/handle-click"; import { longPress } from "../common/directives/long-press-directive"; @@ -49,7 +53,7 @@ export class HuiPictureCard extends LitElement implements LovelaceCard { this._config = config; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._config || !this.hass) { return html``; } diff --git a/src/panels/lovelace/cards/hui-picture-elements-card.ts b/src/panels/lovelace/cards/hui-picture-elements-card.ts index 83114f772e..0562630f86 100644 --- a/src/panels/lovelace/cards/hui-picture-elements-card.ts +++ b/src/panels/lovelace/cards/hui-picture-elements-card.ts @@ -1,5 +1,4 @@ -import { html, LitElement } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { html, LitElement, TemplateResult } from "lit-element"; import { createHuiElement } from "../common/create-hui-element"; @@ -55,7 +54,7 @@ class HuiPictureElementsCard extends LitElement implements LovelaceCard { this._config = config; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._config) { return html``; } diff --git a/src/panels/lovelace/cards/hui-picture-entity-card.ts b/src/panels/lovelace/cards/hui-picture-entity-card.ts index 9fa9a2c896..718e694fe9 100644 --- a/src/panels/lovelace/cards/hui-picture-entity-card.ts +++ b/src/panels/lovelace/cards/hui-picture-entity-card.ts @@ -1,6 +1,10 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html/lib/shady-render"; -import { classMap } from "lit-html/directives/classMap"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; +import { classMap } from "lit-html/directives/class-map"; import "../../../components/ha-card"; import "../components/hui-image"; @@ -65,7 +69,7 @@ class HuiPictureEntityCard extends hassLocalizeLitMixin(LitElement) this._config = { show_name: true, show_state: true, ...config }; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._config || !this.hass) { return html``; } diff --git a/src/panels/lovelace/cards/hui-picture-glance-card.ts b/src/panels/lovelace/cards/hui-picture-glance-card.ts index 1a98be568a..f83848a5e8 100644 --- a/src/panels/lovelace/cards/hui-picture-glance-card.ts +++ b/src/panels/lovelace/cards/hui-picture-glance-card.ts @@ -1,6 +1,10 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { classMap } from "lit-html/directives/classMap"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; +import { classMap } from "lit-html/directives/class-map"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; import { DOMAINS_TOGGLE } from "../../../common/const"; @@ -83,7 +87,7 @@ class HuiPictureGlanceCard extends hassLocalizeLitMixin(LitElement) this._config = config; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._config || !this.hass) { return html``; } diff --git a/src/panels/lovelace/cards/hui-sensor-card.ts b/src/panels/lovelace/cards/hui-sensor-card.ts index 2a8394bea4..aeec27c82e 100755 --- a/src/panels/lovelace/cards/hui-sensor-card.ts +++ b/src/panels/lovelace/cards/hui-sensor-card.ts @@ -4,8 +4,8 @@ import { LitElement, PropertyDeclarations, PropertyValues, -} from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; + TemplateResult, +} from "lit-element"; import "@polymer/paper-spinner/paper-spinner"; import { LovelaceCard, LovelaceCardEditor } from "../types"; @@ -192,7 +192,7 @@ class HuiSensorCard extends LitElement implements LovelaceCard { return 3; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._config || !this.hass) { return html``; } diff --git a/src/panels/lovelace/cards/hui-shopping-list-card.ts b/src/panels/lovelace/cards/hui-shopping-list-card.ts index c0cff3b086..13099310ba 100644 --- a/src/panels/lovelace/cards/hui-shopping-list-card.ts +++ b/src/panels/lovelace/cards/hui-shopping-list-card.ts @@ -1,6 +1,5 @@ -import { html, LitElement } from "@polymer/lit-element"; +import { html, LitElement, TemplateResult } from "lit-element"; import { repeat } from "lit-html/directives/repeat"; -import { TemplateResult } from "lit-html"; import { PaperInputElement } from "@polymer/paper-input/paper-input"; import "@polymer/paper-checkbox/paper-checkbox"; @@ -79,7 +78,7 @@ class HuiShoppingListCard extends hassLocalizeLitMixin(LitElement) } } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._config || !this.hass) { return html``; } diff --git a/src/panels/lovelace/cards/hui-stack-card.ts b/src/panels/lovelace/cards/hui-stack-card.ts index d5f13689c7..c3fdd18ba6 100644 --- a/src/panels/lovelace/cards/hui-stack-card.ts +++ b/src/panels/lovelace/cards/hui-stack-card.ts @@ -1,5 +1,4 @@ -import { html, LitElement } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { html, LitElement, TemplateResult } from "lit-element"; import { createCardElement } from "../common/create-card-element"; @@ -12,10 +11,6 @@ interface Config extends LovelaceCardConfig { } export abstract class HuiStackCard extends LitElement implements LovelaceCard { - protected _cards?: LovelaceCard[]; - private _config?: Config; - private _hass?: HomeAssistant; - static get properties() { return { _config: {}, @@ -33,6 +28,9 @@ export abstract class HuiStackCard extends LitElement implements LovelaceCard { element.hass = this._hass; } } + protected _cards?: LovelaceCard[]; + private _config?: Config; + private _hass?: HomeAssistant; public abstract getCardSize(): number; @@ -42,15 +40,12 @@ export abstract class HuiStackCard extends LitElement implements LovelaceCard { } this._config = config; this._cards = config.cards.map((card) => { - const element = createCardElement(card) as LovelaceCard; - if (this._hass) { - element.hass = this._hass; - } + const element = this._createCardElement(card) as LovelaceCard; return element; }); } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._config) { return html``; } @@ -62,4 +57,31 @@ export abstract class HuiStackCard extends LitElement implements LovelaceCard { } protected abstract renderStyle(): TemplateResult; + + private _createCardElement(cardConfig: LovelaceCardConfig) { + const element = createCardElement(cardConfig) as LovelaceCard; + if (this._hass) { + element.hass = this._hass; + } + element.addEventListener( + "ll-rebuild", + (ev) => { + ev.stopPropagation(); + this._rebuildCard(element, cardConfig); + }, + { once: true } + ); + return element; + } + + private _rebuildCard( + cardElToReplace: LovelaceCard, + config: LovelaceCardConfig + ): void { + const newCardEl = this._createCardElement(config); + cardElToReplace.parentElement!.replaceChild(newCardEl, cardElToReplace); + this._cards = this._cards!.map((curCardEl) => + curCardEl === cardElToReplace ? newCardEl : curCardEl + ); + } } diff --git a/src/panels/lovelace/cards/hui-thermostat-card.ts b/src/panels/lovelace/cards/hui-thermostat-card.ts index a8115c190a..ba84e5e7ae 100644 --- a/src/panels/lovelace/cards/hui-thermostat-card.ts +++ b/src/panels/lovelace/cards/hui-thermostat-card.ts @@ -3,9 +3,9 @@ import { LitElement, PropertyDeclarations, PropertyValues, -} from "@polymer/lit-element"; -import { classMap } from "lit-html/directives/classMap"; -import { TemplateResult } from "lit-html"; + TemplateResult, +} from "lit-element"; +import { classMap } from "lit-html/directives/class-map"; import "../../../components/ha-card"; import "../../../components/ha-icon"; @@ -51,18 +51,6 @@ export interface Config extends LovelaceCardConfig { name?: string; } -function formatTemp(temps: string[]): string { - return temps.filter(Boolean).join("-"); -} - -function computeTemperatureStepSize(hass: HomeAssistant, config: Config) { - const stateObj = hass.states[config.entity]; - if (stateObj.attributes.target_temp_step) { - return stateObj.attributes.target_temp_step; - } - return hass.config.unit_system.temperature === UNIT_F ? 1 : 0.5; -} - export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement) implements LovelaceCard { public static async getConfigElement(): Promise { @@ -79,6 +67,8 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement) private _roundSliderStyle?: TemplateResult; private _jQuery?: any; private _broadCard?: boolean; + private _loaded?: boolean; + private _updated?: boolean; static get properties(): PropertyDeclarations { return { @@ -101,7 +91,14 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement) this._config = { theme: "default", ...config }; } - protected render(): TemplateResult { + public connectedCallback(): void { + super.connectedCallback(); + if (this._updated && !this._loaded) { + this._initialLoad(); + } + } + + protected render(): TemplateResult | void { if (!this.hass || !this._config) { return html``; } @@ -157,7 +154,10 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement) } protected firstUpdated(): void { - this._initialLoad(); + this._updated = true; + if (this.isConnected && !this._loaded) { + this._initialLoad(); + } } protected updated(changedProps: PropertyValues): void { @@ -189,13 +189,23 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement) } } + private get _stepSize(): number { + const stateObj = this.hass!.states[this._config!.entity]; + if (stateObj.attributes.target_temp_step) { + return stateObj.attributes.target_temp_step; + } + return this.hass!.config.unit_system.temperature === UNIT_F ? 1 : 0.5; + } + private async _initialLoad(): Promise { - const radius = this.clientWidth / 3; + this._loaded = true; + + const radius = this.clientWidth / 3.2; this._broadCard = this.clientWidth > 390; (this.shadowRoot!.querySelector( "#thermostat" - )! as HTMLElement).style.minHeight = radius * 2 + "px"; + )! as HTMLElement).style.height = radius * 2 + "px"; const loaded = await loadRoundslider(); await new Promise((resolve) => afterNextRender(resolve)); @@ -212,7 +222,6 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement) : "min-range"; const [sliderValue, uiValue] = this._genSliderValue(stateObj); - const step = computeTemperatureStepSize(this.hass!, this._config!); this._jQuery("#thermostat", this.shadowRoot).roundSlider({ ...thermostatConfig, @@ -220,11 +229,10 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement) min: stateObj.attributes.min_temp, max: stateObj.attributes.max_temp, sliderType: _sliderType, - create: () => this._loaded(), change: (value) => this._setTemperature(value), drag: (value) => this._dragEvent(value), value: sliderValue, - step, + step: this._stepSize, }); this._updateSetTemp(uiValue); } @@ -240,10 +248,13 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement) sliderValue = `${stateObj.attributes.target_temp_low}, ${ stateObj.attributes.target_temp_high }`; - uiValue = formatTemp([ - String(stateObj.attributes.target_temp_low), - String(stateObj.attributes.target_temp_high), - ]); + uiValue = this.formatTemp( + [ + String(stateObj.attributes.target_temp_low), + String(stateObj.attributes.target_temp_high), + ], + false + ); } else { sliderValue = stateObj.attributes.temperature; uiValue = "" + stateObj.attributes.temperature; @@ -252,18 +263,12 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement) return [sliderValue, uiValue]; } - private _loaded(): void { - (this.shadowRoot!.querySelector( - "#thermostat" - )! as HTMLElement).style.minHeight = null; - } - private _updateSetTemp(value: string): void { this.shadowRoot!.querySelector("#set-temperature")!.innerHTML = value; } private _dragEvent(e): void { - this._updateSetTemp(formatTemp(String(e.value).split(","))); + this._updateSetTemp(this.formatTemp(String(e.value).split(","), true)); } private _setTemperature(e): void { @@ -314,6 +319,21 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement) }); } + private formatTemp(temps: string[], spaceStepSize: boolean): string { + temps = temps.filter(Boolean); + + // If we are sliding the slider, append 0 to the temperatures if we're + // having a 0.5 step size, so that the text doesn't jump while sliding + if (spaceStepSize) { + const stepSize = this._stepSize; + temps = temps.map((val) => + val.includes(".") || stepSize === 1 ? val : `${val}.0` + ); + } + + return temps.join("-"); + } + private renderStyle(): TemplateResult { return html` ${this._roundSliderStyle} @@ -370,39 +390,37 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement) --mode-color: var(--unknown-color); } .no-title { - --title-margin-top: 33% !important; + --title-position-top: 33% !important; } .large { --thermostat-padding-top: 25px; --thermostat-margin-bottom: 25px; --title-font-size: 28px; - --title-margin-top: 20%; - --climate-info-margin-top: 17%; - --modes-margin-top: 2%; + --title-position-top: 27%; + --climate-info-position-top: 81%; --set-temperature-font-size: 25px; --current-temperature-font-size: 71px; - --current-temperature-margin-top: 10%; + --current-temperature-position-top: 10%; --current-temperature-text-padding-left: 15px; --uom-font-size: 20px; --uom-margin-left: -18px; --current-mode-font-size: 18px; - --set-temperature-padding-bottom: 5px; + --set-temperature-margin-bottom: -5px; } .small { --thermostat-padding-top: 15px; --thermostat-margin-bottom: 15px; --title-font-size: 18px; - --title-margin-top: 20%; - --climate-info-margin-top: 7.5%; - --modes-margin-top: 1%; + --title-position-top: 28%; + --climate-info-position-top: 79%; --set-temperature-font-size: 16px; --current-temperature-font-size: 25px; - --current-temperature-margin-top: 5%; + --current-temperature-position-top: 5%; --current-temperature-text-padding-left: 7px; --uom-font-size: 12px; --uom-margin-left: -5px; --current-mode-font-size: 14px; - --set-temperature-padding-bottom: 0px; + --set-temperature-margin-bottom: 0px; } #thermostat { margin: 0 auto var(--thermostat-margin-bottom); @@ -449,21 +467,28 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement) } #set-temperature { font-size: var(--set-temperature-font-size); - padding-bottom: var(--set-temperature-padding-bottom); + margin-bottom: var(--set-temperature-margin-bottom); } .title { font-size: var(--title-font-size); - margin-top: var(--title-margin-top); + position: absolute; + top: var(--title-position-top); + left: 50%; + transform: translate(-50%, -50%); } .climate-info { - margin-top: var(--climate-info-margin-top); + position: absolute; + top: var(--climate-info-position-top); + left: 50%; + transform: translate(-50%, -50%); + width: 100%; } .current-mode { font-size: var(--current-mode-font-size); color: var(--secondary-text-color); } .modes { - margin-top: var(--modes-margin-top); + margin-top: 16px; } .modes ha-icon { color: var(--disabled-text-color); @@ -475,7 +500,10 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement) color: var(--mode-color); } .current-temperature { - margin-top: var(--current-temperature-margin-top); + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); font-size: var(--current-temperature-font-size); } .current-temperature-text { diff --git a/src/panels/lovelace/cards/hui-vertical-stack-card.ts b/src/panels/lovelace/cards/hui-vertical-stack-card.ts index b868e1226e..a36c37ea6b 100644 --- a/src/panels/lovelace/cards/hui-vertical-stack-card.ts +++ b/src/panels/lovelace/cards/hui-vertical-stack-card.ts @@ -1,8 +1,7 @@ -import { html } from "@polymer/lit-element"; +import { html, TemplateResult } from "lit-element"; import { computeCardSize } from "../common/compute-card-size"; import { HuiStackCard } from "./hui-stack-card"; -import { TemplateResult } from "lit-html"; class HuiVerticalStackCard extends HuiStackCard { public getCardSize() { diff --git a/src/panels/lovelace/common/create-card-element.ts b/src/panels/lovelace/common/create-card-element.ts index 0b7c18a562..f10d5bd9b5 100644 --- a/src/panels/lovelace/common/create-card-element.ts +++ b/src/panels/lovelace/common/create-card-element.ts @@ -106,7 +106,7 @@ export const createCardElement = ( customElements.whenDefined(tag).then(() => { clearTimeout(timer); - fireEvent(element, "rebuild-view"); + fireEvent(element, "ll-rebuild"); }); return element; diff --git a/src/panels/lovelace/common/create-hui-element.ts b/src/panels/lovelace/common/create-hui-element.ts index eac2082a3d..8b15a4fec1 100644 --- a/src/panels/lovelace/common/create-hui-element.ts +++ b/src/panels/lovelace/common/create-hui-element.ts @@ -72,7 +72,7 @@ export const createHuiElement = ( customElements.whenDefined(tag).then(() => { clearTimeout(timer); - fireEvent(element, "rebuild-view"); + fireEvent(element, "ll-rebuild"); }); return element; diff --git a/src/panels/lovelace/common/create-row-element.ts b/src/panels/lovelace/common/create-row-element.ts index a2bc40f8d0..9f0aa654f8 100644 --- a/src/panels/lovelace/common/create-row-element.ts +++ b/src/panels/lovelace/common/create-row-element.ts @@ -52,6 +52,9 @@ const DOMAIN_TO_ELEMENT_TYPE = { timer: "timer", switch: "toggle", vacuum: "toggle", + // Temporary. Once climate is rewritten, + // water heater should get it's own row. + water_heater: "climate", }; const TIMEOUT = 2000; @@ -115,7 +118,7 @@ export const createRowElement = ( customElements.whenDefined(tag).then(() => { clearTimeout(timer); - fireEvent(element, "rebuild-view"); + fireEvent(element, "ll-rebuild"); }); return element; diff --git a/src/panels/lovelace/common/directives/long-press-directive.ts b/src/panels/lovelace/common/directives/long-press-directive.ts index 879a0f3089..09f68e5faa 100644 --- a/src/panels/lovelace/common/directives/long-press-directive.ts +++ b/src/panels/lovelace/common/directives/long-press-directive.ts @@ -1,5 +1,8 @@ import { directive, PropertyPart } from "lit-html"; -import "@material/mwc-ripple"; +// See https://github.com/home-assistant/home-assistant-polymer/pull/2457 +// on how to undo mwc -> paper migration +// import "@material/mwc-ripple"; +import "@polymer/paper-ripple"; const isTouch = "ontouchstart" in window || @@ -25,7 +28,7 @@ class LongPress extends HTMLElement implements LongPress { constructor() { super(); this.holdTime = 500; - this.ripple = document.createElement("mwc-ripple"); + this.ripple = document.createElement("paper-ripple"); this.timer = undefined; this.held = false; this.cooldownStart = false; @@ -34,6 +37,7 @@ class LongPress extends HTMLElement implements LongPress { public connectedCallback() { Object.assign(this.style, { + borderRadius: "50%", // paper-ripple position: "absolute", width: isTouch ? "100px" : "50px", height: isTouch ? "100px" : "50px", @@ -42,7 +46,9 @@ class LongPress extends HTMLElement implements LongPress { }); this.appendChild(this.ripple); - this.ripple.primary = true; + this.ripple.style.color = "#03a9f4"; // paper-ripple + this.ripple.style.color = "var(--primary-color)"; // paper-ripple + // this.ripple.primary = true; [ "touchcancel", @@ -140,14 +146,17 @@ class LongPress extends HTMLElement implements LongPress { top: `${y}px`, display: null, }); - this.ripple.disabled = false; - this.ripple.active = true; - this.ripple.unbounded = true; + this.ripple.holdDown = true; // paper-ripple + this.ripple.simulatedRipple(); // paper-ripple + // this.ripple.disabled = false; + // this.ripple.active = true; + // this.ripple.unbounded = true; } private stopAnimation() { - this.ripple.active = false; - this.ripple.disabled = true; + this.ripple.holdDown = false; // paper-ripple + // this.ripple.active = false; + // this.ripple.disabled = true; this.style.display = "none"; } } @@ -174,7 +183,6 @@ export const longPressBind = (element: LongPressElement) => { longpress.bind(element); }; -export const longPress = () => - directive((part: PropertyPart) => { - longPressBind(part.committer.element); - }); +export const longPress = directive(() => (part: PropertyPart) => { + longPressBind(part.committer.element); +}); diff --git a/src/panels/lovelace/common/generate-lovelace-config.ts b/src/panels/lovelace/common/generate-lovelace-config.ts index 9357526bdf..0ec77548ae 100644 --- a/src/panels/lovelace/common/generate-lovelace-config.ts +++ b/src/panels/lovelace/common/generate-lovelace-config.ts @@ -14,6 +14,7 @@ import computeStateDomain from "../../../common/entity/compute_state_domain"; import { LocalizeFunc } from "../../../mixins/localize-base-mixin"; import computeDomain from "../../../common/entity/compute_domain"; import { EntityRowConfig, WeblinkConfig } from "../entity-rows/types"; +import { EntitiesCardConfig } from "../cards/hui-entities-card"; const DEFAULT_VIEW_ENTITY_ID = "group.default_view"; const DOMAINS_BADGES = [ @@ -24,11 +25,15 @@ const DOMAINS_BADGES = [ "sun", "timer", ]; -const HIDE_DOMAIN = new Set(["persistent_notification", "configurator"]); +const HIDE_DOMAIN = new Set([ + "persistent_notification", + "configurator", + "geo_location", +]); const computeCards = ( - title: string, - states: Array<[string, HassEntity]> + states: Array<[string, HassEntity]>, + entityCardOptions: Partial ): LovelaceCardConfig[] => { const cards: LovelaceCardConfig[] = []; @@ -68,7 +73,7 @@ const computeCards = ( type: "weather-forecast", entity: entityId, }); - } else if (domain === "weblink") { + } else if (domain === "weblink" && stateObj) { const conf: WeblinkConfig = { type: "weblink", url: stateObj.state, @@ -85,9 +90,9 @@ const computeCards = ( if (entities.length > 0) { cards.unshift({ - title, type: "entities", entities, + ...entityCardOptions, }); } @@ -152,10 +157,13 @@ const generateViewConfig = ( splitted.groups.forEach((groupEntity) => { cards = cards.concat( computeCards( - computeStateName(groupEntity), groupEntity.attributes.entity_id.map( (entityId): [string, HassEntity] => [entityId, entities[entityId]] - ) + ), + { + title: computeStateName(groupEntity), + show_header_toggle: groupEntity.attributes.control !== "hidden", + } ) ); }); @@ -165,10 +173,12 @@ const generateViewConfig = ( .forEach((domain) => { cards = cards.concat( computeCards( - localize(`domain.${domain}`), ungroupedEntitites[domain].map( (entityId): [string, HassEntity] => [entityId, entities[entityId]] - ) + ), + { + title: localize(`domain.${domain}`), + } ) ); }); @@ -237,6 +247,16 @@ export const generateLovelaceConfig = ( ) ); + // Add map of geo locations to default view if loaded + if (hass.config.components.includes("geo_location")) { + if (views[0] && views[0].cards) { + views[0].cards.push({ + type: "map", + geo_location_sources: ["all"], + }); + } + } + // Make sure we don't have Home as title and first tab. if (views.length > 1 && title === "Home") { title = "Home Assistant"; diff --git a/src/panels/lovelace/common/has-changed.ts b/src/panels/lovelace/common/has-changed.ts index d246bebc49..19aed21579 100644 --- a/src/panels/lovelace/common/has-changed.ts +++ b/src/panels/lovelace/common/has-changed.ts @@ -1,5 +1,5 @@ import { HomeAssistant } from "../../../types"; -import { PropertyValues } from "@polymer/lit-element"; +import { PropertyValues } from "lit-element"; // Check if config or Entity changed export function hasConfigOrEntityChanged( diff --git a/src/panels/lovelace/components/hui-action-editor.ts b/src/panels/lovelace/components/hui-action-editor.ts index 7058a2ab73..3ca20e2566 100644 --- a/src/panels/lovelace/components/hui-action-editor.ts +++ b/src/panels/lovelace/components/hui-action-editor.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "@polymer/paper-input/paper-textarea"; import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; import "@polymer/paper-item/paper-item"; @@ -51,7 +55,7 @@ export class HuiActionEditor extends LitElement { return config.service || ""; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this.hass || !this.actions) { return html``; } diff --git a/src/panels/lovelace/components/hui-card-options.ts b/src/panels/lovelace/components/hui-card-options.ts index 4cff932dc7..29e3d41f15 100644 --- a/src/panels/lovelace/components/hui-card-options.ts +++ b/src/panels/lovelace/components/hui-card-options.ts @@ -1,4 +1,4 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; +import { html, LitElement, PropertyDeclarations } from "lit-element"; import "@polymer/paper-button/paper-button"; import "@polymer/paper-menu-button/paper-menu-button"; import "@polymer/paper-icon-button/paper-icon-button"; @@ -46,10 +46,6 @@ export class HuiCardOptions extends hassLocalizeLitMixin(LitElement) { paper-button { color: var(--primary-color); font-weight: 500; - letter-spacing: 0.05em; - font-size: 16px; - padding: 0; - margin: 0; } paper-icon-button { color: var(--primary-text-color); diff --git a/src/panels/lovelace/components/hui-entities-toggle.ts b/src/panels/lovelace/components/hui-entities-toggle.ts index d441f7369f..de4814296d 100644 --- a/src/panels/lovelace/components/hui-entities-toggle.ts +++ b/src/panels/lovelace/components/hui-entities-toggle.ts @@ -3,8 +3,8 @@ import { LitElement, PropertyDeclarations, PropertyValues, -} from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; + TemplateResult, +} from "lit-element"; import { PaperToggleButtonElement } from "@polymer/paper-toggle-button/paper-toggle-button"; import { DOMAINS_TOGGLE } from "../../../common/const"; @@ -35,7 +35,7 @@ class HuiEntitiesToggle extends LitElement { } } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._toggleEntities) { return html``; } diff --git a/src/panels/lovelace/components/hui-entity-editor.ts b/src/panels/lovelace/components/hui-entity-editor.ts index 93c159becd..e94c7c5496 100644 --- a/src/panels/lovelace/components/hui-entity-editor.ts +++ b/src/panels/lovelace/components/hui-entity-editor.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import { HomeAssistant } from "../../../types"; import { fireEvent } from "../../../common/dom/fire_event"; @@ -19,7 +23,7 @@ export class HuiEntityEditor extends LitElement { }; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this.entities) { return html``; } diff --git a/src/panels/lovelace/components/hui-theme-select-editor.ts b/src/panels/lovelace/components/hui-theme-select-editor.ts index 68c452c3d2..497e1a0013 100644 --- a/src/panels/lovelace/components/hui-theme-select-editor.ts +++ b/src/panels/lovelace/components/hui-theme-select-editor.ts @@ -1,6 +1,10 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "@polymer/paper-button/paper-button"; -import { TemplateResult } from "lit-html"; import { HomeAssistant } from "../../../types"; import { fireEvent, HASSDomEvent } from "../../../common/dom/fire_event"; @@ -28,7 +32,7 @@ export class HuiThemeSelectionEditor extends hassLocalizeLitMixin(LitElement) { }; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { const themes = ["Backend-selected", "default"].concat( Object.keys(this.hass!.themes.themes).sort() ); diff --git a/src/panels/lovelace/components/hui-timestamp-display.ts b/src/panels/lovelace/components/hui-timestamp-display.ts index 3a346ff0ce..c908f0b204 100644 --- a/src/panels/lovelace/components/hui-timestamp-display.ts +++ b/src/panels/lovelace/components/hui-timestamp-display.ts @@ -3,8 +3,8 @@ import { LitElement, PropertyDeclarations, PropertyValues, -} from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; + TemplateResult, +} from "lit-element"; import { HomeAssistant } from "../../../types"; import format_date from "../../../common/datetime/format_date"; @@ -49,7 +49,7 @@ class HuiTimestampDisplay extends hassLocalizeLitMixin(LitElement) { this._clearInterval(); } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this.ts || !this.hass) { return html``; } diff --git a/src/panels/lovelace/editor/card-editor/hui-card-picker.ts b/src/panels/lovelace/editor/card-editor/hui-card-picker.ts index c9f06aaac6..3ee078070f 100644 --- a/src/panels/lovelace/editor/card-editor/hui-card-picker.ts +++ b/src/panels/lovelace/editor/card-editor/hui-card-picker.ts @@ -1,5 +1,4 @@ -import { html, LitElement } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { html, LitElement, TemplateResult } from "lit-element"; import "@polymer/paper-button/paper-button"; import { HomeAssistant } from "../../../../types"; @@ -39,7 +38,7 @@ export class HuiCardPicker extends hassLocalizeLitMixin(LitElement) { public hass?: HomeAssistant; public cardPicked?: (cardConf: LovelaceCardConfig) => void; - protected render(): TemplateResult { + protected render(): TemplateResult | void { return html` ${this.renderStyle()}

${this.localize("ui.panel.lovelace.editor.edit_card.pick_card")}

diff --git a/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts b/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts index f47930a851..0170f16984 100644 --- a/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts +++ b/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import { HomeAssistant } from "../../../../types"; import { HASSDomEvent } from "../../../../common/dom/fire_event"; @@ -48,7 +52,7 @@ export class HuiDialogEditCard extends LitElement { : undefined; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._params) { return html``; } diff --git a/src/panels/lovelace/editor/card-editor/hui-dialog-move-card-view.ts b/src/panels/lovelace/editor/card-editor/hui-dialog-move-card-view.ts index 7f88c436cf..d794f7c92f 100644 --- a/src/panels/lovelace/editor/card-editor/hui-dialog-move-card-view.ts +++ b/src/panels/lovelace/editor/card-editor/hui-dialog-move-card-view.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "@polymer/paper-dialog/paper-dialog"; import "@polymer/paper-item/paper-item"; // tslint:disable-next-line:no-duplicate-imports @@ -23,7 +27,7 @@ export class HuiDialogMoveCardView extends hassLocalizeLitMixin(LitElement) { await this.updateComplete; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._params) { return html``; } diff --git a/src/panels/lovelace/editor/card-editor/hui-dialog-pick-card.ts b/src/panels/lovelace/editor/card-editor/hui-dialog-pick-card.ts index 5c55787dfa..292b4c9026 100644 --- a/src/panels/lovelace/editor/card-editor/hui-dialog-pick-card.ts +++ b/src/panels/lovelace/editor/card-editor/hui-dialog-pick-card.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "@polymer/paper-dialog/paper-dialog"; import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable"; @@ -17,7 +21,7 @@ export class HuiDialogPickCard extends hassLocalizeLitMixin(LitElement) { return {}; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { return html` diff --git a/src/panels/lovelace/editor/config-elements/hui-alarm-panel-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-alarm-panel-card-editor.ts index f364c3cb7b..dd196cee7e 100644 --- a/src/panels/lovelace/editor/config-elements/hui-alarm-panel-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-alarm-panel-card-editor.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; @@ -49,7 +53,7 @@ export class HuiAlarmPanelCardEditor extends hassLocalizeLitMixin(LitElement) return this._config!.states || []; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this.hass) { return html``; } diff --git a/src/panels/lovelace/editor/config-elements/hui-entities-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-entities-card-editor.ts index c13b303a1a..d86dc67623 100644 --- a/src/panels/lovelace/editor/config-elements/hui-entities-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-entities-card-editor.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; @@ -12,7 +16,10 @@ import { hassLocalizeLitMixin } from "../../../../mixins/lit-localize-mixin"; import { HomeAssistant } from "../../../../types"; import { LovelaceCardEditor } from "../../types"; import { fireEvent } from "../../../../common/dom/fire_event"; -import { Config, ConfigEntity } from "../../cards/hui-entities-card"; +import { + EntitiesCardConfig, + EntitiesCardEntityConfig, +} from "../../cards/hui-entities-card"; import { configElementStyle } from "./config-elements-style"; import "../../../../components/entity/state-badge"; @@ -53,16 +60,16 @@ export class HuiEntitiesCardEditor extends hassLocalizeLitMixin(LitElement) } public hass?: HomeAssistant; - private _config?: Config; - private _configEntities?: ConfigEntity[]; + private _config?: EntitiesCardConfig; + private _configEntities?: EntitiesCardEntityConfig[]; - public setConfig(config: Config): void { + public setConfig(config: EntitiesCardConfig): void { config = cardConfigStruct(config); this._config = config; this._configEntities = processEditorEntities(config.entities); } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this.hass) { return html``; } diff --git a/src/panels/lovelace/editor/config-elements/hui-entity-button-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-entity-button-card-editor.ts index d5a7669008..9c13aebf7f 100644 --- a/src/panels/lovelace/editor/config-elements/hui-entity-button-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-entity-button-card-editor.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "@polymer/paper-input/paper-input"; import { struct } from "../../common/structs/struct"; @@ -68,7 +72,7 @@ export class HuiEntityButtonCardEditor extends hassLocalizeLitMixin(LitElement) return this._config!.theme || "default"; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this.hass) { return html``; } diff --git a/src/panels/lovelace/editor/config-elements/hui-gauge-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-gauge-card-editor.ts index 1b7d734940..3c0724f84a 100644 --- a/src/panels/lovelace/editor/config-elements/hui-gauge-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-gauge-card-editor.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "@polymer/paper-input/paper-input"; import "@polymer/paper-toggle-button/paper-toggle-button"; @@ -70,7 +74,7 @@ export class HuiGaugeCardEditor extends hassLocalizeLitMixin(LitElement) return this._config!.severity || undefined; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this.hass) { return html``; } diff --git a/src/panels/lovelace/editor/config-elements/hui-glance-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-glance-card-editor.ts index da8b1ff2cd..509d5a145a 100644 --- a/src/panels/lovelace/editor/config-elements/hui-glance-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-glance-card-editor.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; @@ -68,7 +72,7 @@ export class HuiGlanceCardEditor extends hassLocalizeLitMixin(LitElement) return this._config!.columns || NaN; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this.hass) { return html``; } diff --git a/src/panels/lovelace/editor/config-elements/hui-iframe-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-iframe-card-editor.ts index 673156032d..3442e2c5c2 100644 --- a/src/panels/lovelace/editor/config-elements/hui-iframe-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-iframe-card-editor.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "@polymer/paper-input/paper-input"; import { struct } from "../../common/structs/struct"; @@ -44,7 +48,7 @@ export class HuiIframeCardEditor extends hassLocalizeLitMixin(LitElement) return this._config!.aspect_ratio || ""; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this.hass) { return html``; } diff --git a/src/panels/lovelace/editor/config-elements/hui-light-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-light-card-editor.ts index ba65142b1b..2890eba236 100644 --- a/src/panels/lovelace/editor/config-elements/hui-light-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-light-card-editor.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "@polymer/paper-input/paper-input"; import { struct } from "../../common/structs/struct"; @@ -47,7 +51,7 @@ export class HuiLightCardEditor extends hassLocalizeLitMixin(LitElement) return this._config!.entity || ""; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this.hass) { return html``; } diff --git a/src/panels/lovelace/editor/config-elements/hui-map-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-map-card-editor.ts index ed6531a0e0..d775ecdda7 100644 --- a/src/panels/lovelace/editor/config-elements/hui-map-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-map-card-editor.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "@polymer/paper-input/paper-input"; import { struct } from "../../common/structs/struct"; @@ -64,7 +68,7 @@ export class HuiMapCardEditor extends hassLocalizeLitMixin(LitElement) return this._config!.entities || []; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this.hass) { return html``; } diff --git a/src/panels/lovelace/editor/config-elements/hui-markdown-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-markdown-card-editor.ts index c4b002eff1..51be28d856 100644 --- a/src/panels/lovelace/editor/config-elements/hui-markdown-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-markdown-card-editor.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "@polymer/paper-input/paper-input"; import "@polymer/paper-input/paper-textarea"; @@ -40,7 +44,7 @@ export class HuiMarkdownCardEditor extends hassLocalizeLitMixin(LitElement) return this._config!.content || ""; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this.hass) { return html``; } diff --git a/src/panels/lovelace/editor/config-elements/hui-media-control-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-media-control-card-editor.ts index b6ac24fe3f..7d0b136207 100644 --- a/src/panels/lovelace/editor/config-elements/hui-media-control-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-media-control-card-editor.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import { struct } from "../../common/structs/struct"; import { EntitiesEditorEvent, EditorTarget } from "../types"; @@ -34,7 +38,7 @@ export class HuiMediaControlCardEditor extends hassLocalizeLitMixin(LitElement) return this._config!.entity || ""; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this.hass) { return html``; } diff --git a/src/panels/lovelace/editor/config-elements/hui-picture-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-picture-card-editor.ts index 52bba01b3c..6d852fd534 100644 --- a/src/panels/lovelace/editor/config-elements/hui-picture-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-picture-card-editor.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "@polymer/paper-input/paper-input"; import { struct } from "../../common/structs/struct"; @@ -51,7 +55,7 @@ export class HuiPictureCardEditor extends hassLocalizeLitMixin(LitElement) return this._config!.hold_action || { action: "none" }; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this.hass) { return html``; } diff --git a/src/panels/lovelace/editor/config-elements/hui-plant-status-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-plant-status-card-editor.ts index d321f52b76..97cb2a8078 100644 --- a/src/panels/lovelace/editor/config-elements/hui-plant-status-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-plant-status-card-editor.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "@polymer/paper-input/paper-input"; import { struct } from "../../common/structs/struct"; @@ -42,7 +46,7 @@ export class HuiPlantStatusCardEditor extends hassLocalizeLitMixin(LitElement) return this._config!.name || ""; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this.hass) { return html``; } diff --git a/src/panels/lovelace/editor/config-elements/hui-sensor-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-sensor-card-editor.ts index dcf108c3ed..07b7d8d3f3 100644 --- a/src/panels/lovelace/editor/config-elements/hui-sensor-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-sensor-card-editor.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "@polymer/paper-input/paper-input"; import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; import "@polymer/paper-item/paper-item"; @@ -75,7 +79,7 @@ export class HuiSensorCardEditor extends hassLocalizeLitMixin(LitElement) return this._config!.hours_to_show || "24"; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this.hass) { return html``; } diff --git a/src/panels/lovelace/editor/config-elements/hui-shopping-list-editor.ts b/src/panels/lovelace/editor/config-elements/hui-shopping-list-editor.ts index 6bd987db6a..504a82359e 100644 --- a/src/panels/lovelace/editor/config-elements/hui-shopping-list-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-shopping-list-editor.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "@polymer/paper-input/paper-input"; import { struct } from "../../common/structs/struct"; @@ -33,7 +37,7 @@ export class HuiShoppingListEditor extends hassLocalizeLitMixin(LitElement) return this._config!.title || ""; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this.hass) { return html``; } diff --git a/src/panels/lovelace/editor/config-elements/hui-thermostat-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-thermostat-card-editor.ts index e1db48583e..86a3bcf22f 100644 --- a/src/panels/lovelace/editor/config-elements/hui-thermostat-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-thermostat-card-editor.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "@polymer/paper-input/paper-input"; import { struct } from "../../common/structs/struct"; @@ -47,7 +51,7 @@ export class HuiThermostatCardEditor extends hassLocalizeLitMixin(LitElement) return this._config!.theme || "default"; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this.hass) { return html``; } diff --git a/src/panels/lovelace/editor/config-elements/hui-weather-forecast-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-weather-forecast-card-editor.ts index 8854c411a8..4be9757604 100644 --- a/src/panels/lovelace/editor/config-elements/hui-weather-forecast-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-weather-forecast-card-editor.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import { struct } from "../../common/structs/struct"; import { EntitiesEditorEvent, EditorTarget } from "../types"; @@ -41,7 +45,7 @@ export class HuiWeatherForecastCardEditor return this._config!.name || ""; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this.hass) { return html``; } diff --git a/src/panels/lovelace/editor/hui-dialog-save-config.ts b/src/panels/lovelace/editor/hui-dialog-save-config.ts index 295d9ae87c..b13b52cbd0 100644 --- a/src/panels/lovelace/editor/hui-dialog-save-config.ts +++ b/src/panels/lovelace/editor/hui-dialog-save-config.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "@polymer/paper-spinner/paper-spinner"; import "@polymer/paper-dialog/paper-dialog"; @@ -41,7 +45,7 @@ export class HuiSaveConfig extends hassLocalizeLitMixin(LitElement) { return this.shadowRoot!.querySelector("paper-dialog")!; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { return html` ${this.renderStyle()} @@ -108,6 +112,7 @@ export class HuiSaveConfig extends hassLocalizeLitMixin(LitElement) { try { const lovelace = this._params!.lovelace; await lovelace.saveConfig(lovelace.config); + lovelace.setEditMode(true); this._saving = false; this._closeDialog(); } catch (err) { diff --git a/src/panels/lovelace/editor/lovelace-editor/hui-dialog-edit-lovelace.ts b/src/panels/lovelace/editor/lovelace-editor/hui-dialog-edit-lovelace.ts index 2cb86b013b..3f15f505a6 100644 --- a/src/panels/lovelace/editor/lovelace-editor/hui-dialog-edit-lovelace.ts +++ b/src/panels/lovelace/editor/lovelace-editor/hui-dialog-edit-lovelace.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "@polymer/paper-spinner/paper-spinner"; import "@polymer/paper-dialog/paper-dialog"; // This is not a duplicate import, one is for types, one is for element. @@ -47,7 +51,7 @@ export class HuiDialogEditLovelace extends hassLocalizeLitMixin(LitElement) { return this.shadowRoot!.querySelector("paper-dialog")!; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { return html` ${this.renderStyle()} diff --git a/src/panels/lovelace/editor/lovelace-editor/hui-lovelace-editor.ts b/src/panels/lovelace/editor/lovelace-editor/hui-lovelace-editor.ts index 68761be409..b6fa8e5b04 100644 --- a/src/panels/lovelace/editor/lovelace-editor/hui-lovelace-editor.ts +++ b/src/panels/lovelace/editor/lovelace-editor/hui-lovelace-editor.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "@polymer/paper-input/paper-input"; import { EditorTarget } from "../types"; @@ -33,7 +37,7 @@ export class HuiLovelaceEditor extends hassLocalizeLitMixin(LitElement) { return this.config.title || ""; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { return html` ${configElementStyle}
diff --git a/src/panels/lovelace/editor/view-editor/hui-dialog-edit-view.ts b/src/panels/lovelace/editor/view-editor/hui-dialog-edit-view.ts index 087ed20ce2..163127b073 100644 --- a/src/panels/lovelace/editor/view-editor/hui-dialog-edit-view.ts +++ b/src/panels/lovelace/editor/view-editor/hui-dialog-edit-view.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import { HomeAssistant } from "../../../../types"; import { HASSDomEvent } from "../../../../common/dom/fire_event"; @@ -34,7 +38,7 @@ export class HuiDialogEditView extends LitElement { (this.shadowRoot!.children[0] as any).showDialog(); } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._params) { return html``; } diff --git a/src/panels/lovelace/editor/view-editor/hui-edit-view.ts b/src/panels/lovelace/editor/view-editor/hui-edit-view.ts index 8b27068812..537a1ed379 100644 --- a/src/panels/lovelace/editor/view-editor/hui-edit-view.ts +++ b/src/panels/lovelace/editor/view-editor/hui-edit-view.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "@polymer/paper-spinner/paper-spinner"; import "@polymer/paper-tabs/paper-tab"; @@ -83,7 +87,7 @@ export class HuiEditView extends hassLocalizeLitMixin(LitElement) { return this.shadowRoot!.querySelector("paper-dialog")!; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { let content; switch (this._curTab) { case "tab-settings": diff --git a/src/panels/lovelace/editor/view-editor/hui-view-editor.ts b/src/panels/lovelace/editor/view-editor/hui-view-editor.ts index e85cbff0d1..80a6664353 100644 --- a/src/panels/lovelace/editor/view-editor/hui-view-editor.ts +++ b/src/panels/lovelace/editor/view-editor/hui-view-editor.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "@polymer/paper-input/paper-input"; import { EditorTarget } from "../types"; @@ -59,7 +63,7 @@ export class HuiViewEditor extends hassLocalizeLitMixin(LitElement) { this._config = config; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this.hass) { return html``; } diff --git a/src/panels/lovelace/elements/hui-icon-element.ts b/src/panels/lovelace/elements/hui-icon-element.ts index ee398c3c84..3f626446d7 100644 --- a/src/panels/lovelace/elements/hui-icon-element.ts +++ b/src/panels/lovelace/elements/hui-icon-element.ts @@ -1,4 +1,4 @@ -import { html, LitElement } from "@polymer/lit-element"; +import { html, LitElement, TemplateResult } from "lit-element"; import "../../../components/ha-icon"; @@ -8,7 +8,6 @@ import { longPress } from "../common/directives/long-press-directive"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; import { LovelaceElement, LovelaceElementConfig } from "./types"; import { HomeAssistant } from "../../../types"; -import { TemplateResult } from "lit-html"; interface Config extends LovelaceElementConfig { icon: string; @@ -31,7 +30,7 @@ export class HuiIconElement extends hassLocalizeLitMixin(LitElement) this._config = config; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._config) { return html``; } diff --git a/src/panels/lovelace/elements/hui-image-element.ts b/src/panels/lovelace/elements/hui-image-element.ts index af47ba04ef..3271b91a8a 100644 --- a/src/panels/lovelace/elements/hui-image-element.ts +++ b/src/panels/lovelace/elements/hui-image-element.ts @@ -1,4 +1,4 @@ -import { html, LitElement } from "@polymer/lit-element"; +import { html, LitElement, TemplateResult } from "lit-element"; import "../components/hui-image"; @@ -8,7 +8,6 @@ import { longPress } from "../common/directives/long-press-directive"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; import { LovelaceElement, LovelaceElementConfig } from "./types"; import { HomeAssistant } from "../../../types"; -import { TemplateResult } from "lit-html"; interface Config extends LovelaceElementConfig { image?: string; @@ -40,7 +39,7 @@ export class HuiImageElement extends hassLocalizeLitMixin(LitElement) this._config = config; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._config) { return html``; } diff --git a/src/panels/lovelace/elements/hui-service-button-element.ts b/src/panels/lovelace/elements/hui-service-button-element.ts index eb4013f3cf..13fb73d3d0 100644 --- a/src/panels/lovelace/elements/hui-service-button-element.ts +++ b/src/panels/lovelace/elements/hui-service-button-element.ts @@ -1,5 +1,4 @@ -import { html, LitElement } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { html, LitElement, TemplateResult } from "lit-element"; import "../../../components/buttons/ha-call-service-button"; @@ -37,7 +36,7 @@ export class HuiServiceButtonElement extends LitElement this._config = config; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._config) { return html``; } diff --git a/src/panels/lovelace/elements/hui-state-badge-element.ts b/src/panels/lovelace/elements/hui-state-badge-element.ts index 818f7986bb..c7cc4294da 100644 --- a/src/panels/lovelace/elements/hui-state-badge-element.ts +++ b/src/panels/lovelace/elements/hui-state-badge-element.ts @@ -1,11 +1,10 @@ -import { html, LitElement } from "@polymer/lit-element"; +import { html, LitElement, TemplateResult } from "lit-element"; import "../../../components/entity/ha-state-label-badge"; import computeStateName from "../../../common/entity/compute_state_name"; import { LovelaceElement, LovelaceElementConfig } from "./types"; import { HomeAssistant } from "../../../types"; -import { TemplateResult } from "lit-html"; export class HuiStateBadgeElement extends LitElement implements LovelaceElement { @@ -24,7 +23,7 @@ export class HuiStateBadgeElement extends LitElement this._config = config; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if ( !this._config || !this.hass || diff --git a/src/panels/lovelace/elements/hui-state-icon-element.ts b/src/panels/lovelace/elements/hui-state-icon-element.ts index c767252568..a065c15b10 100644 --- a/src/panels/lovelace/elements/hui-state-icon-element.ts +++ b/src/panels/lovelace/elements/hui-state-icon-element.ts @@ -1,5 +1,4 @@ -import { html, LitElement } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { html, LitElement, TemplateResult } from "lit-element"; import "../../../components/entity/state-badge"; @@ -27,7 +26,7 @@ export class HuiStateIconElement extends hassLocalizeLitMixin(LitElement) this._config = config; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if ( !this._config || !this.hass || diff --git a/src/panels/lovelace/elements/hui-state-label-element.ts b/src/panels/lovelace/elements/hui-state-label-element.ts index 6a6f8233f4..552505754b 100644 --- a/src/panels/lovelace/elements/hui-state-label-element.ts +++ b/src/panels/lovelace/elements/hui-state-label-element.ts @@ -1,4 +1,4 @@ -import { html, LitElement } from "@polymer/lit-element"; +import { html, LitElement, TemplateResult } from "lit-element"; import "../../../components/entity/ha-state-label-badge"; @@ -9,7 +9,6 @@ import { longPress } from "../common/directives/long-press-directive"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; import { LovelaceElement, LovelaceElementConfig } from "./types"; import { HomeAssistant } from "../../../types"; -import { TemplateResult } from "lit-html"; interface Config extends LovelaceElementConfig { prefix?: string; @@ -33,7 +32,7 @@ class HuiStateLabelElement extends hassLocalizeLitMixin(LitElement) this._config = config; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._config) { return html``; } 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 3186c9c62b..d452445d78 100644 --- a/src/panels/lovelace/entity-rows/hui-climate-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-climate-entity-row.ts @@ -1,5 +1,4 @@ -import { html, LitElement } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { html, LitElement, TemplateResult } from "lit-element"; import "../../../components/ha-climate-state"; import "../components/hui-generic-entity-row"; @@ -26,7 +25,7 @@ class HuiClimateEntityRow extends LitElement implements EntityRow { this._config = config; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this.hass || !this._config) { return html``; } 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 9410960e5a..8572943852 100644 --- a/src/panels/lovelace/entity-rows/hui-cover-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-cover-entity-row.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "../components/hui-generic-entity-row"; import "../../../components/ha-cover-controls"; @@ -28,7 +32,7 @@ class HuiCoverEntityRow extends LitElement implements EntityRow { this._config = config; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._config || !this.hass) { return html``; } diff --git a/src/panels/lovelace/entity-rows/hui-error-entity-row.ts b/src/panels/lovelace/entity-rows/hui-error-entity-row.ts index 252ed1dfd6..fc0265eddb 100644 --- a/src/panels/lovelace/entity-rows/hui-error-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-error-entity-row.ts @@ -1,5 +1,4 @@ -import { html, LitElement } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { html, LitElement, TemplateResult } from "lit-element"; class HuiErrorEntityRow extends LitElement { public entity?: string; @@ -12,7 +11,7 @@ class HuiErrorEntityRow extends LitElement { }; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { return html` ${this.renderStyle()} ${this.error || "Entity not available"}: ${this.entity || ""} 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 250970653f..f5a56e1c5e 100644 --- a/src/panels/lovelace/entity-rows/hui-group-entity-row.ts +++ b/src/panels/lovelace/entity-rows/hui-group-entity-row.ts @@ -1,5 +1,9 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "../components/hui-generic-entity-row"; import "../../../components/entity/ha-entity-toggle"; @@ -30,7 +34,7 @@ class HuiGroupEntityRow extends hassLocalizeLitMixin(LitElement) this._config = config; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._config || !this.hass) { return html``; } diff --git a/src/panels/lovelace/entity-rows/hui-input-number-entity-row.js b/src/panels/lovelace/entity-rows/hui-input-number-entity-row.js index 4760277902..611d496592 100644 --- a/src/panels/lovelace/entity-rows/hui-input-number-entity-row.js +++ b/src/panels/lovelace/entity-rows/hui-input-number-entity-row.js @@ -6,6 +6,7 @@ import { mixinBehaviors } from "@polymer/polymer/lib/legacy/class"; import "../components/hui-generic-entity-row"; import "../../../components/ha-slider"; +import { computeRTL } from "../../../common/util/compute_rtl"; class HuiInputNumberEntityRow extends mixinBehaviors( [IronResizableBehavior], @@ -51,6 +52,7 @@ class HuiInputNumberEntityRow extends mixinBehaviors( >
void; - private _haStyle?: DocumentFragment; private _saving?: boolean; private _changed?: boolean; private _hashAdded?: boolean; @@ -43,9 +42,8 @@ class LovelaceFullConfigEditor extends hassLocalizeLitMixin(LitElement) { }; } - public render(): TemplateResult { + public render(): TemplateResult | void { return html` - ${this.renderStyle()} @@ -116,18 +114,10 @@ class LovelaceFullConfigEditor extends hassLocalizeLitMixin(LitElement) { }); } - protected renderStyle() { - if (!this._haStyle) { - this._haStyle = document.importNode( - (document.getElementById("ha-style")! - .children[0] as HTMLTemplateElement).content, - true - ); - } - - return html` - ${this._haStyle} - - `; + `, + ]; } private _closeEditor() { diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts index b261529b38..b4af107248 100644 --- a/src/panels/lovelace/hui-root.ts +++ b/src/panels/lovelace/hui-root.ts @@ -3,9 +3,11 @@ import { LitElement, PropertyDeclarations, PropertyValues, -} from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; -import { classMap } from "lit-html/directives/classMap"; + TemplateResult, + CSSResult, + css, +} from "lit-element"; +import { classMap } from "lit-html/directives/class-map"; import "@polymer/app-layout/app-header-layout/app-header-layout"; import "@polymer/app-layout/app-header/app-header"; import "@polymer/app-layout/app-scroll-effects/effects/waterfall"; @@ -45,18 +47,12 @@ import { showEditViewDialog } from "./editor/view-editor/show-edit-view-dialog"; import { showEditLovelaceDialog } from "./editor/lovelace-editor/show-edit-lovelace-dialog"; import { Lovelace } from "./types"; import { afterNextRender } from "../../common/util/render-status"; +import { haStyle } from "../../resources/ha-style"; // CSS and JS should only be imported once. Modules and HTML are safe. const CSS_CACHE = {}; const JS_CACHE = {}; -declare global { - // tslint:disable-next-line - interface HASSDomEvents { - "rebuild-view": {}; - } -} - let loadedUnusedEntities = false; class HUIRoot extends hassLocalizeLitMixin(LitElement) { @@ -70,7 +66,6 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { private _curView?: number | "hass-unused-entities"; private _notificationsOpen: boolean; private _persistentNotifications?: Notification[]; - private _haStyle?: DocumentFragment; private _viewCache?: { [viewId: string]: HUIView }; private _debouncedConfigChanged: () => void; @@ -119,9 +114,8 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { } } - protected render(): TemplateResult { + protected render(): TemplateResult | void { return html` - ${this.renderStyle()} @@ -298,23 +292,15 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) {
+ })}" @ll-rebuild='${this._debouncedConfigChanged}'>
`; } - protected renderStyle(): TemplateResult { - if (!this._haStyle) { - this._haStyle = document.importNode( - (document.getElementById("ha-style")! - .children[0] as HTMLTemplateElement).content, - true - ); - } - - return html` - ${this._haStyle} - - `; + `, + ]; } protected updated(changedProperties: PropertyValues): void { diff --git a/src/panels/lovelace/hui-unused-entities.ts b/src/panels/lovelace/hui-unused-entities.ts index ec3970b9ae..07a681d79f 100644 --- a/src/panels/lovelace/hui-unused-entities.ts +++ b/src/panels/lovelace/hui-unused-entities.ts @@ -1,11 +1,15 @@ -import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; +import { + html, + LitElement, + PropertyDeclarations, + TemplateResult, +} from "lit-element"; import "./cards/hui-entities-card"; import { computeUnusedEntities } from "./common/compute-unused-entities"; import { createCardElement } from "./common/create-card-element"; import { HomeAssistant } from "../../types"; -import { TemplateResult } from "lit-html"; import { LovelaceCard } from "./types"; import { LovelaceConfig } from "../../data/lovelace"; @@ -35,7 +39,7 @@ export class HuiUnusedEntities extends LitElement { this._createElement(); } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._config || !this._hass) { return html``; } diff --git a/src/panels/lovelace/hui-view.ts b/src/panels/lovelace/hui-view.ts index 471e917c1e..11be407f7a 100644 --- a/src/panels/lovelace/hui-view.ts +++ b/src/panels/lovelace/hui-view.ts @@ -3,8 +3,8 @@ import { LitElement, PropertyValues, PropertyDeclarations, -} from "@polymer/lit-element"; -import { TemplateResult } from "lit-html"; + TemplateResult, +} from "lit-element"; import "../../components/entity/ha-state-label-badge"; // This one is for types @@ -14,13 +14,14 @@ import { HaStateLabelBadge } from "../../components/entity/ha-state-label-badge" import applyThemesOnElement from "../../common/dom/apply_themes_on_element"; import { hassLocalizeLitMixin } from "../../mixins/lit-localize-mixin"; -import { LovelaceViewConfig } from "../../data/lovelace"; +import { LovelaceViewConfig, LovelaceCardConfig } from "../../data/lovelace"; import { HomeAssistant } from "../../types"; import { Lovelace, LovelaceCard } from "./types"; import { createCardElement } from "./common/create-card-element"; import { computeCardSize } from "./common/compute-card-size"; import { showEditCardDialog } from "./editor/card-editor/show-edit-card-dialog"; +import { HuiErrorCard } from "./cards/hui-error-card"; let editCodeLoaded = false; @@ -47,7 +48,7 @@ export class HUIView extends hassLocalizeLitMixin(LitElement) { public lovelace?: Lovelace; public columns?: number; public index?: number; - private _cards: LovelaceCard[]; + private _cards: Array; private _badges: Array<{ element: HaStateLabelBadge; entityId: string }>; static get properties(): PropertyDeclarations { @@ -67,7 +68,7 @@ export class HUIView extends hassLocalizeLitMixin(LitElement) { this._badges = []; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { return html` ${this.renderStyles()}
@@ -239,8 +240,7 @@ export class HUIView extends hassLocalizeLitMixin(LitElement) { const elements: LovelaceCard[] = []; const elementsToAppend: HTMLElement[] = []; config.cards.forEach((cardConfig, cardIndex) => { - const element = createCardElement(cardConfig) as LovelaceCard; - element.hass = this.hass; + const element = this._createCardElement(cardConfig); elements.push(element); if (!this.lovelace!.editMode) { @@ -287,6 +287,34 @@ export class HUIView extends hassLocalizeLitMixin(LitElement) { applyThemesOnElement(root, this.hass!.themes, config.theme); } } + + private _createCardElement(cardConfig: LovelaceCardConfig) { + const element = createCardElement(cardConfig) as LovelaceCard; + element.hass = this.hass; + element.addEventListener( + "ll-rebuild", + (ev) => { + // In edit mode let it go to hui-root and rebuild whole view. + if (!this.lovelace!.editMode) { + ev.stopPropagation(); + this._rebuildCard(element, cardConfig); + } + }, + { once: true } + ); + return element; + } + + private _rebuildCard( + cardElToReplace: LovelaceCard, + config: LovelaceCardConfig + ): void { + const newCardEl = this._createCardElement(config); + cardElToReplace.parentElement!.replaceChild(newCardEl, cardElToReplace); + this._cards = this._cards!.map((curCardEl) => + curCardEl === cardElToReplace ? newCardEl : curCardEl + ); + } } declare global { diff --git a/src/panels/lovelace/special-rows/hui-call-service-row.ts b/src/panels/lovelace/special-rows/hui-call-service-row.ts index 33a882c4d3..608016e217 100644 --- a/src/panels/lovelace/special-rows/hui-call-service-row.ts +++ b/src/panels/lovelace/special-rows/hui-call-service-row.ts @@ -1,4 +1,4 @@ -import { html, LitElement } from "@polymer/lit-element"; +import { html, LitElement, TemplateResult } from "lit-element"; import "@polymer/paper-button/paper-button"; import "../../../components/ha-icon"; @@ -6,7 +6,6 @@ import "../../../components/ha-icon"; import { callService } from "../common/call-service"; import { EntityRow, CallServiceConfig } from "../entity-rows/types"; import { HomeAssistant } from "../../../types"; -import { TemplateResult } from "lit-html"; class HuiCallServiceRow extends LitElement implements EntityRow { public hass?: HomeAssistant; @@ -27,7 +26,7 @@ class HuiCallServiceRow extends LitElement implements EntityRow { this._config = { icon: "hass:remote", action_name: "Run", ...config }; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._config) { return html``; } diff --git a/src/panels/lovelace/special-rows/hui-divider-row.ts b/src/panels/lovelace/special-rows/hui-divider-row.ts index f1feced482..38cead769e 100644 --- a/src/panels/lovelace/special-rows/hui-divider-row.ts +++ b/src/panels/lovelace/special-rows/hui-divider-row.ts @@ -1,7 +1,6 @@ -import { html, LitElement } from "@polymer/lit-element"; +import { html, LitElement, TemplateResult } from "lit-element"; import { EntityRow, DividerConfig } from "../entity-rows/types"; import { HomeAssistant } from "../../../types"; -import { TemplateResult } from "lit-html"; class HuiDividerRow extends LitElement implements EntityRow { public hass?: HomeAssistant; @@ -27,7 +26,7 @@ class HuiDividerRow extends LitElement implements EntityRow { }; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._config) { return html``; } diff --git a/src/panels/lovelace/special-rows/hui-section-row.ts b/src/panels/lovelace/special-rows/hui-section-row.ts index cce632f42b..9d2db0c6c4 100644 --- a/src/panels/lovelace/special-rows/hui-section-row.ts +++ b/src/panels/lovelace/special-rows/hui-section-row.ts @@ -1,9 +1,8 @@ -import { html, LitElement } from "@polymer/lit-element"; +import { html, LitElement, TemplateResult } from "lit-element"; import { EntityRow, SectionConfig } from "../entity-rows/types"; import { HomeAssistant } from "../../../types"; import "../../../components/ha-icon"; -import { TemplateResult } from "lit-html"; class HuiSectionRow extends LitElement implements EntityRow { public hass?: HomeAssistant; @@ -23,7 +22,7 @@ class HuiSectionRow extends LitElement implements EntityRow { this._config = config; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._config) { return html``; } diff --git a/src/panels/lovelace/special-rows/hui-weblink-row.ts b/src/panels/lovelace/special-rows/hui-weblink-row.ts index c54beba2fb..d06e8470c9 100644 --- a/src/panels/lovelace/special-rows/hui-weblink-row.ts +++ b/src/panels/lovelace/special-rows/hui-weblink-row.ts @@ -1,11 +1,9 @@ -import { html, LitElement } from "@polymer/lit-element"; +import { html, LitElement, TemplateResult } from "lit-element"; import { EntityRow, WeblinkConfig } from "../entity-rows/types"; import { HomeAssistant } from "../../../types"; import "../../../components/ha-icon"; -import { TemplateResult } from "lit-html"; - class HuiWeblinkRow extends LitElement implements EntityRow { public hass?: HomeAssistant; private _config?: WeblinkConfig; @@ -28,7 +26,7 @@ class HuiWeblinkRow extends LitElement implements EntityRow { }; } - protected render(): TemplateResult { + protected render(): TemplateResult | void { if (!this._config) { return html``; } diff --git a/src/panels/lovelace/types.ts b/src/panels/lovelace/types.ts index db3f7af72b..bf394921b2 100644 --- a/src/panels/lovelace/types.ts +++ b/src/panels/lovelace/types.ts @@ -1,6 +1,13 @@ import { HomeAssistant } from "../../types"; import { LovelaceCardConfig, LovelaceConfig } from "../../data/lovelace"; +declare global { + // tslint:disable-next-line + interface HASSDomEvents { + "ll-rebuild": {}; + } +} + export interface Lovelace { config: LovelaceConfig; editMode: boolean; diff --git a/src/resources/ha-style.js b/src/resources/ha-style.ts similarity index 71% rename from src/resources/ha-style.js rename to src/resources/ha-style.ts index b645210773..cb4f736abb 100644 --- a/src/resources/ha-style.js +++ b/src/resources/ha-style.ts @@ -1,7 +1,33 @@ import "@polymer/paper-styles/paper-styles"; import "@polymer/polymer/polymer-legacy"; +import { css } from "lit-element"; + +export const haStyle = css` + :host { + @apply --paper-font-body1; + } + + app-header-layout, + ha-app-layout { + background-color: var(--primary-background-color); + } + + app-header, + app-toolbar { + background-color: var(--primary-color); + font-weight: 400; + color: var(--text-primary-color, white); + } + + app-toolbar ha-menu-button + [main-title], + app-toolbar paper-icon-button + [main-title] { + margin-left: 24px; + } + + h1 { + @apply --paper-font-title; + } -export const buttonLink = ` button.link { background: none; color: inherit; @@ -12,6 +38,74 @@ export const buttonLink = ` text-decoration: underline; cursor: pointer; } + + .card-actions a { + text-decoration: none; + } + + .card-actions paper-button:not([disabled]), + .card-actions ha-progress-button:not([disabled]), + .card-actions ha-call-api-button:not([disabled]), + .card-actions ha-call-service-button:not([disabled]) { + color: var(--primary-color); + font-weight: 500; + } + + .card-actions paper-button.warning:not([disabled]), + .card-actions ha-call-api-button.warning:not([disabled]), + .card-actions ha-call-service-button.warning:not([disabled]) { + color: var(--google-red-500); + } + + .card-actions paper-button[primary] { + background-color: var(--primary-color); + color: var(--text-primary-color); + } +`; + +export const haStyleDialog = css` + :host { + --ha-dialog-narrow: { + margin: 0; + width: 100% !important; + max-height: calc(100% - 64px); + + position: fixed !important; + bottom: 0px; + left: 0px; + right: 0px; + overflow: scroll; + border-bottom-left-radius: 0px; + border-bottom-right-radius: 0px; + } + + --ha-dialog-fullscreen: { + width: 100% !important; + border-radius: 0px; + position: fixed !important; + margin: 0; + } + } + + /* prevent clipping of positioned elements */ + paper-dialog-scrollable { + --paper-dialog-scrollable: { + -webkit-overflow-scrolling: auto; + } + } + + /* force smooth scrolling for iOS 10 */ + paper-dialog-scrollable.can-scroll { + --paper-dialog-scrollable: { + -webkit-overflow-scrolling: touch; + } + } + + @media all and (max-width: 450px), all and (max-height: 500px) { + paper-dialog { + @apply (--ha-dialog-narrow); + } + } `; const documentContainer = document.createElement("template"); @@ -152,101 +246,13 @@ documentContainer.innerHTML = ` `; diff --git a/src/resources/jquery.roundslider.js b/src/resources/jquery.roundslider.js index 2876976369..920cff0fb9 100644 --- a/src/resources/jquery.roundslider.js +++ b/src/resources/jquery.roundslider.js @@ -1,4 +1,4 @@ -import { html } from "@polymer/lit-element"; +import { html } from "lit-element"; // jQuery import should come before plugin import import { jQuery as jQuery_ } from "./jquery"; import "round-slider"; diff --git a/src/resources/jquery.roundslider.ondemand.ts b/src/resources/jquery.roundslider.ondemand.ts index 9543de3e28..3c92056f97 100644 --- a/src/resources/jquery.roundslider.ondemand.ts +++ b/src/resources/jquery.roundslider.ondemand.ts @@ -1,4 +1,4 @@ -import { TemplateResult } from "lit-html"; +import { TemplateResult } from "lit-element"; type LoadedRoundSlider = Promise<{ roundSliderStyle: TemplateResult; diff --git a/src/translations/en.json b/src/translations/en.json index cb2e5b6a0e..5f6bdd7cb8 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -628,6 +628,12 @@ "label": "Time", "at": "At" }, + "time_pattern": { + "label": "Time Pattern", + "hours": "Hours", + "minutes": "Minutes", + "seconds": "Seconds" + }, "webhook": { "label": "Webhook", "webhook_id": "Webhook ID" diff --git a/src/translations/translationMetadata.json b/src/translations/translationMetadata.json index 3a31673c25..3ea02c95d4 100644 --- a/src/translations/translationMetadata.json +++ b/src/translations/translationMetadata.json @@ -87,12 +87,12 @@ "nl": { "nativeName": "Nederlands" }, + "nb": { + "nativeName": "Norsk Bokmål" + }, "nn": { "nativeName": "Norsk Nynorsk" }, - "no": { - "nativeName": "Norsk" - }, "pl": { "nativeName": "Polski" }, diff --git a/translations/ar.json b/translations/ar.json index 7302eea573..9772b94ceb 100644 --- a/translations/ar.json +++ b/translations/ar.json @@ -20,7 +20,7 @@ "default": { "off": "إيقاف", "on": "تشغيل", - "unknown": "غير معروف ", + "unknown": "غير معروف", "unavailable": "غير متوفر" }, "alarm_control_panel": { @@ -195,7 +195,7 @@ "media_player": { "off": "إيقاف", "on": "قيد التشغيل", - "playing": "جاري التشغيل ", + "playing": "جاري التشغيل", "paused": "موقّف مؤقتا", "idle": "خامل", "standby": "وضع الإنتظار" @@ -249,16 +249,16 @@ "off": "مطفئ", "on": "مشغل", "paused": "موقّف مؤقتا", - "returning": "العودة " + "returning": "العودة" } }, "state_badge": { "default": { - "unknown": "غير معروف ", + "unknown": "غير معروف", "unavailable": "غير متوفر" }, "alarm_control_panel": { - "armed": "مفعل ", + "armed": "مفعل", "disarmed": "غير مفعّل", "armed_home": "مفعّل", "armed_away": "مفعّل", @@ -653,7 +653,7 @@ "vacuum": { "actions": { "resume_cleaning": "استئناف التنظيف", - "return_to_base": "العودة ", + "return_to_base": "العودة", "start_cleaning": "بدء تنظيف", "turn_on": "تشغيل", "turn_off": "إيقاف" diff --git a/translations/bg.json b/translations/bg.json index d97b7127f2..ce0e950995 100644 --- a/translations/bg.json +++ b/translations/bg.json @@ -516,7 +516,7 @@ }, "zwave": { "caption": "Z-Wave", - "description": "Управлявайте своята Z-Wave мрежа " + "description": "Управлявайте своята Z-Wave мрежа" }, "users": { "caption": "Потребители", @@ -526,7 +526,7 @@ }, "editor": { "rename_user": "Преименуване на потребител", - "change_password": "Смяна на парола ", + "change_password": "Смяна на парола", "activate_user": "Активиране на потребител", "deactivate_user": "Деактивиране на потребителя", "delete_user": "Изтриване на потребител" @@ -608,7 +608,7 @@ "is_owner": "Вие сте собственик.", "logout": "Изход", "change_password": { - "header": "Смяна на парола ", + "header": "Смяна на парола", "current_password": "Настояща парола", "new_password": "Нова парола", "confirm_new_password": "Потвърждение на новата парола", diff --git a/translations/ca.json b/translations/ca.json index 5b0e98263c..a2af6aee0d 100644 --- a/translations/ca.json +++ b/translations/ca.json @@ -556,6 +556,10 @@ "device_unavailable": "dispositiu no disponible", "entity_unavailable": "entitat no disponible" } + }, + "zha": { + "caption": "ZHA", + "description": "Gestiona la xarxa domòtica ZIgbee" } }, "profile": { @@ -926,6 +930,19 @@ "save": "Desar", "name": "Nom", "entity_id": "ID de l'entitat" + }, + "more_info_control": { + "script": { + "last_action": "Última acció" + }, + "sun": { + "elevation": "Elevació", + "rising": "Sortint", + "setting": "Configuració" + }, + "updater": { + "title": "Instruccions d'actualització" + } } }, "auth_store": { @@ -975,7 +992,8 @@ "updater": "Actualitzador", "weblink": "Enllaços web", "zwave": "Z-Wave", - "vacuum": "Aspiradora" + "vacuum": "Aspiradora", + "zha": "ZHA" }, "attribute": { "weather": { diff --git a/translations/cs.json b/translations/cs.json index a298eb373b..357eff1109 100644 --- a/translations/cs.json +++ b/translations/cs.json @@ -975,7 +975,8 @@ "updater": "Aktualizátor", "weblink": "Webový odkaz", "zwave": "Z-Wave", - "vacuum": "Vysavač" + "vacuum": "Vysavač", + "zha": "ZHA" }, "attribute": { "weather": { diff --git a/translations/cy.json b/translations/cy.json index 2a371de171..398babf900 100644 --- a/translations/cy.json +++ b/translations/cy.json @@ -298,7 +298,7 @@ "delete_button": "Dileu" }, "config": { - "header": "Ffurfweddu Home Assistant ", + "header": "Ffurfweddu Home Assistant", "introduction": "Yma mae'n bosib ffurfweddu'ch cydrannau ac Home Assistant. Nid yw popeth yn bosib i'w ffurfweddu o'r UI eto, ond rydym yn gweithio arno.", "core": { "caption": "Cyffredinol", @@ -372,7 +372,7 @@ "to": "I" }, "homeassistant": { - "label": "Home Assistant ", + "label": "Home Assistant", "event": "Digwyddiad:", "start": "Dechrau", "shutdown": "Darfod" diff --git a/translations/da.json b/translations/da.json index 607c4045b6..81a71557eb 100644 --- a/translations/da.json +++ b/translations/da.json @@ -320,7 +320,7 @@ "header": "Konfiguration og server kontrol", "introduction": "Ændring af din konfiguration kan det være en trættende proces. Vi ved det. Dette afsnit vil forsøge at gøre dit liv en smule nemmere.", "validation": { - "heading": "Konfigurations validering ", + "heading": "Konfigurations validering", "introduction": "Validér din konfiguration, hvis du for nylig lavede nogle ændringer i din konfiguration og vil sikre dig, at alt er validt", "check_config": "Tjek konfiguration", "valid": "Konfiguration gyldig!", @@ -829,7 +829,7 @@ "arm_home": "Tilkoble hjemme", "arm_away": "Tilkoble ude", "arm_night": "Tilkoblet nat", - "armed_custom_bypass": "Brugerdefineret " + "armed_custom_bypass": "Brugerdefineret" }, "automation": { "last_triggered": "Senest udløst", diff --git a/translations/en.json b/translations/en.json index 935b669e1f..1f33a89f89 100644 --- a/translations/en.json +++ b/translations/en.json @@ -556,6 +556,10 @@ "device_unavailable": "device unavailable", "entity_unavailable": "entity unavailable" } + }, + "zha": { + "caption": "ZHA", + "description": "Zigbee Home Automation network management" } }, "profile": { @@ -926,6 +930,19 @@ "save": "Save", "name": "Name", "entity_id": "Entity ID" + }, + "more_info_control": { + "script": { + "last_action": "Last Action" + }, + "sun": { + "elevation": "Elevation", + "rising": "Rising", + "setting": "Setting" + }, + "updater": { + "title": "Update Instructions" + } } }, "auth_store": { @@ -975,7 +992,8 @@ "updater": "Updater", "weblink": "Weblink", "zwave": "Z-Wave", - "vacuum": "Vacuum" + "vacuum": "Vacuum", + "zha": "ZHA" }, "attribute": { "weather": { diff --git a/translations/es-419.json b/translations/es-419.json index 3e6c5f07a9..2ee15f68b6 100644 --- a/translations/es-419.json +++ b/translations/es-419.json @@ -33,7 +33,7 @@ "arming": "Armando", "disarming": "Desarmando", "triggered": "Activado", - "armed_custom_bypass": "Armada zona específica " + "armed_custom_bypass": "Armada zona específica" }, "automation": { "off": "Apagado", diff --git a/translations/es.json b/translations/es.json index a9b491062a..99d359d7c5 100644 --- a/translations/es.json +++ b/translations/es.json @@ -556,6 +556,9 @@ "device_unavailable": "dispositivo no disponible", "entity_unavailable": "entidad no disponible" } + }, + "zha": { + "caption": "ZHA" } }, "profile": { @@ -898,7 +901,7 @@ "service": "Servicio" }, "relative_time": { - "past": "hace {time} ", + "past": "hace {time}", "future": "En {time}", "never": "Nunca", "duration": { @@ -926,6 +929,19 @@ "save": "Guardar", "name": "Nombre", "entity_id": "Identificación de la entidad" + }, + "more_info_control": { + "script": { + "last_action": "Última acción" + }, + "sun": { + "elevation": "Elevación", + "rising": "Subiendo", + "setting": "Ajuste" + }, + "updater": { + "title": "Instrucciones de actualización" + } } }, "auth_store": { @@ -975,7 +991,8 @@ "updater": "Actualizador", "weblink": "Enlace web", "zwave": "Z-Wave", - "vacuum": "Aspiradora" + "vacuum": "Aspiradora", + "zha": "ZHA" }, "attribute": { "weather": { diff --git a/translations/et.json b/translations/et.json index 8fb9950da7..27400e493b 100644 --- a/translations/et.json +++ b/translations/et.json @@ -321,7 +321,7 @@ "introduction": "Seadete muutmine võib olla väsitav tegevus. Me teame. See osa püüab su elu natuke hõlpsamaks teha.", "validation": { "heading": "Seadete kontrollimine", - "introduction": "Kontrolli oma seadeid kui oled neis hiljuti muutusi teinud ja taha veenduda, et kõik on korrektne", + "introduction": "Kontrolli oma seadeid kui oled neis hiljuti muutusi teinud ja tahad veenduda, et kõik on korrektne", "check_config": "Kontrolli seadeid", "valid": "Seaded on korrektsed!", "invalid": "Seaded on vigased" @@ -423,6 +423,10 @@ "event": "Sündmus:", "enter": "Sisenemine", "leave": "Lahkumine" + }, + "webhook": { + "label": "", + "webhook_id": "" } } }, @@ -552,6 +556,9 @@ "device_unavailable": "seade pole saadaval", "entity_unavailable": "üksus pole saadaval" } + }, + "zha": { + "caption": "ZHA" } }, "profile": { @@ -713,6 +720,20 @@ "required_fields": "Täida kõik nõutud väljad" } } + }, + "lovelace": { + "editor": { + "edit_card": { + "save": "Salvesta", + "pick_card": "Vali kaart, mida soovid lisada.", + "add": "Lisada Kaart", + "edit": "Muuda", + "delete": "Kustuta" + }, + "edit_view": { + "delete": "Kustuta vaade" + } + } } }, "sidebar": { @@ -721,7 +742,8 @@ }, "common": { "loading": "Laadimine", - "cancel": "Loobu" + "cancel": "Loobu", + "save": "Salvesta" }, "duration": { "day": "{count} {count, plural,\n one {päev}\n other {päeva}\n}", @@ -880,6 +902,11 @@ "save": "Salvesta", "name": "Nimi", "entity_id": "Üksuse ID" + }, + "more_info_control": { + "script": { + "last_action": "Viimane Tegevus" + } } }, "auth_store": { @@ -929,7 +956,8 @@ "updater": "Uuendaja", "weblink": "Veebilink", "zwave": "Z-Wave", - "vacuum": "Tühjenda" + "vacuum": "Tühjenda", + "zha": "ZHA" }, "attribute": { "weather": { diff --git a/translations/fr.json b/translations/fr.json index 637d24b272..6236c9583c 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -746,7 +746,7 @@ "configure_ui": "Configurer l'interface utilisateur", "edit_view": { "header": "Voir la configuration", - "add": "Ajouter la vue\n", + "add": "Ajouter la vue", "edit": "Modifier la vue", "delete": "Supprimer la vue" }, diff --git a/translations/he.json b/translations/he.json index 233496a4bd..79f3282b9c 100644 --- a/translations/he.json +++ b/translations/he.json @@ -542,7 +542,7 @@ "description": "ניהול התקנים ושירותים מחוברים", "discovered": "זוהו", "configured": "הוגדר", - "new": "הגדר אינטגריצה ", + "new": "הגדר אינטגריצה", "configure": "הגדר", "none": "כלום אינו הוגדר עדיין", "config_entry": { @@ -583,7 +583,7 @@ "description": "כל אסימון רענון מייצג הפעלת התחברות. אסימוני רענון יוסרו באופן אוטומטי כאשר תלחץ על יציאה. אסימוני הרענון הבאים פעילים כעת עבור חשבונך.", "token_title": "אסימון רענון עבור {clientId}", "created_at": "נוצר בתאריך {date}", - "confirm_delete": "האם אתה בטוח שברצונך למחוק את אסימון הרענון עבור {name} ", + "confirm_delete": "האם אתה בטוח שברצונך למחוק את אסימון הרענון עבור {name}", "delete_failed": "מחיקת אסימון הרענון נכשלה.", "last_used": "נעשה שימוש לאחרונה ב {date} מ{location}", "not_used": "לא היה בשימוש", @@ -602,7 +602,7 @@ "prompt_copy_token": "העתק את אסימון הגישה שלך. הוא לא יוצג שוב.", "empty_state": "אין לך עדיין אסימוני גישה ארוכים.", "last_used": "נעשה שימוש לאחרונה {date} מ{location}", - "not_used": "לא היה בשימוש\n" + "not_used": "לא היה בשימוש" }, "current_user": "אתה מחובר כעת כ- {fullName} .", "is_owner": "אתה הבעלים.", @@ -649,7 +649,7 @@ }, "mfa": { "data": { - "code": "קוד אימות דו " + "code": "קוד אימות דו" }, "description": "פתח את ** {mfa_module_name} ** במכשיר שלך כדי להציג את קוד האימות הדו שלבי ולאמת את הזהות שלך:" } @@ -666,7 +666,7 @@ "step": { "init": { "data": { - "password": " סיסמת הAPI." + "password": "סיסמת הAPI." }, "description": "הזן את סיסמת הAPI שלך תחת http בקונפיגורציה:" }, @@ -737,9 +737,9 @@ "delete": "מחק" }, "migrate": { - "header": "ההגדרה לא מתאימה ", + "header": "ההגדרה לא מתאימה", "para_no_id": "האלמנט הנוכחי לא מכיל מזהה יחודיי. בבקשה הוסף מזהה יחודי לאלמט זה בקובץ 'ui-lovelace.yaml'.", - "para_migrate": "Home Assistant יכול להוסיף מזהה יחודי לכל הכרטיסיות והתצוגות שלך בצורה אוטומטית בכך שתלחץ על לחצן ״הגר הגדרה״. ", + "para_migrate": "Home Assistant יכול להוסיף מזהה יחודי לכל הכרטיסיות והתצוגות שלך בצורה אוטומטית בכך שתלחץ על לחצן ״הגר הגדרה״.", "migrate": "הגר הגדרה" }, "header": "ערוך UI", diff --git a/translations/hr.json b/translations/hr.json index 747b55ad88..ec603c23e7 100644 --- a/translations/hr.json +++ b/translations/hr.json @@ -334,7 +334,7 @@ "caption": "Automatizacija", "description": "Stvaranje i uređivanje automatizacija", "picker": { - "header": "Urednik Automatizacije ", + "header": "Urednik Automatizacije", "introduction": "Automatizacijski urednik omogućuje stvaranje i uređivanje automatizacije. Molimo pročitajte [upute] (https:\/\/home-assistant.io\/docs\/automation\/editor\/) kako biste bili sigurni da ste ispravno konfigurirali Home Assistant.", "pick_automation": "Odaberite automatizaciju za uređivanje", "no_automations": "Nismo mogli pronaći nikakve automatizirane uređaje", @@ -606,7 +606,7 @@ "mfa_setup": { "title_aborted": "Prekinut", "title_success": "Uspješno!", - "step_done": "Postavka gotova za", + "step_done": "Postavka gotova za {step}", "close": "Zatvoriti", "submit": "podnijeti" } @@ -638,7 +638,7 @@ }, "error": { "invalid_auth": "Neispravno korisničko ime ili lozinka", - "invalid_code": "Pogrešan kod za provjeru autentičnosti " + "invalid_code": "Pogrešan kod za provjeru autentičnosti" }, "abort": { "login_expired": "Sesija istekla, prijavite se ponovo." @@ -710,7 +710,7 @@ }, "editor": { "edit_card": { - "header": "Konfiguracija Kartice ", + "header": "Konfiguracija Kartice", "save": "Spremi", "toggle_editor": "Uključi uređivač", "pick_card": "Odaberite karticu koju želite dodati.", @@ -870,7 +870,7 @@ "service": "Usluga" }, "relative_time": { - "past": "{vrijeme} prije", + "past": "{time} prije", "duration": { "week": "{count} {count, plural,\n jedan {week}\n ostali {weeks}\n}" } diff --git a/translations/hu.json b/translations/hu.json index d135760d3f..bfc1b6a258 100644 --- a/translations/hu.json +++ b/translations/hu.json @@ -556,6 +556,10 @@ "device_unavailable": "eszköz nem érhető el", "entity_unavailable": "entitás nem érhető el" } + }, + "zha": { + "caption": "ZHA", + "description": "Zigbee Home Automation hálózat menedzsment" } }, "profile": { @@ -926,6 +930,19 @@ "save": "Mentés", "name": "Név", "entity_id": "Entitás ID" + }, + "more_info_control": { + "script": { + "last_action": "Utolsó Művelet" + }, + "sun": { + "elevation": "Magasság", + "rising": "Napkelte", + "setting": "Napnyugta" + }, + "updater": { + "title": "Frissítési Instrukciók" + } } }, "auth_store": { @@ -975,7 +992,8 @@ "updater": "Frissítések", "weblink": "Hivatkozás", "zwave": "Z-Wave", - "vacuum": "Porszívó" + "vacuum": "Porszívó", + "zha": "ZHA" }, "attribute": { "weather": { diff --git a/translations/id.json b/translations/id.json index cc62c19baf..5f267028b1 100644 --- a/translations/id.json +++ b/translations/id.json @@ -364,7 +364,7 @@ "alias": "Nama", "triggers": { "header": "Pemicu", - "introduction": "Pemicu adalah apa yang memulai pemrosesan pengaturan otomasi. Adalah mungkin untuk menentukan beberapa pemicu untuk aturan yang sama. Setelah pemicu dimulai, Home Assistant akan memvalidasi Kondisi, jika ada, dan memanggil tindakan. ", + "introduction": "Pemicu adalah apa yang memulai pemrosesan pengaturan otomasi. Adalah mungkin untuk menentukan beberapa pemicu untuk aturan yang sama. Setelah pemicu dimulai, Home Assistant akan memvalidasi Kondisi, jika ada, dan memanggil tindakan.", "add": "Tambah pemicu", "duplicate": "Gandakan", "delete": "Hapus", diff --git a/translations/it.json b/translations/it.json index d733a1b540..8aa7d36613 100644 --- a/translations/it.json +++ b/translations/it.json @@ -556,6 +556,10 @@ "device_unavailable": "dispositivo non disponibile", "entity_unavailable": "entità non disponibile" } + }, + "zha": { + "caption": "ZHA", + "description": "Gestione rete Zigbee Home Automation" } }, "profile": { @@ -926,6 +930,19 @@ "save": "Salva", "name": "Nome", "entity_id": "ID Entità" + }, + "more_info_control": { + "script": { + "last_action": "Ultima azione" + }, + "sun": { + "elevation": "Alba", + "rising": "Tramonto", + "setting": "Impostazione" + }, + "updater": { + "title": "Aggiorna istruzioni" + } } }, "auth_store": { @@ -975,7 +992,8 @@ "updater": "Updater", "weblink": "Link Web", "zwave": "Z-Wave", - "vacuum": "Aspirapolvere" + "vacuum": "Aspirapolvere", + "zha": "ZHA" }, "attribute": { "weather": { diff --git a/translations/ko.json b/translations/ko.json index 6326175fce..4e707a1975 100644 --- a/translations/ko.json +++ b/translations/ko.json @@ -556,6 +556,10 @@ "device_unavailable": "기기 사용불가", "entity_unavailable": "구성요소 사용불가" } + }, + "zha": { + "caption": "ZHA", + "description": "Zigbee 홈 자동화 네트워크 관리" } }, "profile": { @@ -926,6 +930,19 @@ "save": "저장", "name": "이름", "entity_id": "구성요소 ID" + }, + "more_info_control": { + "script": { + "last_action": "최근 동작" + }, + "sun": { + "elevation": "고도", + "rising": "해돋이", + "setting": "해넘이" + }, + "updater": { + "title": "업데이트 방법" + } } }, "auth_store": { @@ -975,7 +992,8 @@ "updater": "업데이터", "weblink": "웹링크", "zwave": "Z-Wave", - "vacuum": "청소기" + "vacuum": "청소기", + "zha": "ZHA" }, "attribute": { "weather": { diff --git a/translations/lb.json b/translations/lb.json index fe13994b79..5acff06faf 100644 --- a/translations/lb.json +++ b/translations/lb.json @@ -556,6 +556,10 @@ "device_unavailable": "Apparat net erreechbar", "entity_unavailable": "Entitéit net erreechbar" } + }, + "zha": { + "caption": "ZHA", + "description": "Gestioun vum Zigbee Home Automation Reseau" } }, "profile": { @@ -926,6 +930,19 @@ "save": "Späicheren", "name": "Numm", "entity_id": "Entitéit ID" + }, + "more_info_control": { + "script": { + "last_action": "Läscht Aktioun" + }, + "sun": { + "elevation": "Héicht", + "rising": "Sonnenopgank", + "setting": "Sonnenënnergang" + }, + "updater": { + "title": "Instruktioune fir d'Mise à jour" + } } }, "auth_store": { @@ -975,7 +992,8 @@ "updater": "Aktualiséierung", "weblink": "Weblink", "zwave": "Z-Wave", - "vacuum": "Staubsauger" + "vacuum": "Staubsauger", + "zha": "ZHA" }, "attribute": { "weather": { diff --git a/translations/no.json b/translations/nb.json similarity index 98% rename from translations/no.json rename to translations/nb.json index 5d40fcf0d6..f1ef35f5f1 100644 --- a/translations/no.json +++ b/translations/nb.json @@ -556,6 +556,10 @@ "device_unavailable": "enheten er utilgjengelig", "entity_unavailable": "oppføringen er utilgjengelig" } + }, + "zha": { + "caption": "ZHA", + "description": "ZigBee Home Automation nettverksadministrasjon" } }, "profile": { @@ -926,6 +930,19 @@ "save": "Lagre", "name": "Navn", "entity_id": "Oppføring ID" + }, + "more_info_control": { + "script": { + "last_action": "Siste handling" + }, + "sun": { + "elevation": "Elevasjon", + "rising": "Stiger", + "setting": "Innstilling" + }, + "updater": { + "title": "Oppdateringsanvisning" + } } }, "auth_store": { @@ -975,7 +992,8 @@ "updater": "Oppdateringer", "weblink": "Lenke", "zwave": "Z-Wave", - "vacuum": "Støvsuger" + "vacuum": "Støvsuger", + "zha": "ZHA" }, "attribute": { "weather": { diff --git a/translations/nl.json b/translations/nl.json index 8dbf492b90..a1cbc0b3b9 100644 --- a/translations/nl.json +++ b/translations/nl.json @@ -556,6 +556,10 @@ "device_unavailable": "apparaat niet beschikbaar", "entity_unavailable": "entiteit niet beschikbaar" } + }, + "zha": { + "caption": "ZHA", + "description": "Zigbee Home Automation netwerkbeheer" } }, "profile": { @@ -926,6 +930,19 @@ "save": "Opslaan", "name": "Naam", "entity_id": "Entiteits-ID" + }, + "more_info_control": { + "script": { + "last_action": "Laatste actie" + }, + "sun": { + "elevation": "Hoogtehoek", + "rising": "Opkomst", + "setting": "Instelling" + }, + "updater": { + "title": "Instructies bijwerken" + } } }, "auth_store": { @@ -975,7 +992,8 @@ "updater": "Updater", "weblink": "Web link", "zwave": "Z-Wave", - "vacuum": "Stofzuigen" + "vacuum": "Stofzuigen", + "zha": "ZHA" }, "attribute": { "weather": { diff --git a/translations/nn.json b/translations/nn.json index 32fa52bc00..c9e3928ced 100644 --- a/translations/nn.json +++ b/translations/nn.json @@ -624,7 +624,7 @@ "mfa_setup": { "title_aborted": "Abortado", "title_success": "Sucesso!", - "step_done": "Configuraçãofeita por {passo}", + "step_done": "Configuraçãofeita por {step}", "close": "Fechar", "submit": "Submeter" } @@ -766,7 +766,7 @@ }, "common": { "loading": "Lastar", - "cancel": "Avbryt\n", + "cancel": "Avbryt", "save": "Lagre" }, "duration": { diff --git a/translations/pl.json b/translations/pl.json index 41cb3ed7d4..8411de509d 100644 --- a/translations/pl.json +++ b/translations/pl.json @@ -556,6 +556,10 @@ "device_unavailable": "urządzenie niedostępne", "entity_unavailable": "encja niedostępna" } + }, + "zha": { + "caption": "ZHA", + "description": "Zarządzanie siecią ZigBee Home Automation" } }, "profile": { @@ -926,6 +930,19 @@ "save": "Zapisz", "name": "Nazwa", "entity_id": "Identyfikator encji" + }, + "more_info_control": { + "script": { + "last_action": "Ostatnia akcja" + }, + "sun": { + "elevation": "Wysokość", + "rising": "Wschód", + "setting": "Zachód" + }, + "updater": { + "title": "Instrukcje aktualizacji" + } } }, "auth_store": { @@ -975,7 +992,8 @@ "updater": "Aktualizator", "weblink": "Link", "zwave": "Z-Wave", - "vacuum": "Odkurzacz" + "vacuum": "Odkurzacz", + "zha": "ZHA" }, "attribute": { "weather": { diff --git a/translations/pt-BR.json b/translations/pt-BR.json index feaf717d7d..22ded1d6a4 100644 --- a/translations/pt-BR.json +++ b/translations/pt-BR.json @@ -847,7 +847,7 @@ "light": { "brightness": "Brilho", "color_temperature": "Temperatura de cor", - "white_value": " Balanço de branco", + "white_value": "Balanço de branco", "effect": "Efeito" }, "media_player": { diff --git a/translations/ru.json b/translations/ru.json index f63699c76c..8cfd707257 100644 --- a/translations/ru.json +++ b/translations/ru.json @@ -556,6 +556,10 @@ "device_unavailable": "устройство недоступно", "entity_unavailable": "объект недоступен" } + }, + "zha": { + "caption": "ZHA", + "description": "Управление сетью Zigbee Home Automation" } }, "profile": { @@ -926,6 +930,19 @@ "save": "Сохранить", "name": "Название", "entity_id": "ID объекта" + }, + "more_info_control": { + "script": { + "last_action": "Последнее действие" + }, + "sun": { + "elevation": "Высота над горизонтом", + "rising": "Восход", + "setting": "Заход" + }, + "updater": { + "title": "Инструкция по обновлению" + } } }, "auth_store": { @@ -975,7 +992,8 @@ "updater": "Обновление", "weblink": "Интернет-ссылка", "zwave": "Z-Wave", - "vacuum": "Пылесос" + "vacuum": "Пылесос", + "zha": "ZHA" }, "attribute": { "weather": { diff --git a/translations/sk.json b/translations/sk.json index a5a5764fb1..9d740bbd19 100644 --- a/translations/sk.json +++ b/translations/sk.json @@ -369,7 +369,7 @@ "add": "Pridať spúšťač", "duplicate": "Duplikovať", "delete": "Odstrániť", - "delete_confirm": "Ste si istý odstránením ? ", + "delete_confirm": "Ste si istý odstránením ?", "unsupported_platform": "Nepodporovaná platforma: {platform}", "type_select": "Typ spúšťača", "type": { @@ -556,6 +556,10 @@ "device_unavailable": "zariadenie nie je dostupné", "entity_unavailable": "Entita nie je dostupná" } + }, + "zha": { + "caption": "ZHA", + "description": "Riadenie siete ZigBee Home Automation" } }, "profile": { @@ -624,7 +628,7 @@ "mfa_setup": { "title_aborted": "Prerušené", "title_success": "Úspech!", - "step_done": "Nastavenie dokončené krok {step} ", + "step_done": "Nastavenie dokončené krok {step}", "close": "Zavrieť", "submit": "Odoslať" } @@ -926,6 +930,19 @@ "save": "Uložiť", "name": "Názov", "entity_id": "Entity ID" + }, + "more_info_control": { + "script": { + "last_action": "Posledná akcia" + }, + "sun": { + "elevation": "Nadmorská výška", + "rising": "Vychádzajúce", + "setting": "Zapadajúce" + }, + "updater": { + "title": "Pokyny na aktualizáciu" + } } }, "auth_store": { @@ -975,7 +992,8 @@ "updater": "Aktualizátor", "weblink": "Webový odkaz", "zwave": "Z-Wave", - "vacuum": "Vysávač" + "vacuum": "Vysávač", + "zha": "ZHA" }, "attribute": { "weather": { diff --git a/translations/sl.json b/translations/sl.json index 150082c742..2327c04a99 100644 --- a/translations/sl.json +++ b/translations/sl.json @@ -898,7 +898,7 @@ "service": "Storitev" }, "relative_time": { - "past": "pred {time} ", + "past": "pred {time}", "future": "Čez {time}", "never": "Nikoli", "duration": { diff --git a/translations/sv.json b/translations/sv.json index f9d8808532..00b199cc16 100644 --- a/translations/sv.json +++ b/translations/sv.json @@ -601,7 +601,7 @@ "prompt_name": "Namn?", "prompt_copy_token": "Kopiera din åtkomsttoken. Den kommer inte att visas igen.", "empty_state": "Du har än så länge inga långlivade åtkomsttokens.", - "last_used": "Användes senast den {date} från {location} ", + "last_used": "Användes senast den {date} från {location}", "not_used": "Har aldrig använts" }, "current_user": "Du är inloggad som {fullName}.", diff --git a/translations/ta.json b/translations/ta.json index 637e9bc708..039202bde4 100644 --- a/translations/ta.json +++ b/translations/ta.json @@ -12,19 +12,19 @@ "state": { "default": { "off": "ஆஃப்", - "on": "ஆன் ", + "on": "ஆன்", "unknown": "தெரியவில்லை", "unavailable": "கிடைக்கவில்லை" }, "alarm_control_panel": { - "armed": "எச்சரிக்கை ஒலி அமைக்கப்பட்டுள்ளது ", - "disarmed": "எச்சரிக்கை ஒலி அமைக்கப்படவில்லை ", - "armed_home": "எச்சரிக்கை ஒலி முகப்பு ", - "armed_away": "எச்சரிக்கை ஒலி வெளியே ", - "armed_night": "எச்சரிக்கை ஒலி இரவில் ", + "armed": "எச்சரிக்கை ஒலி அமைக்கப்பட்டுள்ளது", + "disarmed": "எச்சரிக்கை ஒலி அமைக்கப்படவில்லை", + "armed_home": "எச்சரிக்கை ஒலி முகப்பு", + "armed_away": "எச்சரிக்கை ஒலி வெளியே", + "armed_night": "எச்சரிக்கை ஒலி இரவில்", "pending": "நிலுவையில்", - "arming": "எச்சரிக்கை ஒலி அமைக்கிறது ", - "disarming": "எச்சரிக்கை ஒலி நீக்கம் ", + "arming": "எச்சரிக்கை ஒலி அமைக்கிறது", + "disarming": "எச்சரிக்கை ஒலி நீக்கம்", "triggered": "தூண்டப்படுகிறது", "armed_custom_bypass": "விருப்ப எச்சரிக்கை ஒலி" }, @@ -42,7 +42,7 @@ "on": "ஈரம்" }, "gas": { - "off": "தெளிவு ", + "off": "தெளிவு", "on": "கண்டறியப்பட்டது" }, "motion": { @@ -107,7 +107,7 @@ "idle": "பணியின்றி", "auto": "தானாக இயங்குதல்", "dry": "உலர்ந்த", - "fan_only": "விசிறி மட்டும் ", + "fan_only": "விசிறி மட்டும்", "eco": "சுற்றுச்சூழல்", "electric": "மின்சார", "performance": "செயல்திறன்", @@ -121,8 +121,8 @@ "configured": "உள்ளமைக்கப்பட்டது" }, "cover": { - "open": "திறக்கப்பட்டுள்ளது ", - "opening": "திறக்கிறது ", + "open": "திறக்கப்பட்டுள்ளது", + "opening": "திறக்கிறது", "closed": "மூடப்பட்டது", "closing": "மூடுகிறது ", "stopped": "நிறுத்தப்பட்டது" @@ -216,14 +216,14 @@ "unavailable": "கிடைக்கவில்லை" }, "alarm_control_panel": { - "armed": "எச்சரிக்கை ஒலி அமைக்கப்பட்டுள்ளது ", - "disarmed": "எச்சரிக்கை ஒலி அமைக்கப்படவில்லை ", + "armed": "எச்சரிக்கை ஒலி அமைக்கப்பட்டுள்ளது", + "disarmed": "எச்சரிக்கை ஒலி அமைக்கப்படவில்லை", "armed_home": "எச்சரிக்கை ஒலி அமைக்கப்பட்டுள்ளது ", "armed_away": "எச்சரிக்கை ஒலி அமைக்கப்பட்டுள்ளது ", "armed_night": "எச்சரிக்கை ஒலி அமைக்கப்பட்டுள்ளது ", "pending": "கிடப்பில் ", "arming": "எச்சரிக்கை ஒலி அமைக்கிறது ", - "disarming": "எச்சரிக்கை ஒலி அமைக்கப்படவில்லை ", + "disarming": "எச்சரிக்கை ஒலி அமைக்கப்படவில்லை", "triggered": "தூண்ட", "armed_custom_bypass": "எச்சரிக்கை ஒலி அமைக்கப்பட்டுள்ளது " }, diff --git a/translations/tr.json b/translations/tr.json index 352d618ee5..4a7b4c5cac 100644 --- a/translations/tr.json +++ b/translations/tr.json @@ -46,7 +46,7 @@ }, "moisture": { "off": "Kuru", - "on": "Islak " + "on": "Islak" }, "gas": { "off": "Temiz", @@ -115,6 +115,10 @@ "window": { "off": "[%key:state::cover::kapalı%]", "on": "[%key:state::cover::açık%]" + }, + "lock": { + "off": "Kilit kapalı", + "on": "Kilit açık" } }, "calendar": { @@ -141,7 +145,7 @@ "high_demand": "Yüksek talep", "heat_pump": "Isı pompası", "gas": "Gaz", - "manual": "Manuel" + "manual": "Kılavuz" }, "configurator": { "configure": "Ayarla", @@ -348,6 +352,7 @@ "alias": "İsim", "triggers": { "delete": "Sil", + "unsupported_platform": "Desteklenmeyen platform: {platform}", "type": { "sun": { "event": "Olay:" @@ -359,7 +364,11 @@ "leave": "Çıkınca" }, "state": { - "for": "İçin" + "for": "Süre" + }, + "webhook": { + "label": "Webhook", + "webhook_id": "Webhook Kimliği" } } }, @@ -406,6 +415,7 @@ "duplicate": "Kopya", "delete": "Sil", "delete_confirm": "Silmek istediğinize emin misiniz?", + "unsupported_action": "Desteklenmeyen eylem: {action}", "type": { "delay": { "delay": "Gecikme" @@ -448,23 +458,27 @@ }, "integrations": { "caption": "Entegrasyonlar", - "description": "Bağlı cihazları ve hizmetleri yönetin", + "description": "Bağlı aygıtları ve hizmetleri yönetin", "discovered": "Bulundu", - "configured": "Yapılandırılmış", + "configured": "Yapılandırıldı", "new": "Yeni bir entegrasyon kur", "configure": "Yapılandır", "none": "Henüz hiçbir şey yapılandırılmamış", "config_entry": { - "no_devices": "Bu entegrasyona ait hiçbir cihaz yok", - "no_device": "Cihaza ait olmayan cisimler", + "no_devices": "Bu entegrasyona ait hiçbir aygıt yok", + "no_device": "Aygıtsız varlıklar", "delete_confirm": "Bu entegrasyonu silmek istediğinizden emin misiniz?", "restart_confirm": "Bu entegrasyonu kaldırmaya devam etmek için Home Assistant'ı yeniden başlatın", "manuf": "üretici: {manufacturer}", "hub": "Şununla bağlı:", "firmware": "Aygıt yazılımı: {version}", - "device_unavailable": "cihaz kullanılamıyor", - "entity_unavailable": "cisim kullanılamıyor" + "device_unavailable": "aygıt kullanılamıyor", + "entity_unavailable": "varlık kullanılamıyor" } + }, + "zha": { + "caption": "ZHA", + "description": "Zigbee Ev Otomasyonu ağ yönetimi" } }, "profile": { @@ -476,20 +490,29 @@ "description": "Her yenileme jetonu bir oturum açma oturumunu temsil eder. Yenileme jetonları, çıkış yapmak istediğinizde otomatik olarak kaldırılacaktır. Aşağıdaki yenileme jetonları hesabınız için şu anda aktif.", "created_at": "{date} tarihinde oluşturuldu", "last_used": "En son {date} tarihinde {location} konumundan kullanıldı", - "not_used": "Hiç kullanılmadı" + "not_used": "Hiç kullanılmadı", + "current_token_tooltip": "Geçerli yenileme anahtarı silinemedi" }, "long_lived_access_tokens": { + "learn_auth_requests": "Yetkilendirilmiş istekleri nasıl yapacağınızı öğrenin.", "created_at": "{date} tarihinde oluşturuldu", + "confirm_delete": "{name} için erişim anahtarını silmek istediğinizden emin misiniz?", + "delete_failed": "Erişim anahtarı silinemedi.", + "create": "Anahtar oluştur.", + "create_failed": "Erişim anahtarı oluşturulamadı.", "prompt_name": "Ad?", + "prompt_copy_token": "Erişim anahtarınızı kopyalayın. Bu anahtar bir daha görüntülenmeyecektir.", + "empty_state": "Henüz uzun ömürlü erişim anahtarınız yok.", "last_used": "En son {date} tarihinde {location} konumundan kullanıldı", "not_used": "Hiç kullanılmamış" }, "current_user": "{fullName} olarak giriş yaptınız.", + "is_owner": "Sahipsiniz.", "logout": "Çıkış yap", "change_password": { "header": "Parolayı Değiştir", "current_password": "Güncel Parola", - "new_password": "Yeni Parolayı", + "new_password": "Yeni Parola", "confirm_new_password": "Yeni Parolayı Onaylayın", "error_required": "Gerekli", "submit": "Gönder" @@ -569,13 +592,41 @@ "lovelace": { "cards": { "shopping-list": { + "checked_items": "Seçili öğeler", "clear_items": "Seçili ögeleri temizle", "add_item": "Öge Ekle" } }, "editor": { "edit_card": { - "save": "Kaydet" + "header": "Kart Ayarları", + "save": "Kaydet", + "toggle_editor": "Düzenleyiciye Geçiş", + "pick_card": "Eklemek istediğiniz kartı seçin.", + "add": "Kart Ekle", + "edit": "Düzenle", + "delete": "Sil" + }, + "migrate": { + "header": "Yapılandırma Geçersiz", + "para_no_id": "Bu öğenin bir kimliği yok. Lütfen 'ui-lovelace.yaml' dosyasında bu elemente bir kimlik ekleyin.", + "para_migrate": "'Ayarları aktar' düğmesine bastığınız zaman Home Assistant tüm kartlarınıza ve görünümlerinize otomatik olarak kimlik atayabilir.", + "migrate": "Ayarları aktar" + }, + "header": "Kullanıcı arayüzünü düzenle", + "configure_ui": "Kullanıcı arayüzünü ayarla", + "edit_view": { + "header": "Ayarları görüntüle", + "add": "Görünüm ekle", + "edit": "Görünümü düzenle", + "delete": "Görünümü sil" + }, + "save_config": { + "header": "Lovelace kullanıcı arayüzünü kontrolünüz altına alın", + "para": "Home Assistant varsayılan olarak kullanıcı arayüzünüzü yönetecek, yeni Lovelace bileşenleri ya da varlıklar kullanıma sunulduğunda onu güncelleyecektir. Eğer bunu kontrolünüz altına almak istiyorsanız daha sonra biz sizin için bu değişiklikleri otomatik olarak gerçekleştiremeyeceğiz.", + "para_sure": "Kullanıcı arayüzünüzü kontrol altına almak istediğinize emin misiniz?", + "cancel": "Boşver", + "save": "Kontrol altına al" } } } @@ -586,7 +637,8 @@ }, "common": { "loading": "Yükleniyor", - "cancel": "İptal" + "cancel": "İptal", + "save": "Kaydet" }, "duration": { "day": "{count}{count, plural,\n one { gün }\n other { gün }\n}", @@ -646,17 +698,34 @@ } }, "water_heater": { - "currently": "Güncel olarak", + "currently": "Şu an", "on_off": "Açık \/ kapalı", - "target_temperature": "hedef sıcaklık", + "target_temperature": "Hedef sıcaklık", "operation": "İşlem", "away_mode": "Dışarıda modu" + }, + "alarm_control_panel": { + "arm_night": "Geceyi etkinleştir", + "armed_custom_bypass": "Özel atlatma" } }, "dialogs": { "more_info_settings": { "save": "Kaydet", "name": "Ad" + }, + "more_info_control": { + "script": { + "last_action": "Son Eylem" + }, + "sun": { + "elevation": "Yükseklik", + "rising": "Yükseliyor", + "setting": "Ayar" + }, + "updater": { + "title": "Talimatları Güncelle" + } } }, "auth_store": { @@ -704,7 +773,8 @@ "switch": "Anahtar", "updater": "Güncelleyici", "weblink": "Web bağlantısı", - "zwave": "Z-Wave" + "zwave": "Z-Wave", + "zha": "ZHA" }, "attribute": { "weather": { diff --git a/translations/uk.json b/translations/uk.json index 07bfdf8c67..ee9e36de6f 100644 --- a/translations/uk.json +++ b/translations/uk.json @@ -285,6 +285,7 @@ "ui": { "panel": { "shopping-list": { + "clear_completed": "Очистити позначені елементи", "add_item": "Додати елемент", "microphone_tip": "Торкніться мікрофона у верхньому правому куті та скажіть \"Add candy to my shopping list\"" }, @@ -344,30 +345,51 @@ "description": "Створення та редагування автоматизації", "picker": { "header": "Редактор автоматизації", - "pick_automation": "Виберіть автоматизацію для редагування", + "introduction": "Редактор автоматизації дозволяє створювати та редагувати автоматизації. Будь ласка, прочитайте [інструкції] (https:\/\/home-assistant.io\/docs\/automation\/editor\/), щоб переконатися, що ви правильно налаштували Home Assistant.", + "pick_automation": "Оберіть автоматизацію для редагування", + "no_automations": "Ми не знайшли автоматизації для редагування", "add_automation": "Додати автоматизацію" }, "editor": { + "introduction": "Використовуйте автоматизацію, щоб оживити ваш будинок", "default_name": "Нова автоматизація", "save": "Зберегти", "unsaved_confirm": "У вас є незбережені зміни. Ви впевнені, що хочете вийти?", "alias": "Назва", "triggers": { "header": "Тригери", + "introduction": "Тригери - це те, що починає обробляти правило автоматизації. Можна вказати декілька тригерів для одного і того ж правила. Після запуску тригера, Home Assistant перевірить умови, якщо такі є, і викликає дію. \n\n [Докладніше про тригери.] (Https:\/\/home-assistant.io\/docs\/automation\/trigger\/)", + "add": "Додати тригер", + "duplicate": "Дублювати", + "delete": "Видалити", "unsupported_platform": "Непідтримувана платформа: {platform}", "type": { "homeassistant": { + "event": "Подія:", "start": "Початок", "shutdown": "Завершення роботи" }, + "numeric_state": { + "above": "Вище", + "below": "Нижче" + }, "sun": { "label": "Сонце", + "event": "Подія:", "sunrise": "Схід сонця", "sunset": "Захід сонця", "offset": "Зміщення (необов'язково)" }, "time": { - "label": "Час" + "label": "Час", + "at": "У" + }, + "zone": { + "label": "Зона", + "zone": "Зона:", + "event": "Подія:", + "enter": "Увійшов", + "leave": "Залишив" }, "state": { "for": "Протягом" @@ -375,18 +397,31 @@ } }, "conditions": { + "header": "Умови", + "introduction": "Умови є необов'язковою частиною правила автоматизації і можуть використовуватися для запобігання дії, що відбувається під час запуску. Умови виглядають дуже схоже на тригери, але вони різні. Тригер буде дивитися на події, що відбуваються в системі, в той час як умова тільки дивиться на те, як система виглядає зараз. Тригер може спостерігати, що перемикач включений. Умова може бачити тільки, якщо перемикач ввімкнено або вимкнено. \n\n [Докладніше про умови.] (Https:\/\/home-assistant.io\/docs\/scripts\/conditions\/)", + "duplicate": "Дублювати", + "delete": "Видалити", + "delete_confirm": "Ви впевнені, що хочете видалити?", "type": { "sun": { "before": "Перед:", "after": "Після:", "before_offset": "Перед зміщенням (необов'язково)", - "after_offset": "Після зміщення (необов'язково)" + "after_offset": "Після зміщення (опціонально)" + }, + "time": { + "after": "Після", + "before": "До" } } }, "actions": { "header": "Дії", + "introduction": "Що Home Assistant буде робити, коли автоматизація спрацьовує. \n\n [Докладніше про дії.] (Https:\/\/home-assistant.io\/docs\/automation\/action\/)", "add": "Додати дію", + "duplicate": "Дублювати", + "delete": "Видалити", + "delete_confirm": "Ви впевнені, що хочете видалити?", "unsupported_action": "Непідтримувана дія: {action}", "type_select": "Тип дії", "type": { @@ -469,7 +504,7 @@ "dropdown_label": "Тема" }, "refresh_tokens": { - "header": "Токени оновлення ", + "header": "Токени оновлення", "description": "Кожен токен оновлення відображає сеанс входу в систему. Токени оновлення автоматично видалятимуться, коли ви натиснете вийти. Наступні токени оновлення доступні для вашого облікового запису.", "token_title": "Оновити токен для {clientId}", "created_at": "Створений в {date}", @@ -546,7 +581,7 @@ }, "error": { "invalid_auth": "Неправильне ім'я користувача або пароль", - "invalid_code": "Невірний код автентифікації " + "invalid_code": "Невірний код автентифікації" }, "abort": { "login_expired": "Сесія закінчилася, увійдіть знову." @@ -567,7 +602,7 @@ } }, "error": { - "invalid_auth": "Невірний пароль API " + "invalid_auth": "Невірний пароль API" }, "abort": { "no_api_password_set": "Ви не маєте налаштованого пароля API." @@ -632,7 +667,7 @@ "header": "Редагування інтерфейсу", "configure_ui": "Налаштувати інтерфейс користувача", "edit_view": { - "header": "Перегляд Конфігурації ", + "header": "Перегляд Конфігурації", "add": "Додати вигляд", "edit": "Редагувати вигляд", "delete": "Видалити вигляд" @@ -706,7 +741,7 @@ }, "cover": { "position": "Положення", - "tilt_position": "Положення нахилу " + "tilt_position": "Положення нахилу" }, "fan": { "speed": "Швидкість", @@ -756,7 +791,7 @@ "components": { "entity": { "entity-picker": { - "entity": "Об'єкт" + "entity": "Entity" } }, "service-picker": { @@ -790,6 +825,18 @@ "more_info_settings": { "save": "Зберегти", "name": "Назва" + }, + "more_info_control": { + "script": { + "last_action": "Остання дія" + }, + "sun": { + "elevation": "Висота", + "setting": "Налаштування" + }, + "updater": { + "title": "Інструкції по оновленню" + } } }, "auth_store": { @@ -812,9 +859,10 @@ "climate": "Клімат", "configurator": "Конфігуратор", "conversation": "Розмова", + "cover": "Заголовок", "device_tracker": "Трекер пристрою", "fan": "Вентилятор", - "history_graph": "Графік історії ", + "history_graph": "Графік історії", "group": "Група", "light": "Освітлення", "lock": "Замок", diff --git a/translations/vi.json b/translations/vi.json index 65012c9e14..d1390ca2bb 100644 --- a/translations/vi.json +++ b/translations/vi.json @@ -314,7 +314,7 @@ "invalid": "Cấu hình không hợp lệ" }, "reloading": { - "heading": "Nạp lại Cấu hình ", + "heading": "Nạp lại Cấu hình", "introduction": "Một số phần của Home Assistant có thể tải lại mà không yêu cầu khởi động lại. Nhấn nút tải lại sẽ gỡ bỏ cấu hình hiện tại của nó và tải một cấu hình mới.", "core": "Tải lại lõi", "group": "Tải lại nhóm", diff --git a/translations/zh-Hans.json b/translations/zh-Hans.json index 94afe10eaf..d5969dbaa4 100644 --- a/translations/zh-Hans.json +++ b/translations/zh-Hans.json @@ -913,7 +913,7 @@ "notification_toast": { "entity_turned_on": "已打开 {entity}。", "entity_turned_off": "已关闭 {entity}。", - "service_called": "服务 {service} 已调用。 ", + "service_called": "服务 {service} 已调用。", "service_call_failed": "调用服务 {service} 失败。", "connection_lost": "连接中断。正在重新连接..." }, diff --git a/translations/zh-Hant.json b/translations/zh-Hant.json index 5c83df2a18..db115fd6ba 100644 --- a/translations/zh-Hant.json +++ b/translations/zh-Hant.json @@ -556,6 +556,10 @@ "device_unavailable": "裝置不可用", "entity_unavailable": "物件不可用" } + }, + "zha": { + "caption": "ZHA", + "description": "Zigbee 家庭自動化網路管理" } }, "profile": { @@ -926,6 +930,19 @@ "save": "儲存", "name": "名稱", "entity_id": "物件 ID" + }, + "more_info_control": { + "script": { + "last_action": "上次觸發" + }, + "sun": { + "elevation": "海拔", + "rising": "日升", + "setting": "設定" + }, + "updater": { + "title": "更新說明" + } } }, "auth_store": { @@ -975,7 +992,8 @@ "updater": "更新器", "weblink": "網站鏈接", "zwave": "Z-Wave", - "vacuum": "吸塵器" + "vacuum": "吸塵器", + "zha": "ZHA" }, "attribute": { "weather": { diff --git a/yarn.lock b/yarn.lock index d8f8a49567..a4ca8e389e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -704,48 +704,6 @@ log-update "^2.3.0" strip-ansi "^3.0.1" -"@material/animation@^0.40.1": - version "0.40.1" - resolved "https://registry.yarnpkg.com/@material/animation/-/animation-0.40.1.tgz#c5ff31e7d7e17324a0045e889d3530b150b9fcec" - integrity sha512-HtxFUw04EHg4S6pXfTA3Z0wKxnNDNcDhe1Np2Y2geo+lAk2Hb7m8yCL/GaL9o2I/eRYsgUXC0U7+Mk74GCz3zw== - -"@material/base@^0.40.1": - version "0.40.1" - resolved "https://registry.yarnpkg.com/@material/base/-/base-0.40.1.tgz#a0d8e19cee98dae0f96dbf0887a14b3f7acd2aac" - integrity sha512-vrbOK8hONVCYgURQ9h7nkXvMdYnZVVNmAfFFijF8fbWQdwnoPcNTdqV6RoQlhBEqHYHQqLNfdUDlznAPKLclGQ== - -"@material/mwc-base@^0.3.1": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@material/mwc-base/-/mwc-base-0.3.1.tgz#5e1440aa09e0a83633be36eb8102ff88d3fddae8" - integrity sha512-7AdcBu6rxARcUteEBNSJKCen3hP47T/NRsfw+RMn6IedHlEGp2GKwF6YqYDCVSsQbm0IjsJ4ft4+nVXlFVYO2g== - dependencies: - "@polymer/lit-element" "^0.6.2" - lit-html "^0.12.0" - -"@material/mwc-ripple@^0.3.1": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@material/mwc-ripple/-/mwc-ripple-0.3.1.tgz#da812516d0bd0b15b0c4793b783fbdb9e04cd7a0" - integrity sha512-pOdBkP6NJyGz9UftvKjrx8sXvz+yIXMC8q6Qx/LgGw67tgU4qM/1Hy22iePiw1UFNhlqD8ZwtdPLXKVaisGauQ== - dependencies: - "@material/mwc-base" "^0.3.1" - "@material/ripple" "^0.40.0" - "@polymer/lit-element" "^0.6.2" - lit-html "^0.12.0" - -"@material/ripple@^0.40.0": - version "0.40.1" - resolved "https://registry.yarnpkg.com/@material/ripple/-/ripple-0.40.1.tgz#57cbc689303b48282229cb9b62556af7442e852a" - integrity sha512-sndeTS4VHa0v1UGj7MNcxMCuO9LJ1DjoL1EjE6BH3Lm3M1MnXJHdsBo2CgPbU/FI84tt6+eyHGOYPdPrEDJhCA== - dependencies: - "@material/animation" "^0.40.1" - "@material/base" "^0.40.1" - "@material/theme" "^0.40.1" - -"@material/theme@^0.40.1": - version "0.40.1" - resolved "https://registry.yarnpkg.com/@material/theme/-/theme-0.40.1.tgz#3cc3f1bf87ee9581df03e347a1979e53ae617221" - integrity sha512-cH1CsGIDisEQ2oroZhLTypV0Ir00x3WIwFXnPo7qv3832tuIDkZY623U3rUax6KNPz4Hh1j0tNpTwgrNZwvwWA== - "@mdi/svg@^3.0.39": version "3.0.39" resolved "https://registry.yarnpkg.com/@mdi/svg/-/svg-3.0.39.tgz#6a2d50e5650f758a3a8f6ab294cd272c9408fcda" @@ -1029,13 +987,6 @@ "@polymer/iron-meta" "^3.0.0-pre.26" "@polymer/polymer" "^3.0.0" -"@polymer/lit-element@0.6.2", "@polymer/lit-element@^0.6.2": - version "0.6.2" - resolved "https://registry.yarnpkg.com/@polymer/lit-element/-/lit-element-0.6.2.tgz#589f2fa19e84d23c1debb2c329cbab758ae30581" - integrity sha512-4NWvK6SyAyyeW1mQ24ZVR+rtqZNHZ2JWnVTsPF/1iXnmmPwnpLs8mz0HRqz5adyoyt96ed/y2dsDwGBktJYyew== - dependencies: - lit-html "^0.12.0" - "@polymer/neon-animation@^3.0.0-pre.26", "@polymer/neon-animation@^3.0.1": version "3.0.1" resolved "https://registry.yarnpkg.com/@polymer/neon-animation/-/neon-animation-3.0.1.tgz#6658e4b524abc057477772a7473292493d366c24" @@ -8685,10 +8636,17 @@ listr@^0.14.2: p-map "^2.0.0" rxjs "^6.3.3" -lit-html@0.12.0, lit-html@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-0.12.0.tgz#d994420fda74744f9d4a79401b086de929643e6a" - integrity sha512-NyFgq8yTlGEjUFQOmNnK/kj+ZdDVJzTwsLunNSewGiOns7SjuJi6ymCCqzZZ81uW2VwEmliMbOlFZc9QmOJPLA== +lit-element@2.0.0-rc.2: + version "2.0.0-rc.2" + resolved "https://registry.yarnpkg.com/lit-element/-/lit-element-2.0.0-rc.2.tgz#5975c3b282ce47937de861b48456036df71f422b" + integrity sha512-yP6mX23n8WUYXpS2RJUL87DSZYQY327YrnqFiSyPe9aSzjgJ5Jy3In3itzjeiFOT8Od4VKLM7u6bLG9tGFO1pw== + dependencies: + lit-html "^1.0.0-rc.2" + +lit-html@1.0.0-rc.2, lit-html@^1.0.0-rc.2: + version "1.0.0-rc.2" + resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-1.0.0-rc.2.tgz#b9c904520fe005d349aa737a86d83645d97d5a89" + integrity sha512-4bq34lhVmwWly1zBXicOBJLOwaWfjOVbchEEmFnZLuztxjh5wRd2WqV0URX8Q47MQ7PaIjn/eXyTRKsYhSAeRw== load-json-file@^1.0.0: version "1.1.0"