From d7e59935015062e97d7f5d871d9e8e63d0fb396e Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Fri, 7 Dec 2018 21:39:27 -0600 Subject: [PATCH 01/82] UI Editor for `markdown` card --- .../lovelace/cards/hui-markdown-card.ts | 12 ++- .../hui-markdown-card-editor.ts | 97 +++++++++++++++++++ 2 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 src/panels/lovelace/editor/config-elements/hui-markdown-card-editor.ts diff --git a/src/panels/lovelace/cards/hui-markdown-card.ts b/src/panels/lovelace/cards/hui-markdown-card.ts index e30fadaa40..4c33ebf4bc 100644 --- a/src/panels/lovelace/cards/hui-markdown-card.ts +++ b/src/panels/lovelace/cards/hui-markdown-card.ts @@ -4,16 +4,24 @@ import { classMap } from "lit-html/directives/classMap"; import "../../../components/ha-card"; import "../../../components/ha-markdown"; -import { LovelaceCard } from "../types"; +import { LovelaceCard, LovelaceCardEditor } from "../types"; import { LovelaceCardConfig } from "../../../data/lovelace"; import { TemplateResult } from "lit-html"; -interface Config extends LovelaceCardConfig { +export interface Config extends LovelaceCardConfig { content: string; title?: string; } export class HuiMarkdownCard extends LitElement implements LovelaceCard { + public static async getConfigElement(): Promise { + await import("../editor/config-elements/hui-markdown-card-editor"); + return document.createElement("hui-markdown-card-editor"); + } + public static getStubConfig(): object { + return { content: " " }; + } + private _config?: Config; static get properties(): PropertyDeclarations { 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 new file mode 100644 index 0000000000..94753ef548 --- /dev/null +++ b/src/panels/lovelace/editor/config-elements/hui-markdown-card-editor.ts @@ -0,0 +1,97 @@ +import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; +import { TemplateResult } from "lit-html"; +import { struct } from "../../common/structs/struct"; +import "@polymer/paper-input/paper-input"; +import "@polymer/paper-input/paper-textarea"; + +import { EntitiesEditorEvent, EditorTarget } from "../types"; +import { hassLocalizeLitMixin } from "../../../../mixins/lit-localize-mixin"; +import { HomeAssistant } from "../../../../types"; +import { LovelaceCardEditor } from "../../types"; +import { fireEvent } from "../../../../common/dom/fire_event"; +import { Config } from "../../cards/hui-glance-card"; +import { configElementStyle } from "./config-elements-style"; + +const cardConfigStruct = struct({ + type: "string", + id: "string|number", + title: "string?", + content: "string", +}); + +export class HuiMarkdownCardEditor extends hassLocalizeLitMixin(LitElement) + implements LovelaceCardEditor { + public hass?: HomeAssistant; + private _config?: Config; + + public setConfig(config: Config): void { + config = cardConfigStruct(config); + + this._config = { type: "markdown", ...config }; + } + + static get properties(): PropertyDeclarations { + return { hass: {}, _config: {} }; + } + + get _title(): string { + return this._config!.title || ""; + } + + get _content(): string { + return this._config!.content || ""; + } + + protected render(): TemplateResult { + if (!this.hass) { + return html``; + } + + return html` + ${configElementStyle} +
+ + +
+ `; + } + + private _valueChanged(ev: EntitiesEditorEvent): void { + if (!this._config || !this.hass) { + return; + } + const target = ev.target! as EditorTarget; + + if (this[`_${target.configValue}`] === target.value) { + return; + } + if (target.configValue) { + this._config = { + ...this._config, + [target.configValue!]: target.value, + }; + } + fireEvent(this, "config-changed", { config: this._config }); + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-markdown-card-editor": HuiMarkdownCardEditor; + } +} + +customElements.define("hui-markdown-card-editor", HuiMarkdownCardEditor); From 0319fd23c5f3e49a096b4464e7ded49de03ad44a Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Mon, 10 Dec 2018 23:13:26 -0600 Subject: [PATCH 02/82] Remove `id` --- .../lovelace/editor/config-elements/hui-markdown-card-editor.ts | 1 - 1 file changed, 1 deletion(-) 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 94753ef548..3c5a8e37e9 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 @@ -14,7 +14,6 @@ import { configElementStyle } from "./config-elements-style"; const cardConfigStruct = struct({ type: "string", - id: "string|number", title: "string?", content: "string", }); From 758b686684057ef7216d5376daa574310806c9fd Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 11 Dec 2018 17:05:45 +0100 Subject: [PATCH 03/82] Convert HUI-ROOT to Lit Element --- src/data/lovelace.ts | 4 + src/panels/lovelace/hui-editor.ts | 6 + src/panels/lovelace/hui-root.js | 454 ----------------------- src/panels/lovelace/hui-root.ts | 583 ++++++++++++++++++++++++++++++ 4 files changed, 593 insertions(+), 454 deletions(-) delete mode 100644 src/panels/lovelace/hui-root.js create mode 100644 src/panels/lovelace/hui-root.ts diff --git a/src/data/lovelace.ts b/src/data/lovelace.ts index d3ea76c430..994227b87c 100644 --- a/src/data/lovelace.ts +++ b/src/data/lovelace.ts @@ -3,6 +3,8 @@ import { HomeAssistant } from "../types"; export interface LovelaceConfig { title?: string; views: LovelaceViewConfig[]; + background?: string; + resources?: Array<{ type: "css" | "js" | "module" | "html"; url: string }>; } export interface LovelaceViewConfig { @@ -13,6 +15,8 @@ export interface LovelaceViewConfig { path?: string; icon?: string; theme?: string; + panel?: boolean; + background?: string; } export interface LovelaceCardConfig { diff --git a/src/panels/lovelace/hui-editor.ts b/src/panels/lovelace/hui-editor.ts index 202de5b0bb..42b65dbc79 100644 --- a/src/panels/lovelace/hui-editor.ts +++ b/src/panels/lovelace/hui-editor.ts @@ -131,4 +131,10 @@ class LovelaceFullConfigEditor extends hassLocalizeLitMixin(LitElement) { } } +declare global { + interface HTMLElementTagNameMap { + "hui-editor": LovelaceFullConfigEditor; + } +} + customElements.define("hui-editor", LovelaceFullConfigEditor); diff --git a/src/panels/lovelace/hui-root.js b/src/panels/lovelace/hui-root.js deleted file mode 100644 index 415855e555..0000000000 --- a/src/panels/lovelace/hui-root.js +++ /dev/null @@ -1,454 +0,0 @@ -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"; -import "@polymer/app-layout/app-toolbar/app-toolbar"; -import "@polymer/app-route/app-route"; -import "@polymer/paper-icon-button/paper-icon-button"; -import "@polymer/paper-button/paper-button"; -import "@polymer/paper-item/paper-item"; -import "@polymer/paper-listbox/paper-listbox"; -import "@polymer/paper-menu-button/paper-menu-button"; -import "@polymer/paper-tabs/paper-tab"; -import "@polymer/paper-tabs/paper-tabs"; - -import { html } from "@polymer/polymer/lib/utils/html-tag"; -import { PolymerElement } from "@polymer/polymer/polymer-element"; - -import scrollToTarget from "../../common/dom/scroll-to-target"; - -import EventsMixin from "../../mixins/events-mixin"; -import localizeMixin from "../../mixins/localize-mixin"; -import NavigateMixin from "../../mixins/navigate-mixin"; - -import "../../layouts/ha-app-layout"; -import "../../components/ha-start-voice-button"; -import "../../components/ha-icon"; -import { loadModule, loadCSS, loadJS } from "../../common/dom/load_resource"; -import { subscribeNotifications } from "../../data/ws-notifications"; -import { computeNotifications } from "./common/compute-notifications"; -import "./components/notifications/hui-notification-drawer"; -import "./components/notifications/hui-notifications-button"; -import "./hui-unused-entities"; -import "./hui-view"; -import debounce from "../../common/util/debounce"; -import createCardElement from "./common/create-card-element"; -import { showEditViewDialog } from "./editor/view-editor/show-edit-view-dialog"; - -// CSS and JS should only be imported once. Modules and HTML are safe. -const CSS_CACHE = {}; -const JS_CACHE = {}; - -class HUIRoot extends NavigateMixin( - EventsMixin(localizeMixin(PolymerElement)) -) { - static get template() { - return html` - - - - - - - - -
- - - - -
-
-
- - `; - } - - static get properties() { - return { - narrow: Boolean, - showMenu: Boolean, - hass: { type: Object, observer: "_hassChanged" }, - config: { - type: Object, - computed: "_computeConfig(lovelace)", - observer: "_configChanged", - }, - lovelace: { type: Object }, - columns: { type: Number, observer: "_columnsChanged" }, - _curView: { type: Number, value: 0 }, - route: { type: Object, observer: "_routeChanged" }, - notificationsOpen: { type: Boolean, value: false }, - _persistentNotifications: { type: Array, value: [] }, - _notifications: { - type: Array, - computed: "_updateNotifications(hass.states, _persistentNotifications)", - }, - _yamlMode: { - type: Boolean, - computed: "_computeYamlMode(lovelace)", - }, - _storageMode: { - type: Boolean, - computed: "_computeStorageMode(lovelace)", - }, - _editMode: { - type: Boolean, - value: false, - computed: "_computeEditMode(lovelace)", - observer: "_editModeChanged", - }, - routeData: Object, - }; - } - - constructor() { - super(); - this._debouncedConfigChanged = debounce( - () => this._selectView(this._curView), - 100 - ); - } - - connectedCallback() { - super.connectedCallback(); - this._unsubNotifications = subscribeNotifications( - this.hass.connection, - (notifications) => { - this._persistentNotifications = notifications; - } - ); - } - - disconnectedCallback() { - super.disconnectedCallback(); - if (typeof this._unsubNotifications === "function") { - this._unsubNotifications(); - } - } - - _updateNotifications(states, persistent) { - if (!states) return persistent; - - const configurator = computeNotifications(states); - return persistent.concat(configurator); - } - - _routeChanged(route) { - const views = this.config && this.config.views; - if (route.path === "" && route.prefix === "/lovelace" && views) { - this.navigate(`/lovelace/${views[0].path || 0}`, true); - } else if (this.routeData.view) { - const view = this.routeData.view; - let index = 0; - for (let i = 0; i < views.length; i++) { - if (views[i].path === view || i === parseInt(view)) { - index = i; - break; - } - } - if (index !== this._curView) this._selectView(index); - } - } - - _computeViewPath(path, index) { - return path || index; - } - - _computeTitle(config) { - return config.title || "Home Assistant"; - } - - _computeTabsHidden(views, editMode) { - return views.length < 2 && !editMode; - } - - _computeTabTitle(title) { - return title || "Unnamed view"; - } - - _handleRefresh() { - this.fire("config-refresh"); - } - - _handleUnusedEntities() { - this._selectView("unused"); - } - - _deselect(ev) { - ev.target.selected = null; - } - - _handleHelp() { - window.open("https://www.home-assistant.io/lovelace/", "_blank"); - } - - _handleFullEditor() { - this.lovelace.enableFullEditMode(); - } - - _editModeEnable() { - if (this._yamlMode) { - window.alert("The edit UI is not available when in YAML mode."); - return; - } - this.lovelace.setEditMode(true); - if (this.config.views.length < 2) { - this.$.view.classList.remove("tabs-hidden"); - this.fire("iron-resize"); - } - } - - _editModeDisable() { - this.lovelace.setEditMode(false); - if (this.config.views.length < 2) { - this.$.view.classList.add("tabs-hidden"); - this.fire("iron-resize"); - } - } - - _editModeChanged() { - this._selectView(this._curView); - } - - _editView() { - showEditViewDialog(this, { - lovelace: this.lovelace, - viewIndex: this._curView, - }); - } - - _addView() { - showEditViewDialog(this, { - lovelace: this.lovelace, - }); - } - - _handleViewSelected(ev) { - const index = ev.detail.selected; - this._navigateView(index); - } - - _navigateView(viewIndex) { - if (viewIndex !== this._curView) { - const path = this.config.views[viewIndex].path || viewIndex; - this.navigate(`/lovelace/${path}`); - } - scrollToTarget(this, this.$.layout.header.scrollTarget); - } - - _selectView(viewIndex) { - this._curView = viewIndex; - - // Recreate a new element to clear the applied themes. - const root = this.$.view; - if (root.lastChild) { - root.removeChild(root.lastChild); - } - - let view; - let background = this.config.background || ""; - - if (viewIndex === "unused") { - view = document.createElement("hui-unused-entities"); - view.setConfig(this.config); - } else { - const viewConfig = this.config.views[this._curView]; - if (!viewConfig) { - this._editModeEnable(); - return; - } - if (viewConfig.panel) { - view = createCardElement(viewConfig.cards[0]); - view.isPanel = true; - } else { - view = document.createElement("hui-view"); - view.lovelace = this.lovelace; - view.config = viewConfig; - view.columns = this.columns; - view.index = viewIndex; - } - if (viewConfig.background) background = viewConfig.background; - } - - this.$.view.style.background = background; - - view.hass = this.hass; - root.appendChild(view); - } - - _hassChanged(hass) { - if (!this.$.view.lastChild) return; - this.$.view.lastChild.hass = hass; - } - - _configChanged(config) { - this._loadResources(config.resources || []); - // On config change, recreate the view from scratch. - this._selectView(this._curView); - this.$.view.classList.toggle("tabs-hidden", config.views.length < 2); - } - - _columnsChanged(columns) { - if (!this.$.view.lastChild) return; - this.$.view.lastChild.columns = columns; - } - - _loadResources(resources) { - resources.forEach((resource) => { - switch (resource.type) { - case "css": - if (resource.url in CSS_CACHE) break; - CSS_CACHE[resource.url] = loadCSS(resource.url); - break; - - case "js": - if (resource.url in JS_CACHE) break; - JS_CACHE[resource.url] = loadJS(resource.url); - break; - - case "module": - loadModule(resource.url); - break; - - case "html": - import(/* webpackChunkName: "import-href-polyfill" */ "../../resources/html-import/import-href").then( - ({ importHref }) => importHref(resource.url) - ); - break; - - default: - // eslint-disable-next-line - console.warn("Unknown resource type specified: ${resource.type}"); - } - }); - } - - _computeConfig(lovelace) { - return lovelace ? lovelace.config : null; - } - - _computeYamlMode(lovelace) { - return lovelace ? lovelace.mode === "yaml" : false; - } - - _computeStorageMode(lovelace) { - return lovelace ? lovelace.mode === "storage" : false; - } - - _computeEditMode(lovelace) { - return lovelace ? lovelace.editMode : false; - } -} -customElements.define("hui-root", HUIRoot); diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts new file mode 100644 index 0000000000..1fb717bfae --- /dev/null +++ b/src/panels/lovelace/hui-root.ts @@ -0,0 +1,583 @@ +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"; +import "@polymer/app-layout/app-toolbar/app-toolbar"; +import "@polymer/app-route/app-route"; +import "@polymer/paper-icon-button/paper-icon-button"; +import "@polymer/paper-button/paper-button"; +import "@polymer/paper-item/paper-item"; +import "@polymer/paper-listbox/paper-listbox"; +import "@polymer/paper-menu-button/paper-menu-button"; +import "@polymer/paper-tabs/paper-tab"; +import "@polymer/paper-tabs/paper-tabs"; + +import scrollToTarget from "../../common/dom/scroll-to-target"; + +import "../../layouts/ha-app-layout"; +import "../../components/ha-start-voice-button"; +import "../../components/ha-icon"; +import { loadModule, loadCSS, loadJS } from "../../common/dom/load_resource"; +import { subscribeNotifications } from "../../data/ws-notifications"; +import { computeNotifications } from "./common/compute-notifications"; +import "./components/notifications/hui-notification-drawer"; +import "./components/notifications/hui-notifications-button"; +import "./hui-unused-entities"; +import "./hui-view"; +import debounce from "../../common/util/debounce"; +import createCardElement from "./common/create-card-element"; +import { showEditViewDialog } from "./editor/view-editor/show-edit-view-dialog"; +import { hassLocalizeLitMixin } from "../../mixins/lit-localize-mixin"; +import { + html, + LitElement, + PropertyDeclarations, + PropertyValues, +} from "@polymer/lit-element"; +import { HomeAssistant } from "../../types"; +import { Lovelace } from "./types"; +import { LovelaceConfig } from "../../data/lovelace"; +import { HassEntities } from "home-assistant-js-websocket"; +import { navigate } from "../../common/navigate"; +import { fireEvent } from "../../common/dom/fire_event"; +import { classMap } from "lit-html/directives/classMap"; + +// CSS and JS should only be imported once. Modules and HTML are safe. +const CSS_CACHE = {}; +const JS_CACHE = {}; + +class HUIRoot extends hassLocalizeLitMixin(LitElement) { + public narrow?: boolean; + public showMenu?: boolean; + public hass?: HomeAssistant; + public lovelace?: Lovelace; + public columns?: number; + public route?: { path: string; prefix: string }; + public routeData?: { view: string }; + private _curView: number; + private notificationsOpen?: boolean; + private _persistentNotifications?: Notification[]; + private _haStyle?: DocumentFragment; + + private _debouncedConfigChanged: () => void; + private _unsubNotifications?: () => void; + + static get properties(): PropertyDeclarations { + return { + narrow: {}, + showMenu: {}, + hass: {}, + lovelace: {}, + columns: {}, + route: {}, + routeData: {}, + _curView: {}, + notificationsOpen: {}, + _persistentNotifications: {}, + }; + } + + constructor() { + super(); + this._curView = 0; + this._debouncedConfigChanged = debounce( + () => this._selectView(this._curView), + 100 + ); + } + + public connectedCallback() { + super.connectedCallback(); + this._unsubNotifications = subscribeNotifications( + this.hass!.connection, + (notifications) => { + this._persistentNotifications = notifications; + } + ); + } + + public disconnectedCallback() { + super.disconnectedCallback(); + if (this._unsubNotifications) { + this._unsubNotifications(); + } + } + + protected render() { + return html` + ${this.renderStyle()} + + + + + ${ + this._editMode + ? html` + + +
+ ${this.localize("ui.panel.lovelace.editor.header")} +
+
+ ` + : html` + + +
${this.config.title || "Home Assistant"}
+ + + + + + ${ + this._yamlMode + ? html` + Refresh + ` + : "" + } + Unused entities + ${ + this.localize("ui.panel.lovelace.editor.configure_ui") + } + ${ + this._storageMode + ? html` + Raw config editor + ` + : "" + } + Help + + +
+ ` + } + + ${ + this.lovelace!.config.views.length > 1 || this._editMode + ? html` +
+ + ${ + this.lovelace!.config.views.map( + (view) => html` + + ${ + view.icon + ? html` + + ` + : view.title || "Unnamed view" + } + ${ + this._editMode + ? html` + + ` + : "" + } + + ` + ) + } + ${ + this._editMode + ? html` + + + + ` + : "" + } + +
+ ` + : "" + } +
+
+ + `; + } + + protected renderStyle() { + 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) { + super.updated(changedProperties); + + const view = this._view; + const huiView = view.lastChild as any; + + if (changedProperties.has("columns") && huiView) { + (this._view.lastChild as any).columns = this.columns; + } + + if (changedProperties.has("hass") && huiView) { + huiView.hass = this.hass; + } + + if (changedProperties.has("route")) { + const views = this.config && this.config.views; + if ( + this.route!.path === "" && + this.route!.prefix === "/lovelace" && + views + ) { + navigate(this, `/lovelace/${views[0].path || 0}`, true); + } else if (this.routeData!.view) { + const selectedView = this.routeData!.view; + const selectedViewInt = parseInt(selectedView, 10); + let index = 0; + for (let i = 0; i < views.length; i++) { + if (views[i].path === selectedView || i === selectedViewInt) { + index = i; + break; + } + } + if (index !== this._curView) { + this._selectView(index); + } + } + } + + if (changedProperties.has("lovelace")) { + const oldLovelace = changedProperties.get("lovelace") as + | Lovelace + | undefined; + + if (!oldLovelace || oldLovelace.config !== this.lovelace!.config) { + this._loadResources(this.lovelace!.config.resources || []); + // On config change, recreate the view from scratch. + this._selectView(this._curView); + } + + if (!oldLovelace || oldLovelace.editMode !== this.lovelace!.editMode) { + this._editModeChanged(); + } + } + } + + private get _notifications() { + return this._updateNotifications( + this.hass!.states, + this._persistentNotifications! || [] + ); + } + + private get config(): LovelaceConfig { + return this.lovelace!.config; + } + + private get _yamlMode() { + return this.lovelace!.mode === "yaml"; + } + + private get _storageMode() { + return this.lovelace!.mode === "storage"; + } + + private get _editMode() { + return this.lovelace!.editMode; + } + + private get _layout(): any { + return this.shadowRoot!.getElementById("layout"); + } + + private get _view(): HTMLDivElement { + return this.shadowRoot!.getElementById("view") as HTMLDivElement; + } + + private _routeDataChanged(ev) { + this.routeData = ev.detail.value; + } + + private _handleNotificationsOpenChanged(ev) { + this.notificationsOpen = ev.detail.value; + } + + private _updateNotifications( + states: HassEntities, + persistent: Array + ) { + const configurator = computeNotifications(states); + return persistent.concat(configurator); + } + + private _handleRefresh() { + fireEvent(this, "config-refresh"); + } + + private _handleUnusedEntities() { + this._selectView("unused"); + } + + private _deselect(ev) { + ev.target.selected = null; + } + + private _handleHelp() { + window.open("https://www.home-assistant.io/lovelace/", "_blank"); + } + + private _editModeEnable() { + if (this._yamlMode) { + window.alert("The edit UI is not available when in YAML mode."); + return; + } + this.lovelace!.setEditMode(true); + if (this.config.views.length < 2) { + fireEvent(this, "iron-resize"); + } + } + + private _editModeDisable() { + this.lovelace!.setEditMode(false); + if (this.config.views.length < 2) { + fireEvent(this, "iron-resize"); + } + } + + private _editModeChanged() { + this._selectView(this._curView); + } + + private _editView() { + showEditViewDialog(this, { + lovelace: this.lovelace!, + viewIndex: this._curView, + }); + } + + private _addView() { + showEditViewDialog(this, { + lovelace: this.lovelace!, + }); + } + + private _handleViewSelected(ev) { + const index = ev.detail.selected; + this._navigateView(index); + } + + private _navigateView(viewIndex) { + if (viewIndex !== this._curView) { + const path = this.config.views[viewIndex].path || viewIndex; + navigate(this, `/lovelace/${path}`); + } + scrollToTarget(this, this._layout.header.scrollTarget); + } + + private _selectView(viewIndex) { + this._curView = viewIndex; + + // Recreate a new element to clear the applied themes. + const root = this._view; + if (root.lastChild) { + root.removeChild(root.lastChild); + } + + let view; + let background = this.config.background || ""; + + if (viewIndex === "unused") { + view = document.createElement("hui-unused-entities"); + view.setConfig(this.config); + } else { + const viewConfig = this.config.views[this._curView]; + if (!viewConfig) { + this._editModeEnable(); + return; + } + if (viewConfig.panel && viewConfig.cards && viewConfig.cards.length > 0) { + view = createCardElement(viewConfig.cards[0]); + view.isPanel = true; + } else { + view = document.createElement("hui-view"); + view.lovelace = this.lovelace; + view.config = viewConfig; + view.columns = this.columns; + view.index = viewIndex; + } + if (viewConfig.background) { + background = viewConfig.background; + } + } + + this._view.style.background = background; + + view.hass = this.hass; + root.appendChild(view); + } + + private _loadResources(resources) { + resources.forEach((resource) => { + switch (resource.type) { + case "css": + if (resource.url in CSS_CACHE) { + break; + } + CSS_CACHE[resource.url] = loadCSS(resource.url); + break; + + case "js": + if (resource.url in JS_CACHE) { + break; + } + JS_CACHE[resource.url] = loadJS(resource.url); + break; + + case "module": + loadModule(resource.url); + break; + + case "html": + import(/* webpackChunkName: "import-href-polyfill" */ "../../resources/html-import/import-href").then( + ({ importHref }) => importHref(resource.url) + ); + break; + + default: + // tslint:disable-next-line + console.warn(`Unknown resource type specified: ${resource.type}`); + } + }); + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-root": HUIRoot; + } +} + +customElements.define("hui-root", HUIRoot); From e2218f1e6e7dd7c403a2a0482b5f5a656c173742 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 11 Dec 2018 17:17:59 +0100 Subject: [PATCH 04/82] Extract component for editing out of hui-view (#2263) --- src/panels/lovelace/hui-view-editable.ts | 3 +++ src/panels/lovelace/hui-view.js | 16 +++++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 src/panels/lovelace/hui-view-editable.ts diff --git a/src/panels/lovelace/hui-view-editable.ts b/src/panels/lovelace/hui-view-editable.ts new file mode 100644 index 0000000000..8740b29f13 --- /dev/null +++ b/src/panels/lovelace/hui-view-editable.ts @@ -0,0 +1,3 @@ +// hui-view dependencies for when in edit mode. +import "@polymer/paper-fab/paper-fab"; +import "./components/hui-card-options"; diff --git a/src/panels/lovelace/hui-view.js b/src/panels/lovelace/hui-view.js index 369dd3fb1c..e068eee53e 100644 --- a/src/panels/lovelace/hui-view.js +++ b/src/panels/lovelace/hui-view.js @@ -1,9 +1,7 @@ import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; -import "@polymer/paper-fab/paper-fab"; import "../../components/entity/ha-state-label-badge"; -import "./components/hui-card-options"; import applyThemesOnElement from "../../common/dom/apply_themes_on_element"; @@ -13,6 +11,8 @@ import createCardElement from "./common/create-card-element"; import { computeCardSize } from "./common/compute-card-size"; import { showEditCardDialog } from "./editor/card-editor/show-edit-card-dialog"; +let editCodeLoaded = false; + class HUIView extends localizeMixin(EventsMixin(PolymerElement)) { static get template() { return html` @@ -97,7 +97,10 @@ class HUIView extends localizeMixin(EventsMixin(PolymerElement)) { type: Object, observer: "_hassChanged", }, - lovelace: Object, + lovelace: { + type: Object, + observer: "_lovelaceChanged", + }, config: Object, columns: Number, editMode: Boolean, @@ -246,6 +249,13 @@ class HUIView extends localizeMixin(EventsMixin(PolymerElement)) { element.hass = hass; }); } + + _lovelaceChanged(lovelace) { + if (lovelace.editMode && !editCodeLoaded) { + editCodeLoaded = true; + import(/* webpackChunkName: "hui-view-editable" */ "./hui-view-editable"); + } + } } customElements.define("hui-view", HUIView); From 76325a384c97ef26285737721fdc853940e8aba1 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Tue, 11 Dec 2018 19:00:57 +0100 Subject: [PATCH 05/82] Update src/panels/lovelace/hui-root.ts Co-Authored-By: balloob --- src/panels/lovelace/hui-root.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts index 1fb717bfae..40aa919423 100644 --- a/src/panels/lovelace/hui-root.ts +++ b/src/panels/lovelace/hui-root.ts @@ -85,7 +85,7 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { ); } - public connectedCallback() { + public connectedCallback(): void { super.connectedCallback(); this._unsubNotifications = subscribeNotifications( this.hass!.connection, From 884b24da0ef3070d4a261ef2f83fdac0b3e7bb76 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Tue, 11 Dec 2018 19:01:32 +0100 Subject: [PATCH 06/82] Update src/panels/lovelace/hui-root.ts Co-Authored-By: balloob --- src/panels/lovelace/hui-root.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts index 40aa919423..a73150685a 100644 --- a/src/panels/lovelace/hui-root.ts +++ b/src/panels/lovelace/hui-root.ts @@ -102,7 +102,7 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { } } - protected render() { + protected render() : TemplateResult { return html` ${this.renderStyle()} Date: Tue, 11 Dec 2018 19:02:18 +0100 Subject: [PATCH 08/82] Update src/panels/lovelace/hui-root.ts Co-Authored-By: balloob --- src/panels/lovelace/hui-root.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts index 162d59acca..39e918de00 100644 --- a/src/panels/lovelace/hui-root.ts +++ b/src/panels/lovelace/hui-root.ts @@ -441,7 +441,7 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { this._selectView("unused"); } - private _deselect(ev) { + private _deselect(ev): void { ev.target.selected = null; } From 5de36f9579b20a4d95ef60f68352f557e03a865b Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Tue, 11 Dec 2018 19:02:32 +0100 Subject: [PATCH 09/82] Update src/panels/lovelace/hui-root.ts Co-Authored-By: balloob --- src/panels/lovelace/hui-root.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts index 39e918de00..de5d324693 100644 --- a/src/panels/lovelace/hui-root.ts +++ b/src/panels/lovelace/hui-root.ts @@ -449,7 +449,7 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { window.open("https://www.home-assistant.io/lovelace/", "_blank"); } - private _editModeEnable() { + private _editModeEnable(): void { if (this._yamlMode) { window.alert("The edit UI is not available when in YAML mode."); return; From a46f5e3d4ee89c2fd14dba4b3098dc6bbe38a5fc Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Tue, 11 Dec 2018 19:02:44 +0100 Subject: [PATCH 10/82] Update src/panels/lovelace/hui-root.ts Co-Authored-By: balloob --- src/panels/lovelace/hui-root.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts index de5d324693..4f6b82416b 100644 --- a/src/panels/lovelace/hui-root.ts +++ b/src/panels/lovelace/hui-root.ts @@ -467,7 +467,7 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { } } - private _editModeChanged() { + private _editModeChanged(): void { this._selectView(this._curView); } From 0a8f853a8e818dcdf89f36636037a01e19028a25 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Tue, 11 Dec 2018 19:03:01 +0100 Subject: [PATCH 11/82] Update src/panels/lovelace/hui-root.ts Co-Authored-By: balloob --- src/panels/lovelace/hui-root.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts index 4f6b82416b..133564f067 100644 --- a/src/panels/lovelace/hui-root.ts +++ b/src/panels/lovelace/hui-root.ts @@ -95,7 +95,7 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { ); } - public disconnectedCallback() { + public disconnectedCallback(): void { super.disconnectedCallback(); if (this._unsubNotifications) { this._unsubNotifications(); From 8be25f2020f10913132f06ddbab294c96f175de0 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Tue, 11 Dec 2018 19:03:33 +0100 Subject: [PATCH 12/82] Update src/panels/lovelace/hui-root.ts Co-Authored-By: balloob --- src/panels/lovelace/hui-root.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts index 133564f067..3db28da469 100644 --- a/src/panels/lovelace/hui-root.ts +++ b/src/panels/lovelace/hui-root.ts @@ -331,7 +331,7 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { `; } - protected updated(changedProperties: PropertyValues) { + protected updated(changedProperties: PropertyValues): void { super.updated(changedProperties); const view = this._view; From 2d1cf421ef437b58c182ec434df433a9c5f2b35b Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Tue, 11 Dec 2018 19:03:48 +0100 Subject: [PATCH 13/82] Update src/panels/lovelace/hui-root.ts Co-Authored-By: balloob --- src/panels/lovelace/hui-root.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts index 3db28da469..c90a943413 100644 --- a/src/panels/lovelace/hui-root.ts +++ b/src/panels/lovelace/hui-root.ts @@ -401,7 +401,7 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { return this.lovelace!.mode === "yaml"; } - private get _storageMode() { + private get _storageMode():string { return this.lovelace!.mode === "storage"; } From 5a5a7dad1ed841d5dc0a238b8b193c282d264eef Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Tue, 11 Dec 2018 19:03:58 +0100 Subject: [PATCH 14/82] Update src/panels/lovelace/hui-root.ts Co-Authored-By: balloob --- src/panels/lovelace/hui-root.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts index c90a943413..5023efa3e1 100644 --- a/src/panels/lovelace/hui-root.ts +++ b/src/panels/lovelace/hui-root.ts @@ -433,7 +433,7 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { return persistent.concat(configurator); } - private _handleRefresh() { + private _handleRefresh(): void { fireEvent(this, "config-refresh"); } From 27bb1756246a299a1c6566c380461b95a0661501 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Tue, 11 Dec 2018 19:05:01 +0100 Subject: [PATCH 15/82] Apply suggestions from code review Co-Authored-By: balloob --- src/panels/lovelace/hui-root.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts index 5023efa3e1..da2fb6d9fe 100644 --- a/src/panels/lovelace/hui-root.ts +++ b/src/panels/lovelace/hui-root.ts @@ -262,7 +262,7 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { `; } - protected renderStyle() { + protected renderStyle(): TemplateResult { if (!this._haStyle) { this._haStyle = document.importNode( (document.getElementById("ha-style")! @@ -421,14 +421,14 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { this.routeData = ev.detail.value; } - private _handleNotificationsOpenChanged(ev) { + private _handleNotificationsOpenChanged(ev): void { this.notificationsOpen = ev.detail.value; } private _updateNotifications( states: HassEntities, persistent: Array - ) { + ): Array { const configurator = computeNotifications(states); return persistent.concat(configurator); } @@ -437,7 +437,7 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { fireEvent(this, "config-refresh"); } - private _handleUnusedEntities() { + private _handleUnusedEntities(): void { this._selectView("unused"); } @@ -445,7 +445,7 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { ev.target.selected = null; } - private _handleHelp() { + private _handleHelp(): void { window.open("https://www.home-assistant.io/lovelace/", "_blank"); } @@ -460,7 +460,7 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { } } - private _editModeDisable() { + private _editModeDisable(): void { this.lovelace!.setEditMode(false); if (this.config.views.length < 2) { fireEvent(this, "iron-resize"); @@ -489,7 +489,7 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { this._navigateView(index); } - private _navigateView(viewIndex) { + private _navigateView(viewIndex: number): void { if (viewIndex !== this._curView) { const path = this.config.views[viewIndex].path || viewIndex; navigate(this, `/lovelace/${path}`); @@ -497,7 +497,7 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { scrollToTarget(this, this._layout.header.scrollTarget); } - private _selectView(viewIndex) { + private _selectView(viewIndex: number): void { this._curView = viewIndex; // Recreate a new element to clear the applied themes. From 4e232e58ce6321a5a82cc10c31b36150ea4ee701 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 11 Dec 2018 19:26:26 +0100 Subject: [PATCH 16/82] Address comments --- src/panels/lovelace/hui-root.ts | 53 +++++++++++++++++---------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts index da2fb6d9fe..a18cbb3dfd 100644 --- a/src/panels/lovelace/hui-root.ts +++ b/src/panels/lovelace/hui-root.ts @@ -1,3 +1,11 @@ +import { + html, + LitElement, + PropertyDeclarations, + PropertyValues, +} from "@polymer/lit-element"; +import { TemplateResult } from "lit-html"; +import { classMap } from "lit-html/directives/classMap"; 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"; @@ -10,6 +18,7 @@ import "@polymer/paper-listbox/paper-listbox"; import "@polymer/paper-menu-button/paper-menu-button"; import "@polymer/paper-tabs/paper-tab"; import "@polymer/paper-tabs/paper-tabs"; +import { HassEntities } from "home-assistant-js-websocket"; import scrollToTarget from "../../common/dom/scroll-to-target"; @@ -18,28 +27,20 @@ import "../../components/ha-start-voice-button"; import "../../components/ha-icon"; import { loadModule, loadCSS, loadJS } from "../../common/dom/load_resource"; import { subscribeNotifications } from "../../data/ws-notifications"; +import debounce from "../../common/util/debounce"; +import { hassLocalizeLitMixin } from "../../mixins/lit-localize-mixin"; +import { HomeAssistant } from "../../types"; +import { LovelaceConfig } from "../../data/lovelace"; +import { navigate } from "../../common/navigate"; +import { fireEvent } from "../../common/dom/fire_event"; import { computeNotifications } from "./common/compute-notifications"; import "./components/notifications/hui-notification-drawer"; import "./components/notifications/hui-notifications-button"; import "./hui-unused-entities"; import "./hui-view"; -import debounce from "../../common/util/debounce"; import createCardElement from "./common/create-card-element"; import { showEditViewDialog } from "./editor/view-editor/show-edit-view-dialog"; -import { hassLocalizeLitMixin } from "../../mixins/lit-localize-mixin"; -import { - html, - LitElement, - PropertyDeclarations, - PropertyValues, -} from "@polymer/lit-element"; -import { HomeAssistant } from "../../types"; import { Lovelace } from "./types"; -import { LovelaceConfig } from "../../data/lovelace"; -import { HassEntities } from "home-assistant-js-websocket"; -import { navigate } from "../../common/navigate"; -import { fireEvent } from "../../common/dom/fire_event"; -import { classMap } from "lit-html/directives/classMap"; // CSS and JS should only be imported once. Modules and HTML are safe. const CSS_CACHE = {}; @@ -52,8 +53,8 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { public lovelace?: Lovelace; public columns?: number; public route?: { path: string; prefix: string }; - public routeData?: { view: string }; - private _curView: number; + private _routeData?: { view: string }; + private _curView: number | "unused"; private notificationsOpen?: boolean; private _persistentNotifications?: Notification[]; private _haStyle?: DocumentFragment; @@ -69,7 +70,7 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { lovelace: {}, columns: {}, route: {}, - routeData: {}, + _routeData: {}, _curView: {}, notificationsOpen: {}, _persistentNotifications: {}, @@ -102,11 +103,11 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { } } - protected render() : TemplateResult { + protected render(): TemplateResult { return html` ${this.renderStyle()} Date: Tue, 11 Dec 2018 19:38:57 +0100 Subject: [PATCH 17/82] Add move card to view (#2262) * Add move card to view * Fix style * Fix style and tests * last style change * update tests --- .../lovelace/components/hui-card-options.ts | 44 ++++++++++- src/panels/lovelace/editor/config-util.ts | 38 +++++++++ .../lovelace/editor/config-util.spec.ts | 79 ++++++++++++++++++- 3 files changed, 159 insertions(+), 2 deletions(-) diff --git a/src/panels/lovelace/components/hui-card-options.ts b/src/panels/lovelace/components/hui-card-options.ts index 53a8ee0ea9..26c0d4b707 100644 --- a/src/panels/lovelace/components/hui-card-options.ts +++ b/src/panels/lovelace/components/hui-card-options.ts @@ -1,6 +1,8 @@ import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; import "@polymer/paper-button/paper-button"; +import "@polymer/paper-menu-button/paper-menu-button"; import "@polymer/paper-icon-button/paper-icon-button"; +import "@polymer/paper-listbox/paper-listbox"; import { showEditCardDialog } from "../editor/card-editor/show-edit-card-dialog"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; @@ -8,7 +10,7 @@ import { confDeleteCard } from "../editor/delete-card"; import { HomeAssistant } from "../../../types"; import { LovelaceCardConfig } from "../../../data/lovelace"; import { Lovelace } from "../types"; -import { swapCard } from "../editor/config-util"; +import { swapCard, moveCard } from "../editor/config-util"; export class HuiCardOptions extends hassLocalizeLitMixin(LitElement) { public cardConfig?: LovelaceCardConfig; @@ -35,10 +37,19 @@ export class HuiCardOptions extends hassLocalizeLitMixin(LitElement) { color: var(--primary-color); font-weight: 500; } + paper-icon-button { + color: var(--primary-text-color); + } paper-icon-button.delete { color: var(--secondary-text-color); float: right; } + paper-item.header { + color: var(--primary-text-color); + text-transform: uppercase; + font-weight: 500; + font-size: 14px; + }
@@ -60,6 +71,29 @@ export class HuiCardOptions extends hassLocalizeLitMixin(LitElement) { this.path![1] + 1 }" > + + + + Move card to view + ${ + this.lovelace!.config.views.map((view, index) => { + if (index === this.path![0]) { + return; + } + return html` + ${view.title} + `; + }) + } + + { + if (fromPath[0] === toPath[0]) { + throw new Error("You can not move a card to the view it is in."); + } + const fromView = config.views[fromPath[0]]; + const card = fromView.cards![fromPath[1]]; + + const newView1 = { + ...fromView, + cards: (fromView.cards || []).filter( + (_origConf, ind) => ind !== fromPath[1] + ), + }; + + const toView = config.views[toPath[0]]; + const cards = toView.cards ? [...toView.cards, card] : [card]; + + const newView2 = { + ...toView, + cards, + }; + + return { + ...config, + views: config.views.map((origView, index) => + index === toPath[0] + ? newView2 + : index === fromPath[0] + ? newView1 + : origView + ), + }; +}; + export const addView = ( config: LovelaceConfig, viewConfig: LovelaceViewConfig diff --git a/test-mocha/panels/lovelace/editor/config-util.spec.ts b/test-mocha/panels/lovelace/editor/config-util.spec.ts index b8a9717b21..dac981de04 100644 --- a/test-mocha/panels/lovelace/editor/config-util.spec.ts +++ b/test-mocha/panels/lovelace/editor/config-util.spec.ts @@ -1,6 +1,9 @@ import * as assert from "assert"; -import { swapCard } from "../../../../src/panels/lovelace/editor/config-util"; +import { + swapCard, + moveCard, +} from "../../../../src/panels/lovelace/editor/config-util"; import { LovelaceConfig } from "../../../../src/data/lovelace"; describe("swapCard", () => { @@ -52,3 +55,77 @@ describe("swapCard", () => { assert.deepEqual(expected, result); }); }); + +describe("moveCard", () => { + it("move a card to an empty view", () => { + const config: LovelaceConfig = { + views: [ + {}, + { + cards: [{ type: "card1" }, { type: "card2" }], + }, + ], + }; + + const result = moveCard(config, [1, 0], [0]); + const expected = { + views: [ + { + cards: [{ type: "card1" }], + }, + { + cards: [{ type: "card2" }], + }, + ], + }; + assert.deepEqual(expected, result); + }); + + it("move a card to different view", () => { + const config: LovelaceConfig = { + views: [ + { + cards: [{ type: "v1-c1" }, { type: "v1-c2" }], + }, + { + cards: [{ type: "v2-c1" }, { type: "v2-c2" }], + }, + ], + }; + + const result = moveCard(config, [1, 0], [0]); + const expected = { + views: [ + { + cards: [{ type: "v1-c1" }, { type: "v1-c2" }, { type: "v2-c1" }], + }, + { + cards: [{ type: "v2-c2" }], + }, + ], + }; + assert.deepEqual(expected, result); + }); + + it("move a card to the same view", () => { + const config: LovelaceConfig = { + views: [ + { + cards: [{ type: "v1-c1" }, { type: "v1-c2" }], + }, + { + cards: [{ type: "v2-c1" }, { type: "v2-c2" }], + }, + ], + }; + + const result = function() { + moveCard(config, [1, 0], [1]); + }; + assert.throws( + result, + Error, + "You can not move a card to the view it is in." + ); + }); +}); From 767307ef4795c5bb67cff3b91ca138fdc3a75b9c Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 11 Dec 2018 19:47:19 +0100 Subject: [PATCH 18/82] Convert hui-view to Lit (#2265) * Convert hui-view to Lit * Add super call to updated * Update src/panels/lovelace/hui-view.ts Co-Authored-By: balloob * Apply suggestions from code review Co-Authored-By: balloob * Address comments" * Fix things --- .../lovelace/components/hui-card-options.ts | 6 +- src/panels/lovelace/hui-root.ts | 7 +- .../lovelace/{hui-view.js => hui-view.ts} | 219 +++++++++++------- .../lovelace/editor/config-util.spec.ts | 2 +- 4 files changed, 140 insertions(+), 94 deletions(-) rename src/panels/lovelace/{hui-view.js => hui-view.ts} (54%) diff --git a/src/panels/lovelace/components/hui-card-options.ts b/src/panels/lovelace/components/hui-card-options.ts index 26c0d4b707..2386fa8d1a 100644 --- a/src/panels/lovelace/components/hui-card-options.ts +++ b/src/panels/lovelace/components/hui-card-options.ts @@ -14,9 +14,9 @@ import { swapCard, moveCard } from "../editor/config-util"; export class HuiCardOptions extends hassLocalizeLitMixin(LitElement) { public cardConfig?: LovelaceCardConfig; - protected hass?: HomeAssistant; - protected lovelace?: Lovelace; - protected path?: [number, number]; + public hass?: HomeAssistant; + public lovelace?: Lovelace; + public path?: [number, number]; static get properties(): PropertyDeclarations { return { hass: {}, lovelace: {}, path: {} }; diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts index a18cbb3dfd..f794001823 100644 --- a/src/panels/lovelace/hui-root.ts +++ b/src/panels/lovelace/hui-root.ts @@ -38,6 +38,9 @@ import "./components/notifications/hui-notification-drawer"; import "./components/notifications/hui-notifications-button"; import "./hui-unused-entities"; import "./hui-view"; +// Not a duplicate import, this one is for type +// tslint:disable-next-line +import { HUIView } from "./hui-view"; import createCardElement from "./common/create-card-element"; import { showEditViewDialog } from "./editor/view-editor/show-edit-view-dialog"; import { Lovelace } from "./types"; @@ -336,10 +339,10 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { super.updated(changedProperties); const view = this._view; - const huiView = view.lastChild as any; + const huiView = view.lastChild as HUIView; if (changedProperties.has("columns") && huiView) { - (this._view.lastChild as any).columns = this.columns; + huiView.columns = this.columns; } if (changedProperties.has("hass") && huiView) { diff --git a/src/panels/lovelace/hui-view.js b/src/panels/lovelace/hui-view.ts similarity index 54% rename from src/panels/lovelace/hui-view.js rename to src/panels/lovelace/hui-view.ts index e068eee53e..52093225a1 100644 --- a/src/panels/lovelace/hui-view.js +++ b/src/panels/lovelace/hui-view.ts @@ -1,20 +1,75 @@ -import { html } from "@polymer/polymer/lib/utils/html-tag"; -import { PolymerElement } from "@polymer/polymer/polymer-element"; +import { + html, + LitElement, + PropertyValues, + PropertyDeclarations, +} from "@polymer/lit-element"; +import { TemplateResult } from "lit-html"; +import { PolymerElement } from "@polymer/polymer"; import "../../components/entity/ha-state-label-badge"; import applyThemesOnElement from "../../common/dom/apply_themes_on_element"; -import EventsMixin from "../../mixins/events-mixin"; -import localizeMixin from "../../mixins/localize-mixin"; +import { hassLocalizeLitMixin } from "../../mixins/lit-localize-mixin"; +import { LovelaceViewConfig } 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"; let editCodeLoaded = false; -class HUIView extends localizeMixin(EventsMixin(PolymerElement)) { - static get template() { +export class HUIView extends hassLocalizeLitMixin(LitElement) { + public hass?: HomeAssistant; + public lovelace?: Lovelace; + public columns?: number; + public index?: number; + private _cards: LovelaceCard[]; + private _badges: Array<{ element: PolymerElement; entityId: string }>; + + static get properties(): PropertyDeclarations { + return { + hass: {}, + lovelace: {}, + columns: {}, + index: {}, + _cards: {}, + _badges: {}, + }; + } + + constructor() { + super(); + this._cards = []; + this._badges = []; + } + + protected render(): TemplateResult { + return html` + ${this.renderStyles()} +
+
+ ${ + this.lovelace!.editMode + ? html` + + ` + : "" + } + `; + } + + protected renderStyles(): TemplateResult { return html` -
-
- `; } - static get properties() { - return { - hass: { - type: Object, - observer: "_hassChanged", - }, - lovelace: { - type: Object, - observer: "_lovelaceChanged", - }, - config: Object, - columns: Number, - editMode: Boolean, - index: Number, - }; + protected updated(changedProperties: PropertyValues): void { + super.updated(changedProperties); + + const lovelace = this.lovelace!; + + if (lovelace.editMode && !editCodeLoaded) { + editCodeLoaded = true; + import(/* webpackChunkName: "hui-view-editable" */ "./hui-view-editable"); + } + + let editModeChanged = false; + let configChanged = false; + + if (changedProperties.has("lovelace")) { + const oldLovelace = changedProperties.get("lovelace") as Lovelace; + editModeChanged = + !oldLovelace || lovelace.editMode !== oldLovelace.editMode; + configChanged = !oldLovelace || lovelace.config !== oldLovelace.config; + } + + if (configChanged) { + this._createBadges(lovelace.config.views[this.index!]); + } else if (changedProperties.has("hass")) { + this._badges.forEach((badge) => { + const { element, entityId } = badge; + element.setProperties({ + hass: this.hass, + state: this.hass!.states[entityId], + }); + }); + } + + if (configChanged || editModeChanged || changedProperties.has("columns")) { + this._createCards(lovelace.config.views[this.index!]); + } else if (changedProperties.has("hass")) { + this._cards.forEach((element) => { + element.hass = this.hass; + }); + } } - static get observers() { - return [ - // Put all properties in 1 observer so we only call configChanged once - "_createBadges(config)", - "_createCards(config, columns, editMode)", - ]; - } - - constructor() { - super(); - this._cards = []; - this._badges = []; - } - - _addCard() { + private _addCard(): void { showEditCardDialog(this, { - lovelace: this.lovelace, - path: [this.index], + lovelace: this.lovelace!, + path: [this.index!], }); } - _createBadges(config) { - const root = this.$.badges; + private _createBadges(config: LovelaceViewConfig): void { + const root = this.shadowRoot!.getElementById("badges")!; + while (root.lastChild) { root.removeChild(root.lastChild); } @@ -141,14 +194,18 @@ class HUIView extends localizeMixin(EventsMixin(PolymerElement)) { return; } - const elements = []; + const elements: HUIView["_badges"] = []; for (const entityId of config.badges) { - if (!(entityId in this.hass.states)) continue; + if (!(entityId in this.hass!.states)) { + continue; + } - const element = document.createElement("ha-state-label-badge"); + const element = document.createElement( + "ha-state-label-badge" + ) as PolymerElement; element.setProperties({ hass: this.hass, - state: this.hass.states[entityId], + state: this.hass!.states[entityId], }); elements.push({ element, entityId }); root.appendChild(element); @@ -157,8 +214,8 @@ class HUIView extends localizeMixin(EventsMixin(PolymerElement)) { root.style.display = elements.length > 0 ? "block" : "none"; } - _createCards(config) { - const root = this.$.columns; + private _createCards(config: LovelaceViewConfig): void { + const root = this.shadowRoot!.getElementById("columns")!; while (root.lastChild) { root.removeChild(root.lastChild); @@ -169,14 +226,14 @@ class HUIView extends localizeMixin(EventsMixin(PolymerElement)) { return; } - const elements = []; - const elementsToAppend = []; + const elements: LovelaceCard[] = []; + const elementsToAppend: HTMLElement[] = []; config.cards.forEach((cardConfig, cardIndex) => { - const element = createCardElement(cardConfig); + const element = createCardElement(cardConfig) as LovelaceCard; element.hass = this.hass; elements.push(element); - if (!this.lovelace.editMode) { + if (!this.lovelace!.editMode) { elementsToAppend.push(element); return; } @@ -184,14 +241,14 @@ class HUIView extends localizeMixin(EventsMixin(PolymerElement)) { const wrapper = document.createElement("hui-card-options"); wrapper.hass = this.hass; wrapper.lovelace = this.lovelace; - wrapper.path = [this.index, cardIndex]; + wrapper.path = [this.index!, cardIndex]; wrapper.appendChild(element); elementsToAppend.push(wrapper); }); - let columns = []; - const columnEntityCount = []; - for (let i = 0; i < this.columns; i++) { + let columns: HTMLElement[][] = []; + const columnEntityCount: number[] = []; + for (let i = 0; i < this.columns!; i++) { columns.push([]); columnEntityCount.push(0); } @@ -233,29 +290,15 @@ class HUIView extends localizeMixin(EventsMixin(PolymerElement)) { this._cards = elements; if ("theme" in config) { - applyThemesOnElement(root, this.hass.themes, config.theme); - } - } - - _hassChanged(hass) { - this._badges.forEach((badge) => { - const { element, entityId } = badge; - element.setProperties({ - hass, - state: hass.states[entityId], - }); - }); - this._cards.forEach((element) => { - element.hass = hass; - }); - } - - _lovelaceChanged(lovelace) { - if (lovelace.editMode && !editCodeLoaded) { - editCodeLoaded = true; - import(/* webpackChunkName: "hui-view-editable" */ "./hui-view-editable"); + applyThemesOnElement(root, this.hass!.themes, config.theme); } } } +declare global { + interface HTMLElementTagNameMap { + "hui-view": HUIView; + } +} + customElements.define("hui-view", HUIView); diff --git a/test-mocha/panels/lovelace/editor/config-util.spec.ts b/test-mocha/panels/lovelace/editor/config-util.spec.ts index dac981de04..fc417e2ca1 100644 --- a/test-mocha/panels/lovelace/editor/config-util.spec.ts +++ b/test-mocha/panels/lovelace/editor/config-util.spec.ts @@ -119,7 +119,7 @@ describe("moveCard", () => { ], }; - const result = function() { + const result = () => { moveCard(config, [1, 0], [1]); }; assert.throws( From 8e7d7c51882b54fe2579a49879fef41024225de7 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Tue, 11 Dec 2018 14:15:18 -0600 Subject: [PATCH 19/82] :sparkles: UI Editor for `thermostat` card (#2258) --- .../lovelace/cards/hui-thermostat-card.ts | 13 ++- .../hui-thermostat-card-editor.ts | 106 ++++++++++++++++++ 2 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 src/panels/lovelace/editor/config-elements/hui-thermostat-card-editor.ts diff --git a/src/panels/lovelace/cards/hui-thermostat-card.ts b/src/panels/lovelace/cards/hui-thermostat-card.ts index 91f0cc0766..3afff64e5b 100644 --- a/src/panels/lovelace/cards/hui-thermostat-card.ts +++ b/src/panels/lovelace/cards/hui-thermostat-card.ts @@ -13,7 +13,7 @@ import computeStateName from "../../../common/entity/compute_state_name"; import { hasConfigOrEntityChanged } from "../common/has-changed"; import { HomeAssistant, ClimateEntity } from "../../../types"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; -import { LovelaceCard } from "../types"; +import { LovelaceCard, LovelaceCardEditor } from "../types"; import { LovelaceCardConfig } from "../../../data/lovelace"; import "../../../components/ha-card"; @@ -43,7 +43,7 @@ const modeIcons = { idle: "hass:power-sleep", }; -interface Config extends LovelaceCardConfig { +export interface Config extends LovelaceCardConfig { entity: string; theme?: string; name?: string; @@ -55,6 +55,15 @@ function formatTemp(temps: string[]): string { export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement) implements LovelaceCard { + public static async getConfigElement(): Promise { + await import("../editor/config-elements/hui-thermostat-card-editor"); + return document.createElement("hui-thermostat-card-editor"); + } + + public static getStubConfig(): object { + return { entity: "" }; + } + public hass?: HomeAssistant; private _config?: Config; private _roundSliderStyle?: TemplateResult; 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 new file mode 100644 index 0000000000..f4aee2a515 --- /dev/null +++ b/src/panels/lovelace/editor/config-elements/hui-thermostat-card-editor.ts @@ -0,0 +1,106 @@ +import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; +import { TemplateResult } from "lit-html"; +import { struct } from "../../common/structs/struct"; +import "@polymer/paper-input/paper-input"; + +import { EntitiesEditorEvent, EditorTarget } from "../types"; +import { hassLocalizeLitMixin } from "../../../../mixins/lit-localize-mixin"; +import { HomeAssistant } from "../../../../types"; +import { LovelaceCardEditor } from "../../types"; +import { fireEvent } from "../../../../common/dom/fire_event"; +import { Config } from "../../cards/hui-thermostat-card"; +import { configElementStyle } from "./config-elements-style"; + +import "../../components/hui-theme-select-editor"; +import "../../../../components/entity/ha-entity-picker"; + +const cardConfigStruct = struct({ + type: "string", + entity: "string", + name: "string?", + theme: "string?", +}); + +export class HuiThermostatCardEditor extends hassLocalizeLitMixin(LitElement) + implements LovelaceCardEditor { + public hass?: HomeAssistant; + private _config?: Config; + + public setConfig(config: Config): void { + config = cardConfigStruct(config); + this._config = { type: "thermostat", ...config }; + } + + static get properties(): PropertyDeclarations { + return { hass: {}, _config: {} }; + } + + get _entity(): string { + return this._config!.entity || ""; + } + + get _name(): string { + return this._config!.name || ""; + } + + get _theme(): string { + return this._config!.theme || "default"; + } + + protected render(): TemplateResult { + if (!this.hass) { + return html``; + } + + return html` + ${configElementStyle} +
+ +
+ + +
+
+ `; + } + + private _valueChanged(ev: EntitiesEditorEvent): void { + if (!this._config || !this.hass) { + return; + } + const target = ev.target! as EditorTarget; + + if (this[`_${target.configValue}`] === target.value) { + return; + } + if (target.configValue) { + this._config = { ...this._config, [target.configValue!]: target.value }; + } + fireEvent(this, "config-changed", { config: this._config }); + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-thermostat-card-editor": HuiThermostatCardEditor; + } +} + +customElements.define("hui-thermostat-card-editor", HuiThermostatCardEditor); From 97da26eba71e4fcc77c8eb2aa06bbe39a6f067e4 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Tue, 11 Dec 2018 14:15:29 -0600 Subject: [PATCH 20/82] UI Editor for `alarm-panel` card (#2257) * UI Editor for `alarm-panel` card * Adding of states Can't get the last available state to be recognized as being a selection change * Ability to remove states * Clean up * Clean up * Remove id --- .../lovelace/cards/hui-alarm-panel-card.js | 15 ++ .../hui-alarm-panel-card-editor.ts | 192 ++++++++++++++++++ 2 files changed, 207 insertions(+) create mode 100644 src/panels/lovelace/editor/config-elements/hui-alarm-panel-card-editor.ts diff --git a/src/panels/lovelace/cards/hui-alarm-panel-card.js b/src/panels/lovelace/cards/hui-alarm-panel-card.js index 3d1e858f43..6c7b9679c8 100644 --- a/src/panels/lovelace/cards/hui-alarm-panel-card.js +++ b/src/panels/lovelace/cards/hui-alarm-panel-card.js @@ -21,7 +21,22 @@ const Icons = { triggered: "hass:bell-ring", }; +export const Config = { + name: "", + entity: "", + states: "", +}; + class HuiAlarmPanelCard extends LocalizeMixin(EventsMixin(PolymerElement)) { + static async getConfigElement() { + await import("../editor/config-elements/hui-alarm-panel-card-editor"); + return document.createElement("hui-alarm-panel-card-editor"); + } + + static getStubConfig() { + return { states: ["arm_home", "arm_away"] }; + } + static get template() { return html` + `; + } + + private _stateRemoved(ev: EntitiesEditorEvent): void { + if (!this._config || !this._states || !this.hass) { + return; + } + + const target = ev.target! as EditorTarget; + const index = Number(target.value); + if (index > -1) { + const newStates = this._states; + newStates.splice(index, 1); + this._config = { + ...this._config, + states: newStates, + }; + fireEvent(this, "config-changed", { config: this._config }); + } + } + + private _stateAdded(ev: EntitiesEditorEvent): void { + if (!this._config || !this.hass) { + return; + } + const target = ev.target! as EditorTarget; + if (!target.value || this._states.indexOf(target.value) >= 0) { + return; + } + const newStates = this._states; + newStates.push(target.value); + this._config = { + ...this._config, + states: newStates, + }; + target.value = ""; + fireEvent(this, "config-changed", { config: this._config }); + } + + private _valueChanged(ev: EntitiesEditorEvent): void { + if (!this._config || !this.hass) { + return; + } + const target = ev.target! as EditorTarget; + if (this[`_${target.configValue}`] === target.value) { + return; + } + if (target.configValue) { + this._config = { + ...this._config, + [target.configValue!]: target.value, + }; + } + fireEvent(this, "config-changed", { config: this._config }); + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-alarm-panel-card-editor": HuiAlarmPanelCardEditor; + } +} + +customElements.define("hui-alarm-panel-card-editor", HuiAlarmPanelCardEditor); From db4c1e45f56282b2381b324386fdc135d394f62a Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Tue, 11 Dec 2018 14:22:08 -0600 Subject: [PATCH 21/82] UI Editor for `gauge` card (#2229) * UI editor for `gauge` card Need to develop a severity input method still * Config works well but no preview showing * Add `sensor` domain filter * Remove `id` --- src/panels/lovelace/cards/hui-gauge-card.ts | 22 +- .../config-elements/hui-gauge-card-editor.ts | 242 ++++++++++++++++++ 2 files changed, 260 insertions(+), 4 deletions(-) create mode 100644 src/panels/lovelace/editor/config-elements/hui-gauge-card-editor.ts diff --git a/src/panels/lovelace/cards/hui-gauge-card.ts b/src/panels/lovelace/cards/hui-gauge-card.ts index 65508b542e..0cbec4bff9 100644 --- a/src/panels/lovelace/cards/hui-gauge-card.ts +++ b/src/panels/lovelace/cards/hui-gauge-card.ts @@ -6,7 +6,7 @@ import { } from "@polymer/lit-element"; import { TemplateResult } from "lit-html"; -import { LovelaceCard } from "../types"; +import { LovelaceCard, LovelaceCardEditor } from "../types"; import { LovelaceCardConfig } from "../../../data/lovelace"; import { HomeAssistant } from "../../../types"; import { fireEvent } from "../../../common/dom/fire_event"; @@ -18,17 +18,23 @@ import computeStateName from "../../../common/entity/compute_state_name"; import "../../../components/ha-card"; -interface Config extends LovelaceCardConfig { +export interface SeverityConfig { + green?: number; + yellow?: number; + red?: number; +} + +export interface Config extends LovelaceCardConfig { entity: string; name?: string; unit?: string; min?: number; max?: number; - severity?: object; + severity?: SeverityConfig; theme?: string; } -const severityMap = { +export const severityMap = { red: "var(--label-badge-red)", green: "var(--label-badge-green)", yellow: "var(--label-badge-yellow)", @@ -36,6 +42,14 @@ const severityMap = { }; class HuiGaugeCard extends LitElement implements LovelaceCard { + public static async getConfigElement(): Promise { + await import("../editor/config-elements/hui-gauge-card-editor"); + return document.createElement("hui-gauge-card-editor"); + } + public static getStubConfig(): object { + return {}; + } + public hass?: HomeAssistant; private _config?: Config; 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 new file mode 100644 index 0000000000..770bd491c7 --- /dev/null +++ b/src/panels/lovelace/editor/config-elements/hui-gauge-card-editor.ts @@ -0,0 +1,242 @@ +import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; +import { TemplateResult } from "lit-html"; +import { struct } from "../../common/structs/struct"; +import "@polymer/paper-input/paper-input"; +import "@polymer/paper-toggle-button/paper-toggle-button"; + +import { EntitiesEditorEvent, EditorTarget } from "../types"; +import { hassLocalizeLitMixin } from "../../../../mixins/lit-localize-mixin"; +import { HomeAssistant } from "../../../../types"; +import { LovelaceCardEditor } from "../../types"; +import { fireEvent } from "../../../../common/dom/fire_event"; +import { Config, SeverityConfig } from "../../cards/hui-gauge-card"; +import { configElementStyle } from "./config-elements-style"; + +import "../../components/hui-theme-select-editor"; +import "../../components/hui-entity-editor"; + +const cardConfigStruct = struct({ + type: "string", + title: "string?", + entity: "string?", + unit: "string?", + min: "number?", + max: "number?", + severity: "object?", + theme: "string?", +}); + +export class HuiGaugeCardEditor extends hassLocalizeLitMixin(LitElement) + implements LovelaceCardEditor { + public hass?: HomeAssistant; + private _config?: Config; + private _useSeverity?: boolean; + + public setConfig(config: Config): void { + config = cardConfigStruct(config); + + this._useSeverity = config.severity ? true : false; + + this._config = { + type: "gauge", + ...config, + }; + } + + static get properties(): PropertyDeclarations { + return { hass: {}, _config: {} }; + } + + get _title(): string { + return this._config!.title || ""; + } + + get _entity(): string { + return this._config!.entity || ""; + } + + get _unit(): string { + return this._config!.unit || ""; + } + + get _theme(): string { + return this._config!.theme || "default"; + } + + get _min(): number { + return this._config!.number || 0; + } + + get _max(): number { + return this._config!.max || 100; + } + + get _severity(): SeverityConfig | undefined { + return this._config!.severity || undefined; + } + + protected render(): TemplateResult { + if (!this.hass) { + return html``; + } + + return html` + ${configElementStyle} ${this.renderStyle()} +
+
+ + +
+
+ + +
+
+ + +
+
+ Define Severity? +
+ + + +
+
+
+ `; + } + + private renderStyle(): TemplateResult { + return html` + + `; + } + + private _toggleSeverity(ev: EntitiesEditorEvent): void { + if (!this._config || !this.hass) { + return; + } + const target = ev.target! as EditorTarget; + + this._config.severity = target.checked + ? { + green: 0, + yellow: 0, + red: 0, + } + : undefined; + fireEvent(this, "config-changed", { config: this._config }); + } + + private _severityChanged(ev: EntitiesEditorEvent): void { + if (!this._config || !this.hass) { + return; + } + const target = ev.target! as EditorTarget; + const severity = { + ...this._config.severity, + [target.configValue!]: Number(target.value), + }; + this._config = { + ...this._config, + severity, + }; + fireEvent(this, "config-changed", { config: this._config }); + } + + private _valueChanged(ev: EntitiesEditorEvent): void { + if (!this._config || !this.hass) { + return; + } + const target = ev.target! as EditorTarget; + + if (target.configValue) { + let value: any = target.value; + if (target.type === "number") { + value = Number(value); + } + this._config = { ...this._config, [target.configValue!]: value }; + } + fireEvent(this, "config-changed", { config: this._config }); + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-gauge-card-editor": HuiGaugeCardEditor; + } +} + +customElements.define("hui-gauge-card-editor", HuiGaugeCardEditor); From 8679f10f100c0c55f582cf58c34b070b91d58722 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Tue, 11 Dec 2018 14:22:21 -0600 Subject: [PATCH 22/82] UI Editor for `light` card (#2232) * UI Editor for `light` card * Remove `id` --- src/panels/lovelace/cards/hui-light-card.ts | 12 +- .../config-elements/hui-light-card-editor.ts | 110 ++++++++++++++++++ 2 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 src/panels/lovelace/editor/config-elements/hui-light-card-editor.ts diff --git a/src/panels/lovelace/cards/hui-light-card.ts b/src/panels/lovelace/cards/hui-light-card.ts index 4dbdbc40c1..aea91b9825 100644 --- a/src/panels/lovelace/cards/hui-light-card.ts +++ b/src/panels/lovelace/cards/hui-light-card.ts @@ -10,7 +10,7 @@ import { fireEvent } from "../../../common/dom/fire_event"; import { styleMap } from "lit-html/directives/styleMap"; import { HomeAssistant, LightEntity } from "../../../types"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; -import { LovelaceCard } from "../types"; +import { LovelaceCard, LovelaceCardEditor } from "../types"; import { LovelaceCardConfig } from "../../../data/lovelace"; import { longPress } from "../common/directives/long-press-directive"; import { hasConfigOrEntityChanged } from "../common/has-changed"; @@ -38,7 +38,7 @@ const lightConfig = { showTooltip: false, }; -interface Config extends LovelaceCardConfig { +export interface Config extends LovelaceCardConfig { entity: string; name?: string; theme?: string; @@ -46,6 +46,14 @@ interface Config extends LovelaceCardConfig { export class HuiLightCard extends hassLocalizeLitMixin(LitElement) implements LovelaceCard { + public static async getConfigElement(): Promise { + await import("../editor/config-elements/hui-light-card-editor"); + return document.createElement("hui-light-card-editor"); + } + public static getStubConfig(): object { + return {}; + } + public hass?: HomeAssistant; private _config?: Config; private _brightnessTimout?: number; 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 new file mode 100644 index 0000000000..df798d2224 --- /dev/null +++ b/src/panels/lovelace/editor/config-elements/hui-light-card-editor.ts @@ -0,0 +1,110 @@ +import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; +import { TemplateResult } from "lit-html"; +import { struct } from "../../common/structs/struct"; +import "@polymer/paper-input/paper-input"; + +import { EntitiesEditorEvent, EditorTarget } from "../types"; +import { hassLocalizeLitMixin } from "../../../../mixins/lit-localize-mixin"; +import { HomeAssistant } from "../../../../types"; +import { LovelaceCardEditor } from "../../types"; +import { fireEvent } from "../../../../common/dom/fire_event"; +import { Config } from "../../cards/hui-light-card"; +import { configElementStyle } from "./config-elements-style"; + +import "../../components/hui-theme-select-editor"; +import "../../components/hui-entity-editor"; + +const cardConfigStruct = struct({ + type: "string", + name: "string?", + entity: "string?", + theme: "string?", +}); + +export class HuiLightCardEditor extends hassLocalizeLitMixin(LitElement) + implements LovelaceCardEditor { + public hass?: HomeAssistant; + private _config?: Config; + + public setConfig(config: Config): void { + config = cardConfigStruct(config); + + this._config = { type: "light", ...config }; + } + + static get properties(): PropertyDeclarations { + return { hass: {}, _config: {}, _configEntities: {} }; + } + + get _name(): string { + return this._config!.name || ""; + } + + get _theme(): string { + return this._config!.theme || "default"; + } + + get _entity(): string { + return this._config!.entity || ""; + } + + protected render(): TemplateResult { + if (!this.hass) { + return html``; + } + + return html` + ${configElementStyle} +
+ +
+ + +
+
+ `; + } + + private _valueChanged(ev: EntitiesEditorEvent): void { + if (!this._config || !this.hass) { + return; + } + const target = ev.target! as EditorTarget; + + if (this[`_${target.configValue}`] === target.value) { + return; + } + if (target.configValue) { + this._config = { + ...this._config, + [target.configValue!]: target.value, + }; + } + fireEvent(this, "config-changed", { config: this._config }); + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-light-card-editor": HuiLightCardEditor; + } +} + +customElements.define("hui-light-card-editor", HuiLightCardEditor); From 88f0ebf75df4a8aeab6d2fb80c7cb9ff12358d28 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Tue, 11 Dec 2018 14:23:10 -0600 Subject: [PATCH 23/82] UI editor for `shopping-list` card (#2227) * Add UI editor for `shopping-list` card * Cleanup * Export config * Remove `id` --- .../lovelace/cards/hui-shopping-list-card.ts | 13 ++- .../hui-shopping-list-editor.ts | 79 +++++++++++++++++++ 2 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 src/panels/lovelace/editor/config-elements/hui-shopping-list-editor.ts diff --git a/src/panels/lovelace/cards/hui-shopping-list-card.ts b/src/panels/lovelace/cards/hui-shopping-list-card.ts index 547386901b..18fa682001 100644 --- a/src/panels/lovelace/cards/hui-shopping-list-card.ts +++ b/src/panels/lovelace/cards/hui-shopping-list-card.ts @@ -9,7 +9,7 @@ import "../../../components/ha-icon"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; import { HomeAssistant } from "../../../types"; -import { LovelaceCard } from "../types"; +import { LovelaceCard, LovelaceCardEditor } from "../types"; import { LovelaceCardConfig } from "../../../data/lovelace"; import { fetchItems, @@ -19,12 +19,20 @@ import { addItem, } from "../../../data/shopping-list"; -interface Config extends LovelaceCardConfig { +export interface Config extends LovelaceCardConfig { title?: string; } class HuiShoppingListCard extends hassLocalizeLitMixin(LitElement) implements LovelaceCard { + public static async getConfigElement(): Promise { + await import("../editor/config-elements/hui-shopping-list-editor"); + return document.createElement("hui-shopping-list-card-editor"); + } + public static getStubConfig(): object { + return {}; + } + public hass?: HomeAssistant; private _config?: Config; private _uncheckedItems?: ShoppingListItem[]; @@ -33,6 +41,7 @@ class HuiShoppingListCard extends hassLocalizeLitMixin(LitElement) static get properties() { return { + hass: {}, _config: {}, _uncheckedItems: {}, _checkedItems: {}, 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 new file mode 100644 index 0000000000..ffdfdc2139 --- /dev/null +++ b/src/panels/lovelace/editor/config-elements/hui-shopping-list-editor.ts @@ -0,0 +1,79 @@ +import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; +import { TemplateResult } from "lit-html"; +import "@polymer/paper-input/paper-input"; + +import { struct } from "../../common/structs/struct"; +import { EntitiesEditorEvent, EditorTarget } from "../types"; +import { hassLocalizeLitMixin } from "../../../../mixins/lit-localize-mixin"; +import { HomeAssistant } from "../../../../types"; +import { LovelaceCardEditor } from "../../types"; +import { fireEvent } from "../../../../common/dom/fire_event"; +import { Config } from "../../cards/hui-shopping-list-card"; + +const cardConfigStruct = struct({ + type: "string", + title: "string?", +}); + +export class HuiShoppingListEditor extends hassLocalizeLitMixin(LitElement) + implements LovelaceCardEditor { + public hass?: HomeAssistant; + private _config?: Config; + + public setConfig(config: Config): void { + config = cardConfigStruct(config); + + this._config = { type: "shopping-list", ...config }; + } + + static get properties(): PropertyDeclarations { + return { hass: {}, _config: {} }; + } + + get _title(): string { + return this._config!.title || ""; + } + + protected render(): TemplateResult { + if (!this.hass) { + return html``; + } + + return html` +
+ +
+ `; + } + + private _valueChanged(ev: EntitiesEditorEvent): void { + if (!this._config || !this.hass) { + return; + } + const target = ev.target! as EditorTarget; + + if (this[`_${target.configValue}`] === target.value) { + return; + } + if (target.configValue) { + this._config = { + ...this._config, + [target.configValue!]: target.value, + }; + } + fireEvent(this, "config-changed", { config: this._config }); + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-shopping-list-card-editor": HuiShoppingListEditor; + } +} + +customElements.define("hui-shopping-list-card-editor", HuiShoppingListEditor); From 80dd15306e930d9943d4139edda2e4b333ea14e7 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 11 Dec 2018 21:23:19 +0100 Subject: [PATCH 24/82] Convert ha-label-badge to lit (#2266) * Convert ha-label-badge to lit * Add class to TypeScript map --- .../{ha-label-badge.js => ha-label-badge.ts} | 155 +++++++++++------- 1 file changed, 92 insertions(+), 63 deletions(-) rename src/components/{ha-label-badge.js => ha-label-badge.ts} (58%) diff --git a/src/components/ha-label-badge.js b/src/components/ha-label-badge.ts similarity index 58% rename from src/components/ha-label-badge.js rename to src/components/ha-label-badge.ts index 0aafbd8300..8a33d8eb56 100644 --- a/src/components/ha-label-badge.js +++ b/src/components/ha-label-badge.ts @@ -1,9 +1,83 @@ -import { html } from "@polymer/polymer/lib/utils/html-tag"; -import { PolymerElement } from "@polymer/polymer/polymer-element"; +import { + LitElement, + PropertyDeclarations, + PropertyValues, +} from "@polymer/lit-element"; +import { TemplateResult, html } from "lit-html"; +import { classMap } from "lit-html/directives/classMap"; import "./ha-icon"; -class HaLabelBadge extends PolymerElement { - static get template() { +class HaLabelBadge extends LitElement { + public value?: string; + public icon?: string; + public label?: string; + public description?: string; + public image?: string; + + static get properties(): PropertyDeclarations { + return { + value: {}, + icon: {}, + label: {}, + description: {}, + image: {}, + }; + } + + protected render(): TemplateResult { + return html` + ${this.renderStyle()} +
+
+
+ ${ + this.icon && !this.value && !this.image + ? html` + + ` + : "" + } + ${ + this.value && !this.image + ? html` + ${this.value} + ` + : "" + } +
+ ${ + this.label + ? html` +
+ ${this.label} +
+ ` + : "" + } +
+ ${ + this.description + ? html` +
${this.description}
+ ` + : "" + } +
+ `; + } + + protected renderStyle(): TemplateResult { return html` - -
-
-
- - [[value]] -
-
- [[label]] -
-
-
[[description]]
-
`; } - static get properties() { - return { - value: String, - icon: String, - label: String, - description: String, - - image: { - type: String, - observer: "imageChanged", - }, - }; - } - - computeValueClasses(value) { - return value && value.length > 4 ? "value big" : "value"; - } - - computeLabelClasses(label) { - return label && label.length > 5 ? "label big" : "label"; - } - - computeHideLabel(label) { - return !label || !label.trim(); - } - - computeHideIcon(icon, value, image) { - return !icon || value || image; - } - - computeHideValue(value, image) { - return !value || image; - } - - imageChanged(newVal) { - this.$.badge.style.backgroundImage = newVal ? "url(" + newVal + ")" : ""; + protected updated(changedProperties: PropertyValues): void { + if (changedProperties.has("image")) { + this.shadowRoot!.getElementById("badge")!.style.backgroundImage = this + .image + ? `url(${this.image})` + : ""; + } } } + +declare global { + interface HTMLElementTagNameMap { + "ha-label-badge": HaLabelBadge; + } +} + customElements.define("ha-label-badge", HaLabelBadge); From bd46e3b8e08b3134bf6043e882ed55a96d06bf50 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Tue, 11 Dec 2018 14:39:18 -0600 Subject: [PATCH 25/82] :sparkles: UI Editor for `sensor` card (#2267) --- src/panels/lovelace/cards/hui-sensor-card.ts | 13 +- .../config-elements/hui-sensor-card-editor.ts | 194 ++++++++++++++++++ 2 files changed, 205 insertions(+), 2 deletions(-) create mode 100644 src/panels/lovelace/editor/config-elements/hui-sensor-card-editor.ts diff --git a/src/panels/lovelace/cards/hui-sensor-card.ts b/src/panels/lovelace/cards/hui-sensor-card.ts index 2434527bcb..cde93f3056 100755 --- a/src/panels/lovelace/cards/hui-sensor-card.ts +++ b/src/panels/lovelace/cards/hui-sensor-card.ts @@ -8,7 +8,7 @@ import { import { TemplateResult } from "lit-html"; import "@polymer/paper-spinner/paper-spinner"; -import { LovelaceCard } from "../types"; +import { LovelaceCard, LovelaceCardEditor } from "../types"; import { LovelaceCardConfig } from "../../../data/lovelace"; import { HomeAssistant } from "../../../types"; import { fireEvent } from "../../../common/dom/fire_event"; @@ -133,7 +133,7 @@ const coordinates = ( return calcPoints(history, hours, width, detail, min, max); }; -interface Config extends LovelaceCardConfig { +export interface Config extends LovelaceCardConfig { entity: string; name?: string; icon?: string; @@ -145,6 +145,15 @@ interface Config extends LovelaceCardConfig { } class HuiSensorCard extends LitElement implements LovelaceCard { + public static async getConfigElement(): Promise { + await import("../editor/config-elements/hui-sensor-card-editor"); + return document.createElement("hui-sensor-card-editor"); + } + + public static getStubConfig(): object { + return {}; + } + public hass?: HomeAssistant; private _config?: Config; private _history?: any; 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 new file mode 100644 index 0000000000..8ae1eb5e51 --- /dev/null +++ b/src/panels/lovelace/editor/config-elements/hui-sensor-card-editor.ts @@ -0,0 +1,194 @@ +import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; +import { TemplateResult } from "lit-html"; +import { struct } from "../../common/structs/struct"; +import "@polymer/paper-input/paper-input"; +import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; +import "@polymer/paper-item/paper-item"; +import "@polymer/paper-listbox/paper-listbox"; + +import { EntitiesEditorEvent, EditorTarget } from "../types"; +import { hassLocalizeLitMixin } from "../../../../mixins/lit-localize-mixin"; +import { HomeAssistant } from "../../../../types"; +import { LovelaceCardEditor } from "../../types"; +import { fireEvent } from "../../../../common/dom/fire_event"; +import { Config } from "../../cards/hui-sensor-card"; +import { configElementStyle } from "./config-elements-style"; + +import "../../components/hui-theme-select-editor"; +import "../../../../components/entity/ha-entity-picker"; + +const cardConfigStruct = struct({ + type: "string", + entity: "string?", + name: "string?", + icon: "string?", + graph: "string?", + unit: "string?", + detail: "number?", + theme: "string?", + hours_to_show: "number?", +}); + +export class HuiSensorCardEditor extends hassLocalizeLitMixin(LitElement) + implements LovelaceCardEditor { + public hass?: HomeAssistant; + private _config?: Config; + + public setConfig(config: Config): void { + config = cardConfigStruct(config); + + this._config = { type: "sensor", ...config }; + } + + static get properties(): PropertyDeclarations { + return { hass: {}, _config: {} }; + } + + get _entity(): string { + return this._config!.entity || ""; + } + + get _name(): string { + return this._config!.name || ""; + } + + get _icon(): string { + return this._config!.icon || ""; + } + + get _graph(): string { + return this._config!.graph || "line"; + } + + get _unit(): string { + return this._config!.unit || ""; + } + + get _detail(): number { + return this._config!.number || 1; + } + + get _theme(): string { + return this._config!.theme || "default"; + } + + get _hours_to_show(): number { + return this._config!.hours_to_show || 24; + } + + protected render(): TemplateResult { + if (!this.hass) { + return html``; + } + + const graphs = ["line", "none"]; + + return html` + ${configElementStyle} +
+
+ + +
+
+ + + + ${ + graphs.map((graph) => { + return html` + ${graph} + `; + }) + } + + +
+
+ + +
+
+ + +
+
+ `; + } + + private _valueChanged(ev: EntitiesEditorEvent): void { + if (!this._config || !this.hass) { + return; + } + const target = ev.target! as EditorTarget; + + if (this[`_${target.configValue}`] === target.value) { + return; + } + if (target.configValue) { + let value: any = target.value; + if (target.type === "number") { + value = Number(value); + } + this._config = { + ...this._config, + [target.configValue!]: value, + }; + } + fireEvent(this, "config-changed", { config: this._config }); + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-sensor-card-editor": HuiSensorCardEditor; + } +} + +customElements.define("hui-sensor-card-editor", HuiSensorCardEditor); From 99395360c70a38f56b20afce568f37f38f9bb4fb Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 11 Dec 2018 21:41:38 +0100 Subject: [PATCH 26/82] Convert HA-STATE-LABEL-BADGE to lit (#2268) --- ...label-badge.js => ha-state-label-badge.ts} | 369 +++++++++--------- src/mixins/localize-base-mixin.ts | 2 + .../components/hui-theme-select-editor.ts | 2 +- .../lovelace/editor/hui-dialog-save-config.ts | 2 +- .../editor/view-editor/hui-edit-view.ts | 2 +- src/panels/lovelace/hui-view.ts | 26 +- 6 files changed, 208 insertions(+), 195 deletions(-) rename src/components/entity/{ha-state-label-badge.js => ha-state-label-badge.ts} (60%) diff --git a/src/components/entity/ha-state-label-badge.js b/src/components/entity/ha-state-label-badge.ts similarity index 60% rename from src/components/entity/ha-state-label-badge.js rename to src/components/entity/ha-state-label-badge.ts index bbd6f4dcac..c9308e48e6 100644 --- a/src/components/entity/ha-state-label-badge.js +++ b/src/components/entity/ha-state-label-badge.ts @@ -1,25 +1,206 @@ -import { html } from "@polymer/polymer/lib/utils/html-tag"; -import { PolymerElement } from "@polymer/polymer/polymer-element"; - -import "../ha-label-badge"; +import { + LitElement, + html, + PropertyValues, + PropertyDeclarations, +} from "@polymer/lit-element"; +import { TemplateResult } from "lit-html"; +import { HassEntity } from "home-assistant-js-websocket"; +import { classMap } from "lit-html/directives/classMap"; import computeStateDomain from "../../common/entity/compute_state_domain"; import computeStateName from "../../common/entity/compute_state_name"; import domainIcon from "../../common/entity/domain_icon"; import stateIcon from "../../common/entity/state_icon"; import timerTimeRemaining from "../../common/entity/timer_time_remaining"; -import attributeClassNames from "../../common/entity/attribute_class_names"; import secondsToDuration from "../../common/datetime/seconds_to_duration"; +import { fireEvent } from "../../common/dom/fire_event"; +import { hassLocalizeLitMixin } from "../../mixins/lit-localize-mixin"; -import EventsMixin from "../../mixins/events-mixin"; -import LocalizeMixin from "../../mixins/localize-mixin"; +import "../ha-label-badge"; /* * @appliesMixin LocalizeMixin * @appliesMixin EventsMixin */ -class HaStateLabelBadge extends LocalizeMixin(EventsMixin(PolymerElement)) { - static get template() { +export class HaStateLabelBadge extends hassLocalizeLitMixin(LitElement) { + public state?: HassEntity; + private _connected?: boolean; + private _updateRemaining?: number; + private _timerTimeRemaining?: number; + + public connectedCallback(): void { + super.connectedCallback(); + this._connected = true; + this.startInterval(this.state); + } + + public disconnectedCallback(): void { + super.disconnectedCallback(); + this._connected = false; + this.clearInterval(); + } + + protected render(): TemplateResult { + const state = this.state; + + if (!state) { + return html` + ${this.renderStyle()} + + `; + } + + const domain = computeStateDomain(state); + + return html` + ${this.renderStyle()} + + `; + } + + static get properties(): PropertyDeclarations { + return { + hass: {}, + state: {}, + _timerTimeRemaining: {}, + }; + } + + protected firstUpdated(changedProperties: PropertyValues): void { + super.firstUpdated(changedProperties); + this.addEventListener("click", (ev) => { + ev.stopPropagation(); + fireEvent(this, "hass-more-info", { entityId: this.state!.entity_id }); + }); + } + + protected updated(changedProperties: PropertyValues): void { + super.updated(changedProperties); + + if (this._connected && changedProperties.has("state")) { + this.startInterval(this.state); + } + } + + private _computeValue(domain: string, state: HassEntity) { + switch (domain) { + case "binary_sensor": + case "device_tracker": + case "updater": + case "sun": + case "alarm_control_panel": + case "timer": + return null; + case "sensor": + default: + return state.state === "unknown" + ? "-" + : this.localize(`component.${domain}.state.${state.state}`) || + state.state; + } + } + + private _computeIcon(domain: string, state: HassEntity) { + if (state.state === "unavailable") { + return null; + } + switch (domain) { + case "alarm_control_panel": + if (state.state === "pending") { + return "hass:clock-fast"; + } + if (state.state === "armed_away") { + return "hass:nature"; + } + if (state.state === "armed_home") { + return "hass:home-variant"; + } + if (state.state === "armed_night") { + return "hass:weather-night"; + } + if (state.state === "armed_custom_bypass") { + return "hass:security-home"; + } + if (state.state === "triggered") { + return "hass:alert-circle"; + } + // state == 'disarmed' + return domainIcon(domain, state.state); + case "binary_sensor": + case "device_tracker": + case "updater": + return stateIcon(state); + case "sun": + return state.state === "above_horizon" + ? domainIcon(domain) + : "hass:brightness-3"; + case "timer": + return state.state === "active" ? "hass:timer" : "hass:timer-off"; + default: + return null; + } + } + + private _computeLabel(domain, state, _timerTimeRemaining) { + if ( + state.state === "unavailable" || + ["device_tracker", "alarm_control_panel"].includes(domain) + ) { + // Localize the state with a special state_badge namespace, which has variations of + // the state translations that are truncated to fit within the badge label. Translations + // are only added for device_tracker and alarm_control_panel. + return ( + this.localize(`state_badge.${domain}.${state.state}`) || + this.localize(`state_badge.default.${state.state}`) || + state.state + ); + } + if (domain === "timer") { + return secondsToDuration(_timerTimeRemaining); + } + return state.attributes.unit_of_measurement || null; + } + + private clearInterval() { + if (this._updateRemaining) { + clearInterval(this._updateRemaining); + this._updateRemaining = undefined; + } + } + + private startInterval(stateObj) { + this.clearInterval(); + if (computeStateDomain(stateObj) === "timer") { + this.calculateTimerRemaining(stateObj); + + if (stateObj.state === "active") { + this._updateRemaining = window.setInterval( + () => this.calculateTimerRemaining(this.state), + 1000 + ); + } + } + } + + private calculateTimerRemaining(stateObj) { + this._timerTimeRemaining = timerTimeRemaining(stateObj); + } + + private renderStyle(): TemplateResult { return html` - - `; } +} - static get properties() { - return { - hass: Object, - state: { - type: Object, - observer: "stateChanged", - }, - _timerTimeRemaining: { - type: Number, - value: 0, - }, - }; - } - - connectedCallback() { - super.connectedCallback(); - this.startInterval(this.state); - } - - disconnectedCallback() { - super.disconnectedCallback(); - this.clearInterval(); - } - - ready() { - super.ready(); - this.addEventListener("click", (ev) => this.badgeTap(ev)); - } - - badgeTap(ev) { - ev.stopPropagation(); - this.fire("hass-more-info", { entityId: this.state.entity_id }); - } - - computeClassNames(state) { - const classes = [computeStateDomain(state)]; - classes.push(attributeClassNames(state, ["unit_of_measurement"])); - return classes.join(" "); - } - - computeValue(localize, state) { - const domain = computeStateDomain(state); - switch (domain) { - case "binary_sensor": - case "device_tracker": - case "updater": - case "sun": - case "alarm_control_panel": - case "timer": - return null; - case "sensor": - default: - return state.state === "unknown" - ? "-" - : localize(`component.${domain}.state.${state.state}`) || state.state; - } - } - - computeIcon(state) { - if (state.state === "unavailable") { - return null; - } - const domain = computeStateDomain(state); - switch (domain) { - case "alarm_control_panel": - if (state.state === "pending") { - return "hass:clock-fast"; - } - if (state.state === "armed_away") { - return "hass:nature"; - } - if (state.state === "armed_home") { - return "hass:home-variant"; - } - if (state.state === "armed_night") { - return "hass:weather-night"; - } - if (state.state === "armed_custom_bypass") { - return "hass:security-home"; - } - if (state.state === "triggered") { - return "hass:alert-circle"; - } - // state == 'disarmed' - return domainIcon(domain, state.state); - case "binary_sensor": - case "device_tracker": - case "updater": - return stateIcon(state); - case "sun": - return state.state === "above_horizon" - ? domainIcon(domain) - : "hass:brightness-3"; - case "timer": - return state.state === "active" ? "hass:timer" : "hass:timer-off"; - default: - return null; - } - } - - computeImage(state) { - return state.attributes.entity_picture || null; - } - - computeLabel(localize, state, _timerTimeRemaining) { - const domain = computeStateDomain(state); - if ( - state.state === "unavailable" || - ["device_tracker", "alarm_control_panel"].includes(domain) - ) { - // Localize the state with a special state_badge namespace, which has variations of - // the state translations that are truncated to fit within the badge label. Translations - // are only added for device_tracker and alarm_control_panel. - return ( - localize(`state_badge.${domain}.${state.state}`) || - localize(`state_badge.default.${state.state}`) || - state.state - ); - } - if (domain === "timer") { - return secondsToDuration(_timerTimeRemaining); - } - return state.attributes.unit_of_measurement || null; - } - - computeDescription(state) { - return computeStateName(state); - } - - stateChanged(stateObj) { - this.updateStyles(); - this.startInterval(stateObj); - } - - clearInterval() { - if (this._updateRemaining) { - clearInterval(this._updateRemaining); - this._updateRemaining = null; - } - } - - startInterval(stateObj) { - this.clearInterval(); - if (computeStateDomain(stateObj) === "timer") { - this.calculateTimerRemaining(stateObj); - - if (stateObj.state === "active") { - this._updateRemaining = setInterval( - () => this.calculateTimerRemaining(this.state), - 1000 - ); - } - } - } - - calculateTimerRemaining(stateObj) { - this._timerTimeRemaining = timerTimeRemaining(stateObj); +declare global { + interface HTMLElementTagNameMap { + "ha-state-label-badge": HaStateLabelBadge; } } diff --git a/src/mixins/localize-base-mixin.ts b/src/mixins/localize-base-mixin.ts index f7084902e8..a70821e6be 100644 --- a/src/mixins/localize-base-mixin.ts +++ b/src/mixins/localize-base-mixin.ts @@ -1,4 +1,5 @@ import IntlMessageFormat from "intl-messageformat/src/main"; +import { HomeAssistant } from "../types"; /** * Adapted from Polymer app-localize-behavior. @@ -32,6 +33,7 @@ export interface FormatsType { export type LocalizeFunc = (key: string, ...args: any[]) => string; export interface LocalizeMixin { + hass?: HomeAssistant; localize: LocalizeFunc; } diff --git a/src/panels/lovelace/components/hui-theme-select-editor.ts b/src/panels/lovelace/components/hui-theme-select-editor.ts index 206919b213..68c452c3d2 100644 --- a/src/panels/lovelace/components/hui-theme-select-editor.ts +++ b/src/panels/lovelace/components/hui-theme-select-editor.ts @@ -19,7 +19,7 @@ declare global { export class HuiThemeSelectionEditor extends hassLocalizeLitMixin(LitElement) { public value?: string; - protected hass?: HomeAssistant; + public hass?: HomeAssistant; static get properties(): PropertyDeclarations { return { diff --git a/src/panels/lovelace/editor/hui-dialog-save-config.ts b/src/panels/lovelace/editor/hui-dialog-save-config.ts index 7e00454cfa..295d9ae87c 100644 --- a/src/panels/lovelace/editor/hui-dialog-save-config.ts +++ b/src/panels/lovelace/editor/hui-dialog-save-config.ts @@ -14,7 +14,7 @@ import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; import { SaveDialogParams } from "./show-save-config-dialog"; export class HuiSaveConfig extends hassLocalizeLitMixin(LitElement) { - protected hass?: HomeAssistant; + public hass?: HomeAssistant; private _params?: SaveDialogParams; private _saving: boolean; 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 733ec46a39..8b27068812 100644 --- a/src/panels/lovelace/editor/view-editor/hui-edit-view.ts +++ b/src/panels/lovelace/editor/view-editor/hui-edit-view.ts @@ -30,7 +30,7 @@ import { deleteView, addView, replaceView } from "../config-util"; export class HuiEditView extends hassLocalizeLitMixin(LitElement) { public lovelace?: Lovelace; public viewIndex?: number; - protected hass?: HomeAssistant; + public hass?: HomeAssistant; private _config?: LovelaceViewConfig; private _badges?: EntityConfig[]; private _cards?: LovelaceCardConfig[]; diff --git a/src/panels/lovelace/hui-view.ts b/src/panels/lovelace/hui-view.ts index 52093225a1..8fc3cd6d01 100644 --- a/src/panels/lovelace/hui-view.ts +++ b/src/panels/lovelace/hui-view.ts @@ -5,9 +5,11 @@ import { PropertyDeclarations, } from "@polymer/lit-element"; import { TemplateResult } from "lit-html"; -import { PolymerElement } from "@polymer/polymer"; import "../../components/entity/ha-state-label-badge"; +// This one is for types +// tslint:disable-next-line +import { HaStateLabelBadge } from "../../components/entity/ha-state-label-badge"; import applyThemesOnElement from "../../common/dom/apply_themes_on_element"; @@ -28,7 +30,7 @@ export class HUIView extends hassLocalizeLitMixin(LitElement) { public columns?: number; public index?: number; private _cards: LovelaceCard[]; - private _badges: Array<{ element: PolymerElement; entityId: string }>; + private _badges: Array<{ element: HaStateLabelBadge; entityId: string }>; static get properties(): PropertyDeclarations { return { @@ -158,10 +160,8 @@ export class HUIView extends hassLocalizeLitMixin(LitElement) { } else if (changedProperties.has("hass")) { this._badges.forEach((badge) => { const { element, entityId } = badge; - element.setProperties({ - hass: this.hass, - state: this.hass!.states[entityId], - }); + element.hass = this.hass!; + element.state = this.hass!.states[entityId]; }); } @@ -196,17 +196,9 @@ export class HUIView extends hassLocalizeLitMixin(LitElement) { const elements: HUIView["_badges"] = []; for (const entityId of config.badges) { - if (!(entityId in this.hass!.states)) { - continue; - } - - const element = document.createElement( - "ha-state-label-badge" - ) as PolymerElement; - element.setProperties({ - hass: this.hass, - state: this.hass!.states[entityId], - }); + const element = document.createElement("ha-state-label-badge"); + element.hass = this.hass; + element.state = this.hass!.states[entityId]; elements.push({ element, entityId }); root.appendChild(element); } From b1b78c2bb7e92a525bf3192488c3fd8097fbbc38 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 11 Dec 2018 21:43:43 +0100 Subject: [PATCH 27/82] Fix stack trace in badge --- src/components/entity/ha-state-label-badge.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/entity/ha-state-label-badge.ts b/src/components/entity/ha-state-label-badge.ts index c9308e48e6..1f17be363c 100644 --- a/src/components/entity/ha-state-label-badge.ts +++ b/src/components/entity/ha-state-label-badge.ts @@ -184,7 +184,7 @@ export class HaStateLabelBadge extends hassLocalizeLitMixin(LitElement) { private startInterval(stateObj) { this.clearInterval(); - if (computeStateDomain(stateObj) === "timer") { + if (stateObj && computeStateDomain(stateObj) === "timer") { this.calculateTimerRemaining(stateObj); if (stateObj.state === "active") { From fe0b1314803e00160b306bb8f065aec0107dce39 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Tue, 11 Dec 2018 17:05:01 -0600 Subject: [PATCH 28/82] :sparkles: UI Editor for `iframe` card (#2230) * UI Editor for `iframe` card * Remove `id` * Address review comments * Cleaned up some inconsistencies --- src/panels/lovelace/cards/hui-iframe-card.ts | 12 +- .../config-elements/hui-iframe-card-editor.ts | 108 ++++++++++++++++++ 2 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 src/panels/lovelace/editor/config-elements/hui-iframe-card-editor.ts diff --git a/src/panels/lovelace/cards/hui-iframe-card.ts b/src/panels/lovelace/cards/hui-iframe-card.ts index 93a643fc53..bc67b4f8d4 100644 --- a/src/panels/lovelace/cards/hui-iframe-card.ts +++ b/src/panels/lovelace/cards/hui-iframe-card.ts @@ -2,18 +2,26 @@ import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; import "../../../components/ha-card"; -import { LovelaceCard } from "../types"; +import { LovelaceCard, LovelaceCardEditor } from "../types"; import { LovelaceCardConfig } from "../../../data/lovelace"; import { TemplateResult } from "lit-html"; import { styleMap } from "lit-html/directives/styleMap"; -interface Config extends LovelaceCardConfig { +export interface Config extends LovelaceCardConfig { aspect_ratio?: string; title?: string; url: string; } export class HuiIframeCard extends LitElement implements LovelaceCard { + public static async getConfigElement(): Promise { + await import("../editor/config-elements/hui-iframe-card-editor"); + return document.createElement("hui-iframe-card-editor"); + } + public static getStubConfig(): object { + return { url: "https://www.home-assistant.io", aspect_ratio: "50%" }; + } + protected _config?: Config; static get properties(): PropertyDeclarations { 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 new file mode 100644 index 0000000000..fe6ba662cc --- /dev/null +++ b/src/panels/lovelace/editor/config-elements/hui-iframe-card-editor.ts @@ -0,0 +1,108 @@ +import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; +import { TemplateResult } from "lit-html"; +import "@polymer/paper-input/paper-input"; + +import { struct } from "../../common/structs/struct"; +import { EntitiesEditorEvent, EditorTarget } from "../types"; +import { hassLocalizeLitMixin } from "../../../../mixins/lit-localize-mixin"; +import { HomeAssistant } from "../../../../types"; +import { LovelaceCardEditor } from "../../types"; +import { fireEvent } from "../../../../common/dom/fire_event"; +import { Config } from "../../cards/hui-iframe-card"; +import { configElementStyle } from "./config-elements-style"; + +const cardConfigStruct = struct({ + type: "string", + title: "string?", + url: "string?", + aspect_ratio: "string?", +}); + +export class HuiIframeCardEditor extends hassLocalizeLitMixin(LitElement) + implements LovelaceCardEditor { + public hass?: HomeAssistant; + private _config?: Config; + + public setConfig(config: Config): void { + config = cardConfigStruct(config); + + this._config = { type: "iframe", ...config }; + } + + static get properties(): PropertyDeclarations { + return { hass: {}, _config: {} }; + } + + get _title(): string { + return this._config!.title || ""; + } + + get _url(): string { + return this._config!.url || ""; + } + + get _aspect_ratio(): string { + return this._config!.aspect_ratio || ""; + } + + protected render(): TemplateResult { + if (!this.hass) { + return html``; + } + + return html` + ${configElementStyle} +
+
+ + +
+ +
+ `; + } + + private _valueChanged(ev: EntitiesEditorEvent): void { + if (!this._config || !this.hass) { + return; + } + const target = ev.target! as EditorTarget; + let value = target.value; + + if (target.configValue! === "aspect_ratio" && target.value) { + value += "%"; + } + + if (this[`_${target.configValue}`] === value) { + return; + } + if (target.configValue) { + this._config = { ...this._config, [target.configValue!]: value }; + } + fireEvent(this, "config-changed", { config: this._config }); + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-iframe-card-editor": HuiIframeCardEditor; + } +} + +customElements.define("hui-iframe-card-editor", HuiIframeCardEditor); From 4a455e91472eb132844b4f782f0f2129f3af378c Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Wed, 12 Dec 2018 01:09:23 -0600 Subject: [PATCH 29/82] :wrench: Organize editor imports (#2272) --- .../editor/config-elements/hui-alarm-panel-card-editor.ts | 2 +- .../editor/config-elements/hui-entities-card-editor.ts | 3 +-- .../lovelace/editor/config-elements/hui-gauge-card-editor.ts | 2 +- .../lovelace/editor/config-elements/hui-glance-card-editor.ts | 2 +- .../lovelace/editor/config-elements/hui-light-card-editor.ts | 2 +- .../editor/config-elements/hui-markdown-card-editor.ts | 2 +- .../lovelace/editor/config-elements/hui-sensor-card-editor.ts | 2 +- .../editor/config-elements/hui-thermostat-card-editor.ts | 2 +- 8 files changed, 8 insertions(+), 9 deletions(-) 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 d4445615f3..9c63abe031 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,10 +1,10 @@ import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; import { TemplateResult } from "lit-html"; -import { struct } from "../../common/structs/struct"; import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; +import { struct } from "../../common/structs/struct"; import { EntitiesEditorEvent, EditorTarget } from "../types"; import { hassLocalizeLitMixin } from "../../../../mixins/lit-localize-mixin"; import { HomeAssistant } from "../../../../types"; 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 233c9e3ba5..9ac6288da0 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,13 +1,12 @@ import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; import { TemplateResult } from "lit-html"; -import { struct } from "../../common/structs/struct"; import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; import "@polymer/paper-toggle-button/paper-toggle-button"; import { processEditorEntities } from "../process-editor-entities"; - +import { struct } from "../../common/structs/struct"; import { EntitiesEditorEvent, EditorTarget } from "../types"; import { hassLocalizeLitMixin } from "../../../../mixins/lit-localize-mixin"; import { HomeAssistant } from "../../../../types"; 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 770bd491c7..74c210d85c 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,9 +1,9 @@ import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; import { TemplateResult } from "lit-html"; -import { struct } from "../../common/structs/struct"; import "@polymer/paper-input/paper-input"; import "@polymer/paper-toggle-button/paper-toggle-button"; +import { struct } from "../../common/structs/struct"; import { EntitiesEditorEvent, EditorTarget } from "../types"; import { hassLocalizeLitMixin } from "../../../../mixins/lit-localize-mixin"; import { HomeAssistant } from "../../../../types"; 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 dadb82f702..59396e01c6 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,11 +1,11 @@ import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; import { TemplateResult } from "lit-html"; -import { struct } from "../../common/structs/struct"; import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; import "@polymer/paper-toggle-button/paper-toggle-button"; +import { struct } from "../../common/structs/struct"; import { processEditorEntities } from "../process-editor-entities"; import { EntitiesEditorEvent, EditorTarget } from "../types"; import { hassLocalizeLitMixin } from "../../../../mixins/lit-localize-mixin"; 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 df798d2224..d1b9fcdb5b 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,8 +1,8 @@ import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; import { TemplateResult } from "lit-html"; -import { struct } from "../../common/structs/struct"; import "@polymer/paper-input/paper-input"; +import { struct } from "../../common/structs/struct"; import { EntitiesEditorEvent, EditorTarget } from "../types"; import { hassLocalizeLitMixin } from "../../../../mixins/lit-localize-mixin"; import { HomeAssistant } from "../../../../types"; 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 3c5a8e37e9..b76eba71a8 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,9 +1,9 @@ import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; import { TemplateResult } from "lit-html"; -import { struct } from "../../common/structs/struct"; import "@polymer/paper-input/paper-input"; import "@polymer/paper-input/paper-textarea"; +import { struct } from "../../common/structs/struct"; import { EntitiesEditorEvent, EditorTarget } from "../types"; import { hassLocalizeLitMixin } from "../../../../mixins/lit-localize-mixin"; import { HomeAssistant } from "../../../../types"; 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 8ae1eb5e51..f4d42849b6 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,11 +1,11 @@ import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; import { TemplateResult } from "lit-html"; -import { struct } from "../../common/structs/struct"; import "@polymer/paper-input/paper-input"; import "@polymer/paper-dropdown-menu/paper-dropdown-menu"; import "@polymer/paper-item/paper-item"; import "@polymer/paper-listbox/paper-listbox"; +import { struct } from "../../common/structs/struct"; import { EntitiesEditorEvent, EditorTarget } from "../types"; import { hassLocalizeLitMixin } from "../../../../mixins/lit-localize-mixin"; import { HomeAssistant } from "../../../../types"; 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 f4aee2a515..17628de20b 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,8 +1,8 @@ import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; import { TemplateResult } from "lit-html"; -import { struct } from "../../common/structs/struct"; import "@polymer/paper-input/paper-input"; +import { struct } from "../../common/structs/struct"; import { EntitiesEditorEvent, EditorTarget } from "../types"; import { hassLocalizeLitMixin } from "../../../../mixins/lit-localize-mixin"; import { HomeAssistant } from "../../../../types"; From 2059e36dd6a506cd0952328f8e5b076272d0517c Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Wed, 12 Dec 2018 01:12:57 -0600 Subject: [PATCH 30/82] :hammer: Update `value` attributes to properties (#2269) --- .../lovelace/cards/hui-shopping-list-card.ts | 4 ++-- .../config-elements/hui-alarm-panel-card-editor.ts | 2 +- .../config-elements/hui-entities-card-editor.ts | 2 +- .../config-elements/hui-gauge-card-editor.ts | 14 +++++++------- .../config-elements/hui-glance-card-editor.ts | 4 ++-- .../config-elements/hui-light-card-editor.ts | 2 +- .../config-elements/hui-markdown-card-editor.ts | 4 ++-- .../config-elements/hui-sensor-card-editor.ts | 10 +++++----- .../config-elements/hui-shopping-list-editor.ts | 2 +- .../config-elements/hui-thermostat-card-editor.ts | 2 +- .../lovelace/editor/view-editor/hui-view-editor.ts | 6 +++--- 11 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/panels/lovelace/cards/hui-shopping-list-card.ts b/src/panels/lovelace/cards/hui-shopping-list-card.ts index 18fa682001..dc28ae5d4d 100644 --- a/src/panels/lovelace/cards/hui-shopping-list-card.ts +++ b/src/panels/lovelace/cards/hui-shopping-list-card.ts @@ -126,7 +126,7 @@ class HuiShoppingListCard extends hassLocalizeLitMixin(LitElement) @@ -177,7 +177,7 @@ class HuiShoppingListCard extends hassLocalizeLitMixin(LitElement) 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 9c63abe031..c2dab9f5a6 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 @@ -63,7 +63,7 @@ export class HuiAlarmPanelCardEditor extends hassLocalizeLitMixin(LitElement)
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 9ac6288da0..d34556ceb7 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 @@ -73,7 +73,7 @@ export class HuiEntitiesCardEditor extends hassLocalizeLitMixin(LitElement)
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 74c210d85c..a613f99449 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 @@ -86,7 +86,7 @@ export class HuiGaugeCardEditor extends hassLocalizeLitMixin(LitElement)
@@ -102,7 +102,7 @@ export class HuiGaugeCardEditor extends hassLocalizeLitMixin(LitElement)
@@ -117,14 +117,14 @@ export class HuiGaugeCardEditor extends hassLocalizeLitMixin(LitElement) @@ -139,21 +139,21 @@ export class HuiGaugeCardEditor extends hassLocalizeLitMixin(LitElement) 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 59396e01c6..a32a0b804a 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 @@ -79,7 +79,7 @@ export class HuiGlanceCardEditor extends hassLocalizeLitMixin(LitElement)
@@ -93,7 +93,7 @@ export class HuiGlanceCardEditor extends hassLocalizeLitMixin(LitElement) 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 d1b9fcdb5b..eb28b522ae 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 @@ -58,7 +58,7 @@ export class HuiLightCardEditor extends hassLocalizeLitMixin(LitElement)
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 b76eba71a8..2a863fb133 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 @@ -51,13 +51,13 @@ export class HuiMarkdownCardEditor extends hassLocalizeLitMixin(LitElement)
@@ -105,7 +105,7 @@ export class HuiSensorCardEditor extends hassLocalizeLitMixin(LitElement)
@@ -131,14 +131,14 @@ export class HuiSensorCardEditor extends hassLocalizeLitMixin(LitElement)
@@ -153,7 +153,7 @@ export class HuiSensorCardEditor extends hassLocalizeLitMixin(LitElement) 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 ffdfdc2139..621181354f 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 @@ -43,7 +43,7 @@ export class HuiShoppingListEditor extends hassLocalizeLitMixin(LitElement)
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 17628de20b..001ad5c1cf 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 @@ -57,7 +57,7 @@ export class HuiThermostatCardEditor extends hassLocalizeLitMixin(LitElement)
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 f9f95d7ad2..e85cbff0d1 100644 --- a/src/panels/lovelace/editor/view-editor/hui-view-editor.ts +++ b/src/panels/lovelace/editor/view-editor/hui-view-editor.ts @@ -69,19 +69,19 @@ export class HuiViewEditor extends hassLocalizeLitMixin(LitElement) {
From 7cd6619a79ded3fc6e67b7c8418ff3c7c4e2c5ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20D=C3=B6tsch?= Date: Wed, 12 Dec 2018 08:27:56 +0100 Subject: [PATCH 31/82] Added some missing translate tags for cards (#2188) * Added some missing translate tags for cards more-info of: - sun - script - updater * Added some missing translate tags for cards * Added some missing translate tags for cards --- src/dialogs/more-info/controls/more-info-script.js | 7 +++++-- src/dialogs/more-info/controls/more-info-sun.js | 9 +++++++-- src/dialogs/more-info/controls/more-info-updater.js | 5 +++-- src/translations/en.json | 13 +++++++++++++ 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/dialogs/more-info/controls/more-info-script.js b/src/dialogs/more-info/controls/more-info-script.js index bc8ef940c0..fec483e033 100644 --- a/src/dialogs/more-info/controls/more-info-script.js +++ b/src/dialogs/more-info/controls/more-info-script.js @@ -1,15 +1,18 @@ 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 LocalizeMixin from "../../../mixins/localize-mixin"; -class MoreInfoScript extends PolymerElement { +class MoreInfoScript extends LocalizeMixin(PolymerElement) { static get template() { return html`
-
Last Action
+
+ [[localize('ui.dialogs.more_info_control.script.last_action')]] +
[[stateObj.attributes.last_action]]
diff --git a/src/dialogs/more-info/controls/more-info-sun.js b/src/dialogs/more-info/controls/more-info-sun.js index dc95d62b3f..d806826f23 100644 --- a/src/dialogs/more-info/controls/more-info-sun.js +++ b/src/dialogs/more-info/controls/more-info-sun.js @@ -28,7 +28,9 @@ class MoreInfoSun extends LocalizeMixin(PolymerElement) {
-
Elevation
+
+ [[localize('ui.dialogs.more_info_control.sun.elevation')]] +
[[stateObj.attributes.elevation]]
`; @@ -63,7 +65,10 @@ class MoreInfoSun extends LocalizeMixin(PolymerElement) { } itemCaption(type) { - return type === "ris" ? "Rising " : "Setting "; + if (type === "ris") { + return this.localize("ui.dialogs.more_info_control.sun.rising"); + } + return this.localize("ui.dialogs.more_info_control.sun.setting"); } itemDate(type) { diff --git a/src/dialogs/more-info/controls/more-info-updater.js b/src/dialogs/more-info/controls/more-info-updater.js index 7bda369170..b3aed3b696 100644 --- a/src/dialogs/more-info/controls/more-info-updater.js +++ b/src/dialogs/more-info/controls/more-info-updater.js @@ -1,7 +1,8 @@ import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; +import LocalizeMixin from "../../../mixins/localize-mixin"; -class MoreInfoUpdater extends PolymerElement { +class MoreInfoUpdater extends LocalizeMixin(PolymerElement) { static get template() { return html` `; } - - private _computeSeverity(stateValue: string, sections: object): string { - const numberValue = Number(stateValue); - - if (!sections) { - return severityMap.normal; - } - - const sectionsArray = Object.keys(sections); - const sortable = sectionsArray.map((severity) => [ - severity, - sections[severity], - ]); - - for (const severity of sortable) { - if (severityMap[severity[0]] == null || isNaN(severity[1])) { - return severityMap.normal; - } - } - sortable.sort((a, b) => a[1] - b[1]); - - if (numberValue >= sortable[0][1] && numberValue < sortable[1][1]) { - return severityMap[sortable[0][0]]; - } - if (numberValue >= sortable[1][1] && numberValue < sortable[2][1]) { - return severityMap[sortable[1][0]]; - } - if (numberValue >= sortable[2][1]) { - return severityMap[sortable[2][0]]; - } - return severityMap.normal; - } - - private _translateTurn(value: number, config: Config): number { - const maxTurnValue = Math.min(Math.max(value, config.min!), config.max!); - return ( - (5 * (maxTurnValue - config.min!)) / (config.max! - config.min!) / 10 - ); - } - - private _computeBaseUnit(): string { - return this.clientWidth < 200 ? this.clientWidth / 5 + "px" : "50px"; - } - - private _handleClick(): void { - fireEvent(this, "hass-more-info", { entityId: this._config!.entity }); - } } declare global { From d2775717357ce984403adedf44bb0a30babb3a63 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 12 Dec 2018 09:47:32 +0100 Subject: [PATCH 34/82] Generalize errors (#2275) --- gallery/src/demos/demo-hui-stack-card.ts | 3 +++ src/panels/lovelace/cards/hui-error-card.ts | 12 +++++++++++ src/panels/lovelace/cards/hui-gauge-card.ts | 13 +++++------- .../lovelace/cards/hui-legacy-wrapper-card.js | 2 +- .../lovelace/cards/hui-picture-entity-card.ts | 20 ++++++++++++++++++- .../lovelace/common/create-card-element.js | 12 +++++------ .../common/create-error-card-config.js | 7 ------- .../lovelace/common/create-hui-element.js | 14 +++++++------ .../lovelace/common/create-row-element.js | 19 +++++++++--------- .../editor/card-editor/hui-card-preview.ts | 2 +- 10 files changed, 65 insertions(+), 39 deletions(-) delete mode 100644 src/panels/lovelace/common/create-error-card-config.js diff --git a/gallery/src/demos/demo-hui-stack-card.ts b/gallery/src/demos/demo-hui-stack-card.ts index 257d753d4a..32c2e862d6 100644 --- a/gallery/src/demos/demo-hui-stack-card.ts +++ b/gallery/src/demos/demo-hui-stack-card.ts @@ -9,6 +9,9 @@ const ENTITIES = [ getEntity("light", "kitchen_lights", "on", { friendly_name: "Kitchen Lights", }), + getEntity("light", "bed_light", "on", { + friendly_name: "Bed Lights", + }), getEntity("device_tracker", "demo_paulus", "work", { source_type: "gps", latitude: 32.877105, diff --git a/src/panels/lovelace/cards/hui-error-card.ts b/src/panels/lovelace/cards/hui-error-card.ts index 4cbcedb3eb..65c7fe0ddf 100644 --- a/src/panels/lovelace/cards/hui-error-card.ts +++ b/src/panels/lovelace/cards/hui-error-card.ts @@ -9,6 +9,18 @@ interface Config extends LovelaceCardConfig { origConfig: LovelaceCardConfig; } +export const createErrorCardElement = (config) => { + const el = document.createElement("hui-error-card"); + el.setConfig(config); + return el; +}; + +export const createErrorCardConfig = (error, origConfig) => ({ + type: "error", + error, + origConfig, +}); + class HuiErrorCard extends LitElement implements LovelaceCard { private _config?: Config; diff --git a/src/panels/lovelace/cards/hui-gauge-card.ts b/src/panels/lovelace/cards/hui-gauge-card.ts index f9dc793bf8..cc7414fb3c 100644 --- a/src/panels/lovelace/cards/hui-gauge-card.ts +++ b/src/panels/lovelace/cards/hui-gauge-card.ts @@ -17,7 +17,10 @@ import applyThemesOnElement from "../../../common/dom/apply_themes_on_element"; import computeStateName from "../../../common/entity/compute_state_name"; import { LovelaceCard, LovelaceCardEditor } from "../types"; -import createErrorCardConfig from "../common/create-error-card-config"; +import { + createErrorCardConfig, + createErrorCardElement, +} from "./hui-error-card"; export interface SeverityConfig { green?: number; @@ -94,14 +97,8 @@ class HuiGaugeCard extends LitElement implements LovelaceCard { } if (error) { - const errorConfig = createErrorCardConfig( - "Entity not Found!", - this._config - ); - const element = document.createElement("hui-error-card"); - element.setConfig(errorConfig); return html` - ${element} + ${createErrorCardElement(createErrorCardConfig(error, this._config))} `; } diff --git a/src/panels/lovelace/cards/hui-legacy-wrapper-card.js b/src/panels/lovelace/cards/hui-legacy-wrapper-card.js index cdd4de0554..c1b36d2e78 100644 --- a/src/panels/lovelace/cards/hui-legacy-wrapper-card.js +++ b/src/panels/lovelace/cards/hui-legacy-wrapper-card.js @@ -1,4 +1,4 @@ -import createErrorCardConfig from "../common/create-error-card-config"; +import { createErrorCardConfig } from "./hui-error-card"; import computeDomain from "../../../common/entity/compute_domain"; export default class LegacyWrapperCard extends HTMLElement { diff --git a/src/panels/lovelace/cards/hui-picture-entity-card.ts b/src/panels/lovelace/cards/hui-picture-entity-card.ts index 81be371ed9..9fa9a2c896 100644 --- a/src/panels/lovelace/cards/hui-picture-entity-card.ts +++ b/src/panels/lovelace/cards/hui-picture-entity-card.ts @@ -16,6 +16,10 @@ import { LovelaceCardConfig, ActionConfig } from "../../../data/lovelace"; import { LovelaceCard } from "../types"; import { handleClick } from "../common/handle-click"; import { UNAVAILABLE } from "../../../data/entity"; +import { + createErrorCardElement, + createErrorCardConfig, +} from "./hui-error-card"; interface Config extends LovelaceCardConfig { entity: string; @@ -62,11 +66,25 @@ class HuiPictureEntityCard extends hassLocalizeLitMixin(LitElement) } protected render(): TemplateResult { - if (!this._config || !this.hass || !this.hass.states[this._config.entity]) { + if (!this._config || !this.hass) { return html``; } const stateObj = this.hass.states[this._config.entity]; + + if (!stateObj) { + return html` + ${ + createErrorCardElement( + createErrorCardConfig( + `Entity not found: ${this._config.entity}`, + this._config + ) + ) + } + `; + } + const name = this._config.name || computeStateName(stateObj); const state = computeStateDisplay( this.localize, diff --git a/src/panels/lovelace/common/create-card-element.js b/src/panels/lovelace/common/create-card-element.js index 60ff05659f..c33bd394eb 100644 --- a/src/panels/lovelace/common/create-card-element.js +++ b/src/panels/lovelace/common/create-card-element.js @@ -5,7 +5,10 @@ import "../cards/hui-conditional-card"; import "../cards/hui-entities-card"; import "../cards/hui-entity-button-card"; import "../cards/hui-entity-filter-card"; -import "../cards/hui-error-card"; +import { + createErrorCardElement, + createErrorCardConfig, +} from "../cards/hui-error-card"; import "../cards/hui-glance-card"; import "../cards/hui-history-graph-card"; import "../cards/hui-horizontal-stack-card"; @@ -26,8 +29,6 @@ import "../cards/hui-thermostat-card"; import "../cards/hui-weather-forecast-card"; import "../cards/hui-gauge-card"; -import createErrorCardConfig from "./create-error-card-config"; - const CARD_TYPES = new Set([ "alarm-panel", "conditional", @@ -71,9 +72,8 @@ function _createElement(tag, config) { return element; } -function _createErrorElement(error, config) { - return _createElement("hui-error-card", createErrorCardConfig(error, config)); -} +const _createErrorElement = (error, config) => + createErrorCardElement(createErrorCardConfig(error, config)); export default function createCardElement(config) { if (!config || typeof config !== "object" || !config.type) { diff --git a/src/panels/lovelace/common/create-error-card-config.js b/src/panels/lovelace/common/create-error-card-config.js deleted file mode 100644 index f8bf388f81..0000000000 --- a/src/panels/lovelace/common/create-error-card-config.js +++ /dev/null @@ -1,7 +0,0 @@ -export default function createErrorConfig(error, origConfig) { - return { - type: "error", - error, - origConfig, - }; -} diff --git a/src/panels/lovelace/common/create-hui-element.js b/src/panels/lovelace/common/create-hui-element.js index c9d10924db..520ca4f3d5 100644 --- a/src/panels/lovelace/common/create-hui-element.js +++ b/src/panels/lovelace/common/create-hui-element.js @@ -6,7 +6,10 @@ import "../elements/hui-state-icon-element"; import "../elements/hui-state-label-element"; import { fireEvent } from "../../../common/dom/fire_event"; -import createErrorCardConfig from "./create-error-card-config"; +import { + createErrorCardElement, + createErrorCardConfig, +} from "../cards/hui-error-card"; const CUSTOM_TYPE_PREFIX = "custom:"; const ELEMENT_TYPES = new Set([ @@ -19,7 +22,7 @@ const ELEMENT_TYPES = new Set([ ]); const TIMEOUT = 2000; -function _createElement(tag, config) { +const _createElement = (tag, config) => { const element = document.createElement(tag); try { element.setConfig(config); @@ -30,11 +33,10 @@ function _createElement(tag, config) { return _createErrorElement(err.message, config); } return element; -} +}; -function _createErrorElement(error, config) { - return _createElement("hui-error-card", createErrorCardConfig(error, config)); -} +const _createErrorElement = (error, config) => + createErrorCardElement(createErrorCardConfig(error, config)); function _hideErrorElement(element) { element.style.display = "None"; diff --git a/src/panels/lovelace/common/create-row-element.js b/src/panels/lovelace/common/create-row-element.js index c9d1fa072c..140e58a3f2 100644 --- a/src/panels/lovelace/common/create-row-element.js +++ b/src/panels/lovelace/common/create-row-element.js @@ -1,5 +1,9 @@ import { fireEvent } from "../../../common/dom/fire_event"; +import { + createErrorCardElement, + createErrorCardConfig, +} from "../cards/hui-error-card"; import "../entity-rows/hui-climate-entity-row"; import "../entity-rows/hui-cover-entity-row"; import "../entity-rows/hui-group-entity-row"; @@ -19,8 +23,6 @@ import "../special-rows/hui-divider-row"; import "../special-rows/hui-section-row"; import "../special-rows/hui-weblink-row"; -import createErrorCardConfig from "./create-error-card-config"; - const CUSTOM_TYPE_PREFIX = "custom:"; const SPECIAL_TYPES = new Set([ "call-service", @@ -51,7 +53,7 @@ const DOMAIN_TO_ELEMENT_TYPE = { }; const TIMEOUT = 2000; -function _createElement(tag, config) { +const _createElement = (tag, config) => { const element = document.createElement(tag); try { if ("setConfig" in element) element.setConfig(config); @@ -63,18 +65,17 @@ function _createElement(tag, config) { } return element; -} +}; -function _createErrorElement(error, config) { - return _createElement("hui-error-card", createErrorCardConfig(error, config)); -} +const _createErrorElement = (error, config) => + createErrorCardElement(createErrorCardConfig(error, config)); -function _hideErrorElement(element) { +const _hideErrorElement = (element) => { element.style.display = "None"; return window.setTimeout(() => { element.style.display = ""; }, TIMEOUT); -} +}; export default function createRowElement(config) { let tag; diff --git a/src/panels/lovelace/editor/card-editor/hui-card-preview.ts b/src/panels/lovelace/editor/card-editor/hui-card-preview.ts index 26552fc705..39c49b2400 100644 --- a/src/panels/lovelace/editor/card-editor/hui-card-preview.ts +++ b/src/panels/lovelace/editor/card-editor/hui-card-preview.ts @@ -1,12 +1,12 @@ import "@polymer/paper-input/paper-textarea"; import createCardElement from "../../common/create-card-element"; -import createErrorCardConfig from "../../common/create-error-card-config"; import { HomeAssistant } from "../../../../types"; import { LovelaceCardConfig } from "../../../../data/lovelace"; import { LovelaceCard } from "../../types"; import { ConfigError } from "../types"; import { getCardElementTag } from "../../common/get-card-element-tag"; +import { createErrorCardConfig } from "../../cards/hui-error-card"; export class HuiCardPreview extends HTMLElement { private _hass?: HomeAssistant; From 8c61624a9c76af5156e614bf047e56b9c513b0bc Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 12 Dec 2018 13:59:19 +0100 Subject: [PATCH 35/82] Change edit mode + add edit lovelace (#2277) * Change edit mode + add edit lovelace * Comments * Fix (yes it was used :-) * Raw edit header changed --- .../lovelace/components/hui-card-options.ts | 2 +- .../hui-dialog-edit-lovelace.ts | 152 ++++++++++++++++++ .../lovelace-editor/hui-lovelace-editor.ts | 80 +++++++++ .../show-edit-lovelace-dialog.ts | 32 ++++ src/panels/lovelace/hui-editor.ts | 4 +- src/panels/lovelace/hui-root.ts | 73 ++++++--- 6 files changed, 321 insertions(+), 22 deletions(-) create mode 100644 src/panels/lovelace/editor/lovelace-editor/hui-dialog-edit-lovelace.ts create mode 100644 src/panels/lovelace/editor/lovelace-editor/hui-lovelace-editor.ts create mode 100644 src/panels/lovelace/editor/lovelace-editor/show-edit-lovelace-dialog.ts diff --git a/src/panels/lovelace/components/hui-card-options.ts b/src/panels/lovelace/components/hui-card-options.ts index 2386fa8d1a..a40acfda49 100644 --- a/src/panels/lovelace/components/hui-card-options.ts +++ b/src/panels/lovelace/components/hui-card-options.ts @@ -87,7 +87,7 @@ export class HuiCardOptions extends hassLocalizeLitMixin(LitElement) { } return html` ${view.title}${view.title || "Unnamed view"} `; }) 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 new file mode 100644 index 0000000000..2cb86b013b --- /dev/null +++ b/src/panels/lovelace/editor/lovelace-editor/hui-dialog-edit-lovelace.ts @@ -0,0 +1,152 @@ +import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; +import { TemplateResult } from "lit-html"; +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. +// tslint:disable-next-line +import { PaperDialogElement } from "@polymer/paper-dialog/paper-dialog"; +import "@polymer/paper-button/paper-button"; +import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable"; +import "./hui-lovelace-editor"; +import { HomeAssistant } from "../../../../types"; +import { LovelaceConfig } from "../../../../data/lovelace"; +import { hassLocalizeLitMixin } from "../../../../mixins/lit-localize-mixin"; +import { Lovelace } from "../../types"; + +export class HuiDialogEditLovelace extends hassLocalizeLitMixin(LitElement) { + public hass?: HomeAssistant; + private _lovelace?: Lovelace; + private _config?: LovelaceConfig; + private _saving: boolean; + + static get properties(): PropertyDeclarations { + return { + hass: {}, + _lovelace: {}, + }; + } + + protected constructor() { + super(); + this._saving = false; + } + + public async showDialog(lovelace: Lovelace): Promise { + this._lovelace = lovelace; + if (this._dialog == null) { + await this.updateComplete; + } + + const { views, ...lovelaceConfig } = this._lovelace!.config; + this._config = lovelaceConfig as LovelaceConfig; + + this._dialog.open(); + } + + private get _dialog(): PaperDialogElement { + return this.shadowRoot!.querySelector("paper-dialog")!; + } + + protected render(): TemplateResult { + return html` + ${this.renderStyle()} + +

Edit Lovelace

+ + +
+ ${this.localize("ui.common.cancel")} + + + ${this.localize("ui.common.save")} +
+
+ `; + } + + private _closeDialog(): void { + this._config = undefined; + this._dialog.close(); + } + + private async _save(): Promise { + if (!this._config) { + return; + } + if (!this._isConfigChanged()) { + this._closeDialog(); + return; + } + + this._saving = true; + const lovelace = this._lovelace!; + + const config: LovelaceConfig = { + ...lovelace.config, + ...this._config, + }; + + try { + await lovelace.saveConfig(config); + this._closeDialog(); + } catch (err) { + alert(`Saving failed: ${err.message}`); + } finally { + this._saving = false; + } + } + + private _ConfigChanged(ev: CustomEvent): void { + if (ev.detail && ev.detail.config) { + this._config = ev.detail.config; + } + } + + private _isConfigChanged(): boolean { + const { views, ...lovelaceConfig } = this._lovelace!.config; + return JSON.stringify(this._config) !== JSON.stringify(lovelaceConfig); + } + + private renderStyle(): TemplateResult { + return html` + + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-dialog-edit-lovelace": HuiDialogEditLovelace; + } +} + +customElements.define("hui-dialog-edit-lovelace", HuiDialogEditLovelace); diff --git a/src/panels/lovelace/editor/lovelace-editor/hui-lovelace-editor.ts b/src/panels/lovelace/editor/lovelace-editor/hui-lovelace-editor.ts new file mode 100644 index 0000000000..68761be409 --- /dev/null +++ b/src/panels/lovelace/editor/lovelace-editor/hui-lovelace-editor.ts @@ -0,0 +1,80 @@ +import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; +import { TemplateResult } from "lit-html"; +import "@polymer/paper-input/paper-input"; + +import { EditorTarget } from "../types"; +import { hassLocalizeLitMixin } from "../../../../mixins/lit-localize-mixin"; +import { HomeAssistant } from "../../../../types"; +import { fireEvent } from "../../../../common/dom/fire_event"; +import { configElementStyle } from "../config-elements/config-elements-style"; + +import { LovelaceConfig } from "../../../../data/lovelace"; + +declare global { + interface HASSDomEvents { + "lovelace-config-changed": { + config: LovelaceConfig; + }; + } +} + +export class HuiLovelaceEditor extends hassLocalizeLitMixin(LitElement) { + static get properties(): PropertyDeclarations { + return { hass: {}, config: {} }; + } + + public hass?: HomeAssistant; + public config?: LovelaceConfig; + + get _title(): string { + if (!this.config) { + return ""; + } + return this.config.title || ""; + } + + protected render(): TemplateResult { + return html` + ${configElementStyle} +
+ +
+ `; + } + + private _valueChanged(ev: Event): void { + if (!this.config) { + return; + } + + const target = ev.currentTarget! as EditorTarget; + + if (this[`_${target.configValue}`] === target.value) { + return; + } + + let newConfig; + + if (target.configValue) { + newConfig = { + ...this.config, + [target.configValue]: target.value, + }; + } + + fireEvent(this, "lovelace-config-changed", { config: newConfig }); + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-lovelace-editor": HuiLovelaceEditor; + } +} + +customElements.define("hui-lovelace-editor", HuiLovelaceEditor); diff --git a/src/panels/lovelace/editor/lovelace-editor/show-edit-lovelace-dialog.ts b/src/panels/lovelace/editor/lovelace-editor/show-edit-lovelace-dialog.ts new file mode 100644 index 0000000000..bc042dfa15 --- /dev/null +++ b/src/panels/lovelace/editor/lovelace-editor/show-edit-lovelace-dialog.ts @@ -0,0 +1,32 @@ +import { fireEvent } from "../../../../common/dom/fire_event"; +import { Lovelace } from "../../types"; + +declare global { + // for fire event + interface HASSDomEvents { + "show-edit-lovelace": Lovelace; + } +} + +let registeredDialog = false; +const dialogShowEvent = "show-edit-lovelace"; +const dialogTag = "hui-dialog-edit-lovelace"; + +const registerEditLovelaceDialog = (element: HTMLElement) => + fireEvent(element, "register-dialog", { + dialogShowEvent, + dialogTag, + dialogImport: () => + import(/* webpackChunkName: "hui-dialog-edit-lovelace" */ "./hui-dialog-edit-lovelace"), + }); + +export const showEditLovelaceDialog = ( + element: HTMLElement, + lovelace: Lovelace +) => { + if (!registeredDialog) { + registeredDialog = true; + registerEditLovelaceDialog(element); + } + fireEvent(element, dialogShowEvent, lovelace); +}; diff --git a/src/panels/lovelace/hui-editor.ts b/src/panels/lovelace/hui-editor.ts index 42b65dbc79..7ebe72d96c 100644 --- a/src/panels/lovelace/hui-editor.ts +++ b/src/panels/lovelace/hui-editor.ts @@ -90,7 +90,9 @@ class LovelaceFullConfigEditor extends hassLocalizeLitMixin(LitElement) { app-header-layout { height: 100vh; } - + app-toolbar { + background-color: #455a64; + } paper-button { font-size: 16px; } diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts index 04621e7e5c..066c9536b6 100644 --- a/src/panels/lovelace/hui-root.ts +++ b/src/panels/lovelace/hui-root.ts @@ -43,6 +43,7 @@ import "./hui-view"; import { HUIView } from "./hui-view"; import createCardElement from "./common/create-card-element"; 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"; @@ -121,18 +122,51 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { .narrow="${this.narrow}" > - + ${ this._editMode ? html` - +
- ${this.localize("ui.panel.lovelace.editor.header")} + ${ + this.config.title || + this.localize("ui.panel.lovelace.editor.header") + } +
+ + + + + Raw config editor + +
` : html` @@ -180,16 +214,6 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { this.localize("ui.panel.lovelace.editor.configure_ui") } - ${ - this._storageMode - ? html` - Raw config editor - ` - : "" - } Help @@ -224,7 +248,7 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { this._editMode ? html` @@ -293,11 +317,20 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { --paper-tabs-selection-bar-color: var(--text-primary-color, #fff); text-transform: uppercase; } - paper-tab.iron-selected .edit-view-icon { + .edit-mode { + background-color: #455a64; + } + .edit-mode div[main-title] { + pointer-events: auto; + } + paper-tab.iron-selected .edit-icon { display: inline-flex; } - .edit-view-icon { + .edit-icon { + color: var(--accent-color); padding-left: 8px; + } + .edit-icon.view { display: none; } #add-view { @@ -412,10 +445,6 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { return this.lovelace!.mode === "yaml"; } - private get _storageMode(): boolean { - return this.lovelace!.mode === "storage"; - } - private get _editMode() { return this.lovelace!.editMode; } @@ -478,6 +507,10 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { } } + private _editLovelace() { + showEditLovelaceDialog(this, this.lovelace!); + } + private _editView() { showEditViewDialog(this, { lovelace: this.lovelace!, From 6a9cfbfa1c017c1994b457efd9a9d8afe01b8d71 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 12 Dec 2018 14:21:34 +0100 Subject: [PATCH 36/82] TS create element functions (#2276) * TS create element functions * Name chunk --- gallery/src/components/demo-card.js | 2 +- src/data/lovelace.ts | 1 + .../lovelace/cards/hui-conditional-card.ts | 2 +- .../lovelace/cards/hui-entities-card.ts | 2 +- .../lovelace/cards/hui-entity-filter-card.js | 2 +- src/panels/lovelace/cards/hui-error-card.ts | 4 +- .../cards/hui-picture-elements-card.ts | 2 +- src/panels/lovelace/cards/hui-stack-card.ts | 2 +- .../common/compute-unused-entities.js | 38 ------------- .../common/compute-unused-entities.ts | 54 +++++++++++++++++++ ...card-element.js => create-card-element.ts} | 27 ++++++---- ...e-hui-element.js => create-hui-element.ts} | 24 ++++++--- ...e-row-element.js => create-row-element.ts} | 26 +++++---- ...{is-valid-object.js => is-valid-object.ts} | 0 .../editor/card-editor/hui-card-preview.ts | 2 +- src/panels/lovelace/entity-rows/types.ts | 2 +- src/panels/lovelace/hui-root.ts | 25 +++++++-- src/panels/lovelace/hui-unused-entities.ts | 14 +++-- src/panels/lovelace/hui-view.ts | 2 +- 19 files changed, 144 insertions(+), 87 deletions(-) delete mode 100644 src/panels/lovelace/common/compute-unused-entities.js create mode 100644 src/panels/lovelace/common/compute-unused-entities.ts rename src/panels/lovelace/common/{create-card-element.js => create-card-element.ts} (82%) rename src/panels/lovelace/common/{create-hui-element.js => create-hui-element.ts} (75%) rename src/panels/lovelace/common/{create-row-element.js => create-row-element.ts} (84%) rename src/panels/lovelace/common/{is-valid-object.js => is-valid-object.ts} (100%) diff --git a/gallery/src/components/demo-card.js b/gallery/src/components/demo-card.js index 703f24c346..e63ad1eecd 100644 --- a/gallery/src/components/demo-card.js +++ b/gallery/src/components/demo-card.js @@ -7,7 +7,7 @@ import { demoConfig } from "../data/demo_config"; import { demoServices } from "../data/demo_services"; import demoResources from "../data/demo_resources"; import demoStates from "../data/demo_states"; -import createCardElement from "../../../src/panels/lovelace/common/create-card-element"; +import { createCardElement } from "../../../src/panels/lovelace/common/create-card-element"; class DemoCard extends PolymerElement { static get template() { diff --git a/src/data/lovelace.ts b/src/data/lovelace.ts index 994227b87c..84edaa0472 100644 --- a/src/data/lovelace.ts +++ b/src/data/lovelace.ts @@ -5,6 +5,7 @@ export interface LovelaceConfig { views: LovelaceViewConfig[]; background?: string; resources?: Array<{ type: "css" | "js" | "module" | "html"; url: string }>; + excluded_entities?: string[]; } export interface LovelaceViewConfig { diff --git a/src/panels/lovelace/cards/hui-conditional-card.ts b/src/panels/lovelace/cards/hui-conditional-card.ts index 0f2e6329cc..51cdb07a3e 100644 --- a/src/panels/lovelace/cards/hui-conditional-card.ts +++ b/src/panels/lovelace/cards/hui-conditional-card.ts @@ -1,4 +1,4 @@ -import createCardElement from "../common/create-card-element"; +import { createCardElement } from "../common/create-card-element"; import { computeCardSize } from "../common/compute-card-size"; import { HomeAssistant } from "../../../types"; import { LovelaceCard } from "../types"; diff --git a/src/panels/lovelace/cards/hui-entities-card.ts b/src/panels/lovelace/cards/hui-entities-card.ts index 188c8a15ae..2e1e2e1dd2 100644 --- a/src/panels/lovelace/cards/hui-entities-card.ts +++ b/src/panels/lovelace/cards/hui-entities-card.ts @@ -17,7 +17,7 @@ import { EntityConfig, EntityRow } from "../entity-rows/types"; import { LovelaceCard, LovelaceCardEditor } from "../types"; import { LovelaceCardConfig } from "../../../data/lovelace"; import { processConfigEntities } from "../common/process-config-entities"; -import createRowElement from "../common/create-row-element"; +import { createRowElement } from "../common/create-row-element"; import computeDomain from "../../../common/entity/compute_domain"; import applyThemesOnElement from "../../../common/dom/apply_themes_on_element"; diff --git a/src/panels/lovelace/cards/hui-entity-filter-card.js b/src/panels/lovelace/cards/hui-entity-filter-card.js index 841dfaa0c5..7b854b9e5b 100644 --- a/src/panels/lovelace/cards/hui-entity-filter-card.js +++ b/src/panels/lovelace/cards/hui-entity-filter-card.js @@ -1,6 +1,6 @@ import { PolymerElement } from "@polymer/polymer/polymer-element"; -import createCardElement from "../common/create-card-element"; +import { createCardElement } from "../common/create-card-element"; import { processConfigEntities } from "../common/process-config-entities"; function getEntities(hass, filterState, entities) { diff --git a/src/panels/lovelace/cards/hui-error-card.ts b/src/panels/lovelace/cards/hui-error-card.ts index 65c7fe0ddf..59981fc7fb 100644 --- a/src/panels/lovelace/cards/hui-error-card.ts +++ b/src/panels/lovelace/cards/hui-error-card.ts @@ -3,6 +3,7 @@ import { html, LitElement } from "@polymer/lit-element"; import { LovelaceCard } from "../types"; import { LovelaceCardConfig } from "../../../data/lovelace"; import { TemplateResult } from "lit-html"; +import { HomeAssistant } from "../../../types"; interface Config extends LovelaceCardConfig { error: string; @@ -21,7 +22,8 @@ export const createErrorCardConfig = (error, origConfig) => ({ origConfig, }); -class HuiErrorCard extends LitElement implements LovelaceCard { +export class HuiErrorCard extends LitElement implements LovelaceCard { + public hass?: HomeAssistant; private _config?: Config; static get properties() { diff --git a/src/panels/lovelace/cards/hui-picture-elements-card.ts b/src/panels/lovelace/cards/hui-picture-elements-card.ts index 072215f318..02f669b612 100644 --- a/src/panels/lovelace/cards/hui-picture-elements-card.ts +++ b/src/panels/lovelace/cards/hui-picture-elements-card.ts @@ -1,7 +1,7 @@ import { html, LitElement } from "@polymer/lit-element"; import { TemplateResult } from "lit-html"; -import createHuiElement from "../common/create-hui-element"; +import { createHuiElement } from "../common/create-hui-element"; import { LovelaceCard } from "../types"; import { LovelaceCardConfig } from "../../../data/lovelace"; diff --git a/src/panels/lovelace/cards/hui-stack-card.ts b/src/panels/lovelace/cards/hui-stack-card.ts index f246ed8c74..d5f13689c7 100644 --- a/src/panels/lovelace/cards/hui-stack-card.ts +++ b/src/panels/lovelace/cards/hui-stack-card.ts @@ -1,7 +1,7 @@ import { html, LitElement } from "@polymer/lit-element"; import { TemplateResult } from "lit-html"; -import createCardElement from "../common/create-card-element"; +import { createCardElement } from "../common/create-card-element"; import { LovelaceCard } from "../types"; import { LovelaceCardConfig } from "../../../data/lovelace"; diff --git a/src/panels/lovelace/common/compute-unused-entities.js b/src/panels/lovelace/common/compute-unused-entities.js deleted file mode 100644 index faaedcc3a7..0000000000 --- a/src/panels/lovelace/common/compute-unused-entities.js +++ /dev/null @@ -1,38 +0,0 @@ -const EXCLUDED_DOMAINS = ["zone"]; - -function computeUsedEntities(config) { - const entities = new Set(); - - function addEntityId(entity) { - if (typeof entity === "string") { - entities.add(entity); - } else if (entity.entity) { - entities.add(entity.entity); - } - } - - function addEntities(obj) { - if (obj.entity) addEntityId(obj.entity); - if (obj.entities) obj.entities.forEach((entity) => addEntityId(entity)); - if (obj.card) addEntities(obj.card); - if (obj.cards) obj.cards.forEach((card) => addEntities(card)); - if (obj.badges) obj.badges.forEach((badge) => addEntityId(badge)); - } - - config.views.forEach((view) => addEntities(view)); - return entities; -} - -export default function computeUnusedEntities(hass, config) { - const usedEntities = computeUsedEntities(config); - return Object.keys(hass.states) - .filter( - (entity) => - !usedEntities.has(entity) && - !( - config.excluded_entities && config.excluded_entities.includes(entity) - ) && - !EXCLUDED_DOMAINS.includes(entity.split(".", 1)[0]) - ) - .sort(); -} diff --git a/src/panels/lovelace/common/compute-unused-entities.ts b/src/panels/lovelace/common/compute-unused-entities.ts new file mode 100644 index 0000000000..0c4fd0c331 --- /dev/null +++ b/src/panels/lovelace/common/compute-unused-entities.ts @@ -0,0 +1,54 @@ +import { LovelaceConfig } from "../../../data/lovelace"; +import { HomeAssistant } from "../../../types"; + +const EXCLUDED_DOMAINS = ["zone"]; + +const computeUsedEntities = (config) => { + const entities = new Set(); + + const addEntityId = (entity) => { + if (typeof entity === "string") { + entities.add(entity); + } else if (entity.entity) { + entities.add(entity.entity); + } + }; + + const addEntities = (obj) => { + if (obj.entity) { + addEntityId(obj.entity); + } + if (obj.entities) { + obj.entities.forEach((entity) => addEntityId(entity)); + } + if (obj.card) { + addEntities(obj.card); + } + if (obj.cards) { + obj.cards.forEach((card) => addEntities(card)); + } + if (obj.badges) { + obj.badges.forEach((badge) => addEntityId(badge)); + } + }; + + config.views.forEach((view) => addEntities(view)); + return entities; +}; + +export const computeUnusedEntities = ( + hass: HomeAssistant, + config: LovelaceConfig +): string[] => { + const usedEntities = computeUsedEntities(config); + return Object.keys(hass.states) + .filter( + (entity) => + !usedEntities.has(entity) && + !( + config.excluded_entities && config.excluded_entities.includes(entity) + ) && + !EXCLUDED_DOMAINS.includes(entity.split(".", 1)[0]) + ) + .sort(); +}; diff --git a/src/panels/lovelace/common/create-card-element.js b/src/panels/lovelace/common/create-card-element.ts similarity index 82% rename from src/panels/lovelace/common/create-card-element.js rename to src/panels/lovelace/common/create-card-element.ts index c33bd394eb..0b7c18a562 100644 --- a/src/panels/lovelace/common/create-card-element.js +++ b/src/panels/lovelace/common/create-card-element.ts @@ -8,6 +8,7 @@ import "../cards/hui-entity-filter-card"; import { createErrorCardElement, createErrorCardConfig, + HuiErrorCard, } from "../cards/hui-error-card"; import "../cards/hui-glance-card"; import "../cards/hui-history-graph-card"; @@ -28,6 +29,8 @@ import "../cards/hui-shopping-list-card"; import "../cards/hui-thermostat-card"; import "../cards/hui-weather-forecast-card"; import "../cards/hui-gauge-card"; +import { LovelaceCard } from "../types"; +import { LovelaceCardConfig } from "../../../data/lovelace"; const CARD_TYPES = new Set([ "alarm-panel", @@ -59,23 +62,29 @@ const CARD_TYPES = new Set([ const CUSTOM_TYPE_PREFIX = "custom:"; const TIMEOUT = 2000; -function _createElement(tag, config) { - const element = document.createElement(tag); +const _createElement = ( + tag: string, + config: LovelaceCardConfig +): LovelaceCard | HuiErrorCard => { + const element = document.createElement(tag) as LovelaceCard; try { element.setConfig(config); } catch (err) { - // eslint-disable-next-line + // tslint:disable-next-line console.error(tag, err); - // eslint-disable-next-line return _createErrorElement(err.message, config); } return element; -} +}; -const _createErrorElement = (error, config) => - createErrorCardElement(createErrorCardConfig(error, config)); +const _createErrorElement = ( + error: string, + config: LovelaceCardConfig +): HuiErrorCard => createErrorCardElement(createErrorCardConfig(error, config)); -export default function createCardElement(config) { +export const createCardElement = ( + config: LovelaceCardConfig +): LovelaceCard | HuiErrorCard => { if (!config || typeof config !== "object" || !config.type) { return _createErrorElement("No card type configured.", config); } @@ -111,4 +120,4 @@ export default function createCardElement(config) { } return _createElement(`hui-${config.type}-card`, config); -} +}; diff --git a/src/panels/lovelace/common/create-hui-element.js b/src/panels/lovelace/common/create-hui-element.ts similarity index 75% rename from src/panels/lovelace/common/create-hui-element.js rename to src/panels/lovelace/common/create-hui-element.ts index 520ca4f3d5..eac2082a3d 100644 --- a/src/panels/lovelace/common/create-hui-element.js +++ b/src/panels/lovelace/common/create-hui-element.ts @@ -9,7 +9,9 @@ import { fireEvent } from "../../../common/dom/fire_event"; import { createErrorCardElement, createErrorCardConfig, + HuiErrorCard, } from "../cards/hui-error-card"; +import { LovelaceElementConfig, LovelaceElement } from "../elements/types"; const CUSTOM_TYPE_PREFIX = "custom:"; const ELEMENT_TYPES = new Set([ @@ -22,21 +24,25 @@ const ELEMENT_TYPES = new Set([ ]); const TIMEOUT = 2000; -const _createElement = (tag, config) => { - const element = document.createElement(tag); +const _createElement = ( + tag: string, + config: LovelaceElementConfig +): LovelaceElement | HuiErrorCard => { + const element = document.createElement(tag) as LovelaceElement; try { element.setConfig(config); } catch (err) { - // eslint-disable-next-line + // tslint:disable-next-line console.error(tag, err); - // eslint-disable-next-line return _createErrorElement(err.message, config); } return element; }; -const _createErrorElement = (error, config) => - createErrorCardElement(createErrorCardConfig(error, config)); +const _createErrorElement = ( + error: string, + config: LovelaceElementConfig +): HuiErrorCard => createErrorCardElement(createErrorCardConfig(error, config)); function _hideErrorElement(element) { element.style.display = "None"; @@ -45,7 +51,9 @@ function _hideErrorElement(element) { }, TIMEOUT); } -export default function createHuiElement(config) { +export const createHuiElement = ( + config: LovelaceElementConfig +): LovelaceElement | HuiErrorCard => { if (!config || typeof config !== "object" || !config.type) { return _createErrorElement("No element type configured.", config); } @@ -78,4 +86,4 @@ export default function createHuiElement(config) { } return _createElement(`hui-${config.type}-element`, config); -} +}; diff --git a/src/panels/lovelace/common/create-row-element.js b/src/panels/lovelace/common/create-row-element.ts similarity index 84% rename from src/panels/lovelace/common/create-row-element.js rename to src/panels/lovelace/common/create-row-element.ts index 140e58a3f2..a2bc40f8d0 100644 --- a/src/panels/lovelace/common/create-row-element.js +++ b/src/panels/lovelace/common/create-row-element.ts @@ -3,6 +3,7 @@ import { fireEvent } from "../../../common/dom/fire_event"; import { createErrorCardElement, createErrorCardConfig, + HuiErrorCard, } from "../cards/hui-error-card"; import "../entity-rows/hui-climate-entity-row"; import "../entity-rows/hui-cover-entity-row"; @@ -22,6 +23,7 @@ import "../special-rows/hui-call-service-row"; import "../special-rows/hui-divider-row"; import "../special-rows/hui-section-row"; import "../special-rows/hui-weblink-row"; +import { EntityConfig, EntityRow } from "../entity-rows/types"; const CUSTOM_TYPE_PREFIX = "custom:"; const SPECIAL_TYPES = new Set([ @@ -53,22 +55,26 @@ const DOMAIN_TO_ELEMENT_TYPE = { }; const TIMEOUT = 2000; -const _createElement = (tag, config) => { - const element = document.createElement(tag); +const _createElement = ( + tag: string, + config: EntityConfig +): EntityRow | HuiErrorCard => { + const element = document.createElement(tag) as EntityRow; try { - if ("setConfig" in element) element.setConfig(config); + element.setConfig(config); } catch (err) { - // eslint-disable-next-line + // tslint:disable-next-line console.error(tag, err); - // eslint-disable-next-line return _createErrorElement(err.message, config); } return element; }; -const _createErrorElement = (error, config) => - createErrorCardElement(createErrorCardConfig(error, config)); +const _createErrorElement = ( + error: string, + config: EntityConfig +): HuiErrorCard => createErrorCardElement(createErrorCardConfig(error, config)); const _hideErrorElement = (element) => { element.style.display = "None"; @@ -77,7 +83,9 @@ const _hideErrorElement = (element) => { }, TIMEOUT); }; -export default function createRowElement(config) { +export const createRowElement = ( + config: EntityConfig +): EntityRow | HuiErrorCard => { let tag; if ( @@ -117,4 +125,4 @@ export default function createRowElement(config) { tag = `hui-${DOMAIN_TO_ELEMENT_TYPE[domain] || "text"}-entity-row`; return _createElement(tag, config); -} +}; diff --git a/src/panels/lovelace/common/is-valid-object.js b/src/panels/lovelace/common/is-valid-object.ts similarity index 100% rename from src/panels/lovelace/common/is-valid-object.js rename to src/panels/lovelace/common/is-valid-object.ts diff --git a/src/panels/lovelace/editor/card-editor/hui-card-preview.ts b/src/panels/lovelace/editor/card-editor/hui-card-preview.ts index 39c49b2400..7f037282df 100644 --- a/src/panels/lovelace/editor/card-editor/hui-card-preview.ts +++ b/src/panels/lovelace/editor/card-editor/hui-card-preview.ts @@ -1,6 +1,6 @@ import "@polymer/paper-input/paper-textarea"; -import createCardElement from "../../common/create-card-element"; +import { createCardElement } from "../../common/create-card-element"; import { HomeAssistant } from "../../../../types"; import { LovelaceCardConfig } from "../../../../data/lovelace"; import { LovelaceCard } from "../../types"; diff --git a/src/panels/lovelace/entity-rows/types.ts b/src/panels/lovelace/entity-rows/types.ts index 88e983bc69..c73cf9ef50 100644 --- a/src/panels/lovelace/entity-rows/types.ts +++ b/src/panels/lovelace/entity-rows/types.ts @@ -29,7 +29,7 @@ export type EntityRowConfig = | WeblinkConfig | CallServiceConfig; -export interface EntityRow { +export interface EntityRow extends HTMLElement { hass?: HomeAssistant; setConfig(config: EntityRowConfig); } diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts index 066c9536b6..b814c049bc 100644 --- a/src/panels/lovelace/hui-root.ts +++ b/src/panels/lovelace/hui-root.ts @@ -36,12 +36,11 @@ import { fireEvent } from "../../common/dom/fire_event"; import { computeNotifications } from "./common/compute-notifications"; import "./components/notifications/hui-notification-drawer"; import "./components/notifications/hui-notifications-button"; -import "./hui-unused-entities"; import "./hui-view"; // Not a duplicate import, this one is for type // tslint:disable-next-line import { HUIView } from "./hui-view"; -import createCardElement from "./common/create-card-element"; +import { createCardElement } from "./common/create-card-element"; import { showEditViewDialog } from "./editor/view-editor/show-edit-view-dialog"; import { showEditLovelaceDialog } from "./editor/lovelace-editor/show-edit-lovelace-dialog"; import { Lovelace } from "./types"; @@ -51,6 +50,15 @@ import { afterNextRender } from "../../common/util/render-status"; const CSS_CACHE = {}; const JS_CACHE = {}; +declare global { + // tslint:disable-next-line + interface HASSDomEvents { + "rebuild-view": {}; + } +} + +let loadedUnusedEntities = false; + class HUIRoot extends hassLocalizeLitMixin(LitElement) { public narrow?: boolean; public showMenu?: boolean; @@ -59,7 +67,7 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { public columns?: number; public route?: { path: string; prefix: string }; private _routeData?: { view: string }; - private _curView?: number | "unused"; + private _curView?: number | "hass-unused-entities"; private notificationsOpen?: boolean; private _persistentNotifications?: Notification[]; private _haStyle?: DocumentFragment; @@ -394,6 +402,8 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { views ) { navigate(this, `/lovelace/${views[0].path || 0}`, true); + } else if (this._routeData!.view === "hass-unused-entities") { + newSelectView = "hass-unused-entities"; } else if (this._routeData!.view) { const selectedView = this._routeData!.view; const selectedViewInt = parseInt(selectedView, 10); @@ -478,7 +488,7 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { } private _handleUnusedEntities(): void { - this._selectView("unused", false); + navigate(this, `/lovelace/hass-unused-entities`); } private _deselect(ev): void { @@ -556,9 +566,14 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { root.removeChild(root.lastChild); } - if (viewIndex === "unused") { + if (viewIndex === "hass-unused-entities") { + if (!loadedUnusedEntities) { + loadedUnusedEntities = true; + await import(/* webpackChunkName: "hui-unused-entities" */ "./hui-unused-entities"); + } const unusedEntities = document.createElement("hui-unused-entities"); unusedEntities.setConfig(this.config); + unusedEntities.hass = this.hass!; root.style.background = this.config.background || ""; root.appendChild(unusedEntities); return; diff --git a/src/panels/lovelace/hui-unused-entities.ts b/src/panels/lovelace/hui-unused-entities.ts index 9548c44bec..ec3970b9ae 100644 --- a/src/panels/lovelace/hui-unused-entities.ts +++ b/src/panels/lovelace/hui-unused-entities.ts @@ -2,15 +2,16 @@ import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; import "./cards/hui-entities-card"; -import computeUnusedEntities from "./common/compute-unused-entities"; -import createCardElement from "./common/create-card-element"; +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"; export class HuiUnusedEntities extends LitElement { private _hass?: HomeAssistant; - private _config?: object; + private _config?: LovelaceConfig; private _element?: LovelaceCard; static get properties(): PropertyDeclarations { @@ -29,10 +30,7 @@ export class HuiUnusedEntities extends LitElement { this._element.hass = this._hass; } - public setConfig(config: object): void { - if (!config) { - throw new Error("Card config incorrect"); - } + public setConfig(config: LovelaceConfig): void { this._config = config; this._createElement(); } @@ -62,7 +60,7 @@ export class HuiUnusedEntities extends LitElement { private _createElement(): void { if (this._hass) { - const entities = computeUnusedEntities(this._hass, this._config).map( + const entities = computeUnusedEntities(this._hass, this._config!).map( (entity) => ({ entity, secondary_info: "entity-id", diff --git a/src/panels/lovelace/hui-view.ts b/src/panels/lovelace/hui-view.ts index 4bbe6b3b15..471e917c1e 100644 --- a/src/panels/lovelace/hui-view.ts +++ b/src/panels/lovelace/hui-view.ts @@ -18,7 +18,7 @@ import { LovelaceViewConfig } from "../../data/lovelace"; import { HomeAssistant } from "../../types"; import { Lovelace, LovelaceCard } from "./types"; -import createCardElement from "./common/create-card-element"; +import { createCardElement } from "./common/create-card-element"; import { computeCardSize } from "./common/compute-card-size"; import { showEditCardDialog } from "./editor/card-editor/show-edit-card-dialog"; From 118f28285ee627337501c6dbb7b4af74a19343b7 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 12 Dec 2018 15:00:00 +0100 Subject: [PATCH 37/82] :camera: Add camera card on generate (#2279) --- src/panels/lovelace/common/generate-lovelace-config.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/panels/lovelace/common/generate-lovelace-config.ts b/src/panels/lovelace/common/generate-lovelace-config.ts index 448f4507f3..def2e228dd 100644 --- a/src/panels/lovelace/common/generate-lovelace-config.ts +++ b/src/panels/lovelace/common/generate-lovelace-config.ts @@ -42,6 +42,11 @@ const computeCards = ( type: "alarm-panel", entity: entityId, }); + } else if (domain === "camera") { + cards.push({ + type: "picture-entity", + entity: entityId, + }); } else if (domain === "climate") { cards.push({ type: "thermostat", From 18de427145cc17664e0e379b26c3119496ade530 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Thu, 13 Dec 2018 02:40:57 -0600 Subject: [PATCH 38/82] :broom: `domain-filter` as attribute as it does not change (#2271) * :hammer: `domain-filter` as attribute as it does not change * Address review comments --- .../editor/config-elements/hui-alarm-panel-card-editor.ts | 2 +- .../lovelace/editor/config-elements/hui-gauge-card-editor.ts | 2 +- .../lovelace/editor/config-elements/hui-light-card-editor.ts | 2 +- .../lovelace/editor/config-elements/hui-sensor-card-editor.ts | 2 +- .../editor/config-elements/hui-thermostat-card-editor.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) 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 c2dab9f5a6..9a9cd816d6 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 @@ -71,7 +71,7 @@ export class HuiAlarmPanelCardEditor extends hassLocalizeLitMixin(LitElement) .hass="${this.hass}" .value="${this._entity}" .configValue=${"entity"} - .domainFilter=${"alarm_control_panel"} + domain-filter="alarm_control_panel" @change="${this._valueChanged}" allow-custom-entity > 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 a613f99449..c0244b816b 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 @@ -94,7 +94,7 @@ export class HuiGaugeCardEditor extends hassLocalizeLitMixin(LitElement) .hass="${this.hass}" .value="${this._entity}" .configValue=${"entity"} - .domainFilter=${"sensor"} + domain-filter="sensor" @change="${this._valueChanged}" allow-custom-entity > 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 eb28b522ae..9038cdb61a 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 @@ -67,7 +67,7 @@ export class HuiLightCardEditor extends hassLocalizeLitMixin(LitElement) .hass="${this.hass}" .value="${this._entity}" .configValue=${"entity"} - .domainFilter=${"light"} + domain-filter="light" @change="${this._valueChanged}" allow-custom-entity > 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 4661826935..d386ffd640 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 @@ -97,7 +97,7 @@ export class HuiSensorCardEditor extends hassLocalizeLitMixin(LitElement) .hass="${this.hass}" .value="${this._entity}" .configValue=${"entity"} - .domainFilter=${"sensor"} + domain-filter="sensor" @change="${this._valueChanged}" allow-custom-entity > 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 001ad5c1cf..d466d27b57 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 @@ -66,7 +66,7 @@ export class HuiThermostatCardEditor extends hassLocalizeLitMixin(LitElement) .hass="${this.hass}" .value="${this._entity}" .configValue=${"entity"} - .domainFilter=${"climate"} + domain-filter="climate" @change="${this._valueChanged}" allow-custom-entity > From 0dfca2f33b99f6ee8d338f9555983a0db0d847c6 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 13 Dec 2018 15:26:23 +0100 Subject: [PATCH 39/82] Call super updated (#2293) --- src/components/ha-label-badge.ts | 1 + src/panels/config/cloud/cloud-exposed-entities.ts | 1 + src/panels/config/cloud/cloud-webhooks.ts | 1 + src/panels/lovelace/cards/hui-entities-card.ts | 3 ++- src/panels/lovelace/cards/hui-entity-button-card.ts | 1 + src/panels/lovelace/cards/hui-gauge-card.ts | 1 + src/panels/lovelace/cards/hui-glance-card.ts | 1 + src/panels/lovelace/cards/hui-light-card.ts | 1 + src/panels/lovelace/cards/hui-sensor-card.ts | 1 + src/panels/lovelace/cards/hui-thermostat-card.ts | 1 + src/panels/lovelace/components/hui-entities-toggle.ts | 1 + src/panels/lovelace/components/hui-timestamp-display.ts | 1 + src/panels/lovelace/ha-panel-lovelace.ts | 1 + 13 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/components/ha-label-badge.ts b/src/components/ha-label-badge.ts index 8a33d8eb56..f29778a0f0 100644 --- a/src/components/ha-label-badge.ts +++ b/src/components/ha-label-badge.ts @@ -153,6 +153,7 @@ class HaLabelBadge extends LitElement { } protected updated(changedProperties: PropertyValues): void { + super.updated(changedProperties); if (changedProperties.has("image")) { this.shadowRoot!.getElementById("badge")!.style.backgroundImage = this .image diff --git a/src/panels/config/cloud/cloud-exposed-entities.ts b/src/panels/config/cloud/cloud-exposed-entities.ts index e9d6438a2a..fd47f759b0 100644 --- a/src/panels/config/cloud/cloud-exposed-entities.ts +++ b/src/panels/config/cloud/cloud-exposed-entities.ts @@ -70,6 +70,7 @@ export class CloudExposedEntities extends LitElement { } protected updated(changedProperties: PropertyValues) { + super.updated(changedProperties); if ( changedProperties.has("filter") && changedProperties.get("filter") !== this.filter diff --git a/src/panels/config/cloud/cloud-webhooks.ts b/src/panels/config/cloud/cloud-webhooks.ts index db0d3a1dad..e89b6123a9 100644 --- a/src/panels/config/cloud/cloud-webhooks.ts +++ b/src/panels/config/cloud/cloud-webhooks.ts @@ -79,6 +79,7 @@ export class CloudWebhooks extends LitElement { } protected updated(changedProps: PropertyValues) { + super.updated(changedProps); if (changedProps.has("cloudStatus") && this.cloudStatus) { this._cloudHooks = this.cloudStatus.prefs.cloudhooks || {}; } diff --git a/src/panels/lovelace/cards/hui-entities-card.ts b/src/panels/lovelace/cards/hui-entities-card.ts index 2e1e2e1dd2..8fd4e5437d 100644 --- a/src/panels/lovelace/cards/hui-entities-card.ts +++ b/src/panels/lovelace/cards/hui-entities-card.ts @@ -88,7 +88,8 @@ class HuiEntitiesCard extends hassLocalizeLitMixin(LitElement) this._configEntities = entities; } - protected updated(_changedProperties: PropertyValues): void { + protected updated(changedProperties: PropertyValues): void { + super.updated(changedProperties); if (this._hass && this._config) { applyThemesOnElement(this, this._hass.themes, this._config.theme); } diff --git a/src/panels/lovelace/cards/hui-entity-button-card.ts b/src/panels/lovelace/cards/hui-entity-button-card.ts index fbb074b0b4..d2b208ae40 100644 --- a/src/panels/lovelace/cards/hui-entity-button-card.ts +++ b/src/panels/lovelace/cards/hui-entity-button-card.ts @@ -116,6 +116,7 @@ class HuiEntityButtonCard extends hassLocalizeLitMixin(LitElement) } protected updated(changedProps: PropertyValues): void { + super.updated(changedProps); if (!this._config || !this.hass) { return; } diff --git a/src/panels/lovelace/cards/hui-gauge-card.ts b/src/panels/lovelace/cards/hui-gauge-card.ts index cc7414fb3c..cedbec8af9 100644 --- a/src/panels/lovelace/cards/hui-gauge-card.ts +++ b/src/panels/lovelace/cards/hui-gauge-card.ts @@ -151,6 +151,7 @@ class HuiGaugeCard extends LitElement implements LovelaceCard { } protected updated(changedProps: PropertyValues): void { + super.updated(changedProps); if (!this._config || !this.hass) { return; } diff --git a/src/panels/lovelace/cards/hui-glance-card.ts b/src/panels/lovelace/cards/hui-glance-card.ts index ff74e0dc0f..537bc405e2 100644 --- a/src/panels/lovelace/cards/hui-glance-card.ts +++ b/src/panels/lovelace/cards/hui-glance-card.ts @@ -135,6 +135,7 @@ export class HuiGlanceCard extends hassLocalizeLitMixin(LitElement) } protected updated(changedProperties: PropertyValues): void { + super.updated(changedProperties); if (!this._config || !this.hass) { return; } diff --git a/src/panels/lovelace/cards/hui-light-card.ts b/src/panels/lovelace/cards/hui-light-card.ts index aea91b9825..1cb389af0e 100644 --- a/src/panels/lovelace/cards/hui-light-card.ts +++ b/src/panels/lovelace/cards/hui-light-card.ts @@ -162,6 +162,7 @@ export class HuiLightCard extends hassLocalizeLitMixin(LitElement) } protected updated(changedProps: PropertyValues): void { + super.updated(changedProps); if (!this._config || !this.hass || !this._jQuery) { return; } diff --git a/src/panels/lovelace/cards/hui-sensor-card.ts b/src/panels/lovelace/cards/hui-sensor-card.ts index cde93f3056..2b1f40c990 100755 --- a/src/panels/lovelace/cards/hui-sensor-card.ts +++ b/src/panels/lovelace/cards/hui-sensor-card.ts @@ -274,6 +274,7 @@ class HuiSensorCard extends LitElement implements LovelaceCard { } protected updated(changedProps: PropertyValues) { + super.updated(changedProps); if (!this._config || this._config.graph !== "line" || !this.hass) { return; } diff --git a/src/panels/lovelace/cards/hui-thermostat-card.ts b/src/panels/lovelace/cards/hui-thermostat-card.ts index 45e9351fb7..bf9368de46 100644 --- a/src/panels/lovelace/cards/hui-thermostat-card.ts +++ b/src/panels/lovelace/cards/hui-thermostat-card.ts @@ -152,6 +152,7 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement) } protected updated(changedProps: PropertyValues): void { + super.updated(changedProps); if (!this._config || !this.hass || !changedProps.has("hass")) { return; } diff --git a/src/panels/lovelace/components/hui-entities-toggle.ts b/src/panels/lovelace/components/hui-entities-toggle.ts index 95d1559766..d441f7369f 100644 --- a/src/panels/lovelace/components/hui-entities-toggle.ts +++ b/src/panels/lovelace/components/hui-entities-toggle.ts @@ -25,6 +25,7 @@ class HuiEntitiesToggle extends LitElement { } public updated(changedProperties: PropertyValues) { + super.updated(changedProperties); if (changedProperties.has("entities")) { this._toggleEntities = this.entities!.filter( (entityId) => diff --git a/src/panels/lovelace/components/hui-timestamp-display.ts b/src/panels/lovelace/components/hui-timestamp-display.ts index d97b9abdd0..3a346ff0ce 100644 --- a/src/panels/lovelace/components/hui-timestamp-display.ts +++ b/src/panels/lovelace/components/hui-timestamp-display.ts @@ -78,6 +78,7 @@ class HuiTimestampDisplay extends hassLocalizeLitMixin(LitElement) { } protected updated(changedProperties: PropertyValues) { + super.updated(changedProperties); if (!changedProperties.has("format") || !this._connected) { return; } diff --git a/src/panels/lovelace/ha-panel-lovelace.ts b/src/panels/lovelace/ha-panel-lovelace.ts index 136a9283b5..559e1e5311 100644 --- a/src/panels/lovelace/ha-panel-lovelace.ts +++ b/src/panels/lovelace/ha-panel-lovelace.ts @@ -105,6 +105,7 @@ class LovelacePanel extends hassLocalizeLitMixin(LitElement) { } public updated(changedProps: PropertyValues): void { + super.updated(changedProps); if (changedProps.has("narrow") || changedProps.has("showMenu")) { this._updateColumns(); } From 47635055d01abc5b8b5321831191b7fc4ec13510 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 13 Dec 2018 21:46:50 +0100 Subject: [PATCH 40/82] Clear view cache edit mode (#2291) * Clear view cache when canceling edit mode * Fix enabling edit mode on not first view --- src/panels/lovelace/hui-root.ts | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts index b814c049bc..d81b8b7f5c 100644 --- a/src/panels/lovelace/hui-root.ts +++ b/src/panels/lovelace/hui-root.ts @@ -93,6 +93,8 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { constructor() { super(); + // The view can trigger a re-render when it knows that certain + // web components have been loaded. this._debouncedConfigChanged = debounce( () => this._selectView(this._curView, true), 100 @@ -380,7 +382,7 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { protected updated(changedProperties: PropertyValues): void { super.updated(changedProperties); - const view = this._view; + const view = this._viewRoot; const huiView = view.lastChild as HUIView; if (changedProperties.has("columns") && huiView) { @@ -424,18 +426,21 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { | undefined; if (!oldLovelace || oldLovelace.config !== this.lovelace!.config) { - this._viewCache = {}; this._loadResources(this.lovelace!.config.resources || []); - // On config change, recreate the view from scratch. + // On config change, recreate the current view from scratch. force = true; } if (!oldLovelace || oldLovelace.editMode !== this.lovelace!.editMode) { + // On edit mode change, recreate the current view from scratch force = true; } } if (newSelectView !== undefined || force) { + if (force && newSelectView === undefined) { + newSelectView = this._curView; + } this._selectView(newSelectView, force); } } @@ -463,7 +468,7 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { return this.shadowRoot!.getElementById("layout"); } - private get _view(): HTMLDivElement { + private get _viewRoot(): HTMLDivElement { return this.shadowRoot!.getElementById("view") as HTMLDivElement; } @@ -535,11 +540,8 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { } private _handleViewSelected(ev) { - const index = ev.detail.selected; - this._navigateView(index); - } + const viewIndex = ev.detail.selected as number; - private _navigateView(viewIndex: number): void { if (viewIndex !== this._curView) { const path = this.config.views[viewIndex].path || viewIndex; navigate(this, `/lovelace/${path}`); @@ -559,8 +561,12 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { this._curView = viewIndex; + if (force) { + this._viewCache = {}; + } + // Recreate a new element to clear the applied themes. - const root = this._view; + const root = this._viewRoot; if (root.lastChild) { root.removeChild(root.lastChild); From 71ed83ef07a510ab58918584313f668a76c9f6ef Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 13 Dec 2018 21:46:57 +0100 Subject: [PATCH 41/82] Fix opening edit dialog twice when closed by clicking on overlay (#2290) --- .../editor/card-editor/hui-dialog-edit-card.ts | 1 + .../editor/card-editor/hui-dialog-pick-card.ts | 13 ++++++++++++- .../lovelace/editor/card-editor/hui-edit-card.ts | 12 +++++++++++- 3 files changed, 24 insertions(+), 2 deletions(-) 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 3046a4d5f4..f47930a851 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 @@ -58,6 +58,7 @@ export class HuiDialogEditCard extends LitElement { `; } 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 75553235ad..5c55787dfa 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 @@ -11,6 +11,7 @@ import { LovelaceCardConfig } from "../../../../data/lovelace"; export class HuiDialogPickCard extends hassLocalizeLitMixin(LitElement) { public hass?: HomeAssistant; public cardPicked?: (cardConf: LovelaceCardConfig) => void; + public closeDialog?: () => void; static get properties(): PropertyDeclarations { return {}; @@ -18,7 +19,11 @@ export class HuiDialogPickCard extends hassLocalizeLitMixin(LitElement) { protected render(): TemplateResult { return html` - +

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

+

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

Date: Thu, 13 Dec 2018 23:36:01 +0100 Subject: [PATCH 42/82] Fix setting aspect ratio in percentage (#2289) * Fix setting aspect ratio in percentage * Use endsWith * Fix invalid test --- src/common/util/parse-aspect-ratio.ts | 42 +++++++++++-------- .../common/util/parse_aspect_ratio_test.ts | 6 +-- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/common/util/parse-aspect-ratio.ts b/src/common/util/parse-aspect-ratio.ts index cd80d4b90d..8fb1dee0a2 100644 --- a/src/common/util/parse-aspect-ratio.ts +++ b/src/common/util/parse-aspect-ratio.ts @@ -1,24 +1,30 @@ -export default function parseAspectRatio(input) { - // Handle 16x9, 16:9, 1.78x1, 1.78:1, 1.78 - // Ignore everything else - function parseOrThrow(num) { - const parsed = parseFloat(num); - if (isNaN(parsed)) { - throw new Error(`${num} is not a number`); - } - return parsed; +// Handle 16x9, 16:9, 1.78x1, 1.78:1, 1.78 +// Ignore everything else +const parseOrThrow = (num) => { + const parsed = parseFloat(num); + if (isNaN(parsed)) { + throw new Error(`${num} is not a number`); + } + return parsed; +}; + +export default function parseAspectRatio(input: string) { + if (!input) { + return null; } try { - if (input) { - const arr = input.replace(":", "x").split("x"); - if (arr.length === 0) { - return null; - } - - return arr.length === 1 - ? { w: parseOrThrow(arr[0]), h: 1 } - : { w: parseOrThrow(arr[0]), h: parseOrThrow(arr[1]) }; + if (input.endsWith("%")) { + return { w: 100, h: parseOrThrow(input.substr(0, input.length - 1)) }; } + + const arr = input.replace(":", "x").split("x"); + if (arr.length === 0) { + return null; + } + + return arr.length === 1 + ? { w: parseOrThrow(arr[0]), h: 1 } + : { w: parseOrThrow(arr[0]), h: parseOrThrow(arr[1]) }; } catch (err) { // Ignore the error } diff --git a/test-mocha/common/util/parse_aspect_ratio_test.ts b/test-mocha/common/util/parse_aspect_ratio_test.ts index 15b42a0cc1..758010aefa 100644 --- a/test-mocha/common/util/parse_aspect_ratio_test.ts +++ b/test-mocha/common/util/parse_aspect_ratio_test.ts @@ -31,9 +31,9 @@ describe("parseAspectRatio", () => { assert.deepEqual(r, ratio178); }); - it("Skips null states", () => { - const r = parseAspectRatio(null); - assert.equal(r, null); + it("Parses 23%", () => { + const r = parseAspectRatio("23%"); + assert.deepEqual(r, { w: 100, h: 23 }); }); it("Skips empty states", () => { From 2ec8b97378fcfbf7b0ea321d57cf4e0c667bb656 Mon Sep 17 00:00:00 2001 From: Zack Arnett Date: Thu, 13 Dec 2018 21:45:21 -0500 Subject: [PATCH 43/82] remove Animation for thermostat and light (#2303) * Update Animation * Update light --- src/panels/lovelace/cards/hui-light-card.ts | 1 + src/panels/lovelace/cards/hui-thermostat-card.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/panels/lovelace/cards/hui-light-card.ts b/src/panels/lovelace/cards/hui-light-card.ts index 1cb389af0e..b7556f700a 100644 --- a/src/panels/lovelace/cards/hui-light-card.ts +++ b/src/panels/lovelace/cards/hui-light-card.ts @@ -36,6 +36,7 @@ const lightConfig = { lineCap: "round", handleSize: "+12", showTooltip: false, + animation: false, }; export interface Config extends LovelaceCardConfig { diff --git a/src/panels/lovelace/cards/hui-thermostat-card.ts b/src/panels/lovelace/cards/hui-thermostat-card.ts index bf9368de46..b0f099b496 100644 --- a/src/panels/lovelace/cards/hui-thermostat-card.ts +++ b/src/panels/lovelace/cards/hui-thermostat-card.ts @@ -30,6 +30,7 @@ const thermostatConfig = { lineCap: "round", handleSize: "+10", showTooltip: false, + animation: false, }; const modeIcons = { From c46d04eaa6ddc56a1dc13d34299158bb5360bea6 Mon Sep 17 00:00:00 2001 From: Zack Arnett Date: Fri, 14 Dec 2018 05:16:43 -0500 Subject: [PATCH 44/82] Alarm Card Conversion (#2259) * Alarm Card COnversion * Map buttons * Reducing margin under alarm code * Update src/panels/lovelace/cards/hui-alarm-panel-card.ts Co-Authored-By: zsarnett * Comment Updates * Review updates * Reorder css * Update actions * TSlint * TS LINT * Idk whats going on here * Fix import --- src/data/alarm_control_panel.ts | 18 ++ .../lovelace/cards/hui-alarm-panel-card.js | 273 ---------------- .../lovelace/cards/hui-alarm-panel-card.ts | 302 ++++++++++++++++++ 3 files changed, 320 insertions(+), 273 deletions(-) create mode 100644 src/data/alarm_control_panel.ts delete mode 100644 src/panels/lovelace/cards/hui-alarm-panel-card.js create mode 100644 src/panels/lovelace/cards/hui-alarm-panel-card.ts diff --git a/src/data/alarm_control_panel.ts b/src/data/alarm_control_panel.ts new file mode 100644 index 0000000000..58f33c601d --- /dev/null +++ b/src/data/alarm_control_panel.ts @@ -0,0 +1,18 @@ +import { HomeAssistant } from "../types"; + +export const callAlarmAction = ( + hass: HomeAssistant, + entity: string, + action: + | "arm_away" + | "arm_home" + | "arm_night" + | "arm_custom_bypass" + | "disarm", + code: string +) => { + hass!.callService("alarm_control_panel", "alarm_" + action, { + entity_id: entity, + code, + }); +}; diff --git a/src/panels/lovelace/cards/hui-alarm-panel-card.js b/src/panels/lovelace/cards/hui-alarm-panel-card.js deleted file mode 100644 index 6c7b9679c8..0000000000 --- a/src/panels/lovelace/cards/hui-alarm-panel-card.js +++ /dev/null @@ -1,273 +0,0 @@ -import { html } from "@polymer/polymer/lib/utils/html-tag"; -import { PolymerElement } from "@polymer/polymer/polymer-element"; - -import "../../../components/ha-card"; - -import EventsMixin from "../../../mixins/events-mixin"; -import LocalizeMixin from "../../../mixins/localize-mixin"; -import "../../../components/ha-label-badge"; - -/* - * @appliesMixin EventsMixin - */ - -const Icons = { - armed_away: "hass:security-lock", - armed_custom_bypass: "hass:security", - armed_home: "hass:security-home", - armed_night: "hass:security-home", - disarmed: "hass:verified", - pending: "hass:shield-outline", - triggered: "hass:bell-ring", -}; - -export const Config = { - name: "", - entity: "", - states: "", -}; - -class HuiAlarmPanelCard extends LocalizeMixin(EventsMixin(PolymerElement)) { - static async getConfigElement() { - await import("../editor/config-elements/hui-alarm-panel-card-editor"); - return document.createElement("hui-alarm-panel-card-editor"); - } - - static getStubConfig() { - return { states: ["arm_home", "arm_away"] }; - } - - static get template() { - return html` - - - - - - `; - } - - static get properties() { - return { - hass: { - type: Object, - }, - _config: Object, - _stateObj: { - type: Object, - computed: "_computeStateObj(hass.states, _config.entity)", - }, - _value: { - type: String, - value: "", - }, - }; - } - - getCardSize() { - return 4; - } - - setConfig(config) { - if ( - !config || - !config.entity || - config.entity.split(".")[0] !== "alarm_control_panel" - ) { - throw new Error("Invalid card configuration"); - } - - const defaults = { - states: ["arm_away", "arm_home"], - }; - - this._config = { ...defaults, ...config }; - this._icons = Icons; - } - - _computeStateObj(states, entityId) { - return states && entityId in states ? states[entityId] : null; - } - - _computeHeader(localize, stateObj) { - if (!stateObj) return ""; - return this._config.name - ? this._config.name - : this._label(localize, stateObj.state); - } - - _computeIcon(stateObj) { - return this._icons[stateObj.state] || "hass:shield-outline"; - } - - _label(localize, state) { - return ( - localize(`state.alarm_control_panel.${state}`) || - localize(`ui.card.alarm_control_panel.${state}`) - ); - } - - _stateIconLabel(state) { - const stateLabel = state.split("_").pop(); - return stateLabel === "disarmed" || stateLabel === "triggered" - ? "" - : stateLabel; - } - - _showActionToggle(state) { - return state === "disarmed"; - } - - _computeClassName(stateObj) { - if (!stateObj) return "not-found"; - return ""; - } - - _handlePadClick(e) { - const val = e.target.getAttribute("value"); - this._value = val === "clear" ? "" : this._value + val; - } - - _handleActionClick(e) { - this.hass.callService("alarm_control_panel", "alarm_" + e.target.id, { - entity_id: this._stateObj.entity_id, - code: this._value, - }); - this._value = ""; - } -} - -customElements.define("hui-alarm-panel-card", HuiAlarmPanelCard); diff --git a/src/panels/lovelace/cards/hui-alarm-panel-card.ts b/src/panels/lovelace/cards/hui-alarm-panel-card.ts new file mode 100644 index 0000000000..ae83f1b7ca --- /dev/null +++ b/src/panels/lovelace/cards/hui-alarm-panel-card.ts @@ -0,0 +1,302 @@ +import { + html, + LitElement, + PropertyValues, + PropertyDeclarations, +} from "@polymer/lit-element"; +import { TemplateResult } from "lit-html"; +import { classMap } from "lit-html/directives/classMap"; + +import { LovelaceCard } from "../types"; +import { HomeAssistant } from "../../../types"; +import { LovelaceCardConfig } from "../../../data/lovelace"; +import { callAlarmAction } from "../../../data/alarm_control_panel"; +import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; + +import "../../../components/ha-card"; +import "../../../components/ha-label-badge"; +import { + createErrorCardConfig, + createErrorCardElement, +} from "./hui-error-card"; + +const ICONS = { + armed_away: "hass:security-lock", + armed_custom_bypass: "hass:security", + armed_home: "hass:security-home", + armed_night: "hass:security-home", + disarmed: "hass:verified", + pending: "hass:shield-outline", + triggered: "hass:bell-ring", +}; + +const BUTTONS = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "", "0", "clear"]; + +export interface Config extends LovelaceCardConfig { + entity: string; + name?: string; + states?: string[]; +} + +class HuiAlarmPanelCard extends hassLocalizeLitMixin(LitElement) + implements LovelaceCard { + public static async getConfigElement() { + await import("../editor/config-elements/hui-alarm-panel-card-editor"); + return document.createElement("hui-alarm-panel-card-editor"); + } + + public static getStubConfig() { + return { states: ["arm_home", "arm_away"] }; + } + + public hass?: HomeAssistant; + private _config?: Config; + private _code?: string; + + static get properties(): PropertyDeclarations { + return { + hass: {}, + _config: {}, + _code: {}, + }; + } + + public getCardSize(): number { + return 4; + } + + public setConfig(config: Config): void { + if ( + !config || + !config.entity || + config.entity.split(".")[0] !== "alarm_control_panel" + ) { + throw new Error("Invalid card configuration"); + } + + const defaults = { + states: ["arm_away", "arm_home"], + }; + + this._config = { ...defaults, ...config }; + this._code = ""; + } + + protected shouldUpdate(changedProps: PropertyValues): boolean { + if (changedProps.has("_config") || changedProps.has("_code")) { + return true; + } + + const oldHass = changedProps.get("hass") as HomeAssistant | undefined; + if (oldHass) { + return ( + oldHass.states[this._config!.entity] !== + this.hass!.states[this._config!.entity] + ); + } + return true; + } + + protected render(): TemplateResult { + if (!this._config || !this.hass) { + return html``; + } + const stateObj = this.hass.states[this._config.entity]; + + if (!stateObj) { + const element = createErrorCardElement( + createErrorCardConfig("Entity not Found!", this._config) + ); + return html` + ${element} + `; + } + + return html` + ${this.renderStyle()} + + +
+ ${ + (stateObj.state === "disarmed" + ? this._config.states! + : ["disarm"] + ).map((state) => { + return html` + ${this._label(state)} + `; + }) + } +
+ +
+ ${ + BUTTONS.map((value) => { + return value === "" + ? html` + + ` + : html` + ${ + value === "clear" ? this._label("clear_code") : value + } + `; + }) + } +
+
+ `; + } + + private _stateIconLabel(state: string): string { + const stateLabel = state.split("_").pop(); + return stateLabel === "disarmed" || + stateLabel === "triggered" || + !stateLabel + ? "" + : stateLabel; + } + + private _label(state: string): string { + return ( + this.localize(`state.alarm_control_panel.${state}`) || + this.localize(`ui.card.alarm_control_panel.${state}`) + ); + } + + private _handlePadClick(e: MouseEvent): void { + const val = (e.currentTarget! as any).value; + this._code = val === "clear" ? "" : this._code + val; + } + + private _handleActionClick(e: MouseEvent): void { + callAlarmAction( + this.hass!, + this._config!.entity_id, + (e.currentTarget! as any).action, + this._code! + ); + this._code = ""; + } + + private renderStyle(): TemplateResult { + return html` + + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-alarm-panel-card": HuiAlarmPanelCard; + } +} + +customElements.define("hui-alarm-panel-card", HuiAlarmPanelCard); From e20a02c52c19c6ef5c999c022e465b2ec17cb532 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 16 Dec 2018 19:52:13 +0100 Subject: [PATCH 45/82] Fix undefined on plant/weather card (#2339) --- src/cards/ha-plant-card.js | 2 +- src/cards/ha-weather-card.js | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/cards/ha-plant-card.js b/src/cards/ha-plant-card.js index f1a4fcbbdd..8334bf39cd 100644 --- a/src/cards/ha-plant-card.js +++ b/src/cards/ha-plant-card.js @@ -119,7 +119,7 @@ class HaPlantCard extends EventsMixin(PolymerElement) { } computeTitle(stateObj) { - return this.config.name || computeStateName(stateObj); + return (this.config && this.config.name) || computeStateName(stateObj); } computeAttributes(data) { diff --git a/src/cards/ha-weather-card.js b/src/cards/ha-weather-card.js index ef9e086c02..ce9ac0152d 100644 --- a/src/cards/ha-weather-card.js +++ b/src/cards/ha-weather-card.js @@ -39,6 +39,7 @@ class HaWeatherCard extends LocalizeMixin(EventsMixin(PolymerElement)) { opacity: var(--dark-primary-opacity); padding: 24px 16px 16px; display: flex; + align-items: baseline; } .name { @@ -195,6 +196,7 @@ class HaWeatherCard extends LocalizeMixin(EventsMixin(PolymerElement)) { static get properties() { return { hass: Object, + config: Object, stateObj: Object, forecast: { type: Array, @@ -274,7 +276,7 @@ class HaWeatherCard extends LocalizeMixin(EventsMixin(PolymerElement)) { } computeName(stateObj) { - return this.config.name || computeStateName(stateObj); + return (this.config && this.config.name) || computeStateName(stateObj); } showWeatherIcon(condition) { From 9d2b37c9f2f89d1b7653ea1dfa506f763e878662 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Mon, 17 Dec 2018 00:50:27 -0600 Subject: [PATCH 46/82] Remove unnecessary editor types (#2342) --- .../editor/config-elements/hui-alarm-panel-card-editor.ts | 3 +-- .../editor/config-elements/hui-entities-card-editor.ts | 3 +-- .../editor/config-elements/hui-gauge-card-editor.ts | 7 +------ .../editor/config-elements/hui-glance-card-editor.ts | 3 +-- .../editor/config-elements/hui-iframe-card-editor.ts | 3 +-- .../editor/config-elements/hui-light-card-editor.ts | 3 +-- .../editor/config-elements/hui-markdown-card-editor.ts | 3 +-- .../editor/config-elements/hui-sensor-card-editor.ts | 3 +-- .../editor/config-elements/hui-shopping-list-editor.ts | 3 +-- .../editor/config-elements/hui-thermostat-card-editor.ts | 2 +- 10 files changed, 10 insertions(+), 23 deletions(-) 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 9a9cd816d6..85c78a5f12 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 @@ -30,8 +30,7 @@ export class HuiAlarmPanelCardEditor extends hassLocalizeLitMixin(LitElement) public setConfig(config: Config): void { config = cardConfigStruct(config); - - this._config = { type: "alarm-panel", ...config }; + this._config = config; } static get properties(): PropertyDeclarations { 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 d34556ceb7..846b379738 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 @@ -58,8 +58,7 @@ export class HuiEntitiesCardEditor extends hassLocalizeLitMixin(LitElement) public setConfig(config: Config): void { config = cardConfigStruct(config); - - this._config = { type: "entities", ...config }; + this._config = config; this._configEntities = processEditorEntities(config.entities); } 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 c0244b816b..6a430f514c 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 @@ -34,13 +34,8 @@ export class HuiGaugeCardEditor extends hassLocalizeLitMixin(LitElement) public setConfig(config: Config): void { config = cardConfigStruct(config); - this._useSeverity = config.severity ? true : false; - - this._config = { - type: "gauge", - ...config, - }; + this._config = config; } static get properties(): PropertyDeclarations { 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 a32a0b804a..f18aff598d 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 @@ -48,8 +48,7 @@ export class HuiGlanceCardEditor extends hassLocalizeLitMixin(LitElement) public setConfig(config: Config): void { config = cardConfigStruct(config); - - this._config = { type: "glance", ...config }; + this._config = config; this._configEntities = processEditorEntities(config.entities); } 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 fe6ba662cc..78531eeff6 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 @@ -25,8 +25,7 @@ export class HuiIframeCardEditor extends hassLocalizeLitMixin(LitElement) public setConfig(config: Config): void { config = cardConfigStruct(config); - - this._config = { type: "iframe", ...config }; + this._config = config; } static get properties(): PropertyDeclarations { 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 9038cdb61a..26c2a4b922 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 @@ -28,8 +28,7 @@ export class HuiLightCardEditor extends hassLocalizeLitMixin(LitElement) public setConfig(config: Config): void { config = cardConfigStruct(config); - - this._config = { type: "light", ...config }; + this._config = config; } static get properties(): PropertyDeclarations { 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 2a863fb133..b37d60da94 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 @@ -25,8 +25,7 @@ export class HuiMarkdownCardEditor extends hassLocalizeLitMixin(LitElement) public setConfig(config: Config): void { config = cardConfigStruct(config); - - this._config = { type: "markdown", ...config }; + this._config = config; } static get properties(): PropertyDeclarations { 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 d386ffd640..28391d0473 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 @@ -36,8 +36,7 @@ export class HuiSensorCardEditor extends hassLocalizeLitMixin(LitElement) public setConfig(config: Config): void { config = cardConfigStruct(config); - - this._config = { type: "sensor", ...config }; + this._config = config; } static get properties(): PropertyDeclarations { 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 621181354f..ae56d6ab02 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 @@ -22,8 +22,7 @@ export class HuiShoppingListEditor extends hassLocalizeLitMixin(LitElement) public setConfig(config: Config): void { config = cardConfigStruct(config); - - this._config = { type: "shopping-list", ...config }; + this._config = config; } static get properties(): PropertyDeclarations { 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 d466d27b57..9cc1033027 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 @@ -28,7 +28,7 @@ export class HuiThermostatCardEditor extends hassLocalizeLitMixin(LitElement) public setConfig(config: Config): void { config = cardConfigStruct(config); - this._config = { type: "thermostat", ...config }; + this._config = config; } static get properties(): PropertyDeclarations { From cac7f8d1abd25005bb3687734061eda3bf628443 Mon Sep 17 00:00:00 2001 From: Malte Franken Date: Mon, 17 Dec 2018 19:04:58 +1100 Subject: [PATCH 47/82] Extended map to support geo location entities (#2337) * initial version of geo location map * configuring entities not required but source is * extending existing map instead of adding a new one * renamed source to geo_location_source; clearer handling of geo location entities vs defined entities * geo location sources must now be an array * code cleanup --- src/panels/lovelace/cards/hui-map-card.js | 37 +++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/panels/lovelace/cards/hui-map-card.js b/src/panels/lovelace/cards/hui-map-card.js index 32a7631c6d..e6dd8960e6 100644 --- a/src/panels/lovelace/cards/hui-map-card.js +++ b/src/panels/lovelace/cards/hui-map-card.js @@ -111,8 +111,24 @@ class HuiMapCard extends PolymerElement { throw new Error("Error in card configuration."); } - this._configEntities = processConfigEntities(config.entities); + if (!config.entities && !config.geo_location_sources) { + throw new Error( + "Either entities or geo_location_sources must be defined" + ); + } + if (config.entities && !Array.isArray(config.entities)) { + throw new Error("Entities need to be an array"); + } + if ( + config.geo_location_sources && + !Array.isArray(config.geo_location_sources) + ) { + throw new Error("Geo_location_sources needs to be an array"); + } + this._config = config; + this._configGeoLocationSources = config.geo_location_sources; + this._configEntities = config.entities; } getCardSize() { @@ -205,7 +221,24 @@ class HuiMapCard extends PolymerElement { } const mapItems = (this._mapItems = []); - this._configEntities.forEach((entity) => { + let allEntities = []; + if (this._configEntities) { + allEntities = allEntities.concat(this._configEntities); + } + if (this._configGeoLocationSources) { + Object.keys(this.hass.states).forEach((entityId) => { + const stateObj = this.hass.states[entityId]; + if ( + computeStateDomain(stateObj) === "geo_location" && + this._configGeoLocationSources.includes(stateObj.attributes.source) + ) { + allEntities.push(entityId); + } + }); + } + allEntities = processConfigEntities(allEntities); + + allEntities.forEach((entity) => { const entityId = entity.entity; if (!(entityId in hass.states)) { return; From d1a56d6acc1796a19fcba6e3a03cbeab54737f1d Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Mon, 17 Dec 2018 02:31:58 -0600 Subject: [PATCH 48/82] :sparkles: UI Editor for `media-control` card (#2336) * :sparkles: UI Editor for `media-control` card * Address review comments * Note on LL interface --- .../lovelace/cards/hui-media-control-card.js | 14 ++++ .../hui-media-control-card-editor.ts | 83 +++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 src/panels/lovelace/editor/config-elements/hui-media-control-card-editor.ts diff --git a/src/panels/lovelace/cards/hui-media-control-card.js b/src/panels/lovelace/cards/hui-media-control-card.js index 21dc0f2d02..f80b137363 100644 --- a/src/panels/lovelace/cards/hui-media-control-card.js +++ b/src/panels/lovelace/cards/hui-media-control-card.js @@ -2,7 +2,21 @@ import "../../../cards/ha-media_player-card"; import LegacyWrapperCard from "./hui-legacy-wrapper-card"; +// should be interface when converted to TS +export const Config = { + entity: "", +}; + class HuiMediaControlCard extends LegacyWrapperCard { + static async getConfigElement() { + await import("../editor/config-elements/hui-media-control-card-editor"); + return document.createElement("hui-media-control-card-editor"); + } + + static getStubConfig() { + return {}; + } + constructor() { super("ha-media_player-card", "media_player"); } 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 new file mode 100644 index 0000000000..04b13271e1 --- /dev/null +++ b/src/panels/lovelace/editor/config-elements/hui-media-control-card-editor.ts @@ -0,0 +1,83 @@ +import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; +import { TemplateResult } from "lit-html"; + +import { struct } from "../../common/structs/struct"; +import { EntitiesEditorEvent, EditorTarget } from "../types"; +import { hassLocalizeLitMixin } from "../../../../mixins/lit-localize-mixin"; +import { HomeAssistant } from "../../../../types"; +import { LovelaceCardEditor } from "../../types"; +import { fireEvent } from "../../../../common/dom/fire_event"; +import { Config } from "../../cards/hui-media-control-card"; + +import "../../../../components/entity/ha-entity-picker"; + +const cardConfigStruct = struct({ + type: "string", + entity: "string?", +}); + +export class HuiMediaControlCardEditor extends hassLocalizeLitMixin(LitElement) + implements LovelaceCardEditor { + public hass?: HomeAssistant; + private _config?: Config; + + public setConfig(config: Config): void { + config = cardConfigStruct(config); + this._config = config; + } + + static get properties(): PropertyDeclarations { + return { hass: {}, _config: {} }; + } + + get _entity(): string { + return this._config!.entity || ""; + } + + protected render(): TemplateResult { + if (!this.hass) { + return html``; + } + + return html` +
+ +
+ `; + } + + private _valueChanged(ev: EntitiesEditorEvent): void { + if (!this._config || !this.hass) { + return; + } + const target = ev.target! as EditorTarget; + if (this[`_${target.configValue}`] === target.value) { + return; + } + if (target.configValue) { + this._config = { + ...this._config, + [target.configValue!]: target.value, + }; + } + fireEvent(this, "config-changed", { config: this._config }); + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-media-control-card-editor": HuiMediaControlCardEditor; + } +} + +customElements.define( + "hui-media-control-card-editor", + HuiMediaControlCardEditor +); From e5bf842801e6e86b7b11b505322425458b0e1996 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 17 Dec 2018 09:36:55 +0100 Subject: [PATCH 49/82] Fix service button element (#2343) --- src/layouts/app/connection-mixin.js | 27 +++++++++++++++---- .../elements/hui-service-button-element.ts | 2 +- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/layouts/app/connection-mixin.js b/src/layouts/app/connection-mixin.js index 222d1b4ea2..6a763ffcde 100644 --- a/src/layouts/app/connection-mixin.js +++ b/src/layouts/app/connection-mixin.js @@ -56,6 +56,10 @@ export default (superClass) => dockedSidebar: false, moreInfoEntityId: null, callService: async (domain, service, serviceData = {}) => { + if (__DEV__) { + // eslint-disable-next-line + console.log("Calling service", domain, service, serviceData); + } try { await callService(conn, domain, service, serviceData); @@ -91,6 +95,15 @@ export default (superClass) => } this.fire("hass-notification", { message }); } catch (err) { + if (__DEV__) { + // eslint-disable-next-line + console.error( + "Error calling service", + domain, + service, + serviceData + ); + } const message = this.localize( "ui.notification_toast.service_call_failed", "service", @@ -106,21 +119,25 @@ export default (superClass) => fetchWithAuth(auth, `${auth.data.hassUrl}${path}`, init), // For messages that do not get a response sendWS: (msg) => { - // eslint-disable-next-line - if (__DEV__) console.log("Sending", msg); + if (__DEV__) { + // eslint-disable-next-line + console.log("Sending", msg); + } conn.sendMessage(msg); }, // For messages that expect a response callWS: (msg) => { - /* eslint-disable no-console */ - if (__DEV__) console.log("Sending", msg); + if (__DEV__) { + /* eslint-disable no-console */ + console.log("Sending", msg); + } const resp = conn.sendMessagePromise(msg); if (__DEV__) { resp.then( (result) => console.log("Received", result), - (err) => console.log("Error", err) + (err) => console.error("Error", err) ); } return resp; diff --git a/src/panels/lovelace/elements/hui-service-button-element.ts b/src/panels/lovelace/elements/hui-service-button-element.ts index 32a39600fe..eb4013f3cf 100644 --- a/src/panels/lovelace/elements/hui-service-button-element.ts +++ b/src/panels/lovelace/elements/hui-service-button-element.ts @@ -48,7 +48,7 @@ export class HuiServiceButtonElement extends LitElement .hass="${this.hass}" .domain="${this._domain}" .service="${this._service}" - .service-data="${this._config.service_data}" + .serviceData="${this._config.service_data}" >${this._config.title} `; From b7c34c483ae3eef6b609c26d47da0ed9660d6492 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Mon, 17 Dec 2018 03:07:59 -0600 Subject: [PATCH 50/82] :hammer: Fix for element positioning (#2335) * Fix for element positioning * Address comments --- .../demos/demo-hui-picture-elements-card.ts | 49 +++++++++++++++++++ .../cards/hui-picture-elements-card.ts | 20 ++++---- 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/gallery/src/demos/demo-hui-picture-elements-card.ts b/gallery/src/demos/demo-hui-picture-elements-card.ts index aa991d7706..8c01770306 100644 --- a/gallery/src/demos/demo-hui-picture-elements-card.ts +++ b/gallery/src/demos/demo-hui-picture-elements-card.ts @@ -76,6 +76,55 @@ const CONFIGS = [ left: 35% `, }, + { + heading: "Card with header", + config: ` +- type: picture-elements + image: /images/floorplan.png + title: My House + elements: + - type: service-button + title: Lights Off + style: + top: 97% + left: 90% + padding: 0px + service: light.turn_off + service_data: + entity_id: group.all_lights + - type: icon + icon: mdi:cctv + entity: camera.demo_camera + style: + top: 12% + left: 6% + transform: rotate(-60deg) scaleX(-1) + --iron-icon-height: 30px + --iron-icon-width: 30px + --iron-icon-stroke-color: black + --iron-icon-fill-color: rgba(50, 50, 50, .75) + - type: image + entity: light.bed_light + tap_action: + action: toggle + image: /images/light_bulb_off.png + state_image: + 'on': /images/light_bulb_on.png + state_filter: + 'on': brightness(130%) saturate(1.5) drop-shadow(0px 0px 10px gold) + 'off': brightness(80%) saturate(0.8) + style: + top: 35% + left: 65% + width: 7% + padding: 50px 50px 100px 50px + - type: state-icon + entity: binary_sensor.movement_backyard + style: + top: 8% + left: 35% + `, + }, ]; class DemoPicElements extends PolymerElement { diff --git a/src/panels/lovelace/cards/hui-picture-elements-card.ts b/src/panels/lovelace/cards/hui-picture-elements-card.ts index 02f669b612..83114f772e 100644 --- a/src/panels/lovelace/cards/hui-picture-elements-card.ts +++ b/src/panels/lovelace/cards/hui-picture-elements-card.ts @@ -63,15 +63,15 @@ class HuiPictureElementsCard extends LitElement implements LovelaceCard { return html` ${this.renderStyle()} -
+ ${ this._config.elements.map((elementConfig: LovelaceElementConfig) => this._createHuiElement(elementConfig) @@ -85,9 +85,9 @@ class HuiPictureElementsCard extends LitElement implements LovelaceCard { private renderStyle(): TemplateResult { return html` -
- ${ - this.localize("ui.panel.lovelace.editor.edit_card.edit") - } - - - +
+
+ ${ + this.localize("ui.panel.lovelace.editor.edit_card.edit") + } +
+
- - Move card to view - ${ - this.lovelace!.config.views.map((view, index) => { - if (index === this.path![0]) { - return; - } - return html` - ${view.title || "Unnamed view"} - `; - }) - } - - - + + + + + Move Card + ${ + this.localize("ui.panel.lovelace.editor.edit_card.delete") + } + + +
`; } @@ -127,12 +140,11 @@ export class HuiCardOptions extends hassLocalizeLitMixin(LitElement) { ); } - private _moveCard(ev: MouseEvent): void { - const lovelace = this.lovelace!; - const path = this.path!; - lovelace.saveConfig( - moveCard(lovelace.config, path, [(ev.currentTarget! as any).index]) - ); + private _moveCard(): void { + showMoveCardViewDialog(this, { + path: this.path!, + lovelace: this.lovelace!, + }); } private _deleteCard(): void { 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 new file mode 100644 index 0000000000..7f88c436cf --- /dev/null +++ b/src/panels/lovelace/editor/card-editor/hui-dialog-move-card-view.ts @@ -0,0 +1,106 @@ +import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; +import { TemplateResult } from "lit-html"; +import "@polymer/paper-dialog/paper-dialog"; +import "@polymer/paper-item/paper-item"; +// tslint:disable-next-line:no-duplicate-imports +import { PaperDialogElement } from "@polymer/paper-dialog/paper-dialog"; + +import { hassLocalizeLitMixin } from "../../../../mixins/lit-localize-mixin"; +import { moveCard } from "../config-util"; +import { MoveCardViewDialogParams } from "./show-move-card-view-dialog"; + +export class HuiDialogMoveCardView extends hassLocalizeLitMixin(LitElement) { + private _params?: MoveCardViewDialogParams; + + static get properties(): PropertyDeclarations { + return { + _params: {}, + }; + } + + public async showDialog(params: MoveCardViewDialogParams): Promise { + this._params = params; + await this.updateComplete; + } + + protected render(): TemplateResult { + if (!this._params) { + return html``; + } + return html` + + +

Choose view to move card

+ ${ + this._params!.lovelace!.config.views.map((view, index) => { + return html` + ${view.title} + `; + }) + } +
+ `; + } + + private get _dialog(): PaperDialogElement { + return this.shadowRoot!.querySelector("paper-dialog")!; + } + + private _moveCard(e: Event): void { + const newView = (e.currentTarget! as any).index; + const path = this._params!.path!; + if (newView === path[0]) { + return; + } + + const lovelace = this._params!.lovelace!; + + lovelace.saveConfig(moveCard(lovelace.config, path, [newView!])); + this._dialog.close(); + } + + private _openedChanged(ev: MouseEvent) { + if (!(ev.detail as any).value) { + this._params = undefined; + } + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-dialog-move-card-view": HuiDialogMoveCardView; + } +} + +customElements.define("hui-dialog-move-card-view", HuiDialogMoveCardView); diff --git a/src/panels/lovelace/editor/card-editor/hui-edit-card.ts b/src/panels/lovelace/editor/card-editor/hui-edit-card.ts index c793a97376..bd63979d8f 100644 --- a/src/panels/lovelace/editor/card-editor/hui-edit-card.ts +++ b/src/panels/lovelace/editor/card-editor/hui-edit-card.ts @@ -160,6 +160,7 @@ export class HuiEditCard extends hassLocalizeLitMixin(LitElement) { ? html`
`; } diff --git a/src/panels/lovelace/editor/card-editor/show-move-card-view-dialog.ts b/src/panels/lovelace/editor/card-editor/show-move-card-view-dialog.ts new file mode 100644 index 0000000000..5ffccaaa44 --- /dev/null +++ b/src/panels/lovelace/editor/card-editor/show-move-card-view-dialog.ts @@ -0,0 +1,35 @@ +import { fireEvent } from "../../../../common/dom/fire_event"; +import { Lovelace } from "../../types"; + +declare global { + // for fire event + interface HASSDomEvents { + "show-move-card-view": MoveCardViewDialogParams; + } +} + +let registeredDialog = false; + +export interface MoveCardViewDialogParams { + path: [number, number]; + lovelace: Lovelace; +} + +const registerEditCardDialog = (element: HTMLElement) => + fireEvent(element, "register-dialog", { + dialogShowEvent: "show-move-card-view", + dialogTag: "hui-dialog-move-card-view", + dialogImport: () => + import(/* webpackChunkName: "hui-dialog-move-card-view" */ "./hui-dialog-move-card-view"), + }); + +export const showMoveCardViewDialog = ( + element: HTMLElement, + moveCardViewDialogParams: MoveCardViewDialogParams +) => { + if (!registeredDialog) { + registeredDialog = true; + registerEditCardDialog(element); + } + fireEvent(element, "show-move-card-view", moveCardViewDialogParams); +}; diff --git a/src/panels/lovelace/hui-editor.ts b/src/panels/lovelace/hui-editor.ts index 7ebe72d96c..739b17609d 100644 --- a/src/panels/lovelace/hui-editor.ts +++ b/src/panels/lovelace/hui-editor.ts @@ -1,4 +1,5 @@ import { LitElement, html } from "@polymer/lit-element"; +import { classMap } from "lit-html/directives/classMap"; import { TemplateResult } from "lit-html"; import yaml from "js-yaml"; @@ -7,20 +8,27 @@ import "@polymer/app-layout/app-header/app-header"; import "@polymer/app-layout/app-toolbar/app-toolbar"; import "@polymer/paper-button/paper-button"; import "@polymer/paper-icon-button/paper-icon-button"; +import "@polymer/paper-spinner/paper-spinner"; import { Lovelace } from "./types"; import { hassLocalizeLitMixin } from "../../mixins/lit-localize-mixin"; +import "../../components/ha-icon"; + const TAB_INSERT = " "; class LovelaceFullConfigEditor extends hassLocalizeLitMixin(LitElement) { public lovelace?: Lovelace; public closeEditor?: () => void; private _haStyle?: DocumentFragment; + private _saving?: boolean; + private _changed?: boolean; static get properties() { return { lovelace: {}, + _saving: {}, + _changed: {}, }; } @@ -36,6 +44,9 @@ class LovelaceFullConfigEditor extends hassLocalizeLitMixin(LitElement) { >
Edit Config
Save +
@@ -44,6 +55,7 @@ class LovelaceFullConfigEditor extends hassLocalizeLitMixin(LitElement) { autocorrect="off" autocapitalize="off" spellcheck="false" + @input="${this._yamlChanged}" >
@@ -90,12 +102,13 @@ class LovelaceFullConfigEditor extends hassLocalizeLitMixin(LitElement) { app-header-layout { height: 100vh; } - app-toolbar { - background-color: #455a64; - } paper-button { font-size: 16px; } + app-toolbar { + background-color: var(--dark-background-color, #455a64); + color: var(--dark-text-color); + } .content { height: calc(100vh - 68px); @@ -112,20 +125,46 @@ class LovelaceFullConfigEditor extends hassLocalizeLitMixin(LitElement) { font-family: "Courier New", Courier, monospace; padding: 8px; } + + .save-button { + opacity: 0; + margin-left: -16px; + margin-top: -4px; + transition: opacity 1.5s; + } + + .saved { + opacity: 1; + } `; } - private _handleSave() { + private async _handleSave() { + this._saving = true; let value; try { value = yaml.safeLoad(this.textArea.value); } catch (err) { alert(`Unable to parse YAML: ${err}`); + this._saving = false; return; } - this.lovelace!.saveConfig(value); + try { + await this.lovelace!.saveConfig(value); + } catch (err) { + alert(`Unable to save YAML: ${err}`); + } + this._saving = false; + this._changed = false; + } + + private _yamlChanged() { + if (this._changed) { + return; + } + this._changed = true; } private get textArea(): HTMLTextAreaElement { diff --git a/src/panels/lovelace/hui-root.ts b/src/panels/lovelace/hui-root.ts index ca4fa8c9b9..b261529b38 100644 --- a/src/panels/lovelace/hui-root.ts +++ b/src/panels/lovelace/hui-root.ts @@ -319,6 +319,8 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { -ms-user-select: none; -webkit-user-select: none; -moz-user-select: none; + --dark-color: #455a64; + --text-dark-color: #fff; } ha-app-layout { @@ -330,7 +332,8 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) { text-transform: uppercase; } .edit-mode { - background-color: #455a64; + background-color: var(--dark-color, #455a64); + color: var(--text-dark-color); } .edit-mode div[main-title] { pointer-events: auto; From 32cd683b8a24f370d0efce22efcab535b1e18ba2 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 19 Dec 2018 14:42:39 +0100 Subject: [PATCH 63/82] Bumped version to 20181219.0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 592d744e5b..4490e6c065 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup( name="home-assistant-frontend", - version="20181211.0", + version="20181219.0", description="The Home Assistant frontend", url="https://github.com/home-assistant/home-assistant-polymer", author="The Home Assistant Authors", From 3c5fb6d1adbbe1c5289b5e1d1fbc0fc15f2c6335 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 19 Dec 2018 14:43:12 +0100 Subject: [PATCH 64/82] Update translations --- translations/bg.json | 59 ++++++++- translations/ca.json | 4 + translations/cs.json | 28 ++++- translations/da.json | 35 +++++- translations/de.json | 12 +- translations/en.json | 4 + translations/fi.json | 19 ++- translations/fr.json | 33 ++++- translations/he.json | 4 + translations/hr.json | 93 ++++++++++++-- translations/hu.json | 16 ++- translations/it.json | 30 ++++- translations/ko.json | 6 +- translations/lb.json | 13 +- translations/nl.json | 17 ++- translations/no.json | 4 + translations/pl.json | 4 + translations/ru.json | 24 ++-- translations/sk.json | 249 +++++++++++++++++++++++++++++++++++--- translations/sl.json | 4 + translations/sv.json | 27 ++++- translations/zh-Hant.json | 8 +- 22 files changed, 618 insertions(+), 75 deletions(-) diff --git a/translations/bg.json b/translations/bg.json index 123623a634..e7e24447ac 100644 --- a/translations/bg.json +++ b/translations/bg.json @@ -53,8 +53,8 @@ "on": "Регистриран" }, "motion": { - "off": "Чисто", - "on": "Регистрирано" + "off": "Без движение", + "on": "Движение" }, "occupancy": { "off": "Чисто", @@ -144,7 +144,8 @@ "performance": "Производителност", "high_demand": "Високо натоварване", "heat_pump": "Термопомпа", - "gas": "Газ" + "gas": "Газ", + "manual": "Ръчен режим" }, "configurator": { "configure": "Настройване", @@ -422,6 +423,10 @@ "event": "Събитие", "enter": "Влизане", "leave": "Излизане" + }, + "webhook": { + "label": "Webhook", + "webhook_id": "Webhook идентификатор" } } }, @@ -712,6 +717,47 @@ "required_fields": "Попълнете всички задължителни полета" } } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "Отметнати артикули", + "clear_items": "Изтрий отметнатите артикули", + "add_item": "Добави артикул" + } + }, + "editor": { + "edit_card": { + "header": "Конфигуриране на Карта", + "save": "Запази", + "toggle_editor": "Превключете редактора", + "pick_card": "Изберете картата, която искате да добавите.", + "add": "Добавяне на карта", + "edit": "Редактиране", + "delete": "Изтриване" + }, + "migrate": { + "header": "Несъвместима конфигурация", + "para_no_id": "Този елемент няма идентификатор. Моля, добавете идентификатор към този елемент в \"ui-lovelace.yaml\".", + "para_migrate": "Home Assistant може автоматично да добави идентификатори към всичките ви карти и изгледи, като натиска бутона \"Мигриране на конфигурация\".", + "migrate": "Мигриране на конфигурация" + }, + "header": "Редактиране на потребителския интерфейс", + "configure_ui": "Конфигуриране на потребителския интерфейс", + "edit_view": { + "header": "Конфигурация на изглед", + "add": "Добавяне на изглед", + "edit": "Редактиране на изгледа", + "delete": "Изтриване на изгледа" + }, + "save_config": { + "header": "Поемете контрол над потребителския интерфейс на Lovelace", + "para": "По подразбиране Home Assistant поддържа потребителския интерфейс, като го актуализира, когато нови обекти или компоненти на Lovelace станат достъпни. Ако поемете контрол, ние вече няма да правим автоматично промени вместо вас.", + "para_sure": "Наистина ли искате да поемете управлението на потребителския интерфейс?", + "cancel": "Няма значение", + "save": "Поемете контрола" + } + } } }, "sidebar": { @@ -720,7 +766,8 @@ }, "common": { "loading": "Зареждане", - "cancel": "Отмени" + "cancel": "Отмени", + "save": "Запази" }, "duration": { "day": "{count}{count, plural,\n one {ден}\n other {дни}\n}", @@ -780,7 +827,9 @@ "clear_code": "Изчистване", "disarm": "Деактивирaне", "arm_home": "Под охрана - вкъщи", - "arm_away": "Под охрана" + "arm_away": "Под охрана", + "arm_night": "Под охрана - нощ", + "armed_custom_bypass": "Потребителски байпас" }, "automation": { "last_triggered": "Последно задействане", diff --git a/translations/ca.json b/translations/ca.json index 6287c8b1a5..c6150a5951 100644 --- a/translations/ca.json +++ b/translations/ca.json @@ -423,6 +423,10 @@ "event": "Esdeveniment:", "enter": "Entrar", "leave": "Sortir" + }, + "webhook": { + "label": "Webhook", + "webhook_id": "ID de Webhook" } } }, diff --git a/translations/cs.json b/translations/cs.json index c8d3940366..a298eb373b 100644 --- a/translations/cs.json +++ b/translations/cs.json @@ -423,6 +423,10 @@ "event": "Událost:", "enter": "Vstup", "leave": "Opuštění" + }, + "webhook": { + "label": "Webhook", + "webhook_id": "Webhook ID" } } }, @@ -726,13 +730,32 @@ "edit_card": { "header": "Konfigurace karty", "save": "Uložit", - "toggle_editor": "Přepnout Editor" + "toggle_editor": "Přepnout Editor", + "pick_card": "Vyberte kartu, kterou chcete přidat.", + "add": "Přidat kartu", + "edit": "Upravit", + "delete": "Odstranit" }, "migrate": { "header": "Konfigurace není kompatibilní", "para_no_id": "Tento prvek nemá ID. Přidejte k tomuto prvku ID v 'ui-lovelace.yaml'.", "para_migrate": "Home Assistant může automaticky přidávat ID ke všem kartám a pohledům stisknutím tlačítka Migrate config.", "migrate": "Migrovat konfiguraci" + }, + "header": "Upravit UI", + "configure_ui": "Konfigurovat UI", + "edit_view": { + "header": "Zobrazit konfiguraci", + "add": "Přidat pohled", + "edit": "Upravit pohled", + "delete": "Odstranit pohled" + }, + "save_config": { + "header": "Převzít kontrolu nad vaší Lovelace UI", + "para": "Ve výchozím nastavení Home Assistant bude usprávovat vaše uživatelské rozhraní, aktualizovat při přidání nové entity nebo Lovelace komponenty. Pokud převezmete kontrolu nebudeme již provádět změny automaticky za vás.", + "para_sure": "Opravdu chcete převzít kontrolu nad uživalským rohraním ?", + "cancel": "Zahodit změnu", + "save": "Převzít kontrolu" } } } @@ -743,7 +766,8 @@ }, "common": { "loading": "Načítání", - "cancel": "Zrušit" + "cancel": "Zrušit", + "save": "Uložit" }, "duration": { "day": "{count} {count, plural,\none {den}\nother {dny}\n}", diff --git a/translations/da.json b/translations/da.json index 9c9d1aca1e..0ff3ba246a 100644 --- a/translations/da.json +++ b/translations/da.json @@ -423,6 +423,10 @@ "event": "Begivenhed", "enter": "Ankom", "leave": "Forlade" + }, + "webhook": { + "label": "Webhook", + "webhook_id": "Webhook-ID" } } }, @@ -605,6 +609,10 @@ "logout": "Log af", "change_password": { "header": "Skift adgangskode", + "current_password": "Nuværende adgangskode", + "new_password": "Ny adgangskode", + "confirm_new_password": "Bekræft ny adgangskode", + "error_required": "Påkrævet", "submit": "Gem og afslut" }, "mfa": { @@ -708,6 +716,30 @@ "required_fields": "Udfyld alle obligatoriske felter" } } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "Markerede elementer", + "clear_items": "Ryd markerede elementer", + "add_item": "Tilføj element" + } + }, + "editor": { + "migrate": { + "header": "Konfiguration ikke færdiggjort", + "migrate": "Migrer opsætning" + }, + "header": "Rediger UI", + "configure_ui": "Konfigurer UI", + "edit_view": { + "header": "Vis konfiguration" + }, + "edit_card": { + "edit": "Rediger", + "delete": "Slet" + } + } } }, "sidebar": { @@ -716,7 +748,8 @@ }, "common": { "loading": "Indlæser", - "cancel": "Annuller" + "cancel": "Annuller", + "save": "Gem" }, "duration": { "day": "{count} {count, plural,\none {dag}\nother {dage}\n}", diff --git a/translations/de.json b/translations/de.json index 5dbe8b5044..2beb15f3fd 100644 --- a/translations/de.json +++ b/translations/de.json @@ -365,7 +365,7 @@ "alias": "Name", "triggers": { "header": "Auslöser", - "introduction": "Auslöser starten automatisierte Abläufe. Es ist mögliche, mehrere Auslöser für dieselbe Abfolge zu definieren. Wenn ein Auslöser aktiviert wird, prüft Home Assistant die Bedingungen, sofern vorhanden, und führt die Aktion aus.\n\n[Erfahre mehr über Auslöser.](https:\/\/home-assistant.io\/docs\/automation\/trigger\/)", + "introduction": "Auslöser starten automatisierte Abläufe. Es ist möglich, mehrere Auslöser für dieselbe Abfolge zu definieren. Wenn ein Auslöser aktiviert wird, prüft Home Assistant die Bedingungen, sofern vorhanden, und führt die Aktion aus.\n\n[Erfahre mehr über Auslöser.](https:\/\/home-assistant.io\/docs\/automation\/trigger\/)", "add": "Auslöser hinzufügen", "duplicate": "Duplizieren", "delete": "Löschen", @@ -423,12 +423,16 @@ "event": "Ereignis:", "enter": "Betreten", "leave": "Verlassen" + }, + "webhook": { + "label": "Webhook", + "webhook_id": "Webhook ID" } } }, "conditions": { "header": "Bedingungen", - "introduction": "Bedingungen sind ein optionaler Bestandteil bei automatisierten Abläufen und können das Ausführen einer Aktion verhindern. Bedingungen sind Auslösern ähnlich, aber dennoch verschieden. Ein Auslöser beobachtet im System ablaufende Ereignisse, wohingegen Bedingungen nur den aktuellen Systemzustand betrachten. Ein Auslöser kann beobachten, dass ein Schalter aktiviert wird. Eine Bedingung kann lediglich sehen, ob ein Schalter aktuell an oder aus ist.\n\n[Erfahre mehr über Bedingungen.](https:\/\/home-assistant.io\/docs\/scripts\/conditions\/)", + "introduction": "Bedingungen sind ein optionaler Bestandteil bei automatisierten Abläufen und können das Ausführen einer Aktion verhindern. Bedingungen sind Auslösern ähnlich, aber dennoch verschieden. Ein Auslöser beobachtet im System ablaufende Ereignisse, wohingegen Bedingungen nur den aktuellen Systemzustand betrachten. Ein Auslöser kann beobachten, ob ein Schalter aktiviert wird. Eine Bedingung kann lediglich sehen, ob ein Schalter aktuell an oder aus ist.\n\n[Erfahre mehr über Bedingungen.](https:\/\/home-assistant.io\/docs\/scripts\/conditions\/)", "add": "Bedingung hinzufügen", "duplicate": "Duplizieren", "delete": "Löschen", @@ -735,6 +739,7 @@ "migrate": { "header": "Konfiguration inkompatibel", "para_no_id": "Dieses Element hat keine ID. Bitte füge diesem Element eine ID in 'ui-lovelace.yaml' hinzu.", + "para_migrate": "Home Assistant kann für alle Ihre Karten und Ansichten die IDs automatisch generieren, wenn Sie den \"Konfiguration migrieren\"-Button klicken.", "migrate": "Konfiguration migrieren" }, "header": "Benutzeroberfläche bearbeiten", @@ -746,6 +751,9 @@ "delete": "Ansicht löschen" }, "save_config": { + "header": "Lovelace Userinterface selbst verwalten", + "para": "Standardmäßig verwaltet Home Assistant Ihre Benutzeroberfläche und aktualisiert sie, sobald neue Entitäten oder Lovelace-Komponenten verfügbar sind. Wenn Sie die Verwaltung selbst übernehmen, nehmen wir für Sie keine Änderungen mehr vor.", + "para_sure": "Bist du dir sicher, dass du die Benutzeroberfläche selbst verwalten möchtest?", "cancel": "Abbrechen", "save": "Kontrolle übernehmen" } diff --git a/translations/en.json b/translations/en.json index b5d0c50e59..935b669e1f 100644 --- a/translations/en.json +++ b/translations/en.json @@ -423,6 +423,10 @@ "event": "Event:", "enter": "Enter", "leave": "Leave" + }, + "webhook": { + "label": "Webhook", + "webhook_id": "Webhook ID" } } }, diff --git a/translations/fi.json b/translations/fi.json index a1c5304b1c..2d8395b35c 100644 --- a/translations/fi.json +++ b/translations/fi.json @@ -719,13 +719,25 @@ "edit_card": { "header": "Kortti-asetukset", "save": "Tallenna", - "toggle_editor": "Vaihda editori" + "toggle_editor": "Vaihda editori", + "pick_card": "Valitse kortti jonka haluat lisätä", + "add": "Lisää kortti", + "edit": "Muokkaa", + "delete": "Poista" }, "migrate": { "header": "Epäkelvot asetukset", "para_no_id": "Elementillä ei ole ID. Lisää ID elementille 'ui-lovelace.yaml'-tiedostossa.", "para_migrate": "Home Assistant voi lisätä ID:t kaikkiin kortteihisi ja näkymiin automaattisesti painamalla 'Tuo vanhat asetukset'-nappia.", "migrate": "Tuo vanhat asetukset" + }, + "header": "Muokkaa käyttöliittymää", + "configure_ui": "Määrittele käyttöliittymä", + "edit_view": { + "header": "Näytä asetukset", + "add": "Lisää näkymä", + "edit": "Muokkaa näkymää", + "delete": "Poista näkymä" } } } @@ -736,7 +748,8 @@ }, "common": { "loading": "Ladataan", - "cancel": "Peruuta" + "cancel": "Peruuta", + "save": "Tallenna" }, "duration": { "day": "{count} {count, plural,\n one {päivä}\n other {päivää}\n}", @@ -755,7 +768,7 @@ "not_available": "Kuvaa ei saatavilla" }, "persistent_notification": { - "dismiss": "Peruuta" + "dismiss": "Hylkää" }, "scene": { "activate": "Aktivoi" diff --git a/translations/fr.json b/translations/fr.json index 2d1782d341..e39d403385 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -423,6 +423,10 @@ "event": "Événement :", "enter": "Entre", "leave": "Quitter" + }, + "webhook": { + "label": "Webhook", + "webhook_id": "ID Webhook" } } }, @@ -718,19 +722,40 @@ "cards": { "shopping-list": { "checked_items": "Éléments cochés", + "clear_items": "Effacer éléments cochés", "add_item": "Ajouter un élément" } }, "editor": { "edit_card": { + "header": "Configuration de la carte", "save": "Enregistrer", - "toggle_editor": "Activer\/désactiver l’éditeur" + "toggle_editor": "Activer\/désactiver l’éditeur", + "pick_card": "Choisissez l'automatisation à ajouter", + "add": "Ajouter une action", + "edit": "Modifier", + "delete": "Supprimer" }, "migrate": { "header": "Configuration incompatible", "para_no_id": "Cet élément n'a pas d'identifiant. Veuillez ajouter un identifiant à cet élément dans 'ui-lovelace.yaml'.", "para_migrate": "Home Assistant peut ajouter automatiquement des identifiants à toutes vos cartes et vues en appuyant sur le bouton «Migrer la configuration».", "migrate": "Migrer la configuration" + }, + "header": "Modifier l'interface utilisateur", + "configure_ui": "Configurer l'interface utilisateur", + "edit_view": { + "header": "Voir la configuration", + "add": "Ajouter la vue\n", + "edit": "Modifier la vue", + "delete": "Supprimer la vue" + }, + "save_config": { + "header": "Prenez le controle de Lovelace UI", + "para": "Par défaut Home Assistant va maintenir l'interface utilisateur, met à jour quand y'a de nouveaux entités ou composants de Lovelace sont disponibles. Si vous prenez le contrôle on ne fera plus de changements automatiques pour vous.", + "para_sure": "Êtes-vous sûr de vouloir prendre le controle de l'interface utilisateur?", + "cancel": "Oublie ce que j'ai dit, c'est pas grave.", + "save": "Prenez le contrôle" } } } @@ -741,7 +766,8 @@ }, "common": { "loading": "Chargement", - "cancel": "Annuler" + "cancel": "Annuler", + "save": "Enregistrer" }, "duration": { "day": "{count} {count, plural,\none {jour}\nother {jours}\n}", @@ -801,7 +827,8 @@ "clear_code": "Effacer", "disarm": "Désarmer", "arm_home": "Armer (domicile)", - "arm_away": "Armer (absent)" + "arm_away": "Armer (absent)", + "arm_night": "Armer nuit" }, "automation": { "last_triggered": "Dernier déclenchement", diff --git a/translations/he.json b/translations/he.json index cb3d396540..807450996b 100644 --- a/translations/he.json +++ b/translations/he.json @@ -423,6 +423,10 @@ "event": "אירוע:", "enter": "כניסה", "leave": "יציאה" + }, + "webhook": { + "label": "Webhook", + "webhook_id": "Webhook ID" } } }, diff --git a/translations/hr.json b/translations/hr.json index ff5c500471..747b55ad88 100644 --- a/translations/hr.json +++ b/translations/hr.json @@ -251,11 +251,13 @@ }, "vacuum": { "cleaning": "Čišćenje", + "docked": "Usidreni", "error": "Greška", "idle": "Besposlen", "off": "Ugašeno", "on": "Upaljeno", - "paused": "Pauzirano" + "paused": "Pauzirano", + "returning": "Povratak na dok" } }, "state_badge": { @@ -345,12 +347,24 @@ "unsaved_confirm": "Imate nespremljene izmjene. Jeste li sigurni da želite napustiti?", "alias": "Ime", "triggers": { + "header": "Okidači", "introduction": "Okidači su ono što pokreće obradu pravila o automatizaciji. Moguće je odrediti više okidača za isto pravilo. Kada pokrenete okidač, Home Assistant provjerit će uvjete, ako ih ima i pozvati akciju. \n\n [Saznajte više o pokretačima.] (Https:\/\/home-assistant.io\/docs\/automation\/trigger\/)", + "add": "Dodaj okidač", + "duplicate": "Udvostruči", "delete": "Obriši", + "delete_confirm": "Jeste li sigurni dai želite izbrisati?", "unsupported_platform": "Nepodržana platforma: {platform}", + "type_select": "Tip okidača", "type": { + "event": { + "label": "Događaj:", + "event_type": "Vrsta događaja", + "event_data": "Podaci o događaju" + }, "state": { + "label": "Stanje", "from": "Od", + "to": "Do", "for": "Za" }, "homeassistant": { @@ -361,7 +375,8 @@ }, "mqtt": { "label": "MQTT", - "topic": "Tema" + "topic": "Tema", + "payload": "Opterećenje (opcionalno)" }, "numeric_state": { "label": "Numeričko stanje", @@ -391,6 +406,10 @@ "event": "Event:", "enter": "Unesite", "leave": "Napustiti" + }, + "webhook": { + "label": "Webhook", + "webhook_id": "Webhook ID" } } }, @@ -474,8 +493,12 @@ } } }, + "script": { + "description": "Stvaranje i uređivanje skripti" + }, "zwave": { - "caption": "Z-Wave" + "caption": "Z-Wave", + "description": "Upravljajte mrežom Z-Wave" }, "users": { "caption": "Korisnici", @@ -632,7 +655,8 @@ "mfa": { "data": { "code": "Kôd autentifikacije s dva faktora" - } + }, + "description": "Otvori **{mfa_module_name}** na svojem uređaju kao bi vidio kod dvofaktorske autentikacije i provjerio svoj identitet:" } }, "error": { @@ -688,13 +712,32 @@ "edit_card": { "header": "Konfiguracija Kartice ", "save": "Spremi", - "toggle_editor": "Uključi uređivač" + "toggle_editor": "Uključi uređivač", + "pick_card": "Odaberite karticu koju želite dodati.", + "add": "Dodaj karticu", + "edit": "Uredi", + "delete": "Izbrisati" }, "migrate": { "header": "Konfiguracija nije kompatibilna", "para_no_id": "Ovaj element nema ID. Dodajte ID ovom elementu u 'ui-lovelace.yaml'.", "para_migrate": "Home Assistant može dodati ID-ove na sve vaše kartice i pogleda automatski za vas pritiskom na gumb 'Migriraj konfiguriranje'.", "migrate": "Migriraj konfiguraciju" + }, + "header": "Uredi UI", + "configure_ui": "Konfiguriraj UI", + "edit_view": { + "header": "Pogledaj konfiguraciju", + "add": "Dodaj prikaz", + "edit": "Uredi prikaz", + "delete": "Izbriši prikaz" + }, + "save_config": { + "header": "Preuzmite kontrolu nad Lovelace UI", + "para": "Home Assistant će prema zadanim postavkama održavati vaše korisničko sučelje, ažurirati ga kada novi entiteti ili Lovelace komponente postanu dostupni. Ako preuzmete kontrolu, više nećemo automatski vršiti izmjene za vas.", + "para_sure": "Jeste li sigurni da želite preuzeti kontrolu nad svojim korisničkim sučeljem?", + "cancel": "Nema veze", + "save": "Preuzmi kontrolu" } } } @@ -705,7 +748,8 @@ }, "common": { "loading": "Učitavam", - "cancel": "Otkazati" + "cancel": "Otkazati", + "save": "Spremi" }, "duration": { "day": "{count} {count, plural,\n one {dan}\n other {dani}\n}", @@ -736,21 +780,38 @@ "wind_speed": "Brzina vjetra" }, "cardinal_direction": { + "e": "I", + "ene": "ISI", "ese": "ESE", "n": "N", "ne": "NE", "nne": "NNE", - "nw": "NW" - } + "nw": "NW", + "nnw": "SSZ", + "s": "J", + "se": "JI", + "sse": "JJI", + "ssw": "JJZ", + "sw": "JZ", + "w": "Z", + "wnw": "ZSZ", + "wsw": "ZJZ" + }, + "forecast": "Prognoza" }, "alarm_control_panel": { "code": "Kod", + "clear_code": "Vedro", "disarm": "Deaktiviraj", "arm_home": "Aktiviran doma", "arm_away": "Aktiviran odsutno", "arm_night": "Aktiviran nočni", "armed_custom_bypass": "Prilagođena obilaznica" }, + "automation": { + "last_triggered": "Zadnje aktivirano", + "trigger": "Okidač" + }, "fan": { "speed": "Brzina", "oscillate": "Oscilirati", @@ -784,6 +845,8 @@ }, "vacuum": { "actions": { + "resume_cleaning": "Nastavi čišćenje", + "return_to_base": "Povratak na dok", "start_cleaning": "Započnite čišćenje", "turn_on": "Uključiti", "turn_off": "Isključiti" @@ -803,8 +866,14 @@ "entity": "Entitet" } }, + "service-picker": { + "service": "Usluga" + }, "relative_time": { - "past": "{vrijeme} prije" + "past": "{vrijeme} prije", + "duration": { + "week": "{count} {count, plural,\n jedan {week}\n ostali {weeks}\n}" + } }, "history_charts": { "loading_history": "Učitavanje povijesti stanja ...", @@ -814,7 +883,8 @@ "dialogs": { "more_info_settings": { "save": "Spremi", - "name": "Ime" + "name": "Ime", + "entity_id": "ID entiteta" } }, "auth_store": { @@ -863,7 +933,8 @@ "switch": "Prekidač", "updater": "Ažuriranje", "weblink": "WebLink", - "zwave": "Z-Wave" + "zwave": "Z-Wave", + "vacuum": "Vakuum" }, "attribute": { "weather": { diff --git a/translations/hu.json b/translations/hu.json index ba41a66451..e2d57415c7 100644 --- a/translations/hu.json +++ b/translations/hu.json @@ -423,6 +423,10 @@ "event": "Esemény:", "enter": "Érkezés", "leave": "Távozás" + }, + "webhook": { + "label": "Webhook", + "webhook_id": "Webhook ID" } } }, @@ -546,8 +550,8 @@ "no_device": "Entitások eszközök nélkül", "delete_confirm": "Biztosan törölni szeretnéd ezt az integrációt?", "restart_confirm": "Indítsd újra a Home Assistant-ot az integráció törlésének befejezéséhez", - "manuf": "Gyártó: {manufacturer}", - "hub": "Csatlakoztatva", + "manuf": "{manufacturer} által", + "hub": "Kapcsolódva", "firmware": "Firmware: {version}", "device_unavailable": "eszköz nem érhető el", "entity_unavailable": "entitás nem érhető el" @@ -620,7 +624,7 @@ "mfa_setup": { "title_aborted": "Megszakítva", "title_success": "Siker!", - "step_done": "Beállítás kész {step}", + "step_done": "{step} beállítás elvégezve", "close": "Bezárás", "submit": "Küldés" } @@ -699,7 +703,7 @@ } }, "page-onboarding": { - "intro": "Készen állsz arra, hogy felébreszd az otthonod, visszaszerezed a magánéleted és csatlakozz egy világhálós közösséghez?", + "intro": "Készen állsz arra, hogy felébreszd az otthonod, visszaszerezd a magánéleted és csatlakozz egy világhálós közösséghez?", "user": { "intro": "Kezdjük a felhasználói fiók létrehozásával.", "required_field": "Szükséges", @@ -734,8 +738,8 @@ }, "migrate": { "header": "Inkompatibilis Konfiguráció", - "para_no_id": "Ez az elem nem rendelkezik azonosítóval. Kérlek, adj hozzá egyet az 'ui-lovelace.yaml' fájlban!", - "para_migrate": "A Home Assistant a 'Konfiguráció áttelepítése' gomb megnyomásával az összes kártyához és nézethez automatikusan létre tud hozni azonosítókat.", + "para_no_id": "Ez az elem nem rendelkezik ID-val. Kérlek, adj hozzá egyet az 'ui-lovelace.yaml' fájlban!", + "para_migrate": "A Home Assistant a 'Konfiguráció áttelepítése' gomb megnyomásával az összes kártyához és nézethez automatikusan létre tud hozni ID-kat.", "migrate": "Konfiguráció áttelepítése" }, "header": "Felhasználói felület szerkesztése", diff --git a/translations/it.json b/translations/it.json index 60fc3a16db..08697ee5e2 100644 --- a/translations/it.json +++ b/translations/it.json @@ -423,6 +423,10 @@ "event": "Evento", "enter": "Ingresso", "leave": "Uscita" + }, + "webhook": { + "label": "Webhook", + "webhook_id": "Webhook ID" } } }, @@ -726,13 +730,32 @@ "edit_card": { "header": "Configurazione della scheda", "save": "Salva", - "toggle_editor": "Attiva \/ disattiva l'editor" + "toggle_editor": "Attiva \/ disattiva l'editor", + "pick_card": "Scegliere la scheda che si desidera aggiungere.", + "add": "Aggiungi scheda", + "edit": "Modifica", + "delete": "Elimina" }, "migrate": { "header": "Configurazione incompatibile", "para_no_id": "Questo elemento non ha un ID. Aggiungi un ID a questo elemento in 'ui-lovelace.yaml'.", "para_migrate": "Home Assistant può aggiungere automaticamente gli ID a tutte le tue schede e visualizzazioni automaticamente premendo il pulsante \"Eporta configurazione\".", "migrate": "Esporta configurazione" + }, + "header": "Modifica dell'interfaccia utente", + "configure_ui": "Configurare l'interfaccia utente", + "edit_view": { + "header": "Visualizza configurazione", + "add": "Aggiungi vista", + "edit": "Modifica vista", + "delete": "Cancella vista" + }, + "save_config": { + "header": "Prendi il controllo della tua interfaccia utente di Lovelace", + "para": "Per impostazione predefinita, Home Assistant manterrà l'interfaccia utente, aggiornandola quando nuove entità o componenti Lovelace diventano disponibili. Se prendi il controllo non effettueremo più automaticamente le modifiche per te.", + "para_sure": "Sei sicuro di voler prendere il controllo della tua interfaccia utente?", + "cancel": "Non importa", + "save": "Prendere il controllo" } } } @@ -743,7 +766,8 @@ }, "common": { "loading": "Caricamento", - "cancel": "Annulla" + "cancel": "Annulla", + "save": "Salva" }, "duration": { "day": "{count} {count, plural,\none {giorno}\nother {giorni}\n}", @@ -802,7 +826,7 @@ "code": "Codice", "clear_code": "Canc", "disarm": "Disattivato", - "arm_home": "Attivo in casa", + "arm_home": "Attiva In casa", "arm_away": "Attiva Fuori Casa", "arm_night": "Attiva Notte", "armed_custom_bypass": "Attiva con bypass" diff --git a/translations/ko.json b/translations/ko.json index 37a9ec5b85..6326175fce 100644 --- a/translations/ko.json +++ b/translations/ko.json @@ -423,6 +423,10 @@ "event": "이벤트:", "enter": "입장", "leave": "퇴장" + }, + "webhook": { + "label": "Webhook", + "webhook_id": "Webhook ID" } } }, @@ -751,7 +755,7 @@ "para": "기본적으로 Home Assistant 는 사용자 인터페이스를 유지 관리하고, 사용할 수 있는 새로운 구성요소 또는 Lovelace 구성요소가 있을 때 업데이트를 합니다. 사용자가 직접 관리하는 경우 Home Assistant 는 더 이상 자동으로 변경하지 않습니다.", "para_sure": "사용자 인터페이스를 직접 관리하시겠습니까?", "cancel": "아닙니다", - "save": "직접 관리할께요" + "save": "직접 관리할게요" } } } diff --git a/translations/lb.json b/translations/lb.json index 98c7829ee3..afe88eacf1 100644 --- a/translations/lb.json +++ b/translations/lb.json @@ -423,6 +423,10 @@ "event": "Evenement:", "enter": "Eran", "leave": "Verloossen" + }, + "webhook": { + "label": "Webhook", + "webhook_id": "Webhook ID" } } }, @@ -473,7 +477,7 @@ }, "actions": { "header": "Aktiounen", - "introduction": "Aktioune déi den HomeAssistant ausféiert wann den Automatisme ausgeléist gouf.\n[Léier méi iwwert Aktioune.](https:\/\/home-assistant.io\/docs\/automation\/action\/)", + "introduction": "Aktioune déi den Home Assistant ausféiert wann den Automatisme ausgeléist gouf.\n[Léier méi iwwert Aktioune.](https:\/\/home-assistant.io\/docs\/automation\/action\/)", "add": "Aktioun dobäisetzen", "duplicate": "Replikéiere", "delete": "Läschen", @@ -581,7 +585,7 @@ "created_at": "Erstallt um {date}", "confirm_delete": "Sécher fir den Erneierungs Token fir {name} ze läsche?", "delete_failed": "Fehler beim läschen vum Erneierungs Token", - "last_used": "Läscht benotz um {date} vun {location}", + "last_used": "Fir d'Läscht benotzt um {date} vun {location}", "not_used": "Nach nie benotzt ginn", "current_token_tooltip": "Fehler beim läschen vum aktuellen Erneierungs Token" }, @@ -748,6 +752,7 @@ }, "save_config": { "header": "Kontroll iwwert Loveloce UI iwwerhuelen", + "para": "Standardméisseg verwalt Home Assistant de Benotzer Interface an aktualiséiert en soubal nei Entitéiten oder Lovelace-Komponenten disponibel sinn. Wann dir d'Kontrolle iwwerhuelt, kënne mir keng automatesch Ännerung méi fir iech maachen.", "para_sure": "Sécher fir d'Kontrolle iwwert de Benotzer Interface z'iwwerhuelen?", "cancel": "Vergiess et", "save": "Kontroll iwwerhuelen" @@ -910,8 +915,8 @@ } }, "notification_toast": { - "entity_turned_on": "{entity} gouf ausgeschalt", - "entity_turned_off": "{entity} gouf ugeschalt", + "entity_turned_on": "{entity} gouf ugeschalt", + "entity_turned_off": "{entity} gouf ausgeschalt", "service_called": "Service {service} operuff", "service_call_failed": "Fehler beim opruffen vun {service}", "connection_lost": "Verbindung verluer. Verbindung gëtt nees opgebaut..." diff --git a/translations/nl.json b/translations/nl.json index f8c4c8c005..001564a852 100644 --- a/translations/nl.json +++ b/translations/nl.json @@ -423,6 +423,10 @@ "event": "Gebeurtenis:", "enter": "Betreden", "leave": "Verlaten" + }, + "webhook": { + "label": "Webhook", + "webhook_id": "Webhook ID" } } }, @@ -726,13 +730,21 @@ "edit_card": { "header": "Kaart configuratie", "save": "Opslaan", - "toggle_editor": "Toggle Editor" + "toggle_editor": "Toggle Editor", + "delete": "Verwijder" }, "migrate": { "header": "Configuratie incompatibel", "para_no_id": "Dit element heeft geen ID. Voeg een ID toe aan dit element in 'ui-lovelace.yaml'.", "para_migrate": "Home Assistant kan ID's voor al je kaarten en weergaven automatisch voor je toevoegen door op de knop 'Migrate config' te klikken.", "migrate": "Configuratie migreren" + }, + "edit_view": { + "header": "Bekijk de configuratie" + }, + "save_config": { + "cancel": "Laat maar", + "save": "Neem over" } } } @@ -743,7 +755,8 @@ }, "common": { "loading": "Bezig met laden", - "cancel": "Annuleren" + "cancel": "Annuleren", + "save": "Bewaar" }, "duration": { "day": "{count} {count, plural,\none {dag}\nother {dagen}\n}", diff --git a/translations/no.json b/translations/no.json index eabe963409..e52ee5d6ff 100644 --- a/translations/no.json +++ b/translations/no.json @@ -423,6 +423,10 @@ "event": "Hendelse:", "enter": "Ankommer", "leave": "Forlater" + }, + "webhook": { + "label": "Webhook", + "webhook_id": "Webhook ID" } } }, diff --git a/translations/pl.json b/translations/pl.json index 91ef3e2103..290e863471 100644 --- a/translations/pl.json +++ b/translations/pl.json @@ -423,6 +423,10 @@ "event": "Zdarzenie", "enter": "Wprowadź", "leave": "Opuść" + }, + "webhook": { + "label": "Webhook", + "webhook_id": "Identyfikator Webhook" } } }, diff --git a/translations/ru.json b/translations/ru.json index 1f0489d37e..32df77c24f 100644 --- a/translations/ru.json +++ b/translations/ru.json @@ -101,8 +101,8 @@ "on": "Охлаждение" }, "door": { - "off": "Закрыто", - "on": "Открыто" + "off": "Закрыта", + "on": "Открыта" }, "garage_door": { "off": "Закрыто", @@ -182,20 +182,20 @@ "problem": "Проблема" }, "input_boolean": { - "off": "Выключен", - "on": "Включен" + "off": "Выкл", + "on": "Вкл" }, "light": { - "off": "Выключен", - "on": "Включен" + "off": "Выкл", + "on": "Вкл" }, "lock": { "locked": "Закрыт", "unlocked": "Открыт" }, "media_player": { - "off": "Выключен", - "on": "Включен", + "off": "Выкл", + "on": "Вкл", "playing": "Воспроизведение", "paused": "Пауза", "idle": "Ожидание", @@ -206,8 +206,8 @@ "problem": "Проблема" }, "remote": { - "off": "Выключено", - "on": "Включено" + "off": "Выкл", + "on": "Вкл" }, "scene": { "scening": "Переход к сцене" @@ -423,6 +423,10 @@ "event": "Событие:", "enter": "Войти", "leave": "Покинуть" + }, + "webhook": { + "label": "Webhook", + "webhook_id": "Идентификатор Webhook" } } }, diff --git a/translations/sk.json b/translations/sk.json index ff0f983fc4..a5a5764fb1 100644 --- a/translations/sk.json +++ b/translations/sk.json @@ -13,7 +13,8 @@ "dev-templates": "Šablóny", "dev-mqtt": "MQTT", "dev-info": "Info", - "calendar": "Kalendár" + "calendar": "Kalendár", + "profile": "Profil" }, "state": { "default": { @@ -116,8 +117,8 @@ "on": "Otvorené" }, "lock": { - "off": "Zamknuté", - "on": "Odomknuté" + "off": "Zamknutý", + "on": "Odomknutý" } }, "calendar": { @@ -166,17 +167,17 @@ "on": "Zapnutý" }, "group": { - "off": "Vypnuté", - "on": "Zapnuté", + "off": "Vypnutá", + "on": "Zapnutá", "home": "Doma", "not_home": "Preč", - "open": "Otvorené", + "open": "Otvorená", "opening": "Otvára sa", - "closed": "Zatvorené", + "closed": "Zatvorená", "closing": "Zatvára sa", "stopped": "Zastavené", - "locked": "Zamknuté", - "unlocked": "Odomknuté", + "locked": "Zamknutá", + "unlocked": "Odomknutá", "ok": "OK", "problem": "Problém" }, @@ -274,14 +275,14 @@ "alarm_control_panel": { "armed": "Zakód", "disarmed": "Odkód", - "armed_home": "Aktívny", - "armed_away": "Aktívny", - "armed_night": "Aktívny", + "armed_home": "Zakód", + "armed_away": "Zakód", + "armed_night": "Zakód", "pending": "Čaká", "arming": "Aktivácia", "disarming": "Deakt", "triggered": "Alarm", - "armed_custom_bypass": "Zapnutý" + "armed_custom_bypass": "Zakódovaný" }, "device_tracker": { "home": "Doma", @@ -300,7 +301,7 @@ "period": "Obdobie" }, "logbook": { - "showing_entries": "Zobrazujú sa záznamy pre" + "showing_entries": "Zobrazujú sa záznamy za obdobie" }, "mailbox": { "empty": "Nemáte žiadne správy", @@ -380,7 +381,8 @@ "state": { "label": "Stav", "from": "Z", - "to": "Na" + "to": "Na", + "for": "Trvanie stavu" }, "homeassistant": { "label": "Home Assistant", @@ -421,6 +423,10 @@ "event": "Udalosť:", "enter": "Vstúpenie", "leave": "Opustenie" + }, + "webhook": { + "label": "Webhook", + "webhook_id": "Webhook ID" } } }, @@ -497,7 +503,7 @@ }, "event": { "label": "Odpáliť udalosť", - "event": "Udalosť", + "event": "Udalosť:", "service_data": "Dáta služby" } } @@ -525,6 +531,31 @@ "deactivate_user": "Deaktivovať používateľa", "delete_user": "Vymazať používateľa" } + }, + "cloud": { + "caption": "Home Assistant Cloud", + "description_login": "Prihlásený ako {email}", + "description_not_login": "Neprihlásený" + }, + "integrations": { + "caption": "Integrácie", + "description": "Spravovať pripojené zariadenia a služby", + "discovered": "Objavené", + "configured": "Nakonfigurovaný", + "new": "Nastaviť novú integráciu", + "configure": "Konfigurovať", + "none": "Nič zatiaľ nebolo nakonfigurované", + "config_entry": { + "no_devices": "Táto integrácia nemá žiadne zariadenia.", + "no_device": "Entity bez zariadení", + "delete_confirm": "Naozaj chcete odstrániť túto integráciu?", + "restart_confirm": "Ak chcete dokončiť odstránenie tejto integrácie, reštartujte Home Assistant", + "manuf": "od {manufacturer}", + "hub": "Pripojené cez", + "firmware": "Firmvér: {version}", + "device_unavailable": "zariadenie nie je dostupné", + "entity_unavailable": "Entita nie je dostupná" + } } }, "profile": { @@ -546,20 +577,187 @@ "error_no_theme": "Nie sú k dispozícii žiadne témy.", "link_promo": "Získajte viac informácií o témach", "dropdown_label": "Téma" + }, + "refresh_tokens": { + "header": "Obnovovacie Tokeny", + "description": "Každý obnovovací token predstavuje prihlásenú reláciu. Obnovovacie tokeny sa po kliknutí na tlačidlo Odhlásiť sa automaticky odstránia. Pre váš účet sú aktívne nasledovné obnovovacie tokeny.", + "token_title": "Obnovovací token pre {clientId}", + "created_at": "Vytvorený {date}", + "confirm_delete": "Naozaj chcete odstrániť obnovovací token pre {name} ?", + "delete_failed": "Nepodarilo sa odstrániť obnovovací token", + "last_used": "Naposledy použitý {date} z {location}", + "not_used": "Nikdy nebol použitý", + "current_token_tooltip": "Nedá sa odstrániť aktuálny obnovovací token" + }, + "long_lived_access_tokens": { + "header": "Prístupové tokeny s dlhou životnosťou", + "description": "Vytvorte prístupové tokeny s dlhou životnosťou, ktoré umožnia vašim skriptom komunikovať s vašou inštanciou Home Assistant. Každý token bude platný 10 rokov od vytvorenia. Nasledujúce prístupové tokeny s dlhou životnosťou sú v súčasnosti aktívne.", + "learn_auth_requests": "Zistite, ako vytvárať overené požiadavky.", + "created_at": "Vytvorený {date}", + "confirm_delete": "Naozaj chcete odstrániť prístupový token pre {name} ?", + "delete_failed": "Nepodarilo sa odstrániť prístupový token.", + "create": "Vytvoriť Token", + "create_failed": "Nepodarilo sa vytvoriť prístupový token.", + "prompt_name": "Názov?", + "prompt_copy_token": "Skopírujte svoj nový prístupový token. Znova sa nezobrazí.", + "empty_state": "Nemáte žiadne prístupové tokeny s dlhou životnosťou.", + "last_used": "Naposledy použitý {date} z {location}", + "not_used": "Nikdy nebol použitý" + }, + "current_user": "Momentálne ste prihlásení ako {fullName} .", + "is_owner": "Ste vlastníkom.", + "logout": "Odhlásiť sa", + "change_password": { + "header": "Zmena hesla", + "current_password": "Aktuálne heslo", + "new_password": "Nové heslo", + "confirm_new_password": "Potvrďte nové heslo", + "error_required": "Požadované", + "submit": "Odoslať" + }, + "mfa": { + "header": "Multifaktorové autentifikačné moduly", + "disable": "Zakázať", + "enable": "Povoliť", + "confirm_disable": "Naozaj chcete zakázať {name} ?" + }, + "mfa_setup": { + "title_aborted": "Prerušené", + "title_success": "Úspech!", + "step_done": "Nastavenie dokončené krok {step} ", + "close": "Zavrieť", + "submit": "Odoslať" } }, "page-authorize": { + "initializing": "Inicializácia", + "authorizing_client": "Chystáte sa poskytnúť {clientId} prístup k vašej inštancii Home Assistantu.", + "logging_in_with": "Prihlasovanie pomocou ** {authProviderName} **.", + "pick_auth_provider": "Alebo sa prihláste prostredníctvom", + "abort_intro": "Prihlásenie bolo zrušené", "form": { + "working": "Prosím čakajte", + "unknown_error": "Niečo sa pokazilo", "providers": { + "homeassistant": { + "step": { + "init": { + "data": { + "username": "Používateľské meno", + "password": "Heslo" + } + }, + "mfa": { + "data": { + "code": "Kód dvojfaktorovej autentifikácie" + }, + "description": "Otvorte ** {mfa_module_name} ** v zariadení, aby ste si pozreli svoj dvojfaktorový autentifikačný kód a overili svoju totožnosť:" + } + }, + "error": { + "invalid_auth": "Nesprávne používateľské meno alebo heslo", + "invalid_code": "Neplatný overovací kód" + }, + "abort": { + "login_expired": "Platnosť relácie skončila, prosím prihláste znova." + } + }, + "legacy_api_password": { + "step": { + "init": { + "data": { + "password": "Heslo API rozhrania" + }, + "description": "Prosím zadajte heslo API rozhrania v konfigurácií http:" + }, + "mfa": { + "data": { + "code": "Kód dvojfaktorovej autentifikácie" + }, + "description": "Otvorte **{mfa_module_name}** na vašom zariadení a pozrite si kód dvojfaktorovej autentifikácie a overte svoju totožnosť." + } + }, + "error": { + "invalid_auth": "Neplatné heslo rozhrania API", + "invalid_code": "Neplatný autentifikačný kód" + }, + "abort": { + "no_api_password_set": "Nemáte nakonfigurované heslo rozhrania API.", + "login_expired": "Relácia vypršala, prosím prihláste sa znova." + } + }, "trusted_networks": { "step": { "init": { + "data": { + "user": "Používateľ" + }, "description": "Välj en användare att logga in som:" } + }, + "abort": { + "not_whitelisted": "Váš počítač nie je v zozname povolených zariadení." } } } } + }, + "page-onboarding": { + "intro": "Ste pripravení prebudiť váš domov, získať vaše súkromie a pripojiť sa k celosvetovej komunite bastličov?", + "user": { + "intro": "Poďme začať vytvorením používateľského konta.", + "required_field": "Požadované", + "data": { + "name": "Meno", + "username": "Používateľské meno", + "password": "Heslo" + }, + "create_account": "Vytvoriť účet", + "error": { + "required_fields": "Vyplňte všetky povinné polia" + } + } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "Začiarknuté položky", + "clear_items": "Vymažte označené položky", + "add_item": "Pridať položku" + } + }, + "editor": { + "edit_card": { + "header": "Konfigurácia karty", + "save": "Uložiť", + "toggle_editor": "Prepnúť Editor", + "pick_card": "Vyberte kartu, ktorú chcete pridať.", + "add": "Pridať kartu", + "edit": "Upraviť", + "delete": "Vymazať" + }, + "migrate": { + "header": "Nekompatibilná konfigurácia", + "para_no_id": "Tento prvok nemá ID. Pridajte ID k tomuto prvku v ui-lovelace.yaml.", + "para_migrate": "Home Assistant dokáže automaticky pridať ID na všetky vaše karty a zobrazenia stlačením tlačidla Migrácia konfigurácie.", + "migrate": "Migrácia konfigurácie" + }, + "header": "Úprava používateľského rozhrania", + "configure_ui": "Konfigurácia používateľského rozhrania", + "edit_view": { + "header": "Konfigurácia zobrazenia", + "add": "Pridať zobrazenie", + "edit": "Upraviť zobrazenie", + "delete": "Odstrániť zobrazenie" + }, + "save_config": { + "header": "Prevziať kontrolu vášho Lovelace rozhrania", + "para": "Štandardne Home Assistant bude udržiavať vaše užívateľské rozhranie a aktualizovať ho, keď budú k dispozícii nové entity alebo komponenty služby Lovelace. Ak prevezmete kontrolu, nebudeme už automaticky robiť zmeny.", + "para_sure": "Naozaj chcete prevziať kontrolu vášho užívateľského rozhrania?", + "cancel": "Nevadí", + "save": "Prevziať kontrolu" + } + } } }, "sidebar": { @@ -568,7 +766,8 @@ }, "common": { "loading": "Načítava sa", - "cancel": "Zrušiť" + "cancel": "Zrušiť", + "save": "Uložiť" }, "duration": { "day": "{count} {count, plural,\none {deň}\nfew {dni}\nother {dní}\n}", @@ -628,7 +827,9 @@ "clear_code": "Zrušiť", "disarm": "Odkódovať", "arm_home": "Zakódovať doma", - "arm_away": "Zakódovať odchod" + "arm_away": "Zakódovať odchod", + "arm_night": "Zakódovať na noc", + "armed_custom_bypass": "Prispôsobené vylúčenie" }, "automation": { "last_triggered": "Naposledy spustené", @@ -678,6 +879,13 @@ "turn_on": "Zapnúť", "turn_off": "Vypnúť" } + }, + "water_heater": { + "currently": "Aktuálne", + "on_off": "Zapnúť \/ vypnúť", + "target_temperature": "Cieľová teplota", + "operation": "V prevádzke", + "away_mode": "Režim neprítomnosti" } }, "components": { @@ -724,6 +932,11 @@ "ask": "Chcete tieto prihlasovacie údaje uložiť?", "decline": "Nie ďakujem", "confirm": "Uložiť prihlasovacie údaje" + }, + "notification_drawer": { + "click_to_configure": "Kliknutím na tlačidlo nakonfigurujete {entity}", + "empty": "Žiadne upozornenia", + "title": "Upozornenia" } }, "domain": { diff --git a/translations/sl.json b/translations/sl.json index 09be57ec64..150082c742 100644 --- a/translations/sl.json +++ b/translations/sl.json @@ -423,6 +423,10 @@ "event": "Dogodek:", "enter": "Vnesite", "leave": "Odidi" + }, + "webhook": { + "label": "Webhook", + "webhook_id": "Webhook ID" } } }, diff --git a/translations/sv.json b/translations/sv.json index 419a226696..f9d8808532 100644 --- a/translations/sv.json +++ b/translations/sv.json @@ -423,6 +423,10 @@ "event": "Händelse", "enter": "Ankommer", "leave": "Lämnar" + }, + "webhook": { + "label": "Webhook", + "webhook_id": "Webhook ID" } } }, @@ -726,13 +730,31 @@ "edit_card": { "header": "Kortkonfiguration", "save": "Spara", - "toggle_editor": "Visa \/ Dölj redigerare" + "toggle_editor": "Visa \/ Dölj redigerare", + "pick_card": "Välj det kort du vill lägga till.", + "add": "Lägg till kort", + "edit": "Redigera", + "delete": "Ta bort" }, "migrate": { "header": "Konfigurationen är inte giltig", "para_no_id": "Det här elementet har inget ID. Lägg till ett ID till det här elementet i \"ui-lovelace.yaml\".", "para_migrate": "Home Assistant kan automatiskt lägga till IDn till alla dina kort och vyer genom att du klickar på \"Migrera konfiguration\".", "migrate": "Migrera konfigurationen" + }, + "header": "Ändra användargränssnittet", + "configure_ui": "Konfigurera användargränssnittet", + "edit_view": { + "header": "Visa konfiguration", + "add": "Lägg till vy", + "edit": "Redigera vy", + "delete": "Radera vy" + }, + "save_config": { + "header": "Ta kontroll över din Lovelace UI", + "para_sure": "Är du säker på att du vill ta kontroll över ditt användargränssnitt?", + "cancel": "Glöm det", + "save": "Ta kontroll" } } } @@ -743,7 +765,8 @@ }, "common": { "loading": "Läser in", - "cancel": "Avbryt" + "cancel": "Avbryt", + "save": "Spara" }, "duration": { "day": "{count} {count, plural,\none {dag}\nother {dagar}\n}", diff --git a/translations/zh-Hant.json b/translations/zh-Hant.json index 7914810c0f..5c83df2a18 100644 --- a/translations/zh-Hant.json +++ b/translations/zh-Hant.json @@ -423,6 +423,10 @@ "event": "事件:", "enter": "進入區域", "leave": "離開區域" + }, + "webhook": { + "label": "Webhook", + "webhook_id": "Webhook ID" } } }, @@ -750,8 +754,8 @@ "header": "自行編輯 Lovelace UI", "para": "Home Assistant 於預設下,將維護您的使用者介面、於新物件或 Lovelace 元件可使用時進行更新。假如選擇自行編輯,系統將不再為您自動進行變更。", "para_sure": "確定要自行編輯使用者介面?", - "cancel": "取消", - "save": "儲存" + "cancel": "我再想想", + "save": "自行編輯" } } } From 2e750dc1e2ee63f9888930d4031dcee122696ce9 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Fri, 21 Dec 2018 06:53:26 -0600 Subject: [PATCH 65/82] =?UTF-8?q?=E2=9C=A8=20UI=20Editor=20for=20`map`=20c?= =?UTF-8?q?ard=20(#2287)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * :sparkles: UI Editor for `map` card * Address review comments * Revert change properly * Address review comments * Note to change to interface after LL conversion * Remove config options if empty Should apply to other editors * entitites is required * cleanup * cleanup * Fix for number values * Name chunk * Remove zoom default --- src/panels/lovelace/cards/hui-map-card.js | 17 +++ .../config-elements/hui-map-card-editor.ts | 143 ++++++++++++++++++ 2 files changed, 160 insertions(+) create mode 100644 src/panels/lovelace/editor/config-elements/hui-map-card-editor.ts diff --git a/src/panels/lovelace/cards/hui-map-card.js b/src/panels/lovelace/cards/hui-map-card.js index e6dd8960e6..a77a0afc01 100644 --- a/src/panels/lovelace/cards/hui-map-card.js +++ b/src/panels/lovelace/cards/hui-map-card.js @@ -11,7 +11,24 @@ import computeStateName from "../../../common/entity/compute_state_name"; import debounce from "../../../common/util/debounce"; import parseAspectRatio from "../../../common/util/parse-aspect-ratio"; +// should be interface when converted to TS +export const Config = { + title: "", + aspect_ratio: "", + default_zoom: 14, + entities: [], +}; + class HuiMapCard extends PolymerElement { + static async getConfigElement() { + await import(/* webpackChunkName: "hui-map-card-editor" */ "../editor/config-elements/hui-map-card-editor"); + return document.createElement("hui-map-card-editor"); + } + + static getStubConfig() { + return { entities: [] }; + } + static get template() { return html` + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "zha-network": ZHANetwork; + } +} + +customElements.define("zha-network", ZHANetwork); diff --git a/src/translations/en.json b/src/translations/en.json index 068a169d9c..cb2e5b6a0e 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -35,6 +35,7 @@ "updater": "Updater", "vacuum": "Vacuum", "weblink": "Weblink", + "zha": "ZHA", "zwave": "Z-Wave" }, "panel": { @@ -764,6 +765,10 @@ "delete_user": "Delete user" } }, + "zha": { + "caption": "ZHA", + "description": "Zigbee Home Automation network management" + }, "zwave": { "caption": "Z-Wave", "description": "Manage your Z-Wave network" diff --git a/translations/en.json b/translations/en.json index 935b669e1f..84c65942cf 100644 --- a/translations/en.json +++ b/translations/en.json @@ -514,6 +514,13 @@ "caption": "Script", "description": "Create and edit scripts" }, + "zha": { + "caption": "ZHA", + "description": "Manage your Zigbee Home Automation network", + "network": { + "introduction": "Zigbee Home Automation network management" + } + }, "zwave": { "caption": "Z-Wave", "description": "Manage your Z-Wave network" @@ -974,6 +981,7 @@ "switch": "Switch", "updater": "Updater", "weblink": "Weblink", + "zha": "ZHA", "zwave": "Z-Wave", "vacuum": "Vacuum" }, From ad113367e6c7eb33464baaa04e93e011bb4f2458 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Mon, 7 Jan 2019 03:06:59 +0100 Subject: [PATCH 75/82] =?UTF-8?q?=F0=9F=9B=A0=EF=B8=8F=20Small=20fixes=20t?= =?UTF-8?q?o=20sensor=20editor=20(#2415)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Small fixes to sensor editor * any -> string | number --- .../editor/config-elements/hui-sensor-card-editor.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 56a6335319..dcf108c3ed 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 @@ -56,23 +56,23 @@ export class HuiSensorCardEditor extends hassLocalizeLitMixin(LitElement) } get _graph(): string { - return this._config!.graph || "line"; + return this._config!.graph || "none"; } get _unit(): string { return this._config!.unit || ""; } - get _detail(): number { - return this._config!.number || 1; + get _detail(): number | string { + return this._config!.number || "1"; } get _theme(): string { return this._config!.theme || "default"; } - get _hours_to_show(): number { - return this._config!.hours_to_show || 24; + get _hours_to_show(): number | string { + return this._config!.hours_to_show || "24"; } protected render(): TemplateResult { @@ -109,7 +109,7 @@ export class HuiSensorCardEditor extends hassLocalizeLitMixin(LitElement) @value-changed="${this._valueChanged}" > From 3f6a8cac80a5a53b0b4f389055057b7711518ce7 Mon Sep 17 00:00:00 2001 From: hulkhaugen Date: Mon, 7 Jan 2019 10:40:12 +0100 Subject: [PATCH 76/82] Removed excessive bracket in css (#2411) * Removed excessive bracket in css code * lint --- src/cards/ha-weather-card.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/cards/ha-weather-card.js b/src/cards/ha-weather-card.js index ce9ac0152d..320558e0ee 100644 --- a/src/cards/ha-weather-card.js +++ b/src/cards/ha-weather-card.js @@ -30,12 +30,16 @@ class HaWeatherCard extends LocalizeMixin(EventsMixin(PolymerElement)) { .header { font-family: var(--paper-font-headline_-_font-family); - -webkit-font-smoothing: var(--paper-font-headline_-_-webkit-font-smoothing); + -webkit-font-smoothing: var( + --paper-font-headline_-_-webkit-font-smoothing + ); font-size: var(--paper-font-headline_-_font-size); font-weight: var(--paper-font-headline_-_font-weight); letter-spacing: var(--paper-font-headline_-_letter-spacing); line-height: var(--paper-font-headline_-_line-height); - text-rendering: var(--paper-font-common-expensive-kerning_-_text-rendering); + text-rendering: var( + --paper-font-common-expensive-kerning_-_text-rendering + ); opacity: var(--dark-primary-opacity); padding: 24px 16px 16px; display: flex; @@ -102,7 +106,7 @@ class HaWeatherCard extends LocalizeMixin(EventsMixin(PolymerElement)) { .attributes, .templow, - .precipitation { { + .precipitation { color: var(--secondary-text-color); } From ddb050d1fd272b949f5164e7e031142c0ad97f7b Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Tue, 8 Jan 2019 15:18:44 +0100 Subject: [PATCH 77/82] Change title to name (#2425) --- .../editor/config-elements/hui-gauge-card-editor.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 de72b02709..1b7d734940 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 @@ -17,7 +17,7 @@ import "../../components/hui-entity-editor"; const cardConfigStruct = struct({ type: "string", - title: "string?", + name: "string?", entity: "string?", unit: "string?", min: "number?", @@ -42,8 +42,8 @@ export class HuiGaugeCardEditor extends hassLocalizeLitMixin(LitElement) return { hass: {}, _config: {} }; } - get _title(): string { - return this._config!.title || ""; + get _name(): string { + return this._config!.name || ""; } get _entity(): string { @@ -80,9 +80,9 @@ export class HuiGaugeCardEditor extends hassLocalizeLitMixin(LitElement)
Date: Tue, 8 Jan 2019 20:27:01 +0100 Subject: [PATCH 78/82] Set min height to thermostat card (#2416) * Set min height * Set min height on #root * Add min-height on firstUpdated and remove after roundSlider is loaded * Move back to #thermostat --- .../lovelace/cards/hui-thermostat-card.ts | 130 ++++++++++-------- 1 file changed, 72 insertions(+), 58 deletions(-) diff --git a/src/panels/lovelace/cards/hui-thermostat-card.ts b/src/panels/lovelace/cards/hui-thermostat-card.ts index 4ecb862399..a8115c190a 100644 --- a/src/panels/lovelace/cards/hui-thermostat-card.ts +++ b/src/panels/lovelace/cards/hui-thermostat-card.ts @@ -190,6 +190,13 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement) } private async _initialLoad(): Promise { + const radius = this.clientWidth / 3; + this._broadCard = this.clientWidth > 390; + + (this.shadowRoot!.querySelector( + "#thermostat" + )! as HTMLElement).style.minHeight = radius * 2 + "px"; + const loaded = await loadRoundslider(); await new Promise((resolve) => afterNextRender(resolve)); @@ -206,13 +213,14 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement) const [sliderValue, uiValue] = this._genSliderValue(stateObj); const step = computeTemperatureStepSize(this.hass!, this._config!); - this._broadCard = this.clientWidth > 390; + this._jQuery("#thermostat", this.shadowRoot).roundSlider({ ...thermostatConfig, - radius: this.clientWidth / 3, + radius, 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, @@ -244,6 +252,68 @@ 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(","))); + } + + private _setTemperature(e): void { + const stateObj = this.hass!.states[this._config!.entity] as ClimateEntity; + if ( + stateObj.attributes.target_temp_low && + stateObj.attributes.target_temp_high + ) { + if (e.handle.index === 1) { + this.hass!.callService("climate", "set_temperature", { + entity_id: this._config!.entity, + target_temp_low: e.handle.value, + target_temp_high: stateObj.attributes.target_temp_high, + }); + } else { + this.hass!.callService("climate", "set_temperature", { + entity_id: this._config!.entity, + target_temp_low: stateObj.attributes.target_temp_low, + target_temp_high: e.handle.value, + }); + } + } else { + this.hass!.callService("climate", "set_temperature", { + entity_id: this._config!.entity, + temperature: e.value, + }); + } + } + + private _renderIcon(mode: string, currentMode: string): TemplateResult { + if (!modeIcons[mode]) { + return html``; + } + return html` + + `; + } + + private _handleModeClick(e: MouseEvent): void { + this.hass!.callService("climate", "set_operation_mode", { + entity_id: this._config!.entity, + operation_mode: (e.currentTarget as any).mode, + }); + } + private renderStyle(): TemplateResult { return html` ${this._roundSliderStyle} @@ -419,62 +489,6 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement) `; } - - private _updateSetTemp(value: string): void { - this.shadowRoot!.querySelector("#set-temperature")!.innerHTML = value; - } - - private _dragEvent(e): void { - this._updateSetTemp(formatTemp(String(e.value).split(","))); - } - - private _setTemperature(e): void { - const stateObj = this.hass!.states[this._config!.entity] as ClimateEntity; - if ( - stateObj.attributes.target_temp_low && - stateObj.attributes.target_temp_high - ) { - if (e.handle.index === 1) { - this.hass!.callService("climate", "set_temperature", { - entity_id: this._config!.entity, - target_temp_low: e.handle.value, - target_temp_high: stateObj.attributes.target_temp_high, - }); - } else { - this.hass!.callService("climate", "set_temperature", { - entity_id: this._config!.entity, - target_temp_low: stateObj.attributes.target_temp_low, - target_temp_high: e.handle.value, - }); - } - } else { - this.hass!.callService("climate", "set_temperature", { - entity_id: this._config!.entity, - temperature: e.value, - }); - } - } - - private _renderIcon(mode: string, currentMode: string): TemplateResult { - if (!modeIcons[mode]) { - return html``; - } - return html` - - `; - } - - private _handleModeClick(e: MouseEvent): void { - this.hass!.callService("climate", "set_operation_mode", { - entity_id: this._config!.entity, - operation_mode: (e.currentTarget as any).mode, - }); - } } declare global { From 2517e5ba60737405dd89203bcb2aefd4da05c983 Mon Sep 17 00:00:00 2001 From: yosilevy <37745463+yosilevy@users.noreply.github.com> Date: Wed, 9 Jan 2019 22:34:24 +0200 Subject: [PATCH 79/82] Proper RTL support in weather forecast card (#2424) * Proper RTL support in weather forecast card * States panel force left to right since RTL is not usable * Updated class names and switched div to span --- src/cards/ha-weather-card.js | 64 +++++++++++++++++++--- src/panels/dev-state/ha-panel-dev-state.js | 1 + 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/src/cards/ha-weather-card.js b/src/cards/ha-weather-card.js index 320558e0ee..4f27663ede 100644 --- a/src/cards/ha-weather-card.js +++ b/src/cards/ha-weather-card.js @@ -8,6 +8,7 @@ import "../components/ha-icon"; import EventsMixin from "../mixins/events-mixin"; import LocalizeMixin from "../mixins/localize-mixin"; +import { computeRTL } from "../common/util/compute_rtl"; /* * @appliesMixin LocalizeMixin @@ -52,6 +53,11 @@ class HaWeatherCard extends LocalizeMixin(EventsMixin(PolymerElement)) { color: var(--secondary-text-color); } + :host([rtl]) .name { + margin-left: 0px; + margin-right: 16px; + } + .now { display: flex; justify-content: space-between; @@ -65,18 +71,31 @@ class HaWeatherCard extends LocalizeMixin(EventsMixin(PolymerElement)) { margin-right: 32px; } + :host([rtl]) .main { + margin-right: 0px; + } + .main ha-icon { --iron-icon-height: 72px; --iron-icon-width: 72px; margin-right: 8px; } + :host([rtl]) .main ha-icon { + margin-right: 0px; + } + .main .temp { font-size: 52px; line-height: 1em; position: relative; } + :host([rtl]) .main .temp { + direction: ltr; + margin-right: 28px; + } + .main .temp span { font-size: 24px; line-height: 1em; @@ -84,6 +103,14 @@ class HaWeatherCard extends LocalizeMixin(EventsMixin(PolymerElement)) { top: 4px; } + .measurand { + display: inline-block; + } + + :host([rtl]) .measurand { + direction: ltr; + } + .forecast { margin-top: 16px; display: flex; @@ -100,6 +127,10 @@ class HaWeatherCard extends LocalizeMixin(EventsMixin(PolymerElement)) { text-align: center; } + :host([rtl]) .forecast .temp { + direction: ltr; + } + .weekday { font-weight: bold; } @@ -134,7 +165,9 @@ class HaWeatherCard extends LocalizeMixin(EventsMixin(PolymerElement)) { >
[[localize('ui.card.weather.attributes.air_pressure')]]: - [[stateObj.attributes.pressure]] [[getUnit('air_pressure')]] + + [[stateObj.attributes.pressure]] [[getUnit('air_pressure')]] +
@@ -206,6 +243,11 @@ class HaWeatherCard extends LocalizeMixin(EventsMixin(PolymerElement)) { type: Array, computed: "computeForecast(stateObj.attributes.forecast)", }, + rtl: { + type: Boolean, + reflectToAttribute: true, + computed: "_computeRTL(hass)", + }, }; } @@ -299,14 +341,18 @@ class HaWeatherCard extends LocalizeMixin(EventsMixin(PolymerElement)) { return degree; } - getWind(speed, bearing, localize) { + getWindSpeed(speed) { + return `${speed} ${this.getUnit("length")}/h`; + } + + getWindBearing(bearing, localize) { if (bearing != null) { const cardinalDirection = this.windBearingToText(bearing); - return `${speed} ${this.getUnit("length")}/h (${localize( + return `(${localize( `ui.card.weather.cardinal_direction.${cardinalDirection.toLowerCase()}` ) || cardinalDirection})`; } - return `${speed} ${this.getUnit("length")}/h`; + return ``; } _showValue(item) { @@ -328,5 +374,9 @@ class HaWeatherCard extends LocalizeMixin(EventsMixin(PolymerElement)) { { hour: "numeric" } ); } + + _computeRTL(hass) { + return computeRTL(hass); + } } customElements.define("ha-weather-card", HaWeatherCard); diff --git a/src/panels/dev-state/ha-panel-dev-state.js b/src/panels/dev-state/ha-panel-dev-state.js index f309a2386e..c0d495f5a9 100644 --- a/src/panels/dev-state/ha-panel-dev-state.js +++ b/src/panels/dev-state/ha-panel-dev-state.js @@ -28,6 +28,7 @@ class HaPanelDevState extends EventsMixin(PolymerElement) { .content { padding: 16px; + direction: ltr; } ha-entity-picker, From e9d912cc87a618bf7d4dddfa26f1c5af6dacf55b Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 9 Jan 2019 23:04:49 +0100 Subject: [PATCH 80/82] Remove styleMap for base-unit (#2428) --- src/panels/lovelace/cards/hui-gauge-card.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/panels/lovelace/cards/hui-gauge-card.ts b/src/panels/lovelace/cards/hui-gauge-card.ts index dd72db1355..27c1f1bb28 100644 --- a/src/panels/lovelace/cards/hui-gauge-card.ts +++ b/src/panels/lovelace/cards/hui-gauge-card.ts @@ -104,10 +104,7 @@ class HuiGaugeCard extends LitElement implements LovelaceCard { return html` ${this.renderStyle()} - + ${ error ? html` @@ -150,6 +147,15 @@ class HuiGaugeCard extends LitElement implements LovelaceCard { return hasConfigOrEntityChanged(this, changedProps); } + protected firstUpdated(): void { + (this.shadowRoot!.querySelector( + "ha-card" + )! as HTMLElement).style.setProperty( + "--base-unit", + this._computeBaseUnit() + ); + } + protected updated(changedProps: PropertyValues): void { super.updated(changedProps); if (!this._config || !this.hass) { From f3064f007101b271b9a16d4414b6f5b9c835676b Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 9 Jan 2019 14:36:55 -0800 Subject: [PATCH 81/82] Bumped version to 2019109.0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 4490e6c065..448d14ef3b 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup( name="home-assistant-frontend", - version="20181219.0", + version="2019109.0", description="The Home Assistant frontend", url="https://github.com/home-assistant/home-assistant-polymer", author="The Home Assistant Authors", From 417ffde3e825e806451d441dc964d0413663bca7 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 9 Jan 2019 14:37:32 -0800 Subject: [PATCH 82/82] Update translations --- translations/bg.json | 4 +- translations/ca.json | 6 +-- translations/da.json | 28 +++++++++++--- translations/de.json | 4 +- translations/el.json | 59 +++++++++++++++++++++++++++++ translations/en.json | 8 ---- translations/es.json | 28 +++++++++++++- translations/fr.json | 19 +++++----- translations/he.json | 2 +- translations/hu.json | 6 +-- translations/it.json | 22 +++++------ translations/lb.json | 20 +++++----- translations/lv.json | 58 ++++++++++++++++++++++++++--- translations/nl.json | 27 ++++++++++---- translations/nn.json | 82 ++++++++++++++++++++++++++++++++--------- translations/no.json | 2 +- translations/pl.json | 16 ++++---- translations/pt-BR.json | 28 +++++++++++++- translations/pt.json | 40 ++++++++++++++++---- translations/ru.json | 4 +- translations/uk.json | 44 +++++++++++++++------- translations/vi.json | 6 +-- 22 files changed, 389 insertions(+), 124 deletions(-) diff --git a/translations/bg.json b/translations/bg.json index e7e24447ac..d97b7127f2 100644 --- a/translations/bg.json +++ b/translations/bg.json @@ -186,8 +186,8 @@ "on": "Включен" }, "light": { - "off": "Изключена", - "on": "Включен" + "off": "Изключено", + "on": "Включено" }, "lock": { "locked": "Заключен", diff --git a/translations/ca.json b/translations/ca.json index c6150a5951..5b0e98263c 100644 --- a/translations/ca.json +++ b/translations/ca.json @@ -133,8 +133,8 @@ "climate": { "off": "Apagat", "on": "Encès", - "heat": "Calent", - "cool": "Fred", + "heat": "Escalfar", + "cool": "Refredar", "idle": "Inactiu", "auto": "Automàtic", "dry": "Assecar", @@ -824,7 +824,7 @@ }, "alarm_control_panel": { "code": "Codi", - "clear_code": "Esborrar", + "clear_code": "Supr.", "disarm": "Desactivar", "arm_home": "Activar, a casa", "arm_away": "Activar, fora", diff --git a/translations/da.json b/translations/da.json index 0ff3ba246a..607c4045b6 100644 --- a/translations/da.json +++ b/translations/da.json @@ -618,7 +618,8 @@ "mfa": { "header": "Multifaktor godkendelsesmoduler", "disable": "Deaktiver", - "enable": "Aktiver" + "enable": "Aktiver", + "confirm_disable": "Er du sikker på du vil deaktivere {name}?" }, "mfa_setup": { "title_aborted": "Afbrudt", @@ -726,18 +727,35 @@ } }, "editor": { + "edit_card": { + "header": "Kortkonfiguration", + "save": "Gem", + "toggle_editor": "Skifte Editor", + "pick_card": "Vælg det kort, du vil tilføje.", + "add": "Tilføj kort", + "edit": "Rediger", + "delete": "Slet" + }, "migrate": { "header": "Konfiguration ikke færdiggjort", + "para_no_id": "Dette element har ikke et id. Tilføj venligst et id til dette element i \"ui-lovelace.yaml\".", + "para_migrate": "Hjem assistent kan tilføje id'er til alle dine kort og oversigter automatisk for dig ved at trykke på knappen 'Overfør configuration'.", "migrate": "Migrer opsætning" }, "header": "Rediger UI", "configure_ui": "Konfigurer UI", "edit_view": { - "header": "Vis konfiguration" + "header": "Vis konfiguration", + "add": "Tilføje visning", + "edit": "Redigere visning", + "delete": "Slette visning" }, - "edit_card": { - "edit": "Rediger", - "delete": "Slet" + "save_config": { + "header": "Tage kontrol over din 2Lovelace\" UI", + "para": "Som standard vil hjem assistenten fastholde din brugergrænseflade, opdaterer den når nye enheder eller \"Lovelace\" komponenter bliver tilgængelige. Hvis du tager kontrol så vil vi ikke længere foretage ændringer automatisk for dig.", + "para_sure": "Er du sikker på du ønsker at tage kontrol over din brugergrænseflade?", + "cancel": "Glem det", + "save": "tag kontrol" } } } diff --git a/translations/de.json b/translations/de.json index 2beb15f3fd..0ac9086658 100644 --- a/translations/de.json +++ b/translations/de.json @@ -721,9 +721,9 @@ "lovelace": { "cards": { "shopping-list": { - "checked_items": "Markierte Items", + "checked_items": "Markierte Artikel", "clear_items": "Markierte Elemente löschen", - "add_item": "Item hinzufügen" + "add_item": "Artikel hinzufügen" } }, "editor": { diff --git a/translations/el.json b/translations/el.json index cab81d65c9..56810e8123 100644 --- a/translations/el.json +++ b/translations/el.json @@ -222,8 +222,67 @@ "config": { "zwave": { "caption": "Z-Wave" + }, + "automation": { + "editor": { + "triggers": { + "type": { + "state": { + "for": "Για" + } + } + } + } + } + }, + "lovelace": { + "editor": { + "edit_card": { + "save": "Αποθήκευση", + "edit": "Επεξεργασία", + "delete": "Διαγραφή" + }, + "header": "Επεξεργασία UI", + "configure_ui": "Ρύθμιση UI", + "edit_view": { + "header": "Ρυθμίσεις", + "add": "Προσθήκη προβολής", + "edit": "Επεξεργασία προβολής", + "delete": "Διαγραφή προβολής" + } } } + }, + "card": { + "cover": { + "position": "Θέση", + "tilt_position": "Θέση ανάκλισης" + }, + "fan": { + "speed": "Ταχύτητα", + "oscillate": "Περιστροφή", + "direction": "Κατεύθυνση" + }, + "light": { + "brightness": "Φωτεινότητα", + "color_temperature": "Θερμοκρασία χρώματος", + "white_value": "Τιμή λευκού", + "effect": "Εφέ" + }, + "media_player": { + "text_to_speak": "Κείμενο για εκφώνηση" + }, + "climate": { + "currently": "Αυτή τη στιγμή", + "target_temperature": "Επιθυμητή θερμοκρασία", + "target_humidity": "Επιθυμητή υγρασία", + "operation": "Λειτουργία", + "fan_mode": "Λειτουργία ανεμιστήρα", + "away_mode": "Λειτουργία εκτός σπιτιού" + } + }, + "common": { + "save": "Αποθήκευση" } }, "domain": { diff --git a/translations/en.json b/translations/en.json index 84c65942cf..935b669e1f 100644 --- a/translations/en.json +++ b/translations/en.json @@ -514,13 +514,6 @@ "caption": "Script", "description": "Create and edit scripts" }, - "zha": { - "caption": "ZHA", - "description": "Manage your Zigbee Home Automation network", - "network": { - "introduction": "Zigbee Home Automation network management" - } - }, "zwave": { "caption": "Z-Wave", "description": "Manage your Z-Wave network" @@ -981,7 +974,6 @@ "switch": "Switch", "updater": "Updater", "weblink": "Weblink", - "zha": "ZHA", "zwave": "Z-Wave", "vacuum": "Vacuum" }, diff --git a/translations/es.json b/translations/es.json index 07e1f98cac..a9b491062a 100644 --- a/translations/es.json +++ b/translations/es.json @@ -423,6 +423,10 @@ "event": "Evento:", "enter": "Entrar", "leave": "Salir" + }, + "webhook": { + "label": "Webhook", + "webhook_id": "ID de webhook" } } }, @@ -726,13 +730,32 @@ "edit_card": { "header": "Configuración de la tarjeta", "save": "Guardar", - "toggle_editor": "Alternar editor" + "toggle_editor": "Alternar editor", + "pick_card": "Escoge la tarjeta que desea agregar.", + "add": "Añadir tarjeta", + "edit": "Editar", + "delete": "Eliminar" }, "migrate": { "header": "Configuración incompatible", "para_no_id": "Este elemento no tiene un ID. Por favor agregue uno este elemento en 'ui-lovelace.yaml'.", "para_migrate": "Home Assistant puede agregar ID a todas sus tarjetas y vistas automáticamente por usted presionando el botón 'Migrar configuración'.", "migrate": "Migrar configuración" + }, + "header": "Editar la interfaz de usuario", + "configure_ui": "Configurar la interfaz de usuario", + "edit_view": { + "header": "Ver configuración", + "add": "Añadir vista", + "edit": "Editar vista", + "delete": "Borrar vista" + }, + "save_config": { + "header": "Tomar el control de la interfaz de usuario de Lovelace", + "para": "Por defecto, Home Assistant mantendrá su interfaz de usuario y la actualizará cuando haya nuevas entidades o componentes de Lovelace disponibles. Si usted toma el control, ya no haremos cambios automáticamente para usted.", + "para_sure": "¿Está seguro de que desea tomar el control de su interfaz de usuario?", + "cancel": "No importa", + "save": "Tomar el control" } } } @@ -743,7 +766,8 @@ }, "common": { "loading": "Cargando", - "cancel": "Cancelar" + "cancel": "Cancelar", + "save": "Guardar" }, "duration": { "day": "{count} {count, plural,\none {día}\nother {días}\n}", diff --git a/translations/fr.json b/translations/fr.json index e39d403385..637d24b272 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -70,7 +70,7 @@ }, "vibration": { "off": "RAS", - "on": "Détecté" + "on": "Détectée" }, "opening": { "off": "Fermé", @@ -275,8 +275,8 @@ "alarm_control_panel": { "armed": "Activé", "disarmed": "Désactivé", - "armed_home": "Activée (présent)", - "armed_away": "Armée (absent)", + "armed_home": "Armé", + "armed_away": "Armé", "armed_night": "Activé", "pending": "En cours", "arming": "Activer", @@ -301,7 +301,7 @@ "period": "Période" }, "logbook": { - "showing_entries": "Afficher les entrées pour" + "showing_entries": "Afficher les entrées pour le" }, "mailbox": { "empty": "Vous n'avez aucun message", @@ -436,7 +436,7 @@ "add": "Ajouter une condition", "duplicate": "Dupliquer", "delete": "Effacement", - "delete_confirm": "Voulez-vous effacer ?", + "delete_confirm": "Voulez-vous vraiment effacer ?", "unsupported_condition": "Condition non supportée : {condition}", "type_select": "Type de condition", "type": { @@ -480,7 +480,7 @@ "introduction": "Les actions sont ce que Home Assistant fera quand une automatisation est déclenchée.\n\n[En apprendre plus sur les actions.](https:\/\/home-assistant.io\/docs\/automation\/action\/)", "add": "Ajouter une action", "duplicate": "Dupliquer", - "delete": "Effacer", + "delete": "Supprimer", "delete_confirm": "Voulez-vous vraiment effacer ?", "unsupported_action": "Action non supportée : {action}", "type_select": "Type d'action", @@ -533,7 +533,7 @@ } }, "cloud": { - "caption": "Home Assistant Cloud", + "caption": "Nuage Home Assistant", "description_login": "Connecté en tant que {email}", "description_not_login": "Pas connecté" }, @@ -752,7 +752,7 @@ }, "save_config": { "header": "Prenez le controle de Lovelace UI", - "para": "Par défaut Home Assistant va maintenir l'interface utilisateur, met à jour quand y'a de nouveaux entités ou composants de Lovelace sont disponibles. Si vous prenez le contrôle on ne fera plus de changements automatiques pour vous.", + "para": "Par défaut, Home Assistant maintient votre interface utilisateur et la met à jour lorsque de nouvelles entités ou de nouveaux composants Lovelace sont disponibles. Si vous prenez le contrôle, nous ne ferons plus les changements automatiquement pour vous.", "para_sure": "Êtes-vous sûr de vouloir prendre le controle de l'interface utilisateur?", "cancel": "Oublie ce que j'ai dit, c'est pas grave.", "save": "Prenez le contrôle" @@ -828,7 +828,8 @@ "disarm": "Désarmer", "arm_home": "Armer (domicile)", "arm_away": "Armer (absent)", - "arm_night": "Armer nuit" + "arm_night": "Armer nuit", + "armed_custom_bypass": "Bypass personnalisé" }, "automation": { "last_triggered": "Dernier déclenchement", diff --git a/translations/he.json b/translations/he.json index 807450996b..233496a4bd 100644 --- a/translations/he.json +++ b/translations/he.json @@ -561,7 +561,7 @@ "profile": { "push_notifications": { "header": "הודעות דחיפה", - "description": "שלח התראות למכשיר זה", + "description": "שלח התראות למכשיר זה.", "error_load_platform": "הגדר את notify.html5.", "error_use_https": "נדרש SSL מופעל עבור הממשק.", "push_notifications": "הודעות דחיפה", diff --git a/translations/hu.json b/translations/hu.json index e2d57415c7..d135760d3f 100644 --- a/translations/hu.json +++ b/translations/hu.json @@ -292,7 +292,7 @@ "ui": { "panel": { "shopping-list": { - "clear_completed": "Kijelöltek törlése", + "clear_completed": "Bejelöltek törlése", "add_item": "Tétel hozzáadása", "microphone_tip": "Koppints a jobb felső sarokban található mikrofonra, és mondd ki: \"Add candy to my shopping list\"" }, @@ -721,8 +721,8 @@ "lovelace": { "cards": { "shopping-list": { - "checked_items": "Kijelölt tételek", - "clear_items": "Kijelölt tételek törlése", + "checked_items": "Bejelölt tételek", + "clear_items": "Bejelölt tételek törlése", "add_item": "Tétel hozzáadása" } }, diff --git a/translations/it.json b/translations/it.json index 08697ee5e2..d733a1b540 100644 --- a/translations/it.json +++ b/translations/it.json @@ -274,7 +274,7 @@ }, "alarm_control_panel": { "armed": "Attivo", - "disarmed": "Disattivo", + "disarmed": "Disattiva", "armed_home": "Attivo", "armed_away": "Attivo", "armed_night": "Attivo", @@ -368,7 +368,7 @@ "introduction": "I trigger sono ciò che avvia l'elaborazione di una regola di automazione. È possibile specificare più trigger per la stessa regola. Una volta avviato il trigger, Home Assistant convaliderà le condizioni, se presenti, e chiamerà l'azione. \n\n [Ulteriori informazioni sui trigger.](Https:\/\/home-assistant.io\/docs\/automation\/trigger\/)", "add": "Aggiungi trigger", "duplicate": "Duplica", - "delete": "Cancella", + "delete": "Elimina", "delete_confirm": "Sicuro di voler eliminare?", "unsupported_platform": "Piattaforma non supportata: {platform}", "type_select": "Tipo di trigger", @@ -426,7 +426,7 @@ }, "webhook": { "label": "Webhook", - "webhook_id": "Webhook ID" + "webhook_id": "ID Webhook" } } }, @@ -435,7 +435,7 @@ "introduction": "Le condizioni sono una parte facoltativa di una regola di automazione e possono essere utilizzate per impedire che un'azione si verifichi quando viene attivata. Le condizioni sembrano molto simili ai trigger, ma sono molto diverse. Un trigger analizzerà gli eventi che si verificano nel sistema mentre una condizione analizza solo l'aspetto del sistema in questo momento. Un trigger può osservare che un interruttore è in fase di accensione. Una condizione può vedere solo se un interruttore è attivo o meno. \n\n [Ulteriori informazioni sulle condizioni.](Https:\/\/home-assistant.io\/docs\/scripts\/conditions\/)", "add": "Aggiungi condizione", "duplicate": "Duplica", - "delete": "Cancella", + "delete": "Elimina", "delete_confirm": "Sicuro di voler eliminare?", "unsupported_condition": "Condizione non supportata: {condition}", "type_select": "Tipo di condizione", @@ -480,7 +480,7 @@ "introduction": "Le azioni sono ciò che Home Assistant farà quando un trigger attiva un automazione. \n\n [Ulteriori informazioni sulle azioni.](Https:\/\/home-assistant.io\/docs\/automation\/action\/)", "add": "Aggiungi azione", "duplicate": "Duplica", - "delete": "Cancella", + "delete": "Elimina", "delete_confirm": "Sicuro di voler eliminare?", "unsupported_action": "Azione non supportata: {action}", "type_select": "Tipo di azione", @@ -504,7 +504,7 @@ "event": { "label": "Scatena Evento", "event": "Evento:", - "service_data": "Dato servizio" + "service_data": "Dati servizio" } } } @@ -535,7 +535,7 @@ "cloud": { "caption": "Home Assistant Cloud", "description_login": "Connesso come {email}", - "description_not_login": "Non loggato" + "description_not_login": "Accesso non effettuato" }, "integrations": { "caption": "integrazioni", @@ -551,7 +551,7 @@ "delete_confirm": "Sei sicuro di voler eliminare questa integrazione?", "restart_confirm": "Riavvia Home Assistant per terminare la rimozione di questa integrazione", "manuf": "da {manufacturer}", - "hub": "Connesso via", + "hub": "Connesso tramite", "firmware": "Firmware: {version}", "device_unavailable": "dispositivo non disponibile", "entity_unavailable": "entità non disponibile" @@ -600,7 +600,7 @@ "create_failed": "Impossibile creare il token di accesso.", "prompt_name": "Nome?", "prompt_copy_token": "Copia il tuo token di accesso. Non verrà più mostrato.", - "empty_state": "Non hai ancora token di accesso di lunga durata.", + "empty_state": "Non hai ancora un token di accesso di lunga durata.", "last_used": "Utilizzato l'ultima volta il {date} da {location}", "not_used": "Non è mai stato usato" }, @@ -754,7 +754,7 @@ "header": "Prendi il controllo della tua interfaccia utente di Lovelace", "para": "Per impostazione predefinita, Home Assistant manterrà l'interfaccia utente, aggiornandola quando nuove entità o componenti Lovelace diventano disponibili. Se prendi il controllo non effettueremo più automaticamente le modifiche per te.", "para_sure": "Sei sicuro di voler prendere il controllo della tua interfaccia utente?", - "cancel": "Non importa", + "cancel": "Rinuncia", "save": "Prendere il controllo" } } @@ -825,7 +825,7 @@ "alarm_control_panel": { "code": "Codice", "clear_code": "Canc", - "disarm": "Disattivato", + "disarm": "Disattiva", "arm_home": "Attiva In casa", "arm_away": "Attiva Fuori Casa", "arm_night": "Attiva Notte", diff --git a/translations/lb.json b/translations/lb.json index afe88eacf1..fe13994b79 100644 --- a/translations/lb.json +++ b/translations/lb.json @@ -275,9 +275,9 @@ "alarm_control_panel": { "armed": "Aktivéiert", "disarmed": "Desaktivéieren", - "armed_home": "Aktivéiert", - "armed_away": "Aktivéiert", - "armed_night": "Aktivéiert", + "armed_home": "Uzbrojony", + "armed_away": "Uzbrojony", + "armed_night": "Uzbrojony", "pending": "Ustoend", "arming": "Aktivéieren", "disarming": "Desaktivéieren", @@ -317,7 +317,7 @@ "description": "Konfiguratioun validéieren an de Server kontrolléieren", "section": { "core": { - "header": "Konfiguratioun an Server Kontroll", + "header": "Konfiguracja i konktrola serwera", "introduction": "D'Ännere vun der Konfiguratioun kann e lästege Prozess sinn. Mir wëssen dat. Dës Sektioun probéiert fir Äert Liewen e bësse méi einfach ze maachen.", "validation": { "heading": "Validatioun vun der Konfiguratioun", @@ -419,7 +419,7 @@ "zone": { "label": "Zone", "entity": "Entitéit mam Standuert", - "zone": "Zon", + "zone": "Strefa", "event": "Evenement:", "enter": "Eran", "leave": "Verloossen" @@ -445,7 +445,7 @@ "state": "Zoustand" }, "numeric_state": { - "label": "Numereschen Zoustand", + "label": "Stan (numeryczny)", "above": "Iwwert", "below": "Ënnert", "value_template": "Wäerte Modell (optional)" @@ -469,9 +469,9 @@ "before": "Virdrun" }, "zone": { - "label": "Zon", + "label": "Strefa", "entity": "Entitéit mam Standuert", - "zone": "Zon" + "zone": "Strefa" } } }, @@ -491,7 +491,7 @@ }, "delay": { "label": "Delai", - "delay": "Delai" + "delay": "Opóźnienie" }, "wait_template": { "label": "Waart", @@ -875,7 +875,7 @@ "actions": { "resume_cleaning": "Fuer mam botzen weider", "return_to_base": "Zeréck zur Statioun kommen", - "start_cleaning": "Fänkt mam botzen un", + "start_cleaning": "Fänk mam botzen un", "turn_on": "Uschalten", "turn_off": "Ausschalten" } diff --git a/translations/lv.json b/translations/lv.json index 6ac3539796..0a6ee3432e 100644 --- a/translations/lv.json +++ b/translations/lv.json @@ -317,7 +317,7 @@ "description": "Veiciet konfigurācijas failu pārbaudi un pārvaldiet serveri", "section": { "core": { - "header": "Konfigurācijas un servera pārvaldība", + "header": "Konfigurācijas un Servera pārvaldība", "introduction": "Izmaiņas konfigurācijā var būt nogurdinošs process. Mēs zinām. Šai sadaļai vajadzētu padarīt dzīvi mazliet vieglāku.", "validation": { "heading": "Konfigurācijas pārbaude", @@ -351,7 +351,7 @@ "caption": "Automatizācija", "description": "Veidojiet un rediģējiet automatizācijas", "picker": { - "header": "Automatizāciju redaktors", + "header": "Automatizāciju Redaktors", "introduction": "Automatizācijas redaktors ļauj jums izveidot un rediģēt automatizācijas. Lūdzu, izlasiet [norādījumus] (https:\/\/home-assistant.io\/docs\/automation\/editor\/), lai pārliecinātos, ka esat pareizi konfigurējis Home Assistant.", "pick_automation": "Izvēlieties automatizāciju kuru rediģēt", "no_automations": "Mēs nevarējām atrast rediģējamas automatizācijas", @@ -423,6 +423,10 @@ "event": "Notikums:", "enter": "Ieiet", "leave": "Iziet" + }, + "webhook": { + "label": "Webhook", + "webhook_id": "Webhook ID" } } }, @@ -713,6 +717,47 @@ "required_fields": "Aizpildiet visus obligātos laukus" } } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "Atzīmētie vienumi", + "clear_items": "Notīrīt atzīmētos vienumus", + "add_item": "Pievienot vienumu" + } + }, + "editor": { + "edit_card": { + "header": "Kartes Konfigurācija", + "save": "Saglabāt", + "toggle_editor": "Pārslēgt Redaktoru", + "pick_card": "Izvēlieties karti, kuru vēlaties pievienot.", + "add": "Pievienot karti", + "edit": "Rediģēt", + "delete": "Dzēst" + }, + "migrate": { + "header": "Konfigurācija Nesaderīga", + "para_no_id": "Šim elementam nav ID. Lūdzu, pievienojiet ID šim elementam 'ui-lovelace.yaml' failā.", + "para_migrate": "Home Assistant var automātiski pievienot ID visām kartēm un skatiem, nospiežot pogu \"Pārvietot konfigurāciju\".", + "migrate": "Pārvietot konfigurāciju" + }, + "header": "Rediģēt lietotāja interfeisu", + "configure_ui": "Konfigurēt lietotāja interfeisu", + "edit_view": { + "header": "Skatīt konfigurāciju", + "add": "Pievienot skatu", + "edit": "Rediģēt skatu", + "delete": "Dzēst skatu" + }, + "save_config": { + "header": "Pārņemt kontroli pār savu Lovelace UI", + "para": "Pēc noklusējuma Home Assistant uzturēs jūsu lietotāja interfeisu, atjauninot to, kad būs pieejami jauni objekti vai Lovelace komponenti. Ja jūs uzņematies kontroli, mēs jums vairs neveiksim izmaiņas automātiski jūsu vietā.", + "para_sure": "Vai tiešām vēlaties kontrolēt savu lietotāja interfeisu?", + "cancel": "Nekas", + "save": "Pārņemt kontroli" + } + } } }, "sidebar": { @@ -721,7 +766,8 @@ }, "common": { "loading": "Ielāde", - "cancel": "Atcelt" + "cancel": "Atcelt", + "save": "Saglabāt" }, "duration": { "day": "{count} {count, plural,\none {diena}\nother {dienas}\n}", @@ -778,10 +824,12 @@ }, "alarm_control_panel": { "code": "Kods", - "clear_code": "Dzēst", + "clear_code": "Notīrīt", "disarm": "Atslēgt", "arm_home": "Pieslēgt mājas", - "arm_away": "Pieslēgt prombūtni" + "arm_away": "Pieslēgt prombūtni", + "arm_night": "Pieslēgts uz nakti", + "armed_custom_bypass": "Pielāgots apvedceļš" }, "automation": { "last_triggered": "Pēdējais izsaukums", diff --git a/translations/nl.json b/translations/nl.json index 001564a852..8dbf492b90 100644 --- a/translations/nl.json +++ b/translations/nl.json @@ -236,7 +236,7 @@ "ready": "Gereed" }, "query_stage": { - "initializing": "Initialiseren ({query_stage})", + "initializing": "Voorbereiden ({query_stage})", "dead": "Onbereikbaar ({query_stage})" } }, @@ -248,7 +248,7 @@ "lightning": "Bliksem", "lightning-rainy": "Bliksem, regenachtig", "partlycloudy": "Gedeeltelijk bewolkt", - "pouring": "Gieten", + "pouring": "Regen", "rainy": "Regenachtig", "snowy": "Sneeuwachtig", "snowy-rainy": "Sneeuw-, regenachtig", @@ -276,8 +276,8 @@ "armed": "Actief", "disarmed": "Uit", "armed_home": "Actief", - "armed_away": "Ingeschakeld", - "armed_night": "Ingeschakeld", + "armed_away": "Actief", + "armed_night": "Actief", "pending": "Wacht", "arming": "Activeren", "disarming": "Uitschakelen", @@ -301,7 +301,7 @@ "period": "Periode" }, "logbook": { - "showing_entries": "Toon items voor" + "showing_entries": "Toont gegevens van" }, "mailbox": { "empty": "Je hebt geen berichten", @@ -445,7 +445,7 @@ "state": "Staat" }, "numeric_state": { - "label": "Numerieke status", + "label": "Numerieke staat", "above": "Boven", "below": "Onder", "value_template": "Waardetemplate (optioneel)" @@ -731,6 +731,9 @@ "header": "Kaart configuratie", "save": "Opslaan", "toggle_editor": "Toggle Editor", + "pick_card": "Kies de kaart die je wilt toevoegen.", + "add": "Kaart toevoegen", + "edit": "Bewerken", "delete": "Verwijder" }, "migrate": { @@ -739,10 +742,18 @@ "para_migrate": "Home Assistant kan ID's voor al je kaarten en weergaven automatisch voor je toevoegen door op de knop 'Migrate config' te klikken.", "migrate": "Configuratie migreren" }, + "header": "Bewerk UI", + "configure_ui": "Configureer UI", "edit_view": { - "header": "Bekijk de configuratie" + "header": "Bekijk de configuratie", + "add": "Weergave toevoegen", + "edit": "Weergave bewerken", + "delete": "Weergave verwijderen" }, "save_config": { + "header": "Neem de controle over uw Lovelace UI", + "para": "Normaal gesproken onderhoudt Home Assistant je gebruikersinterface en update die met nieuwe entiteiten of Lovelace-onderdelen wanneer deze beschikbaar zijn. Als je het beheer overneemt, zullen we niet langer automatisch wijzigingen aanbrengen.", + "para_sure": "Weet je zeker dat je de controle wilt over je gebruikersinterface?", "cancel": "Laat maar", "save": "Neem over" } @@ -756,7 +767,7 @@ "common": { "loading": "Bezig met laden", "cancel": "Annuleren", - "save": "Bewaar" + "save": "Opslaan" }, "duration": { "day": "{count} {count, plural,\none {dag}\nother {dagen}\n}", diff --git a/translations/nn.json b/translations/nn.json index e8a893de38..32fa52bc00 100644 --- a/translations/nn.json +++ b/translations/nn.json @@ -145,7 +145,7 @@ "high_demand": "Høg etterspurnad", "heat_pump": "Varmepumpe", "gas": "Gass", - "manual": "Håndbok" + "manual": "Handbok" }, "configurator": { "configure": "Konfigurerer", @@ -423,6 +423,10 @@ "event": "Hending:", "enter": "Kjem", "leave": "Forlet" + }, + "webhook": { + "label": "Webhook", + "webhook_id": "Webhook ID" } } }, @@ -545,12 +549,12 @@ "no_devices": "Essa integração não possui dispositivos.", "no_device": "Entidades sem dispositivos.", "delete_confirm": "Voc^tem certeza que deseja apagar essa integração?", - "restart_confirm": "Reinicie Home Assistant para finalizar essa integração", - "manuf": "por {fabricante}", - "hub": "Conectado via", - "firmware": "Firmware: {versão}", - "device_unavailable": "Dispositivo indisponível", - "entity_unavailable": "Entidade indisponível" + "restart_confirm": "Restart Home Assistant for å fjerne denne integrasjonen", + "manuf": "av {manufacturer}", + "hub": "Tilkopla via", + "firmware": "Firmware: {version}", + "device_unavailable": "Eininga utilgjengelig", + "entity_unavailable": "Oppføringa utilgjengelig" } } }, @@ -600,11 +604,11 @@ "last_used": "Sist brukt den {date} frå {location}", "not_used": "Har aldri vore brukt" }, - "current_user": "Você está atualmente conectado como {NomeCompleto}.", + "current_user": "Du er for augeblinken logga inn som {fullName}.", "is_owner": "Du er ein eigar", - "logout": "Sair", + "logout": "Logg ut", "change_password": { - "header": "Mudar Senha", + "header": "Bytt passord", "current_password": "Senha Atual", "new_password": "Nova Senha", "confirm_new_password": "Confirme Nova Senha", @@ -713,6 +717,47 @@ "required_fields": "Fyll ut dei nødvendige felta" } } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "Markerte element", + "clear_items": "Fjern dei markerrte elementa", + "add_item": "Legg til element" + } + }, + "editor": { + "edit_card": { + "header": "Kortkonfigurasjon", + "save": "Lagre", + "toggle_editor": "Bytt redigeringsverktøy", + "pick_card": "Vel kortet du vil legge til.", + "add": "Legg til kort", + "edit": "Redigere", + "delete": "Slett" + }, + "migrate": { + "header": "Konfigurasjonen er ikkje kompatibel", + "para_no_id": "Dette elementet har ikkje ein ID. Ver vennleg og legg til ein ID til dette elementet i \"ui-lovelace.yaml\"-fila di.", + "para_migrate": "Home assistant kan legge til ID-ar til alle korta og sidene dine automatisk for deg ved å trykke \"Overfør konfigurasjon\"-knappen.", + "migrate": "Overfør konfigurasjon" + }, + "header": "Rediger brukargrensesnitt", + "configure_ui": "Konfigurer brukargrensesnitt", + "edit_view": { + "header": "Vis konfigurasjon", + "add": "Legg til side", + "edit": "Rediger sida", + "delete": "Slett sida" + }, + "save_config": { + "header": "Ta kontroll over Lovelace-brukargrensesnittet", + "para": "Som standard kjem Home Assistant til å vedlikehalde brukargrensesnittet, og oppdatere det når nye oppføringar eller Lovelace-komponentar vert tilgjengelege. Dersom du tek kontroll, vil vi ikkje lenger kunne lage dette til automatisk for deg.", + "para_sure": "Er du sikker på at du vil ta kontroll over brukergrensesnittet ditt?", + "cancel": "Gløym det", + "save": "Ta kontroll" + } + } } }, "sidebar": { @@ -721,7 +766,8 @@ }, "common": { "loading": "Lastar", - "cancel": "Avbryt\n" + "cancel": "Avbryt\n", + "save": "Lagre" }, "duration": { "day": "{count} {count, plural,\none {dag}\nother {dagar}\n}", @@ -782,8 +828,8 @@ "disarm": "Skru av", "arm_home": "Heimemodus", "arm_away": "Bortemodus", - "arm_night": "Acionamento noturno", - "armed_custom_bypass": "Atalho configurado" + "arm_night": "Aktiver natt", + "armed_custom_bypass": "Tilpassa bypass" }, "automation": { "last_triggered": "Sist utløyst", @@ -835,11 +881,11 @@ } }, "water_heater": { - "currently": "Atualmente", - "on_off": "Liga \/ desliga", - "target_temperature": "Temperatura desejada", - "operation": "Operação", - "away_mode": "Modo distante" + "currently": "For augeblinken", + "on_off": "På \/ av", + "target_temperature": "Temperaturmål", + "operation": "Operasjon", + "away_mode": "Bortemodus" } }, "components": { diff --git a/translations/no.json b/translations/no.json index e52ee5d6ff..5d40fcf0d6 100644 --- a/translations/no.json +++ b/translations/no.json @@ -827,7 +827,7 @@ "clear_code": "Klarer", "disarm": "Deaktiver", "arm_home": "Armer hjemme", - "arm_away": "Armer bort", + "arm_away": "Armer borte", "arm_night": "Armer natt", "armed_custom_bypass": "Tilpasset bypass" }, diff --git a/translations/pl.json b/translations/pl.json index 290e863471..41cb3ed7d4 100644 --- a/translations/pl.json +++ b/translations/pl.json @@ -486,7 +486,7 @@ "type_select": "Typ akcji", "type": { "service": { - "label": "Wykonanie usługi", + "label": "Wywołanie usługi", "service_data": "Dane usługi" }, "delay": { @@ -494,7 +494,7 @@ "delay": "Opóźnienie" }, "wait_template": { - "label": "Czekaj", + "label": "Oczekiwanie", "wait_template": "Szablon czekania", "timeout": "Limit czasu (opcjonalnie)" }, @@ -502,7 +502,7 @@ "label": "Warunek" }, "event": { - "label": "Uruchom zdarzenie", + "label": "Wywołanie zdarzenia", "event": "Zdarzenie:", "service_data": "Dane usługi" } @@ -825,11 +825,11 @@ "alarm_control_panel": { "code": "Kod", "clear_code": "Wyczyść", - "disarm": "Rozbrojony", - "arm_home": "uzbrojony (w domu)", - "arm_away": "uzbrojony (nieobecny)", - "arm_night": "uzbrojony (noc)", - "armed_custom_bypass": "uzbrojony (częściowo)" + "disarm": "Rozbrojenie", + "arm_home": "Uzbrojenie (w domu)", + "arm_away": "Uzbrojenie (nieobecny)", + "arm_night": "Uzbrojenie (noc)", + "armed_custom_bypass": "Uzbrój (częściowo)" }, "automation": { "last_triggered": "Ostatnie uruchomienie", diff --git a/translations/pt-BR.json b/translations/pt-BR.json index d41350931c..feaf717d7d 100644 --- a/translations/pt-BR.json +++ b/translations/pt-BR.json @@ -423,6 +423,10 @@ "event": "Evento:", "enter": "Entrar", "leave": "Sair" + }, + "webhook": { + "label": "Webhook", + "webhook_id": "ID da Webhook" } } }, @@ -726,13 +730,32 @@ "edit_card": { "header": "Configuração de cartão", "save": "Salvar", - "toggle_editor": "Alternar Editor" + "toggle_editor": "Alternar Editor", + "pick_card": "Escolha o cartão que você deseja adicionar.", + "add": "Adicionar cartão", + "edit": "Editar", + "delete": "Excluir" }, "migrate": { "header": "Configuração Incompatível", "para_no_id": "Este elemento não possui um ID. Por favor adicione um ID a este elemento em 'ui-lovelace.yaml'.", "para_migrate": "O Home Assistant pode adicionar IDs a todos os seus cards e visualizações automaticamente clicando no botão 'Migrar config'.", "migrate": "Migrar configuração" + }, + "header": "Editar “interface” do usuário", + "configure_ui": "Configurar “interface” do usuário", + "edit_view": { + "header": "Configurações", + "add": "Editar visualização", + "edit": "Editar visualização", + "delete": "Excluir visualização" + }, + "save_config": { + "header": "Assuma o controle da sua interface do Lovelace", + "para": "Por padrão, o Home Assistant manterá sua interface de usuário, atualizando-a quando novas entidades ou componentes do Lovelace estiverem disponíveis. Se você assumir o controle, não faremos mais alterações automaticamente para você.", + "para_sure": "Tem certeza de que deseja assumir o controle da sua interface de usuário?", + "cancel": "Nunca", + "save": "Assuma o controle" } } } @@ -743,7 +766,8 @@ }, "common": { "loading": "Carregando", - "cancel": "Cancelar" + "cancel": "Cancelar", + "save": "Salvar" }, "duration": { "day": "{count} {count, plural,\none {dia}\nother {dias}\n}", diff --git a/translations/pt.json b/translations/pt.json index 5a44af4799..2b5ecef9ed 100644 --- a/translations/pt.json +++ b/translations/pt.json @@ -273,16 +273,16 @@ "unavailable": "Indisp" }, "alarm_control_panel": { - "armed": "Armad", + "armed": "Armado", "disarmed": "Desarm", - "armed_home": "Armad", - "armed_away": "Armad", - "armed_night": "Armad", + "armed_home": "Armado", + "armed_away": "Armado", + "armed_night": "Armado", "pending": "Pend", "arming": "A armar", "disarming": "Desarmar", "triggered": "Disp", - "armed_custom_bypass": "Armad" + "armed_custom_bypass": "Armado" }, "device_tracker": { "home": "Casa", @@ -423,6 +423,10 @@ "event": "Evento:", "enter": "Entrar", "leave": "Sair" + }, + "webhook": { + "label": "", + "webhook_id": "" } } }, @@ -601,7 +605,7 @@ "not_used": "Nunca foi utilizado" }, "current_user": "Esta actualmente ligado como {fullName}", - "is_owner": "Você é o proprietário.", + "is_owner": "Você é um proprietário.", "logout": "Sair", "change_password": { "header": "Alterar palavra-passe", @@ -726,13 +730,32 @@ "edit_card": { "header": "Configuração do cartão", "save": "Guardar", - "toggle_editor": "Alterar para editor" + "toggle_editor": "Alterar para editor", + "pick_card": "Escolha o cartão que deseja adicionar.", + "add": "Adicionar Cartão", + "edit": "Editar", + "delete": "Apagar" }, "migrate": { "header": "Configuração Incompatível", "para_no_id": "Este elemento não possui um ID. Por favor adicione um ID a este elemento em 'ui-lovelace.yaml'.", "para_migrate": "O Home Assistant pode adicionar IDs a todos os seus cartões e vistas automaticamente clicando no botão 'Migrar configuração'.", "migrate": "Migrar configuração" + }, + "header": "Editar UI", + "configure_ui": "Configurar UI", + "edit_view": { + "header": "Ver configuração", + "add": "Acrescentar vista", + "edit": "Editar vista", + "delete": "Apagar a vista" + }, + "save_config": { + "header": "Assumir controle sobre a interface do Lovelace", + "para": "Por omissão o Home Assistant irá manter a sua interface de utilizador, actualizando sempre que uma entidade nova ou componentes Lovelace fiquem disponíveis. Se assumir o controle não será possivel fazer alterações automáticas por si.", + "para_sure": "Tem certeza que deseja assumir o controle sobre a interface de utilizador?", + "cancel": "Cancelar", + "save": "Assumir o controle" } } } @@ -743,7 +766,8 @@ }, "common": { "loading": "A carregar", - "cancel": "Cancelar" + "cancel": "Cancelar", + "save": "Guardar" }, "duration": { "day": "{count} {count, plural,\n one {dia}\n other {dias}\n}", diff --git a/translations/ru.json b/translations/ru.json index 32df77c24f..f63699c76c 100644 --- a/translations/ru.json +++ b/translations/ru.json @@ -388,11 +388,11 @@ "label": "Home Assistant", "event": "Событие:", "start": "Запуск", - "shutdown": "Выключение" + "shutdown": "Завершение работы" }, "mqtt": { "label": "MQTT", - "topic": "Топик", + "topic": "Тема", "payload": "Значение (опционально)" }, "numeric_state": { diff --git a/translations/uk.json b/translations/uk.json index 34a09cbfd7..07bfdf8c67 100644 --- a/translations/uk.json +++ b/translations/uk.json @@ -50,7 +50,7 @@ }, "gas": { "off": "Чисто", - "on": "Виявлено" + "on": "Виявлено газ" }, "motion": { "off": "Немає руху", @@ -58,26 +58,26 @@ }, "occupancy": { "off": "Чисто", - "on": "Виявлено" + "on": "Виявлено присутність" }, "smoke": { "off": "Чисто", - "on": "Виявлено" + "on": "Виявлено дим" }, "sound": { "off": "Чисто", - "on": "Виявлено" + "on": "Виявлено звук" }, "vibration": { - "off": "Чисто", - "on": "Виявлено" + "off": "Не виявлено", + "on": "Виявлена вібрація" }, "opening": { "off": "Закрито", "on": "Відкритий" }, "safety": { - "off": "Безпека", + "off": "Безпечно", "on": "Небезпечно" }, "presence": { @@ -106,14 +106,14 @@ }, "garage_door": { "off": "ЗачиненІ", - "on": "Відкрито" + "on": "Відкриті" }, "heat": { "off": "Норма", "on": "Нагрівання" }, "window": { - "off": "Зачинено", + "off": "Зачинене", "on": "Відчинене" }, "lock": { @@ -255,6 +255,9 @@ "sunny": "Сонячно", "windy": "Вітряно", "windy-variant": "Вітряно" + }, + "vacuum": { + "idle": "Очікування" } }, "state_badge": { @@ -605,6 +608,8 @@ "lovelace": { "cards": { "shopping-list": { + "checked_items": "Позначені елементи", + "clear_items": "Очистити позначені елементи", "add_item": "Додати елемент" } }, @@ -612,20 +617,32 @@ "edit_card": { "header": "Конфігурація картки", "save": "Зберегти", + "toggle_editor": "Перемкнути редактор", "pick_card": "Виберіть картку, яку хочете додати.", "add": "Додати картку", "edit": "Редагувати", "delete": "Видалити" }, "migrate": { - "header": "Конфігурація несумісна" + "header": "Конфігурація несумісна", + "para_no_id": "Цей елемент не має ID. Додайте ID до цього елемента в 'ui-lovelace.yaml'.", + "para_migrate": "Домашній помічник може автоматично додавати ідентифікатори ID до всіх ваших карт і переглядів, натиснувши кнопку \"Перенести налаштування\".", + "migrate": "Перенесення конфігурації" }, "header": "Редагування інтерфейсу", + "configure_ui": "Налаштувати інтерфейс користувача", "edit_view": { - "header": "Перегляд Конфігурації " + "header": "Перегляд Конфігурації ", + "add": "Додати вигляд", + "edit": "Редагувати вигляд", + "delete": "Видалити вигляд" }, "save_config": { - "header": "Візьміть під свій контроль Lovelace UI" + "header": "Візьміть під свій контроль Lovelace UI", + "para": "За замовчуванням Home Assistant буде підтримувати ваш користувальницький інтерфейс, оновлюючи його, коли з'являться нові об'єкти або компоненти Lovelace. Якщо ви візьмете під контроль, ми більше не будемо автоматично вносити зміни для вас.", + "para_sure": "Ви впевнені, що хочете взяти під свій контроль користувальницький інтерфейс?", + "cancel": "Неважливо", + "save": "Взяти під контроль" } } } @@ -680,7 +697,8 @@ "disarm": "Зняття з охорони", "arm_home": "Поставити на охорону", "arm_away": "Охорона (не вдома)", - "arm_night": "Нічна охорона" + "arm_night": "Нічна охорона", + "armed_custom_bypass": "Користувацький обхід" }, "automation": { "last_triggered": "Спрацьовано", diff --git a/translations/vi.json b/translations/vi.json index 38c49a5f1f..65012c9e14 100644 --- a/translations/vi.json +++ b/translations/vi.json @@ -28,7 +28,7 @@ "disarmed": "Vô hiệu hóa", "armed_home": "Bảo vệ ở nhà", "armed_away": "Bảo vệ đi vắng", - "armed_night": "An ninh ban đêm", + "armed_night": "Ban đêm", "pending": "Đang chờ xử lý", "arming": "Kích hoạt", "disarming": "Giải giáp", @@ -747,8 +747,8 @@ "code": "Mã số", "clear_code": "Xóa", "disarm": "Vô hiệu hoá", - "arm_home": "An ninh ở nhà", - "arm_away": "An ninh đi vắng", + "arm_home": "Ở nhà", + "arm_away": "Đi vắng", "arm_night": "An ninh ban đêm", "armed_custom_bypass": "Bỏ qua tùy chỉnh" },