-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Added migrate dialog when card has no ID #2008
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 16 commits
fb6c5c9
fd6b6e3
c41875d
a7dfd2b
dd6edc3
cd953c3
1bedb04
c2f5b63
4ca7699
040df0a
6857b19
161a75f
58b585d
a6a973e
896b1bf
299a277
c4540eb
d96c289
a84788f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| 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 { ConfigError } from "./types"; | ||
|
|
||
| const CUSTOM_TYPE_PREFIX = "custom:"; | ||
|
|
||
| export class HuiCardPreview extends HTMLElement { | ||
| private _hass?: HomeAssistant; | ||
| private _element?: LovelaceCard; | ||
|
|
||
| set hass(value: HomeAssistant) { | ||
| this._hass = value; | ||
| if (this._element) { | ||
| this._element.hass = value; | ||
| } | ||
| } | ||
|
|
||
| set error(error: ConfigError) { | ||
| const configValue = createErrorCardConfig( | ||
| `${error.type}: ${error.message}`, | ||
| undefined | ||
| ); | ||
|
|
||
| this._createCard(configValue); | ||
| } | ||
|
|
||
| set config(configValue: LovelaceConfig) { | ||
| if (!configValue) { | ||
| return; | ||
| } | ||
|
|
||
| if (!this._element) { | ||
| this._createCard(configValue); | ||
| return; | ||
| } | ||
|
|
||
| const tag = configValue.type.startsWith(CUSTOM_TYPE_PREFIX) | ||
| ? configValue.type.substr(CUSTOM_TYPE_PREFIX.length) | ||
| : `hui-${configValue.type}-card`; | ||
|
|
||
| if (tag.toUpperCase() === this._element.tagName) { | ||
| this._element.setConfig(configValue); | ||
| } else { | ||
| this._createCard(configValue); | ||
| } | ||
| } | ||
|
|
||
| private _createCard(configValue: LovelaceConfig): void { | ||
| if (this._element) { | ||
| this.removeChild(this._element); | ||
| } | ||
|
|
||
| this._element = createCardElement(configValue); | ||
|
|
||
| if (this._hass) { | ||
| this._element!.hass = this._hass; | ||
| } | ||
|
|
||
| this.appendChild(this._element!); | ||
| } | ||
| } | ||
|
|
||
| declare global { | ||
| interface HTMLElementTagNameMap { | ||
| "hui-card-preview": HuiCardPreview; | ||
| } | ||
| } | ||
|
|
||
| customElements.define("hui-card-preview", HuiCardPreview); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,229 +1,68 @@ | ||
| import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element"; | ||
| import yaml from "js-yaml"; | ||
| import { when } from "lit-html/directives/when"; | ||
| import { TemplateResult } from "lit-html"; | ||
|
|
||
| import "@polymer/paper-button/paper-button"; | ||
| import "@polymer/paper-input/paper-textarea"; | ||
| import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable"; | ||
| import "@polymer/paper-dialog/paper-dialog"; | ||
| import { HomeAssistant } from "../../../types"; | ||
| import { LovelaceConfig } from "../types"; | ||
| import "./hui-edit-card"; | ||
| // 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 { HomeAssistant } from "../../../types"; | ||
| import { getCardConfig, updateCardConfig } from "../common/data"; | ||
| import { fireEvent } from "../../../common/dom/fire_event"; | ||
|
|
||
| import "./hui-yaml-editor"; | ||
| import "./hui-yaml-card-preview"; | ||
| import { HuiEditCard } from "./hui-edit-card"; | ||
| import "./hui-migrate-config"; | ||
| // This is not a duplicate import, one is for types, one is for element. | ||
| // tslint:disable-next-line | ||
| import { HuiYAMLCardPreview } from "./hui-yaml-card-preview"; | ||
| import { LovelaceCardEditor, LovelaceConfig } from "../types"; | ||
| import { YamlChangedEvent, ConfigValue } from "./types"; | ||
|
|
||
| const CUSTOM_TYPE_PREFIX = "custom:"; | ||
| import { HuiMigrateConfig } from "./hui-migrate-config"; | ||
|
|
||
| export class HuiDialogEditCard extends LitElement { | ||
| protected hass?: HomeAssistant; | ||
| private _cardId?: string; | ||
| private _originalConfigYaml?: string; | ||
| private _configElement?: LovelaceCardEditor | null; | ||
| protected _hass?: HomeAssistant; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are we making this a |
||
| private _cardConfig?: LovelaceConfig; | ||
| private _reloadLovelace?: () => void; | ||
| private _editorToggle?: boolean; | ||
| private _configValue?: ConfigValue; | ||
|
|
||
| static get properties(): PropertyDeclarations { | ||
| return { | ||
| hass: {}, | ||
| cardId: { | ||
| type: Number, | ||
| }, | ||
| _dialogClosedCallback: {}, | ||
| _configElement: {}, | ||
| _editorToggle: {}, | ||
| _hass: {}, | ||
| _cardConfig: {}, | ||
| }; | ||
| } | ||
|
|
||
| public async showDialog({ hass, cardId, reloadLovelace }) { | ||
| this.hass = hass; | ||
| this._cardId = cardId; | ||
| this._reloadLovelace = reloadLovelace; | ||
| this._editorToggle = true; | ||
| this._configElement = undefined; | ||
| this._configValue = { format: "yaml", value: "" }; | ||
| this._loadConfig().then(() => this._loadConfigElement()); | ||
| // Wait till dialog is rendered. | ||
| await this.updateComplete; | ||
| this._dialog.open(); | ||
| private get _editDialog(): HuiEditCard { | ||
| return this.shadowRoot!.querySelector("hui-edit-card")!; | ||
| } | ||
|
|
||
| private get _dialog(): PaperDialogElement { | ||
| return this.shadowRoot!.querySelector("paper-dialog")!; | ||
| private get _migrateDialog(): HuiMigrateConfig { | ||
| return this.shadowRoot!.querySelector("hui-migrate-config")!; | ||
| } | ||
|
|
||
| private get _previewEl(): HuiYAMLCardPreview { | ||
| return this.shadowRoot!.querySelector("hui-yaml-card-preview")!; | ||
| public async showDialog({ hass, cardConfig, reloadLovelace }) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For a future PR, we should just make this a single object, not explode it, and type it. That way we can export the type and make sure people call it correctly, even potentially have a helper. public async showDialog(params: EditDialogParams) {and then export const showEditDialog = (element: HTMLElement, hass: HomeAssistant, cardConfig: CardConfig, reloadLoveLace: () => void) =>
fireEvent(element, 'show-edit-card-dialog', { hass, cardConfig, reloadLovelace }) |
||
| this._hass = hass; | ||
| this._cardConfig = cardConfig; | ||
| this._reloadLovelace = reloadLovelace; | ||
| await this.updateComplete; | ||
| this._cardConfig!.id | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can typescript handle that?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| ? this._editDialog.openDialog() | ||
| : this._migrateDialog.openDialog(); | ||
| } | ||
|
|
||
| protected render(): TemplateResult { | ||
| return html` | ||
| <style> | ||
| paper-dialog { | ||
| width: 650px; | ||
| } | ||
| .element-editor { | ||
| margin-bottom: 16px; | ||
| } | ||
| </style> | ||
| <paper-dialog with-backdrop> | ||
| <h2>Card Configuration</h2> | ||
| <paper-dialog-scrollable> | ||
| ${ | ||
| this._editorToggle && this._configElement !== null | ||
| ? html` | ||
| <div class="element-editor"> | ||
| ${ | ||
| when( | ||
| this._configElement, | ||
| () => this._configElement, | ||
| () => | ||
| html` | ||
| Loading... | ||
| ` | ||
| ) | ||
| } | ||
| </div> | ||
| ` | ||
| : html` | ||
| <hui-yaml-editor | ||
| .yaml="${this._configValue!.value}" | ||
| @yaml-changed="${this._handleYamlChanged}" | ||
| ></hui-yaml-editor> | ||
| ` | ||
| } | ||
| <hui-yaml-card-preview | ||
| .hass="${this.hass}" | ||
| .value="${this._configValue}" | ||
| ></hui-yaml-card-preview> | ||
| </paper-dialog-scrollable> | ||
| <div class="paper-dialog-buttons"> | ||
| <paper-button @click="${this._toggleEditor}" | ||
| >Toggle Editor</paper-button | ||
| > | ||
| <paper-button @click="${this._closeDialog}">Cancel</paper-button> | ||
| <paper-button @click="${this._updateConfigInBackend}" | ||
| >Save</paper-button | ||
| > | ||
| </div> | ||
| </paper-dialog> | ||
| ${ | ||
| this._cardConfig!.id | ||
| ? html` | ||
| <hui-edit-card | ||
| .cardConfig="${this._cardConfig}" | ||
| .hass="${this._hass}" | ||
| @reload-lovelace="${this._reloadLovelace}" | ||
| > | ||
| </hui-edit-card> | ||
| ` | ||
| : html` | ||
| <hui-migrate-config | ||
| .hass="${this._hass}" | ||
| @reload-lovelace="${this._reloadLovelace}" | ||
| ></hui-migrate-config> | ||
| ` | ||
| } | ||
| `; | ||
| } | ||
|
|
||
| private _handleYamlChanged(ev: YamlChangedEvent): void { | ||
| this._configValue = { format: "yaml", value: ev.detail.yaml }; | ||
| this._updatePreview(this._configValue); | ||
| } | ||
|
|
||
| private _handleJSConfigChanged(value: LovelaceConfig): void { | ||
| this._configElement!.setConfig(value); | ||
| this._configValue = { format: "js", value }; | ||
| this._updatePreview(this._configValue); | ||
| } | ||
|
|
||
| private _updatePreview(value: ConfigValue) { | ||
| if (!this._previewEl) { | ||
| return; | ||
| } | ||
| this._previewEl.value = value; | ||
| } | ||
|
|
||
| private _closeDialog(): void { | ||
| this._dialog.close(); | ||
| } | ||
|
|
||
| private _toggleEditor(): void { | ||
| if (this._editorToggle && this._configValue!.format === "js") { | ||
| this._configValue = { | ||
| format: "yaml", | ||
| value: yaml.safeDump(this._configValue!.value), | ||
| }; | ||
| } else if (this._configElement && this._configValue!.format === "yaml") { | ||
| this._configValue = { | ||
| format: "js", | ||
| value: yaml.safeLoad(this._configValue!.value), | ||
| }; | ||
| this._configElement.setConfig(this._configValue!.value as LovelaceConfig); | ||
| } | ||
| this._editorToggle = !this._editorToggle; | ||
| } | ||
|
|
||
| private async _loadConfig(): Promise<void> { | ||
| const cardConfig = await getCardConfig(this.hass!, this._cardId!); | ||
| this._configValue = { | ||
| format: "yaml", | ||
| value: cardConfig, | ||
| }; | ||
| this._originalConfigYaml = cardConfig; | ||
|
|
||
| // This will center the dialog with the updated config Element | ||
| fireEvent(this._dialog, "iron-resize"); | ||
| } | ||
|
|
||
| private async _loadConfigElement(): Promise<void> { | ||
| const conf = yaml.safeLoad(this._configValue!.value); | ||
|
|
||
| const tag = conf.type.startsWith(CUSTOM_TYPE_PREFIX) | ||
| ? conf.type.substr(CUSTOM_TYPE_PREFIX.length) | ||
| : `hui-${conf.type}-card`; | ||
|
|
||
| const elClass = customElements.get(tag); | ||
| let configElement; | ||
|
|
||
| try { | ||
| configElement = await elClass.getConfigElement(); | ||
| } catch (err) { | ||
| this._configElement = null; | ||
| return; | ||
| } | ||
|
|
||
| configElement.setConfig(conf); | ||
| configElement.hass = this.hass; | ||
| configElement.addEventListener("config-changed", (ev) => | ||
| this._handleJSConfigChanged(ev.detail.config) | ||
| ); | ||
| this._configValue = { format: "js", value: conf }; | ||
| this._configElement = configElement; | ||
|
|
||
| // This will center the dialog with the updated config Element | ||
| fireEvent(this._dialog, "iron-resize"); | ||
| } | ||
|
|
||
| private async _updateConfigInBackend(): Promise<void> { | ||
| if (this._configValue!.format === "js") { | ||
| this._configValue = { | ||
| format: "yaml", | ||
| value: yaml.safeDump(this._configValue!.value), | ||
| }; | ||
| } | ||
|
|
||
| if (this._configValue!.value === this._originalConfigYaml) { | ||
| this._dialog.close(); | ||
| return; | ||
| } | ||
|
|
||
| try { | ||
| await updateCardConfig( | ||
| this.hass!, | ||
| this._cardId!, | ||
| this._configValue!.value | ||
| ); | ||
| this._dialog.close(); | ||
| this._reloadLovelace!(); | ||
| } catch (err) { | ||
| alert(`Saving failed: ${err.reason}`); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| declare global { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure why this was changed. I dont think this is "prettier"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is, small objects will be put on a single line.