From f054cdc9efcee15a2f64a19632a7232343464dd2 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 21 Nov 2018 21:11:00 +0100 Subject: [PATCH 01/69] Use overrideIcon via data binding (#2078) --- src/components/entity/state-badge.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/entity/state-badge.js b/src/components/entity/state-badge.js index 783c36467a..ab3e0906ab 100644 --- a/src/components/entity/state-badge.js +++ b/src/components/entity/state-badge.js @@ -44,7 +44,7 @@ class StateBadge extends PolymerElement { id="icon" data-domain$="[[_computeDomain(stateObj)]]" data-state$="[[stateObj.state]]" - icon="[[_computeIcon(stateObj)]]" + icon="[[_computeIcon(stateObj, overrideIcon)]]" > `; } @@ -63,8 +63,8 @@ class StateBadge extends PolymerElement { return computeStateDomain(stateObj); } - _computeIcon(stateObj) { - return this.overrideIcon || stateIcon(stateObj); + _computeIcon(stateObj, overrideIcon) { + return overrideIcon || stateIcon(stateObj); } _updateIconAppearance(newVal) { From a82561355c7a34e856933e7d0c0851629639873f Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Thu, 22 Nov 2018 04:15:22 +0100 Subject: [PATCH 02/69] Dont change config on init (#2044) * dont change config on init * set default title empty * used firstUpdated instead of updated * prevent double events * check if val changed * typing * clean * lint * clean * prettier is having a fight --- .../lovelace/components/hui-entity-editor.ts | 4 +- .../components/hui-theme-select-editor.ts | 7 ++- .../hui-entities-card-editor.ts | 43 ++++++++------ .../config-elements/hui-glance-card-editor.ts | 56 +++++++++++-------- src/panels/lovelace/editor/hui-edit-card.ts | 9 ++- 5 files changed, 73 insertions(+), 46 deletions(-) diff --git a/src/panels/lovelace/components/hui-entity-editor.ts b/src/panels/lovelace/components/hui-entity-editor.ts index 886dc206a8..7c9212e3a1 100644 --- a/src/panels/lovelace/components/hui-entity-editor.ts +++ b/src/panels/lovelace/components/hui-entity-editor.ts @@ -52,7 +52,7 @@ export class HuiEntityEditor extends LitElement { private _addEntity() { const newConfigEntities = this.entities!.concat({ entity: "" }); - fireEvent(this, "change", { entities: newConfigEntities }); + fireEvent(this, "entities-changed", { entities: newConfigEntities }); } private _valueChanged(ev: Event): void { @@ -68,7 +68,7 @@ export class HuiEntityEditor extends LitElement { }; } - fireEvent(this, "change", { entities: newConfigEntities }); + fireEvent(this, "entities-changed", { entities: newConfigEntities }); } private renderStyle(): TemplateResult { diff --git a/src/panels/lovelace/components/hui-theme-select-editor.ts b/src/panels/lovelace/components/hui-theme-select-editor.ts index 8c8a4b4de1..71c9017183 100644 --- a/src/panels/lovelace/components/hui-theme-select-editor.ts +++ b/src/panels/lovelace/components/hui-theme-select-editor.ts @@ -31,7 +31,7 @@ export class HuiThemeSelectionEditor extends hassLocalizeLitMixin(LitElement) { > ${ @@ -57,8 +57,11 @@ export class HuiThemeSelectionEditor extends hassLocalizeLitMixin(LitElement) { } private _changed(ev): void { + if (!this.hass || ev.target.value === "") { + return; + } this.value = ev.target.value; - fireEvent(this, "change"); + fireEvent(this, "theme-changed"); } } 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 f4d761ddda..25452f64f2 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 @@ -26,11 +26,15 @@ export class HuiEntitiesCardEditor extends hassLocalizeLitMixin(LitElement) private _configEntities?: ConfigEntity[]; static get properties(): PropertyDeclarations { - return { - hass: {}, - _config: {}, - _configEntities: {}, - }; + return { hass: {}, _config: {}, _configEntities: {} }; + } + + get _title(): string { + return this._config!.title || ""; + } + + get _theme(): string { + return this._config!.theme || "Backend-selected"; } public setConfig(config: Config): void { @@ -47,20 +51,20 @@ export class HuiEntitiesCardEditor extends hassLocalizeLitMixin(LitElement) ${this.renderStyle()} { + if (!this._originalConfig) { + return; + } const conf = this._originalConfig; - const tag = conf!.type.startsWith(CUSTOM_TYPE_PREFIX) + const tag = conf.type.startsWith(CUSTOM_TYPE_PREFIX) ? conf!.type.substr(CUSTOM_TYPE_PREFIX.length) : `hui-${conf!.type}-card`; @@ -362,8 +364,9 @@ export class HuiEditCard extends hassLocalizeLitMixin(LitElement) { configElement.addEventListener("config-changed", (ev) => this._handleUIConfigChanged(ev.detail.config) ); - this._configValue = { format: "json", value: conf! }; + this._configValue = { format: "json", value: conf }; this._configElement = configElement; + this._updatePreview(conf); } } From 3497cb892e05c2981366e93270ed4b154098c687 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Thu, 22 Nov 2018 05:48:12 -0600 Subject: [PATCH 03/69] Convert toggle functions to TypeScript (#2082) * Convert toggle functions to TypeScript * Update hui-picture-glance-card.ts * Update hui-picture-glance-card.ts --- .../lovelace/cards/hui-entity-button-card.ts | 4 ++-- src/panels/lovelace/cards/hui-glance-card.ts | 4 ++-- .../lovelace/cards/hui-picture-entity-card.js | 2 +- .../lovelace/cards/hui-picture-glance-card.ts | 4 ++-- .../lovelace/common/entity/toggle-entity.js | 7 ------- .../lovelace/common/entity/toggle-entity.ts | 10 ++++++++++ ...on-off-entities.js => turn-on-off-entities.ts} | 15 +++++++++++---- ...urn-on-off-entity.js => turn-on-off-entity.ts} | 11 ++++++++--- src/panels/lovelace/common/handle-click.ts | 4 ++-- 9 files changed, 38 insertions(+), 23 deletions(-) delete mode 100644 src/panels/lovelace/common/entity/toggle-entity.js create mode 100644 src/panels/lovelace/common/entity/toggle-entity.ts rename src/panels/lovelace/common/entity/{turn-on-off-entities.js => turn-on-off-entities.ts} (78%) rename src/panels/lovelace/common/entity/{turn-on-off-entity.js => turn-on-off-entity.ts} (65%) diff --git a/src/panels/lovelace/cards/hui-entity-button-card.ts b/src/panels/lovelace/cards/hui-entity-button-card.ts index 0f6d0f5c99..de0d81a2e4 100644 --- a/src/panels/lovelace/cards/hui-entity-button-card.ts +++ b/src/panels/lovelace/cards/hui-entity-button-card.ts @@ -10,12 +10,12 @@ import { styleMap } from "lit-html/directives/styleMap"; import "../../../components/ha-card"; -import toggleEntity from "../common/entity/toggle-entity"; import isValidEntityId from "../../../common/entity/valid_entity_id"; import stateIcon from "../../../common/entity/state_icon"; import computeStateDomain from "../../../common/entity/compute_state_domain"; import computeStateName from "../../../common/entity/compute_state_name"; import applyThemesOnElement from "../../../common/dom/apply_themes_on_element"; +import { toggleEntity } from "../common/entity/toggle-entity"; import { HomeAssistant, LightEntity } from "../../../types"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; import { LovelaceCard, LovelaceConfig } from "../types"; @@ -199,7 +199,7 @@ class HuiEntityButtonCard extends hassLocalizeLitMixin(LitElement) const action = hold ? config.hold_action : config.tap_action || "more-info"; switch (action) { case "toggle": - toggleEntity(this.hass, entityId); + toggleEntity(this.hass!, entityId); break; case "call-service": if (!config.service) { diff --git a/src/panels/lovelace/cards/hui-glance-card.ts b/src/panels/lovelace/cards/hui-glance-card.ts index 3a09b856ed..d3c40ee8ca 100644 --- a/src/panels/lovelace/cards/hui-glance-card.ts +++ b/src/panels/lovelace/cards/hui-glance-card.ts @@ -13,12 +13,12 @@ import { HomeAssistant } from "../../../types"; import { LovelaceCard, LovelaceConfig, LovelaceCardEditor } from "../types"; import { longPress } from "../common/directives/long-press-directive"; import { EntityConfig } from "../entity-rows/types"; +import { toggleEntity } from "../common/entity/toggle-entity"; import computeStateDisplay from "../../../common/entity/compute_state_display"; import computeStateName from "../../../common/entity/compute_state_name"; import processConfigEntities from "../common/process-config-entities"; import applyThemesOnElement from "../../../common/dom/apply_themes_on_element"; -import toggleEntity from "../common/entity/toggle-entity"; import "../../../components/entity/state-badge"; import "../../../components/ha-card"; @@ -245,7 +245,7 @@ export class HuiGlanceCard extends hassLocalizeLitMixin(LitElement) const action = hold ? config.hold_action : config.tap_action || "more-info"; switch (action) { case "toggle": - toggleEntity(this.hass, entityId); + toggleEntity(this.hass!, entityId); break; case "call-service": const [domain, service] = config.service!.split(".", 2); diff --git a/src/panels/lovelace/cards/hui-picture-entity-card.js b/src/panels/lovelace/cards/hui-picture-entity-card.js index b16e9dab3e..03d6fa488c 100644 --- a/src/panels/lovelace/cards/hui-picture-entity-card.js +++ b/src/panels/lovelace/cards/hui-picture-entity-card.js @@ -7,10 +7,10 @@ import "../components/hui-image"; import computeDomain from "../../../common/entity/compute_domain"; import computeStateDisplay from "../../../common/entity/compute_state_display"; import computeStateName from "../../../common/entity/compute_state_name"; -import toggleEntity from "../common/entity/toggle-entity"; import EventsMixin from "../../../mixins/events-mixin"; import LocalizeMixin from "../../../mixins/localize-mixin"; +import { toggleEntity } from "../common/entity/toggle-entity"; import { longPressBind } from "../common/directives/long-press-directive"; const UNAVAILABLE = "Unavailable"; diff --git a/src/panels/lovelace/cards/hui-picture-glance-card.ts b/src/panels/lovelace/cards/hui-picture-glance-card.ts index e12e1c22e6..593567bf88 100644 --- a/src/panels/lovelace/cards/hui-picture-glance-card.ts +++ b/src/panels/lovelace/cards/hui-picture-glance-card.ts @@ -9,13 +9,13 @@ import { LovelaceCard, LovelaceConfig } from "../types"; import { EntityConfig } from "../entity-rows/types"; import { navigate } from "../../../common/navigate"; import { HomeAssistant } from "../../../types"; +import { toggleEntity } from "../common/entity/toggle-entity"; import computeStateDisplay from "../../../common/entity/compute_state_display"; import computeStateName from "../../../common/entity/compute_state_name"; import processConfigEntities from "../common/process-config-entities"; import computeDomain from "../../../common/entity/compute_domain"; import stateIcon from "../../../common/entity/state_icon"; -import toggleEntity from "../common/entity/toggle-entity"; import "../../../components/ha-card"; import "../../../components/ha-icon"; @@ -172,7 +172,7 @@ class HuiPictureGlanceCard extends hassLocalizeLitMixin(LitElement) } private _callService(ev: MouseEvent): void { - toggleEntity(this.hass, (ev.target as any).entity); + toggleEntity(this.hass!, (ev.target as any).entity); } private _handleImageClick(): void { diff --git a/src/panels/lovelace/common/entity/toggle-entity.js b/src/panels/lovelace/common/entity/toggle-entity.js deleted file mode 100644 index 91deadcd7b..0000000000 --- a/src/panels/lovelace/common/entity/toggle-entity.js +++ /dev/null @@ -1,7 +0,0 @@ -import { STATES_OFF } from "../../../../common/const"; -import turnOnOffEntity from "./turn-on-off-entity"; - -export default function toggleEntity(hass, entityId) { - const turnOn = STATES_OFF.includes(hass.states[entityId].state); - turnOnOffEntity(hass, entityId, turnOn); -} diff --git a/src/panels/lovelace/common/entity/toggle-entity.ts b/src/panels/lovelace/common/entity/toggle-entity.ts new file mode 100644 index 0000000000..873821127c --- /dev/null +++ b/src/panels/lovelace/common/entity/toggle-entity.ts @@ -0,0 +1,10 @@ +import { STATES_OFF } from "../../../../common/const"; +import { turnOnOffEntity } from "./turn-on-off-entity"; +import { HomeAssistant } from "../../../../types"; +export const toggleEntity = ( + hass: HomeAssistant, + entityId: string +): Promise => { + const turnOn = STATES_OFF.includes(hass.states[entityId].state); + return turnOnOffEntity(hass, entityId, turnOn); +}; diff --git a/src/panels/lovelace/common/entity/turn-on-off-entities.js b/src/panels/lovelace/common/entity/turn-on-off-entities.ts similarity index 78% rename from src/panels/lovelace/common/entity/turn-on-off-entities.js rename to src/panels/lovelace/common/entity/turn-on-off-entities.ts index 7f46f4414b..495413e9d9 100644 --- a/src/panels/lovelace/common/entity/turn-on-off-entities.js +++ b/src/panels/lovelace/common/entity/turn-on-off-entities.ts @@ -1,7 +1,12 @@ -import { STATES_OFF } from "../../../../common/const"; import computeDomain from "../../../../common/entity/compute_domain"; +import { STATES_OFF } from "../../../../common/const"; +import { HomeAssistant } from "../../../../types"; -export default function turnOnOffEntities(hass, entityIds, turnOn = true) { +export const turnOnOffEntities = ( + hass: HomeAssistant, + entityIds: string[], + turnOn = true +): void => { const domainsToCall = {}; entityIds.forEach((entityId) => { if (STATES_OFF.includes(hass.states[entityId].state) === turnOn) { @@ -10,7 +15,9 @@ export default function turnOnOffEntities(hass, entityIds, turnOn = true) { ? stateDomain : "homeassistant"; - if (!(serviceDomain in domainsToCall)) domainsToCall[serviceDomain] = []; + if (!(serviceDomain in domainsToCall)) { + domainsToCall[serviceDomain] = []; + } domainsToCall[serviceDomain].push(entityId); } }); @@ -31,4 +38,4 @@ export default function turnOnOffEntities(hass, entityIds, turnOn = true) { const entities = domainsToCall[domain]; hass.callService(domain, service, { entity_id: entities }); }); -} +}; diff --git a/src/panels/lovelace/common/entity/turn-on-off-entity.js b/src/panels/lovelace/common/entity/turn-on-off-entity.ts similarity index 65% rename from src/panels/lovelace/common/entity/turn-on-off-entity.js rename to src/panels/lovelace/common/entity/turn-on-off-entity.ts index 6a19f0ad74..8823438bf3 100644 --- a/src/panels/lovelace/common/entity/turn-on-off-entity.js +++ b/src/panels/lovelace/common/entity/turn-on-off-entity.ts @@ -1,6 +1,11 @@ import computeDomain from "../../../../common/entity/compute_domain"; +import { HomeAssistant } from "../../../../types"; -export default function turnOnOffEntity(hass, entityId, turnOn = true) { +export const turnOnOffEntity = ( + hass: HomeAssistant, + entityId: string, + turnOn = true +): Promise => { const stateDomain = computeDomain(entityId); const serviceDomain = stateDomain === "group" ? "homeassistant" : stateDomain; @@ -16,5 +21,5 @@ export default function turnOnOffEntity(hass, entityId, turnOn = true) { service = turnOn ? "turn_on" : "turn_off"; } - hass.callService(serviceDomain, service, { entity_id: entityId }); -} + return hass.callService(serviceDomain, service, { entity_id: entityId }); +}; diff --git a/src/panels/lovelace/common/handle-click.ts b/src/panels/lovelace/common/handle-click.ts index c7d1321228..f420a0f39a 100644 --- a/src/panels/lovelace/common/handle-click.ts +++ b/src/panels/lovelace/common/handle-click.ts @@ -2,7 +2,7 @@ import { HomeAssistant } from "../../../types"; import { LovelaceElementConfig } from "../elements/types"; import { fireEvent } from "../../../common/dom/fire_event"; import { navigate } from "../../../common/navigate"; -import toggleEntity from "../../../../src/panels/lovelace/common/entity/toggle-entity"; +import { toggleEntity } from "../../../../src/panels/lovelace/common/entity/toggle-entity"; export const handleClick = ( node: HTMLElement, @@ -28,7 +28,7 @@ export const handleClick = ( navigate(node, config.navigation_path ? config.navigation_path : ""); break; case "toggle": - toggleEntity(hass, config.entity); + toggleEntity(hass, config.entity!); break; case "call-service": { if (config.service) { From 6885abd2348ab7b4cfe0529ddbee1da5b94f834b Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Fri, 23 Nov 2018 01:56:35 -0600 Subject: [PATCH 04/69] Convert shopping-list add item call to websockets (#2080) --- src/data/shopping-list.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/data/shopping-list.ts b/src/data/shopping-list.ts index 14ff992abd..e2c57cdc78 100644 --- a/src/data/shopping-list.ts +++ b/src/data/shopping-list.ts @@ -36,6 +36,7 @@ export const addItem = ( hass: HomeAssistant, name: string ): Promise => - hass.callApi("POST", "shopping_list/item", { + hass.callWS({ + type: "shopping_list/items/add", name, }); From 785ed6f9dbcd9fe7a6118108f38e046a842ff614 Mon Sep 17 00:00:00 2001 From: Simon Holzmayer Date: Fri, 23 Nov 2018 11:52:48 +0100 Subject: [PATCH 05/69] add "for" input field to numeric_state in trigger editor (#2081) --- src/panels/config/js/trigger/numeric_state.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/panels/config/js/trigger/numeric_state.js b/src/panels/config/js/trigger/numeric_state.js index 41cf07838d..cfa9ead60f 100644 --- a/src/panels/config/js/trigger/numeric_state.js +++ b/src/panels/config/js/trigger/numeric_state.js @@ -24,7 +24,18 @@ export default class NumericStateTrigger extends Component { /* eslint-disable camelcase */ render({ trigger, hass, localize }) { const { value_template, entity_id, below, above } = trigger; + let trgFor = trigger.for; + if (trgFor && (trgFor.hours || trgFor.minutes || trgFor.seconds)) { + // If the trigger was defined using the yaml dict syntax, convert it to + // the equivalent string format + let { hours = 0, minutes = 0, seconds = 0 } = trgFor; + hours = hours.toString(); + minutes = minutes.toString().padStart(2, "0"); + seconds = seconds.toString().padStart(2, "0"); + + trgFor = `${hours}:${minutes}:${seconds}`; + } return (
+
); } From d41a4cf78b8c6bb56ed987925ec049b689d62e56 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 23 Nov 2018 17:39:50 +0100 Subject: [PATCH 06/69] Generate Lovelace config on the fly (#2091) * Generate Lovelace config on the fly * Disable editing * Fix domain name title rendering --- src/common/entity/extract_views.ts | 9 +- src/common/entity/get_view_entities.ts | 2 +- src/common/entity/split_by_groups.ts | 7 +- .../common/generate-lovelace-config.ts | 236 ++++++++++++++++++ src/panels/lovelace/ha-panel-lovelace.js | 21 +- src/panels/lovelace/hui-root.js | 4 + 6 files changed, 266 insertions(+), 13 deletions(-) create mode 100644 src/panels/lovelace/common/generate-lovelace-config.ts diff --git a/src/common/entity/extract_views.ts b/src/common/entity/extract_views.ts index bcc7084646..d5679e5518 100644 --- a/src/common/entity/extract_views.ts +++ b/src/common/entity/extract_views.ts @@ -1,14 +1,15 @@ -import { HassEntities, HassEntity } from "home-assistant-js-websocket"; +import { HassEntities } from "home-assistant-js-websocket"; import { DEFAULT_VIEW_ENTITY_ID } from "../const"; +import { GroupEntity } from "../../types"; // Return an ordered array of available views -export default function extractViews(entities: HassEntities): HassEntity[] { - const views: HassEntity[] = []; +export default function extractViews(entities: HassEntities): GroupEntity[] { + const views: GroupEntity[] = []; Object.keys(entities).forEach((entityId) => { const entity = entities[entityId]; if (entity.attributes.view) { - views.push(entity); + views.push(entity as GroupEntity); } }); diff --git a/src/common/entity/get_view_entities.ts b/src/common/entity/get_view_entities.ts index 62aa7e5d89..c3d249cfcd 100644 --- a/src/common/entity/get_view_entities.ts +++ b/src/common/entity/get_view_entities.ts @@ -8,7 +8,7 @@ import { GroupEntity } from "../../types"; export default function getViewEntities( entities: HassEntities, view: GroupEntity -) { +): HassEntities { const viewEntities = {}; view.attributes.entity_id.forEach((entityId) => { diff --git a/src/common/entity/split_by_groups.ts b/src/common/entity/split_by_groups.ts index a894472d8c..aed1ab7f0e 100644 --- a/src/common/entity/split_by_groups.ts +++ b/src/common/entity/split_by_groups.ts @@ -1,18 +1,19 @@ import computeDomain from "./compute_domain"; -import { HassEntity, HassEntities } from "home-assistant-js-websocket"; +import { HassEntities } from "home-assistant-js-websocket"; +import { GroupEntity } from "../../types"; // Split a collection into a list of groups and a 'rest' list of ungrouped // entities. // Returns { groups: [], ungrouped: {} } export default function splitByGroups(entities: HassEntities) { - const groups: HassEntity[] = []; + const groups: GroupEntity[] = []; const ungrouped: HassEntities = {}; Object.keys(entities).forEach((entityId) => { const entity = entities[entityId]; if (computeDomain(entityId) === "group") { - groups.push(entity); + groups.push(entity as GroupEntity); } else { ungrouped[entityId] = entity; } diff --git a/src/panels/lovelace/common/generate-lovelace-config.ts b/src/panels/lovelace/common/generate-lovelace-config.ts new file mode 100644 index 0000000000..ca8b4fd0e9 --- /dev/null +++ b/src/panels/lovelace/common/generate-lovelace-config.ts @@ -0,0 +1,236 @@ +import { HomeAssistant, GroupEntity } from "../../../types"; +import { HassEntity, HassEntities } from "home-assistant-js-websocket"; +import extractViews from "../../../common/entity/extract_views"; +import getViewEntities from "../../../common/entity/get_view_entities"; +import computeStateName from "../../../common/entity/compute_state_name"; +import splitByGroups from "../../../common/entity/split_by_groups"; +import computeObjectId from "../../../common/entity/compute_object_id"; +import computeStateDomain from "../../../common/entity/compute_state_domain"; +import { LocalizeFunc } from "../../../mixins/localize-base-mixin"; + +interface CardConfig { + id?: string; + type: string; + [key: string]: any; +} + +interface ViewConfig { + title?: string; + badges?: string[]; + cards?: CardConfig[]; + id?: string; + icon?: string; +} + +interface LovelaceConfig { + _frontendAuto: boolean; + title?: string; + views: ViewConfig[]; +} + +const DEFAULT_VIEW_ENTITY_ID = "group.default_view"; +const DOMAINS_BADGES = [ + "binary_sensor", + "device_tracker", + "mailbox", + "sensor", + "sun", + "timer", +]; +const HIDE_DOMAIN = new Set(["persistent_notification", "configurator"]); + +const computeCards = (title: string, states: HassEntity[]): CardConfig[] => { + const cards: CardConfig[] = []; + + // For entity card + const entities: string[] = []; + + states.forEach((stateObj) => { + const domain = computeStateDomain(stateObj); + if (domain === "alarm_control_panel") { + cards.push({ + type: "alarm-panel", + entity: stateObj.entity_id, + }); + } else if (domain === "climate") { + cards.push({ + type: "thermostat", + entity: stateObj.entity_id, + }); + } else if (domain === "media_player") { + cards.push({ + type: "media-control", + entity: stateObj.entity_id, + }); + } else if (domain === "weather") { + cards.push({ + type: "weather-forecast", + entity: stateObj.entity_id, + }); + } else { + entities.push(stateObj.entity_id); + } + }); + + if (entities.length > 0) { + cards.unshift({ + title, + type: "entities", + entities, + }); + } + + return cards; +}; + +const computeDefaultViewStates = (hass: HomeAssistant): HassEntities => { + const states = {}; + Object.keys(hass.states).forEach((entityId) => { + const stateObj = hass.states[entityId]; + if ( + !stateObj.attributes.hidden && + !HIDE_DOMAIN.has(computeStateDomain(stateObj)) + ) { + states[entityId] = hass.states[entityId]; + } + }); + return states; +}; + +const generateViewConfig = ( + localize: LocalizeFunc, + id: string, + title: string | undefined, + icon: string | undefined, + entities: HassEntities, + groupOrders: { [entityId: string]: number } +): ViewConfig => { + const splitted = splitByGroups(entities); + splitted.groups.sort( + (gr1, gr2) => groupOrders[gr1.entity_id] - groupOrders[gr2.entity_id] + ); + + const badgeEntities: { [domain: string]: string[] } = {}; + const ungroupedEntitites: { [domain: string]: string[] } = {}; + + // Organize ungrouped entities in badges/ungrouped things + Object.keys(splitted.ungrouped).forEach((entityId) => { + const state = splitted.ungrouped[entityId]; + const domain = computeStateDomain(state); + + const coll = DOMAINS_BADGES.includes(domain) + ? badgeEntities + : ungroupedEntitites; + + if (!(domain in coll)) { + coll[domain] = []; + } + + coll[domain].push(state.entity_id); + }); + + let badges: string[] = []; + DOMAINS_BADGES.forEach((domain) => { + if (domain in badgeEntities) { + badges = badges.concat(badgeEntities[domain]); + } + }); + + let cards: CardConfig[] = []; + + splitted.groups.forEach((groupEntity) => { + cards = cards.concat( + computeCards( + computeStateName(groupEntity), + groupEntity.attributes.entity_id.map((entityId) => entities[entityId]) + ) + ); + }); + + Object.keys(ungroupedEntitites) + .sort() + .forEach((domain) => { + cards = cards.concat( + computeCards( + localize(`domain.${domain}`), + ungroupedEntitites[domain].map((entityId) => entities[entityId]) + ) + ); + }); + + return { + id, + title, + icon, + badges, + cards, + }; +}; + +export const generateLovelaceConfig = ( + hass: HomeAssistant, + localize: LocalizeFunc +): LovelaceConfig => { + const viewEntities = extractViews(hass.states); + + const views = viewEntities.map((viewEntity: GroupEntity) => { + const states = getViewEntities(hass.states, viewEntity); + + // In the case of a normal view, we use group order as specified in view + const groupOrders = {}; + Object.keys(states).forEach((entityId, idx) => { + groupOrders[entityId] = idx; + }); + + return generateViewConfig( + localize, + computeObjectId(viewEntity.entity_id), + computeStateName(viewEntity), + viewEntity.attributes.icon, + states, + groupOrders + ); + }); + + let title = hass.config.location_name; + + // User can override default view. If they didn't, we will add one + // that contains all entities. + if ( + viewEntities.length === 0 || + viewEntities[0].entity_id !== DEFAULT_VIEW_ENTITY_ID + ) { + const states = computeDefaultViewStates(hass); + + // In the case of a default view, we want to use the group order attribute + const groupOrders = {}; + Object.keys(states).forEach((entityId) => { + const stateObj = states[entityId]; + if (stateObj.attributes.order) { + groupOrders[entityId] = stateObj.attributes.order; + } + }); + + views.unshift( + generateViewConfig( + localize, + "default_view", + "Home", + undefined, + states, + groupOrders + ) + ); + + // Make sure we don't have Home as title and first tab. + if (views.length > 1 && title === "Home") { + title = "Home Assistant"; + } + } + + return { + _frontendAuto: true, + title, + views, + }; +}; diff --git a/src/panels/lovelace/ha-panel-lovelace.js b/src/panels/lovelace/ha-panel-lovelace.js index a866a9eda9..f69434e714 100644 --- a/src/panels/lovelace/ha-panel-lovelace.js +++ b/src/panels/lovelace/ha-panel-lovelace.js @@ -5,8 +5,9 @@ import "@polymer/paper-button/paper-button"; import "../../layouts/hass-loading-screen"; import "../../layouts/hass-error-screen"; import "./hui-root"; +import localizeMixin from "../../mixins/localize-mixin"; -class Lovelace extends PolymerElement { +class Lovelace extends localizeMixin(PolymerElement) { static get template() { return html` + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-sensor-entity-row": HuiSensorEntityRow; + } +} + +customElements.define("hui-sensor-entity-row", HuiSensorEntityRow); From 412b7595d2afc21da4b7b63dc3d3a7a7bf37cacc Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 23 Nov 2018 20:42:41 +0100 Subject: [PATCH 08/69] Handle non existing states (#2098) --- .../common/generate-lovelace-config.ts | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/panels/lovelace/common/generate-lovelace-config.ts b/src/panels/lovelace/common/generate-lovelace-config.ts index ca8b4fd0e9..aa5f912d28 100644 --- a/src/panels/lovelace/common/generate-lovelace-config.ts +++ b/src/panels/lovelace/common/generate-lovelace-config.ts @@ -7,6 +7,7 @@ import splitByGroups from "../../../common/entity/split_by_groups"; import computeObjectId from "../../../common/entity/compute_object_id"; import computeStateDomain from "../../../common/entity/compute_state_domain"; import { LocalizeFunc } from "../../../mixins/localize-base-mixin"; +import computeDomain from "../../../common/entity/compute_domain"; interface CardConfig { id?: string; @@ -39,38 +40,42 @@ const DOMAINS_BADGES = [ ]; const HIDE_DOMAIN = new Set(["persistent_notification", "configurator"]); -const computeCards = (title: string, states: HassEntity[]): CardConfig[] => { +const computeCards = ( + title: string, + states: Array<[string, HassEntity]> +): CardConfig[] => { const cards: CardConfig[] = []; // For entity card const entities: string[] = []; - states.forEach((stateObj) => { - const domain = computeStateDomain(stateObj); + for (const [entityId /*, stateObj */] of states) { + const domain = computeDomain(entityId); + if (domain === "alarm_control_panel") { cards.push({ type: "alarm-panel", - entity: stateObj.entity_id, + entity: entityId, }); } else if (domain === "climate") { cards.push({ type: "thermostat", - entity: stateObj.entity_id, + entity: entityId, }); } else if (domain === "media_player") { cards.push({ type: "media-control", - entity: stateObj.entity_id, + entity: entityId, }); } else if (domain === "weather") { cards.push({ type: "weather-forecast", - entity: stateObj.entity_id, + entity: entityId, }); } else { - entities.push(stateObj.entity_id); + entities.push(entityId); } - }); + } if (entities.length > 0) { cards.unshift({ @@ -142,7 +147,9 @@ const generateViewConfig = ( cards = cards.concat( computeCards( computeStateName(groupEntity), - groupEntity.attributes.entity_id.map((entityId) => entities[entityId]) + groupEntity.attributes.entity_id.map( + (entityId): [string, HassEntity] => [entityId, entities[entityId]] + ) ) ); }); @@ -153,7 +160,9 @@ const generateViewConfig = ( cards = cards.concat( computeCards( localize(`domain.${domain}`), - ungroupedEntitites[domain].map((entityId) => entities[entityId]) + ungroupedEntitites[domain].map( + (entityId): [string, HassEntity] => [entityId, entities[entityId]] + ) ) ); }); From 101a364a83d2a20fa472e88a86102b037ed0f3d2 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Sat, 24 Nov 2018 14:03:54 +0100 Subject: [PATCH 09/69] Type LovelaceConfig -> LovelaceCardConfig (#2103) * LovelaceConfig -> LovelaceCardConfig * Typo --- .../lovelace/cards/hui-conditional-card.ts | 6 ++-- .../lovelace/cards/hui-entities-card.ts | 4 +-- .../lovelace/cards/hui-entity-button-card.ts | 4 +-- src/panels/lovelace/cards/hui-error-card.ts | 8 ++--- src/panels/lovelace/cards/hui-gauge-card.ts | 4 +-- src/panels/lovelace/cards/hui-glance-card.ts | 4 +-- src/panels/lovelace/cards/hui-iframe-card.ts | 4 +-- src/panels/lovelace/cards/hui-light-card.ts | 4 +-- .../lovelace/cards/hui-markdown-card.ts | 4 +-- src/panels/lovelace/cards/hui-picture-card.ts | 4 +-- .../cards/hui-picture-elements-card.ts | 4 +-- .../lovelace/cards/hui-picture-glance-card.ts | 4 +-- .../lovelace/cards/hui-shopping-list-card.ts | 4 +-- src/panels/lovelace/cards/hui-stack-card.ts | 6 ++-- .../lovelace/cards/hui-thermostat-card.ts | 4 +-- src/panels/lovelace/common/data.ts | 4 +-- .../common/generate-lovelace-config.ts | 33 +++++-------------- .../lovelace/components/hui-card-options.ts | 4 +-- .../lovelace/editor/hui-card-preview.ts | 6 ++-- .../lovelace/editor/hui-dialog-edit-card.ts | 4 +-- src/panels/lovelace/editor/hui-edit-card.ts | 15 +++++---- src/panels/lovelace/editor/types.ts | 4 +-- src/panels/lovelace/types.ts | 22 ++++++++++--- 23 files changed, 80 insertions(+), 80 deletions(-) diff --git a/src/panels/lovelace/cards/hui-conditional-card.ts b/src/panels/lovelace/cards/hui-conditional-card.ts index 5111855b1a..4646b7386b 100644 --- a/src/panels/lovelace/cards/hui-conditional-card.ts +++ b/src/panels/lovelace/cards/hui-conditional-card.ts @@ -1,7 +1,7 @@ import createCardElement from "../common/create-card-element"; import { computeCardSize } from "../common/compute-card-size"; import { HomeAssistant } from "../../../types"; -import { LovelaceCard, LovelaceConfig } from "../types"; +import { LovelaceCard, LovelaceCardConfig } from "../types"; interface Condition { entity: string; @@ -9,8 +9,8 @@ interface Condition { state_not?: string; } -interface Config extends LovelaceConfig { - card: LovelaceConfig; +interface Config extends LovelaceCardConfig { + card: LovelaceCardConfig; conditions: Condition[]; } diff --git a/src/panels/lovelace/cards/hui-entities-card.ts b/src/panels/lovelace/cards/hui-entities-card.ts index 2689fa4ad9..cbb51e71a7 100644 --- a/src/panels/lovelace/cards/hui-entities-card.ts +++ b/src/panels/lovelace/cards/hui-entities-card.ts @@ -14,7 +14,7 @@ import { DOMAINS_HIDE_MORE_INFO } from "../../../common/const"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; import { HomeAssistant } from "../../../types"; import { EntityConfig, EntityRow } from "../entity-rows/types"; -import { LovelaceCard, LovelaceConfig, LovelaceCardEditor } from "../types"; +import { LovelaceCard, LovelaceCardConfig, LovelaceCardEditor } from "../types"; import processConfigEntities from "../common/process-config-entities"; import createRowElement from "../common/create-row-element"; import computeDomain from "../../../common/entity/compute_domain"; @@ -29,7 +29,7 @@ export interface ConfigEntity extends EntityConfig { url?: string; } -export interface Config extends LovelaceConfig { +export interface Config extends LovelaceCardConfig { show_header_toggle?: boolean; title?: string; entities: ConfigEntity[]; diff --git a/src/panels/lovelace/cards/hui-entity-button-card.ts b/src/panels/lovelace/cards/hui-entity-button-card.ts index de0d81a2e4..78c0320e26 100644 --- a/src/panels/lovelace/cards/hui-entity-button-card.ts +++ b/src/panels/lovelace/cards/hui-entity-button-card.ts @@ -18,11 +18,11 @@ import applyThemesOnElement from "../../../common/dom/apply_themes_on_element"; import { toggleEntity } from "../common/entity/toggle-entity"; import { HomeAssistant, LightEntity } from "../../../types"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; -import { LovelaceCard, LovelaceConfig } from "../types"; +import { LovelaceCard, LovelaceCardConfig } from "../types"; import { longPress } from "../common/directives/long-press-directive"; import { fireEvent } from "../../../common/dom/fire_event"; -interface Config extends LovelaceConfig { +interface Config extends LovelaceCardConfig { entity: string; name?: string; icon?: string; diff --git a/src/panels/lovelace/cards/hui-error-card.ts b/src/panels/lovelace/cards/hui-error-card.ts index 5aa785d62d..6d89c406c9 100644 --- a/src/panels/lovelace/cards/hui-error-card.ts +++ b/src/panels/lovelace/cards/hui-error-card.ts @@ -1,11 +1,11 @@ import { html, LitElement } from "@polymer/lit-element"; -import { LovelaceCard, LovelaceConfig } from "../types"; +import { LovelaceCard, LovelaceCardConfig } from "../types"; import { TemplateResult } from "lit-html"; -interface Config extends LovelaceConfig { +interface Config extends LovelaceCardConfig { error: string; - origConfig: LovelaceConfig; + origConfig: LovelaceCardConfig; } class HuiErrorCard extends LitElement implements LovelaceCard { @@ -50,7 +50,7 @@ class HuiErrorCard extends LitElement implements LovelaceCard { `; } - private _toStr(config: LovelaceConfig): string { + private _toStr(config: LovelaceCardConfig): string { return JSON.stringify(config, null, 2); } } diff --git a/src/panels/lovelace/cards/hui-gauge-card.ts b/src/panels/lovelace/cards/hui-gauge-card.ts index 5fbfeece6f..e901f5d3cf 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, LovelaceConfig } from "../types"; +import { LovelaceCard, LovelaceCardConfig } from "../types"; import { HomeAssistant } from "../../../types"; import { fireEvent } from "../../../common/dom/fire_event"; @@ -16,7 +16,7 @@ import { hasConfigOrEntityChanged } from "../common/has-changed"; import "../../../components/ha-card"; -interface Config extends LovelaceConfig { +interface Config extends LovelaceCardConfig { entity: string; title?: string; unit_of_measurement?: string; diff --git a/src/panels/lovelace/cards/hui-glance-card.ts b/src/panels/lovelace/cards/hui-glance-card.ts index d3c40ee8ca..246a0e564d 100644 --- a/src/panels/lovelace/cards/hui-glance-card.ts +++ b/src/panels/lovelace/cards/hui-glance-card.ts @@ -10,7 +10,7 @@ import { classMap } from "lit-html/directives/classMap"; import { fireEvent } from "../../../common/dom/fire_event"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; import { HomeAssistant } from "../../../types"; -import { LovelaceCard, LovelaceConfig, LovelaceCardEditor } from "../types"; +import { LovelaceCard, LovelaceCardConfig, LovelaceCardEditor } from "../types"; import { longPress } from "../common/directives/long-press-directive"; import { EntityConfig } from "../entity-rows/types"; import { toggleEntity } from "../common/entity/toggle-entity"; @@ -31,7 +31,7 @@ export interface ConfigEntity extends EntityConfig { service_data?: object; } -export interface Config extends LovelaceConfig { +export interface Config extends LovelaceCardConfig { show_name?: boolean; show_state?: boolean; title?: string; diff --git a/src/panels/lovelace/cards/hui-iframe-card.ts b/src/panels/lovelace/cards/hui-iframe-card.ts index 822f60f870..a964bcac90 100644 --- a/src/panels/lovelace/cards/hui-iframe-card.ts +++ b/src/panels/lovelace/cards/hui-iframe-card.ts @@ -2,11 +2,11 @@ import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; import "../../../components/ha-card"; -import { LovelaceCard, LovelaceConfig } from "../types"; +import { LovelaceCard, LovelaceCardConfig } from "../types"; import { TemplateResult } from "lit-html"; import { styleMap } from "lit-html/directives/styleMap"; -interface Config extends LovelaceConfig { +interface Config extends LovelaceCardConfig { aspect_ratio?: string; title?: string; url: string; diff --git a/src/panels/lovelace/cards/hui-light-card.ts b/src/panels/lovelace/cards/hui-light-card.ts index 1bbf158271..99e2c2c613 100644 --- a/src/panels/lovelace/cards/hui-light-card.ts +++ b/src/panels/lovelace/cards/hui-light-card.ts @@ -12,7 +12,7 @@ import { jQuery } from "../../../resources/jquery"; import { roundSliderStyle } from "../../../resources/jquery.roundslider"; import { HomeAssistant, LightEntity } from "../../../types"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; -import { LovelaceCard, LovelaceConfig } from "../types"; +import { LovelaceCard, LovelaceCardConfig } from "../types"; import { longPress } from "../common/directives/long-press-directive"; import stateIcon from "../../../common/entity/state_icon"; @@ -37,7 +37,7 @@ const lightConfig = { showTooltip: false, }; -interface Config extends LovelaceConfig { +interface Config extends LovelaceCardConfig { entity: string; name?: string; theme?: string; diff --git a/src/panels/lovelace/cards/hui-markdown-card.ts b/src/panels/lovelace/cards/hui-markdown-card.ts index 5cedf5873b..99380293a8 100644 --- a/src/panels/lovelace/cards/hui-markdown-card.ts +++ b/src/panels/lovelace/cards/hui-markdown-card.ts @@ -4,10 +4,10 @@ import { classMap } from "lit-html/directives/classMap"; import "../../../components/ha-card"; import "../../../components/ha-markdown"; -import { LovelaceCard, LovelaceConfig } from "../types"; +import { LovelaceCard, LovelaceCardConfig } from "../types"; import { TemplateResult } from "lit-html"; -interface Config extends LovelaceConfig { +interface Config extends LovelaceCardConfig { content: string; title?: string; } diff --git a/src/panels/lovelace/cards/hui-picture-card.ts b/src/panels/lovelace/cards/hui-picture-card.ts index e988c0ea97..f5744a5c7f 100644 --- a/src/panels/lovelace/cards/hui-picture-card.ts +++ b/src/panels/lovelace/cards/hui-picture-card.ts @@ -2,13 +2,13 @@ import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; import "../../../components/ha-card"; -import { LovelaceCard, LovelaceConfig } from "../types"; +import { LovelaceCard, LovelaceCardConfig } from "../types"; import { navigate } from "../../../common/navigate"; import { HomeAssistant } from "../../../types"; import { TemplateResult } from "lit-html"; import { classMap } from "lit-html/directives/classMap"; -interface Config extends LovelaceConfig { +interface Config extends LovelaceCardConfig { image?: string; navigation_path?: string; service?: string; diff --git a/src/panels/lovelace/cards/hui-picture-elements-card.ts b/src/panels/lovelace/cards/hui-picture-elements-card.ts index d99cdb3249..4d77fdaab8 100644 --- a/src/panels/lovelace/cards/hui-picture-elements-card.ts +++ b/src/panels/lovelace/cards/hui-picture-elements-card.ts @@ -3,11 +3,11 @@ import { TemplateResult } from "lit-html"; import createHuiElement from "../common/create-hui-element"; -import { LovelaceCard, LovelaceConfig } from "../types"; +import { LovelaceCard, LovelaceCardConfig } from "../types"; import { HomeAssistant } from "../../../types"; import { LovelaceElementConfig, LovelaceElement } from "../elements/types"; -interface Config extends LovelaceConfig { +interface Config extends LovelaceCardConfig { title?: string; image: string; elements: LovelaceElementConfig[]; diff --git a/src/panels/lovelace/cards/hui-picture-glance-card.ts b/src/panels/lovelace/cards/hui-picture-glance-card.ts index 593567bf88..776126ddb6 100644 --- a/src/panels/lovelace/cards/hui-picture-glance-card.ts +++ b/src/panels/lovelace/cards/hui-picture-glance-card.ts @@ -5,7 +5,7 @@ import { TemplateResult } from "lit-html"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; import { fireEvent } from "../../../common/dom/fire_event"; import { DOMAINS_TOGGLE } from "../../../common/const"; -import { LovelaceCard, LovelaceConfig } from "../types"; +import { LovelaceCard, LovelaceCardConfig } from "../types"; import { EntityConfig } from "../entity-rows/types"; import { navigate } from "../../../common/navigate"; import { HomeAssistant } from "../../../types"; @@ -23,7 +23,7 @@ import "../components/hui-image"; const STATES_OFF = new Set(["closed", "locked", "not_home", "off"]); -interface Config extends LovelaceConfig { +interface Config extends LovelaceCardConfig { entities: EntityConfig[]; title?: string; navigation_path?: string; diff --git a/src/panels/lovelace/cards/hui-shopping-list-card.ts b/src/panels/lovelace/cards/hui-shopping-list-card.ts index a9191f1dcb..1930dfbdff 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, LovelaceConfig } from "../types"; +import { LovelaceCard, LovelaceCardConfig } from "../types"; import { fetchItems, completeItem, @@ -19,7 +19,7 @@ import { addItem, } from "../../../data/shopping-list"; -interface Config extends LovelaceConfig { +interface Config extends LovelaceCardConfig { title?: string; } diff --git a/src/panels/lovelace/cards/hui-stack-card.ts b/src/panels/lovelace/cards/hui-stack-card.ts index 2bc6ca5022..cf2820cdc8 100644 --- a/src/panels/lovelace/cards/hui-stack-card.ts +++ b/src/panels/lovelace/cards/hui-stack-card.ts @@ -3,11 +3,11 @@ import { TemplateResult } from "lit-html"; import createCardElement from "../common/create-card-element"; -import { LovelaceCard, LovelaceConfig } from "../types"; +import { LovelaceCard, LovelaceCardConfig } from "../types"; import { HomeAssistant } from "../../../types"; -interface Config extends LovelaceConfig { - cards: LovelaceConfig[]; +interface Config extends LovelaceCardConfig { + cards: LovelaceCardConfig[]; } export abstract class HuiStackCard extends LitElement implements LovelaceCard { diff --git a/src/panels/lovelace/cards/hui-thermostat-card.ts b/src/panels/lovelace/cards/hui-thermostat-card.ts index a9491043eb..e39376c32a 100644 --- a/src/panels/lovelace/cards/hui-thermostat-card.ts +++ b/src/panels/lovelace/cards/hui-thermostat-card.ts @@ -15,7 +15,7 @@ import { hasConfigOrEntityChanged } from "../common/has-changed"; import { roundSliderStyle } from "../../../resources/jquery.roundslider"; import { HomeAssistant, ClimateEntity } from "../../../types"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; -import { LovelaceCard, LovelaceConfig } from "../types"; +import { LovelaceCard, LovelaceCardConfig } from "../types"; import "../../../components/ha-card"; import "../../../components/ha-icon"; @@ -43,7 +43,7 @@ const modeIcons = { idle: "hass:power-sleep", }; -interface Config extends LovelaceConfig { +interface Config extends LovelaceCardConfig { entity: string; theme?: string; } diff --git a/src/panels/lovelace/common/data.ts b/src/panels/lovelace/common/data.ts index 685c00c52b..373dccb4d6 100644 --- a/src/panels/lovelace/common/data.ts +++ b/src/panels/lovelace/common/data.ts @@ -1,5 +1,5 @@ import { HomeAssistant } from "../../../types"; -import { LovelaceConfig } from "../types"; +import { LovelaceCardConfig } from "../types"; export const getCardConfig = ( hass: HomeAssistant, @@ -13,7 +13,7 @@ export const getCardConfig = ( export const updateCardConfig = ( hass: HomeAssistant, cardId: string, - config: LovelaceConfig | string, + config: LovelaceCardConfig | string, configFormat: "json" | "yaml" ): Promise => hass.callWS({ diff --git a/src/panels/lovelace/common/generate-lovelace-config.ts b/src/panels/lovelace/common/generate-lovelace-config.ts index aa5f912d28..6109b96fef 100644 --- a/src/panels/lovelace/common/generate-lovelace-config.ts +++ b/src/panels/lovelace/common/generate-lovelace-config.ts @@ -1,4 +1,9 @@ import { HomeAssistant, GroupEntity } from "../../../types"; +import { + LovelaceConfig, + LovelaceCardConfig, + LovelaceViewConfig, +} from "../types"; import { HassEntity, HassEntities } from "home-assistant-js-websocket"; import extractViews from "../../../common/entity/extract_views"; import getViewEntities from "../../../common/entity/get_view_entities"; @@ -9,26 +14,6 @@ import computeStateDomain from "../../../common/entity/compute_state_domain"; import { LocalizeFunc } from "../../../mixins/localize-base-mixin"; import computeDomain from "../../../common/entity/compute_domain"; -interface CardConfig { - id?: string; - type: string; - [key: string]: any; -} - -interface ViewConfig { - title?: string; - badges?: string[]; - cards?: CardConfig[]; - id?: string; - icon?: string; -} - -interface LovelaceConfig { - _frontendAuto: boolean; - title?: string; - views: ViewConfig[]; -} - const DEFAULT_VIEW_ENTITY_ID = "group.default_view"; const DOMAINS_BADGES = [ "binary_sensor", @@ -43,8 +28,8 @@ const HIDE_DOMAIN = new Set(["persistent_notification", "configurator"]); const computeCards = ( title: string, states: Array<[string, HassEntity]> -): CardConfig[] => { - const cards: CardConfig[] = []; +): LovelaceCardConfig[] => { + const cards: LovelaceCardConfig[] = []; // For entity card const entities: string[] = []; @@ -109,7 +94,7 @@ const generateViewConfig = ( icon: string | undefined, entities: HassEntities, groupOrders: { [entityId: string]: number } -): ViewConfig => { +): LovelaceViewConfig => { const splitted = splitByGroups(entities); splitted.groups.sort( (gr1, gr2) => groupOrders[gr1.entity_id] - groupOrders[gr2.entity_id] @@ -141,7 +126,7 @@ const generateViewConfig = ( } }); - let cards: CardConfig[] = []; + let cards: LovelaceCardConfig[] = []; splitted.groups.forEach((groupEntity) => { cards = cards.concat( diff --git a/src/panels/lovelace/components/hui-card-options.ts b/src/panels/lovelace/components/hui-card-options.ts index 436cfa65c7..d1d6858c1c 100644 --- a/src/panels/lovelace/components/hui-card-options.ts +++ b/src/panels/lovelace/components/hui-card-options.ts @@ -2,12 +2,12 @@ import "@polymer/paper-button/paper-button"; import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; import { fireEvent } from "../../../common/dom/fire_event"; import { HomeAssistant } from "../../../types"; -import { LovelaceConfig } from "../types"; +import { LovelaceCardConfig } from "../types"; let registeredDialog = false; export class HuiCardOptions extends LitElement { - public cardConfig?: LovelaceConfig; + public cardConfig?: LovelaceCardConfig; protected hass?: HomeAssistant; static get properties(): PropertyDeclarations { diff --git a/src/panels/lovelace/editor/hui-card-preview.ts b/src/panels/lovelace/editor/hui-card-preview.ts index 57f4491fbd..31617da87d 100644 --- a/src/panels/lovelace/editor/hui-card-preview.ts +++ b/src/panels/lovelace/editor/hui-card-preview.ts @@ -3,7 +3,7 @@ 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 { LovelaceCard, LovelaceConfig } from "../types"; +import { LovelaceCard, LovelaceCardConfig } from "../types"; import { ConfigError } from "./types"; const CUSTOM_TYPE_PREFIX = "custom:"; @@ -28,7 +28,7 @@ export class HuiCardPreview extends HTMLElement { this._createCard(configValue); } - set config(configValue: LovelaceConfig) { + set config(configValue: LovelaceCardConfig) { if (!configValue) { return; } @@ -49,7 +49,7 @@ export class HuiCardPreview extends HTMLElement { } } - private _createCard(configValue: LovelaceConfig): void { + private _createCard(configValue: LovelaceCardConfig): void { if (this._element) { this.removeChild(this._element); } diff --git a/src/panels/lovelace/editor/hui-dialog-edit-card.ts b/src/panels/lovelace/editor/hui-dialog-edit-card.ts index 478c0c1b48..6fb993517a 100644 --- a/src/panels/lovelace/editor/hui-dialog-edit-card.ts +++ b/src/panels/lovelace/editor/hui-dialog-edit-card.ts @@ -2,13 +2,13 @@ import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; import { TemplateResult } from "lit-html"; import { HomeAssistant } from "../../../types"; -import { LovelaceConfig } from "../types"; +import { LovelaceCardConfig } from "../types"; import "./hui-edit-card"; import "./hui-migrate-config"; export class HuiDialogEditCard extends LitElement { protected _hass?: HomeAssistant; - private _cardConfig?: LovelaceConfig; + private _cardConfig?: LovelaceCardConfig; private _reloadLovelace?: () => void; static get properties(): PropertyDeclarations { diff --git a/src/panels/lovelace/editor/hui-edit-card.ts b/src/panels/lovelace/editor/hui-edit-card.ts index 2ffd9ff5cc..166b8913d1 100644 --- a/src/panels/lovelace/editor/hui-edit-card.ts +++ b/src/panels/lovelace/editor/hui-edit-card.ts @@ -21,7 +21,7 @@ import "./hui-card-preview"; // This is not a duplicate import, one is for types, one is for element. // tslint:disable-next-line import { HuiCardPreview } from "./hui-card-preview"; -import { LovelaceCardEditor, LovelaceConfig } from "../types"; +import { LovelaceCardEditor, LovelaceCardConfig } from "../types"; import { YamlChangedEvent, ConfigValue, ConfigError } from "./types"; import { extYamlSchema } from "./yaml-ext-schema"; @@ -30,7 +30,7 @@ const CUSTOM_TYPE_PREFIX = "custom:"; export class HuiEditCard extends hassLocalizeLitMixin(LitElement) { protected hass?: HomeAssistant; private _cardId?: string; - private _originalConfig?: LovelaceConfig; + private _originalConfig?: LovelaceCardConfig; private _configElement?: LovelaceCardEditor | null; private _uiEditor?: boolean; private _configValue?: ConfigValue; @@ -59,7 +59,7 @@ export class HuiEditCard extends hassLocalizeLitMixin(LitElement) { this._saving = false; } - set cardConfig(cardConfig: LovelaceConfig) { + set cardConfig(cardConfig: LovelaceCardConfig) { this._originalConfig = cardConfig; if (String(cardConfig.id) !== this._cardId) { this._loading = true; @@ -210,7 +210,8 @@ export class HuiEditCard extends hassLocalizeLitMixin(LitElement) { schema: extYamlSchema, }), }; - this._configElement.setConfig(this._configValue!.value as LovelaceConfig); + this._configElement.setConfig(this._configValue! + .value as LovelaceCardConfig); this._uiEditor = !this._uiEditor; } this._resizeDialog(); @@ -274,7 +275,7 @@ export class HuiEditCard extends hassLocalizeLitMixin(LitElement) { try { const config = yaml.safeLoad(this._configValue.value, { schema: extYamlSchema, - }) as LovelaceConfig; + }) as LovelaceCardConfig; this._updatePreview(config); this._configState = "OK"; if (!this._isToggleAvailable && this._configElement !== null) { @@ -290,12 +291,12 @@ export class HuiEditCard extends hassLocalizeLitMixin(LitElement) { } } - private _handleUIConfigChanged(value: LovelaceConfig): void { + private _handleUIConfigChanged(value: LovelaceCardConfig): void { this._configValue = { format: "json", value }; this._updatePreview(value); } - private _updatePreview(config: LovelaceConfig) { + private _updatePreview(config: LovelaceCardConfig) { if (!this._previewEl) { return; } diff --git a/src/panels/lovelace/editor/types.ts b/src/panels/lovelace/editor/types.ts index 3fbc360b47..c89ab3e10a 100644 --- a/src/panels/lovelace/editor/types.ts +++ b/src/panels/lovelace/editor/types.ts @@ -1,4 +1,4 @@ -import { LovelaceConfig } from "../types"; +import { LovelaceCardConfig } from "../types"; import { EntityConfig } from "../entity-rows/types"; export interface YamlChangedEvent extends Event { @@ -9,7 +9,7 @@ export interface YamlChangedEvent extends Event { export interface ConfigValue { format: "json" | "yaml"; - value?: string | LovelaceConfig; + value?: string | LovelaceCardConfig; } export interface ConfigError { diff --git a/src/panels/lovelace/types.ts b/src/panels/lovelace/types.ts index 7f3fabeaae..ca7a2e2d58 100644 --- a/src/panels/lovelace/types.ts +++ b/src/panels/lovelace/types.ts @@ -1,17 +1,31 @@ import { HomeAssistant } from "../../types"; -export interface LovelaceConfig { +export interface LovelaceCardConfig { + id?: string; type: string; - id: string; + [key: string]: any; +} + +export interface LovelaceViewConfig { + title?: string; + badges?: string[]; + cards?: LovelaceCardConfig[]; + id?: string; + icon?: string; +} +export interface LovelaceConfig { + _frontendAuto: boolean; + title?: string; + views: LovelaceViewConfig[]; } export interface LovelaceCard extends HTMLElement { hass?: HomeAssistant; getCardSize(): number; - setConfig(config: LovelaceConfig): void; + setConfig(config: LovelaceCardConfig): void; } export interface LovelaceCardEditor extends HTMLElement { hass?: HomeAssistant; - setConfig(config: LovelaceConfig): void; + setConfig(config: LovelaceCardConfig): void; } From b939ae6ab4baffec14a552d53ca0171562a452e4 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 25 Nov 2018 15:18:41 +0100 Subject: [PATCH 10/69] Fix wrong import (#2106) --- src/panels/lovelace/components/hui-entities-toggle.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/panels/lovelace/components/hui-entities-toggle.js b/src/panels/lovelace/components/hui-entities-toggle.js index fd5d80a109..9b52a8bc1d 100644 --- a/src/panels/lovelace/components/hui-entities-toggle.js +++ b/src/panels/lovelace/components/hui-entities-toggle.js @@ -3,7 +3,7 @@ import { PolymerElement } from "@polymer/polymer/polymer-element"; import "@polymer/paper-toggle-button/paper-toggle-button"; import { DOMAINS_TOGGLE } from "../../../common/const"; -import turnOnOffEntities from "../common/entity/turn-on-off-entities"; +import { turnOnOffEntities } from "../common/entity/turn-on-off-entities"; class HuiEntitiesToggle extends PolymerElement { static get template() { From 69df6179bb3014978d65e96579b75b784162d1fd Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Sun, 25 Nov 2018 20:09:32 +0100 Subject: [PATCH 11/69] Add dialog to save config (#2100) * Add dialog to save config * Change types * Helper funcs for register dialog * Clean up * Migrate config after save * Clean up * Unused imports * Comments * Missed half... * cardConfig cant be undefined --- src/panels/lovelace/common/data.ts | 23 ++- .../lovelace/components/hui-card-options.ts | 15 +- .../lovelace/editor/hui-dialog-edit-card.ts | 70 +++++--- .../lovelace/editor/hui-dialog-save-config.ts | 150 ++++++++++++++++++ src/panels/lovelace/ha-panel-lovelace.js | 7 + src/panels/lovelace/hui-root.js | 10 +- src/panels/lovelace/types.ts | 1 + src/translations/en.json | 7 + 8 files changed, 241 insertions(+), 42 deletions(-) create mode 100644 src/panels/lovelace/editor/hui-dialog-save-config.ts diff --git a/src/panels/lovelace/common/data.ts b/src/panels/lovelace/common/data.ts index 373dccb4d6..289e277b46 100644 --- a/src/panels/lovelace/common/data.ts +++ b/src/panels/lovelace/common/data.ts @@ -1,5 +1,21 @@ import { HomeAssistant } from "../../../types"; -import { LovelaceCardConfig } from "../types"; +import { LovelaceConfig, LovelaceCardConfig } from "../types"; + +export const migrateConfig = (hass: HomeAssistant): Promise => + hass.callWS({ + type: "lovelace/config/migrate", + }); + +export const saveConfig = ( + hass: HomeAssistant, + config: LovelaceConfig | string, + configFormat: "json" | "yaml" +): Promise => + hass.callWS({ + type: "lovelace/config/save", + config, + format: configFormat, + }); export const getCardConfig = ( hass: HomeAssistant, @@ -22,8 +38,3 @@ export const updateCardConfig = ( card_config: config, format: configFormat, }); - -export const migrateConfig = (hass: HomeAssistant): Promise => - hass.callWS({ - type: "lovelace/config/migrate", - }); diff --git a/src/panels/lovelace/components/hui-card-options.ts b/src/panels/lovelace/components/hui-card-options.ts index d1d6858c1c..ebd0767251 100644 --- a/src/panels/lovelace/components/hui-card-options.ts +++ b/src/panels/lovelace/components/hui-card-options.ts @@ -1,6 +1,10 @@ import "@polymer/paper-button/paper-button"; import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; import { fireEvent } from "../../../common/dom/fire_event"; +import { + showEditCardDialog, + registerEditCardDialog, +} from "../editor/hui-dialog-edit-card"; import { HomeAssistant } from "../../../types"; import { LovelaceCardConfig } from "../types"; @@ -18,11 +22,7 @@ export class HuiCardOptions extends LitElement { super.connectedCallback(); if (!registeredDialog) { registeredDialog = true; - fireEvent(this, "register-dialog", { - dialogShowEvent: "show-edit-card", - dialogTag: "hui-dialog-edit-card", - dialogImport: () => import("../editor/hui-dialog-edit-card"), - }); + registerEditCardDialog(this); } } @@ -48,9 +48,8 @@ export class HuiCardOptions extends LitElement { `; } private _editCard() { - fireEvent(this, "show-edit-card", { - hass: this.hass, - cardConfig: this.cardConfig, + showEditCardDialog(this, { + cardConfig: this.cardConfig!, reloadLovelace: () => fireEvent(this, "config-refresh"), }); } diff --git a/src/panels/lovelace/editor/hui-dialog-edit-card.ts b/src/panels/lovelace/editor/hui-dialog-edit-card.ts index 6fb993517a..b8cbe5b835 100644 --- a/src/panels/lovelace/editor/hui-dialog-edit-card.ts +++ b/src/panels/lovelace/editor/hui-dialog-edit-card.ts @@ -3,48 +3,66 @@ import { TemplateResult } from "lit-html"; import { HomeAssistant } from "../../../types"; import { LovelaceCardConfig } from "../types"; +import { fireEvent } from "../../../common/dom/fire_event"; import "./hui-edit-card"; import "./hui-migrate-config"; +const dialogShowEvent = "show-edit-card"; +const dialogTag = "hui-dialog-edit-config"; + +export interface EditCardDialogParams { + cardConfig: LovelaceCardConfig; + reloadLovelace: () => void; +} + +export const registerEditCardDialog = (element: HTMLElement) => + fireEvent(element, "register-dialog", { + dialogShowEvent, + dialogTag, + dialogImport: () => import("./hui-dialog-edit-card"), + }); + +export const showEditCardDialog = ( + element: HTMLElement, + editCardDialogParams: EditCardDialogParams +) => fireEvent(element, dialogShowEvent, editCardDialogParams); + export class HuiDialogEditCard extends LitElement { - protected _hass?: HomeAssistant; - private _cardConfig?: LovelaceCardConfig; - private _reloadLovelace?: () => void; + protected hass?: HomeAssistant; + private _params?: EditCardDialogParams; static get properties(): PropertyDeclarations { return { - _hass: {}, + hass: {}, _cardConfig: {}, }; } - public async showDialog({ hass, cardConfig, reloadLovelace }): Promise { - this._hass = hass; - this._cardConfig = cardConfig; - this._reloadLovelace = reloadLovelace; + public async showDialog(params: EditCardDialogParams): Promise { + this._params = params; await this.updateComplete; (this.shadowRoot!.children[0] as any).showDialog(); } protected render(): TemplateResult { + if (!this._params) { + return html``; + } + if (!this._params.cardConfig.id) { + return html` + + `; + } return html` - ${ - this._cardConfig!.id - ? html` - - - ` - : html` - - ` - } + + `; } } @@ -55,4 +73,4 @@ declare global { } } -customElements.define("hui-dialog-edit-card", HuiDialogEditCard); +customElements.define(dialogTag, HuiDialogEditCard); diff --git a/src/panels/lovelace/editor/hui-dialog-save-config.ts b/src/panels/lovelace/editor/hui-dialog-save-config.ts new file mode 100644 index 0000000000..e5c0f01985 --- /dev/null +++ b/src/panels/lovelace/editor/hui-dialog-save-config.ts @@ -0,0 +1,150 @@ +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 { HomeAssistant } from "../../../types"; +import { LovelaceConfig } from "../types"; + +import { saveConfig, migrateConfig } from "../common/data"; +import { fireEvent } from "../../../common/dom/fire_event"; +import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; + +const dialogShowEvent = "show-save-config"; +const dialogTag = "hui-dialog-save-config"; + +export interface SaveDialogParams { + config: LovelaceConfig; + reloadLovelace: () => void; +} + +export const registerSaveDialog = (element: HTMLElement) => + fireEvent(element, "register-dialog", { + dialogShowEvent, + dialogTag, + dialogImport: () => import("./hui-dialog-save-config"), + }); + +export const showSaveDialog = ( + element: HTMLElement, + saveDialogParams: SaveDialogParams +) => fireEvent(element, dialogShowEvent, saveDialogParams); + +export class HuiSaveConfig extends hassLocalizeLitMixin(LitElement) { + protected hass?: HomeAssistant; + private _params?: SaveDialogParams; + private _saving: boolean; + + static get properties(): PropertyDeclarations { + return { + hass: {}, + _params: {}, + _saving: {}, + }; + } + + protected constructor() { + super(); + this._saving = false; + } + + public async showDialog(params: SaveDialogParams): Promise { + this._params = params; + await this.updateComplete; + this._dialog.open(); + } + + private get _dialog(): PaperDialogElement { + return this.shadowRoot!.querySelector("paper-dialog")!; + } + + protected render(): TemplateResult { + return html` + ${this.renderStyle()} + +

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

+ +

${this.localize("ui.panel.lovelace.editor.save_config.para")}

+

+ ${this.localize("ui.panel.lovelace.editor.save_config.para_sure")} +

+
+
+ ${ + this.localize("ui.panel.lovelace.editor.save_config.cancel") + } + + + ${ + this.localize("ui.panel.lovelace.editor.save_config.save") + } +
+
+ `; + } + + private renderStyle(): TemplateResult { + return html` + + `; + } + + private _closeDialog(): void { + this._dialog.close(); + } + + private async _saveConfig(): Promise { + if (!this.hass || !this._params) { + return; + } + this._saving = true; + delete this._params.config._frontendAuto; + try { + await saveConfig(this.hass, this._params.config, "json"); + await migrateConfig(this.hass); + this._saving = false; + this._closeDialog(); + this._params.reloadLovelace!(); + } catch (err) { + alert(`Saving failed: ${err.message}`); + this._saving = false; + } + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-dialog-save-config": HuiSaveConfig; + } +} + +customElements.define(dialogTag, HuiSaveConfig); diff --git a/src/panels/lovelace/ha-panel-lovelace.js b/src/panels/lovelace/ha-panel-lovelace.js index f69434e714..2e7f4237de 100644 --- a/src/panels/lovelace/ha-panel-lovelace.js +++ b/src/panels/lovelace/ha-panel-lovelace.js @@ -2,11 +2,14 @@ import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; import "@polymer/paper-button/paper-button"; +import { registerSaveDialog } from "./editor/hui-dialog-save-config"; import "../../layouts/hass-loading-screen"; import "../../layouts/hass-error-screen"; import "./hui-root"; import localizeMixin from "../../mixins/localize-mixin"; +let registeredDialog = false; + class Lovelace extends localizeMixin(PolymerElement) { static get template() { return html` @@ -125,6 +128,10 @@ class Lovelace extends localizeMixin(PolymerElement) { _config: generateLovelaceConfig(this.hass, this.localize), _state: "loaded", }); + if (!registeredDialog) { + registeredDialog = true; + registerSaveDialog(this); + } } else { this.setProperties({ _state: "error", diff --git a/src/panels/lovelace/hui-root.js b/src/panels/lovelace/hui-root.js index c04fb9dedd..e6e25069cc 100644 --- a/src/panels/lovelace/hui-root.js +++ b/src/panels/lovelace/hui-root.js @@ -29,8 +29,8 @@ 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 { showSaveDialog } from "./editor/hui-dialog-save-config"; // CSS and JS should only be imported once. Modules and HTML are safe. const CSS_CACHE = {}; @@ -275,7 +275,13 @@ class HUIRoot extends NavigateMixin(EventsMixin(PolymerElement)) { _editModeEnable() { if (this.config._frontendAuto) { - alert("Unable to edit automatic generated UI yet."); + showSaveDialog(this, { + config: this.config, + reloadLovelace: () => { + this.fire("config-refresh"); + this._editMode = true; + }, + }); return; } this._editMode = true; diff --git a/src/panels/lovelace/types.ts b/src/panels/lovelace/types.ts index ca7a2e2d58..6ebd271676 100644 --- a/src/panels/lovelace/types.ts +++ b/src/panels/lovelace/types.ts @@ -13,6 +13,7 @@ export interface LovelaceViewConfig { id?: string; icon?: string; } + export interface LovelaceConfig { _frontendAuto: boolean; title?: string; diff --git a/src/translations/en.json b/src/translations/en.json index b7e0846d2b..c8a14d9d28 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -772,6 +772,13 @@ "save": "Save", "toggle_editor": "Toggle Editor" }, + "save_config": { + "header": "Take control of your Lovelace UI", + "para": "By default Home Assistant will maintain your user interface, updating it when new entities or Lovelace components become available. If you take control we will no longer make changes automatically for you.", + "para_sure": "Are you sure you want to take control of your user interface?", + "cancel": "Never mind", + "save": "Take control" + }, "migrate": { "header": "Configuration Incompatible", "para_no_id": "This element doesn't have an ID. Please add an ID to this element in 'ui-lovelace.yaml'.", From 8ad5280501e3e5b91a48f740df39956bb3c11616 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 25 Nov 2018 20:47:29 +0100 Subject: [PATCH 12/69] Document types in fireEvent (#2108) * Document types in fireEvent * Fix more types for fireEvent * Adjust new code to new fireEvent --- .../dom/{fire_event.js => fire_event.ts} | 41 ++++++++++---- src/layouts/app/dialog-manager-mixin.js | 25 --------- src/layouts/app/dialog-manager-mixin.ts | 56 +++++++++++++++++++ src/layouts/app/home-assistant.js | 4 +- .../lovelace/cards/hui-picture-glance-card.ts | 2 +- src/panels/lovelace/common/handle-click.ts | 4 +- .../lovelace/components/hui-card-options.ts | 10 ++++ .../components/hui-theme-select-editor.ts | 13 ++++- .../lovelace/editor/hui-dialog-edit-card.ts | 16 +++++- .../lovelace/editor/hui-dialog-save-config.ts | 7 +++ src/panels/lovelace/editor/hui-edit-card.ts | 15 +++++ src/polymer-types.ts | 15 +++++ 12 files changed, 166 insertions(+), 42 deletions(-) rename src/common/dom/{fire_event.js => fire_event.ts} (72%) delete mode 100644 src/layouts/app/dialog-manager-mixin.js create mode 100644 src/layouts/app/dialog-manager-mixin.ts create mode 100644 src/polymer-types.ts diff --git a/src/common/dom/fire_event.js b/src/common/dom/fire_event.ts similarity index 72% rename from src/common/dom/fire_event.js rename to src/common/dom/fire_event.ts index c9e6785b2a..57ecbd02c3 100644 --- a/src/common/dom/fire_event.js +++ b/src/common/dom/fire_event.ts @@ -28,6 +28,17 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +declare global { + // tslint:disable-next-line + interface HASSDomEvents {} +} + +export type ValidHassDomEvent = keyof HASSDomEvents; + +export interface HASSDomEvent extends Event { + detail: T; +} + /** * Dispatches a custom event with an optional detail value. * @@ -35,23 +46,33 @@ * @param {*=} detail Detail value containing event-specific * payload. * @param {{ bubbles: (boolean|undefined), - cancelable: (boolean|undefined), - composed: (boolean|undefined) }=} - * options Object specifying options. These may include: - * `bubbles` (boolean, defaults to `true`), - * `cancelable` (boolean, defaults to false), and - * `node` on which to fire the event (HTMLElement, defaults to `this`). - * @return {Event} The new event that was fired. - */ -export const fireEvent = (node, type, detail, options) => { + * cancelable: (boolean|undefined), + * composed: (boolean|undefined) }=} + * options Object specifying options. These may include: + * `bubbles` (boolean, defaults to `true`), + * `cancelable` (boolean, defaults to false), and + * `node` on which to fire the event (HTMLElement, defaults to `this`). + * @return {Event} The new event that was fired. + */ +export const fireEvent = ( + node: HTMLElement, + type: HassEvent, + detail?: HASSDomEvents[HassEvent], + options?: { + bubbles?: boolean; + cancelable?: boolean; + composed?: boolean; + } +) => { options = options || {}; + // @ts-ignore detail = detail === null || detail === undefined ? {} : detail; const event = new Event(type, { bubbles: options.bubbles === undefined ? true : options.bubbles, cancelable: Boolean(options.cancelable), composed: options.composed === undefined ? true : options.composed, }); - event.detail = detail; + (event as any).detail = detail; node.dispatchEvent(event); return event; }; diff --git a/src/layouts/app/dialog-manager-mixin.js b/src/layouts/app/dialog-manager-mixin.js deleted file mode 100644 index 7deeaa2fd0..0000000000 --- a/src/layouts/app/dialog-manager-mixin.js +++ /dev/null @@ -1,25 +0,0 @@ -export default (superClass) => - class extends superClass { - ready() { - super.ready(); - this.addEventListener("register-dialog", (e) => - this.registerDialog(e.detail) - ); - } - - registerDialog({ dialogShowEvent, dialogTag, dialogImport }) { - let loaded = null; - - this.addEventListener(dialogShowEvent, (showEv) => { - if (!loaded) { - loaded = dialogImport().then(() => { - const dialogEl = document.createElement(dialogTag); - this.shadowRoot.appendChild(dialogEl); - this.provideHass(dialogEl); - return dialogEl; - }); - } - loaded.then((dialogEl) => dialogEl.showDialog(showEv.detail)); - }); - } - }; diff --git a/src/layouts/app/dialog-manager-mixin.ts b/src/layouts/app/dialog-manager-mixin.ts new file mode 100644 index 0000000000..90295c3866 --- /dev/null +++ b/src/layouts/app/dialog-manager-mixin.ts @@ -0,0 +1,56 @@ +import { PolymerElement } from "@polymer/polymer"; +import { Constructor } from "@polymer/lit-element"; +import { HASSDomEvent, ValidHassDomEvent } from "../../common/dom/fire_event"; + +interface RegisterDialogParams { + dialogShowEvent: keyof HASSDomEvents; + dialogTag: keyof HTMLElementTagNameMap; + dialogImport: () => Promise; +} + +interface HassDialog extends HTMLElement { + showDialog(params: T); +} + +declare global { + // for fire event + interface HASSDomEvents { + "register-dialog": RegisterDialogParams; + } + // for add event listener + interface HTMLElementEventMap { + "register-dialog": HASSDomEvent; + } +} + +export const dialogManagerMixin = (superClass: Constructor) => + class extends superClass { + public ready() { + super.ready(); + this.addEventListener("register-dialog", (e) => + this.registerDialog(e.detail) + ); + } + + private registerDialog({ + dialogShowEvent, + dialogTag, + dialogImport, + }: RegisterDialogParams) { + let loaded: Promise>; + + this.addEventListener(dialogShowEvent, (showEv) => { + if (!loaded) { + loaded = dialogImport().then(() => { + const dialogEl = document.createElement(dialogTag) as HassDialog; + this.shadowRoot!.appendChild(dialogEl); + (this as any).provideHass(dialogEl); + return dialogEl; + }); + } + loaded.then((dialogEl) => + dialogEl.showDialog((showEv as HASSDomEvent).detail) + ); + }); + } + }; diff --git a/src/layouts/app/home-assistant.js b/src/layouts/app/home-assistant.js index 1d05e2bd1a..27983b1e3c 100644 --- a/src/layouts/app/home-assistant.js +++ b/src/layouts/app/home-assistant.js @@ -16,7 +16,7 @@ import TranslationsMixin from "./translations-mixin"; import ThemesMixin from "./themes-mixin"; import MoreInfoMixin from "./more-info-mixin"; import SidebarMixin from "./sidebar-mixin"; -import DialogManagerMixin from "./dialog-manager-mixin"; +import { dialogManagerMixin } from "./dialog-manager-mixin"; import ConnectionMixin from "./connection-mixin"; import NotificationMixin from "./notification-mixin"; import DisconnectToastMixin from "./disconnect-toast-mixin"; @@ -33,7 +33,7 @@ class HomeAssistant extends ext(PolymerElement, [ DisconnectToastMixin, ConnectionMixin, NotificationMixin, - DialogManagerMixin, + dialogManagerMixin, HassBaseMixin, ]) { static get template() { diff --git a/src/panels/lovelace/cards/hui-picture-glance-card.ts b/src/panels/lovelace/cards/hui-picture-glance-card.ts index 776126ddb6..8853146118 100644 --- a/src/panels/lovelace/cards/hui-picture-glance-card.ts +++ b/src/panels/lovelace/cards/hui-picture-glance-card.ts @@ -180,7 +180,7 @@ class HuiPictureGlanceCard extends hassLocalizeLitMixin(LitElement) navigate(this, this._config!.navigation_path!); } else if (this._config!.camera_image) { fireEvent(this, "hass-more-info", { - entityId: this._config!.camera_image, + entityId: this._config!.camera_image!, }); } } diff --git a/src/panels/lovelace/common/handle-click.ts b/src/panels/lovelace/common/handle-click.ts index f420a0f39a..714f4217eb 100644 --- a/src/panels/lovelace/common/handle-click.ts +++ b/src/panels/lovelace/common/handle-click.ts @@ -22,7 +22,9 @@ export const handleClick = ( switch (action) { case "more-info": - fireEvent(node, "hass-more-info", { entityId: config.entity }); + if (config.entity) { + fireEvent(node, "hass-more-info", { entityId: config.entity }); + } break; case "navigate": navigate(node, config.navigation_path ? config.navigation_path : ""); diff --git a/src/panels/lovelace/components/hui-card-options.ts b/src/panels/lovelace/components/hui-card-options.ts index ebd0767251..8cc1ab6a85 100644 --- a/src/panels/lovelace/components/hui-card-options.ts +++ b/src/panels/lovelace/components/hui-card-options.ts @@ -8,6 +8,16 @@ import { import { HomeAssistant } from "../../../types"; import { LovelaceCardConfig } from "../types"; +declare global { + // for fire event + interface HASSDomEvents { + "show-edit-card": { + cardConfig: LovelaceCardConfig; + reloadLovelace: () => void; + }; + } +} + let registeredDialog = false; export class HuiCardOptions extends LitElement { diff --git a/src/panels/lovelace/components/hui-theme-select-editor.ts b/src/panels/lovelace/components/hui-theme-select-editor.ts index 71c9017183..206919b213 100644 --- a/src/panels/lovelace/components/hui-theme-select-editor.ts +++ b/src/panels/lovelace/components/hui-theme-select-editor.ts @@ -3,9 +3,20 @@ import "@polymer/paper-button/paper-button"; import { TemplateResult } from "lit-html"; import { HomeAssistant } from "../../../types"; -import { fireEvent } from "../../../common/dom/fire_event"; +import { fireEvent, HASSDomEvent } from "../../../common/dom/fire_event"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; +declare global { + // for fire event + interface HASSDomEvents { + "theme-changed": undefined; + } + // for add event listener + interface HTMLElementEventMap { + "theme-changed": HASSDomEvent; + } +} + export class HuiThemeSelectionEditor extends hassLocalizeLitMixin(LitElement) { public value?: string; protected hass?: HomeAssistant; diff --git a/src/panels/lovelace/editor/hui-dialog-edit-card.ts b/src/panels/lovelace/editor/hui-dialog-edit-card.ts index b8cbe5b835..741ac97497 100644 --- a/src/panels/lovelace/editor/hui-dialog-edit-card.ts +++ b/src/panels/lovelace/editor/hui-dialog-edit-card.ts @@ -2,11 +2,23 @@ import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; import { TemplateResult } from "lit-html"; import { HomeAssistant } from "../../../types"; +import { fireEvent, HASSDomEvent } from "../../../common/dom/fire_event"; import { LovelaceCardConfig } from "../types"; -import { fireEvent } from "../../../common/dom/fire_event"; import "./hui-edit-card"; import "./hui-migrate-config"; +declare global { + // for fire event + interface HASSDomEvents { + "reload-lovelace": undefined; + "show-edit-card": EditCardDialogParams; + } + // for add event listener + interface HTMLElementEventMap { + "reload-lovelace": HASSDomEvent; + } +} + const dialogShowEvent = "show-edit-card"; const dialogTag = "hui-dialog-edit-config"; @@ -69,7 +81,7 @@ export class HuiDialogEditCard extends LitElement { declare global { interface HTMLElementTagNameMap { - "hui-dialog-edit-card": HuiDialogEditCard; + "hui-dialog-edit-config": HuiDialogEditCard; } } diff --git a/src/panels/lovelace/editor/hui-dialog-save-config.ts b/src/panels/lovelace/editor/hui-dialog-save-config.ts index e5c0f01985..de759c54cf 100644 --- a/src/panels/lovelace/editor/hui-dialog-save-config.ts +++ b/src/panels/lovelace/editor/hui-dialog-save-config.ts @@ -15,6 +15,13 @@ import { saveConfig, migrateConfig } from "../common/data"; import { fireEvent } from "../../../common/dom/fire_event"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; +declare global { + // for fire event + interface HASSDomEvents { + "show-save-config": SaveDialogParams; + } +} + const dialogShowEvent = "show-save-config"; const dialogTag = "hui-dialog-save-config"; diff --git a/src/panels/lovelace/editor/hui-edit-card.ts b/src/panels/lovelace/editor/hui-edit-card.ts index 166b8913d1..1814b62df8 100644 --- a/src/panels/lovelace/editor/hui-edit-card.ts +++ b/src/panels/lovelace/editor/hui-edit-card.ts @@ -24,6 +24,21 @@ import { HuiCardPreview } from "./hui-card-preview"; import { LovelaceCardEditor, LovelaceCardConfig } from "../types"; import { YamlChangedEvent, ConfigValue, ConfigError } from "./types"; import { extYamlSchema } from "./yaml-ext-schema"; +import { EntityConfig } from "../entity-rows/types"; + +declare global { + interface HASSDomEvents { + "yaml-changed": { + yaml: string; + }; + "entities-changed": { + entities: EntityConfig[]; + }; + "config-changed": { + config: LovelaceCardConfig; + }; + } +} const CUSTOM_TYPE_PREFIX = "custom:"; diff --git a/src/polymer-types.ts b/src/polymer-types.ts new file mode 100644 index 0000000000..d38ee79cc4 --- /dev/null +++ b/src/polymer-types.ts @@ -0,0 +1,15 @@ +// Force file to be a module to augment global scope. +export {}; + +declare global { + // for fire event + interface HASSDomEvents { + "iron-resize": undefined; + "config-refresh": undefined; + "ha-refresh-cloud-status": undefined; + "hass-more-info": { + entityId: string; + }; + "location-changed": undefined; + } +} From 07b65f37dbba27eb05b079b0beb41cd959d473a4 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 26 Nov 2018 14:09:27 +0100 Subject: [PATCH 13/69] Add Cloud Webhook management (#2102) * Add Cloud Webhook support * Lint * Tweak text * Rename it to cloudhook * Fix final type * fix type * Catch null --- src/data/cloud.ts | 19 ++ src/data/webhook.ts | 12 + src/panels/config/cloud/cloud-alexa-pref.ts | 4 + src/panels/config/cloud/cloud-google-pref.ts | 6 +- .../cloud/cloud-webhook-manage-dialog.ts | 142 +++++++++++ src/panels/config/cloud/cloud-webhooks.ts | 234 ++++++++++++++++++ .../config/cloud/ha-config-cloud-account.js | 28 ++- src/panels/config/cloud/types.ts | 10 + src/resources/ha-style.js | 24 +- src/types.ts | 5 + 10 files changed, 472 insertions(+), 12 deletions(-) create mode 100644 src/data/cloud.ts create mode 100644 src/data/webhook.ts create mode 100644 src/panels/config/cloud/cloud-webhook-manage-dialog.ts create mode 100644 src/panels/config/cloud/cloud-webhooks.ts diff --git a/src/data/cloud.ts b/src/data/cloud.ts new file mode 100644 index 0000000000..150e92f731 --- /dev/null +++ b/src/data/cloud.ts @@ -0,0 +1,19 @@ +import { HomeAssistant } from "../types"; + +export interface CloudWebhook { + webhook_id: string; + cloudhook_id: string; + cloudhook_url: string; +} + +export const createCloudhook = (hass: HomeAssistant, webhookId: string) => + hass.callWS({ + type: "cloud/cloudhook/create", + webhook_id: webhookId, + }); + +export const deleteCloudhook = (hass: HomeAssistant, webhookId: string) => + hass.callWS({ + type: "cloud/cloudhook/delete", + webhook_id: webhookId, + }); diff --git a/src/data/webhook.ts b/src/data/webhook.ts new file mode 100644 index 0000000000..98ae07495a --- /dev/null +++ b/src/data/webhook.ts @@ -0,0 +1,12 @@ +import { HomeAssistant } from "../types"; + +export interface Webhook { + webhook_id: string; + domain: string; + name: string; +} + +export const fetchWebhooks = (hass: HomeAssistant): Promise => + hass.callWS({ + type: "webhook/list", + }); diff --git a/src/panels/config/cloud/cloud-alexa-pref.ts b/src/panels/config/cloud/cloud-alexa-pref.ts index e92ac32296..149084acc8 100644 --- a/src/panels/config/cloud/cloud-alexa-pref.ts +++ b/src/panels/config/cloud/cloud-alexa-pref.ts @@ -24,6 +24,10 @@ export class CloudAlexaPref extends LitElement { } protected render(): TemplateResult { + if (!this.cloudStatus) { + return html``; + } + const enabled = this.cloudStatus!.prefs.alexa_enabled; return html` diff --git a/src/panels/config/cloud/cloud-google-pref.ts b/src/panels/config/cloud/cloud-google-pref.ts index 5d39501927..015c5155c2 100644 --- a/src/panels/config/cloud/cloud-google-pref.ts +++ b/src/panels/config/cloud/cloud-google-pref.ts @@ -25,7 +25,11 @@ export class CloudGooglePref extends LitElement { } protected render(): TemplateResult { - const { google_enabled, google_allow_unlock } = this.cloudStatus!.prefs; + if (!this.cloudStatus) { + return html``; + } + + const { google_enabled, google_allow_unlock } = this.cloudStatus.prefs; return html` ${this.renderStyle()} diff --git a/src/panels/config/cloud/cloud-webhook-manage-dialog.ts b/src/panels/config/cloud/cloud-webhook-manage-dialog.ts new file mode 100644 index 0000000000..610f916f24 --- /dev/null +++ b/src/panels/config/cloud/cloud-webhook-manage-dialog.ts @@ -0,0 +1,142 @@ +import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; + +import "@polymer/paper-button/paper-button"; +import "@polymer/paper-input/paper-input"; +import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable"; +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"; +// tslint:disable-next-line +import { PaperInputElement } from "@polymer/paper-input/paper-input"; + +import { buttonLink } from "../../../resources/ha-style"; + +import { HomeAssistant } from "../../../types"; +import { WebhookDialogParams } from "./types"; + +const inputLabel = "Public URL – Click to copy to clipboard"; + +export class CloudWebhookManageDialog extends LitElement { + protected hass?: HomeAssistant; + private _params?: WebhookDialogParams; + + static get properties(): PropertyDeclarations { + return { + _params: {}, + }; + } + + public async showDialog(params: WebhookDialogParams) { + this._params = params; + // Wait till dialog is rendered. + await this.updateComplete; + this._dialog.open(); + } + + protected render() { + if (!this._params) { + return html``; + } + const { webhook, cloudhook } = this._params; + const docsUrl = + webhook.domain === "automation" + ? "https://www.home-assistant.io/docs/automation/trigger/#webhook-trigger" + : `https://www.home-assistant.io/components/${webhook.domain}/`; + return html` + ${this._renderStyle()} + +

Webhook for ${webhook.name}

+
+

The webhook is available at the following url:

+ +

+ If you no longer want to use this webhook, you can + . +

+
+ +
+ VIEW DOCUMENTATION + CLOSE +
+
+ `; + } + + private get _dialog(): PaperDialogElement { + return this.shadowRoot!.querySelector("paper-dialog")!; + } + + private get _paperInput(): PaperInputElement { + return this.shadowRoot!.querySelector("paper-input")!; + } + + private _closeDialog() { + this._dialog.close(); + } + + private async _disableWebhook() { + if (!confirm("Are you sure you want to disable this webhook?")) { + return; + } + + this._params!.disableHook(); + this._closeDialog(); + } + + private _copyClipboard(ev: FocusEvent) { + // paper-input -> iron-input -> input + const paperInput = ev.currentTarget as PaperInputElement; + const input = (paperInput.inputElement as any) + .inputElement as HTMLInputElement; + input.setSelectionRange(0, input.value.length); + try { + document.execCommand("copy"); + paperInput.label = "COPIED TO CLIPBOARD"; + } catch (err) { + // Copying failed. Oh no + } + } + + private _restoreLabel() { + this._paperInput.label = inputLabel; + } + + private _renderStyle() { + return html` + + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "cloud-webhook-manage-dialog": CloudWebhookManageDialog; + } +} + +customElements.define("cloud-webhook-manage-dialog", CloudWebhookManageDialog); diff --git a/src/panels/config/cloud/cloud-webhooks.ts b/src/panels/config/cloud/cloud-webhooks.ts new file mode 100644 index 0000000000..bec6948ab3 --- /dev/null +++ b/src/panels/config/cloud/cloud-webhooks.ts @@ -0,0 +1,234 @@ +import { + html, + LitElement, + PropertyDeclarations, + PropertyValues, +} from "@polymer/lit-element"; +import "@polymer/paper-toggle-button/paper-toggle-button"; +import "@polymer/paper-item/paper-item"; +import "@polymer/paper-item/paper-item-body"; +import "@polymer/paper-spinner/paper-spinner"; +import "../../../components/ha-card"; + +import { fireEvent } from "../../../common/dom/fire_event"; + +import { HomeAssistant, WebhookError } from "../../../types"; +import { WebhookDialogParams, CloudStatusLoggedIn } from "./types"; +import { Webhook, fetchWebhooks } from "../../../data/webhook"; +import { + createCloudhook, + deleteCloudhook, + CloudWebhook, +} from "../../../data/cloud"; + +declare global { + // for fire event + interface HASSDomEvents { + "manage-cloud-webhook": WebhookDialogParams; + } +} + +export class CloudWebhooks extends LitElement { + public hass?: HomeAssistant; + public cloudStatus?: CloudStatusLoggedIn; + private _cloudHooks?: { [webhookId: string]: CloudWebhook }; + private _localHooks?: Webhook[]; + private _progress: string[]; + + static get properties(): PropertyDeclarations { + return { + hass: {}, + cloudStatus: {}, + _cloudHooks: {}, + _localHooks: {}, + _progress: {}, + }; + } + + constructor() { + super(); + this._progress = []; + } + + public connectedCallback() { + super.connectedCallback(); + this._fetchData(); + } + + protected render() { + return html` + ${this.renderStyle()} + +
+ Anything that is configured to be triggered by a webhook can be given + a publicly accessible URL to allow you to send data back to Home + Assistant from anywhere, without exposing your instance to the + internet. +
+ + ${this._renderBody()} + + +
+ `; + } + + protected updated(changedProps: PropertyValues) { + if (changedProps.has("cloudStatus") && this.cloudStatus) { + this._cloudHooks = this.cloudStatus.prefs.cloudhooks || {}; + } + } + + private _renderBody() { + if (!this.cloudStatus || !this._localHooks || !this._cloudHooks) { + return html` +
Loading…
+ `; + } + + return this._localHooks.map( + (entry) => html` +
+ +
+ ${entry.name} + ${ + entry.domain === entry.name.toLowerCase() + ? "" + : ` (${entry.domain})` + } +
+
${entry.webhook_id}
+
+ ${ + this._progress.includes(entry.webhook_id) + ? html` +
+ +
+ ` + : this._cloudHooks![entry.webhook_id] + ? html` + Manage + ` + : html` + + ` + } +
+ ` + ); + } + + private _showDialog(webhookId: string) { + const webhook = this._localHooks!.find( + (ent) => ent.webhook_id === webhookId + ); + const cloudhook = this._cloudHooks![webhookId]; + const params: WebhookDialogParams = { + webhook: webhook!, + cloudhook, + disableHook: () => this._disableWebhook(webhookId), + }; + fireEvent(this, "manage-cloud-webhook", params); + } + + private _handleManageButton(ev: MouseEvent) { + const entry = (ev.currentTarget as any).parentElement.entry as Webhook; + this._showDialog(entry.webhook_id); + } + + private async _enableWebhook(ev: MouseEvent) { + const entry = (ev.currentTarget as any).parentElement.entry; + this._progress = [...this._progress, entry.webhook_id]; + let updatedWebhook; + + try { + updatedWebhook = await createCloudhook(this.hass!, entry.webhook_id); + } catch (err) { + alert((err as WebhookError).message); + return; + } finally { + this._progress = this._progress.filter((wid) => wid !== entry.webhook_id); + } + + this._cloudHooks = { + ...this._cloudHooks, + [entry.webhook_id]: updatedWebhook, + }; + + // Only open dialog if we're not also enabling others, otherwise it's confusing + if (this._progress.length === 0) { + this._showDialog(entry.webhook_id); + } + } + + private async _disableWebhook(webhookId: string) { + this._progress = [...this._progress, webhookId]; + try { + await deleteCloudhook(this.hass!, webhookId!); + } catch (err) { + alert(`Failed to disable webhook: ${(err as WebhookError).message}`); + return; + } finally { + this._progress = this._progress.filter((wid) => wid !== webhookId); + } + + // Remove cloud related parts from entry. + const { [webhookId]: disabledHook, ...newHooks } = this._cloudHooks!; + this._cloudHooks = newHooks; + } + + private async _fetchData() { + this._localHooks = await fetchWebhooks(this.hass!); + } + + private renderStyle() { + return html` + + `; + } +} + +declare global { + interface HTMLElementTagNameMap { + "cloud-webhooks": CloudWebhooks; + } +} + +customElements.define("cloud-webhooks", CloudWebhooks); diff --git a/src/panels/config/cloud/ha-config-cloud-account.js b/src/panels/config/cloud/ha-config-cloud-account.js index 516bc0f3d1..b5305af2c7 100644 --- a/src/panels/config/cloud/ha-config-cloud-account.js +++ b/src/panels/config/cloud/ha-config-cloud-account.js @@ -10,15 +10,19 @@ import "../../../layouts/hass-subpage"; import "../../../resources/ha-style"; import "../ha-config-section"; +import "./cloud-webhooks"; import formatDateTime from "../../../common/datetime/format_date_time"; import EventsMixin from "../../../mixins/events-mixin"; import LocalizeMixin from "../../../mixins/localize-mixin"; +import { fireEvent } from "../../../common/dom/fire_event"; import { fetchSubscriptionInfo } from "./data"; import "./cloud-alexa-pref"; import "./cloud-google-pref"; +let registeredWebhookDialog = false; + /* * @appliesMixin EventsMixin * @appliesMixin LocalizeMixin @@ -129,6 +133,11 @@ class HaConfigCloudAccount extends EventsMixin(LocalizeMixin(PolymerElement)) { hass="[[hass]]" cloud-status="[[cloudStatus]]" > + + @@ -152,9 +161,26 @@ class HaConfigCloudAccount extends EventsMixin(LocalizeMixin(PolymerElement)) { this._fetchSubscriptionInfo(); } + connectedCallback() { + super.connectedCallback(); + + if (!registeredWebhookDialog) { + registeredWebhookDialog = true; + fireEvent(this, "register-dialog", { + dialogShowEvent: "manage-cloud-webhook", + dialogTag: "cloud-webhook-manage-dialog", + dialogImport: () => import("./cloud-webhook-manage-dialog"), + }); + } + } + async _fetchSubscriptionInfo() { this._subscription = await fetchSubscriptionInfo(this.hass); - if (this._subscription.provider && this.cloudStatus.cloud !== "connected") { + if ( + this._subscription.provider && + this.cloudStatus && + this.cloudStatus.cloud !== "connected" + ) { this.fire("ha-refresh-cloud-status"); } } diff --git a/src/panels/config/cloud/types.ts b/src/panels/config/cloud/types.ts index a42ab724b0..80affe7d3f 100644 --- a/src/panels/config/cloud/types.ts +++ b/src/panels/config/cloud/types.ts @@ -1,3 +1,6 @@ +import { CloudWebhook } from "../../../data/cloud"; +import { Webhook } from "../../../data/webhook"; + export interface EntityFilter { include_domains: string[]; include_entities: string[]; @@ -19,6 +22,7 @@ export type CloudStatusLoggedIn = CloudStatusBase & { google_enabled: boolean; alexa_enabled: boolean; google_allow_unlock: boolean; + cloudhooks: { [webhookId: string]: CloudWebhook }; }; }; @@ -27,3 +31,9 @@ export type CloudStatus = CloudStatusBase | CloudStatusLoggedIn; export interface SubscriptionInfo { human_description: string; } + +export interface WebhookDialogParams { + webhook: Webhook; + cloudhook: CloudWebhook; + disableHook: () => void; +} diff --git a/src/resources/ha-style.js b/src/resources/ha-style.js index 57c1e51a8d..b645210773 100644 --- a/src/resources/ha-style.js +++ b/src/resources/ha-style.js @@ -1,6 +1,19 @@ import "@polymer/paper-styles/paper-styles"; import "@polymer/polymer/polymer-legacy"; +export const buttonLink = ` + button.link { + background: none; + color: inherit; + border: none; + padding: 0; + font: inherit; + text-align: left; + text-decoration: underline; + cursor: pointer; + } +`; + const documentContainer = document.createElement("template"); documentContainer.setAttribute("style", "display: none;"); @@ -162,16 +175,7 @@ documentContainer.innerHTML = ` @apply --paper-font-title; } - button.link { - background: none; - color: inherit; - border: none; - padding: 0; - font: inherit; - text-align: left; - text-decoration: underline; - cursor: pointer; - } + ${buttonLink} .card-actions a { text-decoration: none; diff --git a/src/types.ts b/src/types.ts index dad3f5ffd4..9fc4b9db09 100644 --- a/src/types.ts +++ b/src/types.ts @@ -15,6 +15,11 @@ declare global { var __VERSION__: string; } +export interface WebhookError { + code: number; + message: string; +} + export interface Credential { auth_provider_type: string; auth_provider_id: string; From 5ab419534c45bce359b3722d1a9ac70da63f21be Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 26 Nov 2018 14:10:01 +0100 Subject: [PATCH 14/69] Convert authorize page to lit (#2115) * Convert authorize page to lit * Don't use ha-markdown * Simplify CSS --- src/auth/ha-auth-flow.js | 4 +- src/auth/ha-authorize.js | 154 ------------------------ src/auth/ha-authorize.ts | 158 +++++++++++++++++++++++++ src/auth/ha-pick-auth-provider.js | 4 +- src/data/auth.ts | 5 + src/mixins/lit-localize-lite-mixin.ts | 60 ++++++++++ src/mixins/localize-lite-base-mixin.ts | 44 +++++++ src/mixins/localize-lite-mixin.js | 72 ----------- src/mixins/localize-lite-mixin.ts | 40 +++++++ src/onboarding/ha-onboarding.js | 2 +- 10 files changed, 312 insertions(+), 231 deletions(-) delete mode 100644 src/auth/ha-authorize.js create mode 100644 src/auth/ha-authorize.ts create mode 100644 src/data/auth.ts create mode 100644 src/mixins/lit-localize-lite-mixin.ts create mode 100644 src/mixins/localize-lite-base-mixin.ts delete mode 100644 src/mixins/localize-lite-mixin.js create mode 100644 src/mixins/localize-lite-mixin.ts diff --git a/src/auth/ha-auth-flow.js b/src/auth/ha-auth-flow.js index e872c04e97..469ff0df73 100644 --- a/src/auth/ha-auth-flow.js +++ b/src/auth/ha-auth-flow.js @@ -2,9 +2,9 @@ import { PolymerElement } from "@polymer/polymer/polymer-element"; import "@polymer/paper-button/paper-button"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import "../components/ha-form"; -import LocalizeLiteMixin from "../mixins/localize-lite-mixin"; +import { localizeLiteMixin } from "../mixins/localize-lite-mixin"; -class HaAuthFlow extends LocalizeLiteMixin(PolymerElement) { +class HaAuthFlow extends localizeLiteMixin(PolymerElement) { static get template() { return html` - - - - - `; - } - - static get properties() { - return { - _authProvider: String, - _authProviders: Array, - clientId: String, - redirectUri: String, - oauth2State: String, - translationFragment: { - type: String, - value: "page-authorize", - }, - }; - } - - async ready() { - super.ready(); - const query = {}; - const values = location.search.substr(1).split("&"); - for (let i = 0; i < values.length; i++) { - const value = values[i].split("="); - if (value.length > 1) { - query[decodeURIComponent(value[0])] = decodeURIComponent(value[1]); - } - } - const props = {}; - if (query.client_id) props.clientId = query.client_id; - if (query.redirect_uri) props.redirectUri = query.redirect_uri; - if (query.state) props.oauth2State = query.state; - this.setProperties(props); - - import(/* webpackChunkName: "pick-auth-provider" */ "../auth/ha-pick-auth-provider"); - - // Fetch auth providers - try { - const response = await window.providersPromise; - const authProviders = await response.json(); - - // Forward to main screen which will redirect to right onboarding page. - if ( - response.status === 400 && - authProviders.code === "onboarding_required" - ) { - location.href = "/"; - return; - } - - if (authProviders.length === 0) { - alert("No auth providers returned. Unable to finish login."); - return; - } - - this.setProperties({ - _authProviders: authProviders, - _authProvider: authProviders[0], - }); - } catch (err) { - // eslint-disable-next-line - console.error("Error loading auth providers", err); - this._state = "error-loading"; - } - } - - _computeMultiple(array) { - return array && array.length > 1; - } - - async _handleAuthProviderPick(ev) { - this._authProvider = ev.detail; - } - - _computeInactiveProvders(curProvider, providers) { - return providers.filter( - (prv) => prv.type !== curProvider.type || prv.id !== curProvider.id - ); - } - - _computeIntro(localize, clientId, authProvider) { - return ( - localize( - "ui.panel.page-authorize.authorizing_client", - "clientId", - clientId - ) + - "\n\n" + - localize( - "ui.panel.page-authorize.logging_in_with", - "authProviderName", - authProvider.name - ) - ); - } -} -customElements.define("ha-authorize", HaAuthorize); diff --git a/src/auth/ha-authorize.ts b/src/auth/ha-authorize.ts new file mode 100644 index 0000000000..e93a992959 --- /dev/null +++ b/src/auth/ha-authorize.ts @@ -0,0 +1,158 @@ +import { litLocalizeLiteMixin } from "../mixins/lit-localize-lite-mixin"; +import { LitElement, html, PropertyDeclarations } from "@polymer/lit-element"; +import "./ha-auth-flow"; +import { AuthProvider } from "../data/auth"; + +import(/* webpackChunkName: "pick-auth-provider" */ "../auth/ha-pick-auth-provider"); + +interface QueryParams { + client_id?: string; + redirect_uri?: string; + state?: string; +} + +class HaAuthorize extends litLocalizeLiteMixin(LitElement) { + public clientId?: string; + public redirectUri?: string; + public oauth2State?: string; + private _authProvider?: AuthProvider; + private _authProviders?: AuthProvider[]; + + constructor() { + super(); + this.translationFragment = "page-authorize"; + const query: QueryParams = {}; + const values = location.search.substr(1).split("&"); + for (const item of values) { + const value = item.split("="); + if (value.length > 1) { + query[decodeURIComponent(value[0])] = decodeURIComponent(value[1]); + } + } + if (query.client_id) { + this.clientId = query.client_id; + } + if (query.redirect_uri) { + this.redirectUri = query.redirect_uri; + } + if (query.state) { + this.oauth2State = query.state; + } + } + + static get properties(): PropertyDeclarations { + return { + _authProvider: {}, + _authProviders: {}, + clientId: {}, + redirectUri: {}, + oauth2State: {}, + }; + } + + public render() { + if (!this._authProviders) { + return html` +

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

+ `; + } + + // We don't have a good approach yet to map text markup in localization. + // So we sanitize the translation with innerText and then inject + // the name with a bold tag. + const loggingInWith = document.createElement("div"); + loggingInWith.innerText = this.localize( + "ui.panel.page-authorize.logging_in_with", + "authProviderName", + "NAME" + ); + loggingInWith.innerHTML = loggingInWith.innerHTML.replace( + "**NAME**", + `${this._authProvider!.name}` + ); + + const inactiveProviders = this._authProviders.filter( + (prv) => prv !== this._authProvider + ); + + return html` + ${this.renderStyle()} +

+ ${ + this.localize( + "ui.panel.page-authorize.authorizing_client", + "clientId", + this.clientId + ) + } +

+ ${loggingInWith} + + + + ${ + inactiveProviders.length > 0 + ? html` + + ` + : "" + } + `; + } + + public async firstUpdated() { + // Fetch auth providers + try { + const response = await (window as any).providersPromise; + const authProviders = await response.json(); + + // Forward to main screen which will redirect to right onboarding page. + if ( + response.status === 400 && + authProviders.code === "onboarding_required" + ) { + location.href = "/?"; + return; + } + + if (authProviders.length === 0) { + alert("No auth providers returned. Unable to finish login."); + return; + } + + this._authProviders = authProviders; + this._authProvider = authProviders[0]; + } catch (err) { + // tslint:disable-next-line + console.error("Error loading auth providers", err); + } + } + + protected renderStyle() { + return html` + + `; + } + + private async _handleAuthProviderPick(ev) { + this._authProvider = ev.detail; + } +} +customElements.define("ha-authorize", HaAuthorize); diff --git a/src/auth/ha-pick-auth-provider.js b/src/auth/ha-pick-auth-provider.js index 3e31129069..6e63f3a1d5 100644 --- a/src/auth/ha-pick-auth-provider.js +++ b/src/auth/ha-pick-auth-provider.js @@ -4,13 +4,13 @@ import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; import EventsMixin from "../mixins/events-mixin"; -import LocalizeLiteMixin from "../mixins/localize-lite-mixin"; +import { localizeLiteMixin } from "../mixins/localize-lite-mixin"; /* * @appliesMixin EventsMixin */ class HaPickAuthProvider extends EventsMixin( - LocalizeLiteMixin(PolymerElement) + localizeLiteMixin(PolymerElement) ) { static get template() { return html` diff --git a/src/data/auth.ts b/src/data/auth.ts new file mode 100644 index 0000000000..52c3af9099 --- /dev/null +++ b/src/data/auth.ts @@ -0,0 +1,5 @@ +export interface AuthProvider { + name: string; + id: string; + type: string; +} diff --git a/src/mixins/lit-localize-lite-mixin.ts b/src/mixins/lit-localize-lite-mixin.ts new file mode 100644 index 0000000000..4c6f4a25e5 --- /dev/null +++ b/src/mixins/lit-localize-lite-mixin.ts @@ -0,0 +1,60 @@ +import { + Constructor, + LitElement, + PropertyDeclarations, + PropertyValues, +} from "@polymer/lit-element"; +import { HomeAssistant } from "../types"; +import { getActiveTranslation } from "../util/hass-translation"; +import { LocalizeFunc, LocalizeMixin } from "./localize-base-mixin"; +import { localizeLiteBaseMixin } from "./localize-lite-base-mixin"; + +const empty = () => ""; + +interface LitLocalizeLiteMixin { + language: string; + resources: {}; + translationFragment: string; +} + +export const litLocalizeLiteMixin = ( + superClass: Constructor +): Constructor => + // @ts-ignore + class extends localizeLiteBaseMixin(superClass) { + protected hass?: HomeAssistant; + protected localize!: LocalizeFunc; + + static get properties(): PropertyDeclarations { + return { + hass: {}, + localize: {}, + language: {}, + resources: {}, + translationFragment: {}, + }; + } + + constructor() { + super(); + // This will prevent undefined errors if called before connected to DOM. + this.localize = empty; + this.language = getActiveTranslation(); + } + + public connectedCallback(): void { + super.connectedCallback(); + this._initializeLocalizeLite(); + this.localize = this.__computeLocalize(this.language, this.resources); + } + + public updated(changedProperties: PropertyValues) { + super.updated(changedProperties); + if ( + changedProperties.has("language") || + changedProperties.has("resources") + ) { + this.localize = this.__computeLocalize(this.language, this.resources); + } + } + }; diff --git a/src/mixins/localize-lite-base-mixin.ts b/src/mixins/localize-lite-base-mixin.ts new file mode 100644 index 0000000000..d9fe1e2a58 --- /dev/null +++ b/src/mixins/localize-lite-base-mixin.ts @@ -0,0 +1,44 @@ +/** + * Lite base mixin to add localization without depending on the Hass object. + */ +import { localizeBaseMixin } from "./localize-base-mixin"; +import { getTranslation } from "../util/hass-translation"; + +/** + * @polymerMixin + */ +export const localizeLiteBaseMixin = (superClass) => + class extends localizeBaseMixin(superClass) { + protected _initializeLocalizeLite() { + if (this.resources) { + return; + } + + if (!this.translationFragment) { + // In dev mode, we will issue a warning if after a second we are still + // not configured correctly. + if (__DEV__) { + setTimeout( + () => + !this.resources && + // tslint:disable-next-line + console.error( + "Forgot to pass in resources or set translationFragment for", + this.nodeName + ), + 1000 + ); + } + return; + } + + this._updateResources(); + } + + private async _updateResources() { + const { language, data } = await getTranslation(this.translationFragment); + this.resources = { + [language]: data, + }; + } + }; diff --git a/src/mixins/localize-lite-mixin.js b/src/mixins/localize-lite-mixin.js deleted file mode 100644 index 8df031b522..0000000000 --- a/src/mixins/localize-lite-mixin.js +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Lite mixin to add localization without depending on the Hass object. - */ -import { dedupingMixin } from "@polymer/polymer/lib/utils/mixin"; -import { localizeBaseMixin } from "./localize-base-mixin"; -import { getActiveTranslation, getTranslation } from "../util/hass-translation"; - -/** - * @polymerMixin - */ -export default dedupingMixin( - (superClass) => - class extends localizeBaseMixin(superClass) { - static get properties() { - return { - language: { - type: String, - value: getActiveTranslation(), - }, - resources: Object, - // The fragment to load. - translationFragment: String, - /** - * Translates a string to the current `language`. Any parameters to the - * string should be passed in order, as follows: - * `localize(stringKey, param1Name, param1Value, param2Name, param2Value)` - */ - localize: { - type: Function, - computed: "__computeLocalize(language, resources, formats)", - }, - }; - } - - ready() { - super.ready(); - - if (this.resources) { - return; - } - - if (!this.translationFragment) { - // In dev mode, we will issue a warning if after a second we are still - // not configured correctly. - if (__DEV__) { - /* eslint-disable no-console */ - setTimeout( - () => - !this.resources && - console.error( - "Forgot to pass in resources or set translationFragment for", - this.nodeName - ), - 1000 - ); - } - return; - } - - this._updateResources(); - } - - async _updateResources() { - const { language, data } = await getTranslation( - this.translationFragment - ); - this.resources = { - [language]: data, - }; - } - } -); diff --git a/src/mixins/localize-lite-mixin.ts b/src/mixins/localize-lite-mixin.ts new file mode 100644 index 0000000000..16ffa615a1 --- /dev/null +++ b/src/mixins/localize-lite-mixin.ts @@ -0,0 +1,40 @@ +/** + * Lite mixin to add localization without depending on the Hass object. + */ +import { dedupingMixin } from "@polymer/polymer/lib/utils/mixin"; +import { getActiveTranslation } from "../util/hass-translation"; +import { localizeLiteBaseMixin } from "./localize-lite-base-mixin"; + +/** + * @polymerMixin + */ +export const localizeLiteMixin = dedupingMixin( + (superClass) => + class extends localizeLiteBaseMixin(superClass) { + static get properties() { + return { + language: { + type: String, + value: getActiveTranslation(), + }, + resources: Object, + // The fragment to load. + translationFragment: String, + /** + * Translates a string to the current `language`. Any parameters to the + * string should be passed in order, as follows: + * `localize(stringKey, param1Name, param1Value, param2Name, param2Value)` + */ + localize: { + type: Function, + computed: "__computeLocalize(language, resources, formats)", + }, + }; + } + + public ready() { + super.ready(); + this._initializeLocalizeLite(); + } + } +); diff --git a/src/onboarding/ha-onboarding.js b/src/onboarding/ha-onboarding.js index 3a30c3c8c5..ec9d8b2149 100644 --- a/src/onboarding/ha-onboarding.js +++ b/src/onboarding/ha-onboarding.js @@ -4,7 +4,7 @@ import "@polymer/paper-input/paper-input"; import "@polymer/paper-button/paper-button"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; -import localizeLiteMixin from "../mixins/localize-lite-mixin"; +import { localizeLiteMixin } from "../mixins/localize-lite-mixin"; class HaOnboarding extends localizeLiteMixin(PolymerElement) { static get template() { From 278ea184cc21d594cff52c36798645930b26b36c Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 26 Nov 2018 14:39:01 +0100 Subject: [PATCH 15/69] Update translations --- translations/bg.json | 2 +- translations/ca.json | 25 ++++++++++++++++++++++- translations/cs.json | 25 ++++++++++++++++++++++- translations/en.json | 25 ++++++++++++++++++++++- translations/et.json | 3 ++- translations/he.json | 14 +++++++++++++ translations/hu.json | 20 +++++++++++++++++- translations/ko.json | 25 ++++++++++++++++++++++- translations/lb.json | 25 ++++++++++++++++++++++- translations/nl.json | 24 +++++++++++++++++++++- translations/no.json | 25 ++++++++++++++++++++++- translations/pl.json | 43 ++++++++++++++++++++++++++++++--------- translations/pt.json | 25 ++++++++++++++++++++++- translations/ru.json | 25 ++++++++++++++++++++++- translations/zh-Hant.json | 25 ++++++++++++++++++++++- 15 files changed, 308 insertions(+), 23 deletions(-) diff --git a/translations/bg.json b/translations/bg.json index 93b883c4a1..123623a634 100644 --- a/translations/bg.json +++ b/translations/bg.json @@ -632,7 +632,7 @@ "abort_intro": "Входът е прекратен", "form": { "working": "Моля, изчакайте", - "unknown_error": "Ся си е*а майката", + "unknown_error": "Неочаквана грешка", "providers": { "homeassistant": { "step": { diff --git a/translations/ca.json b/translations/ca.json index e7c9cf7b48..07321e0970 100644 --- a/translations/ca.json +++ b/translations/ca.json @@ -144,7 +144,8 @@ "performance": "Rendiment", "high_demand": "Plena potència", "heat_pump": "Bomba de calor", - "gas": "Gas" + "gas": "Gas", + "manual": "Manual" }, "configurator": { "configure": "Configurar", @@ -712,6 +713,28 @@ "required_fields": "Ompliu tots els camps obligatoris" } } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "Elements seleccionats", + "clear_items": "Esborra els elements seleccionats", + "add_item": "Afegir element" + } + }, + "editor": { + "edit": { + "header": "Targeta de Configuració", + "save": "Desa", + "toggle_editor": "Commuta l'editor" + }, + "migrate": { + "header": "Configuració incompatible", + "para_no_id": "Aquest element no té ID. Afegiu un ID per aquest element a 'ui-lovelace.yaml'.", + "para_migrate": "Home Assistant pot afegir ID's a totes les vostres targetes i visualitzacions automàticament fent clic al botó \"Migrar la configuració\".", + "migrate": "Migrar la configuració" + } + } } }, "sidebar": { diff --git a/translations/cs.json b/translations/cs.json index d570aba54e..c21c88a26b 100644 --- a/translations/cs.json +++ b/translations/cs.json @@ -144,7 +144,8 @@ "performance": "Vysoký výkon", "high_demand": "Vysoký výkon", "heat_pump": "Tepelné čerpadlo", - "gas": "Plyn" + "gas": "Plyn", + "manual": "Ruční" }, "configurator": { "configure": "Nakonfigurovat", @@ -712,6 +713,28 @@ "required_fields": "Vyplňte všechna povinná pole" } } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "Označené položky", + "clear_items": "Vymazat označené položky", + "add_item": "Přidat položku" + } + }, + "editor": { + "edit": { + "header": "Konfigurace karty", + "save": "Uložit", + "toggle_editor": "Přepnout Editor" + }, + "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" + } + } } }, "sidebar": { diff --git a/translations/en.json b/translations/en.json index d70c46c649..722f9dd2e4 100644 --- a/translations/en.json +++ b/translations/en.json @@ -144,7 +144,8 @@ "performance": "Performance", "high_demand": "High demand", "heat_pump": "Heat pump", - "gas": "Gas" + "gas": "Gas", + "manual": "Manual" }, "configurator": { "configure": "Configure", @@ -712,6 +713,28 @@ "required_fields": "Fill in all required fields" } } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "Checked items", + "clear_items": "Clear checked items", + "add_item": "Add item" + } + }, + "editor": { + "edit": { + "header": "Card Configuration", + "save": "Save", + "toggle_editor": "Toggle Editor" + }, + "migrate": { + "header": "Configuration Incompatible", + "para_no_id": "This element doesn't have an ID. Please add an ID to this element in 'ui-lovelace.yaml'.", + "para_migrate": "Home Assistant can add ID's to all your cards and views automatically for you by pressing the 'Migrate config' button.", + "migrate": "Migrate config" + } + } } }, "sidebar": { diff --git a/translations/et.json b/translations/et.json index b13a870c86..8fb9950da7 100644 --- a/translations/et.json +++ b/translations/et.json @@ -144,7 +144,8 @@ "performance": "Jõudlus", "high_demand": "Kõrge nõudlus", "heat_pump": "Soojuspump", - "gas": "Gaas" + "gas": "Gaas", + "manual": "Käsitsi" }, "configurator": { "configure": "Seadista", diff --git a/translations/he.json b/translations/he.json index 04161f784b..5d411cf77f 100644 --- a/translations/he.json +++ b/translations/he.json @@ -712,6 +712,20 @@ "required_fields": "מלא את כל השדות הדרושים" } } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "פריטים מסומנים", + "clear_items": "נקה פריטים מסומנים", + "add_item": "הוסף פריט" + } + }, + "editor": { + "edit": { + "save": "שמור" + } + } } }, "sidebar": { diff --git a/translations/hu.json b/translations/hu.json index 14d43a3970..db1edd1404 100644 --- a/translations/hu.json +++ b/translations/hu.json @@ -144,7 +144,8 @@ "performance": "Teljesítmény", "high_demand": "Magas igénybevétel", "heat_pump": "Hőszivattyú", - "gas": "Gáz" + "gas": "Gáz", + "manual": "Kézikönyv" }, "configurator": { "configure": "Beállítás", @@ -712,6 +713,23 @@ "required_fields": "Töltsd ki az összes szükséges mezőt" } } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "Ellenőrzött elemek ", + "clear_items": "Ellenőrzött elemek ", + "add_item": "Elem hozzáadása" + } + }, + "editor": { + "edit": { + "save": "Mentés" + }, + "migrate": { + "header": "Inkompatibilis konfiguráció!" + } + } } }, "sidebar": { diff --git a/translations/ko.json b/translations/ko.json index 07ed2e3e1e..05e4707f96 100644 --- a/translations/ko.json +++ b/translations/ko.json @@ -144,7 +144,8 @@ "performance": "고효율", "high_demand": "고성능", "heat_pump": "순환펌프", - "gas": "가스" + "gas": "가스", + "manual": "수동" }, "configurator": { "configure": "설정", @@ -712,6 +713,28 @@ "required_fields": "필수 입력란을 모두 채워주세요" } } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "선택한 항목", + "clear_items": "선택한 항목 삭제", + "add_item": "항목 추가" + } + }, + "editor": { + "edit": { + "header": "카드 구성", + "save": "저장하기", + "toggle_editor": "에디터 전환" + }, + "migrate": { + "header": "설정이 호환되지 않습니다", + "para_no_id": "이 구성요소에는 ID가 없습니다. 'ui-lovelace.yaml' 에 구성요소의 ID를 추가해주세요.", + "para_migrate": "Home Assistant 는 '설정 마이그레이션' 버튼을 눌러 자동으로 모든 카드와 보기에 ID를 추가 할 수 있습니다.", + "migrate": "설정 마이그레이션" + } + } } }, "sidebar": { diff --git a/translations/lb.json b/translations/lb.json index be103f45c2..0e80d80684 100644 --- a/translations/lb.json +++ b/translations/lb.json @@ -144,7 +144,8 @@ "performance": "Leeschtung", "high_demand": "Héich Ufro", "heat_pump": "Heizung", - "gas": "Gas" + "gas": "Gas", + "manual": "Manuell" }, "configurator": { "configure": "Astellen", @@ -712,6 +713,28 @@ "required_fields": "Fëllt all néideg Felder aus" } } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "Markéiert Elementer", + "clear_items": "Markéiert Elementer läschen", + "add_item": "Element dobäisetzen" + } + }, + "editor": { + "edit": { + "header": "Kaart Konfiguratioun", + "save": "Späicheren", + "toggle_editor": "Editeur ëmschalten" + }, + "migrate": { + "header": "Konfiguratioun net kompatibel", + "para_no_id": "Dëst Element huet keng ID. Definéiert w.e.g. eng ID fir dëst Element am 'ui-lovelace.yaml'.", + "para_migrate": "Home Assistant kann ID's zu all äre Kaarten automatesch dobäisetzen andeem dir de Knäppche 'Konfiguratioun migréieren' dréckt.", + "migrate": "Konfiguratioun migréieren" + } + } } }, "sidebar": { diff --git a/translations/nl.json b/translations/nl.json index 6ec0c54658..9b06bc384f 100644 --- a/translations/nl.json +++ b/translations/nl.json @@ -144,7 +144,8 @@ "performance": "Prestatie", "high_demand": "Hoge vraag", "heat_pump": "Warmtepomp", - "gas": "Gas" + "gas": "Gas", + "manual": "Handmatig" }, "configurator": { "configure": "Configureer", @@ -712,6 +713,27 @@ "required_fields": "Vul alle verplichte velden in" } } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "Geselecteerde items", + "clear_items": "Geselecteerde items wissen", + "add_item": "Item toevoegen" + } + }, + "editor": { + "edit": { + "header": "Kaart configuratie", + "save": "Opslaan" + }, + "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" + } + } } }, "sidebar": { diff --git a/translations/no.json b/translations/no.json index 0a9c04958f..85b03c5eda 100644 --- a/translations/no.json +++ b/translations/no.json @@ -144,7 +144,8 @@ "performance": "Ytelse", "high_demand": "Høy etterspørsel", "heat_pump": "Varmepumpe", - "gas": "Gass" + "gas": "Gass", + "manual": "Manuell" }, "configurator": { "configure": "Konfigurer", @@ -712,6 +713,28 @@ "required_fields": "Fyll ut alle nødvendige felt" } } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "Merkede elementer", + "clear_items": "Fjern merkede elementer", + "add_item": "Legg til" + } + }, + "editor": { + "edit": { + "header": "Kortkonfigurasjon", + "save": "Lagre", + "toggle_editor": "Bytt redigering" + }, + "migrate": { + "header": "Konfigurasjon inkompatibel", + "para_no_id": "Dette elementet har ingen ID. Vennligst legg til en ID til dette elementet i 'ui-lovelace.yaml'.", + "para_migrate": "Home Assistant kan legge til ID-er til alle dine kort og visninger automatisk for deg ved å trykke på 'Overfør konfigurasjon' knappen.", + "migrate": "Overfør konfigurasjon" + } + } } }, "sidebar": { diff --git a/translations/pl.json b/translations/pl.json index 8548c00b03..a15fd8f3fa 100644 --- a/translations/pl.json +++ b/translations/pl.json @@ -45,8 +45,8 @@ "on": "włączony" }, "moisture": { - "off": "sucho", - "on": "wilgotno" + "off": "brak wilgoci", + "on": "wilgoć" }, "gas": { "off": "brak", @@ -144,7 +144,8 @@ "performance": "wydajność", "high_demand": "duży rozbiór", "heat_pump": "pompa ciepła", - "gas": "gaz" + "gas": "gaz", + "manual": "manualnie" }, "configurator": { "configure": "Skonfiguruj", @@ -386,8 +387,8 @@ "homeassistant": { "label": "Home Assistant", "event": "Zdarzenie:", - "start": "Początek", - "shutdown": "Zamknięcie systemu" + "start": "uruchomienie", + "shutdown": "zakończenie" }, "mqtt": { "label": "MQTT", @@ -403,8 +404,8 @@ "sun": { "label": "Słońce", "event": "Zdarzenie:", - "sunrise": "Wschód słońca", - "sunset": "Zachód słońca", + "sunrise": "wschód słońca", + "sunset": "zachód słońca", "offset": "Przesunięcie (opcjonalnie)" }, "template": { @@ -451,8 +452,8 @@ "after": "Po:", "before_offset": "Przed przesunięciem (opcjonalnie)", "after_offset": "Po przesunięciu (opcjonalnie)", - "sunrise": "Wschód słońca", - "sunset": "Zachód słońca" + "sunrise": "wschód słońca", + "sunset": "zachód słońca" }, "template": { "label": "Szablon", @@ -712,6 +713,28 @@ "required_fields": "Wypełnij wszystkie wymagane pola" } } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "Pozycje zaznaczone", + "clear_items": "Wyczyść zaznaczone pozycje", + "add_item": "Dodaj pozycję" + } + }, + "editor": { + "edit": { + "header": "Konfiguracja karty", + "save": "Zapisz", + "toggle_editor": "Przełącz edytor" + }, + "migrate": { + "header": "Konfiguracja niekompatybilna", + "para_no_id": "Ten element nie ma ID. Dodaj ID do tego elementu w \"ui-lovelace.yaml\".", + "para_migrate": "Home Assistant może automatycznie dodać ID do wszystkich twoich kart i widoków, po kliknięciu przycisku \"Migracja konfiguracji\".", + "migrate": "Migracja konfiguracji" + } + } } }, "sidebar": { @@ -745,7 +768,7 @@ "activate": "Aktywuj" }, "script": { - "execute": "Wykonaj" + "execute": "Uruchom" }, "weather": { "attributes": { diff --git a/translations/pt.json b/translations/pt.json index 0c67c902a2..af46894bb3 100644 --- a/translations/pt.json +++ b/translations/pt.json @@ -144,7 +144,8 @@ "performance": "Desempenho", "high_demand": "Necessidade alta", "heat_pump": "Bomba de calor", - "gas": "Gás" + "gas": "Gás", + "manual": "Manual" }, "configurator": { "configure": "Configurar", @@ -712,6 +713,28 @@ "required_fields": "Preencha todos os campos obrigatórios" } } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "Itens marcados", + "clear_items": "Limpar itens marcados", + "add_item": "Adicionar Item" + } + }, + "editor": { + "edit": { + "header": "Configuração do cartão", + "save": "Guardar", + "toggle_editor": "Alterar para editor" + }, + "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" + } + } } }, "sidebar": { diff --git a/translations/ru.json b/translations/ru.json index 4bd1bfc937..e852c409af 100644 --- a/translations/ru.json +++ b/translations/ru.json @@ -144,7 +144,8 @@ "performance": "Производительность", "high_demand": "Большая нагрузка", "heat_pump": "Тепловой насос", - "gas": "Газовый" + "gas": "Газовый", + "manual": "Руководство" }, "configurator": { "configure": "Настроить", @@ -712,6 +713,28 @@ "required_fields": "Заполните все обязательные поля" } } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "Отмеченные элементы", + "clear_items": "Очистить отмеченные элементы", + "add_item": "Добавить элемент" + } + }, + "editor": { + "edit": { + "header": "Конфигурация карты", + "save": "Сохранить", + "toggle_editor": "Переключить редактор" + }, + "migrate": { + "header": "Конфигурация несовместима", + "para_no_id": "Этот элемент не имеет ID. Добавьте ID для этого элемента в 'ui-lovelace.yaml'.", + "para_migrate": "Home Assistant может добавить ID для всех ваших карт и представлений автоматически, если нажать кнопку 'Миграция конфигурации'.", + "migrate": "Миграция конфигурации" + } + } } }, "sidebar": { diff --git a/translations/zh-Hant.json b/translations/zh-Hant.json index 05b409bbdf..dab37a0daa 100644 --- a/translations/zh-Hant.json +++ b/translations/zh-Hant.json @@ -144,7 +144,8 @@ "performance": "效能", "high_demand": "高用量", "heat_pump": "暖氣", - "gas": "瓦斯模式" + "gas": "瓦斯模式", + "manual": "手動" }, "configurator": { "configure": "設定", @@ -712,6 +713,28 @@ "required_fields": "填寫所有所需欄位" } } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "已選取項目", + "clear_items": "清除已選取項目", + "add_item": "新增項目" + } + }, + "editor": { + "edit": { + "header": "卡片設定", + "save": "儲存", + "toggle_editor": "切換編輯器" + }, + "migrate": { + "header": "設定不相容", + "para_no_id": "該元件未含 ID,請於「ui-lovelace.yaml」中為該元件新增 ID。", + "para_migrate": "Home Assistant 能於您點選「遷移設定」按鈕後,自動新增 ID 與視圖至所有卡片。", + "migrate": "遷移設定" + } + } } }, "sidebar": { From bb8ec4b2ef89b8b31ab92714006c6a91fe2fa840 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 26 Nov 2018 14:39:06 +0100 Subject: [PATCH 16/69] Bumped version to 20181126.0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 17eb385449..24233b1bb6 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup( name="home-assistant-frontend", - version="20181121.0", + version="20181126.0", description="The Home Assistant frontend", url="https://github.com/home-assistant/home-assistant-polymer", author="The Home Assistant Authors", From 21be35bc461eb16fb51d0fc64d6f4a6a3b50cce6 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Mon, 26 Nov 2018 07:46:40 -0600 Subject: [PATCH 17/69] Conert shopping-list update to WebSockets (#2114) --- src/data/shopping-list.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/data/shopping-list.ts b/src/data/shopping-list.ts index e2c57cdc78..ff156469d4 100644 --- a/src/data/shopping-list.ts +++ b/src/data/shopping-list.ts @@ -16,7 +16,9 @@ export const saveEdit = ( itemId: number, name: string ): Promise => - hass.callApi("POST", "shopping_list/item/" + itemId, { + hass.callWS({ + type: "shopping_list/items/update", + item_id: itemId, name, }); @@ -25,7 +27,9 @@ export const completeItem = ( itemId: number, complete: boolean ): Promise => - hass.callApi("POST", "shopping_list/item/" + itemId, { + hass.callWS({ + type: "shopping_list/items/update", + item_id: itemId, complete, }); From 3752530f965a30548ac0e18dc5b48d8de6a5fbf6 Mon Sep 17 00:00:00 2001 From: Zack Arnett Date: Mon, 26 Nov 2018 15:01:07 -0500 Subject: [PATCH 18/69] Update UI in the config Elements (#2117) * UpdateUI * Updating continues * Update name of file --- .../config-elements/config-elements-style.ts | 16 ++++ .../hui-entities-card-editor.ts | 54 ++++++------ .../config-elements/hui-glance-card-editor.ts | 82 +++++++++---------- src/panels/lovelace/editor/hui-edit-card.ts | 12 ++- 4 files changed, 89 insertions(+), 75 deletions(-) create mode 100644 src/panels/lovelace/editor/config-elements/config-elements-style.ts diff --git a/src/panels/lovelace/editor/config-elements/config-elements-style.ts b/src/panels/lovelace/editor/config-elements/config-elements-style.ts new file mode 100644 index 0000000000..0d44339055 --- /dev/null +++ b/src/panels/lovelace/editor/config-elements/config-elements-style.ts @@ -0,0 +1,16 @@ +import { html } from "@polymer/lit-element"; + +export const configElementStyle = html` + +`; diff --git a/src/panels/lovelace/editor/config-elements/hui-entities-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-entities-card-editor.ts index 25452f64f2..eebdd38494 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,9 +1,9 @@ import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; import { TemplateResult } from "lit-html"; -import "@polymer/paper-checkbox/paper-checkbox"; 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 { EntitiesEditorEvent, EditorTarget } from "../types"; @@ -12,6 +12,7 @@ import { HomeAssistant } from "../../../../types"; import { LovelaceCardEditor } from "../../types"; import { fireEvent } from "../../../../common/dom/fire_event"; import { Config, ConfigEntity } from "../../cards/hui-entities-card"; +import { configElementStyle } from "./config-elements-style"; import "../../../../components/entity/state-badge"; import "../../components/hui-theme-select-editor"; @@ -48,30 +49,32 @@ export class HuiEntitiesCardEditor extends hassLocalizeLitMixin(LitElement) } return html` - ${this.renderStyle()} - - + ${configElementStyle} +
+ + + Show Header Toggle? +
- Show Header Toggle? `; } @@ -102,17 +105,6 @@ export class HuiEntitiesCardEditor extends hassLocalizeLitMixin(LitElement) fireEvent(this, "config-changed", { config: this._config }); } - - private renderStyle(): TemplateResult { - return html` - - `; - } } declare global { 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 dacbc481a0..0f6cc2fdfe 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,9 +1,9 @@ import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; import { TemplateResult } from "lit-html"; -import "@polymer/paper-checkbox/paper-checkbox"; 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 { EntitiesEditorEvent, EditorTarget } from "../types"; @@ -12,6 +12,7 @@ import { HomeAssistant } from "../../../../types"; import { LovelaceCardEditor } from "../../types"; import { fireEvent } from "../../../../common/dom/fire_event"; import { Config, ConfigEntity } from "../../cards/hui-glance-card"; +import { configElementStyle } from "./config-elements-style"; import "../../../../components/entity/state-badge"; import "../../components/hui-theme-select-editor"; @@ -52,42 +53,48 @@ export class HuiGlanceCardEditor extends hassLocalizeLitMixin(LitElement) } return html` - ${this.renderStyle()} - - - + ${configElementStyle} +
+ +
+ + +
+
+ Show Entity's Name? + Show Entity's State Text? +
+
- Show Entity's Name? - Show Entity's State Text? `; } @@ -117,17 +124,6 @@ export class HuiGlanceCardEditor extends hassLocalizeLitMixin(LitElement) } fireEvent(this, "config-changed", { config: this._config }); } - - private renderStyle(): TemplateResult { - return html` - - `; - } } declare global { diff --git a/src/panels/lovelace/editor/hui-edit-card.ts b/src/panels/lovelace/editor/hui-edit-card.ts index 1814b62df8..6b7114e654 100644 --- a/src/panels/lovelace/editor/hui-edit-card.ts +++ b/src/panels/lovelace/editor/hui-edit-card.ts @@ -131,6 +131,7 @@ export class HuiEditCard extends hassLocalizeLitMixin(LitElement) { > ` } +
${ @@ -197,7 +198,16 @@ export class HuiEditCard extends hassLocalizeLitMixin(LitElement) { display: none; } .element-editor { - margin-bottom: 16px; + margin-bottom: 8px; + } + hr { + color: #000; + opacity: 0.12; + } + hui-card-preview { + padding-top: 8px; + margin-bottom: 4px; + display: block; } `; From 1cc6e099531c16eee9179bed70c657cf3240bebb Mon Sep 17 00:00:00 2001 From: cdce8p <30130371+cdce8p@users.noreply.github.com> Date: Mon, 26 Nov 2018 23:27:00 +0100 Subject: [PATCH 19/69] Add html to LitElement.prototype (#2120) --- src/layouts/app/home-assistant.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/layouts/app/home-assistant.js b/src/layouts/app/home-assistant.js index 27983b1e3c..f8f5f939de 100644 --- a/src/layouts/app/home-assistant.js +++ b/src/layouts/app/home-assistant.js @@ -4,6 +4,7 @@ import "@polymer/iron-flex-layout/iron-flex-layout-classes"; import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; import { afterNextRender } from "@polymer/polymer/lib/utils/render-status"; +import { html as litHtml, LitElement } from "@polymer/lit-element"; import "../home-assistant-main"; import "../ha-init-page"; @@ -21,6 +22,8 @@ import ConnectionMixin from "./connection-mixin"; import NotificationMixin from "./notification-mixin"; import DisconnectToastMixin from "./disconnect-toast-mixin"; +LitElement.prototype.html = litHtml; + const ext = (baseClass, mixins) => mixins.reduceRight((base, mixin) => mixin(base), baseClass); From 97f5d8e7e2b5b646fcd05bf68ae1c3539bdcdb11 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Tue, 27 Nov 2018 10:05:33 +0100 Subject: [PATCH 20/69] Move lovelace data to /src/data/lovelace.ts (#2119) * move lovelace data * move types * change imports from cards --- .../common/data.ts => data/lovelace.ts} | 28 +++++++++++++++++-- .../lovelace/cards/hui-conditional-card.ts | 3 +- .../lovelace/cards/hui-entities-card.ts | 3 +- .../lovelace/cards/hui-entity-button-card.ts | 3 +- src/panels/lovelace/cards/hui-error-card.ts | 3 +- src/panels/lovelace/cards/hui-gauge-card.ts | 3 +- src/panels/lovelace/cards/hui-glance-card.ts | 3 +- src/panels/lovelace/cards/hui-iframe-card.ts | 3 +- src/panels/lovelace/cards/hui-light-card.ts | 3 +- .../lovelace/cards/hui-markdown-card.ts | 3 +- src/panels/lovelace/cards/hui-picture-card.ts | 3 +- .../cards/hui-picture-elements-card.ts | 3 +- .../lovelace/cards/hui-picture-glance-card.ts | 3 +- .../lovelace/cards/hui-shopping-list-card.ts | 3 +- src/panels/lovelace/cards/hui-stack-card.ts | 3 +- .../lovelace/cards/hui-thermostat-card.ts | 3 +- .../common/generate-lovelace-config.ts | 2 +- .../lovelace/components/hui-card-options.ts | 2 +- .../lovelace/editor/hui-card-preview.ts | 3 +- .../lovelace/editor/hui-dialog-edit-card.ts | 2 +- .../lovelace/editor/hui-dialog-save-config.ts | 7 +++-- src/panels/lovelace/editor/hui-edit-card.ts | 4 +-- .../lovelace/editor/hui-migrate-config.ts | 2 +- src/panels/lovelace/editor/hui-yaml-editor.ts | 2 +- src/panels/lovelace/editor/types.ts | 2 +- src/panels/lovelace/ha-panel-lovelace.js | 3 +- src/panels/lovelace/types.ts | 21 +------------- 27 files changed, 74 insertions(+), 49 deletions(-) rename src/{panels/lovelace/common/data.ts => data/lovelace.ts} (61%) diff --git a/src/panels/lovelace/common/data.ts b/src/data/lovelace.ts similarity index 61% rename from src/panels/lovelace/common/data.ts rename to src/data/lovelace.ts index 289e277b46..9aac8076ab 100644 --- a/src/panels/lovelace/common/data.ts +++ b/src/data/lovelace.ts @@ -1,5 +1,29 @@ -import { HomeAssistant } from "../../../types"; -import { LovelaceConfig, LovelaceCardConfig } from "../types"; +import { HomeAssistant } from "../types"; + +export interface LovelaceConfig { + _frontendAuto: boolean; + title?: string; + views: LovelaceViewConfig[]; +} + +export interface LovelaceViewConfig { + title?: string; + badges?: string[]; + cards?: LovelaceCardConfig[]; + id?: string; + icon?: string; +} + +export interface LovelaceCardConfig { + id?: string; + type: string; + [key: string]: any; +} + +export const fetchConfig = (hass: HomeAssistant): Promise => + hass.callWS({ + type: "lovelace/config", + }); export const migrateConfig = (hass: HomeAssistant): Promise => hass.callWS({ diff --git a/src/panels/lovelace/cards/hui-conditional-card.ts b/src/panels/lovelace/cards/hui-conditional-card.ts index 4646b7386b..0f2e6329cc 100644 --- a/src/panels/lovelace/cards/hui-conditional-card.ts +++ b/src/panels/lovelace/cards/hui-conditional-card.ts @@ -1,7 +1,8 @@ import createCardElement from "../common/create-card-element"; import { computeCardSize } from "../common/compute-card-size"; import { HomeAssistant } from "../../../types"; -import { LovelaceCard, LovelaceCardConfig } from "../types"; +import { LovelaceCard } from "../types"; +import { LovelaceCardConfig } from "../../../data/lovelace"; interface Condition { entity: string; diff --git a/src/panels/lovelace/cards/hui-entities-card.ts b/src/panels/lovelace/cards/hui-entities-card.ts index cbb51e71a7..182c26aac5 100644 --- a/src/panels/lovelace/cards/hui-entities-card.ts +++ b/src/panels/lovelace/cards/hui-entities-card.ts @@ -14,7 +14,8 @@ import { DOMAINS_HIDE_MORE_INFO } from "../../../common/const"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; import { HomeAssistant } from "../../../types"; import { EntityConfig, EntityRow } from "../entity-rows/types"; -import { LovelaceCard, LovelaceCardConfig, LovelaceCardEditor } from "../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 computeDomain from "../../../common/entity/compute_domain"; diff --git a/src/panels/lovelace/cards/hui-entity-button-card.ts b/src/panels/lovelace/cards/hui-entity-button-card.ts index 78c0320e26..4bc9d08e5d 100644 --- a/src/panels/lovelace/cards/hui-entity-button-card.ts +++ b/src/panels/lovelace/cards/hui-entity-button-card.ts @@ -18,7 +18,8 @@ import applyThemesOnElement from "../../../common/dom/apply_themes_on_element"; import { toggleEntity } from "../common/entity/toggle-entity"; import { HomeAssistant, LightEntity } from "../../../types"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; -import { LovelaceCard, LovelaceCardConfig } from "../types"; +import { LovelaceCard } from "../types"; +import { LovelaceCardConfig } from "../../../data/lovelace"; import { longPress } from "../common/directives/long-press-directive"; import { fireEvent } from "../../../common/dom/fire_event"; diff --git a/src/panels/lovelace/cards/hui-error-card.ts b/src/panels/lovelace/cards/hui-error-card.ts index 6d89c406c9..4cbcedb3eb 100644 --- a/src/panels/lovelace/cards/hui-error-card.ts +++ b/src/panels/lovelace/cards/hui-error-card.ts @@ -1,6 +1,7 @@ import { html, LitElement } from "@polymer/lit-element"; -import { LovelaceCard, LovelaceCardConfig } from "../types"; +import { LovelaceCard } from "../types"; +import { LovelaceCardConfig } from "../../../data/lovelace"; import { TemplateResult } from "lit-html"; interface Config extends LovelaceCardConfig { diff --git a/src/panels/lovelace/cards/hui-gauge-card.ts b/src/panels/lovelace/cards/hui-gauge-card.ts index e901f5d3cf..aea51d6419 100644 --- a/src/panels/lovelace/cards/hui-gauge-card.ts +++ b/src/panels/lovelace/cards/hui-gauge-card.ts @@ -6,7 +6,8 @@ import { } from "@polymer/lit-element"; import { TemplateResult } from "lit-html"; -import { LovelaceCard, LovelaceCardConfig } from "../types"; +import { LovelaceCard } from "../types"; +import { LovelaceCardConfig } from "../../../data/lovelace"; import { HomeAssistant } from "../../../types"; import { fireEvent } from "../../../common/dom/fire_event"; diff --git a/src/panels/lovelace/cards/hui-glance-card.ts b/src/panels/lovelace/cards/hui-glance-card.ts index 246a0e564d..0fefb11001 100644 --- a/src/panels/lovelace/cards/hui-glance-card.ts +++ b/src/panels/lovelace/cards/hui-glance-card.ts @@ -10,7 +10,8 @@ import { classMap } from "lit-html/directives/classMap"; import { fireEvent } from "../../../common/dom/fire_event"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; import { HomeAssistant } from "../../../types"; -import { LovelaceCard, LovelaceCardConfig, LovelaceCardEditor } from "../types"; +import { LovelaceCard, LovelaceCardEditor } from "../types"; +import { LovelaceCardConfig } from "../../../data/lovelace"; import { longPress } from "../common/directives/long-press-directive"; import { EntityConfig } from "../entity-rows/types"; import { toggleEntity } from "../common/entity/toggle-entity"; diff --git a/src/panels/lovelace/cards/hui-iframe-card.ts b/src/panels/lovelace/cards/hui-iframe-card.ts index a964bcac90..93a643fc53 100644 --- a/src/panels/lovelace/cards/hui-iframe-card.ts +++ b/src/panels/lovelace/cards/hui-iframe-card.ts @@ -2,7 +2,8 @@ import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; import "../../../components/ha-card"; -import { LovelaceCard, LovelaceCardConfig } from "../types"; +import { LovelaceCard } from "../types"; +import { LovelaceCardConfig } from "../../../data/lovelace"; import { TemplateResult } from "lit-html"; import { styleMap } from "lit-html/directives/styleMap"; diff --git a/src/panels/lovelace/cards/hui-light-card.ts b/src/panels/lovelace/cards/hui-light-card.ts index 99e2c2c613..11204aa5fc 100644 --- a/src/panels/lovelace/cards/hui-light-card.ts +++ b/src/panels/lovelace/cards/hui-light-card.ts @@ -12,7 +12,8 @@ import { jQuery } from "../../../resources/jquery"; import { roundSliderStyle } from "../../../resources/jquery.roundslider"; import { HomeAssistant, LightEntity } from "../../../types"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; -import { LovelaceCard, LovelaceCardConfig } from "../types"; +import { LovelaceCard } from "../types"; +import { LovelaceCardConfig } from "../../../data/lovelace"; import { longPress } from "../common/directives/long-press-directive"; import stateIcon from "../../../common/entity/state_icon"; diff --git a/src/panels/lovelace/cards/hui-markdown-card.ts b/src/panels/lovelace/cards/hui-markdown-card.ts index 99380293a8..e30fadaa40 100644 --- a/src/panels/lovelace/cards/hui-markdown-card.ts +++ b/src/panels/lovelace/cards/hui-markdown-card.ts @@ -4,7 +4,8 @@ import { classMap } from "lit-html/directives/classMap"; import "../../../components/ha-card"; import "../../../components/ha-markdown"; -import { LovelaceCard, LovelaceCardConfig } from "../types"; +import { LovelaceCard } from "../types"; +import { LovelaceCardConfig } from "../../../data/lovelace"; import { TemplateResult } from "lit-html"; interface Config extends LovelaceCardConfig { diff --git a/src/panels/lovelace/cards/hui-picture-card.ts b/src/panels/lovelace/cards/hui-picture-card.ts index f5744a5c7f..a638da66a2 100644 --- a/src/panels/lovelace/cards/hui-picture-card.ts +++ b/src/panels/lovelace/cards/hui-picture-card.ts @@ -2,7 +2,8 @@ import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; import "../../../components/ha-card"; -import { LovelaceCard, LovelaceCardConfig } from "../types"; +import { LovelaceCard } from "../types"; +import { LovelaceCardConfig } from "../../../data/lovelace"; import { navigate } from "../../../common/navigate"; import { HomeAssistant } from "../../../types"; import { TemplateResult } from "lit-html"; diff --git a/src/panels/lovelace/cards/hui-picture-elements-card.ts b/src/panels/lovelace/cards/hui-picture-elements-card.ts index 4d77fdaab8..16e22e1bb6 100644 --- a/src/panels/lovelace/cards/hui-picture-elements-card.ts +++ b/src/panels/lovelace/cards/hui-picture-elements-card.ts @@ -3,7 +3,8 @@ import { TemplateResult } from "lit-html"; import createHuiElement from "../common/create-hui-element"; -import { LovelaceCard, LovelaceCardConfig } from "../types"; +import { LovelaceCard } from "../types"; +import { LovelaceCardConfig } from "../../../data/lovelace"; import { HomeAssistant } from "../../../types"; import { LovelaceElementConfig, LovelaceElement } from "../elements/types"; diff --git a/src/panels/lovelace/cards/hui-picture-glance-card.ts b/src/panels/lovelace/cards/hui-picture-glance-card.ts index 8853146118..816148aa86 100644 --- a/src/panels/lovelace/cards/hui-picture-glance-card.ts +++ b/src/panels/lovelace/cards/hui-picture-glance-card.ts @@ -5,7 +5,8 @@ import { TemplateResult } from "lit-html"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; import { fireEvent } from "../../../common/dom/fire_event"; import { DOMAINS_TOGGLE } from "../../../common/const"; -import { LovelaceCard, LovelaceCardConfig } from "../types"; +import { LovelaceCard } from "../types"; +import { LovelaceCardConfig } from "../../../data/lovelace"; import { EntityConfig } from "../entity-rows/types"; import { navigate } from "../../../common/navigate"; import { HomeAssistant } from "../../../types"; diff --git a/src/panels/lovelace/cards/hui-shopping-list-card.ts b/src/panels/lovelace/cards/hui-shopping-list-card.ts index 1930dfbdff..05a53d88e0 100644 --- a/src/panels/lovelace/cards/hui-shopping-list-card.ts +++ b/src/panels/lovelace/cards/hui-shopping-list-card.ts @@ -9,7 +9,8 @@ import "../../../components/ha-icon"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; import { HomeAssistant } from "../../../types"; -import { LovelaceCard, LovelaceCardConfig } from "../types"; +import { LovelaceCard } from "../types"; +import { LovelaceCardConfig } from "../../../data/lovelace"; import { fetchItems, completeItem, diff --git a/src/panels/lovelace/cards/hui-stack-card.ts b/src/panels/lovelace/cards/hui-stack-card.ts index cf2820cdc8..f246ed8c74 100644 --- a/src/panels/lovelace/cards/hui-stack-card.ts +++ b/src/panels/lovelace/cards/hui-stack-card.ts @@ -3,7 +3,8 @@ import { TemplateResult } from "lit-html"; import createCardElement from "../common/create-card-element"; -import { LovelaceCard, LovelaceCardConfig } from "../types"; +import { LovelaceCard } from "../types"; +import { LovelaceCardConfig } from "../../../data/lovelace"; import { HomeAssistant } from "../../../types"; 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 e39376c32a..c2f5f5fab4 100644 --- a/src/panels/lovelace/cards/hui-thermostat-card.ts +++ b/src/panels/lovelace/cards/hui-thermostat-card.ts @@ -15,7 +15,8 @@ import { hasConfigOrEntityChanged } from "../common/has-changed"; import { roundSliderStyle } from "../../../resources/jquery.roundslider"; import { HomeAssistant, ClimateEntity } from "../../../types"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; -import { LovelaceCard, LovelaceCardConfig } from "../types"; +import { LovelaceCard } from "../types"; +import { LovelaceCardConfig } from "../../../data/lovelace"; import "../../../components/ha-card"; import "../../../components/ha-icon"; diff --git a/src/panels/lovelace/common/generate-lovelace-config.ts b/src/panels/lovelace/common/generate-lovelace-config.ts index 6109b96fef..ec53061460 100644 --- a/src/panels/lovelace/common/generate-lovelace-config.ts +++ b/src/panels/lovelace/common/generate-lovelace-config.ts @@ -3,7 +3,7 @@ import { LovelaceConfig, LovelaceCardConfig, LovelaceViewConfig, -} from "../types"; +} from "../../../data/lovelace"; import { HassEntity, HassEntities } from "home-assistant-js-websocket"; import extractViews from "../../../common/entity/extract_views"; import getViewEntities from "../../../common/entity/get_view_entities"; diff --git a/src/panels/lovelace/components/hui-card-options.ts b/src/panels/lovelace/components/hui-card-options.ts index 8cc1ab6a85..5b8126e206 100644 --- a/src/panels/lovelace/components/hui-card-options.ts +++ b/src/panels/lovelace/components/hui-card-options.ts @@ -6,7 +6,7 @@ import { registerEditCardDialog, } from "../editor/hui-dialog-edit-card"; import { HomeAssistant } from "../../../types"; -import { LovelaceCardConfig } from "../types"; +import { LovelaceCardConfig } from "../../../data/lovelace"; declare global { // for fire event diff --git a/src/panels/lovelace/editor/hui-card-preview.ts b/src/panels/lovelace/editor/hui-card-preview.ts index 31617da87d..4cedeec537 100644 --- a/src/panels/lovelace/editor/hui-card-preview.ts +++ b/src/panels/lovelace/editor/hui-card-preview.ts @@ -3,7 +3,8 @@ 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 { LovelaceCard, LovelaceCardConfig } from "../types"; +import { LovelaceCardConfig } from "../../../data/lovelace"; +import { LovelaceCard } from "../types"; import { ConfigError } from "./types"; const CUSTOM_TYPE_PREFIX = "custom:"; diff --git a/src/panels/lovelace/editor/hui-dialog-edit-card.ts b/src/panels/lovelace/editor/hui-dialog-edit-card.ts index 741ac97497..7907098a47 100644 --- a/src/panels/lovelace/editor/hui-dialog-edit-card.ts +++ b/src/panels/lovelace/editor/hui-dialog-edit-card.ts @@ -3,7 +3,7 @@ import { TemplateResult } from "lit-html"; import { HomeAssistant } from "../../../types"; import { fireEvent, HASSDomEvent } from "../../../common/dom/fire_event"; -import { LovelaceCardConfig } from "../types"; +import { LovelaceCardConfig } from "../../../data/lovelace"; import "./hui-edit-card"; import "./hui-migrate-config"; diff --git a/src/panels/lovelace/editor/hui-dialog-save-config.ts b/src/panels/lovelace/editor/hui-dialog-save-config.ts index de759c54cf..9b7bc343ff 100644 --- a/src/panels/lovelace/editor/hui-dialog-save-config.ts +++ b/src/panels/lovelace/editor/hui-dialog-save-config.ts @@ -9,9 +9,12 @@ import { PaperDialogElement } from "@polymer/paper-dialog/paper-dialog"; import "@polymer/paper-button/paper-button"; import { HomeAssistant } from "../../../types"; -import { LovelaceConfig } from "../types"; -import { saveConfig, migrateConfig } from "../common/data"; +import { + saveConfig, + migrateConfig, + LovelaceConfig, +} from "../../../data/lovelace"; import { fireEvent } from "../../../common/dom/fire_event"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; diff --git a/src/panels/lovelace/editor/hui-edit-card.ts b/src/panels/lovelace/editor/hui-edit-card.ts index 6b7114e654..5e69084d92 100644 --- a/src/panels/lovelace/editor/hui-edit-card.ts +++ b/src/panels/lovelace/editor/hui-edit-card.ts @@ -12,7 +12,7 @@ import "@polymer/paper-button/paper-button"; import "@polymer/paper-input/paper-textarea"; import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable"; import { HomeAssistant } from "../../../types"; -import { updateCardConfig } from "../common/data"; +import { updateCardConfig, LovelaceCardConfig } from "../../../data/lovelace"; import { fireEvent } from "../../../common/dom/fire_event"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; @@ -21,7 +21,7 @@ import "./hui-card-preview"; // This is not a duplicate import, one is for types, one is for element. // tslint:disable-next-line import { HuiCardPreview } from "./hui-card-preview"; -import { LovelaceCardEditor, LovelaceCardConfig } from "../types"; +import { LovelaceCardEditor } from "../types"; import { YamlChangedEvent, ConfigValue, ConfigError } from "./types"; import { extYamlSchema } from "./yaml-ext-schema"; import { EntityConfig } from "../entity-rows/types"; diff --git a/src/panels/lovelace/editor/hui-migrate-config.ts b/src/panels/lovelace/editor/hui-migrate-config.ts index 078a8a53cc..63d42786d6 100644 --- a/src/panels/lovelace/editor/hui-migrate-config.ts +++ b/src/panels/lovelace/editor/hui-migrate-config.ts @@ -11,7 +11,7 @@ import { fireEvent } from "../../../common/dom/fire_event"; import { HomeAssistant } from "../../../types"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; -import { migrateConfig } from "../common/data"; +import { migrateConfig } from "../../../data/lovelace"; export class HuiMigrateConfig extends hassLocalizeLitMixin(LitElement) { protected hass?: HomeAssistant; diff --git a/src/panels/lovelace/editor/hui-yaml-editor.ts b/src/panels/lovelace/editor/hui-yaml-editor.ts index da8f322cbf..6dcb47b70c 100644 --- a/src/panels/lovelace/editor/hui-yaml-editor.ts +++ b/src/panels/lovelace/editor/hui-yaml-editor.ts @@ -5,7 +5,7 @@ import "@polymer/paper-spinner/paper-spinner"; import { HomeAssistant } from "../../../types"; import { fireEvent } from "../../../common/dom/fire_event"; -import { getCardConfig } from "../common/data"; +import { getCardConfig } from "../../../data/lovelace"; export class HuiYAMLEditor extends LitElement { public cardId?: string; diff --git a/src/panels/lovelace/editor/types.ts b/src/panels/lovelace/editor/types.ts index c89ab3e10a..8c929f37a5 100644 --- a/src/panels/lovelace/editor/types.ts +++ b/src/panels/lovelace/editor/types.ts @@ -1,4 +1,4 @@ -import { LovelaceCardConfig } from "../types"; +import { LovelaceCardConfig } from "../../../data/lovelace"; import { EntityConfig } from "../entity-rows/types"; export interface YamlChangedEvent extends Event { diff --git a/src/panels/lovelace/ha-panel-lovelace.js b/src/panels/lovelace/ha-panel-lovelace.js index 2e7f4237de..c7b8fa27a8 100644 --- a/src/panels/lovelace/ha-panel-lovelace.js +++ b/src/panels/lovelace/ha-panel-lovelace.js @@ -3,6 +3,7 @@ import { PolymerElement } from "@polymer/polymer/polymer-element"; import "@polymer/paper-button/paper-button"; import { registerSaveDialog } from "./editor/hui-dialog-save-config"; +import { fetchConfig } from "../../data/lovelace"; import "../../layouts/hass-loading-screen"; import "../../layouts/hass-error-screen"; import "./hui-root"; @@ -114,7 +115,7 @@ class Lovelace extends localizeMixin(PolymerElement) { async _fetchConfig() { try { - const conf = await this.hass.callWS({ type: "lovelace/config" }); + const conf = await fetchConfig(this.hass); this.setProperties({ _config: conf, _state: "loaded", diff --git a/src/panels/lovelace/types.ts b/src/panels/lovelace/types.ts index 6ebd271676..141f12c86f 100644 --- a/src/panels/lovelace/types.ts +++ b/src/panels/lovelace/types.ts @@ -1,24 +1,5 @@ import { HomeAssistant } from "../../types"; - -export interface LovelaceCardConfig { - id?: string; - type: string; - [key: string]: any; -} - -export interface LovelaceViewConfig { - title?: string; - badges?: string[]; - cards?: LovelaceCardConfig[]; - id?: string; - icon?: string; -} - -export interface LovelaceConfig { - _frontendAuto: boolean; - title?: string; - views: LovelaceViewConfig[]; -} +import { LovelaceCardConfig } from "../../data/lovelace"; export interface LovelaceCard extends HTMLElement { hass?: HomeAssistant; From 4487c3dc1a99ca55868a58d428cba91f13b322ca Mon Sep 17 00:00:00 2001 From: Zack Arnett Date: Tue, 27 Nov 2018 11:17:59 -0500 Subject: [PATCH 21/69] Removes Height, Light Width and Line Color from Sensor (#2122) * Sensor fix * SVG prettified - Use Accent Color only - Dont Calc height * Prettier --- src/panels/lovelace/cards/hui-sensor-card.js | 26 +++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/panels/lovelace/cards/hui-sensor-card.js b/src/panels/lovelace/cards/hui-sensor-card.js index 58890b3b50..58a8c96574 100755 --- a/src/panels/lovelace/cards/hui-sensor-card.js +++ b/src/panels/lovelace/cards/hui-sensor-card.js @@ -42,15 +42,11 @@ class HuiSensorCard extends EventsMixin(LitElement) { const cardConfig = { detail: 1, icon: false, - height: 100, hours_to_show: 24, - line_color: "var(--accent-color)", - line_width: 5, ...config, }; cardConfig.hours_to_show = Number(cardConfig.hours_to_show); cardConfig.height = Number(cardConfig.height); - cardConfig.line_width = Number(cardConfig.line_width); cardConfig.detail = cardConfig.detail === 1 || cardConfig.detail === 2 ? cardConfig.detail @@ -64,7 +60,7 @@ class HuiSensorCard extends EventsMixin(LitElement) { return change; } - render({ _config, _entity, _line } = this) { + render({ _entity, _line } = this) { return html` ${this._style()} @@ -85,11 +81,17 @@ class HuiSensorCard extends EventsMixin(LitElement) { ${ _line ? svg` - - - ` + + + + ` : "" } @@ -144,8 +146,8 @@ class HuiSensorCard extends EventsMixin(LitElement) { _calcPoints(history, hours, width, detail = 1) { const coords = []; - const margin = this._config.line_width; - const height = this._config.height - margin * 4; + const margin = 5; + const height = 80; width -= margin * 2; let yRatio = (this._max - this._min) / height; yRatio = yRatio !== 0 ? yRatio : height; From ffc7f9706dca41e679d440c682fd94bb84047be5 Mon Sep 17 00:00:00 2001 From: Zack Arnett Date: Tue, 27 Nov 2018 11:48:41 -0500 Subject: [PATCH 22/69] Update Aspect Ratio on Map card (#2126) * Update Aspect Ratio * Update Card Size --- src/panels/lovelace/cards/hui-map-card.js | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/panels/lovelace/cards/hui-map-card.js b/src/panels/lovelace/cards/hui-map-card.js index d49686e2c4..76034be484 100644 --- a/src/panels/lovelace/cards/hui-map-card.js +++ b/src/panels/lovelace/cards/hui-map-card.js @@ -10,6 +10,7 @@ import processConfigEntities from "../common/process-config-entities"; import computeStateDomain from "../../../common/entity/compute_state_domain"; import computeStateName from "../../../common/entity/compute_state_name"; import debounce from "../../../common/util/debounce"; +import parseAspectRatio from "../../../common/util/parse-aspect-ratio"; Leaflet.Icon.Default.imagePath = "/static/images/leaflet"; @@ -97,7 +98,15 @@ class HuiMapCard extends PolymerElement { return; } - this.$.root.style.paddingTop = this._config.aspect_ratio || "100%"; + const ratio = parseAspectRatio(this._config.aspect_ratio); + + if (ratio && ratio.w > 0 && ratio.h > 0) { + this.$.root.style.paddingBottom = `${((100 * ratio.h) / ratio.w).toFixed( + 2 + )}%`; + } else { + this.$.root.style.paddingBottom = "100%"; + } } setConfig(config) { @@ -110,8 +119,13 @@ class HuiMapCard extends PolymerElement { } getCardSize() { - let ar = this._config.aspect_ratio || "100%"; - ar = ar.substr(0, ar.length - 1); + const ratio = parseAspectRatio(this._config.aspect_ratio); + let ar; + if (ratio && ratio.w > 0 && ratio.h > 0) { + ar = `${((100 * ratio.h) / ratio.w).toFixed(2)}`; + } else { + ar = "100"; + } return 1 + Math.floor(ar / 25) || 3; } From 8757dbb66408f5dc9bbe3ed60f9ab8179285483c Mon Sep 17 00:00:00 2001 From: Zack Arnett Date: Tue, 27 Nov 2018 14:22:53 -0500 Subject: [PATCH 23/69] Plant add name (#2130) --- src/cards/ha-plant-card.js | 3 ++- src/panels/lovelace/cards/hui-legacy-wrapper-card.js | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cards/ha-plant-card.js b/src/cards/ha-plant-card.js index 2cb91c762d..f1a4fcbbdd 100644 --- a/src/cards/ha-plant-card.js +++ b/src/cards/ha-plant-card.js @@ -103,6 +103,7 @@ class HaPlantCard extends EventsMixin(PolymerElement) { return { hass: Object, stateObj: Object, + config: Object, }; } @@ -118,7 +119,7 @@ class HaPlantCard extends EventsMixin(PolymerElement) { } computeTitle(stateObj) { - return computeStateName(stateObj); + return this.config.name || computeStateName(stateObj); } computeAttributes(data) { diff --git a/src/panels/lovelace/cards/hui-legacy-wrapper-card.js b/src/panels/lovelace/cards/hui-legacy-wrapper-card.js index b9957c41bb..cdd4de0554 100644 --- a/src/panels/lovelace/cards/hui-legacy-wrapper-card.js +++ b/src/panels/lovelace/cards/hui-legacy-wrapper-card.js @@ -34,6 +34,7 @@ export default class LegacyWrapperCard extends HTMLElement { this._ensureElement(this._tag); this.lastChild.hass = hass; this.lastChild.stateObj = hass.states[entityId]; + this.lastChild.config = this._config; } else { this._ensureElement("HUI-ERROR-CARD"); this.lastChild.setConfig( From f04f58ac882d41d71c4c4fce09f3bd11e01447da Mon Sep 17 00:00:00 2001 From: Zack Arnett Date: Tue, 27 Nov 2018 14:25:52 -0500 Subject: [PATCH 24/69] Change Title to Name (#2129) --- src/panels/lovelace/cards/hui-alarm-panel-card.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/panels/lovelace/cards/hui-alarm-panel-card.js b/src/panels/lovelace/cards/hui-alarm-panel-card.js index 49015fbf1a..3d1e858f43 100644 --- a/src/panels/lovelace/cards/hui-alarm-panel-card.js +++ b/src/panels/lovelace/cards/hui-alarm-panel-card.js @@ -209,8 +209,8 @@ class HuiAlarmPanelCard extends LocalizeMixin(EventsMixin(PolymerElement)) { _computeHeader(localize, stateObj) { if (!stateObj) return ""; - return this._config.title - ? this._config.title + return this._config.name + ? this._config.name : this._label(localize, stateObj.state); } From d2741af24b39e0d5fe8a0c59de93e9a9c99b8c1a Mon Sep 17 00:00:00 2001 From: Zack Arnett Date: Tue, 27 Nov 2018 14:26:56 -0500 Subject: [PATCH 25/69] Add name to config (#2128) --- src/panels/lovelace/cards/hui-thermostat-card.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/panels/lovelace/cards/hui-thermostat-card.ts b/src/panels/lovelace/cards/hui-thermostat-card.ts index c2f5f5fab4..792f68134f 100644 --- a/src/panels/lovelace/cards/hui-thermostat-card.ts +++ b/src/panels/lovelace/cards/hui-thermostat-card.ts @@ -47,6 +47,7 @@ const modeIcons = { interface Config extends LovelaceCardConfig { entity: string; theme?: string; + name?: string; } function formatTemp(temps: string[]): string { @@ -97,7 +98,8 @@ export class HuiThermostatCard extends hassLocalizeLitMixin(LitElement)
-
${computeStateName(stateObj)}
+
${this._config.name || + computeStateName(stateObj)}
${stateObj.attributes.current_temperature} From bf69c8ce4680b46ea6b304227d7f76e780db7048 Mon Sep 17 00:00:00 2001 From: Zack Arnett Date: Tue, 27 Nov 2018 14:30:22 -0500 Subject: [PATCH 26/69] Title to Name (#2127) --- src/panels/lovelace/cards/hui-gauge-card.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/panels/lovelace/cards/hui-gauge-card.ts b/src/panels/lovelace/cards/hui-gauge-card.ts index aea51d6419..d19610d33f 100644 --- a/src/panels/lovelace/cards/hui-gauge-card.ts +++ b/src/panels/lovelace/cards/hui-gauge-card.ts @@ -10,16 +10,17 @@ import { LovelaceCard } from "../types"; import { LovelaceCardConfig } from "../../../data/lovelace"; import { HomeAssistant } from "../../../types"; import { fireEvent } from "../../../common/dom/fire_event"; +import { hasConfigOrEntityChanged } from "../common/has-changed"; import isValidEntityId from "../../../common/entity/valid_entity_id"; import applyThemesOnElement from "../../../common/dom/apply_themes_on_element"; -import { hasConfigOrEntityChanged } from "../common/has-changed"; +import computeStateName from "../../../common/entity/compute_state_name"; import "../../../components/ha-card"; interface Config extends LovelaceCardConfig { entity: string; - title?: string; + name?: string; unit_of_measurement?: string; min?: number; max?: number; @@ -93,7 +94,9 @@ class HuiGaugeCard extends LitElement implements LovelaceCard { "" }
-
${this._config.title}
+
+ ${this._config.name || computeStateName(stateObj)} +
` @@ -211,7 +214,7 @@ class HuiGaugeCard extends LitElement implements LovelaceCard { .gauge-data #percent { font-size: calc(var(--base-unit) * 0.55); } - .gauge-data #title { + .gauge-data #name { padding-top: calc(var(--base-unit) * 0.15); font-size: calc(var(--base-unit) * 0.3); } From b37ea482d312c54528c8b425b5ba08270d4f2a5d Mon Sep 17 00:00:00 2001 From: Zack Arnett Date: Tue, 27 Nov 2018 15:06:51 -0500 Subject: [PATCH 27/69] Add name variable - Weather Card (#2131) * Add name variable * Update to state name --- src/cards/ha-weather-card.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/cards/ha-weather-card.js b/src/cards/ha-weather-card.js index 163663923f..bb87f7f9e5 100644 --- a/src/cards/ha-weather-card.js +++ b/src/cards/ha-weather-card.js @@ -1,6 +1,8 @@ import { html } from "@polymer/polymer/lib/utils/html-tag"; import { PolymerElement } from "@polymer/polymer/polymer-element"; +import { computeStateName } from "../common/entity/compute_state_name"; + import "../components/ha-card"; import "../components/ha-icon"; @@ -106,7 +108,7 @@ class HaWeatherCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
[[computeState(stateObj.state, localize)]] -
[[stateObj.attributes.friendly_name]]
+
[[computeName(stateObj)]]
@@ -271,6 +273,10 @@ class HaWeatherCard extends LocalizeMixin(EventsMixin(PolymerElement)) { return localize(`state.weather.${state}`) || state; } + computeName(stateObj) { + return this.config.name || computeStateName(stateObj); + } + showWeatherIcon(condition) { return condition in this.weatherIcons; } From 230ec51de5ae27490d22a7498522a702ba876832 Mon Sep 17 00:00:00 2001 From: Zack Arnett Date: Tue, 27 Nov 2018 15:35:41 -0500 Subject: [PATCH 28/69] Fixes: #2084 : Fix for extra padding (#2133) * Fix for extra padding * Easy fix --- src/components/ha-cards.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ha-cards.js b/src/components/ha-cards.js index 587b41a0d7..f88e1bb72e 100644 --- a/src/components/ha-cards.js +++ b/src/components/ha-cards.js @@ -123,7 +123,7 @@ class HaCards extends PolymerElement {
-
@@ -145,6 +161,10 @@ class HaGallery extends PolymerElement { type: Array, computed: "_computeMoreInfos(_demos)", }, + _utilDemos: { + type: Array, + computed: "_computeUtil(_demos)", + }, }; } @@ -178,7 +198,7 @@ class HaGallery extends PolymerElement { while (root.lastChild) root.removeChild(root.lastChild); if (demo) { - DEMOS(`./${demo}.js`); + DEMOS(`./${demo}.ts`); const el = document.createElement(demo); root.appendChild(el); } @@ -199,6 +219,10 @@ class HaGallery extends PolymerElement { _computeMoreInfos(demos) { return demos.filter((demo) => demo.includes("more-info")); } + + _computeUtil(demos) { + return demos.filter((demo) => demo.includes("util")); + } } customElements.define("ha-gallery", HaGallery); diff --git a/src/data/light.ts b/src/data/light.ts new file mode 100644 index 0000000000..8d0a701d29 --- /dev/null +++ b/src/data/light.ts @@ -0,0 +1,7 @@ +export const SUPPORT_BRIGHTNESS = 1; +export const SUPPORT_COLOR_TEMP = 2; +export const SUPPORT_EFFECT = 4; +export const SUPPORT_FLASH = 8; +export const SUPPORT_COLOR = 16; +export const SUPPORT_TRANSITION = 32; +export const SUPPORT_WHITE_VALUE = 128; From 5947bd6d746e033ceec243d3a49b68123f45e328 Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Wed, 5 Dec 2018 15:00:04 -0600 Subject: [PATCH 65/69] Align `picture-glance` card tap/hold actions (#2187) Removed unneccessary `force_dialog` config. Updated `handleClick` to use `entity` or `camera_image` for `more-info` dialog --- .../lovelace/cards/hui-picture-glance-card.ts | 47 ++++++++++--------- src/panels/lovelace/common/handle-click.ts | 7 ++- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/src/panels/lovelace/cards/hui-picture-glance-card.ts b/src/panels/lovelace/cards/hui-picture-glance-card.ts index cbd4543663..1a98be568a 100644 --- a/src/panels/lovelace/cards/hui-picture-glance-card.ts +++ b/src/panels/lovelace/cards/hui-picture-glance-card.ts @@ -3,37 +3,37 @@ import { classMap } from "lit-html/directives/classMap"; import { TemplateResult } from "lit-html"; import { hassLocalizeLitMixin } from "../../../mixins/lit-localize-mixin"; -import { fireEvent } from "../../../common/dom/fire_event"; import { DOMAINS_TOGGLE } from "../../../common/const"; import { LovelaceCard } from "../types"; -import { LovelaceCardConfig } from "../../../data/lovelace"; +import { LovelaceCardConfig, ActionConfig } from "../../../data/lovelace"; import { EntityConfig } from "../entity-rows/types"; -import { navigate } from "../../../common/navigate"; import { HomeAssistant } from "../../../types"; -import { toggleEntity } from "../common/entity/toggle-entity"; - +import { longPress } from "../common/directives/long-press-directive"; +import { processConfigEntities } from "../common/process-config-entities"; import computeStateDisplay from "../../../common/entity/compute_state_display"; import computeStateName from "../../../common/entity/compute_state_name"; -import { processConfigEntities } from "../common/process-config-entities"; import computeDomain from "../../../common/entity/compute_domain"; import stateIcon from "../../../common/entity/state_icon"; import "../../../components/ha-card"; import "../../../components/ha-icon"; import "../components/hui-image"; +import { handleClick } from "../common/handle-click"; +import { fireEvent } from "../../../common/dom/fire_event"; +import { toggleEntity } from "../common/entity/toggle-entity"; const STATES_OFF = new Set(["closed", "locked", "not_home", "off"]); interface Config extends LovelaceCardConfig { entities: EntityConfig[]; title?: string; - navigation_path?: string; image?: string; camera_image?: string; state_image?: {}; aspect_ratio?: string; entity?: string; - force_dialog?: boolean; + tap_action?: ActionConfig; + hold_action?: ActionConfig; } class HuiPictureGlanceCard extends hassLocalizeLitMixin(LitElement) @@ -88,19 +88,22 @@ class HuiPictureGlanceCard extends hassLocalizeLitMixin(LitElement) return html``; } - const isClickable = - this._config.navigation_path || this._config.camera_image; - return html` ${this.renderStyle()} diff --git a/src/panels/lovelace/common/handle-click.ts b/src/panels/lovelace/common/handle-click.ts index ba463d2025..bf1e3c149d 100644 --- a/src/panels/lovelace/common/handle-click.ts +++ b/src/panels/lovelace/common/handle-click.ts @@ -9,6 +9,7 @@ export const handleClick = ( hass: HomeAssistant, config: { entity?: string; + camera_image?: string; hold_action?: ActionConfig; tap_action?: ActionConfig; }, @@ -30,8 +31,10 @@ export const handleClick = ( switch (actionConfig.action) { case "more-info": - if (config.entity) { - fireEvent(node, "hass-more-info", { entityId: config.entity }); + if (config.entity || config.camera_image) { + fireEvent(node, "hass-more-info", { + entityId: config.entity ? config.entity! : config.camera_image!, + }); } break; case "navigate": From fb180c7b9b1c3097e7822945b23515edc1450c0b Mon Sep 17 00:00:00 2001 From: Ian Richardson Date: Wed, 5 Dec 2018 15:00:52 -0600 Subject: [PATCH 66/69] Align `picture` card tap/hold actions (#2186) Also removed unneccessary `navigation_path` config from `picture-entity` --- src/panels/lovelace/cards/hui-picture-card.ts | 30 +++++++++---------- .../lovelace/cards/hui-picture-entity-card.ts | 1 - 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/panels/lovelace/cards/hui-picture-card.ts b/src/panels/lovelace/cards/hui-picture-card.ts index a638da66a2..43ddd1a14e 100644 --- a/src/panels/lovelace/cards/hui-picture-card.ts +++ b/src/panels/lovelace/cards/hui-picture-card.ts @@ -3,17 +3,17 @@ import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; import "../../../components/ha-card"; import { LovelaceCard } from "../types"; -import { LovelaceCardConfig } from "../../../data/lovelace"; -import { navigate } from "../../../common/navigate"; +import { LovelaceCardConfig, ActionConfig } from "../../../data/lovelace"; import { HomeAssistant } from "../../../types"; import { TemplateResult } from "lit-html"; import { classMap } from "lit-html/directives/classMap"; +import { handleClick } from "../common/handle-click"; +import { longPress } from "../common/directives/long-press-directive"; interface Config extends LovelaceCardConfig { image?: string; - navigation_path?: string; - service?: string; - service_data?: object; + tap_action?: ActionConfig; + hold_action?: ActionConfig; } export class HuiPictureCard extends LitElement implements LovelaceCard { @@ -46,11 +46,13 @@ export class HuiPictureCard extends LitElement implements LovelaceCard { return html` ${this.renderStyle()} Date: Wed, 5 Dec 2018 22:05:51 +0100 Subject: [PATCH 67/69] Handle mouse events on touchscreens. Fix #2085 (#2170) * Handle mouse events on touchscreens. Fix #2085 * Some more fixes. Makes listeners non-passive! * Only prevent preventable events. * Different approach * Some travis fixes * Try to avoid clicking while scrolling --- .../common/directives/long-press-directive.ts | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/src/panels/lovelace/common/directives/long-press-directive.ts b/src/panels/lovelace/common/directives/long-press-directive.ts index 2b59a84d63..718ccbafab 100644 --- a/src/panels/lovelace/common/directives/long-press-directive.ts +++ b/src/panels/lovelace/common/directives/long-press-directive.ts @@ -19,6 +19,8 @@ class LongPress extends HTMLElement implements LongPress { protected ripple: any; protected timer: number | undefined; protected held: boolean; + protected cooldownStart: boolean; + protected cooldownEnd: boolean; constructor() { super(); @@ -26,6 +28,8 @@ class LongPress extends HTMLElement implements LongPress { this.ripple = document.createElement("mwc-ripple"); this.timer = undefined; this.held = false; + this.cooldownStart = false; + this.cooldownEnd = false; } public connectedCallback() { @@ -41,7 +45,8 @@ class LongPress extends HTMLElement implements LongPress { this.ripple.primary = true; [ - isTouch ? "touchcancel" : "mouseout", + "touchcancel", + "mouseout", "mouseup", "touchmove", "mousewheel", @@ -80,6 +85,9 @@ class LongPress extends HTMLElement implements LongPress { }); const clickStart = (ev: Event) => { + if (this.cooldownStart) { + return; + } this.held = false; let x; let y; @@ -94,30 +102,35 @@ class LongPress extends HTMLElement implements LongPress { this.startAnimation(x, y); this.held = true; }, this.holdTime); + + this.cooldownStart = true; + window.setTimeout(() => (this.cooldownStart = false), 100); }; - const clickEnd = () => { - clearTimeout(this.timer); - this.stopAnimation(); - if (isTouch && this.timer === undefined) { + const clickEnd = (ev: Event) => { + if ( + this.cooldownEnd || + (ev instanceof TouchEvent && this.timer === undefined) + ) { return; } + clearTimeout(this.timer); + this.stopAnimation(); this.timer = undefined; if (this.held) { element.dispatchEvent(new Event("ha-hold")); } else { element.dispatchEvent(new Event("ha-click")); } + this.cooldownEnd = true; + window.setTimeout(() => (this.cooldownEnd = false), 100); }; - if (isTouch) { - element.addEventListener("touchstart", clickStart, { passive: true }); - element.addEventListener("touchend", clickEnd); - element.addEventListener("touchcancel", clickEnd); - } else { - element.addEventListener("mousedown", clickStart, { passive: true }); - element.addEventListener("click", clickEnd); - } + element.addEventListener("touchstart", clickStart, { passive: true }); + element.addEventListener("touchend", clickEnd); + element.addEventListener("touchcancel", clickEnd); + element.addEventListener("mousedown", clickStart, { passive: true }); + element.addEventListener("click", clickEnd); } private startAnimation(x: number, y: number) { From 2d0f14d0785dc4de64a9d4402bace0068d51a990 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 5 Dec 2018 22:07:34 +0100 Subject: [PATCH 68/69] Update translations --- translations/ca.json | 14 +- translations/cs.json | 4 +- translations/de.json | 22 ++- translations/en.json | 2 +- translations/es-419.json | 25 +++- translations/es.json | 27 +++- translations/fi.json | 35 ++++- translations/fr.json | 25 +++- translations/gsw.json | 8 + translations/he.json | 2 +- translations/hr.json | 300 +++++++++++++++++++++++++++++++++++--- translations/hu.json | 21 ++- translations/it.json | 35 ++++- translations/ko.json | 6 +- translations/lb.json | 40 ++--- translations/nl.json | 7 +- translations/nn.json | 2 +- translations/no.json | 2 +- translations/pl.json | 4 +- translations/pt-BR.json | 31 +++- translations/pt.json | 2 +- translations/ro.json | 14 +- translations/ru.json | 72 ++++----- translations/sl.json | 63 +++++--- translations/sv.json | 27 +++- translations/tr.json | 195 ++++++++++++++++++++++++- translations/uk.json | 10 +- translations/zh-Hans.json | 25 +++- translations/zh-Hant.json | 4 +- 29 files changed, 857 insertions(+), 167 deletions(-) diff --git a/translations/ca.json b/translations/ca.json index 07321e0970..a3e9102958 100644 --- a/translations/ca.json +++ b/translations/ca.json @@ -232,7 +232,7 @@ "default": { "initializing": "Inicialitzant", "dead": "No disponible", - "sleeping": "En espera", + "sleeping": "Dormint", "ready": "A punt" }, "query_stage": { @@ -297,11 +297,11 @@ "microphone_tip": "Toqueu el micròfon a la part superior dreta i dieu \"Add candy to my shopping list\"" }, "history": { - "showing_entries": "S'estan mostrant entrades per a", + "showing_entries": "Mostrant entrades de", "period": "Període" }, "logbook": { - "showing_entries": "S'estan mostrant entrades per a" + "showing_entries": "Mostrant entrades de" }, "mailbox": { "empty": "No teniu missatges", @@ -537,7 +537,7 @@ "caption": "Integracions", "description": "Gestioneu dispositius i serveis connectats", "discovered": "Descobert", - "configured": "Configurat", + "configured": "Configurades", "new": "Configureu una nova integració", "configure": "Configurar", "none": "Encara no hi ha res configurat", @@ -723,7 +723,7 @@ } }, "editor": { - "edit": { + "edit_card": { "header": "Targeta de Configuració", "save": "Desa", "toggle_editor": "Commuta l'editor" @@ -746,8 +746,8 @@ "cancel": "Cancel·lar" }, "duration": { - "day": "{count} {count, plural,\none {dia}\nother {dies}\n}", - "week": "{count} {count, plural,\none {setmana}\nother {setmanes}\n}", + "day": "{count} {count, plural,\n one {dia}\n other {dies}\n}", + "week": "{count} {count, plural,\n one {setmana}\n other {setmanes}\n}", "second": "{count} {count, plural,\none {segon}\nother {segons}\n}", "minute": "{count} {count, plural,\none {minut}\nother {minuts}\n}", "hour": "{count} {count, plural,\none {hora}\nother {hores}\n}" diff --git a/translations/cs.json b/translations/cs.json index c21c88a26b..c8d3940366 100644 --- a/translations/cs.json +++ b/translations/cs.json @@ -579,7 +579,7 @@ "description": "Každý obnovovací token představuje relaci přihlášení. Aktualizační tokeny budou automaticky odstraněny po klepnutí na tlačítko Odhlásit. Následující tokeny obnovení jsou v současné době aktivní pro váš účet.", "token_title": "Obnovit token pro {clientId}", "created_at": "Vytvořeno {date}", - "confirm_delete": "Opravdu že chcete odstranit token pro {název}?", + "confirm_delete": "Opravdu že chcete odstranit token pro {name}?", "delete_failed": "Nepodařilo se smazat token.", "last_used": "Naposledy použito {date} z {location}", "not_used": "Nikdy nebylo použito", @@ -723,7 +723,7 @@ } }, "editor": { - "edit": { + "edit_card": { "header": "Konfigurace karty", "save": "Uložit", "toggle_editor": "Přepnout Editor" diff --git a/translations/de.json b/translations/de.json index 688a55e94c..f480228937 100644 --- a/translations/de.json +++ b/translations/de.json @@ -144,7 +144,8 @@ "performance": "Leistung", "high_demand": "Hoher Verbrauch", "heat_pump": "Wärmepumpe", - "gas": "Gas" + "gas": "Gas", + "manual": "Handbuch" }, "configurator": { "configure": "Konfigurieren", @@ -712,6 +713,25 @@ "required_fields": "Fülle alle Pflichtfelder aus." } } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "Markierte Items", + "clear_items": "Markierte Elemente löschen", + "add_item": "Item hinzufügen" + } + }, + "editor": { + "edit_card": { + "save": "Speichern", + "toggle_editor": "Editor umschalten" + }, + "migrate": { + "header": "Konfiguration inkompatibel", + "para_no_id": "Dieses Element hat keine ID. Bitte füge diesem Element eine ID in 'ui-lovelace.yaml' hinzu." + } + } } }, "sidebar": { diff --git a/translations/en.json b/translations/en.json index 722f9dd2e4..015430a1ab 100644 --- a/translations/en.json +++ b/translations/en.json @@ -723,7 +723,7 @@ } }, "editor": { - "edit": { + "edit_card": { "header": "Card Configuration", "save": "Save", "toggle_editor": "Toggle Editor" diff --git a/translations/es-419.json b/translations/es-419.json index 6a878a5635..3e6c5f07a9 100644 --- a/translations/es-419.json +++ b/translations/es-419.json @@ -144,7 +144,8 @@ "performance": "Rendimiento", "high_demand": "Alta Demanda", "heat_pump": "Bomba de Calor", - "gas": "Gas" + "gas": "Gas", + "manual": "Manual" }, "configurator": { "configure": "Configurar", @@ -712,6 +713,28 @@ "required_fields": "Completar todos los campos requeridos" } } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "lementos marcados", + "clear_items": "Borrar elementos marcados", + "add_item": "Agregar elemento" + } + }, + "editor": { + "edit_card": { + "header": "Configuración de la tarjeta", + "save": "Guardar", + "toggle_editor": "Cambiar editor" + }, + "migrate": { + "header": "Configuración inválida", + "para_no_id": "Este elemento no tiene un ID. Por favor agregue uno a 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" + } + } } }, "sidebar": { diff --git a/translations/es.json b/translations/es.json index cca9adf21d..07e1f98cac 100644 --- a/translations/es.json +++ b/translations/es.json @@ -144,7 +144,8 @@ "performance": "Rendimiento", "high_demand": "Alta demanda", "heat_pump": "Bomba de calor", - "gas": "Gas" + "gas": "Gas", + "manual": "Manual" }, "configurator": { "configure": "Configurar", @@ -589,7 +590,7 @@ "description": "Crea tokens de acceso de larga duración para permitir que tus scripts interactúen con tu Home Assistant. Cada token será válido por 10 años desde la creación. Los siguientes tokens de acceso de larga duración están actualmente activos.", "learn_auth_requests": "Aprenda a realizar solicitudes autenticadas.", "created_at": "Creado el {date}", - "confirm_delete": "¿Está seguro de que desea eliminar el token de acceso para {nombre}?", + "confirm_delete": "¿Está seguro de que desea eliminar el token de acceso para {name}?", "delete_failed": "Error al eliminar el token de acceso.", "create": "Crear Token", "create_failed": "No se ha podido crear el token de acceso.", @@ -712,6 +713,28 @@ "required_fields": "Complete todos los campos requeridos" } } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "Elementos marcados", + "clear_items": "Borrar elementos marcados", + "add_item": "Añadir artículo" + } + }, + "editor": { + "edit_card": { + "header": "Configuración de la tarjeta", + "save": "Guardar", + "toggle_editor": "Alternar editor" + }, + "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" + } + } } }, "sidebar": { diff --git a/translations/fi.json b/translations/fi.json index 69c48b27c4..a1c5304b1c 100644 --- a/translations/fi.json +++ b/translations/fi.json @@ -144,7 +144,8 @@ "performance": "Tehokas", "high_demand": "Täysi teho", "heat_pump": "Lämpöpumppu", - "gas": "Kaasu" + "gas": "Kaasu", + "manual": "käsisäätöinen" }, "configurator": { "configure": "Määrittele", @@ -619,7 +620,8 @@ }, "page-authorize": { "initializing": "Alustetaan", - "logging_in_with": "Kirjaudutaan sisään", + "authorizing_client": "Olet antamassa pääsyn {clientId} Home Assistant ympäristöösi.", + "logging_in_with": "Kirjaudutaan sisään **{authProviderName}**.", "pick_auth_provider": "Tai kirjaudu sisään joillakin seuraavista", "abort_intro": "Kirjautuminen on keskeytetty", "form": { @@ -681,6 +683,9 @@ }, "description": "Valitse käyttäjä, jolla haluat kirjautua:" } + }, + "abort": { + "not_whitelisted": "Tietokonettasi ei ole sallittu." } } } @@ -701,6 +706,28 @@ "required_fields": "Täytä kaikki pakolliset kentät" } } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "Valitut", + "clear_items": "Tyhjää valitut", + "add_item": "Lisää" + } + }, + "editor": { + "edit_card": { + "header": "Kortti-asetukset", + "save": "Tallenna", + "toggle_editor": "Vaihda editori" + }, + "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" + } + } } }, "sidebar": { @@ -769,7 +796,9 @@ "clear_code": "Tyhjennä", "disarm": "Poista hälytys", "arm_home": "Viritä (kotona)", - "arm_away": "Viritä (poissa)" + "arm_away": "Viritä (poissa)", + "arm_night": "Viritä yöksi", + "armed_custom_bypass": "Mukautettu ohitus" }, "automation": { "last_triggered": "Viimeksi käynnistetty", diff --git a/translations/fr.json b/translations/fr.json index f9d2311c54..2d1782d341 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -144,7 +144,8 @@ "performance": "Performance", "high_demand": "Forte demande", "heat_pump": "Pompe à chaleur", - "gas": "Gaz" + "gas": "Gaz", + "manual": "Manuel" }, "configurator": { "configure": "Configurer", @@ -712,6 +713,26 @@ "required_fields": "Remplissez tous les champs requis" } } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "Éléments cochés", + "add_item": "Ajouter un élément" + } + }, + "editor": { + "edit_card": { + "save": "Enregistrer", + "toggle_editor": "Activer\/désactiver l’éditeur" + }, + "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" + } + } } }, "sidebar": { @@ -849,7 +870,7 @@ "service": "Service" }, "relative_time": { - "past": "{time} auparavant", + "past": "Il y a {time}", "future": "Dans {time}", "never": "Jamais", "duration": { diff --git a/translations/gsw.json b/translations/gsw.json index 069cb85b0e..dd0543b2d4 100644 --- a/translations/gsw.json +++ b/translations/gsw.json @@ -348,6 +348,7 @@ }, "actions": { "header": "Aktione", + "unsupported_action": "Nicht unterstützte Aktion: {action}", "type": { "delay": { "label": "Vrzögerig" @@ -410,6 +411,13 @@ "mfa": { "disable": "Deaktiviert" } + }, + "lovelace": { + "editor": { + "edit_card": { + "save": "Speichern" + } + } } }, "login-form": { diff --git a/translations/he.json b/translations/he.json index 5d411cf77f..cae9ad84b7 100644 --- a/translations/he.json +++ b/translations/he.json @@ -722,7 +722,7 @@ } }, "editor": { - "edit": { + "edit_card": { "save": "שמור" } } diff --git a/translations/hr.json b/translations/hr.json index 9f4cc0f783..ff5c500471 100644 --- a/translations/hr.json +++ b/translations/hr.json @@ -99,6 +99,17 @@ "off": "Zatvoreno", "on": "Otvori" }, + "garage_door": { + "off": "Zatvoren", + "on": "Otvoreno" + }, + "heat": { + "off": "Normalno" + }, + "window": { + "off": "Zatvoreno", + "on": "Otvoreno" + }, "lock": { "off": "Zaključano", "on": "Otključano" @@ -127,7 +138,8 @@ "performance": "Performanse", "high_demand": "Velike potražnje", "heat_pump": "Toplinska pumpa", - "gas": "Plin" + "gas": "Plin", + "manual": "Priručnik" }, "configurator": { "configure": "Konfiguriranje", @@ -223,15 +235,27 @@ } }, "weather": { + "clear-night": "Vedro, noć", "cloudy": "Oblačno", "fog": "Magla", "lightning": "Munja", + "lightning-rainy": "Munja, kišna", "partlycloudy": "Djelomično oblačno", "pouring": "Lije", "rainy": "Kišovito", "snowy": "Snježno", + "snowy-rainy": "Snježno, kišno", "sunny": "Sunčano", - "windy": "Vjetrovito" + "windy": "Vjetrovito", + "windy-variant": "Vjetrovito" + }, + "vacuum": { + "cleaning": "Čišćenje", + "error": "Greška", + "idle": "Besposlen", + "off": "Ugašeno", + "on": "Upaljeno", + "paused": "Pauzirano" } }, "state_badge": { @@ -263,53 +287,209 @@ "add_item": "Dodaj stavku", "microphone_tip": "Dodirnite mikrofon u gornjem desnom kutu i recite “Add candy to my shopping list”" }, + "history": { + "showing_entries": "Prikazivanje stavki za", + "period": "Razdoblje" + }, "logbook": { "showing_entries": "Prikaži entitete za" }, + "mailbox": { + "empty": "Nemate nijednu poruku", + "playback_title": "Reprodukcija poruke", + "delete_prompt": "Izbrisati ovu poruku?", + "delete_button": "Izbrisati" + }, "config": { + "header": "Konfigurirajte Home Assistant", "core": { + "caption": "Općenito", "section": { "core": { - "header": "Konfiguracija i kontrola poslužitelja" + "header": "Konfiguracija i kontrola poslužitelja", + "validation": { + "check_config": "Provjerite konfiguraciju", + "valid": "Konfiguracija valjana!", + "invalid": "Konfiguracija nije važeća" + }, + "reloading": { + "core": "Ponovno učitati jezgru", + "group": "Ponovno učitajte grupe", + "automation": "Ponovo učitajte automatizacije" + }, + "server_management": { + "heading": "Upravljanje poslužiteljem", + "introduction": "Kontrolirajte vaš Home Assistant server ... iz Home Assistant.", + "restart": "Ponovno pokretanje" + } } } }, - "zwave": { - "caption": "Z-Wave" + "customize": { + "description": "Prilagodite entitete" }, "automation": { + "caption": "Automatizacija", + "description": "Stvaranje i uređivanje automatizacija", "picker": { - "header": "Urednik Automatizacije " + "header": "Urednik Automatizacije ", + "introduction": "Automatizacijski urednik omogućuje stvaranje i uređivanje automatizacije. Molimo pročitajte [upute] (https:\/\/home-assistant.io\/docs\/automation\/editor\/) kako biste bili sigurni da ste ispravno konfigurirali Home Assistant.", + "pick_automation": "Odaberite automatizaciju za uređivanje", + "no_automations": "Nismo mogli pronaći nikakve automatizirane uređaje", + "add_automation": "Dodaj automatizaciju" }, "editor": { + "introduction": "Upotrijebite automatizaciju kako bi vaš dom oživio", + "default_name": "Nova automatizacija", + "save": "Spremi", + "unsaved_confirm": "Imate nespremljene izmjene. Jeste li sigurni da želite napustiti?", + "alias": "Ime", + "triggers": { + "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\/)", + "delete": "Obriši", + "unsupported_platform": "Nepodržana platforma: {platform}", + "type": { + "state": { + "from": "Od", + "for": "Za" + }, + "homeassistant": { + "label": "Home Assistant", + "event": "Događaj:", + "start": "Početak", + "shutdown": "Ugasiti" + }, + "mqtt": { + "label": "MQTT", + "topic": "Tema" + }, + "numeric_state": { + "label": "Numeričko stanje", + "above": "Iznad", + "below": "Ispod", + "value_template": "Predložak vrijednosti (nije obavezno)" + }, + "sun": { + "label": "Sunce", + "event": "Event:", + "sunrise": "Izlazak sunca", + "sunset": "Zalazak sunca", + "offset": "Offset (nije obavezno)" + }, + "template": { + "label": "Predložak", + "value_template": "Predložak vrijednosti" + }, + "time": { + "label": "Vrijeme", + "at": "U" + }, + "zone": { + "label": "Zona", + "entity": "Entitet s lokacijom", + "zone": "Zona", + "event": "Event:", + "enter": "Unesite", + "leave": "Napustiti" + } + } + }, + "conditions": { + "header": "Uvjeti", + "introduction": "Uvjeti su neobvezni dio pravila o automatizaciji i mogu se upotrebljavati kako bi se spriječilo da se neka akcija dogodi prilikom pokretanja. Uvjeti izgledaju vrlo slični pokretačima, ali su vrlo različiti. Okidač će pogledati događaje koji se događaju u sustavu, a stanje samo gleda kako sustav izgleda upravo sada. Okidač može primijetiti da je prekidač uključen. Stanje može vidjeti samo ako je uključen ili isključen prekidač. \n\n [Saznajte više o uvjetima.] (Https:\/\/home-assistant.io\/docs\/scripts\/conditions\/)", + "add": "Dodaj uvjet", + "duplicate": "Dupliciran", + "delete": "Obriši", + "delete_confirm": "Sigurno želite pobrisati?", + "unsupported_condition": "Nepodržano stanje: {condition}", + "type_select": "Vrsta uvjeta", + "type": { + "state": { + "label": "Stanje", + "state": "Stanje" + }, + "numeric_state": { + "label": "Numeričko stanje", + "above": "Iznad", + "below": "Ispod", + "value_template": "Predložak vrijednosti (opciono)" + }, + "sun": { + "label": "Sunce", + "before": "Prije:", + "after": "Nakon:", + "before_offset": "Prije pomaka (izborno)", + "after_offset": "Nakon pomaka (izborno)", + "sunrise": "Izlazak sunca", + "sunset": "Zalazak sunca" + }, + "template": { + "label": "Predložak", + "value_template": "Predložak vrijednosti" + }, + "time": { + "label": "Vrijeme", + "after": "Nakon", + "before": "Prije" + }, + "zone": { + "label": "Zona", + "entity": "Entitet sa lokacijom", + "zone": "Zona" + } + } + }, "actions": { + "header": "Akcije", + "introduction": "Radnje su ono što će Home Assistant učiniti kada se aktivira automatizacija. \n\n [Saznajte više o radnjama.] (Https:\/\/home-assistant.io\/docs\/automation\/action\/)", + "add": "Dodajte radnju", "duplicate": "Dupliciraj", "delete": "Obriši", "delete_confirm": "Sigurno želite pobrisati?", "unsupported_action": "Nepodržana radnja: {action}", + "type_select": "Vrsta akcije", "type": { + "service": { + "label": "Zovi servis", + "service_data": "Podaci o usluzi" + }, "delay": { + "label": "Odgoditi", "delay": "Odgodi" }, + "wait_template": { + "label": "Čekaj", + "wait_template": "Čekaj predložak", + "timeout": "Vremensko ograničenje (opcionalno)" + }, + "condition": { + "label": "Stanje" + }, "event": { "label": "Pokreni događaj", "event": "Event:", "service_data": "Servisni podaci" } } - }, - "triggers": { - "type": { - "state": { - "for": "Za" - } - } } } }, + "zwave": { + "caption": "Z-Wave" + }, "users": { "caption": "Korisnici", - "description": "Upravljanje korisnicima" + "description": "Upravljanje korisnicima", + "picker": { + "title": "Korisnici" + }, + "editor": { + "rename_user": "Preimenuj korisnika", + "change_password": "Promijeni lozinku", + "activate_user": "Aktivirajte korisnika", + "deactivate_user": "Deaktivirajte korisnika", + "delete_user": "Izbriši korisnika" + } }, "cloud": { "caption": "Home Assistant Cloud", @@ -422,7 +602,8 @@ "step": { "init": { "data": { - "username": "Korisničko ime" + "username": "Korisničko ime", + "password": "Lozinka" } }, "mfa": { @@ -433,6 +614,7 @@ } }, "error": { + "invalid_auth": "Neispravno korisničko ime ili lozinka", "invalid_code": "Pogrešan kod za provjeru autentičnosti " }, "abort": { @@ -442,26 +624,49 @@ "legacy_api_password": { "step": { "init": { + "data": { + "password": "API lozinka" + }, "description": "Unesite API lozinku u svoj http config:" + }, + "mfa": { + "data": { + "code": "Kôd autentifikacije s dva faktora" + } } }, + "error": { + "invalid_auth": "Nevažeća lozinka za API", + "invalid_code": "Nevažeći kôd za autentifikaciju" + }, "abort": { + "no_api_password_set": "Nemate konfiguriranu lozinku za API.", "login_expired": "Sesija istekla, molim vas prijavite se ponovno." } }, "trusted_networks": { "step": { "init": { + "data": { + "user": "Korisnik" + }, "description": "Odaberite korisnika kojim se želite prijaviti:" } + }, + "abort": { + "not_whitelisted": "Računalo nije na popisu dopuštenih." } } } } }, "page-onboarding": { + "intro": "Jeste li spremni probuditi svoj dom, vratiti svoju privatnost i pridružiti se svjetskoj zajednici tinkerera?", "user": { + "intro": "Započnimo stvaranjem korisničkog računa.", + "required_field": "Potreban", "data": { + "name": "Ime", "username": "Korisničko ime", "password": "Lozinka" }, @@ -470,18 +675,52 @@ "required_fields": "Ispunite sva potrebna polja" } } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "Označene stavke", + "clear_items": "Izbrišite označene stavke", + "add_item": "Dodaj stavku" + } + }, + "editor": { + "edit_card": { + "header": "Konfiguracija Kartice ", + "save": "Spremi", + "toggle_editor": "Uključi uređivač" + }, + "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" + } + } } }, "sidebar": { "log_out": "Odjava", "developer_tools": "Razvojni alati" }, + "common": { + "loading": "Učitavam", + "cancel": "Otkazati" + }, "duration": { "day": "{count} {count, plural,\n one {dan}\n other {dani}\n}", "week": "{count} {count, plural,\n one {tjedan}\n other {tjedni}\n}", - "second": "{count} {count, plural,\n one {sekunde}\n other {sekunde}\n}" + "second": "{count} {count, plural,\n one {sekunde}\n other {sekunde}\n}", + "minute": "{broj} {broj, množina, jedna {minuta} druge {minute}}", + "hour": "{broj} {broj, množina, jedan {sat} drugi {sati}}" + }, + "login-form": { + "password": "Lozinka" }, "card": { + "camera": { + "not_available": "Slika nije dostupna" + }, "scene": { "activate": "Aktivirati" }, @@ -497,14 +736,24 @@ "wind_speed": "Brzina vjetra" }, "cardinal_direction": { - "n": "N" + "ese": "ESE", + "n": "N", + "ne": "NE", + "nne": "NNE", + "nw": "NW" } }, "alarm_control_panel": { - "code": "Kod" + "code": "Kod", + "disarm": "Deaktiviraj", + "arm_home": "Aktiviran doma", + "arm_away": "Aktiviran odsutno", + "arm_night": "Aktiviran nočni", + "armed_custom_bypass": "Prilagođena obilaznica" }, "fan": { "speed": "Brzina", + "oscillate": "Oscilirati", "direction": "Smjer" }, "light": { @@ -549,6 +798,14 @@ } }, "components": { + "entity": { + "entity-picker": { + "entity": "Entitet" + } + }, + "relative_time": { + "past": "{vrijeme} prije" + }, "history_charts": { "loading_history": "Učitavanje povijesti stanja ...", "no_history_found": "Nije pronađena povijest stanja." @@ -607,5 +864,12 @@ "updater": "Ažuriranje", "weblink": "WebLink", "zwave": "Z-Wave" + }, + "attribute": { + "weather": { + "humidity": "Vlažnost", + "visibility": "Vidljivost", + "wind_speed": "Brzina vjetra" + } } } \ No newline at end of file diff --git a/translations/hu.json b/translations/hu.json index db1edd1404..37ac3d1fab 100644 --- a/translations/hu.json +++ b/translations/hu.json @@ -145,7 +145,7 @@ "high_demand": "Magas igénybevétel", "heat_pump": "Hőszivattyú", "gas": "Gáz", - "manual": "Kézikönyv" + "manual": "Manuális" }, "configurator": { "configure": "Beállítás", @@ -600,7 +600,7 @@ "last_used": "Utolsó használat ideje: {date}, helye: {location}", "not_used": "Sosem használt" }, - "current_user": "Jelenleg bejelentkezve mint {fullName}.", + "current_user": "Jelenleg {fullName} felhasználóként vagy bejelentkezve.", "is_owner": "Tulajdonos vagy.", "logout": "Kijelentkezés", "change_password": { @@ -717,17 +717,22 @@ "lovelace": { "cards": { "shopping-list": { - "checked_items": "Ellenőrzött elemek ", - "clear_items": "Ellenőrzött elemek ", - "add_item": "Elem hozzáadása" + "checked_items": "Kijelölt tételek", + "clear_items": "Kijelölt tételek törlése", + "add_item": "Tétel hozzáadása" } }, "editor": { - "edit": { - "save": "Mentés" + "edit_card": { + "header": "Kártya Konfiguráció", + "save": "Mentés", + "toggle_editor": "Szerkesztő" }, "migrate": { - "header": "Inkompatibilis konfiguráció!" + "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.", + "migrate": "Konfiguráció áttelepítése" } } } diff --git a/translations/it.json b/translations/it.json index faa011978b..60fc3a16db 100644 --- a/translations/it.json +++ b/translations/it.json @@ -144,7 +144,8 @@ "performance": "Prestazioni", "high_demand": "Forte richiesta", "heat_pump": "Pompa di calore", - "gas": "Gas" + "gas": "Gas", + "manual": "Manuale" }, "configurator": { "configure": "Configura", @@ -545,9 +546,9 @@ "no_device": "Entità senza dispositivi", "delete_confirm": "Sei sicuro di voler eliminare questa integrazione?", "restart_confirm": "Riavvia Home Assistant per terminare la rimozione di questa integrazione", - "manuf": "da {produttore}", + "manuf": "da {manufacturer}", "hub": "Connesso via", - "firmware": "Firmware: {versione}", + "firmware": "Firmware: {version}", "device_unavailable": "dispositivo non disponibile", "entity_unavailable": "entità non disponibile" } @@ -712,6 +713,28 @@ "required_fields": "Compila tutti i campi richiesti" } } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "Elementi selezionati", + "clear_items": "Cancella gli elementi selezionati", + "add_item": "Aggiungi elemento" + } + }, + "editor": { + "edit_card": { + "header": "Configurazione della scheda", + "save": "Salva", + "toggle_editor": "Attiva \/ disattiva l'editor" + }, + "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" + } + } } }, "sidebar": { @@ -794,7 +817,7 @@ }, "fan": { "speed": "Velocità", - "oscillate": "Oscillante", + "oscillate": "Oscillazione", "direction": "Direzione" }, "light": { @@ -836,9 +859,9 @@ "water_heater": { "currently": "Attualmente", "on_off": "Acceso \/ Spento", - "target_temperature": "Temperatura di riferimento", + "target_temperature": "Temperatura da raggiungere", "operation": "Operazione", - "away_mode": "Modalità Assente" + "away_mode": "Modalità fuori casa" } }, "components": { diff --git a/translations/ko.json b/translations/ko.json index 05e4707f96..f0dfd5350b 100644 --- a/translations/ko.json +++ b/translations/ko.json @@ -365,7 +365,7 @@ "alias": "이름", "triggers": { "header": "트리거", - "introduction": "트리거는 자동화 규칙을 처리하는 시작점 입니다. 같은 자동화 규칙에 여러 개의 트리거를 지정할 수 있습니다. 트리거가 발동되면 Home Assistant는 조건을 확인하고 동작을 호출합니다. \n\n [트리거에 대해 자세히 알아보기](https:\/\/home-assistant.io\/docs\/automation\/trigger\/)", + "introduction": "트리거는 자동화 규칙을 처리하는 시작점 입니다. 같은 자동화 규칙에 여러 개의 트리거를 지정할 수 있습니다. 트리거가 발동되면 Home Assistant는 조건을 확인하고 동작을 호출합니다. \n\n[트리거에 대해 자세히 알아보기](https:\/\/home-assistant.io\/docs\/automation\/trigger\/)", "add": "트리거 추가", "duplicate": "복제", "delete": "삭제", @@ -428,7 +428,7 @@ }, "conditions": { "header": "조건", - "introduction": "조건은 자동화 규칙의 선택사항이며 트리거 될 때 발생하는 동작을 방지하는 데 사용할 수 있습니다. 조건은 트리거와 비슷해 보이지만 매우 다릅니다. 트리거는 시스템에서 발생하는 이벤트를 검사하고 조건은 시스템의 현재 상태를 검사합니다. 스위치를 예로 들면, 트리거는 스위치가 켜지는 것(이벤트)을, 조건은 스위치가 현재 켜져 있는지 혹은 꺼져 있는지(상태)를 검사합니다. \n\n [조건에 대해 자세히 알아보기](https:\/\/home-assistant.io\/docs\/scripts\/conditions\/)", + "introduction": "조건은 자동화 규칙의 선택사항이며 트리거 될 때 발생하는 동작을 방지하는 데 사용할 수 있습니다. 조건은 트리거와 비슷해 보이지만 매우 다릅니다. 트리거는 시스템에서 발생하는 이벤트를 검사하고 조건은 시스템의 현재 상태를 검사합니다. 스위치를 예로 들면, 트리거는 스위치가 켜지는 것(이벤트)을, 조건은 스위치가 현재 켜져 있는지 혹은 꺼져 있는지(상태)를 검사합니다. \n\n[조건에 대해 자세히 알아보기](https:\/\/home-assistant.io\/docs\/scripts\/conditions\/)", "add": "조건 추가", "duplicate": "복제", "delete": "삭제", @@ -723,7 +723,7 @@ } }, "editor": { - "edit": { + "edit_card": { "header": "카드 구성", "save": "저장하기", "toggle_editor": "에디터 전환" diff --git a/translations/lb.json b/translations/lb.json index 0e80d80684..446d93937d 100644 --- a/translations/lb.json +++ b/translations/lb.json @@ -575,30 +575,30 @@ "dropdown_label": "Thema" }, "refresh_tokens": { - "header": "Tokeny Odświeżenia", + "header": "Token erneieren", "description": "All Sessioun Token representéiert eng Login Sessioun. Sessioun's Token ginn automatesch gelëscht wann dir op auslogge klickt. Folgend Sessioun's Token si fir de Moment fir Ären Account aktiv.", - "token_title": "Token odświeżenia dla {clientId}", - "created_at": "Utworzono {date}", - "confirm_delete": "Jesteś pewien że chcesz usunąć token odświeżenia dla {name}?", - "delete_failed": "Nie udało się usunąć tokena odświeżenia.", - "last_used": "Ostatnio użyty {date} z miejsca {location}", - "not_used": "Nigdy nie został użyty", - "current_token_tooltip": "Nie można usunąć obecnego tokena odświeżenia." + "token_title": "Token erneiren fir {clientId}", + "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}", + "not_used": "Nach nie benotzt ginn", + "current_token_tooltip": "Fehler beim läschen vum aktuellen Erneierungs Token" }, "long_lived_access_tokens": { "header": "Lang gëlteg Access Token", "description": "Erstellt laang gëlteg Access Token déi et äre Skripten erlabe mat ärem Home Assistant z'interagéieren. All eenzelen Token ass gëlteg fir 10 Joer. Folgend Access Token sinn am Moment aktiv.", - "learn_auth_requests": "Naucz się robić uwierzytelnione żądania.", - "created_at": "Utworzono {date}", - "confirm_delete": "Jesteś pewien że chcesz usunąć token dostępu dla {name}?", - "delete_failed": "Nie udało się usunąć tokena dostępu.", - "create": "Utwórz Token", - "create_failed": "Nie udało się utworzyć tokena dostępu.", - "prompt_name": "Nazwa?", - "prompt_copy_token": "Zapisz swój token dostępu. Nie zostanie więcej pokazany.", - "empty_state": "Nie posiadasz jeszcze długoterminowych tokenów dostępu.", - "last_used": "Ostatnio użyty {date} z miejsca {location}", - "not_used": "Nigdy nie został użyty" + "learn_auth_requests": "Leiert wéi een \"authenticated requests\" erstellt.", + "created_at": "Erstallt um {date}", + "confirm_delete": "Sécher fir den Access Token fir {name} ze läsche?", + "delete_failed": "Fehler beim läschen vum Access Token", + "create": "Token erstellen", + "create_failed": "Fehler beim erstellen vum Access Token", + "prompt_name": "Numm?", + "prompt_copy_token": "Kopéiert den Access Token. E gëtt nie méi ugewisen.", + "empty_state": "Et ginn nach keng laang gëlteg Access Token.", + "last_used": "Fir d'Läscht benotzt um {date} vun {location}", + "not_used": "Nach nie benotzt ginn" }, "current_user": "Dir sidd aktuell ageloggt als {fullName}.", "is_owner": "Dir sidd Proprietär.", @@ -723,7 +723,7 @@ } }, "editor": { - "edit": { + "edit_card": { "header": "Kaart Konfiguratioun", "save": "Späicheren", "toggle_editor": "Editeur ëmschalten" diff --git a/translations/nl.json b/translations/nl.json index 9b06bc384f..f8c4c8c005 100644 --- a/translations/nl.json +++ b/translations/nl.json @@ -723,9 +723,10 @@ } }, "editor": { - "edit": { + "edit_card": { "header": "Kaart configuratie", - "save": "Opslaan" + "save": "Opslaan", + "toggle_editor": "Toggle Editor" }, "migrate": { "header": "Configuratie incompatibel", @@ -748,7 +749,7 @@ "day": "{count} {count, plural,\none {dag}\nother {dagen}\n}", "week": "{count} {count, plural,\none {week}\nother {weken}\n}", "second": "{count} {count, plural,\none {seconde}\nother {seconden}\n}", - "minute": "{count} {count, plural,\néén {minuut}\nandere {minuten}\n}", + "minute": "{count} {count, plural,\none {minuut}\nother {minuten}\n}", "hour": "{count} {count, plural,\none {uur}\nother {uur}\n}" }, "login-form": { diff --git a/translations/nn.json b/translations/nn.json index b67f0e4d73..7a08a4a236 100644 --- a/translations/nn.json +++ b/translations/nn.json @@ -477,7 +477,7 @@ "duplicate": "Dupliser", "delete": "Slett", "delete_confirm": "Er du sikker på at du vil slette?", - "unsupported_action": "Ikkjestøtta handling: {action}", + "unsupported_action": "Ikkje støtta handling: {action}", "type_select": "Handlingstype", "type": { "service": { diff --git a/translations/no.json b/translations/no.json index 85b03c5eda..8eafc5251a 100644 --- a/translations/no.json +++ b/translations/no.json @@ -723,7 +723,7 @@ } }, "editor": { - "edit": { + "edit_card": { "header": "Kortkonfigurasjon", "save": "Lagre", "toggle_editor": "Bytt redigering" diff --git a/translations/pl.json b/translations/pl.json index a15fd8f3fa..e61774b8c0 100644 --- a/translations/pl.json +++ b/translations/pl.json @@ -331,7 +331,7 @@ "introduction": "Niektóre części Home Assistant'a można przeładować bez konieczności ponownego uruchomienia. Kliknięcie przeładuj spowoduje ponowne wczytanie konfiguracji.", "core": "Przeładuj rdzeń", "group": "Przeładuj grupy", - "automation": "Przeładuj reguły automatyzacji", + "automation": "Przeładuj automatyzacje", "script": "Przeładuj skrypty" }, "server_management": { @@ -723,7 +723,7 @@ } }, "editor": { - "edit": { + "edit_card": { "header": "Konfiguracja karty", "save": "Zapisz", "toggle_editor": "Przełącz edytor" diff --git a/translations/pt-BR.json b/translations/pt-BR.json index 1e4e56623a..d41350931c 100644 --- a/translations/pt-BR.json +++ b/translations/pt-BR.json @@ -144,7 +144,8 @@ "performance": "Desempenho", "high_demand": "Alta demanda", "heat_pump": "Bomba de calor", - "gas": "Gás" + "gas": "Gás", + "manual": "Manual" }, "configurator": { "configure": "Configurar", @@ -580,7 +581,7 @@ "created_at": "Criado em {date}", "confirm_delete": "Tem certeza de que deseja excluir o token de acesso para {name} ?", "delete_failed": "Falha ao excluir o token de acesso.", - "last_used": "Usado pela última vez em {data} em {localização}", + "last_used": "Usado pela última vez em {date} em {location}", "not_used": "Nunca foi usado", "current_token_tooltip": "Não é possível excluir o token de atualização atual" }, @@ -596,7 +597,7 @@ "prompt_name": "Nome?", "prompt_copy_token": "Copie seu token de acesso. Ele não será mostrado novamente.", "empty_state": "Você ainda não tem tokens de acesso de longa duração.", - "last_used": "Usado pela última vez em {data} em {localização}", + "last_used": "Usado pela última vez em {date} em {location}", "not_used": "Nunca foi usado" }, "current_user": "Você está logado como {fullName} .", @@ -712,6 +713,28 @@ "required_fields": "Preencha todos os campos obrigatórios" } } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "Itens marcados", + "clear_items": "Limpar itens marcados", + "add_item": "Adicionar item" + } + }, + "editor": { + "edit_card": { + "header": "Configuração de cartão", + "save": "Salvar", + "toggle_editor": "Alternar Editor" + }, + "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" + } + } } }, "sidebar": { @@ -901,7 +924,7 @@ "climate": "Clima", "configurator": "Configurador", "conversation": "Conversação", - "cover": "Cortina", + "cover": "Cobertura", "device_tracker": "Rastreador de dispositivo", "fan": "Ventilador", "history_graph": "Gráfico de histórico", diff --git a/translations/pt.json b/translations/pt.json index af46894bb3..5a44af4799 100644 --- a/translations/pt.json +++ b/translations/pt.json @@ -723,7 +723,7 @@ } }, "editor": { - "edit": { + "edit_card": { "header": "Configuração do cartão", "save": "Guardar", "toggle_editor": "Alterar para editor" diff --git a/translations/ro.json b/translations/ro.json index 342862511d..c01020907e 100644 --- a/translations/ro.json +++ b/translations/ro.json @@ -369,7 +369,7 @@ "duplicate": "Dublura", "delete": "Ștergeți", "delete_confirm": "Sigur doriți să ștergeți?", - "unsupported_platform": "Platformă neacceptată: {platforma}", + "unsupported_platform": "Platformă neacceptată: {platform}", "type_select": "Tip acțiune", "type": { "event": { @@ -577,8 +577,8 @@ "header": "Tokenuri de innoire", "description": "Fiecare token de innoire reprezinta o sesiune de logare. Tokenuriile de innoire vor fi inlaturate cand se da click pe log out. Urmatoarele tokenuri de innoire sunt active in contul dumneavoastra.", "token_title": "înnoirea token pentru {clientId}", - "created_at": "Creat in {data}", - "confirm_delete": "Sigur doriti sa stergeti tokenul de acces pentru {nume}?", + "created_at": "Creat in {date}", + "confirm_delete": "Sigur doriti sa stergeti tokenul de acces pentru {name}?", "delete_failed": "Ştergerea tokenului de acces eşuată", "last_used": "Ultima utilizate la {data} din {locaţie}", "not_used": "Nu a fost utilizat niciodata", @@ -588,8 +588,8 @@ "header": "Tokenuri de acces de lunga durata", "description": "Creați tokenuri de acces cu durată lungă de viață pentru a permite script-urilor dvs. să interacționeze cu instanța dvs. Home Assistant. Fiecare token va fi valabil timp de 10 ani de la creatie. Următoarele tokenuri de acces de lungă durată sunt active la ora actuala.", "learn_auth_requests": "Aflați cum să faceți cereri autentificate.", - "created_at": "Creat in {data}", - "confirm_delete": "Sigur doriti sa stergeti tokenul de acces pentru {nume}?", + "created_at": "Creat in {date}", + "confirm_delete": "Sigur doriti sa stergeti tokenul de acces pentru {name}?", "delete_failed": "Ştergerea tokenului de acces eşuată", "create": "Creaza un Token", "create_failed": "Crearea tokenului de acces eşuată", @@ -726,8 +726,8 @@ "day": "{count}{count, plural,\n one { zi }\n other { zile }\n}", "week": "{count}{count, plural,\n one { săptămână }\n other { săptămâni }\n}", "second": "{count} {count, plural,\none {secunda}\nother {secunde}\n}", - "minute": "{count}{count, plural,\n un { minute }\n alte { minutes }\n}", - "hour": "{count}{count, plural,\n o { hour }\n alte { hours }\n}" + "minute": "{count} {count, plural,\n one { minute }\n other { minutes }\n}", + "hour": "{count}{count, plural,\n one { zi }\n other { zile }\n}" }, "login-form": { "password": "Parola", diff --git a/translations/ru.json b/translations/ru.json index e852c409af..55e9ed8bb1 100644 --- a/translations/ru.json +++ b/translations/ru.json @@ -36,13 +36,13 @@ "armed_custom_bypass": "Охрана с исключениями" }, "automation": { - "off": "Выключено", - "on": "Включено" + "off": "Выкл", + "on": "Вкл" }, "binary_sensor": { "default": { - "off": "Выключено", - "on": "Включено" + "off": "Выкл", + "on": "Вкл" }, "moisture": { "off": "Сухо", @@ -101,12 +101,12 @@ "on": "Охлаждение" }, "door": { - "off": "Закрыта", - "on": "Открыта" + "off": "Закрыто", + "on": "Открыто" }, "garage_door": { - "off": "Закрыта", - "on": "Открыта" + "off": "Закрыто", + "on": "Открыто" }, "heat": { "off": "Норма", @@ -122,8 +122,8 @@ } }, "calendar": { - "off": "Выключено", - "on": "Включено" + "off": "Выкл", + "on": "Вкл" }, "camera": { "recording": "Запись", @@ -131,9 +131,9 @@ "idle": "Бездействие" }, "climate": { - "off": "Выключено", - "on": "Включено", - "heat": "Обогрев", + "off": "Выкл", + "on": "Вкл", + "heat": "Нагрев", "cool": "Охлаждение", "idle": "Бездействие", "auto": "Авто", @@ -145,40 +145,40 @@ "high_demand": "Большая нагрузка", "heat_pump": "Тепловой насос", "gas": "Газовый", - "manual": "Руководство" + "manual": "Ручной режим" }, "configurator": { "configure": "Настроить", "configured": "Настроено" }, "cover": { - "open": "Открыта", + "open": "Открыто", "opening": "Открывается", - "closed": "Закрыта", + "closed": "Закрыто", "closing": "Закрывается", - "stopped": "Остановлена" + "stopped": "Остановлено" }, "device_tracker": { "home": "Дома", "not_home": "Отсутствует" }, "fan": { - "off": "Выключен", - "on": "Включен" + "off": "Выкл", + "on": "Вкл" }, "group": { - "off": "Выключено", - "on": "Включено", + "off": "Выкл", + "on": "Вкл", "home": "Дома", "not_home": "Отсутствует", "open": "Открыто", "opening": "Открывается", "closed": "Закрыто", "closing": "Закрывается", - "stopped": "Остановлена", + "stopped": "Остановлено", "locked": "Заблокирована", "unlocked": "Разблокирована", - "ok": "OK", + "ok": "ОК", "problem": "Проблема" }, "input_boolean": { @@ -213,12 +213,12 @@ "scening": "Переход к сцене" }, "script": { - "off": "Выключен", - "on": "Включен" + "off": "Выкл", + "on": "Вкл" }, "sensor": { - "off": "Выключен", - "on": "Включен" + "off": "Выкл", + "on": "Вкл" }, "sun": { "above_horizon": "Над горизонтом", @@ -237,7 +237,7 @@ }, "query_stage": { "initializing": "Инициализация ({query_stage})", - "dead": "Неисправен ({query_stage})" + "dead": "Неисправно ({query_stage})" } }, "weather": { @@ -282,7 +282,7 @@ "arming": "Постановка на охрану", "disarming": "Снятие с охраны", "triggered": "Тревога", - "armed_custom_bypass": "Под охраной" + "armed_custom_bypass": "Охрана" }, "device_tracker": { "home": "Дома", @@ -490,7 +490,7 @@ "delay": "Задержка" }, "wait_template": { - "label": "Ожидать", + "label": "Ожидание", "wait_template": "Шаблон ожидания", "timeout": "Тайм-аут (опционально)" }, @@ -542,11 +542,11 @@ "configure": "Настроить", "none": "Пока ничего не настроено", "config_entry": { - "no_devices": "Эта интеграция не имеет устройств.", + "no_devices": "Эта интеграция не имеет устройств", "no_device": "Объекты без устройств", "delete_confirm": "Вы уверены, что хотите удалить эту интеграцию?", "restart_confirm": "Перезапустите Home Assistant, чтобы завершить удаление этой интеграции", - "manuf": "от {manufacturer}", + "manuf": "Производитель: {manufacturer}", "hub": "Подключено через", "firmware": "Прошивка: {version}", "device_unavailable": "устройство недоступно", @@ -723,16 +723,16 @@ } }, "editor": { - "edit": { - "header": "Конфигурация карты", + "edit_card": { + "header": "Настройка карточки", "save": "Сохранить", "toggle_editor": "Переключить редактор" }, "migrate": { "header": "Конфигурация несовместима", "para_no_id": "Этот элемент не имеет ID. Добавьте ID для этого элемента в 'ui-lovelace.yaml'.", - "para_migrate": "Home Assistant может добавить ID для всех ваших карт и представлений автоматически, если нажать кнопку 'Миграция конфигурации'.", - "migrate": "Миграция конфигурации" + "para_migrate": "Home Assistant может автоматически добавить ID для всех карточек и видов, если нажать кнопку 'Перенести настройки'.", + "migrate": "Перенести настройки" } } } diff --git a/translations/sl.json b/translations/sl.json index 77cdf04e24..9265400143 100644 --- a/translations/sl.json +++ b/translations/sl.json @@ -36,13 +36,13 @@ "armed_custom_bypass": "Vklopljen izjeme po meri" }, "automation": { - "off": "Izklopljena", - "on": "Vklopljena" + "off": "Izključen", + "on": "Vklopljen" }, "binary_sensor": { "default": { - "off": "Izklopljeno", - "on": "Vklopljeno" + "off": "Izključen", + "on": "Vklopljen" }, "moisture": { "off": "Suho", @@ -57,12 +57,12 @@ "on": "Zaznano" }, "occupancy": { - "off": "Prosto", - "on": "Zasedeno" + "off": "Čisto", + "on": "Zaznano" }, "smoke": { "off": "Čisto", - "on": "Zaznan" + "on": "Zaznano" }, "sound": { "off": "Čisto", @@ -144,7 +144,8 @@ "performance": "Učinkovitost", "high_demand": "Visoka poraba", "heat_pump": "Toplotna črpalka", - "gas": "Plin" + "gas": "Plin", + "manual": "Ročno" }, "configurator": { "configure": "Konfiguriraj", @@ -216,16 +217,16 @@ "on": "On" }, "sensor": { - "off": "Off", - "on": "On" + "off": "Izključen", + "on": "Vklopljen" }, "sun": { "above_horizon": "Nad obzorjem", "below_horizon": "Pod obzorjem" }, "switch": { - "off": "Off", - "on": "On" + "off": "Izključen", + "on": "Vklopljen" }, "zwave": { "default": { @@ -281,7 +282,7 @@ "arming": "Vklapljam", "disarming": "Izklopi", "triggered": "Sprožen", - "armed_custom_bypass": "Vklopljen" + "armed_custom_bypass": "Aktiven" }, "device_tracker": { "home": "Doma", @@ -430,8 +431,8 @@ "introduction": "Pogoji so neobvezni del pravila za avtomatizacijo in jih je mogoče uporabiti za preprečitev, da bi se dejanje zgodilo ob sprožitvi. Pogoji so zelo podobni sprožilcem, vendar so zelo različni. Sprožilec bo pogledal dogodke, ki se dogajajo v sistemu, medtem ko pogoj gleda samo na to, kako sistem trenutno izgleda. Sprožilec lahko opazi, da je stikalo vklopljeno. Pogoj lahko vidi le, če je stikalo trenutno vklopljeno ali izklopljeno. \n\n [Več o pogojih.] (Https:\/\/home-assistant.io\/docs\/scripts\/conditions\/)", "add": "Dodaj pogoj", "duplicate": "Podvoji", - "delete": "Briši", - "delete_confirm": "Ste sigurni, da želite pobrisati?", + "delete": "Izbriši", + "delete_confirm": "Ste prepričani, da želite izbrisati?", "unsupported_condition": "Nepodprti pogoj: {condition}", "type_select": "Vrsta pogoja", "type": { @@ -443,7 +444,7 @@ "label": "Numerično stanje", "above": "Nad", "below": "Pod", - "value_template": "Vrednostna predloga" + "value_template": "Vrednostna predloga (neobvezno)" }, "sun": { "label": "Sonce", @@ -465,7 +466,7 @@ }, "zone": { "label": "Območje", - "entity": "Subjekti z lokacijo", + "entity": "Subjekt z lokacijo", "zone": "Območje" } } @@ -475,8 +476,8 @@ "introduction": "Akcije so, kaj bo storil Home Assistent, ko se sproži avtomatizacija. \n\n [Več o dejavnostih.] (Https:\/\/home-assistant.io\/docs\/automation\/action\/)", "add": "Dodaj akcijo", "duplicate": "Podvoji", - "delete": "Briši", - "delete_confirm": "Res želite pobrisati?", + "delete": "Izbriši", + "delete_confirm": "Ste prepričani, da želite izbrisati?", "unsupported_action": "Nepodprta akcija: {action}", "type_select": "Vrsta ukrepa", "type": { @@ -556,7 +557,7 @@ "profile": { "push_notifications": { "header": "Push obvestila", - "description": "Prikazuj obvestila na tej napravi", + "description": "Pošiljaj obvestila tej napravi", "error_load_platform": "Konfiguriraj notify.html5 (push obvestila).", "error_use_https": "Zahteva SSL za Frontend.", "push_notifications": "Push obvestila", @@ -712,6 +713,28 @@ "required_fields": "Izpolnite vsa zahtevana polja" } } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "Označeni predmeti", + "clear_items": "Počisti označene elemente", + "add_item": "Dodaj element" + } + }, + "editor": { + "edit_card": { + "header": "Konfiguracija kartice", + "save": "Shrani", + "toggle_editor": "Preklop na urejevalnik" + }, + "migrate": { + "header": "Konfiguracija Nezdružljiva", + "para_no_id": "Ta element nima ID-ja. Prosimo, dodajte ID tega elementa v 'ui-lovelace.yaml'.", + "para_migrate": "Home Assistant lahko doda ID-je vsem vašim karticam in pogledom samodejno s pritiskom gumba »Migriraj nastavitve«.", + "migrate": "Migriraj nastavitve" + } + } } }, "sidebar": { diff --git a/translations/sv.json b/translations/sv.json index 0ad503267c..419a226696 100644 --- a/translations/sv.json +++ b/translations/sv.json @@ -144,7 +144,8 @@ "performance": "Prestanda", "high_demand": "Hög efterfrågan", "heat_pump": "Värmepump", - "gas": "Gas" + "gas": "Gas", + "manual": "Manuell" }, "configurator": { "configure": "Konfigurera", @@ -589,7 +590,7 @@ "description": "Skapa långlivade åtkomsttokens för att låta dina skript interagera med din hemassistentenhet. Varje token kommer att vara giltig i 10 år från skapandet. Följande långlivade åtkomsttoken är för närvarande aktiva.", "learn_auth_requests": "Lär dig hur du gör autentiserade förfrågningar.", "created_at": "Skapades den {date}", - "confirm_delete": "Är du säker du vill radera åtkomsttoken för {namn}?", + "confirm_delete": "Är du säker du vill radera åtkomsttoken för {name}?", "delete_failed": "Det gick inte att ta bort åtkomsttoken.", "create": "Skapa token", "create_failed": "Det gick inte att skapa åtkomsttoken.", @@ -712,6 +713,28 @@ "required_fields": "Fyll i alla fält som krävs" } } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "Markerade objekt", + "clear_items": "Rensa avbockade objekt", + "add_item": "Lägg till objekt" + } + }, + "editor": { + "edit_card": { + "header": "Kortkonfiguration", + "save": "Spara", + "toggle_editor": "Visa \/ Dölj redigerare" + }, + "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" + } + } } }, "sidebar": { diff --git a/translations/tr.json b/translations/tr.json index 79bcdf1f22..352d618ee5 100644 --- a/translations/tr.json +++ b/translations/tr.json @@ -13,6 +13,7 @@ "dev-templates": "Taslaklar", "dev-mqtt": "MQTT", "dev-info": "Bilgi", + "calendar": "Takvim", "profile": "Profil" }, "state": { @@ -139,7 +140,8 @@ "performance": "Performans", "high_demand": "Yüksek talep", "heat_pump": "Isı pompası", - "gas": "Gaz" + "gas": "Gaz", + "manual": "Manuel" }, "configurator": { "configure": "Ayarla", @@ -233,6 +235,25 @@ "initializing": "Başlatılıyor ({query_stage})", "dead": "Ölü ({query_stage})" } + }, + "weather": { + "clear-night": "Açık, gece", + "cloudy": "Bulutlu", + "fog": "Sis", + "lightning": "Yıldırım", + "lightning-rainy": "Yıldırım, yağmurlu", + "partlycloudy": "Parçalı bulutlu", + "rainy": "Yağmurlu", + "snowy": "Karlı", + "snowy-rainy": "Karlı, yağmurlu", + "sunny": "Güneşli", + "windy": "Rüzgarlı", + "windy-variant": "Rüzgarlı" + }, + "vacuum": { + "error": "Hata", + "off": "Kapalı", + "on": "Açık" } }, "state_badge": { @@ -322,6 +343,9 @@ "header": "Otomasyon Düzenleyici" }, "editor": { + "save": "Kaydet", + "unsaved_confirm": "Kaydedilmemiş değişiklikleriniz var. Çıkmak istediğinize emin misiniz?", + "alias": "İsim", "triggers": { "delete": "Sil", "type": { @@ -330,7 +354,9 @@ }, "zone": { "zone": "Bölge", - "event": "Olay:" + "event": "Olay:", + "enter": "Girince", + "leave": "Çıkınca" }, "state": { "for": "İçin" @@ -354,27 +380,39 @@ "value_template": "Değer şablonu (isteğe bağlı)" }, "sun": { - "label": "Güneş" + "label": "Güneş", + "before": "Önce:", + "after": "Sonra:", + "sunrise": "Gün Doğumu", + "sunset": "Gün Batımı" }, "template": { "label": "Şablon", "value_template": "Değer şablonu" }, "time": { - "label": "Zaman" + "label": "Zaman", + "after": "Sonra", + "before": "Önce" }, "zone": { - "entity": "Konumlu girdi" + "label": "Bölge", + "entity": "Konumlu girdi", + "zone": "Bölge" } } }, "actions": { "duplicate": "Kopya", "delete": "Sil", + "delete_confirm": "Silmek istediğinize emin misiniz?", "type": { "delay": { "delay": "Gecikme" }, + "condition": { + "label": "Durum" + }, "event": { "event": "Olay:", "service_data": "Hizmet verisi" @@ -391,6 +429,18 @@ "caption": "Z-Wave", "description": "Z-Wave ağınızı yönetin" }, + "users": { + "caption": "Kullanıcılar", + "description": "Kullanıcıları yönet", + "picker": { + "title": "Kullanıcılar" + }, + "editor": { + "rename_user": "Kullanıcıyı yeniden adlandır", + "change_password": "Parolayı değiştir", + "delete_user": "Kullanıcıyı sil" + } + }, "cloud": { "caption": "Home Assistant Cloud", "description_login": "{email} olarak oturum açtınız", @@ -419,14 +469,22 @@ }, "profile": { "push_notifications": { - "description": "Bu cihaza bildirimler gönder" + "description": "Bu cihaza bildirimler gönder", + "link_promo": "Daha fazla bilgi edinin" }, "refresh_tokens": { - "description": "Her yenileme jetonu bir oturum açma oturumunu temsil eder. Yenileme jetonları, çıkış yapmak istediğinizde otomatik olarak kaldırılacaktır. Aşağıdaki yenileme jetonları hesabınız için şu anda aktif." + "description": "Her yenileme jetonu bir oturum açma oturumunu temsil eder. Yenileme jetonları, çıkış yapmak istediğinizde otomatik olarak kaldırılacaktır. Aşağıdaki yenileme jetonları hesabınız için şu anda aktif.", + "created_at": "{date} tarihinde oluşturuldu", + "last_used": "En son {date} tarihinde {location} konumundan kullanıldı", + "not_used": "Hiç kullanılmadı" }, "long_lived_access_tokens": { + "created_at": "{date} tarihinde oluşturuldu", + "prompt_name": "Ad?", + "last_used": "En son {date} tarihinde {location} konumundan kullanıldı", "not_used": "Hiç kullanılmamış" }, + "current_user": "{fullName} olarak giriş yaptınız.", "logout": "Çıkış yap", "change_password": { "header": "Parolayı Değiştir", @@ -449,6 +507,77 @@ "close": "Kapat", "submit": "Gönder" } + }, + "page-authorize": { + "form": { + "working": "Lütfen bekleyin", + "unknown_error": "Bir şeyler ters gitti", + "providers": { + "homeassistant": { + "step": { + "init": { + "data": { + "username": "Kullanıcı Adı", + "password": "Parola" + } + } + }, + "error": { + "invalid_auth": "Geçersiz kullanıcı adı ya da parola" + }, + "abort": { + "login_expired": "Oturum süresi doldu, lütfen tekrar giriş yapın." + } + }, + "legacy_api_password": { + "step": { + "init": { + "data": { + "password": "API Parolası" + } + } + }, + "error": { + "invalid_auth": "Geçersiz API parolası" + } + }, + "trusted_networks": { + "step": { + "init": { + "data": { + "user": "Kullanıcı" + }, + "description": "Lütfen giriş yapmak istediğiniz bir kullanıcı seçin:" + } + } + } + } + } + }, + "page-onboarding": { + "user": { + "intro": "Bir kullanıcı hesabı oluşturarak başlayalım.", + "required_field": "Gerekli", + "data": { + "name": "Ad", + "username": "Kullanıcı Adı", + "password": "Parola" + }, + "create_account": "Hesap Oluştur" + } + }, + "lovelace": { + "cards": { + "shopping-list": { + "clear_items": "Seçili ögeleri temizle", + "add_item": "Öge Ekle" + } + }, + "editor": { + "edit_card": { + "save": "Kaydet" + } + } } }, "sidebar": { @@ -476,6 +605,46 @@ "persistent_notification": { "dismiss": "Kapat" }, + "weather": { + "attributes": { + "air_pressure": "Hava basıncı", + "humidity": "Nem", + "temperature": "Sıcaklık", + "visibility": "Görünürlük", + "wind_speed": "Rüzgar hızı" + } + }, + "fan": { + "speed": "Hız", + "oscillate": "Salınım", + "direction": "Yön" + }, + "light": { + "brightness": "Parlaklık", + "effect": "Efekt" + }, + "climate": { + "on_off": "Açık \/ kapalı", + "target_temperature": "Hedef sıcaklık", + "target_humidity": "Hedef nem", + "fan_mode": "Fan modu", + "swing_mode": "Salınım modu", + "away_mode": "Dışarıda modu" + }, + "lock": { + "code": "Kod", + "lock": "Kilitle", + "unlock": "Kilidi aç" + }, + "media_player": { + "source": "Kaynak" + }, + "vacuum": { + "actions": { + "turn_on": "Aç", + "turn_off": "Kapat" + } + }, "water_heater": { "currently": "Güncel olarak", "on_off": "Açık \/ kapalı", @@ -484,8 +653,20 @@ "away_mode": "Dışarıda modu" } }, + "dialogs": { + "more_info_settings": { + "save": "Kaydet", + "name": "Ad" + } + }, "auth_store": { + "ask": "Bu girişi kaydetmek istiyor musunuz?", + "decline": "Hayır teşekkürler", "confirm": "Girişi kaydet" + }, + "notification_drawer": { + "empty": "Bildirim bulunmamakta", + "title": "Bildirimler" } }, "domain": { diff --git a/translations/uk.json b/translations/uk.json index 79879b6dae..a989d37c0b 100644 --- a/translations/uk.json +++ b/translations/uk.json @@ -73,7 +73,7 @@ "on": "Виявлено" }, "opening": { - "off": "Закритий", + "off": "Закрито", "on": "Відкритий" }, "safety": { @@ -101,11 +101,11 @@ "on": "Охолодження" }, "door": { - "off": "Зачинено", - "on": "Відкрито" + "off": "Зачинені", + "on": "Відчинені" }, "garage_door": { - "off": "Зачинено", + "off": "ЗачиненІ", "on": "Відкрито" }, "heat": { @@ -114,7 +114,7 @@ }, "window": { "off": "Зачинено", - "on": "Відкрито" + "on": "Відчинене" }, "lock": { "off": "Заблоковано", diff --git a/translations/zh-Hans.json b/translations/zh-Hans.json index 53959b9bf3..2b831f8973 100644 --- a/translations/zh-Hans.json +++ b/translations/zh-Hans.json @@ -144,7 +144,8 @@ "performance": "性能", "high_demand": "高需求", "heat_pump": "热泵", - "gas": "燃气" + "gas": "燃气", + "manual": "手动" }, "configurator": { "configure": "设置", @@ -712,6 +713,28 @@ "required_fields": "请填写所有必填字段" } } + }, + "lovelace": { + "cards": { + "shopping-list": { + "checked_items": "已完成项目", + "clear_items": "清除已完成项目", + "add_item": "新增项目" + } + }, + "editor": { + "edit_card": { + "header": "卡片配置", + "save": "保存", + "toggle_editor": "切换编辑器" + }, + "migrate": { + "header": "配置不兼容", + "para_no_id": "此元素没有 ID。请在 'ui-lovelace.yaml' 中为此元素添加 ID。", + "para_migrate": "通过点击“迁移配置”按钮,Home Assistant 可以自动为您的所有卡片和视图添加 ID。", + "migrate": "迁移配置" + } + } } }, "sidebar": { diff --git a/translations/zh-Hant.json b/translations/zh-Hant.json index dab37a0daa..8941ebf990 100644 --- a/translations/zh-Hant.json +++ b/translations/zh-Hant.json @@ -557,7 +557,7 @@ "profile": { "push_notifications": { "header": "通知推送", - "description": "傳送通知推送至此裝置", + "description": "傳送通知推送至此裝置。", "error_load_platform": "設定 notify.html5。", "error_use_https": "需要啟用前端 SSL 加密。", "push_notifications": "通知推送", @@ -723,7 +723,7 @@ } }, "editor": { - "edit": { + "edit_card": { "header": "卡片設定", "save": "儲存", "toggle_editor": "切換編輯器" From 0cd4980f44290e418468cbf242029486718a2e7c Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 5 Dec 2018 22:07:41 +0100 Subject: [PATCH 69/69] Bumped version to 20181205.0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 24233b1bb6..5c2d1ff135 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup( name="home-assistant-frontend", - version="20181126.0", + version="20181205.0", description="The Home Assistant frontend", url="https://github.com/home-assistant/home-assistant-polymer", author="The Home Assistant Authors",