From 15a2790b9f0f744775bb41013d992e8e88a12fa8 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Mon, 23 Dec 2019 10:39:17 +0100 Subject: [PATCH] Add support to add all device entities to Lovelace (#4356) * Add support to add all device entities to Lovelace * Reload config when it was changed while Lovelace was not active * Localize * Update ha-panel-lovelace.ts * Move to device entities card * Move Lovelace logic to lovelace combine with unused entities * Unused imports * Added suggestions and support for YAML mode --- src/components/ha-yaml-editor.ts | 20 +- .../device-detail/ha-device-entities-card.ts | 100 ++++---- .../config/devices/ha-config-device-page.ts | 4 +- .../common/generate-lovelace-config.ts | 9 +- .../lovelace/components/hui-card-options.ts | 3 +- .../lovelace/editor/add-entities-to-view.ts | 60 +++++ .../card-editor/hui-dialog-edit-card.ts | 13 +- .../card-editor/hui-dialog-suggest-card.ts | 215 ++++++++++++++++++ .../card-editor/show-edit-card-dialog.ts | 39 +--- .../card-editor/show-suggest-card-dialog.ts | 26 +++ src/panels/lovelace/editor/config-util.ts | 30 +++ .../select-view/hui-dialog-select-view.ts | 6 +- .../select-view/show-select-view-dialog.ts | 4 +- .../unused-entities/hui-unused-entities.ts | 51 ++--- src/panels/lovelace/ha-panel-lovelace.ts | 12 +- src/panels/lovelace/views/hui-view.ts | 3 +- src/translations/en.json | 17 +- 17 files changed, 491 insertions(+), 121 deletions(-) create mode 100644 src/panels/lovelace/editor/add-entities-to-view.ts create mode 100755 src/panels/lovelace/editor/card-editor/hui-dialog-suggest-card.ts create mode 100644 src/panels/lovelace/editor/card-editor/show-suggest-card-dialog.ts diff --git a/src/components/ha-yaml-editor.ts b/src/components/ha-yaml-editor.ts index dc3a0cb08e..d6b808177e 100644 --- a/src/components/ha-yaml-editor.ts +++ b/src/components/ha-yaml-editor.ts @@ -1,7 +1,10 @@ import { safeDump, safeLoad } from "js-yaml"; import "./ha-code-editor"; -import { LitElement, property, customElement, html } from "lit-element"; +import { LitElement, property, customElement, html, query } from "lit-element"; import { fireEvent } from "../common/dom/fire_event"; +import { afterNextRender } from "../common/util/render-status"; +// tslint:disable-next-line +import { HaCodeEditor } from "./ha-code-editor"; const isEmpty = (obj: object) => { for (const key in obj) { @@ -18,14 +21,23 @@ export class HaYamlEditor extends LitElement { @property() public isValid = true; @property() public label?: string; @property() private _yaml?: string; + @query("ha-code-editor") private _editor?: HaCodeEditor; - protected firstUpdated() { + public setValue(value) { try { - this._yaml = - this.value && !isEmpty(this.value) ? safeDump(this.value) : ""; + this._yaml = value && !isEmpty(value) ? safeDump(value) : ""; } catch (err) { alert(`There was an error converting to YAML: ${err}`); } + afterNextRender(() => { + if (this._editor?.codemirror) { + this._editor.codemirror.refresh(); + } + }); + } + + protected firstUpdated() { + this.setValue(this.value); } protected render() { diff --git a/src/panels/config/devices/device-detail/ha-device-entities-card.ts b/src/panels/config/devices/device-detail/ha-device-entities-card.ts index 3b19563b86..abc7d88753 100644 --- a/src/panels/config/devices/device-detail/ha-device-entities-card.ts +++ b/src/panels/config/devices/device-detail/ha-device-entities-card.ts @@ -27,6 +27,7 @@ import { domainIcon } from "../../../../common/entity/domain_icon"; // tslint:disable-next-line import { HaSwitch } from "../../../../components/ha-switch"; import { EntityRegistryStateEntry } from "../ha-config-device-page"; +import { addEntitiesToLovelaceView } from "../../../lovelace/editor/add-entities-to-view"; @customElement("ha-device-entities-card") export class HaDeviceEntitiesCard extends LitElement { @@ -49,51 +50,60 @@ export class HaDeviceEntitiesCard extends LitElement { ${this.entities.length - ? this.entities.map((entry: EntityRegistryStateEntry) => { - if (!this._showDisabled && entry.disabled_by) { - return ""; - } - const stateObj = this.hass.states[entry.entity_id]; - return html` - - ${stateObj - ? html` - - ` - : html` - - `} - -
${entry.stateName}
-
${entry.entity_id}
-
-
+ ? html` + ${this.entities.map((entry: EntityRegistryStateEntry) => { + if (!this._showDisabled && entry.disabled_by) { + return ""; + } + const stateObj = this.hass.states[entry.entity_id]; + return html` + ${stateObj ? html` - + .stateObj=${stateObj} + slot="item-icon" + > ` - : ""} - -
-
- `; - }) + : html` + + `} + +
${entry.stateName}
+
${entry.entity_id}
+
+
+ ${stateObj + ? html` + + ` + : ""} + +
+ + `; + })} +
+ + ${this.hass.localize( + "ui.panel.config.devices.entities.add_entities_lovelace" + )} + +
+ ` : html`
@@ -125,6 +135,14 @@ export class HaDeviceEntitiesCard extends LitElement { fireEvent(this, "hass-more-info", { entityId: entry.entity_id }); } + private _addToLovelaceView(): void { + addEntitiesToLovelaceView( + this, + this.hass, + this.entities.map((entity) => entity.entity_id) + ); + } + static get styles(): CSSResult { return css` ha-icon { diff --git a/src/panels/config/devices/ha-config-device-page.ts b/src/panels/config/devices/ha-config-device-page.ts index 70ba49d703..2bc8d4fb0d 100644 --- a/src/panels/config/devices/ha-config-device-page.ts +++ b/src/panels/config/devices/ha-config-device-page.ts @@ -156,7 +156,9 @@ export class HaConfigDevicePage extends LitElement { ${entities.length ? html`
- ${this.hass.localize("ui.panel.config.devices.entities")} + ${this.hass.localize( + "ui.panel.config.devices.entities.entities" + )}
, +export const computeCards = ( + states: Array<[string, HassEntity?]>, entityCardOptions: Partial ): LovelaceCardConfig[] => { const cards: LovelaceCardConfig[] = []; @@ -132,6 +132,11 @@ const computeCards = ( title: stateObj.attributes.friendly_name, refresh_interval: stateObj.attributes.refresh, }); + } else if (domain === "light") { + cards.push({ + type: "light", + entity: entityId, + }); } else if (domain === "media_player") { cards.push({ type: "media-control", diff --git a/src/panels/lovelace/components/hui-card-options.ts b/src/panels/lovelace/components/hui-card-options.ts index 7689c66aee..cdcc59d197 100644 --- a/src/panels/lovelace/components/hui-card-options.ts +++ b/src/panels/lovelace/components/hui-card-options.ts @@ -142,7 +142,8 @@ export class HuiCardOptions extends LitElement { private _editCard(): void { showEditCardDialog(this, { - lovelace: this.lovelace!, + lovelaceConfig: this.lovelace!.config, + saveConfig: this.lovelace!.saveConfig, path: this.path!, }); } diff --git a/src/panels/lovelace/editor/add-entities-to-view.ts b/src/panels/lovelace/editor/add-entities-to-view.ts new file mode 100644 index 0000000000..6bbc9c59ae --- /dev/null +++ b/src/panels/lovelace/editor/add-entities-to-view.ts @@ -0,0 +1,60 @@ +import { HomeAssistant } from "../../../types"; +import { + LovelaceConfig, + fetchConfig, + saveConfig, +} from "../../../data/lovelace"; +import { showSelectViewDialog } from "./select-view/show-select-view-dialog"; +import { showSuggestCardDialog } from "./card-editor/show-suggest-card-dialog"; + +export const addEntitiesToLovelaceView = async ( + element: HTMLElement, + hass: HomeAssistant, + entities: string[], + lovelaceConfig?: LovelaceConfig, + saveConfigFunc?: (newConfig: LovelaceConfig) => void +) => { + if ((hass!.panels.lovelace?.config as any)?.mode === "yaml") { + showSuggestCardDialog(element, { + entities, + }); + return; + } + if (!lovelaceConfig) { + try { + lovelaceConfig = await fetchConfig(hass.connection, false); + } catch { + alert( + hass.localize( + "ui.panel.lovelace.editor.add_entities.generated_unsupported" + ) + ); + return; + } + } + showSelectViewDialog(element, { + lovelaceConfig, + viewSelectedCallback: (view) => { + if (!saveConfigFunc) { + saveConfigFunc = async (newConfig: LovelaceConfig): Promise => { + try { + await saveConfig(hass!, newConfig); + } catch { + alert( + hass.localize( + "ui.panel.config.devices.add_entities.saving_failed" + ) + ); + } + }; + } + + showSuggestCardDialog(element, { + lovelaceConfig: lovelaceConfig!, + saveConfig: saveConfigFunc, + path: [view], + entities, + }); + }, + }); +}; diff --git a/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts b/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts index 525b703c6c..e75a279163 100755 --- a/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts +++ b/src/panels/lovelace/editor/card-editor/hui-dialog-edit-card.ts @@ -24,6 +24,7 @@ import { addCard, replaceCard } from "../config-util"; import "../../../../components/dialog/ha-paper-dialog"; import { haStyleDialog } from "../../../../resources/styles"; +import { showSaveSuccessToast } from "../../../../util/toast-saved-success"; declare global { // for fire event @@ -38,7 +39,7 @@ declare global { @customElement("hui-dialog-edit-card") export class HuiDialogEditCard extends LitElement { - @property() protected hass?: HomeAssistant; + @property() protected hass!: HomeAssistant; @property() private _params?: EditCardDialogParams; @@ -51,7 +52,7 @@ export class HuiDialogEditCard extends LitElement { public async showDialog(params: EditCardDialogParams): Promise { this._params = params; const [view, card] = params.path; - this._viewConfig = params.lovelace.config.views[view]; + this._viewConfig = params.lovelaceConfig.views[view]; this._cardConfig = card !== undefined ? this._viewConfig.cards![card] : undefined; } @@ -283,22 +284,22 @@ export class HuiDialogEditCard extends LitElement { } private async _save(): Promise { - const lovelace = this._params!.lovelace; this._saving = true; - await lovelace.saveConfig( + await this._params!.saveConfig( this._params!.path.length === 1 ? addCard( - lovelace.config, + this._params!.lovelaceConfig, this._params!.path as [number], this._cardConfig! ) : replaceCard( - lovelace.config, + this._params!.lovelaceConfig, this._params!.path as [number, number], this._cardConfig! ) ); this._saving = false; + showSaveSuccessToast(this, this.hass); this._close(); } } diff --git a/src/panels/lovelace/editor/card-editor/hui-dialog-suggest-card.ts b/src/panels/lovelace/editor/card-editor/hui-dialog-suggest-card.ts new file mode 100755 index 0000000000..3fbf3d03e2 --- /dev/null +++ b/src/panels/lovelace/editor/card-editor/hui-dialog-suggest-card.ts @@ -0,0 +1,215 @@ +import { + css, + html, + LitElement, + TemplateResult, + CSSResultArray, + customElement, + property, + query, +} from "lit-element"; + +import { HomeAssistant } from "../../../../types"; +import { LovelaceCardConfig } from "../../../../data/lovelace"; +import "./hui-card-editor"; +import "./hui-card-preview"; +import "./hui-card-picker"; +import { addCards } from "../config-util"; + +import "../../../../components/ha-yaml-editor"; +import "../../../../components/dialog/ha-paper-dialog"; +import { haStyleDialog } from "../../../../resources/styles"; +import { showEditCardDialog } from "./show-edit-card-dialog"; +import { computeCards } from "../../common/generate-lovelace-config"; +import { SuggestCardDialogParams } from "./show-suggest-card-dialog"; +import { showSaveSuccessToast } from "../../../../util/toast-saved-success"; +// tslint:disable-next-line +import { HaPaperDialog } from "../../../../components/dialog/ha-paper-dialog"; +// tslint:disable-next-line +import { HaYamlEditor } from "../../../../components/ha-yaml-editor"; + +@customElement("hui-dialog-suggest-card") +export class HuiDialogSuggestCard extends LitElement { + @property() protected hass!: HomeAssistant; + @property() private _params?: SuggestCardDialogParams; + @property() private _cardConfig?: LovelaceCardConfig[]; + @property() private _saving: boolean = false; + @property() private _yamlMode: boolean = false; + @query("ha-paper-dialog") private _dialog?: HaPaperDialog; + @query("ha-yaml-editor") private _yamlEditor?: HaYamlEditor; + + public async showDialog(params: SuggestCardDialogParams): Promise { + this._params = params; + this._yamlMode = + (this.hass.panels.lovelace?.config as any)?.mode === "yaml"; + this._cardConfig = + params.cardConfig || + computeCards( + params.entities.map((entityId) => [ + entityId, + this.hass.states[entityId], + ]), + {} + ); + if (this._dialog) { + this._dialog.open(); + } + if (this._yamlEditor) { + this._yamlEditor.setValue(this._cardConfig); + } + } + + protected render(): TemplateResult | void { + return html` + +

+ ${this.hass!.localize("ui.panel.lovelace.editor.suggest_card.header")} +

+ + ${this._cardConfig + ? html` +
+ ${this._cardConfig.map( + (cardConfig) => html` + + ` + )} +
+ ` + : ""} + ${this._yamlMode && this._cardConfig + ? html` +
+ +
+ ` + : ""} +
+
+ + ${this._yamlMode + ? this.hass!.localize("ui.common.close") + : this.hass!.localize("ui.common.cancel")} + + ${!this._yamlMode + ? html` + ${this.hass!.localize( + "ui.panel.lovelace.editor.suggest_card.create_own" + )} + + ${this._saving + ? html` + + ` + : this.hass!.localize( + "ui.panel.lovelace.editor.suggest_card.add" + )} + + ` + : ""} +
+
+ `; + } + + static get styles(): CSSResultArray { + return [ + haStyleDialog, + css` + @media all and (max-width: 450px), all and (max-height: 500px) { + /* overrule the ha-style-dialog max-height on small screens */ + ha-paper-dialog { + max-height: 100%; + height: 100%; + } + } + @media all and (min-width: 850px) { + ha-paper-dialog { + width: 845px; + } + } + ha-paper-dialog { + max-width: 845px; + } + mwc-button paper-spinner { + width: 14px; + height: 14px; + margin-right: 20px; + } + .hidden { + display: none; + } + .element-preview { + position: relative; + } + hui-card-preview { + padding-top: 8px; + margin: 4px auto; + max-width: 390px; + display: block; + width: 100%; + } + .editor { + padding-top: 16px; + } + `, + ]; + } + + private _close(): void { + this._dialog!.close(); + this._params = undefined; + this._cardConfig = undefined; + this._yamlMode = false; + } + + private _pickCard(): void { + if ( + !this._params?.lovelaceConfig || + !this._params?.path || + !this._params?.saveConfig + ) { + return; + } + showEditCardDialog(this, { + lovelaceConfig: this._params!.lovelaceConfig, + saveConfig: this._params!.saveConfig, + path: this._params!.path, + entities: this._params!.entities, + }); + this._close(); + } + + private async _save(): Promise { + if ( + !this._params?.lovelaceConfig || + !this._params?.path || + !this._params?.saveConfig || + !this._cardConfig + ) { + return; + } + this._saving = true; + await this._params!.saveConfig( + addCards( + this._params!.lovelaceConfig, + this._params!.path as [number], + this._cardConfig + ) + ); + this._saving = false; + showSaveSuccessToast(this, this.hass); + this._close(); + } +} + +declare global { + interface HTMLElementTagNameMap { + "hui-dialog-suggest-card": HuiDialogSuggestCard; + } +} diff --git a/src/panels/lovelace/editor/card-editor/show-edit-card-dialog.ts b/src/panels/lovelace/editor/card-editor/show-edit-card-dialog.ts index 4adcaf7620..13b3214342 100644 --- a/src/panels/lovelace/editor/card-editor/show-edit-card-dialog.ts +++ b/src/panels/lovelace/editor/card-editor/show-edit-card-dialog.ts @@ -1,40 +1,25 @@ import { fireEvent } from "../../../../common/dom/fire_event"; -import { Lovelace } from "../../types"; - -declare global { - // for fire event - interface HASSDomEvents { - "show-edit-card": EditCardDialogParams; - } -} - -let registeredDialog = false; -const dialogShowEvent = "show-edit-card"; -const dialogTag = "hui-dialog-edit-card"; +import { LovelaceConfig } from "../../../../data/lovelace"; export interface EditCardDialogParams { - lovelace: Lovelace; + lovelaceConfig: LovelaceConfig; + saveConfig: (config: LovelaceConfig) => void; path: [number] | [number, number]; entities?: string[]; // We can pass entity id's that will be added to the config when a card is picked } -const registerEditCardDialog = (element: HTMLElement): Event => - fireEvent(element, "register-dialog", { - dialogShowEvent, - dialogTag, - dialogImport: () => - import( - /* webpackChunkName: "hui-dialog-edit-card" */ "./hui-dialog-edit-card" - ), - }); +const importEditCardDialog = () => + import( + /* webpackChunkName: "hui-dialog-edit-card" */ "./hui-dialog-edit-card" + ); export const showEditCardDialog = ( element: HTMLElement, editCardDialogParams: EditCardDialogParams ): void => { - if (!registeredDialog) { - registeredDialog = true; - registerEditCardDialog(element); - } - fireEvent(element, dialogShowEvent, editCardDialogParams); + fireEvent(element, "show-dialog", { + dialogTag: "hui-dialog-edit-card", + dialogImport: importEditCardDialog, + dialogParams: editCardDialogParams, + }); }; diff --git a/src/panels/lovelace/editor/card-editor/show-suggest-card-dialog.ts b/src/panels/lovelace/editor/card-editor/show-suggest-card-dialog.ts new file mode 100644 index 0000000000..1dce62e34c --- /dev/null +++ b/src/panels/lovelace/editor/card-editor/show-suggest-card-dialog.ts @@ -0,0 +1,26 @@ +import { fireEvent } from "../../../../common/dom/fire_event"; +import { LovelaceConfig, LovelaceCardConfig } from "../../../../data/lovelace"; + +export interface SuggestCardDialogParams { + lovelaceConfig?: LovelaceConfig; + saveConfig?: (config: LovelaceConfig) => void; + path?: [number]; + entities: string[]; // We can pass entity id's that will be added to the config when a card is picked + cardConfig?: LovelaceCardConfig[]; // We can pass a suggested config +} + +const importsuggestCardDialog = () => + import( + /* webpackChunkName: "hui-dialog-suggest-card" */ "./hui-dialog-suggest-card" + ); + +export const showSuggestCardDialog = ( + element: HTMLElement, + suggestCardDialogParams: SuggestCardDialogParams +): void => { + fireEvent(element, "show-dialog", { + dialogTag: "hui-dialog-suggest-card", + dialogImport: importsuggestCardDialog, + dialogParams: suggestCardDialogParams, + }); +}; diff --git a/src/panels/lovelace/editor/config-util.ts b/src/panels/lovelace/editor/config-util.ts index ef05a7f5e7..9c87efb386 100644 --- a/src/panels/lovelace/editor/config-util.ts +++ b/src/panels/lovelace/editor/config-util.ts @@ -34,6 +34,36 @@ export const addCard = ( }; }; +export const addCards = ( + config: LovelaceConfig, + path: [number], + cardConfigs: LovelaceCardConfig[] +): LovelaceConfig => { + const [viewIndex] = path; + const views: LovelaceViewConfig[] = []; + + config.views.forEach((viewConf, index) => { + if (index !== viewIndex) { + views.push(config.views[index]); + return; + } + + const cards = viewConf.cards + ? [...viewConf.cards, ...cardConfigs] + : [...cardConfigs]; + + views.push({ + ...viewConf, + cards, + }); + }); + + return { + ...config, + views, + }; +}; + export const replaceCard = ( config: LovelaceConfig, path: [number, number], diff --git a/src/panels/lovelace/editor/select-view/hui-dialog-select-view.ts b/src/panels/lovelace/editor/select-view/hui-dialog-select-view.ts index 1fe44229b2..5ca69eb7e2 100644 --- a/src/panels/lovelace/editor/select-view/hui-dialog-select-view.ts +++ b/src/panels/lovelace/editor/select-view/hui-dialog-select-view.ts @@ -30,8 +30,8 @@ export class HuiDialogSelectView extends LitElement { toggleAttribute( this, "hide-icons", - this._params!.lovelace!.config - ? !this._params!.lovelace!.config.views.some((view) => view.icon) + this._params?.lovelaceConfig + ? !this._params.lovelaceConfig.views.some((view) => view.icon) : true ); } @@ -48,7 +48,7 @@ export class HuiDialogSelectView extends LitElement { >

Choose a view

diff --git a/src/panels/lovelace/editor/select-view/show-select-view-dialog.ts b/src/panels/lovelace/editor/select-view/show-select-view-dialog.ts index 0b9460b5d5..62ee573361 100644 --- a/src/panels/lovelace/editor/select-view/show-select-view-dialog.ts +++ b/src/panels/lovelace/editor/select-view/show-select-view-dialog.ts @@ -1,8 +1,8 @@ import { fireEvent } from "../../../../common/dom/fire_event"; -import { Lovelace } from "../../types"; +import { LovelaceConfig } from "../../../../data/lovelace"; export interface SelectViewDialogParams { - lovelace: Lovelace; + lovelaceConfig: LovelaceConfig; viewSelectedCallback: (view: number) => void; } diff --git a/src/panels/lovelace/editor/unused-entities/hui-unused-entities.ts b/src/panels/lovelace/editor/unused-entities/hui-unused-entities.ts index 72cc7593e7..93cacf9db3 100644 --- a/src/panels/lovelace/editor/unused-entities/hui-unused-entities.ts +++ b/src/panels/lovelace/editor/unused-entities/hui-unused-entities.ts @@ -30,19 +30,18 @@ import { computeDomain } from "../../../../common/entity/compute_domain"; import { computeRTL } from "../../../../common/util/compute_rtl"; import { computeUnusedEntities } from "../../common/compute-unused-entities"; -import { showSelectViewDialog } from "../select-view/show-select-view-dialog"; -import { showEditCardDialog } from "../card-editor/show-edit-card-dialog"; import { HomeAssistant } from "../../../../types"; import { Lovelace } from "../../types"; import { LovelaceConfig } from "../../../../data/lovelace"; import { fireEvent } from "../../../../common/dom/fire_event"; +import { addEntitiesToLovelaceView } from "../add-entities-to-view"; @customElement("hui-unused-entities") export class HuiUnusedEntities extends LitElement { @property() public lovelace?: Lovelace; - @property() public hass?: HomeAssistant; + @property() public hass!: HomeAssistant; @property() public narrow?: boolean; @@ -156,23 +155,18 @@ export class HuiUnusedEntities extends LitElement { }; })} .id=${"entity_id"} - .selectable=${this.lovelace!.mode === "storage"} + selectable @selection-changed=${this._handleSelectionChanged} > - ${this.lovelace.mode === "storage" - ? html` - - ` - : ""} + + `; } @@ -206,19 +200,14 @@ export class HuiUnusedEntities extends LitElement { }); } - private _selectView(): void { - showSelectViewDialog(this, { - lovelace: this.lovelace!, - viewSelectedCallback: (view) => this._addCard(view), - }); - } - - private _addCard(view: number): void { - showEditCardDialog(this, { - lovelace: this.lovelace!, - path: [view], - entities: this._selectedEntities, - }); + private _addToLovelaceView(): void { + addEntitiesToLovelaceView( + this, + this.hass, + this._selectedEntities, + this.lovelace!.config, + this.lovelace!.saveConfig + ); } static get styles(): CSSResult { diff --git a/src/panels/lovelace/ha-panel-lovelace.ts b/src/panels/lovelace/ha-panel-lovelace.ts index 1c4e046605..fb517979a5 100644 --- a/src/panels/lovelace/ha-panel-lovelace.ts +++ b/src/panels/lovelace/ha-panel-lovelace.ts @@ -50,6 +50,7 @@ class LovelacePanel extends LitElement { private mqls?: MediaQueryList[]; private _ignoreNextUpdateEvent = false; + private _fetchConfigOnConnect = false; constructor() { super(); @@ -160,6 +161,9 @@ class LovelacePanel extends LitElement { // to the states panel to make sure new entities are shown. this._state = "loading"; this._regenerateConfig(); + } else if (this._fetchConfigOnConnect) { + // Config was changed when we were not at the lovelace panel + this._fetchConfig(false); } } @@ -191,6 +195,12 @@ class LovelacePanel extends LitElement { this._ignoreNextUpdateEvent = false; return; } + if (!this.isConnected) { + // We can't fire events from an element that is connected + // Make sure we fetch the config as soon as the user goes back to Lovelace + this._fetchConfigOnConnect = true; + return; + } showToast(this, { message: this.hass!.localize("ui.panel.lovelace.changed_toast.message"), action: { @@ -206,7 +216,7 @@ class LovelacePanel extends LitElement { this._fetchConfig(true); } - private async _fetchConfig(forceDiskRefresh) { + private async _fetchConfig(forceDiskRefresh: boolean) { let conf: LovelaceConfig; let confMode: Lovelace["mode"] = this.panel!.config.mode; let confProm: Promise; diff --git a/src/panels/lovelace/views/hui-view.ts b/src/panels/lovelace/views/hui-view.ts index 4d7b6ba827..9798522dea 100644 --- a/src/panels/lovelace/views/hui-view.ts +++ b/src/panels/lovelace/views/hui-view.ts @@ -240,7 +240,8 @@ export class HUIView extends LitElement { private _addCard(): void { showEditCardDialog(this, { - lovelace: this.lovelace!, + lovelaceConfig: this.lovelace!.config, + saveConfig: this.lovelace!.saveConfig, path: [this.index!], }); } diff --git a/src/translations/en.json b/src/translations/en.json index d5fba1419f..0641d1e52f 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -516,6 +516,7 @@ "common": { "loading": "Loading", "cancel": "Cancel", + "close": "Close", "save": "Save", "yes": "Yes", "no": "No", @@ -1227,7 +1228,11 @@ "device_not_found": "Device not found.", "info": "Device info", "details": "Here are all the details of your device.", - "entities": "Entities", + "entities": { + "entities": "Entities", + "add_entities_lovelace": "Add all device entities to Lovelace", + "none": "This device has no entities" + }, "automations": "Automations", "confirm_rename_entity_ids": "Do you also want to rename the entity id's of your entities?", "data_table": { @@ -1529,6 +1534,11 @@ "domain": "Domain", "last_changed": "Last Changed" }, + "add_entities": { + "yaml_unsupported": "You can not use this function when using Lovelace in YAML mode.", + "generated_unsupported": "You can only use this function when you have taken control of Lovelace.", + "saving_failed": "Saving Lovelace config failed." + }, "views": { "confirm_delete": "Are you sure you want to delete this view?", "existing_cards": "You can't delete a view that has cards in it. Remove the cards first." @@ -1584,6 +1594,11 @@ "move": "Move to View", "options": "More options" }, + "suggest_card": { + "header": "We created a suggestion for you", + "create_own": "Create your own", + "add": "Add to Lovelace" + }, "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.",