Show non-editable scripts in UI (#13917)

This commit is contained in:
Bram Kragten 2022-09-29 18:11:48 +02:00 committed by GitHub
parent 0b76183acd
commit 7ff138534f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 135 additions and 14 deletions

View File

@ -300,9 +300,15 @@ export const deleteScript = (hass: HomeAssistant, objectId: string) =>
let inititialScriptEditorData: Partial<ScriptConfig> | undefined;
export const getScriptConfig = (hass: HomeAssistant, objectId: string) =>
export const fetchScriptFileConfig = (hass: HomeAssistant, objectId: string) =>
hass.callApi<ScriptConfig>("GET", `config/script/config/${objectId}`);
export const getScriptStateConfig = (hass: HomeAssistant, entity_id: string) =>
hass.callWS<{ config: ScriptConfig }>({
type: "script/config",
entity_id,
});
export const showScriptEditor = (data?: Partial<ScriptConfig>) => {
inititialScriptEditorData = data;
navigate("/config/script/edit/new");

View File

@ -27,6 +27,8 @@ export class HaBlueprintScriptEditor extends LitElement {
@property({ reflect: true, type: Boolean }) public narrow!: boolean;
@property({ type: Boolean }) public disabled = false;
@property({ attribute: false }) public config!: BlueprintScriptConfig;
@state() private _blueprints?: Blueprints;
@ -46,6 +48,14 @@ export class HaBlueprintScriptEditor extends LitElement {
protected render() {
const blueprint = this._blueprint;
return html`
${this.disabled
? html`<ha-alert alert-type="warning">
${this.hass.localize("ui.panel.config.script.editor.read_only")}
<mwc-button slot="action" @click=${this._duplicate}>
${this.hass.localize("ui.panel.config.script.editor.migrate")}
</mwc-button>
</ha-alert>`
: ""}
<ha-card
outlined
class="blueprint"
@ -64,6 +74,7 @@ export class HaBlueprintScriptEditor extends LitElement {
)}
.blueprints=${this._blueprints}
.value=${this.config.use_blueprint.path}
.disabled=${this.disabled}
@value-changed=${this._blueprintChanged}
></ha-blueprint-picker>
`
@ -97,6 +108,7 @@ export class HaBlueprintScriptEditor extends LitElement {
.hass=${this.hass}
.selector=${value.selector}
.key=${key}
.disabled=${this.disabled}
.value=${(this.config.use_blueprint.input &&
this.config.use_blueprint.input[key]) ??
value?.default}
@ -105,6 +117,7 @@ export class HaBlueprintScriptEditor extends LitElement {
: html`<ha-textfield
.key=${key}
required
.disabled=${this.disabled}
.value=${(this.config.use_blueprint.input &&
this.config.use_blueprint.input[key]) ??
value?.default}
@ -170,6 +183,10 @@ export class HaBlueprintScriptEditor extends LitElement {
});
}
private _duplicate() {
fireEvent(this, "duplicate");
}
static get styles(): CSSResultGroup {
return [
haStyle,

View File

@ -42,6 +42,9 @@ class HaConfigScript extends HassRouterPage {
edit: {
tag: "ha-script-editor",
},
show: {
tag: "ha-script-editor",
},
trace: {
tag: "ha-script-trace",
load: () => import("./ha-script-trace"),
@ -84,6 +87,16 @@ class HaConfigScript extends HassRouterPage {
}
}
if (
(!changedProps || changedProps.has("route")) &&
this._currentPage === "show"
) {
pageEl.creatingNew = undefined;
const scriptId = this.routeTail.path.substr(1);
pageEl.entityId = scriptId === "new" ? null : scriptId;
return;
}
if (
(!changedProps || changedProps.has("route")) &&
this._currentPage !== "dashboard"

View File

@ -42,7 +42,8 @@ import "../../../components/ha-yaml-editor";
import type { HaYamlEditor } from "../../../components/ha-yaml-editor";
import {
deleteScript,
getScriptConfig,
getScriptStateConfig,
fetchScriptFileConfig,
getScriptEditorInitData,
isMaxMode,
MODES,
@ -69,6 +70,8 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
@property() public scriptId: string | null = null;
@property() public entityId: string | null = null;
@property({ attribute: false }) public route!: Route;
@property({ type: Boolean }) public isWide = false;
@ -87,6 +90,8 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
@state() private _mode: "gui" | "yaml" = "gui";
@state() private _readOnly = false;
@query("ha-yaml-editor", true) private _yamlEditor?: HaYamlEditor;
@query("manual-script-editor")
@ -241,7 +246,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
"ui.panel.config.automation.editor.re_order"
)}
graphic="icon"
.disabled=${this._mode !== "gui"}
.disabled=${this._readOnly || this._mode !== "gui"}
@click=${this._toggleReOrderMode}
>
${this.hass.localize(
@ -294,14 +299,20 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
<li divider role="separator"></li>
<mwc-list-item
.disabled=${!this.scriptId}
.disabled=${!this._readOnly && !this.scriptId}
.label=${this.hass.localize(
"ui.panel.config.script.picker.duplicate"
this._readOnly
? "ui.panel.config.script.editor.migrate"
: "ui.panel.config.script.editor.duplicate"
)}
graphic="icon"
@click=${this._duplicate}
>
${this.hass.localize("ui.panel.config.script.picker.duplicate")}
${this.hass.localize(
this._readOnly
? "ui.panel.config.script.editor.migrate"
: "ui.panel.config.script.editor.duplicate"
)}
<ha-svg-icon
slot="graphic"
.path=${mdiContentDuplicate}
@ -309,7 +320,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
</mwc-list-item>
<mwc-list-item
.disabled=${!this.scriptId}
.disabled=${this._readOnly || !this.scriptId}
aria-label=${this.hass.localize(
"ui.panel.config.script.picker.delete"
)}
@ -354,6 +365,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
.schema=${schema}
.data=${data}
.hass=${this.hass}
.disabled=${this._readOnly}
.computeLabel=${this._computeLabelCallback}
.computeHelper=${this._computeHelperCallback}
@value-changed=${this._valueChanged}
@ -369,6 +381,8 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
.narrow=${this.narrow}
.isWide=${this.isWide}
.config=${this._config}
.disabled=${this._readOnly}
@duplicate=${this._duplicate}
@value-changed=${this._configChanged}
></blueprint-script-editor>
`
@ -378,6 +392,8 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
.narrow=${this.narrow}
.isWide=${this.isWide}
.config=${this._config}
.disabled=${this._readOnly}
@duplicate=${this._duplicate}
@value-changed=${this._configChanged}
></manual-script-editor>
`}
@ -387,6 +403,18 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
`
: this._mode === "yaml"
? html`
${this._readOnly
? html`<ha-alert alert-type="warning">
${this.hass.localize(
"ui.panel.config.script.editor.read_only"
)}
<mwc-button slot="action" @click=${this._duplicate}>
${this.hass.localize(
"ui.panel.config.script.editor.migrate"
)}
</mwc-button>
</ha-alert>`
: ""}
${this._errors
? html`
<ha-alert alert-type="error">${this._errors}</ha-alert>
@ -395,6 +423,7 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
<ha-yaml-editor
.hass=${this.hass}
.defaultValue=${this._preprocessYaml()}
.readOnly=${this._readOnly}
@value-changed=${this._yamlChanged}
></ha-yaml-editor>
<ha-card outlined>
@ -433,11 +462,12 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
if (
changedProps.has("scriptId") &&
this.scriptId &&
!this.entityId &&
this.hass &&
// Only refresh config if we picked a new script. If same ID, don't fetch it.
(!oldScript || oldScript !== this.scriptId)
) {
getScriptConfig(this.hass, this.scriptId).then(
fetchScriptFileConfig(this.hass, this.scriptId).then(
(config) => {
// Normalize data: ensure sequence is a list
// Happens when people copy paste their scripts into the config
@ -446,9 +476,20 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
config.sequence = [value];
}
this._dirty = false;
this._readOnly = false;
this._config = config;
},
(resp) => {
const entity = Object.values(this.hass.entities).find(
(ent) =>
ent.platform === "script" && ent.unique_id === this.scriptId
);
if (entity) {
navigate(`/config/script/show/${entity.entity_id}`, {
replace: true,
});
return;
}
alert(
resp.status_code === 404
? this.hass.localize(
@ -478,6 +519,20 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
...baseConfig,
...initData,
} as ScriptConfig;
this._readOnly = false;
}
if (changedProps.has("entityId") && this.entityId) {
getScriptStateConfig(this.hass, this.entityId).then((c) => {
this._config = c.config;
});
const regEntry = this.hass.entities[this.entityId];
if (regEntry?.unique_id) {
this.scriptId = regEntry.unique_id;
}
this._entityId = this.entityId;
this._dirty = false;
this._readOnly = true;
}
}
@ -603,6 +658,9 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
private _valueChanged(ev: CustomEvent) {
ev.stopPropagation();
if (this._readOnly) {
return;
}
this._errors = undefined;
const values = ev.detail.value as any;
@ -693,13 +751,20 @@ export class HaScriptEditor extends KeyboardShortcutMixin(LitElement) {
};
private async _duplicate() {
const result = await this.confirmUnsavedChanged();
const result = this._readOnly
? await showConfirmationDialog(this, {
title: "Migrate script?",
text: "You can migrate this script, so it can be edited from the UI. After it is migrated and you have saved it, you will have to manually delete your old script from your configuration. Do you want to migrate this script?",
})
: await this.confirmUnsavedChanged();
if (result) {
showScriptEditor({
...this._config,
alias: `${this._config?.alias} (${this.hass.localize(
"ui.panel.config.script.picker.duplicate"
)})`,
alias: this._readOnly
? this._config?.alias
: `${this._config?.alias} (${this.hass.localize(
"ui.panel.config.script.picker.duplicate"
)})`,
});
}
}

View File

@ -27,7 +27,7 @@ import "../../../components/ha-icon-overflow-menu";
import "../../../components/ha-svg-icon";
import {
deleteScript,
getScriptConfig,
fetchScriptFileConfig,
showScriptEditor,
triggerScript,
} from "../../../data/script";
@ -254,6 +254,8 @@ class HaScriptPicker extends LitElement {
const entry = this.hass.entities[ev.detail.id];
if (entry) {
navigate(`/config/script/edit/${entry.unique_id}`);
} else {
navigate(`/config/script/show/${ev.detail.id}`);
}
}
@ -301,7 +303,7 @@ class HaScriptPicker extends LitElement {
private async _duplicate(script: any) {
try {
const entry = this.hass.entities[script.entity_id];
const config = await getScriptConfig(this.hass, entry.unique_id);
const config = await fetchScriptFileConfig(this.hass, entry.unique_id);
showScriptEditor({
...config,
alias: `${config?.alias} (${this.hass.localize(

View File

@ -20,6 +20,8 @@ export class HaManualScriptEditor extends LitElement {
@property({ type: Boolean }) public narrow!: boolean;
@property({ type: Boolean }) public disabled = false;
@property({ attribute: false }) public config!: ScriptConfig;
@property({ type: Boolean, reflect: true, attribute: "re-order-mode" })
@ -27,6 +29,14 @@ export class HaManualScriptEditor extends LitElement {
protected render() {
return html`
${this.disabled
? html`<ha-alert alert-type="warning">
${this.hass.localize("ui.panel.config.script.editor.read_only")}
<mwc-button slot="action" @click=${this._duplicate}>
${this.hass.localize("ui.panel.config.script.editor.migrate")}
</mwc-button>
</ha-alert>`
: ""}
${this.reOrderMode
? html`
<ha-alert
@ -72,6 +82,7 @@ export class HaManualScriptEditor extends LitElement {
@value-changed=${this._sequenceChanged}
.hass=${this.hass}
.narrow=${this.narrow}
.disabled=${this.disabled}
.reOrderMode=${this.reOrderMode}
></ha-automation-action>
`;
@ -88,6 +99,10 @@ export class HaManualScriptEditor extends LitElement {
this.reOrderMode = !this.reOrderMode;
}
private _duplicate() {
fireEvent(this, "duplicate");
}
static get styles(): CSSResultGroup {
return [
haStyle,

View File

@ -2323,6 +2323,9 @@
"introduction": "Use scripts to run a sequence of actions.",
"show_trace": "[%key:ui::panel::config::automation::editor::show_trace%]",
"show_info": "[%key:ui::panel::config::automation::editor::show_info%]",
"read_only": "This script can not be edited from the UI, because it is not stored in the ''scripts.yaml'' file.",
"migrate": "Migrate",
"duplicate": "Duplicate",
"header": "Script: {name}",
"default_name": "New Script",
"modes": {