diff --git a/hassio/src/addon-view/config/hassio-addon-network.ts b/hassio/src/addon-view/config/hassio-addon-network.ts
index d90a68ffd3..99f871be99 100644
--- a/hassio/src/addon-view/config/hassio-addon-network.ts
+++ b/hassio/src/addon-view/config/hassio-addon-network.ts
@@ -88,8 +88,8 @@ class HassioAddonNetwork extends LitElement {
- Reset to defaults >
+ Reset to defaults
+
Save
diff --git a/hassio/src/dashboard/hassio-update.ts b/hassio/src/dashboard/hassio-update.ts
index 3bb15444ed..9bb6cc73ec 100644
--- a/hassio/src/dashboard/hassio-update.ts
+++ b/hassio/src/dashboard/hassio-update.ts
@@ -164,8 +164,9 @@ export class HassioUpdate extends LitElement {
try {
await this.hass.callApi
>("POST", item.apiPath);
} catch (err) {
- // Only show an error if the status code was not 504, or no status at all (connection terminated)
- if (err.status_code && err.status_code !== 504) {
+ // Only show an error if the status code was not expected (user behind proxy)
+ // or no status at all(connection terminated)
+ if (err.status_code && ![502, 503, 504].includes(err.status_code)) {
showAlertDialog(this, {
title: "Update failed",
text: extractApiErrorMessage(err),
diff --git a/hassio/src/system/hassio-supervisor-info.ts b/hassio/src/system/hassio-supervisor-info.ts
index fd043751de..12af46d091 100644
--- a/hassio/src/system/hassio-supervisor-info.ts
+++ b/hassio/src/system/hassio-supervisor-info.ts
@@ -18,6 +18,7 @@ import {
setSupervisorOption,
SupervisorOptions,
updateSupervisor,
+ fetchHassioSupervisorInfo,
} from "../../../src/data/hassio/supervisor";
import {
showAlertDialog,
@@ -176,10 +177,11 @@ class HassioSupervisorInfo extends LitElement {
try {
const data: Partial = {
- channel: this.supervisorInfo.channel !== "stable" ? "beta" : "stable",
+ channel: this.supervisorInfo.channel === "stable" ? "beta" : "stable",
};
await setSupervisorOption(this.hass, data);
await reloadSupervisor(this.hass);
+ this.supervisorInfo = await fetchHassioSupervisorInfo(this.hass);
} catch (err) {
showAlertDialog(this, {
title: "Failed to set supervisor option",
@@ -195,6 +197,7 @@ class HassioSupervisorInfo extends LitElement {
try {
await reloadSupervisor(this.hass);
+ this.supervisorInfo = await fetchHassioSupervisorInfo(this.hass);
} catch (err) {
showAlertDialog(this, {
title: "Failed to reload the supervisor",
diff --git a/package.json b/package.json
index 1410d6bf3b..1db467294c 100644
--- a/package.json
+++ b/package.json
@@ -79,6 +79,7 @@
"@polymer/polymer": "3.1.0",
"@thomasloven/round-slider": "0.5.0",
"@types/chromecast-caf-sender": "^1.0.3",
+ "@types/sortablejs": "^1.10.6",
"@vaadin/vaadin-combo-box": "^5.0.10",
"@vaadin/vaadin-date-picker": "^4.0.7",
"@vue/web-component-wrapper": "^1.2.0",
diff --git a/setup.py b/setup.py
index 4c386522cb..b1a1ef7a73 100644
--- a/setup.py
+++ b/setup.py
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
setup(
name="home-assistant-frontend",
- version="20200904.0",
+ version="20200907.0",
description="The Home Assistant frontend",
url="https://github.com/home-assistant/home-assistant-polymer",
author="The Home Assistant Authors",
diff --git a/src/components/entity/ha-entity-attribute-picker.ts b/src/components/entity/ha-entity-attribute-picker.ts
new file mode 100644
index 0000000000..ee2958323b
--- /dev/null
+++ b/src/components/entity/ha-entity-attribute-picker.ts
@@ -0,0 +1,178 @@
+import "@polymer/paper-input/paper-input";
+import "@polymer/paper-item/paper-item";
+import "@vaadin/vaadin-combo-box/theme/material/vaadin-combo-box-light";
+import { HassEntity } from "home-assistant-js-websocket";
+import {
+ css,
+ CSSResult,
+ customElement,
+ html,
+ LitElement,
+ property,
+ PropertyValues,
+ query,
+ TemplateResult,
+} from "lit-element";
+import { fireEvent } from "../../common/dom/fire_event";
+import { PolymerChangedEvent } from "../../polymer-types";
+import { HomeAssistant } from "../../types";
+import "../ha-icon-button";
+import "./state-badge";
+
+export type HaEntityPickerEntityFilterFunc = (entityId: HassEntity) => boolean;
+
+const rowRenderer = (root: HTMLElement, _owner, model: { item: string }) => {
+ if (!root.firstElementChild) {
+ root.innerHTML = `
+
+
+ `;
+ }
+ root.querySelector("paper-item")!.textContent = model.item;
+};
+
+@customElement("ha-entity-attribute-picker")
+class HaEntityAttributePicker extends LitElement {
+ @property({ attribute: false }) public hass!: HomeAssistant;
+
+ @property() public entityId?: string;
+
+ @property({ type: Boolean }) public autofocus = false;
+
+ @property({ type: Boolean }) public disabled = false;
+
+ @property({ type: Boolean, attribute: "allow-custom-value" })
+ public allowCustomValue;
+
+ @property() public label?: string;
+
+ @property() public value?: string;
+
+ @property({ type: Boolean }) private _opened = false;
+
+ @query("vaadin-combo-box-light") private _comboBox!: HTMLElement;
+
+ protected shouldUpdate(changedProps: PropertyValues) {
+ return !(!changedProps.has("_opened") && this._opened);
+ }
+
+ protected updated(changedProps: PropertyValues) {
+ if (changedProps.has("_opened") && this._opened) {
+ const state = this.entityId ? this.hass.states[this.entityId] : undefined;
+ (this._comboBox as any).items = state
+ ? Object.keys(state.attributes)
+ : [];
+ }
+ }
+
+ protected render(): TemplateResult {
+ if (!this.hass) {
+ return html``;
+ }
+
+ return html`
+
+
+ ${this.value
+ ? html`
+
+ Clear
+
+ `
+ : ""}
+
+
+ Toggle
+
+
+
+ `;
+ }
+
+ private _clearValue(ev: Event) {
+ ev.stopPropagation();
+ this._setValue("");
+ }
+
+ private get _value() {
+ return this.value || "";
+ }
+
+ private _openedChanged(ev: PolymerChangedEvent) {
+ this._opened = ev.detail.value;
+ }
+
+ private _valueChanged(ev: PolymerChangedEvent) {
+ const newValue = ev.detail.value;
+ if (newValue !== this._value) {
+ this._setValue(newValue);
+ }
+ }
+
+ private _setValue(value: string) {
+ this.value = value;
+ setTimeout(() => {
+ fireEvent(this, "value-changed", { value });
+ fireEvent(this, "change");
+ }, 0);
+ }
+
+ static get styles(): CSSResult {
+ return css`
+ paper-input > ha-icon-button {
+ --mdc-icon-button-size: 24px;
+ padding: 0px 2px;
+ color: var(--secondary-text-color);
+ }
+ [hidden] {
+ display: none;
+ }
+ `;
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "ha-entity-attribute-picker": HaEntityAttributePicker;
+ }
+}
diff --git a/src/components/entity/ha-entity-picker.ts b/src/components/entity/ha-entity-picker.ts
index 300ae57a79..51ddf0d30f 100644
--- a/src/components/entity/ha-entity-picker.ts
+++ b/src/components/entity/ha-entity-picker.ts
@@ -1,4 +1,3 @@
-import "../ha-icon-button";
import "@polymer/paper-input/paper-input";
import "@polymer/paper-item/paper-icon-item";
import "@polymer/paper-item/paper-item-body";
@@ -20,6 +19,7 @@ import { computeDomain } from "../../common/entity/compute_domain";
import { computeStateName } from "../../common/entity/compute_state_name";
import { PolymerChangedEvent } from "../../polymer-types";
import { HomeAssistant } from "../../types";
+import "../ha-icon-button";
import "./state-badge";
export type HaEntityPickerEntityFilterFunc = (entityId: HassEntity) => boolean;
@@ -95,6 +95,8 @@ class HaEntityPicker extends LitElement {
@query("vaadin-combo-box-light") private _comboBox!: HTMLElement;
+ private _initedStates = false;
+
private _getStates = memoizeOne(
(
_opened: boolean,
@@ -148,11 +150,18 @@ class HaEntityPicker extends LitElement {
);
protected shouldUpdate(changedProps: PropertyValues) {
+ if (
+ changedProps.has("value") ||
+ changedProps.has("label") ||
+ changedProps.has("disabled")
+ ) {
+ return true;
+ }
return !(!changedProps.has("_opened") && this._opened);
}
protected updated(changedProps: PropertyValues) {
- if (changedProps.has("_opened") && this._opened) {
+ if (!this._initedStates || (changedProps.has("_opened") && this._opened)) {
const states = this._getStates(
this._opened,
this.hass,
@@ -162,6 +171,7 @@ class HaEntityPicker extends LitElement {
this.includeDeviceClasses
);
(this._comboBox as any).items = states;
+ this._initedStates = true;
}
}
@@ -169,7 +179,6 @@ class HaEntityPicker extends LitElement {
if (!this.hass) {
return html``;
}
-
return html`
- #sortable a:nth-of-type(2n) paper-icon-item {
- animation-name: keyframes1;
- animation-iteration-count: infinite;
- transform-origin: 50% 10%;
- animation-delay: -0.75s;
- animation-duration: 0.25s;
- }
-
- #sortable a:nth-of-type(2n-1) paper-icon-item {
- animation-name: keyframes2;
- animation-iteration-count: infinite;
- animation-direction: alternate;
- transform-origin: 30% 5%;
- animation-delay: -0.5s;
- animation-duration: 0.33s;
- }
-
- #sortable {
- outline: none;
- display: flex;
- flex-direction: column;
- }
-
- .sortable-ghost {
- opacity: 0.4;
- }
-
- .sortable-fallback {
- opacity: 0;
- }
-
- @keyframes keyframes1 {
- 0% {
- transform: rotate(-1deg);
- animation-timing-function: ease-in;
- }
-
- 50% {
- transform: rotate(1.5deg);
- animation-timing-function: ease-out;
- }
- }
-
- @keyframes keyframes2 {
- 0% {
- transform: rotate(1deg);
- animation-timing-function: ease-in;
- }
-
- 50% {
- transform: rotate(-1.5deg);
- animation-timing-function: ease-out;
- }
- }
-
- .hide-panel {
- display: none;
- position: absolute;
- right: 8px;
- }
-
- :host([expanded]) .hide-panel {
- display: inline-flex;
- }
-
- paper-icon-item.hidden-panel,
- paper-icon-item.hidden-panel span,
- paper-icon-item.hidden-panel ha-icon[slot="item-icon"] {
- color: var(--secondary-text-color);
- cursor: pointer;
- }
-
-`;
diff --git a/src/components/ha-sidebar.ts b/src/components/ha-sidebar.ts
index 12b1c17d39..1226fffbc4 100644
--- a/src/components/ha-sidebar.ts
+++ b/src/components/ha-sidebar.ts
@@ -23,7 +23,6 @@ import {
LitElement,
property,
PropertyValues,
- TemplateResult,
} from "lit-element";
import { classMap } from "lit-html/directives/class-map";
import { guard } from "lit-html/directives/guard";
@@ -31,6 +30,7 @@ import memoizeOne from "memoize-one";
import { LocalStorage } from "../common/decorators/local-storage";
import { fireEvent } from "../common/dom/fire_event";
import { computeDomain } from "../common/entity/compute_domain";
+import { navigate } from "../common/navigate";
import { compare } from "../common/string/compare";
import { computeRTL } from "../common/util/compute_rtl";
import { ActionHandlerDetail } from "../data/lovelace";
@@ -160,7 +160,7 @@ const computePanels = memoizeOne(
let Sortable;
-let sortStyles: TemplateResult;
+let sortStyles: CSSResult;
@customElement("ha-sidebar")
class HaSidebar extends LitElement {
@@ -228,7 +228,13 @@ class HaSidebar extends LitElement {
}
return html`
- ${this._editMode ? sortStyles : ""}
+ ${this._editMode
+ ? html`
+
+ `
+ : ""}