ha-frontend/src/panels/lovelace/editor/card-editor/hui-dialog-suggest-card.ts

274 lines
7.7 KiB
TypeScript

import deepFreeze from "deep-freeze";
import { css, CSSResultGroup, html, LitElement, nothing } from "lit";
import { customElement, property, query, state } from "lit/decorators";
import { fireEvent } from "../../../../common/dom/fire_event";
import "../../../../components/ha-yaml-editor";
import type { HaYamlEditor } from "../../../../components/ha-yaml-editor";
import { LovelaceCardConfig } from "../../../../data/lovelace/config/card";
import { LovelaceSectionConfig } from "../../../../data/lovelace/config/section";
import { isStrategyView } from "../../../../data/lovelace/config/view";
import { haStyleDialog } from "../../../../resources/styles";
import { HomeAssistant } from "../../../../types";
import { showSaveSuccessToast } from "../../../../util/toast-saved-success";
import { addCards, addSection } from "../config-util";
import {
LovelaceContainerPath,
parseLovelaceContainerPath,
} from "../lovelace-path";
import "./hui-card-preview";
import { showCreateCardDialog } from "./show-create-card-dialog";
import { SuggestCardDialogParams } from "./show-suggest-card-dialog";
import { LovelaceConfig } from "../../../../data/lovelace/config/types";
@customElement("hui-dialog-suggest-card")
export class HuiDialogSuggestCard extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@state() private _params?: SuggestCardDialogParams;
@state() private _cardConfig?: LovelaceCardConfig[];
@state() private _sectionConfig?: LovelaceSectionConfig;
@state() private _saving = false;
@query("ha-yaml-editor") private _yamlEditor?: HaYamlEditor;
public showDialog(params: SuggestCardDialogParams): void {
this._params = params;
this._cardConfig = params.cardConfig;
this._sectionConfig = params.sectionConfig;
if (!Object.isFrozen(this._cardConfig)) {
this._cardConfig = deepFreeze(this._cardConfig);
}
if (!Object.isFrozen(this._sectionConfig)) {
this._sectionConfig = deepFreeze(this._sectionConfig);
}
if (this._yamlEditor) {
this._yamlEditor.setValue(this._cardConfig);
}
}
public closeDialog(): void {
this._params = undefined;
this._cardConfig = undefined;
fireEvent(this, "dialog-closed", { dialog: this.localName });
}
private get _viewSupportsSection(): boolean {
if (!this._params?.lovelaceConfig || !this._params?.path) {
return false;
}
const { viewIndex } = parseLovelaceContainerPath(this._params.path);
const viewConfig = this._params!.lovelaceConfig.views[viewIndex];
return !isStrategyView(viewConfig) && viewConfig.type === "sections";
}
private _renderPreview() {
if (this._sectionConfig && this._viewSupportsSection) {
return html`
<div class="element-preview">
<hui-section
.hass=${this.hass}
.config=${this._sectionConfig}
></hui-section>
</div>
`;
}
if (this._cardConfig) {
return html`
<div class="element-preview">
${this._cardConfig.map(
(cardConfig) => html`
<hui-card-preview
.hass=${this.hass}
.config=${cardConfig}
></hui-card-preview>
`
)}
</div>
`;
}
return nothing;
}
protected render() {
if (!this._params) {
return nothing;
}
return html`
<ha-dialog
open
scrimClickAction
@closed=${this.closeDialog}
.heading=${this.hass!.localize(
"ui.panel.lovelace.editor.suggest_card.header"
)}
>
<div>
${this._renderPreview()}
${this._params.yaml && this._cardConfig
? html`
<div class="editor">
<ha-yaml-editor
.hass=${this.hass}
.defaultValue=${this._cardConfig}
></ha-yaml-editor>
</div>
`
: nothing}
</div>
<mwc-button
slot="secondaryAction"
@click=${this.closeDialog}
dialogInitialFocus
>
${this._params.yaml
? this.hass!.localize("ui.common.close")
: this.hass!.localize("ui.common.cancel")}
</mwc-button>
${!this._params.yaml
? html`
<mwc-button slot="primaryAction" @click=${this._pickCard}
>${this.hass!.localize(
"ui.panel.lovelace.editor.suggest_card.create_own"
)}</mwc-button
>
<mwc-button
slot="primaryAction"
.disabled=${this._saving}
@click=${this._save}
>
${this._saving
? html`
<ha-circular-progress
indeterminate
aria-label="Saving"
size="small"
></ha-circular-progress>
`
: this.hass!.localize(
"ui.panel.lovelace.editor.suggest_card.add"
)}
</mwc-button>
`
: ""}
</ha-dialog>
`;
}
static get styles(): CSSResultGroup {
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-dialog {
max-height: 100%;
height: 100%;
}
}
@media all and (min-width: 850px) {
ha-dialog {
width: 845px;
}
}
ha-dialog {
max-width: 845px;
--dialog-z-index: 6;
}
.hidden {
display: none;
}
.element-preview {
position: relative;
}
hui-card-preview,
hui-section {
padding-top: 8px;
margin: 4px auto;
max-width: 390px;
display: block;
width: 100%;
}
.editor {
padding-top: 16px;
}
`,
];
}
private _pickCard(): void {
if (
!this._params?.lovelaceConfig ||
!this._params?.path ||
!this._params?.saveConfig
) {
return;
}
showCreateCardDialog(this, {
lovelaceConfig: this._params!.lovelaceConfig,
saveConfig: this._params!.saveConfig,
path: this._params!.path,
entities: this._params!.entities,
});
this.closeDialog();
}
private _computeNewConfig(
config: LovelaceConfig,
path: LovelaceContainerPath
): LovelaceConfig {
if (!this._viewSupportsSection) {
return addCards(config, path, this._cardConfig!);
}
const { viewIndex, sectionIndex } = parseLovelaceContainerPath(path);
// If container is a view, add a section
if (sectionIndex === undefined) {
const newSection = this._sectionConfig ?? {
type: "grid",
cards: this._cardConfig,
};
return addSection(config, viewIndex, newSection);
}
// Else add cards to section
const newCards = this._sectionConfig
? this._sectionConfig.cards || []
: this._cardConfig!;
return addCards(config, [viewIndex, sectionIndex], newCards);
}
private async _save(): Promise<void> {
if (
!this._params?.lovelaceConfig ||
!this._params?.path ||
!this._params?.saveConfig ||
!this._cardConfig
) {
return;
}
this._saving = true;
const newConfig = this._computeNewConfig(
this._params.lovelaceConfig,
this._params.path
);
await this._params!.saveConfig(newConfig);
this._saving = false;
showSaveSuccessToast(this, this.hass);
this.closeDialog();
}
}
declare global {
interface HTMLElementTagNameMap {
"hui-dialog-suggest-card": HuiDialogSuggestCard;
}
}