mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-19 23:36:36 +00:00
Add category and labels to automation/script save and rename dialog (#23240)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
parent
523c38a83e
commit
5cd6f22e99
@ -3,7 +3,7 @@
|
|||||||
// Returns a function, that, as long as it continues to be invoked, will not
|
// Returns a function, that, as long as it continues to be invoked, will not
|
||||||
// be triggered. The function will be called after it stops being called for
|
// be triggered. The function will be called after it stops being called for
|
||||||
// N milliseconds. If `immediate` is passed, trigger the function on the
|
// N milliseconds. If `immediate` is passed, trigger the function on the
|
||||||
// leading edge, instead of the trailing.
|
// leading edge and on the trailing.
|
||||||
|
|
||||||
export const debounce = <T extends any[]>(
|
export const debounce = <T extends any[]>(
|
||||||
func: (...args: T) => void,
|
func: (...args: T) => void,
|
||||||
@ -14,9 +14,7 @@ export const debounce = <T extends any[]>(
|
|||||||
const debouncedFunc = (...args: T): void => {
|
const debouncedFunc = (...args: T): void => {
|
||||||
const later = () => {
|
const later = () => {
|
||||||
timeout = undefined;
|
timeout = undefined;
|
||||||
if (!immediate) {
|
func(...args);
|
||||||
func(...args);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
const callNow = immediate && !timeout;
|
const callNow = immediate && !timeout;
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
|
@ -19,6 +19,9 @@ export class HaFab extends FabBase {
|
|||||||
margin-inline-end: 12px;
|
margin-inline-end: 12px;
|
||||||
direction: var(--direction);
|
direction: var(--direction);
|
||||||
}
|
}
|
||||||
|
:disabled {
|
||||||
|
opacity: var(--light-disabled-opacity);
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
// safari workaround - must be explicit
|
// safari workaround - must be explicit
|
||||||
mainWindow.document.dir === "rtl"
|
mainWindow.document.dir === "rtl"
|
||||||
|
@ -30,7 +30,7 @@ export const PreventUnsavedMixin = <T extends Constructor<LitElement>>(
|
|||||||
window.removeEventListener("beforeunload", this._handleUnload);
|
window.removeEventListener("beforeunload", this._handleUnload);
|
||||||
}
|
}
|
||||||
|
|
||||||
public willUpdate(changedProperties: PropertyValues): void {
|
protected willUpdate(changedProperties: PropertyValues): void {
|
||||||
super.willUpdate(changedProperties);
|
super.willUpdate(changedProperties);
|
||||||
|
|
||||||
if (this.isDirty) {
|
if (this.isDirty) {
|
||||||
|
@ -2,19 +2,25 @@ import "@material/mwc-button";
|
|||||||
import type { CSSResultGroup } from "lit";
|
import type { CSSResultGroup } from "lit";
|
||||||
import { css, html, LitElement, nothing } from "lit";
|
import { css, html, LitElement, nothing } from "lit";
|
||||||
import { customElement, property, state } from "lit/decorators";
|
import { customElement, property, state } from "lit/decorators";
|
||||||
|
import { mdiClose, mdiPlus } from "@mdi/js";
|
||||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
import "../../../../components/ha-alert";
|
import "../../../../components/ha-alert";
|
||||||
import { createCloseHeading } from "../../../../components/ha-dialog";
|
|
||||||
import "../../../../components/ha-domain-icon";
|
import "../../../../components/ha-domain-icon";
|
||||||
import "../../../../components/ha-icon-picker";
|
import "../../../../components/ha-icon-picker";
|
||||||
import "../../../../components/ha-textarea";
|
import "../../../../components/ha-textarea";
|
||||||
import "../../../../components/ha-textfield";
|
import "../../../../components/ha-textfield";
|
||||||
|
import "../../../../components/ha-labels-picker";
|
||||||
|
import "../../category/ha-category-picker";
|
||||||
|
import "../../../../components/ha-expansion-panel";
|
||||||
|
import "../../../../components/chips/ha-chip-set";
|
||||||
|
import "../../../../components/chips/ha-assist-chip";
|
||||||
|
|
||||||
import type { HassDialog } from "../../../../dialogs/make-dialog-manager";
|
import type { HassDialog } from "../../../../dialogs/make-dialog-manager";
|
||||||
import { haStyle, haStyleDialog } from "../../../../resources/styles";
|
import { haStyle, haStyleDialog } from "../../../../resources/styles";
|
||||||
import type { HomeAssistant } from "../../../../types";
|
import type { HomeAssistant } from "../../../../types";
|
||||||
import type {
|
import type {
|
||||||
AutomationRenameDialogParams,
|
AutomationRenameDialogParams,
|
||||||
|
EntityRegistryUpdate,
|
||||||
ScriptRenameDialogParams,
|
ScriptRenameDialogParams,
|
||||||
} from "./show-dialog-automation-rename";
|
} from "./show-dialog-automation-rename";
|
||||||
|
|
||||||
@ -26,6 +32,10 @@ class DialogAutomationRename extends LitElement implements HassDialog {
|
|||||||
|
|
||||||
@state() private _error?: string;
|
@state() private _error?: string;
|
||||||
|
|
||||||
|
@state() private _visibleOptionals: string[] = [];
|
||||||
|
|
||||||
|
@state() private _entryUpdates!: EntityRegistryUpdate;
|
||||||
|
|
||||||
private _params!: AutomationRenameDialogParams | ScriptRenameDialogParams;
|
private _params!: AutomationRenameDialogParams | ScriptRenameDialogParams;
|
||||||
|
|
||||||
private _newName?: string;
|
private _newName?: string;
|
||||||
@ -46,6 +56,17 @@ class DialogAutomationRename extends LitElement implements HassDialog {
|
|||||||
`ui.panel.config.${this._params.domain}.editor.default_name`
|
`ui.panel.config.${this._params.domain}.editor.default_name`
|
||||||
);
|
);
|
||||||
this._newDescription = params.config.description || "";
|
this._newDescription = params.config.description || "";
|
||||||
|
this._entryUpdates = params.entityRegistryUpdate || {
|
||||||
|
labels: params.entityRegistryEntry?.labels || [],
|
||||||
|
category: params.entityRegistryEntry?.categories[params.domain] || "",
|
||||||
|
};
|
||||||
|
|
||||||
|
this._visibleOptionals = [
|
||||||
|
this._newDescription ? "description" : "",
|
||||||
|
this._newIcon ? "icon" : "",
|
||||||
|
this._entryUpdates.category ? "category" : "",
|
||||||
|
this._entryUpdates.labels.length > 0 ? "labels" : "",
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public closeDialog(): void {
|
public closeDialog(): void {
|
||||||
@ -55,6 +76,19 @@ class DialogAutomationRename extends LitElement implements HassDialog {
|
|||||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||||
}
|
}
|
||||||
this._opened = false;
|
this._opened = false;
|
||||||
|
this._visibleOptionals = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected _renderOptionalChip(id: string, label: string) {
|
||||||
|
if (this._visibleOptionals.includes(id)) {
|
||||||
|
return nothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<ha-assist-chip id=${id} @click=${this._addOptional} label=${label}>
|
||||||
|
<ha-svg-icon slot="icon" .path=${mdiPlus}></ha-svg-icon>
|
||||||
|
</ha-assist-chip>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
@ -66,15 +100,27 @@ class DialogAutomationRename extends LitElement implements HassDialog {
|
|||||||
open
|
open
|
||||||
scrimClickAction
|
scrimClickAction
|
||||||
@closed=${this.closeDialog}
|
@closed=${this.closeDialog}
|
||||||
.heading=${createCloseHeading(
|
.heading=${this.hass.localize(
|
||||||
this.hass,
|
this._params.config.alias
|
||||||
this.hass.localize(
|
? "ui.panel.config.automation.editor.rename"
|
||||||
this._params.config.alias
|
: "ui.panel.config.automation.editor.save"
|
||||||
? "ui.panel.config.automation.editor.rename"
|
|
||||||
: "ui.panel.config.automation.editor.save"
|
|
||||||
)
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
<ha-dialog-header slot="heading">
|
||||||
|
<ha-icon-button
|
||||||
|
slot="navigationIcon"
|
||||||
|
dialogAction="cancel"
|
||||||
|
.label=${this.hass.localize("ui.common.close")}
|
||||||
|
.path=${mdiClose}
|
||||||
|
></ha-icon-button>
|
||||||
|
<span slot="title"
|
||||||
|
>${this.hass.localize(
|
||||||
|
this._params.config.alias
|
||||||
|
? "ui.panel.config.automation.editor.rename"
|
||||||
|
: "ui.panel.config.automation.editor.save"
|
||||||
|
)}</span
|
||||||
|
>
|
||||||
|
</ha-dialog-header>
|
||||||
${this._error
|
${this._error
|
||||||
? html`<ha-alert alert-type="error"
|
? html`<ha-alert alert-type="error"
|
||||||
>${this.hass.localize(
|
>${this.hass.localize(
|
||||||
@ -96,7 +142,8 @@ class DialogAutomationRename extends LitElement implements HassDialog {
|
|||||||
@input=${this._valueChanged}
|
@input=${this._valueChanged}
|
||||||
></ha-textfield>
|
></ha-textfield>
|
||||||
|
|
||||||
${this._params.domain === "script"
|
${this._params.domain === "script" &&
|
||||||
|
this._visibleOptionals.includes("icon")
|
||||||
? html`
|
? html`
|
||||||
<ha-icon-picker
|
<ha-icon-picker
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
@ -115,33 +162,97 @@ class DialogAutomationRename extends LitElement implements HassDialog {
|
|||||||
</ha-icon-picker>
|
</ha-icon-picker>
|
||||||
`
|
`
|
||||||
: nothing}
|
: nothing}
|
||||||
<ha-textarea
|
${this._visibleOptionals.includes("description")
|
||||||
.label=${this.hass.localize(
|
? html` <ha-textarea
|
||||||
"ui.panel.config.automation.editor.description.label"
|
.label=${this.hass.localize(
|
||||||
)}
|
"ui.panel.config.automation.editor.description.label"
|
||||||
.placeholder=${this.hass.localize(
|
)}
|
||||||
"ui.panel.config.automation.editor.description.placeholder"
|
.placeholder=${this.hass.localize(
|
||||||
)}
|
"ui.panel.config.automation.editor.description.placeholder"
|
||||||
name="description"
|
)}
|
||||||
autogrow
|
name="description"
|
||||||
.value=${this._newDescription}
|
autogrow
|
||||||
@input=${this._valueChanged}
|
.value=${this._newDescription}
|
||||||
></ha-textarea>
|
@input=${this._valueChanged}
|
||||||
|
></ha-textarea>`
|
||||||
|
: nothing}
|
||||||
|
${this._visibleOptionals.includes("category")
|
||||||
|
? html` <ha-category-picker
|
||||||
|
id="category"
|
||||||
|
.hass=${this.hass}
|
||||||
|
.scope=${this._params.domain}
|
||||||
|
.value=${this._entryUpdates.category}
|
||||||
|
@value-changed=${this._registryEntryChanged}
|
||||||
|
></ha-category-picker>`
|
||||||
|
: nothing}
|
||||||
|
${this._visibleOptionals.includes("labels")
|
||||||
|
? html` <ha-labels-picker
|
||||||
|
id="labels"
|
||||||
|
.hass=${this.hass}
|
||||||
|
.value=${this._entryUpdates.labels}
|
||||||
|
@value-changed=${this._registryEntryChanged}
|
||||||
|
></ha-labels-picker>`
|
||||||
|
: nothing}
|
||||||
|
|
||||||
<mwc-button @click=${this.closeDialog} slot="secondaryAction">
|
<ha-chip-set>
|
||||||
${this.hass.localize("ui.dialogs.generic.cancel")}
|
${this._renderOptionalChip(
|
||||||
</mwc-button>
|
"description",
|
||||||
<mwc-button @click=${this._save} slot="primaryAction">
|
this.hass.localize(
|
||||||
${this.hass.localize(
|
"ui.panel.config.automation.editor.dialog.add_description"
|
||||||
this._params.config.alias
|
)
|
||||||
? "ui.panel.config.automation.editor.rename"
|
|
||||||
: "ui.panel.config.automation.editor.save"
|
|
||||||
)}
|
)}
|
||||||
</mwc-button>
|
${this._params.domain === "script"
|
||||||
|
? this._renderOptionalChip(
|
||||||
|
"icon",
|
||||||
|
this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.dialog.add_icon"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
: nothing}
|
||||||
|
${this._renderOptionalChip(
|
||||||
|
"category",
|
||||||
|
this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.dialog.add_category"
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
${this._renderOptionalChip(
|
||||||
|
"labels",
|
||||||
|
this.hass.localize(
|
||||||
|
"ui.panel.config.automation.editor.dialog.add_labels"
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</ha-chip-set>
|
||||||
|
|
||||||
|
<div slot="primaryAction">
|
||||||
|
<mwc-button @click=${this.closeDialog}>
|
||||||
|
${this.hass.localize("ui.dialogs.generic.cancel")}
|
||||||
|
</mwc-button>
|
||||||
|
<mwc-button @click=${this._save}>
|
||||||
|
${this.hass.localize(
|
||||||
|
this._params.config.alias
|
||||||
|
? "ui.panel.config.automation.editor.rename"
|
||||||
|
: "ui.panel.config.automation.editor.save"
|
||||||
|
)}
|
||||||
|
</mwc-button>
|
||||||
|
</div>
|
||||||
</ha-dialog>
|
</ha-dialog>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _addOptional(ev) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
const option: string = ev.target.id;
|
||||||
|
this._visibleOptionals = [...this._visibleOptionals, option];
|
||||||
|
}
|
||||||
|
|
||||||
|
private _registryEntryChanged(ev) {
|
||||||
|
ev.stopPropagation();
|
||||||
|
const id: string = ev.target.id;
|
||||||
|
const value = ev.detail.value;
|
||||||
|
|
||||||
|
this._entryUpdates = { ...this._entryUpdates, [id]: value };
|
||||||
|
}
|
||||||
|
|
||||||
private _iconChanged(ev: CustomEvent) {
|
private _iconChanged(ev: CustomEvent) {
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
this._newIcon = ev.detail.value || undefined;
|
this._newIcon = ev.detail.value || undefined;
|
||||||
@ -162,19 +273,26 @@ class DialogAutomationRename extends LitElement implements HassDialog {
|
|||||||
this._error = "Name is required";
|
this._error = "Name is required";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._params.domain === "script") {
|
if (this._params.domain === "script") {
|
||||||
this._params.updateConfig({
|
this._params.updateConfig(
|
||||||
...this._params.config,
|
{
|
||||||
alias: this._newName,
|
...this._params.config,
|
||||||
description: this._newDescription,
|
alias: this._newName,
|
||||||
icon: this._newIcon,
|
description: this._newDescription,
|
||||||
});
|
icon: this._newIcon,
|
||||||
|
},
|
||||||
|
this._entryUpdates
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
this._params.updateConfig({
|
this._params.updateConfig(
|
||||||
...this._params.config,
|
{
|
||||||
alias: this._newName,
|
...this._params.config,
|
||||||
description: this._newDescription,
|
alias: this._newName,
|
||||||
});
|
description: this._newDescription,
|
||||||
|
},
|
||||||
|
this._entryUpdates
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.closeDialog();
|
this.closeDialog();
|
||||||
@ -185,12 +303,21 @@ class DialogAutomationRename extends LitElement implements HassDialog {
|
|||||||
haStyle,
|
haStyle,
|
||||||
haStyleDialog,
|
haStyleDialog,
|
||||||
css`
|
css`
|
||||||
|
ha-dialog {
|
||||||
|
--dialog-content-padding: 0 24px 24px 24px;
|
||||||
|
}
|
||||||
ha-textfield,
|
ha-textfield,
|
||||||
ha-textarea,
|
ha-textarea,
|
||||||
ha-icon-picker {
|
ha-icon-picker,
|
||||||
|
ha-category-picker,
|
||||||
|
ha-labels-picker,
|
||||||
|
ha-chip-set {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
ha-icon-picker {
|
ha-icon-picker,
|
||||||
|
ha-category-picker,
|
||||||
|
ha-labels-picker,
|
||||||
|
ha-chip-set {
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
ha-alert {
|
ha-alert {
|
||||||
|
@ -1,22 +1,38 @@
|
|||||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
import type { AutomationConfig } from "../../../../data/automation";
|
import type { AutomationConfig } from "../../../../data/automation";
|
||||||
import type { ScriptConfig } from "../../../../data/script";
|
import type { ScriptConfig } from "../../../../data/script";
|
||||||
|
import type { EntityRegistryEntry } from "../../../../data/entity_registry";
|
||||||
|
|
||||||
export const loadAutomationRenameDialog = () =>
|
export const loadAutomationRenameDialog = () =>
|
||||||
import("./dialog-automation-rename");
|
import("./dialog-automation-rename");
|
||||||
|
|
||||||
export interface AutomationRenameDialogParams {
|
interface BaseRenameDialogParams {
|
||||||
config: AutomationConfig;
|
entityRegistryUpdate?: EntityRegistryUpdate;
|
||||||
domain: "automation";
|
entityRegistryEntry?: EntityRegistryEntry;
|
||||||
updateConfig: (config: AutomationConfig) => void;
|
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ScriptRenameDialogParams {
|
export interface EntityRegistryUpdate {
|
||||||
|
labels: string[];
|
||||||
|
category: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AutomationRenameDialogParams extends BaseRenameDialogParams {
|
||||||
|
config: AutomationConfig;
|
||||||
|
domain: "automation";
|
||||||
|
updateConfig: (
|
||||||
|
config: AutomationConfig,
|
||||||
|
entityRegistryUpdate: EntityRegistryUpdate
|
||||||
|
) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ScriptRenameDialogParams extends BaseRenameDialogParams {
|
||||||
config: ScriptConfig;
|
config: ScriptConfig;
|
||||||
domain: "script";
|
domain: "script";
|
||||||
updateConfig: (config: ScriptConfig) => void;
|
updateConfig: (
|
||||||
onClose: () => void;
|
config: ScriptConfig,
|
||||||
|
entityRegistryUpdate: EntityRegistryUpdate
|
||||||
|
) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const showAutomationRenameDialog = (
|
export const showAutomationRenameDialog = (
|
||||||
|
@ -53,8 +53,8 @@ import { substituteBlueprint } from "../../../data/blueprint";
|
|||||||
import { validateConfig } from "../../../data/config";
|
import { validateConfig } from "../../../data/config";
|
||||||
import { UNAVAILABLE } from "../../../data/entity";
|
import { UNAVAILABLE } from "../../../data/entity";
|
||||||
import {
|
import {
|
||||||
fetchEntityRegistry,
|
|
||||||
type EntityRegistryEntry,
|
type EntityRegistryEntry,
|
||||||
|
updateEntityRegistryEntry,
|
||||||
} from "../../../data/entity_registry";
|
} from "../../../data/entity_registry";
|
||||||
import {
|
import {
|
||||||
showAlertDialog,
|
showAlertDialog,
|
||||||
@ -67,7 +67,10 @@ import type { Entries, HomeAssistant, Route } from "../../../types";
|
|||||||
import { showToast } from "../../../util/toast";
|
import { showToast } from "../../../util/toast";
|
||||||
import "../ha-config-section";
|
import "../ha-config-section";
|
||||||
import { showAutomationModeDialog } from "./automation-mode-dialog/show-dialog-automation-mode";
|
import { showAutomationModeDialog } from "./automation-mode-dialog/show-dialog-automation-mode";
|
||||||
import { showAutomationRenameDialog } from "./automation-rename-dialog/show-dialog-automation-rename";
|
import {
|
||||||
|
type EntityRegistryUpdate,
|
||||||
|
showAutomationRenameDialog,
|
||||||
|
} from "./automation-rename-dialog/show-dialog-automation-rename";
|
||||||
import "./blueprint-automation-editor";
|
import "./blueprint-automation-editor";
|
||||||
import "./manual-automation-editor";
|
import "./manual-automation-editor";
|
||||||
import { showMoreInfoDialog } from "../../../dialogs/more-info/show-ha-more-info-dialog";
|
import { showMoreInfoDialog } from "../../../dialogs/more-info/show-ha-more-info-dialog";
|
||||||
@ -137,6 +140,12 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
|||||||
})
|
})
|
||||||
private _registryEntry?: EntityRegistryEntry;
|
private _registryEntry?: EntityRegistryEntry;
|
||||||
|
|
||||||
|
@state() private _saving = false;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
@consume({ context: fullEntitiesContext, subscribe: true })
|
||||||
|
_entityRegistry!: EntityRegistryEntry[];
|
||||||
|
|
||||||
private _configSubscriptions: Record<
|
private _configSubscriptions: Record<
|
||||||
string,
|
string,
|
||||||
(config?: AutomationConfig) => void
|
(config?: AutomationConfig) => void
|
||||||
@ -144,6 +153,33 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
|||||||
|
|
||||||
private _configSubscriptionsId = 1;
|
private _configSubscriptionsId = 1;
|
||||||
|
|
||||||
|
private _entityRegistryUpdate?: EntityRegistryUpdate;
|
||||||
|
|
||||||
|
private _newAutomationId?: string;
|
||||||
|
|
||||||
|
private _entityRegCreated?: (
|
||||||
|
value: PromiseLike<EntityRegistryEntry> | EntityRegistryEntry
|
||||||
|
) => void;
|
||||||
|
|
||||||
|
protected willUpdate(changedProps) {
|
||||||
|
super.willUpdate(changedProps);
|
||||||
|
|
||||||
|
if (
|
||||||
|
this._entityRegCreated &&
|
||||||
|
this._newAutomationId &&
|
||||||
|
changedProps.has("entityRegistry")
|
||||||
|
) {
|
||||||
|
const automation = this._entityRegistry.find(
|
||||||
|
(entity: EntityRegistryEntry) =>
|
||||||
|
entity.unique_id === this._newAutomationId
|
||||||
|
);
|
||||||
|
if (automation) {
|
||||||
|
this._entityRegCreated(automation);
|
||||||
|
this._entityRegCreated = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult | typeof nothing {
|
protected render(): TemplateResult | typeof nothing {
|
||||||
if (!this._config) {
|
if (!this._config) {
|
||||||
return nothing;
|
return nothing;
|
||||||
@ -456,8 +492,11 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
|||||||
</div>
|
</div>
|
||||||
<ha-fab
|
<ha-fab
|
||||||
slot="fab"
|
slot="fab"
|
||||||
class=${classMap({ dirty: !this._readOnly && this._dirty })}
|
class=${classMap({
|
||||||
|
dirty: !this._readOnly && this._dirty,
|
||||||
|
})}
|
||||||
.label=${this.hass.localize("ui.panel.config.automation.editor.save")}
|
.label=${this.hass.localize("ui.panel.config.automation.editor.save")}
|
||||||
|
.disabled=${this._saving}
|
||||||
extended
|
extended
|
||||||
@click=${this._saveAutomation}
|
@click=${this._saveAutomation}
|
||||||
>
|
>
|
||||||
@ -577,8 +616,7 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
|||||||
this._config = normalizeAutomationConfig(config);
|
this._config = normalizeAutomationConfig(config);
|
||||||
this._checkValidation();
|
this._checkValidation();
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
const entityRegistry = await fetchEntityRegistry(this.hass.connection);
|
const entity = this._entityRegistry.find(
|
||||||
const entity = entityRegistry.find(
|
|
||||||
(ent) =>
|
(ent) =>
|
||||||
ent.platform === "automation" && ent.unique_id === this.automationId
|
ent.platform === "automation" && ent.unique_id === this.automationId
|
||||||
);
|
);
|
||||||
@ -841,13 +879,16 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
|||||||
showAutomationRenameDialog(this, {
|
showAutomationRenameDialog(this, {
|
||||||
config: this._config!,
|
config: this._config!,
|
||||||
domain: "automation",
|
domain: "automation",
|
||||||
updateConfig: (config) => {
|
updateConfig: (config, entityRegistryUpdate) => {
|
||||||
this._config = config;
|
this._config = config;
|
||||||
|
this._entityRegistryUpdate = entityRegistryUpdate;
|
||||||
this._dirty = true;
|
this._dirty = true;
|
||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
resolve(true);
|
resolve(true);
|
||||||
},
|
},
|
||||||
onClose: () => resolve(false),
|
onClose: () => resolve(false),
|
||||||
|
entityRegistryUpdate: this._entityRegistryUpdate,
|
||||||
|
entityRegistryEntry: this._registryEntry,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -883,21 +924,49 @@ export class HaAutomationEditor extends PreventUnsavedMixin(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._saving = true;
|
||||||
this._validationErrors = undefined;
|
this._validationErrors = undefined;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await saveAutomationConfig(this.hass, id, this._config!);
|
await saveAutomationConfig(this.hass, id, this._config!);
|
||||||
|
|
||||||
|
if (this._entityRegistryUpdate !== undefined) {
|
||||||
|
let entityId = this._entityId;
|
||||||
|
|
||||||
|
// wait for automation to appear in entity registry when creating a new automation
|
||||||
|
if (!entityId) {
|
||||||
|
this._newAutomationId = id;
|
||||||
|
const automation = await new Promise<EntityRegistryEntry>(
|
||||||
|
(resolve) => {
|
||||||
|
this._entityRegCreated = resolve;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
entityId = automation.entity_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entityId) {
|
||||||
|
await updateEntityRegistryEntry(this.hass, entityId, {
|
||||||
|
categories: {
|
||||||
|
automation: this._entityRegistryUpdate.category || null,
|
||||||
|
},
|
||||||
|
labels: this._entityRegistryUpdate.labels || [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._dirty = false;
|
||||||
|
|
||||||
|
if (!this.automationId) {
|
||||||
|
navigate(`/config/automation/edit/${id}`, { replace: true });
|
||||||
|
}
|
||||||
} catch (errors: any) {
|
} catch (errors: any) {
|
||||||
this._errors = errors.body.message || errors.error || errors.body;
|
this._errors = errors.body.message || errors.error || errors.body;
|
||||||
showToast(this, {
|
showToast(this, {
|
||||||
message: errors.body.message || errors.error || errors.body,
|
message: errors.body.message || errors.error || errors.body,
|
||||||
});
|
});
|
||||||
throw errors;
|
throw errors;
|
||||||
}
|
} finally {
|
||||||
|
this._saving = false;
|
||||||
this._dirty = false;
|
|
||||||
|
|
||||||
if (!this.automationId) {
|
|
||||||
navigate(`/config/automation/edit/${id}`, { replace: true });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,10 @@ import "../../../components/ha-svg-icon";
|
|||||||
import "../../../components/ha-yaml-editor";
|
import "../../../components/ha-yaml-editor";
|
||||||
import { validateConfig } from "../../../data/config";
|
import { validateConfig } from "../../../data/config";
|
||||||
import { UNAVAILABLE } from "../../../data/entity";
|
import { UNAVAILABLE } from "../../../data/entity";
|
||||||
import type { EntityRegistryEntry } from "../../../data/entity_registry";
|
import {
|
||||||
|
type EntityRegistryEntry,
|
||||||
|
updateEntityRegistryEntry,
|
||||||
|
} from "../../../data/entity_registry";
|
||||||
import type { BlueprintScriptConfig, ScriptConfig } from "../../../data/script";
|
import type { BlueprintScriptConfig, ScriptConfig } from "../../../data/script";
|
||||||
import {
|
import {
|
||||||
deleteScript,
|
deleteScript,
|
||||||
@ -58,6 +61,7 @@ import { haStyle } from "../../../resources/styles";
|
|||||||
import type { Entries, HomeAssistant, Route } from "../../../types";
|
import type { Entries, HomeAssistant, Route } from "../../../types";
|
||||||
import { showToast } from "../../../util/toast";
|
import { showToast } from "../../../util/toast";
|
||||||
import { showAutomationModeDialog } from "../automation/automation-mode-dialog/show-dialog-automation-mode";
|
import { showAutomationModeDialog } from "../automation/automation-mode-dialog/show-dialog-automation-mode";
|
||||||
|
import type { EntityRegistryUpdate } from "../automation/automation-rename-dialog/show-dialog-automation-rename";
|
||||||
import { showAutomationRenameDialog } from "../automation/automation-rename-dialog/show-dialog-automation-rename";
|
import { showAutomationRenameDialog } from "../automation/automation-rename-dialog/show-dialog-automation-rename";
|
||||||
import "./blueprint-script-editor";
|
import "./blueprint-script-editor";
|
||||||
import "./manual-script-editor";
|
import "./manual-script-editor";
|
||||||
@ -116,6 +120,34 @@ export class HaScriptEditor extends SubscribeMixin(
|
|||||||
|
|
||||||
@state() private _blueprintConfig?: BlueprintScriptConfig;
|
@state() private _blueprintConfig?: BlueprintScriptConfig;
|
||||||
|
|
||||||
|
@state() private _saving = false;
|
||||||
|
|
||||||
|
private _entityRegistryUpdate?: EntityRegistryUpdate;
|
||||||
|
|
||||||
|
private _newScriptId?: string;
|
||||||
|
|
||||||
|
private _entityRegCreated?: (
|
||||||
|
value: PromiseLike<EntityRegistryEntry> | EntityRegistryEntry
|
||||||
|
) => void;
|
||||||
|
|
||||||
|
protected willUpdate(changedProps) {
|
||||||
|
super.willUpdate(changedProps);
|
||||||
|
|
||||||
|
if (
|
||||||
|
this._entityRegCreated &&
|
||||||
|
this._newScriptId &&
|
||||||
|
changedProps.has("entityRegistry")
|
||||||
|
) {
|
||||||
|
const script = this.entityRegistry.find(
|
||||||
|
(entity: EntityRegistryEntry) => entity.unique_id === this._newScriptId
|
||||||
|
);
|
||||||
|
if (script) {
|
||||||
|
this._entityRegCreated(script);
|
||||||
|
this._entityRegCreated = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult | typeof nothing {
|
protected render(): TemplateResult | typeof nothing {
|
||||||
if (!this._config) {
|
if (!this._config) {
|
||||||
return nothing;
|
return nothing;
|
||||||
@ -410,11 +442,12 @@ export class HaScriptEditor extends SubscribeMixin(
|
|||||||
<ha-fab
|
<ha-fab
|
||||||
slot="fab"
|
slot="fab"
|
||||||
class=${classMap({
|
class=${classMap({
|
||||||
dirty: this._dirty,
|
dirty: !this._readOnly && this._dirty,
|
||||||
})}
|
})}
|
||||||
.label=${this.hass.localize(
|
.label=${this.hass.localize(
|
||||||
"ui.panel.config.script.editor.save_script"
|
"ui.panel.config.script.editor.save_script"
|
||||||
)}
|
)}
|
||||||
|
.disabled=${this._saving}
|
||||||
extended
|
extended
|
||||||
@click=${this._saveScript}
|
@click=${this._saveScript}
|
||||||
>
|
>
|
||||||
@ -812,13 +845,18 @@ export class HaScriptEditor extends SubscribeMixin(
|
|||||||
showAutomationRenameDialog(this, {
|
showAutomationRenameDialog(this, {
|
||||||
config: this._config!,
|
config: this._config!,
|
||||||
domain: "script",
|
domain: "script",
|
||||||
updateConfig: (config) => {
|
updateConfig: (config, entityRegistryUpdate) => {
|
||||||
this._config = config;
|
this._config = config;
|
||||||
|
this._entityRegistryUpdate = entityRegistryUpdate;
|
||||||
this._dirty = true;
|
this._dirty = true;
|
||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
resolve(true);
|
resolve(true);
|
||||||
},
|
},
|
||||||
onClose: () => resolve(false),
|
onClose: () => resolve(false),
|
||||||
|
entityRegistryUpdate: this._entityRegistryUpdate,
|
||||||
|
entityRegistryEntry: this.entityRegistry.find(
|
||||||
|
(entry) => entry.unique_id === this.scriptId
|
||||||
|
),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -855,24 +893,48 @@ export class HaScriptEditor extends SubscribeMixin(
|
|||||||
}
|
}
|
||||||
const id = this.scriptId || this._entityId || Date.now();
|
const id = this.scriptId || this._entityId || Date.now();
|
||||||
|
|
||||||
|
this._saving = true;
|
||||||
try {
|
try {
|
||||||
await this.hass!.callApi(
|
await this.hass!.callApi(
|
||||||
"POST",
|
"POST",
|
||||||
"config/script/config/" + id,
|
"config/script/config/" + id,
|
||||||
this._config
|
this._config
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (this._entityRegistryUpdate !== undefined) {
|
||||||
|
let entityId = id.toString().startsWith("script.")
|
||||||
|
? id.toString()
|
||||||
|
: `script.${id}`;
|
||||||
|
|
||||||
|
// wait for new script to appear in entity registry
|
||||||
|
if (!this.scriptId) {
|
||||||
|
const script = await new Promise<EntityRegistryEntry>((resolve) => {
|
||||||
|
this._entityRegCreated = resolve;
|
||||||
|
});
|
||||||
|
entityId = script.entity_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
await updateEntityRegistryEntry(this.hass, entityId, {
|
||||||
|
categories: {
|
||||||
|
script: this._entityRegistryUpdate.category || null,
|
||||||
|
},
|
||||||
|
labels: this._entityRegistryUpdate.labels || [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this._dirty = false;
|
||||||
|
|
||||||
|
if (!this.scriptId) {
|
||||||
|
navigate(`/config/script/edit/${id}`, { replace: true });
|
||||||
|
}
|
||||||
} catch (errors: any) {
|
} catch (errors: any) {
|
||||||
this._errors = errors.body.message || errors.error || errors.body;
|
this._errors = errors.body.message || errors.error || errors.body;
|
||||||
showToast(this, {
|
showToast(this, {
|
||||||
message: errors.body.message || errors.error || errors.body,
|
message: errors.body.message || errors.error || errors.body,
|
||||||
});
|
});
|
||||||
throw errors;
|
throw errors;
|
||||||
}
|
} finally {
|
||||||
|
this._saving = false;
|
||||||
this._dirty = false;
|
|
||||||
|
|
||||||
if (!this.scriptId) {
|
|
||||||
navigate(`/config/script/edit/${id}`, { replace: true });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3708,6 +3708,12 @@
|
|||||||
"label": "Unknown"
|
"label": "Unknown"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"dialog": {
|
||||||
|
"add_description": "Add description",
|
||||||
|
"add_icon": "Add icon",
|
||||||
|
"add_category": "Add category",
|
||||||
|
"add_labels": "Add labels"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"trace": {
|
"trace": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user