Update create automation dialog (#15286)

This commit is contained in:
Paul Bottein 2023-02-07 15:18:00 +01:00 committed by GitHub
parent c19cba85ec
commit b2bfb1fdcb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 197 additions and 51 deletions

View File

@ -41,9 +41,9 @@ class HaBluePrintPicker extends LitElement {
return [];
}
const result = Object.entries(blueprints)
.filter(([_path, blueprint]) => !("error" in blueprint))
.filter((entry): entry is [string, Blueprint] => !("error" in entry[1]))
.map(([path, blueprint]) => ({
...(blueprint as Blueprint).metadata,
...blueprint.metadata,
path,
}));
return result.sort((a, b) =>

View File

@ -16,6 +16,7 @@ export interface BlueprintMetaData {
input?: Record<string, BlueprintInput | null>;
description?: string;
source_url?: string;
author?: string;
}
export interface BlueprintInput {
@ -63,3 +64,19 @@ export const deleteBlueprint = (
domain,
path,
});
export type BlueprintSourceType = "local" | "community" | "homeassistant";
export const getBlueprintSourceType = (
blueprint: Blueprint
): BlueprintSourceType => {
const sourceUrl = blueprint.metadata.source_url;
if (!sourceUrl) {
return "local";
}
if (sourceUrl.includes("github.com/home-assistant")) {
return "homeassistant";
}
return "community";
};

View File

@ -1,17 +1,40 @@
import "@material/mwc-button";
import "@material/mwc-list/mwc-list";
import {
mdiAccount,
mdiFile,
mdiHomeAssistant,
mdiOpenInNew,
mdiPencilOutline,
mdiWeb,
} from "@mdi/js";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
import { fireEvent } from "../../../common/dom/fire_event";
import "../../../components/ha-blueprint-picker";
import "../../../components/ha-circular-progress";
import { shouldHandleRequestSelectedEvent } from "../../../common/mwc/handle-request-selected-event";
import { stringCompare } from "../../../common/string/compare";
import { createCloseHeading } from "../../../components/ha-dialog";
import "../../../components/ha-icon-next";
import "../../../components/ha-list-item";
import "../../../components/ha-tip";
import { showAutomationEditor } from "../../../data/automation";
import {
Blueprint,
Blueprints,
BlueprintSourceType,
fetchBlueprints,
getBlueprintSourceType,
} from "../../../data/blueprint";
import { HassDialog } from "../../../dialogs/make-dialog-manager";
import { haStyle, haStyleDialog } from "../../../resources/styles";
import type { HomeAssistant } from "../../../types";
import "@material/mwc-list/mwc-list-item";
import "../../../components/ha-icon-next";
import "@material/mwc-list/mwc-list";
import { documentationUrl } from "../../../util/documentation-url";
const SOURCE_TYPE_ICONS: Record<BlueprintSourceType, string> = {
local: mdiFile,
community: mdiAccount,
homeassistant: mdiHomeAssistant,
};
@customElement("ha-dialog-new-automation")
class DialogNewAutomation extends LitElement implements HassDialog {
@ -19,8 +42,13 @@ class DialogNewAutomation extends LitElement implements HassDialog {
@state() private _opened = false;
@state() public blueprints?: Blueprints;
public showDialog(): void {
this._opened = true;
fetchBlueprints(this.hass!, "automation").then((blueprints) => {
this.blueprints = blueprints;
});
}
public closeDialog(): void {
@ -30,10 +58,33 @@ class DialogNewAutomation extends LitElement implements HassDialog {
this._opened = false;
}
private _processedBlueprints = memoizeOne((blueprints?: Blueprints) => {
if (!blueprints) {
return [];
}
const result = Object.entries(blueprints)
.filter((entry): entry is [string, Blueprint] => !("error" in entry[1]))
.map(([path, blueprint]) => {
const sourceType = getBlueprintSourceType(blueprint);
return {
...blueprint.metadata,
sourceType,
path,
};
});
return result.sort((a, b) =>
stringCompare(a.name, b.name, this.hass!.locale.language)
);
});
protected render(): TemplateResult {
if (!this._opened) {
return html``;
}
const processedBlueprints = this._processedBlueprints(this.blueprints);
return html`
<ha-dialog
open
@ -41,48 +92,117 @@ class DialogNewAutomation extends LitElement implements HassDialog {
@closed=${this.closeDialog}
.heading=${createCloseHeading(
this.hass,
this.hass.localize("ui.panel.config.automation.dialog_new.how")
this.hass.localize("ui.panel.config.automation.dialog_new.header")
)}
>
<mwc-list>
<mwc-list-item twoline class="blueprint" @click=${this._blueprint}>
<mwc-list
innerRole="listbox"
itemRoles="option"
innerAriaLabel=${this.hass.localize(
"ui.panel.config.automation.dialog_new.header"
)}
rootTabbable
dialogInitialFocus
>
<ha-list-item
hasmeta
twoline
graphic="icon"
@request-selected=${this._blank}
>
<ha-svg-icon slot="graphic" .path=${mdiPencilOutline}></ha-svg-icon>
${this.hass.localize(
"ui.panel.config.automation.dialog_new.blueprint.use_blueprint"
)}
<span slot="secondary">
<ha-blueprint-picker
@value-changed=${this._blueprintPicked}
.hass=${this.hass}
></ha-blueprint-picker>
</span>
</mwc-list-item>
<li divider role="separator"></li>
<mwc-list-item hasmeta twoline @click=${this._blank}>
${this.hass.localize(
"ui.panel.config.automation.dialog_new.start_empty"
"ui.panel.config.automation.dialog_new.create_empty"
)}
<span slot="secondary">
${this.hass.localize(
"ui.panel.config.automation.dialog_new.start_empty_description"
"ui.panel.config.automation.dialog_new.create_empty_description"
)}
</span>
<ha-icon-next slot="meta"></ha-icon-next>
</mwc-list-item>
</ha-list-item>
<li divider role="separator"></li>
${processedBlueprints.map(
(blueprint) => html`
<ha-list-item
hasmeta
twoline
graphic="icon"
@request-selected=${this._blueprint}
.path=${blueprint.path}
>
<ha-svg-icon
slot="graphic"
.path=${SOURCE_TYPE_ICONS[blueprint.sourceType]}
></ha-svg-icon>
${blueprint.name}
<span slot="secondary">
${blueprint.author
? this.hass.localize(
`ui.panel.config.automation.dialog_new.blueprint_source.author`,
{ author: blueprint.author }
)
: this.hass.localize(
`ui.panel.config.automation.dialog_new.blueprint_source.${blueprint.sourceType}`
)}
</span>
<ha-icon-next slot="meta"></ha-icon-next>
</ha-list-item>
`
)}
${processedBlueprints.length === 0
? html`
<a
href=${documentationUrl(this.hass, "/get-blueprints")}
target="_blank"
rel="noreferrer noopener"
class="item"
>
<ha-list-item hasmeta twoline graphic="icon">
<ha-svg-icon slot="graphic" .path=${mdiWeb}></ha-svg-icon>
${this.hass.localize(
"ui.panel.config.automation.dialog_new.create_blueprint"
)}
<span slot="secondary">
${this.hass.localize(
"ui.panel.config.automation.dialog_new.create_blueprint_description"
)}
</span>
<ha-svg-icon slot="meta" path=${mdiOpenInNew}></ha-svg-icon>
</ha-list-item>
</a>
`
: html`
<ha-tip>
<a
href=${documentationUrl(this.hass, "/get-blueprints")}
target="_blank"
rel="noreferrer noopener"
>
${this.hass.localize(
"ui.panel.config.automation.dialog_new.discover_blueprint_tip"
)}
</a>
</ha-tip>
`}
</mwc-list>
</ha-dialog>
`;
}
private async _blueprintPicked(ev: CustomEvent) {
private async _blueprint(ev) {
if (!shouldHandleRequestSelectedEvent(ev)) {
return;
}
const path = (ev.currentTarget! as any).path;
this.closeDialog();
showAutomationEditor({ use_blueprint: { path: ev.detail.value } });
showAutomationEditor({ use_blueprint: { path } });
}
private async _blueprint() {
this.shadowRoot!.querySelector("ha-blueprint-picker")!.open();
}
private async _blank() {
private async _blank(ev) {
if (!shouldHandleRequestSelectedEvent(ev)) {
return;
}
this.closeDialog();
showAutomationEditor();
}
@ -92,14 +212,24 @@ class DialogNewAutomation extends LitElement implements HassDialog {
haStyle,
haStyleDialog,
css`
mwc-list-item.blueprint {
height: 110px;
}
ha-blueprint-picker {
margin-top: 8px;
}
ha-dialog {
--dialog-content-padding: 0;
--mdc-dialog-max-height: 60vh;
}
@media all and (min-width: 550px) {
ha-dialog {
--mdc-dialog-min-width: 500px;
}
}
ha-icon-next {
width: 24px;
}
ha-tip {
margin-top: 8px;
margin-bottom: 4px;
}
a.item {
text-decoration: unset;
}
`,
];

View File

@ -1931,19 +1931,18 @@
}
},
"dialog_new": {
"header": "Create a new automation",
"how": "How do you want to create your new automation?",
"blueprint": {
"use_blueprint": "Use a blueprint"
"header": "Create automation",
"create_empty": "Create new automation",
"create_empty_description": "Start with an empty automation from scratch",
"create_blueprint": "Create from blueprint",
"create_blueprint_description": "Discover community blueprints",
"blueprint_source": {
"author": "By {author}",
"local": "By you",
"community": "By the community",
"homeassistant": "By Home Assistant"
},
"thingtalk": {
"header": "Describe the automation you want to create",
"intro": "And we will try to create it for you. For example: Turn the lights off when I leave.",
"input_label": "What should this automation do?",
"create": "Create"
},
"start_empty": "Start with an empty automation",
"start_empty_description": "Create a new automation from scratch"
"discover_blueprint_tip": "Discover more community blueprints"
},
"editor": {
"enable": "[%key:ui::common::enable%]",