diff --git a/src/panels/config/customize/ha-config-customize.js b/src/panels/config/customize/ha-config-customize.js deleted file mode 100644 index d9fa1d6e43..0000000000 --- a/src/panels/config/customize/ha-config-customize.js +++ /dev/null @@ -1,111 +0,0 @@ -import { html } from "@polymer/polymer/lib/utils/html-tag"; -/* eslint-plugin-disable lit */ -import { PolymerElement } from "@polymer/polymer/polymer-element"; -import { computeStateDomain } from "../../../common/entity/compute_state_domain"; -import { computeStateName } from "../../../common/entity/compute_state_name"; -import { sortStatesByName } from "../../../common/entity/states_sort_by_name"; -import "../../../layouts/hass-tabs-subpage"; -import LocalizeMixin from "../../../mixins/localize-mixin"; -import "../../../styles/polymer-ha-style"; -import { documentationUrl } from "../../../util/documentation-url"; -import "../ha-config-section"; -import "../ha-entity-config"; -import { configSections } from "../ha-panel-config"; -import "./ha-form-customize"; - -/* - * @appliesMixin LocalizeMixin - */ -class HaConfigCustomize extends LocalizeMixin(PolymerElement) { - static get template() { - return html` - - - - - - [[localize('ui.panel.config.customize.picker.header')]] - - - [[localize('ui.panel.config.customize.picker.introduction')]] - - - [[localize("ui.panel.config.customize.picker.documentation")]] - - - - - - - - `; - } - - static get properties() { - return { - hass: Object, - isWide: Boolean, - narrow: Boolean, - route: Object, - showAdvanced: Boolean, - entities: { - type: Array, - computed: "computeEntities(hass)", - }, - - entityConfig: { - type: Object, - value: { - component: "ha-form-customize", - computeSelectCaption: (stateObj) => - computeStateName(stateObj) + - " (" + - computeStateDomain(stateObj) + - ")", - }, - }, - }; - } - - computeClasses(isWide) { - return isWide ? "content" : "content narrow"; - } - - _backTapped() { - history.back(); - } - - _computeTabs() { - return configSections.advanced; - } - - computeEntities(hass) { - return Object.keys(hass.states) - .map((key) => hass.states[key]) - .sort(sortStatesByName); - } - - _computeDocumentationUrl(hass) { - return documentationUrl( - hass, - "/docs/configuration/customizing-devices/#customization-using-the-ui" - ); - } -} -customElements.define("ha-config-customize", HaConfigCustomize); diff --git a/src/panels/config/customize/ha-config-customize.ts b/src/panels/config/customize/ha-config-customize.ts new file mode 100644 index 0000000000..c1802cc6aa --- /dev/null +++ b/src/panels/config/customize/ha-config-customize.ts @@ -0,0 +1,91 @@ +import { + css, + CSSResult, + html, + LitElement, + property, + TemplateResult, +} from "lit-element"; +import "../../../components/ha-card"; +import "../../../layouts/hass-loading-screen"; +import "../../../layouts/hass-tabs-subpage"; +import { HomeAssistant, Route } from "../../../types"; +import { documentationUrl } from "../../../util/documentation-url"; +import "../ha-config-section"; +import "../ha-entity-config"; +import { configSections } from "../ha-panel-config"; +import "./ha-form-customize"; + +class HaConfigCustomize extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property() public isWide?: boolean; + + @property() public narrow?: boolean; + + @property() public route!: Route; + + @property() private _selectedEntityId = ""; + + protected render(): TemplateResult { + return html` + + + + + ${this.hass.localize("ui.panel.config.customize.picker.header")} + + + ${this.hass.localize( + "ui.panel.config.customize.picker.introduction" + )} + + + ${this.hass.localize( + "ui.panel.config.customize.picker.documentation" + )} + + + + + + + + `; + } + + protected firstUpdated(changedProps) { + super.firstUpdated(changedProps); + + if (!this.route.path.includes("/edit/")) { + return; + } + const routeSegments = this.route.path.split("/edit/"); + this._selectedEntityId = routeSegments.length > 1 ? routeSegments[1] : ""; + } + + static get styles(): CSSResult { + return css` + a { + color: var(--primary-color); + } + `; + } +} +customElements.define("ha-config-customize", HaConfigCustomize); diff --git a/src/panels/config/customize/ha-form-customize.js b/src/panels/config/customize/ha-form-customize.js index 4df81153df..5e22d6b5d9 100644 --- a/src/panels/config/customize/ha-form-customize.js +++ b/src/panels/config/customize/ha-form-customize.js @@ -12,7 +12,7 @@ import hassAttributeUtil from "../../../util/hass-attributes-util"; import "../ha-form-style"; import "./ha-form-customize-attributes"; -class HaFormCustomize extends LocalizeMixin(PolymerElement) { +export class HaFormCustomize extends LocalizeMixin(PolymerElement) { static get template() { return html` - - - - - - - [[computeSelectCaption(state)]] - - - - - - - - - - No entities found! :-( - - - - - [[formState]] - - - - - - - - - SAVE - - DELETE - - - - `; - } - - static get properties() { - return { - hass: { - type: Object, - observer: "hassChanged", - }, - - label: { - type: String, - value: "Device", - }, - - entities: { - type: Array, - observer: "entitiesChanged", - }, - - allowDelete: { - type: Boolean, - value: false, - }, - - selectedEntity: { - type: Number, - value: -1, - observer: "entityChanged", - }, - - formState: { - type: String, - // no-devices, loading, saving, editing - value: "no-devices", - }, - - config: { - type: Object, - }, - }; - } - - connectedCallback() { - super.connectedCallback(); - this.formEl = document.createElement(this.config.component); - this.formEl.hass = this.hass; - this.$.form.appendChild(this.formEl); - this.entityChanged(this.selectedEntity); - } - - computeSelectCaption(stateObj) { - return this.config.computeSelectCaption - ? this.config.computeSelectCaption(stateObj) - : computeStateName(stateObj); - } - - computeShowNoDevices(formState) { - return formState === "no-devices"; - } - - computeShowSpinner(formState) { - return formState === "loading" || formState === "saving"; - } - - computeShowPlaceholder(formState) { - return formState !== "editing"; - } - - computeShowForm(formState) { - return formState === "editing"; - } - - hassChanged(hass) { - if (this.formEl) { - this.formEl.hass = hass; - } - } - - entitiesChanged(entities, oldEntities) { - if (entities.length === 0) { - this.formState = "no-devices"; - return; - } - if (!oldEntities) { - this.selectedEntity = 0; - return; - } - - const oldEntityId = oldEntities[this.selectedEntity].entity_id; - - const newIndex = entities.findIndex(function (ent) { - return ent.entity_id === oldEntityId; - }); - - if (newIndex === -1) { - this.selectedEntity = 0; - } else if (newIndex !== this.selectedEntity) { - // Entity moved index - this.selectedEntity = newIndex; - } - } - - entityChanged(index) { - if (!this.entities || !this.formEl) return; - const entity = this.entities[index]; - if (!entity) return; - - this.formState = "loading"; - // eslint-disable-next-line @typescript-eslint/no-this-alias - const el = this; - this.formEl.loadEntity(entity).then(function () { - el.formState = "editing"; - }); - } - - saveEntity() { - this.formState = "saving"; - // eslint-disable-next-line @typescript-eslint/no-this-alias - const el = this; - this.formEl.saveEntity().then(function () { - el.formState = "editing"; - }); - } -} - -customElements.define("ha-entity-config", HaEntityConfig); diff --git a/src/panels/config/ha-entity-config.ts b/src/panels/config/ha-entity-config.ts new file mode 100644 index 0000000000..9fb1d804dd --- /dev/null +++ b/src/panels/config/ha-entity-config.ts @@ -0,0 +1,124 @@ +import "@material/mwc-button"; +import { + css, + CSSResult, + customElement, + html, + LitElement, + property, + PropertyValues, + query, + TemplateResult, +} from "lit-element"; +import "../../components/buttons/ha-progress-button"; +import "../../components/entity/ha-entity-picker"; +import "../../components/ha-card"; +import "../../components/ha-circular-progress"; +import { haStyle } from "../../resources/styles"; +import "../../styles/polymer-ha-style"; +import type { HomeAssistant } from "../../types"; +import { HaFormCustomize } from "./customize/ha-form-customize"; + +@customElement("ha-entity-config") +export class HaEntityConfig extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property() public selectedEntityId!: string; + + // False if no entity is selected or currently saving or loading + @property() private _formEditState = false; + + @query("#form") private _form!: HaFormCustomize; + + protected render(): TemplateResult { + return html` + + + + + + + + + + + + + ${this.hass.localize("ui.common.save")} + + + + `; + } + + protected updated(changedProps: PropertyValues) { + super.updated(changedProps); + if ( + changedProps.has("selectedEntityId") && + changedProps.get("selectedEntityId") !== this.selectedEntityId + ) { + this._selectEntity(this.selectedEntityId); + this.requestUpdate(); + } + } + + private _selectedEntityChanged(ev) { + this._selectEntity(ev.target.value); + } + + private async _selectEntity(entityId?: string) { + if (!this._form || !entityId) return; + const entity = this.hass.states[entityId]; + if (!entity) return; + + this._formEditState = false; + await this._form.loadEntity(entity); + this._formEditState = true; + } + + private async _saveEntity(ev) { + if (!this._formEditState) return; + this._formEditState = false; + const button = ev.target; + button.progress = true; + + try { + await this._form.saveEntity(); + this._formEditState = true; + button.actionSuccess(); + } catch { + button.actionError(); + } finally { + button.progress = false; + } + } + + static get styles(): CSSResult[] { + return [ + haStyle, + css` + ha-card { + direction: ltr; + } + + .form-placeholder { + height: 96px; + } + + .hidden { + display: none; + } + `, + ]; + } +} diff --git a/src/translations/en.json b/src/translations/en.json index 3d61e25995..c54528db73 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1108,8 +1108,7 @@ "picker": { "header": "Customizations", "introduction": "Tweak per-entity attributes. Added/edited customizations will take effect immediately. Removed customizations will take effect when the entity is updated.", - "documentation": "Customization documentation", - "entity": "Entity" + "documentation": "Customization documentation" }, "warning": { "include_sentence": "It seems that your configuration.yaml doesn't properly",