mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-14 12:56:37 +00:00
Add fields
and multiple
support to object selector (#25843)
* Add schema and multiple for object selector * Add selector to gallery * Fix description * Improve formatting * Add ellipsis * Update fields instead of schema * Update gallery * Update format * Fix format value * Fix dialog size
This commit is contained in:
parent
f87e20cae9
commit
b608bd949b
@ -416,6 +416,34 @@ const SCHEMAS: {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
items: {
|
||||||
|
name: "Items",
|
||||||
|
selector: {
|
||||||
|
object: {
|
||||||
|
label_field: "name",
|
||||||
|
description_field: "value",
|
||||||
|
multiple: true,
|
||||||
|
fields: {
|
||||||
|
name: {
|
||||||
|
label: "Name",
|
||||||
|
selector: { text: {} },
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
label: "Value",
|
||||||
|
selector: {
|
||||||
|
number: {
|
||||||
|
mode: "slider",
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
unit_of_measurement: "%",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -1,16 +1,27 @@
|
|||||||
import type { PropertyValues } from "lit";
|
import { mdiClose, mdiDelete, mdiDrag, mdiPencil } from "@mdi/js";
|
||||||
import { html, LitElement } from "lit";
|
import { css, html, LitElement, nothing, type PropertyValues } from "lit";
|
||||||
import { customElement, property, query } from "lit/decorators";
|
import { customElement, property, query } from "lit/decorators";
|
||||||
|
import memoizeOne from "memoize-one";
|
||||||
|
import { ensureArray } from "../../common/array/ensure-array";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
|
import type { ObjectSelector } from "../../data/selector";
|
||||||
|
import { formatSelectorValue } from "../../data/selector/format_selector_value";
|
||||||
|
import { showFormDialog } from "../../dialogs/form/show-form-dialog";
|
||||||
import type { HomeAssistant } from "../../types";
|
import type { HomeAssistant } from "../../types";
|
||||||
import "../ha-yaml-editor";
|
import type { HaFormSchema } from "../ha-form/types";
|
||||||
import "../ha-input-helper-text";
|
import "../ha-input-helper-text";
|
||||||
|
import "../ha-md-list";
|
||||||
|
import "../ha-md-list-item";
|
||||||
|
import "../ha-sortable";
|
||||||
|
import "../ha-yaml-editor";
|
||||||
import type { HaYamlEditor } from "../ha-yaml-editor";
|
import type { HaYamlEditor } from "../ha-yaml-editor";
|
||||||
|
|
||||||
@customElement("ha-selector-object")
|
@customElement("ha-selector-object")
|
||||||
export class HaObjectSelector extends LitElement {
|
export class HaObjectSelector extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public selector!: ObjectSelector;
|
||||||
|
|
||||||
@property() public value?: any;
|
@property() public value?: any;
|
||||||
|
|
||||||
@property() public label?: string;
|
@property() public label?: string;
|
||||||
@ -23,11 +34,136 @@ export class HaObjectSelector extends LitElement {
|
|||||||
|
|
||||||
@property({ type: Boolean }) public required = true;
|
@property({ type: Boolean }) public required = true;
|
||||||
|
|
||||||
@query("ha-yaml-editor", true) private _yamlEditor!: HaYamlEditor;
|
@property({ attribute: false }) public localizeValue?: (
|
||||||
|
key: string
|
||||||
|
) => string;
|
||||||
|
|
||||||
|
@query("ha-yaml-editor", true) private _yamlEditor?: HaYamlEditor;
|
||||||
|
|
||||||
private _valueChangedFromChild = false;
|
private _valueChangedFromChild = false;
|
||||||
|
|
||||||
|
private _computeLabel = (schema: HaFormSchema): string => {
|
||||||
|
const translationKey = this.selector.object?.translation_key;
|
||||||
|
|
||||||
|
if (this.localizeValue && translationKey) {
|
||||||
|
const label = this.localizeValue(
|
||||||
|
`${translationKey}.fields.${schema.name}`
|
||||||
|
);
|
||||||
|
if (label) {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.selector.object?.fields?.[schema.name]?.label || schema.name;
|
||||||
|
};
|
||||||
|
|
||||||
|
private _renderItem(item: any, index: number) {
|
||||||
|
const labelField =
|
||||||
|
this.selector.object!.label_field ||
|
||||||
|
Object.keys(this.selector.object!.fields!)[0];
|
||||||
|
|
||||||
|
const labelSelector = this.selector.object!.fields![labelField].selector;
|
||||||
|
|
||||||
|
const label = labelSelector
|
||||||
|
? formatSelectorValue(this.hass, item[labelField], labelSelector)
|
||||||
|
: "";
|
||||||
|
|
||||||
|
let description = "";
|
||||||
|
|
||||||
|
const descriptionField = this.selector.object!.description_field;
|
||||||
|
if (descriptionField) {
|
||||||
|
const descriptionSelector =
|
||||||
|
this.selector.object!.fields![descriptionField].selector;
|
||||||
|
|
||||||
|
description = descriptionSelector
|
||||||
|
? formatSelectorValue(
|
||||||
|
this.hass,
|
||||||
|
item[descriptionField],
|
||||||
|
descriptionSelector
|
||||||
|
)
|
||||||
|
: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const reorderable = this.selector.object!.multiple || false;
|
||||||
|
const multiple = this.selector.object!.multiple || false;
|
||||||
|
return html`
|
||||||
|
<ha-md-list-item class="item">
|
||||||
|
${reorderable
|
||||||
|
? html`
|
||||||
|
<ha-svg-icon
|
||||||
|
class="handle"
|
||||||
|
.path=${mdiDrag}
|
||||||
|
slot="start"
|
||||||
|
></ha-svg-icon>
|
||||||
|
`
|
||||||
|
: nothing}
|
||||||
|
<div slot="headline" class="label">${label}</div>
|
||||||
|
${description
|
||||||
|
? html`<div slot="supporting-text" class="description">
|
||||||
|
${description}
|
||||||
|
</div>`
|
||||||
|
: nothing}
|
||||||
|
<ha-icon-button
|
||||||
|
slot="end"
|
||||||
|
.item=${item}
|
||||||
|
.index=${index}
|
||||||
|
.label=${this.hass.localize("ui.common.edit")}
|
||||||
|
.path=${mdiPencil}
|
||||||
|
@click=${this._editItem}
|
||||||
|
></ha-icon-button>
|
||||||
|
<ha-icon-button
|
||||||
|
slot="end"
|
||||||
|
.index=${index}
|
||||||
|
.label=${this.hass.localize("ui.common.delete")}
|
||||||
|
.path=${multiple ? mdiDelete : mdiClose}
|
||||||
|
@click=${this._deleteItem}
|
||||||
|
></ha-icon-button>
|
||||||
|
</ha-md-list-item>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
|
if (!this.selector.object) {
|
||||||
|
return nothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.selector.object.fields) {
|
||||||
|
if (this.selector.object.multiple) {
|
||||||
|
const items = ensureArray(this.value ?? []);
|
||||||
|
return html`
|
||||||
|
${this.label ? html`<label>${this.label}</label>` : nothing}
|
||||||
|
<div class="items-container">
|
||||||
|
<ha-sortable
|
||||||
|
handle-selector=".handle"
|
||||||
|
draggable-selector=".item"
|
||||||
|
@item-moved=${this._itemMoved}
|
||||||
|
>
|
||||||
|
<ha-md-list>
|
||||||
|
${items.map((item, index) => this._renderItem(item, index))}
|
||||||
|
</ha-md-list>
|
||||||
|
</ha-sortable>
|
||||||
|
<ha-button outlined @click=${this._addItem}>
|
||||||
|
${this.hass.localize("ui.common.add")}
|
||||||
|
</ha-button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
${this.label ? html`<label>${this.label}</label>` : nothing}
|
||||||
|
<div class="items-container">
|
||||||
|
${this.value
|
||||||
|
? html`<ha-md-list>
|
||||||
|
${this._renderItem(this.value, 0)}
|
||||||
|
</ha-md-list>`
|
||||||
|
: html`
|
||||||
|
<ha-button outlined @click=${this._addItem}>
|
||||||
|
${this.hass.localize("ui.common.add")}
|
||||||
|
</ha-button>
|
||||||
|
`}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
return html`<ha-yaml-editor
|
return html`<ha-yaml-editor
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.readonly=${this.disabled}
|
.readonly=${this.disabled}
|
||||||
@ -44,9 +180,103 @@ export class HaObjectSelector extends LitElement {
|
|||||||
: ""} `;
|
: ""} `;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _schema = memoizeOne((selector: ObjectSelector) => {
|
||||||
|
if (!selector.object || !selector.object.fields) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return Object.entries(selector.object.fields).map(([key, field]) => ({
|
||||||
|
name: key,
|
||||||
|
selector: field.selector,
|
||||||
|
required: field.required ?? false,
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
private _itemMoved(ev) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
const newIndex = ev.detail.newIndex;
|
||||||
|
const oldIndex = ev.detail.oldIndex;
|
||||||
|
if (!this.selector.object!.multiple) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const newValue = ensureArray(this.value ?? []).concat();
|
||||||
|
const item = newValue.splice(oldIndex, 1)[0];
|
||||||
|
newValue.splice(newIndex, 0, item);
|
||||||
|
fireEvent(this, "value-changed", { value: newValue });
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _addItem(ev) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
|
||||||
|
const newItem = await showFormDialog(this, {
|
||||||
|
title: this.hass.localize("ui.common.add"),
|
||||||
|
schema: this._schema(this.selector),
|
||||||
|
data: {},
|
||||||
|
computeLabel: this._computeLabel,
|
||||||
|
submitText: this.hass.localize("ui.common.add"),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (newItem === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.selector.object!.multiple) {
|
||||||
|
fireEvent(this, "value-changed", { value: newItem });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newValue = ensureArray(this.value ?? []).concat();
|
||||||
|
newValue.push(newItem);
|
||||||
|
fireEvent(this, "value-changed", { value: newValue });
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _editItem(ev) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
const item = ev.currentTarget.item;
|
||||||
|
const index = ev.currentTarget.index;
|
||||||
|
|
||||||
|
const updatedItem = await showFormDialog(this, {
|
||||||
|
title: this.hass.localize("ui.common.edit"),
|
||||||
|
schema: this._schema(this.selector),
|
||||||
|
data: item,
|
||||||
|
computeLabel: this._computeLabel,
|
||||||
|
submitText: this.hass.localize("ui.common.save"),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (updatedItem === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.selector.object!.multiple) {
|
||||||
|
fireEvent(this, "value-changed", { value: updatedItem });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newValue = ensureArray(this.value ?? []).concat();
|
||||||
|
newValue[index] = updatedItem;
|
||||||
|
fireEvent(this, "value-changed", { value: newValue });
|
||||||
|
}
|
||||||
|
|
||||||
|
private _deleteItem(ev) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
const index = ev.currentTarget.index;
|
||||||
|
|
||||||
|
if (!this.selector.object!.multiple) {
|
||||||
|
fireEvent(this, "value-changed", { value: undefined });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newValue = ensureArray(this.value ?? []).concat();
|
||||||
|
newValue.splice(index, 1);
|
||||||
|
fireEvent(this, "value-changed", { value: newValue });
|
||||||
|
}
|
||||||
|
|
||||||
protected updated(changedProps: PropertyValues) {
|
protected updated(changedProps: PropertyValues) {
|
||||||
super.updated(changedProps);
|
super.updated(changedProps);
|
||||||
if (changedProps.has("value") && !this._valueChangedFromChild) {
|
if (
|
||||||
|
changedProps.has("value") &&
|
||||||
|
!this._valueChangedFromChild &&
|
||||||
|
this._yamlEditor
|
||||||
|
) {
|
||||||
this._yamlEditor.setValue(this.value);
|
this._yamlEditor.setValue(this.value);
|
||||||
}
|
}
|
||||||
this._valueChangedFromChild = false;
|
this._valueChangedFromChild = false;
|
||||||
@ -63,6 +293,42 @@ export class HaObjectSelector extends LitElement {
|
|||||||
}
|
}
|
||||||
fireEvent(this, "value-changed", { value });
|
fireEvent(this, "value-changed", { value });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return [
|
||||||
|
css`
|
||||||
|
ha-md-list {
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
ha-md-list-item {
|
||||||
|
border: 1px solid var(--divider-color);
|
||||||
|
border-radius: 8px;
|
||||||
|
--ha-md-list-item-gap: 0;
|
||||||
|
--md-list-item-top-space: 0;
|
||||||
|
--md-list-item-bottom-space: 0;
|
||||||
|
--md-list-item-leading-space: 12px;
|
||||||
|
--md-list-item-trailing-space: 4px;
|
||||||
|
--md-list-item-two-line-container-height: 48px;
|
||||||
|
--md-list-item-one-line-container-height: 48px;
|
||||||
|
}
|
||||||
|
.handle {
|
||||||
|
cursor: move;
|
||||||
|
padding: 8px;
|
||||||
|
margin-inline-start: -8px;
|
||||||
|
}
|
||||||
|
label {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
ha-md-list-item .label,
|
||||||
|
ha-md-list-item .description {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
@ -334,8 +334,20 @@ export interface NumberSelector {
|
|||||||
} | null;
|
} | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ObjectSelectorField {
|
||||||
|
selector: Selector;
|
||||||
|
label?: string;
|
||||||
|
required?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ObjectSelector {
|
export interface ObjectSelector {
|
||||||
object: {} | null;
|
object?: {
|
||||||
|
label_field?: string;
|
||||||
|
description_field?: string;
|
||||||
|
translation_key?: string;
|
||||||
|
fields?: Record<string, ObjectSelectorField>;
|
||||||
|
multiple?: boolean;
|
||||||
|
} | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AssistPipelineSelector {
|
export interface AssistPipelineSelector {
|
||||||
|
104
src/data/selector/format_selector_value.ts
Normal file
104
src/data/selector/format_selector_value.ts
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
import { ensureArray } from "../../common/array/ensure-array";
|
||||||
|
import { computeAreaName } from "../../common/entity/compute_area_name";
|
||||||
|
import { computeDeviceName } from "../../common/entity/compute_device_name";
|
||||||
|
import { computeEntityName } from "../../common/entity/compute_entity_name";
|
||||||
|
import { getEntityContext } from "../../common/entity/context/get_entity_context";
|
||||||
|
import { blankBeforeUnit } from "../../common/translations/blank_before_unit";
|
||||||
|
import type { HomeAssistant } from "../../types";
|
||||||
|
import type { Selector } from "../selector";
|
||||||
|
|
||||||
|
export const formatSelectorValue = (
|
||||||
|
hass: HomeAssistant,
|
||||||
|
value: any,
|
||||||
|
selector?: Selector
|
||||||
|
) => {
|
||||||
|
if (value == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!selector) {
|
||||||
|
return ensureArray(value).join(", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("text" in selector) {
|
||||||
|
const { prefix, suffix } = selector.text || {};
|
||||||
|
|
||||||
|
const texts = ensureArray(value);
|
||||||
|
return texts
|
||||||
|
.map((text) => `${prefix || ""}${text}${suffix || ""}`)
|
||||||
|
.join(", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("number" in selector) {
|
||||||
|
const { unit_of_measurement } = selector.number || {};
|
||||||
|
const numbers = ensureArray(value);
|
||||||
|
return numbers
|
||||||
|
.map((number) => {
|
||||||
|
const num = Number(number);
|
||||||
|
if (isNaN(num)) {
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
return unit_of_measurement
|
||||||
|
? `${num}${blankBeforeUnit(unit_of_measurement, hass.locale)}${unit_of_measurement}`
|
||||||
|
: num.toString();
|
||||||
|
})
|
||||||
|
.join(", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("floor" in selector) {
|
||||||
|
const floors = ensureArray(value);
|
||||||
|
return floors
|
||||||
|
.map((floorId) => {
|
||||||
|
const floor = hass.floors[floorId];
|
||||||
|
if (!floor) {
|
||||||
|
return floorId;
|
||||||
|
}
|
||||||
|
return floor.name || floorId;
|
||||||
|
})
|
||||||
|
.join(", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("area" in selector) {
|
||||||
|
const areas = ensureArray(value);
|
||||||
|
return areas
|
||||||
|
.map((areaId) => {
|
||||||
|
const area = hass.areas[areaId];
|
||||||
|
if (!area) {
|
||||||
|
return areaId;
|
||||||
|
}
|
||||||
|
return computeAreaName(area);
|
||||||
|
})
|
||||||
|
.join(", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("entity" in selector) {
|
||||||
|
const entities = ensureArray(value);
|
||||||
|
return entities
|
||||||
|
.map((entityId) => {
|
||||||
|
const stateObj = hass.states[entityId];
|
||||||
|
if (!stateObj) {
|
||||||
|
return entityId;
|
||||||
|
}
|
||||||
|
const { device } = getEntityContext(stateObj, hass);
|
||||||
|
const deviceName = device ? computeDeviceName(device) : undefined;
|
||||||
|
const entityName = computeEntityName(stateObj, hass);
|
||||||
|
return [deviceName, entityName].filter(Boolean).join(" ") || entityId;
|
||||||
|
})
|
||||||
|
.join(", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("device" in selector) {
|
||||||
|
const devices = ensureArray(value);
|
||||||
|
return devices
|
||||||
|
.map((deviceId) => {
|
||||||
|
const device = hass.devices[deviceId];
|
||||||
|
if (!device) {
|
||||||
|
return deviceId;
|
||||||
|
}
|
||||||
|
return device.name || deviceId;
|
||||||
|
})
|
||||||
|
.join(", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ensureArray(value).join(", ");
|
||||||
|
};
|
89
src/dialogs/form/dialog-form.ts
Normal file
89
src/dialogs/form/dialog-form.ts
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
import { css, html, LitElement, nothing } from "lit";
|
||||||
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
|
import "../../components/ha-button";
|
||||||
|
import { createCloseHeading } from "../../components/ha-dialog";
|
||||||
|
import "../../components/ha-form/ha-form";
|
||||||
|
import type { HomeAssistant } from "../../types";
|
||||||
|
import type { HassDialog } from "../make-dialog-manager";
|
||||||
|
import type { FormDialogData, FormDialogParams } from "./show-form-dialog";
|
||||||
|
import { haStyleDialog } from "../../resources/styles";
|
||||||
|
|
||||||
|
@customElement("dialog-form")
|
||||||
|
export class DialogForm
|
||||||
|
extends LitElement
|
||||||
|
implements HassDialog<FormDialogData>
|
||||||
|
{
|
||||||
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||||
|
|
||||||
|
@state() private _params?: FormDialogParams;
|
||||||
|
|
||||||
|
@state() private _data: FormDialogData = {};
|
||||||
|
|
||||||
|
public async showDialog(params: FormDialogParams): Promise<void> {
|
||||||
|
this._params = params;
|
||||||
|
this._data = params.data || {};
|
||||||
|
}
|
||||||
|
|
||||||
|
public closeDialog() {
|
||||||
|
this._params = undefined;
|
||||||
|
this._data = {};
|
||||||
|
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _submit(): void {
|
||||||
|
this._params?.submit?.(this._data);
|
||||||
|
this.closeDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _cancel(): void {
|
||||||
|
this._params?.cancel?.();
|
||||||
|
this.closeDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _valueChanged(ev: CustomEvent): void {
|
||||||
|
this._data = ev.detail.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render() {
|
||||||
|
if (!this._params || !this.hass) {
|
||||||
|
return nothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<ha-dialog
|
||||||
|
open
|
||||||
|
scrimClickAction
|
||||||
|
escapeKeyAction
|
||||||
|
.heading=${createCloseHeading(this.hass, this._params.title)}
|
||||||
|
@closed=${this._cancel}
|
||||||
|
>
|
||||||
|
<ha-form
|
||||||
|
dialogInitialFocus
|
||||||
|
.hass=${this.hass}
|
||||||
|
.computeLabel=${this._params.computeLabel}
|
||||||
|
.computeHelper=${this._params.computeHelper}
|
||||||
|
.data=${this._data}
|
||||||
|
.schema=${this._params.schema}
|
||||||
|
@value-changed=${this._valueChanged}
|
||||||
|
>
|
||||||
|
</ha-form>
|
||||||
|
<ha-button @click=${this._cancel} slot="secondaryAction">
|
||||||
|
${this._params.cancelText || this.hass.localize("ui.common.cancel")}
|
||||||
|
</ha-button>
|
||||||
|
<ha-button @click=${this._submit} slot="primaryAction">
|
||||||
|
${this._params.submitText || this.hass.localize("ui.common.save")}
|
||||||
|
</ha-button>
|
||||||
|
</ha-dialog>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
static styles = [haStyleDialog, css``];
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"dialog-form": DialogForm;
|
||||||
|
}
|
||||||
|
}
|
45
src/dialogs/form/show-form-dialog.ts
Normal file
45
src/dialogs/form/show-form-dialog.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
|
import type { HaFormSchema } from "../../components/ha-form/types";
|
||||||
|
|
||||||
|
export type FormDialogData = Record<string, any>;
|
||||||
|
|
||||||
|
export interface FormDialogParams {
|
||||||
|
title: string;
|
||||||
|
schema: HaFormSchema[];
|
||||||
|
data?: FormDialogData;
|
||||||
|
submit?: (data?: FormDialogData) => void;
|
||||||
|
cancel?: () => void;
|
||||||
|
computeLabel?: (schema, data) => string | undefined;
|
||||||
|
computeHelper?: (schema) => string | undefined;
|
||||||
|
submitText?: string;
|
||||||
|
cancelText?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const showFormDialog = (
|
||||||
|
element: HTMLElement,
|
||||||
|
dialogParams: FormDialogParams
|
||||||
|
) =>
|
||||||
|
new Promise<FormDialogData | null>((resolve) => {
|
||||||
|
const origCancel = dialogParams.cancel;
|
||||||
|
const origSubmit = dialogParams.submit;
|
||||||
|
|
||||||
|
fireEvent(element, "show-dialog", {
|
||||||
|
dialogTag: "dialog-form",
|
||||||
|
dialogImport: () => import("./dialog-form"),
|
||||||
|
dialogParams: {
|
||||||
|
...dialogParams,
|
||||||
|
cancel: () => {
|
||||||
|
resolve(null);
|
||||||
|
if (origCancel) {
|
||||||
|
origCancel();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
submit: (data: FormDialogData) => {
|
||||||
|
resolve(data);
|
||||||
|
if (origSubmit) {
|
||||||
|
origSubmit(data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user