Use unique id for script (#13817)

Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
Paul Bottein 2022-09-28 11:27:09 +02:00 committed by GitHub
parent 3959a7475c
commit fc86a66c33
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 100 additions and 93 deletions

View File

@ -15,7 +15,6 @@ import {
Describe,
boolean,
} from "superstruct";
import { computeObjectId } from "../common/entity/compute_object_id";
import { navigate } from "../common/navigate";
import { HomeAssistant } from "../types";
import {
@ -278,9 +277,9 @@ export type ActionType = keyof ActionTypes;
export const triggerScript = (
hass: HomeAssistant,
entityId: string,
scriptId: string,
variables?: Record<string, unknown>
) => hass.callService("script", computeObjectId(entityId), variables);
) => hass.callService("script", scriptId, variables);
export const canRun = (state: ScriptEntity) => {
if (state.state === "off") {

View File

@ -88,8 +88,8 @@ class HaConfigScript extends HassRouterPage {
this._currentPage !== "dashboard"
) {
pageEl.creatingNew = undefined;
const scriptEntityId = this.routeTail.path.substr(1);
pageEl.scriptEntityId = scriptEntityId === "new" ? null : scriptEntityId;
const scriptId = this.routeTail.path.substr(1);
pageEl.scriptId = scriptId === "new" ? null : scriptId;
}
}
}

View File

@ -24,7 +24,6 @@ import { property, query, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../../common/dom/fire_event";
import { computeObjectId } from "../../../common/entity/compute_object_id";
import { navigate } from "../../../common/navigate";
import { slugify } from "../../../common/string/slugify";
import { computeRTL } from "../../../common/util/compute_rtl";
@ -68,7 +67,7 @@ import type { HaManualScriptEditor } from "./manual-script-editor";
export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
@property({ attribute: false }) public hass!: HomeAssistant;
@property() public scriptEntityId: string | null = null;
@property() public scriptId: string | null = null;
@property({ attribute: false }) public route!: Route;
@ -162,7 +161,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
}
const schema = this._schema(
!!this.scriptEntityId,
!!this.scriptId,
"use_blueprint" in this._config,
this._config.mode
);
@ -183,7 +182,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
.backCallback=${this._backTapped}
.header=${!this._config?.alias ? "" : this._config.alias}
>
${this.scriptEntityId && !this.narrow
${this.scriptId && !this.narrow
? html`
<mwc-button @click=${this._showTrace} slot="toolbar-icon">
${this.hass.localize(
@ -201,7 +200,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
<mwc-list-item
graphic="icon"
.disabled=${!this.scriptEntityId}
.disabled=${!this.scriptId}
@click=${this._showInfo}
>
${this.hass.localize("ui.panel.config.script.editor.show_info")}
@ -213,16 +212,16 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
<mwc-list-item
graphic="icon"
.disabled=${!this.scriptEntityId}
.disabled=${!this.scriptId}
@click=${this._runScript}
>
${this.hass.localize("ui.panel.config.script.picker.run_script")}
<ha-svg-icon slot="graphic" .path=${mdiPlay}></ha-svg-icon>
</mwc-list-item>
${this.scriptEntityId && this.narrow
${this.scriptId && this.narrow
? html`
<a href="/config/script/trace/${this.scriptEntityId}">
<a href="/config/script/trace/${this.scriptId}">
<mwc-list-item graphic="icon">
${this.hass.localize(
"ui.panel.config.script.editor.show_trace"
@ -295,7 +294,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
<li divider role="separator"></li>
<mwc-list-item
.disabled=${!this.scriptEntityId}
.disabled=${!this.scriptId}
.label=${this.hass.localize(
"ui.panel.config.script.picker.duplicate"
)}
@ -310,17 +309,17 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
</mwc-list-item>
<mwc-list-item
.disabled=${!this.scriptEntityId}
.disabled=${!this.scriptId}
aria-label=${this.hass.localize(
"ui.panel.config.script.picker.delete"
)}
class=${classMap({ warning: Boolean(this.scriptEntityId) })}
class=${classMap({ warning: Boolean(this.scriptId) })}
graphic="icon"
@click=${this._deleteConfirm}
>
${this.hass.localize("ui.panel.config.script.picker.delete")}
<ha-svg-icon
class=${classMap({ warning: Boolean(this.scriptEntityId) })}
class=${classMap({ warning: Boolean(this.scriptId) })}
slot="graphic"
.path=${mdiDelete}
>
@ -430,15 +429,15 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
protected updated(changedProps: PropertyValues): void {
super.updated(changedProps);
const oldScript = changedProps.get("scriptEntityId");
const oldScript = changedProps.get("scriptId");
if (
changedProps.has("scriptEntityId") &&
this.scriptEntityId &&
changedProps.has("scriptId") &&
this.scriptId &&
this.hass &&
// Only refresh config if we picked a new script. If same ID, don't fetch it.
(!oldScript || oldScript !== this.scriptEntityId)
(!oldScript || oldScript !== this.scriptId)
) {
getScriptConfig(this.hass, computeObjectId(this.scriptEntityId)).then(
getScriptConfig(this.hass, this.scriptId).then(
(config) => {
// Normalize data: ensure sequence is a list
// Happens when people copy paste their scripts into the config
@ -458,7 +457,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
: this.hass.localize(
"ui.panel.config.script.editor.load_error_unknown",
"err_no",
resp.status_code
resp.status_code || resp.code
)
);
history.back();
@ -466,11 +465,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
);
}
if (
changedProps.has("scriptEntityId") &&
!this.scriptEntityId &&
this.hass
) {
if (changedProps.has("scriptId") && !this.scriptId && this.hass) {
const initData = getScriptEditorInitData();
this._dirty = !!initData;
const baseConfig: Partial<ScriptConfig> = {
@ -530,24 +525,30 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
};
private async _showInfo() {
if (!this.scriptEntityId) {
if (!this.scriptId) {
return;
}
fireEvent(this, "hass-more-info", { entityId: this.scriptEntityId });
const entity = Object.values(this.hass.entities).find(
(entry) => entry.unique_id === this.scriptId
);
if (!entity) {
return;
}
fireEvent(this, "hass-more-info", { entityId: entity.entity_id });
}
private async _showTrace() {
if (this.scriptEntityId) {
if (this.scriptId) {
const result = await this.confirmUnsavedChanged();
if (result) {
navigate(`/config/script/trace/${this.scriptEntityId}`);
navigate(`/config/script/trace/${this.scriptId}`);
}
}
}
private async _runScript(ev: CustomEvent) {
ev.stopPropagation();
await triggerScript(this.hass, this.scriptEntityId as string);
await triggerScript(this.hass, this.scriptId!);
showToast(this, {
message: this.hass.localize(
"ui.notification_toast.triggered",
@ -613,7 +614,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
max: isMaxMode(values.mode) ? values.max : undefined,
};
if (!this.scriptEntityId) {
if (!this.scriptId) {
this.updateEntityId(values.id, values.alias);
}
@ -720,10 +721,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
}
private async _delete() {
await deleteScript(
this.hass,
computeObjectId(this.scriptEntityId as string)
);
await deleteScript(this.hass, this.scriptId!);
history.back();
}
@ -741,7 +739,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
}
}
private _saveScript(): void {
private async _saveScript(): Promise<void> {
if (this._idError) {
showToast(this, {
message: this.hass.localize(
@ -756,24 +754,27 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
});
return;
}
const id = this.scriptEntityId
? computeObjectId(this.scriptEntityId)
: this._entityId || Date.now();
this.hass!.callApi("POST", "config/script/config/" + id, this._config).then(
() => {
this._dirty = false;
if (!this.scriptEntityId) {
navigate(`/config/script/edit/${id}`, { replace: true });
}
},
(errors) => {
this._errors = errors.body.message || errors.error || errors.body;
showToast(this, {
message: errors.body.message || errors.error || errors.body,
});
throw errors;
}
);
const id = this.scriptId || this._entityId || Date.now();
try {
await this.hass!.callApi(
"POST",
"config/script/config/" + id,
this._config
);
} catch (errors: any) {
this._errors = errors.body.message || errors.error || errors.body;
showToast(this, {
message: errors.body.message || errors.error || errors.body,
});
throw errors;
}
this._dirty = false;
if (!this.scriptId) {
navigate(`/config/script/edit/${id}`, { replace: true });
}
}
protected handleKeyboardSave() {

View File

@ -13,7 +13,6 @@ import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { formatDateTime } from "../../../common/datetime/format_date_time";
import { fireEvent, HASSDomEvent } from "../../../common/dom/fire_event";
import { computeObjectId } from "../../../common/entity/compute_object_id";
import { computeStateName } from "../../../common/entity/compute_state_name";
import { navigate } from "../../../common/navigate";
import { computeRTL } from "../../../common/util/compute_rtl";
@ -252,11 +251,15 @@ class HaScriptPicker extends LitElement {
}
private _handleRowClicked(ev: HASSDomEvent<RowClickedEvent>) {
navigate(`/config/script/edit/${ev.detail.id}`);
const entry = this.hass.entities[ev.detail.id];
if (entry) {
navigate(`/config/script/edit/${entry.unique_id}`);
}
}
private _runScript = async (script: any) => {
await triggerScript(this.hass, script.entity_id);
const entry = this.hass.entities[script.entity_id];
await triggerScript(this.hass, entry.unique_id);
showToast(this, {
message: this.hass.localize(
"ui.notification_toast.triggered",
@ -271,7 +274,10 @@ class HaScriptPicker extends LitElement {
}
private _showTrace(script: any) {
navigate(`/config/script/trace/${script.entity_id}`);
const entry = this.hass.entities[script.entity_id];
if (entry) {
navigate(`/config/script/trace/${entry.unique_id}`);
}
}
private _showHelp() {
@ -294,10 +300,8 @@ class HaScriptPicker extends LitElement {
private async _duplicate(script: any) {
try {
const config = await getScriptConfig(
this.hass,
computeObjectId(script.entity_id)
);
const entry = this.hass.entities[script.entity_id];
const config = await getScriptConfig(this.hass, entry.unique_id);
showScriptEditor({
...config,
alias: `${config?.alias} (${this.hass.localize(
@ -338,7 +342,8 @@ class HaScriptPicker extends LitElement {
private async _delete(script: any) {
try {
await deleteScript(this.hass, computeObjectId(script.entity_id));
const entry = this.hass.entities[script.entity_id];
await deleteScript(this.hass, entry.unique_id);
} catch (err: any) {
await showAlertDialog(this, {
text:

View File

@ -44,7 +44,7 @@ import { fireEvent } from "../../../common/dom/fire_event";
export class HaScriptTrace extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;
@property() public scriptEntityId!: string;
@property() public scriptId!: string;
@property({ attribute: false }) public scripts!: ScriptEntity[];
@ -54,6 +54,8 @@ export class HaScriptTrace extends LitElement {
@property({ attribute: false }) public route!: Route;
@state() private _entityId?: string;
@state() private _traces?: ScriptTrace[];
@state() private _runId?: string;
@ -74,15 +76,15 @@ export class HaScriptTrace extends LitElement {
@query("hat-script-graph") private _graph?: HatScriptGraph;
protected render(): TemplateResult {
const stateObj = this.scriptEntityId
? this.hass.states[this.scriptEntityId]
const stateObj = this._entityId
? this.hass.states[this._entityId]
: undefined;
const graph = this._graph;
const trackedNodes = graph?.trackedNodes;
const renderedNodes = graph?.renderedNodes;
const title = stateObj?.attributes.friendly_name || this.scriptEntityId;
const title = stateObj?.attributes.friendly_name || this._entityId;
let devButtons: TemplateResult | string = "";
if (__DEV__) {
@ -95,11 +97,11 @@ export class HaScriptTrace extends LitElement {
return html`
${devButtons}
<hass-subpage .hass=${this.hass} .narrow=${this.narrow} .header=${title}>
${!this.narrow && this.scriptEntityId
${!this.narrow && this.scriptId
? html`
<a
class="trace-link"
href="/config/script/edit/${this.scriptEntityId}"
href="/config/script/edit/${this.scriptId}"
slot="toolbar-icon"
>
<mwc-button>
@ -120,7 +122,7 @@ export class HaScriptTrace extends LitElement {
<mwc-list-item
graphic="icon"
.disabled=${!this.scriptEntityId}
.disabled=${!stateObj}
@click=${this._showInfo}
>
${this.hass.localize("ui.panel.config.script.editor.show_info")}
@ -130,11 +132,11 @@ export class HaScriptTrace extends LitElement {
></ha-svg-icon>
</mwc-list-item>
${this.narrow && this.scriptEntityId
${this.narrow && this.scriptId
? html`
<a
class="trace-link"
href="/config/script/edit/${this.scriptEntityId}"
href="/config/script/edit/${this.scriptId}"
>
<mwc-list-item graphic="icon">
${this.hass.localize(
@ -309,25 +311,33 @@ export class HaScriptTrace extends LitElement {
protected firstUpdated(changedProps) {
super.firstUpdated(changedProps);
if (!this.scriptEntityId) {
if (!this.scriptId) {
return;
}
const params = new URLSearchParams(location.search);
this._loadTraces(params.get("run_id") || undefined);
this._entityId = Object.values(this.hass.entities).find(
(entry) => entry.unique_id === this.scriptId
)?.entity_id;
}
public willUpdate(changedProps) {
super.willUpdate(changedProps);
// Only reset if scriptEntityId has changed and we had one before.
if (changedProps.get("scriptEntityId")) {
// Only reset if scriptId has changed and we had one before.
if (changedProps.get("scriptId")) {
this._traces = undefined;
this._runId = undefined;
this._trace = undefined;
this._logbookEntries = undefined;
if (this.scriptEntityId) {
if (this.scriptId) {
this._loadTraces();
this._entityId = Object.values(this.hass.entities).find(
(entry) => entry.unique_id === this.scriptId
)?.entity_id;
}
}
@ -364,11 +374,7 @@ export class HaScriptTrace extends LitElement {
}
private async _loadTraces(runId?: string) {
this._traces = await loadTraces(
this.hass,
"script",
this.scriptEntityId.split(".")[1]
);
this._traces = await loadTraces(this.hass, "script", this.scriptId);
// Newest will be on top.
this._traces.reverse();
@ -410,7 +416,7 @@ export class HaScriptTrace extends LitElement {
const trace = await loadTrace(
this.hass,
"script",
this.scriptEntityId.split(".")[1],
this.scriptId,
this._runId!
);
this._logbookEntries = isComponentLoaded(this.hass, "logbook")
@ -426,7 +432,7 @@ export class HaScriptTrace extends LitElement {
private _downloadTrace() {
const aEl = document.createElement("a");
aEl.download = `trace ${this.scriptEntityId} ${
aEl.download = `trace ${this._entityId} ${
this._trace!.timestamp.start
}.json`;
aEl.href = `data:application/json;charset=utf-8,${encodeURI(
@ -476,10 +482,10 @@ export class HaScriptTrace extends LitElement {
}
private async _showInfo() {
if (!this.scriptEntityId) {
if (!this._entityId) {
return;
}
fireEvent(this, "hass-more-info", { entityId: this.scriptEntityId });
fireEvent(this, "hass-more-info", { entityId: this._entityId });
}
static get styles(): CSSResultGroup {

View File

@ -170,11 +170,7 @@ class HaLogbookRenderer extends LitElement {
<div
class="entry-container ${classMap({ clickable: hasTrace })}"
.traceLink=${traceContext
? `/config/${traceContext.domain}/trace/${
traceContext.domain === "script"
? `script.${traceContext.item_id}`
: traceContext.item_id
}?run_id=${traceContext.run_id}`
? `/config/${traceContext.domain}/trace/${traceContext.item_id}?run_id=${traceContext.run_id}`
: undefined}
@click=${this._handleClick}
>