Merge pull request #2802 from home-assistant/dev

20190219.0
This commit is contained in:
Paulus Schoutsen 2019-02-19 10:14:00 -08:00 committed by GitHub
commit 1f2371641e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 317 additions and 58 deletions

View File

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

View File

@ -28,6 +28,7 @@ const fixedIcons = {
light: "hass:lightbulb", light: "hass:lightbulb",
mailbox: "hass:mailbox", mailbox: "hass:mailbox",
notify: "hass:comment-alert", notify: "hass:comment-alert",
person: "hass:account",
plant: "hass:flower", plant: "hass:flower",
proximity: "hass:apple-safari", proximity: "hass:apple-safari",
remote: "hass:remote", remote: "hass:remote",

View File

@ -22,9 +22,10 @@ import { HassEntity } from "home-assistant-js-websocket";
class HaEntitiesPickerLight extends LitElement { class HaEntitiesPickerLight extends LitElement {
@property() public hass?: HomeAssistant; @property() public hass?: HomeAssistant;
@property() public value?: string[]; @property() public value?: string[];
@property() public domainFilter?: string; @property({ attribute: "domain-filter" }) public domainFilter?: string;
@property() public pickedEntityLabel?: string; @property({ attribute: "picked-entity-label" })
@property() public pickEntityLabel?: string; public pickedEntityLabel?: string;
@property({ attribute: "pick-entity-label" }) public pickEntityLabel?: string;
protected render(): TemplateResult | void { protected render(): TemplateResult | void {
if (!this.hass) { if (!this.hass) {

View File

@ -55,11 +55,12 @@ const rowRenderer = (
class HaEntityPicker extends LitElement { class HaEntityPicker extends LitElement {
@property({ type: Boolean }) public autofocus?: boolean; @property({ type: Boolean }) public autofocus?: boolean;
@property({ type: Boolean }) public disabled?: boolean; @property({ type: Boolean }) public disabled?: boolean;
@property({ type: Boolean }) public allowCustomEntity; @property({ type: Boolean, attribute: "allow-custom-entity" })
public allowCustomEntity;
@property() public hass?: HomeAssistant; @property() public hass?: HomeAssistant;
@property() public label?: string; @property() public label?: string;
@property() public value?: string; @property() public value?: string;
@property() public domainFilter?: string; @property({ attribute: "domain-filter" }) public domainFilter?: string;
@property() public entityFilter?: HaEntityPickerEntityFilterFunc; @property() public entityFilter?: HaEntityPickerEntityFilterFunc;
@property({ type: Boolean }) private _opened?: boolean; @property({ type: Boolean }) private _opened?: boolean;
@property() private _hass?: HomeAssistant; @property() private _hass?: HomeAssistant;

View File

@ -227,7 +227,7 @@ class MoreInfoClimate extends LocalizeMixin(EventsMixin(PolymerElement)) {
items="[[stateObj.attributes.fan_list]]" items="[[stateObj.attributes.fan_list]]"
on-dom-change="handleFanListUpdate" on-dom-change="handleFanListUpdate"
> >
<paper-item>[[item]]</paper-item> <paper-item>[[_localizeFanMode(localize, item)]]</paper-item>
</template> </template>
</paper-listbox> </paper-listbox>
</paper-dropdown-menu> </paper-dropdown-menu>
@ -553,6 +553,10 @@ class MoreInfoClimate extends LocalizeMixin(EventsMixin(PolymerElement)) {
_localizeOperationMode(localize, mode) { _localizeOperationMode(localize, mode) {
return localize(`state.climate.${mode}`) || mode; return localize(`state.climate.${mode}`) || mode;
} }
_localizeFanMode(localize, mode) {
return localize(`state_attributes.climate.fan_mode.${mode}`) || mode;
}
} }
customElements.define("more-info-climate", MoreInfoClimate); customElements.define("more-info-climate", MoreInfoClimate);

View File

@ -27,6 +27,8 @@ import {
showAreaRegistryDetailDialog, showAreaRegistryDetailDialog,
loadAreaRegistryDetailDialog, loadAreaRegistryDetailDialog,
} from "./show-dialog-area-registry-detail"; } from "./show-dialog-area-registry-detail";
import { classMap } from "lit-html/directives/class-map";
import { computeRTL } from "../../../common/util/compute_rtl";
class HaConfigAreaRegistry extends LitElement { class HaConfigAreaRegistry extends LitElement {
public hass?: HomeAssistant; public hass?: HomeAssistant;
@ -48,20 +50,25 @@ class HaConfigAreaRegistry extends LitElement {
`; `;
} }
return html` return html`
<hass-subpage header="Area Registry"> <hass-subpage
header="${this.hass.localize("ui.panel.config.area_registry.caption")}"
>
<ha-config-section .isWide=${this.isWide}> <ha-config-section .isWide=${this.isWide}>
<span slot="header"> <span slot="header">
${this.hass.localize("ui.panel.config.area_registry.picker.header")} ${this.hass.localize("ui.panel.config.area_registry.picker.header")}
</span> </span>
<span slot="introduction"> <span slot="introduction">
Areas are used to organize where devices are. This information will ${this.hass.localize(
be used throughout Home Assistant to help you in organizing your "ui.panel.config.area_registry.picker.introduction"
interface, permissions and integrations with other systems. )}
<p> <p>
To place devices in an area, navigate to ${this.hass.localize(
<a href="/config/integrations">the integrations page</a> and then "ui.panel.config.area_registry.picker.introduction2"
click on a configured integration to get to the device cards. )}
</p> </p>
<a href="/config/integrations"
><ha-icon icon="mdi:link"></ha-icon
></a>
</span> </span>
<paper-card> <paper-card>
${this._items.map((entry) => { ${this._items.map((entry) => {
@ -94,8 +101,13 @@ class HaConfigAreaRegistry extends LitElement {
<paper-fab <paper-fab
?is-wide=${this.isWide} ?is-wide=${this.isWide}
icon="hass:plus" icon="hass:plus"
title="Create Area" title="${this.hass.localize(
"ui.panel.config.area_registry.picker.create_area"
)}"
@click=${this._createArea} @click=${this._createArea}
class="${classMap({
rtl: computeRTL(this.hass),
})}"
></paper-fab> ></paper-fab>
`; `;
} }
@ -188,6 +200,17 @@ All devices in this area will become unassigned.`)
bottom: 24px; bottom: 24px;
right: 24px; right: 24px;
} }
paper-fab.rtl {
right: auto;
left: 16px;
}
paper-fab[is-wide].rtl {
bottom: 24px;
right: auto;
left: 24px;
}
`; `;
} }
} }

View File

@ -110,6 +110,9 @@ class HaAutomationEditor extends LitElement {
"ui.panel.config.automation.editor.save" "ui.panel.config.automation.editor.save"
)}" )}"
@click=${this._saveAutomation} @click=${this._saveAutomation}
class="${classMap({
rtl: computeRTL(this.hass),
})}"
></paper-fab> ></paper-fab>
</ha-app-layout> </ha-app-layout>
`; `;
@ -280,6 +283,17 @@ class HaAutomationEditor extends LitElement {
paper-fab[dirty] { paper-fab[dirty] {
margin-bottom: 0; margin-bottom: 0;
} }
paper-fab.rtl {
right: auto;
left: 16px;
}
paper-fab[is-wide].rtl {
bottom: 24px;
right: auto;
left: 24px;
}
`, `,
]; ];
} }

View File

@ -8,7 +8,6 @@ import "@polymer/paper-item/paper-item";
import { html } from "@polymer/polymer/lib/utils/html-tag"; import { html } from "@polymer/polymer/lib/utils/html-tag";
import { PolymerElement } from "@polymer/polymer/polymer-element"; import { PolymerElement } from "@polymer/polymer/polymer-element";
import "../../../components/ha-markdown";
import "../../../layouts/ha-app-layout"; import "../../../layouts/ha-app-layout";
import "../ha-config-section"; import "../ha-config-section";
@ -16,6 +15,8 @@ import "../ha-config-section";
import NavigateMixin from "../../../mixins/navigate-mixin"; import NavigateMixin from "../../../mixins/navigate-mixin";
import LocalizeMixin from "../../../mixins/localize-mixin"; import LocalizeMixin from "../../../mixins/localize-mixin";
import computeStateName from "../../../common/entity/compute_state_name"; import computeStateName from "../../../common/entity/compute_state_name";
import { computeRTL } from "../../../common/util/compute_rtl";
/* /*
* @appliesMixin LocalizeMixin * @appliesMixin LocalizeMixin
* @appliesMixin NavigateMixin * @appliesMixin NavigateMixin
@ -44,12 +45,19 @@ class HaAutomationPicker extends LocalizeMixin(NavigateMixin(PolymerElement)) {
right: 24px; right: 24px;
} }
a { paper-fab[rtl] {
color: var(--primary-color); right: auto;
left: 16px;
} }
ha-markdown p { paper-fab[rtl][is-wide] {
margin: 0px; bottom: 24px;
right: auto;
left: 24px;
}
a {
color: var(--primary-color);
} }
</style> </style>
@ -71,9 +79,10 @@ class HaAutomationPicker extends LocalizeMixin(NavigateMixin(PolymerElement)) {
[[localize('ui.panel.config.automation.picker.header')]] [[localize('ui.panel.config.automation.picker.header')]]
</div> </div>
<div slot="introduction"> <div slot="introduction">
<ha-markdown [[localize('ui.panel.config.automation.picker.introduction')]]
content="[[localize('ui.panel.config.automation.picker.introduction')]]" <a href="https://home-assistant.io/docs/automation/editor/"
></ha-markdown> ><ha-icon icon="mdi:link"></ha-icon
></a>
</div> </div>
<paper-card <paper-card
@ -104,6 +113,7 @@ class HaAutomationPicker extends LocalizeMixin(NavigateMixin(PolymerElement)) {
icon="hass:plus" icon="hass:plus"
title="[[localize('ui.panel.config.automation.picker.add_automation')]]" title="[[localize('ui.panel.config.automation.picker.add_automation')]]"
on-click="addAutomation" on-click="addAutomation"
rtl$="[[rtl]]"
></paper-fab> ></paper-fab>
</ha-app-layout> </ha-app-layout>
`; `;
@ -131,6 +141,12 @@ class HaAutomationPicker extends LocalizeMixin(NavigateMixin(PolymerElement)) {
isWide: { isWide: {
type: Boolean, type: Boolean,
}, },
rtl: {
type: Boolean,
reflectToAttribute: true,
computed: "_computeRTL(hass)",
},
}; };
} }
@ -158,6 +174,10 @@ class HaAutomationPicker extends LocalizeMixin(NavigateMixin(PolymerElement)) {
_backTapped() { _backTapped() {
history.back(); history.back();
} }
_computeRTL(hass) {
return computeRTL(hass);
}
} }
customElements.define("ha-automation-picker", HaAutomationPicker); customElements.define("ha-automation-picker", HaAutomationPicker);

View File

@ -51,7 +51,11 @@ class HaConfigEntityRegistry extends LitElement {
`; `;
} }
return html` return html`
<hass-subpage header="Entity Registry"> <hass-subpage
header="${this.hass.localize(
"ui.panel.config.entity_registry.caption"
)}"
>
<ha-config-section .isWide=${this.isWide}> <ha-config-section .isWide=${this.isWide}>
<span slot="header"> <span slot="header">
${this.hass.localize( ${this.hass.localize(
@ -59,14 +63,16 @@ class HaConfigEntityRegistry extends LitElement {
)} )}
</span> </span>
<span slot="introduction"> <span slot="introduction">
Home Assistant keeps a registry of every entity it has ever seen ${this.hass.localize(
that can be uniquely identified. Each of these entities will have an "ui.panel.config.entity_registry.picker.introduction"
entity ID assigned which will be reserved for just this entity. )}
<p> <p>
Use the entity registry to override the name, change the entity ID ${this.hass.localize(
or remove the entry from Home Assistant. Note, removing the entity "ui.panel.config.entity_registry.picker.introduction2"
registry entry won't remove the entity. To do that, remove it from )}
<a href="/config/integrations">the integrations page</a>. <a href="/config/integrations"
><ha-icon icon="mdi:link"></ha-icon
></a>
</p> </p>
</span> </span>
<paper-card> <paper-card>

View File

@ -3,7 +3,6 @@ import { h, Component } from "preact";
import "@polymer/paper-card/paper-card"; import "@polymer/paper-card/paper-card";
import "@polymer/paper-input/paper-input"; import "@polymer/paper-input/paper-input";
import "../ha-config-section"; import "../ha-config-section";
import "../../../components/ha-markdown";
import Trigger from "./trigger/index"; import Trigger from "./trigger/index";
import Condition from "./condition/index"; import Condition from "./condition/index";
@ -68,11 +67,14 @@ export default class Automation extends Component {
{localize("ui.panel.config.automation.editor.triggers.header")} {localize("ui.panel.config.automation.editor.triggers.header")}
</span> </span>
<span slot="introduction"> <span slot="introduction">
<ha-markdown <p>
content={localize( {localize(
"ui.panel.config.automation.editor.triggers.introduction" "ui.panel.config.automation.editor.triggers.introduction"
)} )}
/> </p>
<a href="https://home-assistant.io/docs/automation/trigger/">
<ha-icon icon="mdi:link" />
</a>
</span> </span>
<Trigger <Trigger
trigger={trigger} trigger={trigger}
@ -87,11 +89,14 @@ export default class Automation extends Component {
{localize("ui.panel.config.automation.editor.conditions.header")} {localize("ui.panel.config.automation.editor.conditions.header")}
</span> </span>
<span slot="introduction"> <span slot="introduction">
<ha-markdown <p>
content={localize( {localize(
"ui.panel.config.automation.editor.conditions.introduction" "ui.panel.config.automation.editor.conditions.introduction"
)} )}
/> </p>
<a href="https://home-assistant.io/docs/scripts/conditions/">
<ha-icon icon="mdi:link" />
</a>
</span> </span>
<Condition <Condition
condition={condition || []} condition={condition || []}
@ -106,11 +111,14 @@ export default class Automation extends Component {
{localize("ui.panel.config.automation.editor.actions.header")} {localize("ui.panel.config.automation.editor.actions.header")}
</span> </span>
<span slot="introduction"> <span slot="introduction">
<ha-markdown <p>
content={localize( {localize(
"ui.panel.config.automation.editor.actions.introduction" "ui.panel.config.automation.editor.actions.introduction"
)} )}
/> </p>
<a href="https://home-assistant.io/docs/automation/action/">
<ha-icon icon="mdi:link" />
</a>
</span> </span>
<Script <Script
script={action} script={action}

View File

@ -16,6 +16,8 @@ import computeStateName from "../../../common/entity/compute_state_name";
import NavigateMixin from "../../../mixins/navigate-mixin"; import NavigateMixin from "../../../mixins/navigate-mixin";
import LocalizeMixin from "../../../mixins/localize-mixin"; import LocalizeMixin from "../../../mixins/localize-mixin";
import { computeRTL } from "../../../common/util/compute_rtl";
function ScriptEditor(mountEl, props, mergeEl) { function ScriptEditor(mountEl, props, mergeEl) {
return render(h(Script, props), mountEl, mergeEl); return render(h(Script, props), mountEl, mergeEl);
} }
@ -81,6 +83,17 @@ class HaScriptEditor extends LocalizeMixin(NavigateMixin(PolymerElement)) {
paper-fab[dirty] { paper-fab[dirty] {
margin-bottom: 0; margin-bottom: 0;
} }
paper-fab[rtl] {
right: auto;
left: 16px;
}
paper-fab[rtl][is-wide] {
bottom: 24px;
right: auto;
left: 24px;
}
</style> </style>
<ha-app-layout has-scrolling-region=""> <ha-app-layout has-scrolling-region="">
<app-header slot="header" fixed=""> <app-header slot="header" fixed="">
@ -105,6 +118,7 @@ class HaScriptEditor extends LocalizeMixin(NavigateMixin(PolymerElement)) {
icon="hass:content-save" icon="hass:content-save"
title="Save" title="Save"
on-click="saveScript" on-click="saveScript"
rtl$="[[rtl]]"
></paper-fab> ></paper-fab>
</ha-app-layout> </ha-app-layout>
`; `;
@ -164,6 +178,12 @@ class HaScriptEditor extends LocalizeMixin(NavigateMixin(PolymerElement)) {
type: Boolean, type: Boolean,
value: false, value: false,
}, },
rtl: {
type: Boolean,
reflectToAttribute: true,
computed: "_computeRTL(hass)",
},
}; };
} }
@ -287,6 +307,10 @@ class HaScriptEditor extends LocalizeMixin(NavigateMixin(PolymerElement)) {
computeName(script) { computeName(script) {
return script && computeStateName(script); return script && computeStateName(script);
} }
_computeRTL(hass) {
return computeRTL(hass);
}
} }
customElements.define("ha-script-editor", HaScriptEditor); customElements.define("ha-script-editor", HaScriptEditor);

View File

@ -8,6 +8,8 @@ import "@polymer/paper-item/paper-item";
import { html } from "@polymer/polymer/lib/utils/html-tag"; import { html } from "@polymer/polymer/lib/utils/html-tag";
import { PolymerElement } from "@polymer/polymer/polymer-element"; import { PolymerElement } from "@polymer/polymer/polymer-element";
import { computeRTL } from "../../../common/util/compute_rtl";
import "../../../layouts/ha-app-layout"; import "../../../layouts/ha-app-layout";
import "../ha-config-section"; import "../ha-config-section";
@ -44,6 +46,17 @@ class HaScriptPicker extends LocalizeMixin(NavigateMixin(PolymerElement)) {
right: 24px; right: 24px;
} }
paper-fab[rtl] {
right: auto;
left: 16px;
}
paper-fab[rtl][is-wide] {
bottom: 24px;
right: auto;
left: 24px;
}
a { a {
color: var(--primary-color); color: var(--primary-color);
} }
@ -98,6 +111,7 @@ class HaScriptPicker extends LocalizeMixin(NavigateMixin(PolymerElement)) {
icon="hass:plus" icon="hass:plus"
title="Add Script" title="Add Script"
on-click="addScript" on-click="addScript"
rtl$="[[rtl]]"
></paper-fab> ></paper-fab>
</ha-app-layout> </ha-app-layout>
`; `;
@ -125,6 +139,12 @@ class HaScriptPicker extends LocalizeMixin(NavigateMixin(PolymerElement)) {
isWide: { isWide: {
type: Boolean, type: Boolean,
}, },
rtl: {
type: Boolean,
reflectToAttribute: true,
computed: "_computeRTL(hass)",
},
}; };
} }
@ -151,6 +171,10 @@ class HaScriptPicker extends LocalizeMixin(NavigateMixin(PolymerElement)) {
_backTapped() { _backTapped() {
history.back(); history.back();
} }
_computeRTL(hass) {
return computeRTL(hass);
}
} }
customElements.define("ha-script-picker", HaScriptPicker); customElements.define("ha-script-picker", HaScriptPicker);

View File

@ -11,6 +11,8 @@ import LocalizeMixin from "../../../mixins/localize-mixin";
import NavigateMixin from "../../../mixins/navigate-mixin"; import NavigateMixin from "../../../mixins/navigate-mixin";
import EventsMixin from "../../../mixins/events-mixin"; import EventsMixin from "../../../mixins/events-mixin";
import { computeRTL } from "../../../common/util/compute_rtl";
let registeredDialog = false; let registeredDialog = false;
/* /*
@ -34,6 +36,16 @@ class HaUserPicker extends EventsMixin(
bottom: 24px; bottom: 24px;
right: 24px; right: 24px;
} }
paper-fab[rtl] {
right: auto;
left: 16px;
}
paper-fab[rtl][is-wide] {
bottom: 24px;
right: auto;
left: 24px;
}
paper-card { paper-card {
display: block; display: block;
max-width: 600px; max-width: 600px;
@ -70,6 +82,7 @@ class HaUserPicker extends EventsMixin(
icon="hass:plus" icon="hass:plus"
title="[[localize('ui.panel.config.users.picker.add_user')]]" title="[[localize('ui.panel.config.users.picker.add_user')]]"
on-click="_addUser" on-click="_addUser"
rtl$="[[rtl]]"
></paper-fab> ></paper-fab>
</hass-subpage> </hass-subpage>
`; `;
@ -79,6 +92,12 @@ class HaUserPicker extends EventsMixin(
return { return {
hass: Object, hass: Object,
users: Array, users: Array,
rtl: {
type: Boolean,
reflectToAttribute: true,
computed: "_computeRTL(hass)",
},
}; };
} }
@ -104,6 +123,10 @@ class HaUserPicker extends EventsMixin(
return `/config/users/${user.id}`; return `/config/users/${user.id}`;
} }
_computeRTL(hass) {
return computeRTL(hass);
}
_addUser() { _addUser() {
this.fire("show-add-user", { this.fire("show-add-user", {
hass: this.hass, hass: this.hass,

View File

@ -31,14 +31,14 @@ class HaDialogAddUser extends LocalizeMixin(PolymerElement) {
opened="{{_opened}}" opened="{{_opened}}"
on-opened-changed="_openedChanged" on-opened-changed="_openedChanged"
> >
<h2>Add user</h2> <h2>[[localize('ui.panel.config.users.add_user.caption')]]</h2>
<div> <div>
<template is="dom-if" if="[[_errorMsg]]"> <template is="dom-if" if="[[_errorMsg]]">
<div class="error">[[_errorMsg]]</div> <div class="error">[[_errorMsg]]</div>
</template> </template>
<paper-input <paper-input
class="name" class="name"
label="Name" label="[[localize('ui.panel.config.users.add_user.name')]]"
value="{{_name}}" value="{{_name}}"
required required
auto-validate auto-validate
@ -48,7 +48,7 @@ class HaDialogAddUser extends LocalizeMixin(PolymerElement) {
></paper-input> ></paper-input>
<paper-input <paper-input
class="username" class="username"
label="Username" label="[[localize('ui.panel.config.users.add_user.username')]]"
value="{{_username}}" value="{{_username}}"
required required
auto-validate auto-validate
@ -56,7 +56,7 @@ class HaDialogAddUser extends LocalizeMixin(PolymerElement) {
error-message="Required" error-message="Required"
></paper-input> ></paper-input>
<paper-input <paper-input
label="Password" label="[[localize('ui.panel.config.users.add_user.password')]]"
type="password" type="password"
value="{{_password}}" value="{{_password}}"
required required
@ -71,7 +71,9 @@ class HaDialogAddUser extends LocalizeMixin(PolymerElement) {
</div> </div>
</template> </template>
<template is="dom-if" if="[[!_loading]]"> <template is="dom-if" if="[[!_loading]]">
<mwc-button on-click="_createUser">Create</mwc-button> <mwc-button on-click="_createUser"
>[[localize('ui.panel.config.users.add_user.create')]]</mwc-button
>
</template> </template>
</div> </div>
</paper-dialog> </paper-dialog>

View File

@ -35,7 +35,9 @@ class HaUserEditor extends EventsMixin(
} }
</style> </style>
<hass-subpage header="View user"> <hass-subpage
header="[[localize('ui.panel.config.users.editor.caption')]]"
>
<paper-card heading="[[_computeName(user)]]"> <paper-card heading="[[_computeName(user)]]">
<table class="card-content"> <table class="card-content">
<tr> <tr>

View File

@ -177,7 +177,7 @@ class HuiEntityButtonCard extends LitElement implements LovelaceCard {
if (!stateObj.attributes.hs_color) { if (!stateObj.attributes.hs_color) {
return ""; return "";
} }
const { hue, sat } = stateObj.attributes.hs_color; const [hue, sat] = stateObj.attributes.hs_color;
if (sat <= 10) { if (sat <= 10) {
return ""; return "";
} }

View File

@ -135,6 +135,7 @@ export class HuiLightCard extends LitElement implements LovelaceCard {
const stateObj = this.hass!.states[this._config!.entity] as LightEntity; const stateObj = this.hass!.states[this._config!.entity] as LightEntity;
if (!stateObj) { if (!stateObj) {
// Card will require refresh to work again
return; return;
} }

View File

@ -213,6 +213,7 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
private get _stepSize(): number { private get _stepSize(): number {
const stateObj = this.hass!.states[this._config!.entity]; const stateObj = this.hass!.states[this._config!.entity];
if (stateObj.attributes.target_temp_step) { if (stateObj.attributes.target_temp_step) {
return stateObj.attributes.target_temp_step; return stateObj.attributes.target_temp_step;
} }
@ -220,6 +221,13 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
} }
private async _initialLoad(): Promise<void> { private async _initialLoad(): Promise<void> {
const stateObj = this.hass!.states[this._config!.entity] as ClimateEntity;
if (!stateObj) {
// Card will require refresh to work again
return;
}
this._loaded = true; this._loaded = true;
await this.updateComplete; await this.updateComplete;
@ -233,15 +241,13 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard {
(this.shadowRoot!.querySelector( (this.shadowRoot!.querySelector(
"#thermostat" "#thermostat"
)! as HTMLElement).style.height = radius * 2 + "px"; ) as HTMLElement)!.style.height = radius * 2 + "px";
const loaded = await loadRoundslider(); const loaded = await loadRoundslider();
this._roundSliderStyle = loaded.roundSliderStyle; this._roundSliderStyle = loaded.roundSliderStyle;
this._jQuery = loaded.jQuery; this._jQuery = loaded.jQuery;
const stateObj = this.hass!.states[this._config!.entity] as ClimateEntity;
const _sliderType = const _sliderType =
stateObj.attributes.target_temp_low && stateObj.attributes.target_temp_low &&
stateObj.attributes.target_temp_high stateObj.attributes.target_temp_high

View File

@ -138,6 +138,7 @@ export class HuiEditCard extends LitElement {
<paper-dialog <paper-dialog
with-backdrop with-backdrop
opened opened
modal
@opened-changed="${this._openedChanged}" @opened-changed="${this._openedChanged}"
> >
<h2> <h2>
@ -200,6 +201,7 @@ export class HuiEditCard extends LitElement {
afterNextRender(() => { afterNextRender(() => {
this.yamlEditor.codemirror.refresh(); this.yamlEditor.codemirror.refresh();
this._resizeDialog(); this._resizeDialog();
this.yamlEditor.codemirror.focus();
}); });
} }
} }

View File

@ -38,6 +38,7 @@ class LovelaceFullConfigEditor extends LitElement {
return { return {
hass: {}, hass: {},
lovelace: {}, lovelace: {},
closeEditor: {},
_saving: {}, _saving: {},
_changed: {}, _changed: {},
}; };
@ -150,7 +151,9 @@ class LovelaceFullConfigEditor extends LitElement {
} }
} }
window.onbeforeunload = null; window.onbeforeunload = null;
this.closeEditor!(); if (this.closeEditor) {
this.closeEditor();
}
} }
private async _handleSave() { private async _handleSave() {

View File

@ -15,6 +15,7 @@ import applyThemesOnElement from "../../common/dom/apply_themes_on_element";
import { LovelaceViewConfig, LovelaceCardConfig } from "../../data/lovelace"; import { LovelaceViewConfig, LovelaceCardConfig } from "../../data/lovelace";
import { HomeAssistant } from "../../types"; import { HomeAssistant } from "../../types";
import { classMap } from "lit-html/directives/class-map";
import { Lovelace, LovelaceCard } from "./types"; import { Lovelace, LovelaceCard } from "./types";
import { createCardElement } from "./common/create-card-element"; import { createCardElement } from "./common/create-card-element";
@ -22,6 +23,8 @@ import { computeCardSize } from "./common/compute-card-size";
import { showEditCardDialog } from "./editor/card-editor/show-edit-card-dialog"; import { showEditCardDialog } from "./editor/card-editor/show-edit-card-dialog";
import { HuiErrorCard } from "./cards/hui-error-card"; import { HuiErrorCard } from "./cards/hui-error-card";
import { computeRTL } from "../../common/util/compute_rtl";
let editCodeLoaded = false; let editCodeLoaded = false;
// Find column with < 5 entities, else column with lowest count // Find column with < 5 entities, else column with lowest count
@ -99,6 +102,9 @@ export class HUIView extends LitElement {
"ui.panel.lovelace.editor.edit_card.add" "ui.panel.lovelace.editor.edit_card.add"
)}" )}"
@click="${this._addCard}" @click="${this._addCard}"
class="${classMap({
rtl: computeRTL(this.hass!),
})}"
></paper-fab> ></paper-fab>
` `
: ""} : ""}
@ -148,6 +154,12 @@ export class HUIView extends LitElement {
z-index: 1; z-index: 1;
} }
paper-fab.rtl {
float: left;
right: auto;
left: 16px;
}
@media (max-width: 500px) { @media (max-width: 500px) {
:host { :host {
padding-left: 0; padding-left: 0;

View File

@ -315,6 +315,15 @@
} }
} }
}, },
"state_attributes": {
"climate": {
"fan_mode": {
"off": "[%key:state::default::off%]",
"on": "[%key:state::default::on%]",
"auto": "[%key:state::climate::auto%]"
}
}
},
"state_badge": { "state_badge": {
"default": { "default": {
"unknown": "Unk", "unknown": "Unk",
@ -537,7 +546,9 @@
"caption": "Area Registry", "caption": "Area Registry",
"description": "Overview of all areas in your home.", "description": "Overview of all areas in your home.",
"picker": { "picker": {
"header": "Area Registry" "header": "Area Registry",
"introduction": "Areas are used to organize where devices are. This information will be used throughout Home Assistant to help you in organizing your interface, permissions and integrations with other systems.",
"introduction2": "To place devices in an area, use the link below to navigate to the integrations page and then click on a configured integration to get to the device cards."
}, },
"no_areas": "Looks like you have no areas yet!", "no_areas": "Looks like you have no areas yet!",
"create_area": "CREATE AREA", "create_area": "CREATE AREA",
@ -592,7 +603,7 @@
"description": "Create and edit automations", "description": "Create and edit automations",
"picker": { "picker": {
"header": "Automation Editor", "header": "Automation Editor",
"introduction": "The automation editor allows you to create and edit automations. Please read [the instructions](https://home-assistant.io/docs/automation/editor/) to make sure that you have configured Home Assistant correctly.", "introduction": "The automation editor allows you to create and edit automations. Please follow the link below to read the instructions to make sure that you have configured Home Assistant correctly.",
"pick_automation": "Pick automation to edit", "pick_automation": "Pick automation to edit",
"no_automations": "We couldnt find any editable automations", "no_automations": "We couldnt find any editable automations",
"add_automation": "Add automation" "add_automation": "Add automation"
@ -605,7 +616,7 @@
"alias": "Name", "alias": "Name",
"triggers": { "triggers": {
"header": "Triggers", "header": "Triggers",
"introduction": "Triggers are what starts the processing of an automation rule. It is possible to specify multiple triggers for the same rule. Once a trigger starts, Home Assistant will validate the conditions, if any, and call the action.\n\n[Learn more about triggers.](https://home-assistant.io/docs/automation/trigger/)", "introduction": "Triggers are what starts the processing of an automation rule. It is possible to specify multiple triggers for the same rule. Once a trigger starts, Home Assistant will validate the conditions, if any, and call the action. Click the link below to learn more about triggers.",
"add": "Add trigger", "add": "Add trigger",
"duplicate": "Duplicate", "duplicate": "Duplicate",
"delete": "[%key:ui::panel::mailbox::delete_button%]", "delete": "[%key:ui::panel::mailbox::delete_button%]",
@ -686,7 +697,7 @@
}, },
"conditions": { "conditions": {
"header": "Conditions", "header": "Conditions",
"introduction": "Conditions are an optional part of an automation rule and can be used to prevent an action from happening when triggered. Conditions look very similar to triggers but are very different. A trigger will look at events happening in the system while a condition only looks at how the system looks right now. A trigger can observe that a switch is being turned on. A condition can only see if a switch is currently on or off.\n\n[Learn more about conditions.](https://home-assistant.io/docs/scripts/conditions/)", "introduction": "Conditions are an optional part of an automation rule and can be used to prevent an action from happening when triggered. Conditions look very similar to triggers but are very different. A trigger will look at events happening in the system while a condition only looks at how the system looks right now. A trigger can observe that a switch is being turned on. A condition can only see if a switch is currently on or off. Click the link below to learn more about conditions.",
"add": "Add condition", "add": "Add condition",
"duplicate": "[%key:ui::panel::config::automation::editor::triggers::duplicate%]", "duplicate": "[%key:ui::panel::config::automation::editor::triggers::duplicate%]",
"delete": "[%key:ui::panel::mailbox::delete_button%]", "delete": "[%key:ui::panel::mailbox::delete_button%]",
@ -731,7 +742,7 @@
}, },
"actions": { "actions": {
"header": "Actions", "header": "Actions",
"introduction": "The actions are what Home Assistant will do when the automation is triggered.\n\n[Learn more about actions.](https://home-assistant.io/docs/automation/action/)", "introduction": "The actions are what Home Assistant will do when the automation is triggered. Click the link below to learn more about actions.",
"add": "Add action", "add": "Add action",
"duplicate": "[%key:ui::panel::config::automation::editor::triggers::duplicate%]", "duplicate": "[%key:ui::panel::config::automation::editor::triggers::duplicate%]",
"delete": "[%key:ui::panel::mailbox::delete_button%]", "delete": "[%key:ui::panel::mailbox::delete_button%]",
@ -778,6 +789,8 @@
"description": "Overview of all known entities.", "description": "Overview of all known entities.",
"picker": { "picker": {
"header": "Entity Registry", "header": "Entity Registry",
"introduction": "Home Assistant keeps a registry of every entity it has ever seen that can be uniquely identified. Each of these entities will have an entity ID assigned which will be reserved for just this entity.",
"introduction2": "Use the entity registry to override the name, change the entity ID or remove the entry from Home Assistant. Note, removing the entity registry entry won't remove the entity. To do that, follow the link below and remove it from the integrations page.",
"unavailable": "(unavailable)" "unavailable": "(unavailable)"
}, },
"editor": { "editor": {
@ -825,11 +838,19 @@
"title": "Users" "title": "Users"
}, },
"editor": { "editor": {
"caption": "View user",
"rename_user": "Rename user", "rename_user": "Rename user",
"change_password": "Change password", "change_password": "Change password",
"activate_user": "Activate user", "activate_user": "Activate user",
"deactivate_user": "Deactivate user", "deactivate_user": "Deactivate user",
"delete_user": "Delete user" "delete_user": "Delete user"
},
"add_user": {
"caption": "Add user",
"name": "Name",
"username": "Username",
"password": "Password",
"create": "Create"
} }
}, },
"zha": { "zha": {

View File

@ -265,6 +265,11 @@
"on": "Encesa", "on": "Encesa",
"paused": "Pausada", "paused": "Pausada",
"returning": "Retornant a la base" "returning": "Retornant a la base"
},
"timer": {
"active": "actiu",
"idle": "inactiu",
"paused": "en pausa"
} }
}, },
"state_badge": { "state_badge": {
@ -860,6 +865,10 @@
"unused_entities": "Entitats sense utilitzar", "unused_entities": "Entitats sense utilitzar",
"help": "Ajuda", "help": "Ajuda",
"refresh": "Actualitzar" "refresh": "Actualitzar"
},
"warning": {
"entity_not_found": "Entitat no disponible: {entity}",
"entity_non_numeric": "Entitat no numèrica: {entity}"
} }
} }
}, },

View File

@ -265,6 +265,11 @@
"on": "On", "on": "On",
"paused": "Sat på pause", "paused": "Sat på pause",
"returning": "Vender tilbage til dock" "returning": "Vender tilbage til dock"
},
"timer": {
"active": "aktiv",
"idle": "inaktiv",
"paused": "pause"
} }
}, },
"state_badge": { "state_badge": {
@ -860,6 +865,10 @@
"unused_entities": "Ubrugte enheder", "unused_entities": "Ubrugte enheder",
"help": "Hjælp", "help": "Hjælp",
"refresh": "Opdater" "refresh": "Opdater"
},
"warning": {
"entity_not_found": "Enhed ikke tilgængelig: {entity}",
"entity_non_numeric": "Enhed er ikke-numerisk: {entity}"
} }
} }
}, },

View File

@ -265,6 +265,11 @@
"on": "On", "on": "On",
"paused": "Paused", "paused": "Paused",
"returning": "Returning to dock" "returning": "Returning to dock"
},
"timer": {
"active": "active",
"idle": "idle",
"paused": "paused"
} }
}, },
"state_badge": { "state_badge": {
@ -860,6 +865,10 @@
"unused_entities": "Unused entities", "unused_entities": "Unused entities",
"help": "Help", "help": "Help",
"refresh": "Refresh" "refresh": "Refresh"
},
"warning": {
"entity_not_found": "Entity not available: {entity}",
"entity_non_numeric": "Entity is non-numeric: {entity}"
} }
} }
}, },

View File

@ -263,8 +263,13 @@
"idle": "대기중", "idle": "대기중",
"off": "꺼짐", "off": "꺼짐",
"on": "켜짐", "on": "켜짐",
"paused": "일시 중지됨", "paused": "일시중지됨",
"returning": "충전 복귀 중" "returning": "충전 복귀 중"
},
"timer": {
"active": "활성화",
"idle": "대기중",
"paused": "일시중지됨"
} }
}, },
"state_badge": { "state_badge": {
@ -860,6 +865,10 @@
"unused_entities": "미사용 구성요소", "unused_entities": "미사용 구성요소",
"help": "도움말", "help": "도움말",
"refresh": "새로고침" "refresh": "새로고침"
},
"warning": {
"entity_not_found": "구성요소를 사용할 수 없습니다: {entity}",
"entity_non_numeric": "구성요소가 숫자형식이 아닙니다: {entity}"
} }
} }
}, },

View File

@ -265,6 +265,11 @@
"on": "Un", "on": "Un",
"paused": "Pauseiert", "paused": "Pauseiert",
"returning": "Kënnt zur Statioun zeréck" "returning": "Kënnt zur Statioun zeréck"
},
"timer": {
"active": "Aktiv",
"idle": "Waart",
"paused": "Pauseiert"
} }
}, },
"state_badge": { "state_badge": {
@ -860,6 +865,10 @@
"unused_entities": "Onbenotzt Entitéiten", "unused_entities": "Onbenotzt Entitéiten",
"help": "Hëllef", "help": "Hëllef",
"refresh": "Erneieren" "refresh": "Erneieren"
},
"warning": {
"entity_not_found": "Entitéit net erreechbar: {entitiy}",
"entity_non_numeric": "Entitéit ass net numerescher Natur: {entitiy}"
} }
} }
}, },

View File

@ -265,6 +265,11 @@
"on": "Включен", "on": "Включен",
"paused": "Приостановлен", "paused": "Приостановлен",
"returning": "Возвращается к док-станции" "returning": "Возвращается к док-станции"
},
"timer": {
"active": "Отсчёт",
"idle": "Ожидание",
"paused": "Пауза"
} }
}, },
"state_badge": { "state_badge": {
@ -860,6 +865,10 @@
"unused_entities": "Неиспользуемые объекты", "unused_entities": "Неиспользуемые объекты",
"help": "Справка", "help": "Справка",
"refresh": "Обновить" "refresh": "Обновить"
},
"warning": {
"entity_not_found": "Объект недоступен: {entity}",
"entity_non_numeric": "Объект не является числом: {entity}"
} }
} }
}, },

View File

@ -265,6 +265,10 @@
"on": "开启", "on": "开启",
"paused": "已暂停", "paused": "已暂停",
"returning": "正在返回" "returning": "正在返回"
},
"timer": {
"active": "激活",
"idle": "空闲"
} }
}, },
"state_badge": { "state_badge": {
@ -854,6 +858,9 @@
"unused_entities": "未使用的实体", "unused_entities": "未使用的实体",
"help": "帮助", "help": "帮助",
"refresh": "刷新" "refresh": "刷新"
},
"warning": {
"entity_not_found": "实体不可用"
} }
} }
}, },