Change edit mode + add edit lovelace (#2277)

* Change edit mode + add edit lovelace

* Comments

* Fix (yes it was used :-)

* Raw edit header changed
This commit is contained in:
Bram Kragten 2018-12-12 13:59:19 +01:00 committed by Paulus Schoutsen
parent d277571735
commit 8c61624a9c
6 changed files with 321 additions and 22 deletions

View File

@ -87,7 +87,7 @@ export class HuiCardOptions extends hassLocalizeLitMixin(LitElement) {
} }
return html` return html`
<paper-item @click="${this._moveCard}" .index="${index}" <paper-item @click="${this._moveCard}" .index="${index}"
>${view.title}</paper-item >${view.title || "Unnamed view"}</paper-item
> >
`; `;
}) })

View File

@ -0,0 +1,152 @@
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
import { TemplateResult } from "lit-html";
import "@polymer/paper-spinner/paper-spinner";
import "@polymer/paper-dialog/paper-dialog";
// 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 "@polymer/paper-button/paper-button";
import "@polymer/paper-dialog-scrollable/paper-dialog-scrollable";
import "./hui-lovelace-editor";
import { HomeAssistant } from "../../../../types";
import { LovelaceConfig } from "../../../../data/lovelace";
import { hassLocalizeLitMixin } from "../../../../mixins/lit-localize-mixin";
import { Lovelace } from "../../types";
export class HuiDialogEditLovelace extends hassLocalizeLitMixin(LitElement) {
public hass?: HomeAssistant;
private _lovelace?: Lovelace;
private _config?: LovelaceConfig;
private _saving: boolean;
static get properties(): PropertyDeclarations {
return {
hass: {},
_lovelace: {},
};
}
protected constructor() {
super();
this._saving = false;
}
public async showDialog(lovelace: Lovelace): Promise<void> {
this._lovelace = lovelace;
if (this._dialog == null) {
await this.updateComplete;
}
const { views, ...lovelaceConfig } = this._lovelace!.config;
this._config = lovelaceConfig as LovelaceConfig;
this._dialog.open();
}
private get _dialog(): PaperDialogElement {
return this.shadowRoot!.querySelector("paper-dialog")!;
}
protected render(): TemplateResult {
return html`
${this.renderStyle()}
<paper-dialog with-backdrop>
<h2>Edit Lovelace</h2>
<paper-dialog-scrollable>
<hui-lovelace-editor
.hass="${this.hass}"
.config="${this._config}"
@lovelace-config-changed="${this._ConfigChanged}"
></hui-lovelace-editor
></paper-dialog-scrollable>
<div class="paper-dialog-buttons">
<paper-button @click="${this._closeDialog}"
>${this.localize("ui.common.cancel")}</paper-button
>
<paper-button
?disabled="${!this._config || this._saving}"
@click="${this._save}"
>
<paper-spinner
?active="${this._saving}"
alt="Saving"
></paper-spinner>
${this.localize("ui.common.save")}</paper-button
>
</div>
</paper-dialog>
`;
}
private _closeDialog(): void {
this._config = undefined;
this._dialog.close();
}
private async _save(): Promise<void> {
if (!this._config) {
return;
}
if (!this._isConfigChanged()) {
this._closeDialog();
return;
}
this._saving = true;
const lovelace = this._lovelace!;
const config: LovelaceConfig = {
...lovelace.config,
...this._config,
};
try {
await lovelace.saveConfig(config);
this._closeDialog();
} catch (err) {
alert(`Saving failed: ${err.message}`);
} finally {
this._saving = false;
}
}
private _ConfigChanged(ev: CustomEvent): void {
if (ev.detail && ev.detail.config) {
this._config = ev.detail.config;
}
}
private _isConfigChanged(): boolean {
const { views, ...lovelaceConfig } = this._lovelace!.config;
return JSON.stringify(this._config) !== JSON.stringify(lovelaceConfig);
}
private renderStyle(): TemplateResult {
return html`
<style>
paper-dialog {
width: 650px;
}
paper-button paper-spinner {
width: 14px;
height: 14px;
margin-right: 20px;
}
paper-spinner {
display: none;
}
paper-spinner[active] {
display: block;
}
</style>
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"hui-dialog-edit-lovelace": HuiDialogEditLovelace;
}
}
customElements.define("hui-dialog-edit-lovelace", HuiDialogEditLovelace);

View File

@ -0,0 +1,80 @@
import { html, LitElement, PropertyDeclarations } from "@polymer/lit-element";
import { TemplateResult } from "lit-html";
import "@polymer/paper-input/paper-input";
import { EditorTarget } from "../types";
import { hassLocalizeLitMixin } from "../../../../mixins/lit-localize-mixin";
import { HomeAssistant } from "../../../../types";
import { fireEvent } from "../../../../common/dom/fire_event";
import { configElementStyle } from "../config-elements/config-elements-style";
import { LovelaceConfig } from "../../../../data/lovelace";
declare global {
interface HASSDomEvents {
"lovelace-config-changed": {
config: LovelaceConfig;
};
}
}
export class HuiLovelaceEditor extends hassLocalizeLitMixin(LitElement) {
static get properties(): PropertyDeclarations {
return { hass: {}, config: {} };
}
public hass?: HomeAssistant;
public config?: LovelaceConfig;
get _title(): string {
if (!this.config) {
return "";
}
return this.config.title || "";
}
protected render(): TemplateResult {
return html`
${configElementStyle}
<div class="card-config">
<paper-input
label="Title"
.value="${this._title}"
.configValue="${"title"}"
@value-changed="${this._valueChanged}"
></paper-input>
</div>
`;
}
private _valueChanged(ev: Event): void {
if (!this.config) {
return;
}
const target = ev.currentTarget! as EditorTarget;
if (this[`_${target.configValue}`] === target.value) {
return;
}
let newConfig;
if (target.configValue) {
newConfig = {
...this.config,
[target.configValue]: target.value,
};
}
fireEvent(this, "lovelace-config-changed", { config: newConfig });
}
}
declare global {
interface HTMLElementTagNameMap {
"hui-lovelace-editor": HuiLovelaceEditor;
}
}
customElements.define("hui-lovelace-editor", HuiLovelaceEditor);

View File

@ -0,0 +1,32 @@
import { fireEvent } from "../../../../common/dom/fire_event";
import { Lovelace } from "../../types";
declare global {
// for fire event
interface HASSDomEvents {
"show-edit-lovelace": Lovelace;
}
}
let registeredDialog = false;
const dialogShowEvent = "show-edit-lovelace";
const dialogTag = "hui-dialog-edit-lovelace";
const registerEditLovelaceDialog = (element: HTMLElement) =>
fireEvent(element, "register-dialog", {
dialogShowEvent,
dialogTag,
dialogImport: () =>
import(/* webpackChunkName: "hui-dialog-edit-lovelace" */ "./hui-dialog-edit-lovelace"),
});
export const showEditLovelaceDialog = (
element: HTMLElement,
lovelace: Lovelace
) => {
if (!registeredDialog) {
registeredDialog = true;
registerEditLovelaceDialog(element);
}
fireEvent(element, dialogShowEvent, lovelace);
};

View File

@ -90,7 +90,9 @@ class LovelaceFullConfigEditor extends hassLocalizeLitMixin(LitElement) {
app-header-layout { app-header-layout {
height: 100vh; height: 100vh;
} }
app-toolbar {
background-color: #455a64;
}
paper-button { paper-button {
font-size: 16px; font-size: 16px;
} }

View File

@ -43,6 +43,7 @@ import "./hui-view";
import { HUIView } from "./hui-view"; import { HUIView } from "./hui-view";
import createCardElement from "./common/create-card-element"; import createCardElement from "./common/create-card-element";
import { showEditViewDialog } from "./editor/view-editor/show-edit-view-dialog"; import { showEditViewDialog } from "./editor/view-editor/show-edit-view-dialog";
import { showEditLovelaceDialog } from "./editor/lovelace-editor/show-edit-lovelace-dialog";
import { Lovelace } from "./types"; import { Lovelace } from "./types";
import { afterNextRender } from "../../common/util/render-status"; import { afterNextRender } from "../../common/util/render-status";
@ -121,18 +122,51 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) {
.narrow="${this.narrow}" .narrow="${this.narrow}"
></hui-notification-drawer> ></hui-notification-drawer>
<ha-app-layout id="layout"> <ha-app-layout id="layout">
<app-header slot="header" effects="waterfall" fixed condenses> <app-header slot="header" effects="waterfall" class="${classMap({
"edit-mode": this._editMode,
})}" fixed condenses>
${ ${
this._editMode this._editMode
? html` ? html`
<app-toolbar> <app-toolbar class="edit-mode">
<paper-icon-button <paper-icon-button
icon="hass:close" icon="hass:close"
@click="${this._editModeDisable}" @click="${this._editModeDisable}"
></paper-icon-button> ></paper-icon-button>
<div main-title> <div main-title>
${this.localize("ui.panel.lovelace.editor.header")} ${
this.config.title ||
this.localize("ui.panel.lovelace.editor.header")
}
<paper-icon-button
icon="hass:pencil"
class="edit-icon"
@click="${this._editLovelace}"
></paper-icon-button>
</div> </div>
<paper-icon-button
icon="hass:help-circle"
title="Help"
@click="${this._handleHelp}"
></paper-icon-button>
<paper-menu-button
no-animations
horizontal-align="right"
horizontal-offset="-5"
>
<paper-icon-button
icon="hass:dots-vertical"
slot="dropdown-trigger"
></paper-icon-button>
<paper-listbox
@iron-select="${this._deselect}"
slot="dropdown-content"
>
<paper-item @click="${this.lovelace!.enableFullEditMode}"
>Raw config editor</paper-item
>
</paper-listbox>
</paper-menu-button>
</app-toolbar> </app-toolbar>
` `
: html` : html`
@ -180,16 +214,6 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) {
this.localize("ui.panel.lovelace.editor.configure_ui") this.localize("ui.panel.lovelace.editor.configure_ui")
}</paper-item }</paper-item
> >
${
this._storageMode
? html`
<paper-item
@click="${this.lovelace!.enableFullEditMode}"
>Raw config editor</paper-item
>
`
: ""
}
<paper-item @click="${this._handleHelp}">Help</paper-item> <paper-item @click="${this._handleHelp}">Help</paper-item>
</paper-listbox> </paper-listbox>
</paper-menu-button> </paper-menu-button>
@ -224,7 +248,7 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) {
this._editMode this._editMode
? html` ? html`
<ha-icon <ha-icon
class="edit-view-icon" class="edit-icon view"
@click="${this._editView}" @click="${this._editView}"
icon="hass:pencil" icon="hass:pencil"
></ha-icon> ></ha-icon>
@ -293,11 +317,20 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) {
--paper-tabs-selection-bar-color: var(--text-primary-color, #fff); --paper-tabs-selection-bar-color: var(--text-primary-color, #fff);
text-transform: uppercase; text-transform: uppercase;
} }
paper-tab.iron-selected .edit-view-icon { .edit-mode {
background-color: #455a64;
}
.edit-mode div[main-title] {
pointer-events: auto;
}
paper-tab.iron-selected .edit-icon {
display: inline-flex; display: inline-flex;
} }
.edit-view-icon { .edit-icon {
color: var(--accent-color);
padding-left: 8px; padding-left: 8px;
}
.edit-icon.view {
display: none; display: none;
} }
#add-view { #add-view {
@ -412,10 +445,6 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) {
return this.lovelace!.mode === "yaml"; return this.lovelace!.mode === "yaml";
} }
private get _storageMode(): boolean {
return this.lovelace!.mode === "storage";
}
private get _editMode() { private get _editMode() {
return this.lovelace!.editMode; return this.lovelace!.editMode;
} }
@ -478,6 +507,10 @@ class HUIRoot extends hassLocalizeLitMixin(LitElement) {
} }
} }
private _editLovelace() {
showEditLovelaceDialog(this, this.lovelace!);
}
private _editView() { private _editView() {
showEditViewDialog(this, { showEditViewDialog(this, {
lovelace: this.lovelace!, lovelace: this.lovelace!,