- ${this.hass.localize( - "ui.panel.config.automation.editor.modes.description", - "documentation_link", - html`${this.hass.localize( - "ui.panel.config.automation.editor.modes.documentation" - )}` - )} -
-- ${this.hass.localize( - "ui.panel.config.automation.editor.triggers.introduction" - )} -
- - ${this.hass.localize( - "ui.panel.config.automation.editor.triggers.learn_more" - )} - - -- ${this.hass.localize( - "ui.panel.config.automation.editor.conditions.introduction" - )} -
- - ${this.hass.localize( - "ui.panel.config.automation.editor.conditions.learn_more" - )} - - -- ${this.hass.localize( - "ui.panel.config.automation.editor.actions.introduction" - )} -
- - ${this.hass.localize( - "ui.panel.config.automation.editor.actions.learn_more" - )} - - -+ ${this.hass.localize( + "ui.panel.config.automation.editor.modes.description", + "documentation_link", + html`${this.hass.localize( + "ui.panel.config.automation.editor.modes.documentation" + )}` + )} +
++ ${this.hass.localize( + "ui.panel.config.automation.editor.triggers.introduction" + )} +
+ + ${this.hass.localize( + "ui.panel.config.automation.editor.triggers.learn_more" + )} + + ++ ${this.hass.localize( + "ui.panel.config.automation.editor.conditions.introduction" + )} +
+ + ${this.hass.localize( + "ui.panel.config.automation.editor.conditions.learn_more" + )} + + ++ ${this.hass.localize( + "ui.panel.config.automation.editor.actions.introduction" + )} +
+ + ${this.hass.localize( + "ui.panel.config.automation.editor.actions.learn_more" + )} + + +${this._result.raw_data}` + : html`${this.hass.localize( + "ui.panel.config.blueprint.add.import_introduction" + )}
+ + ${this.hass.localize( + "ui.panel.config.blueprint.overview.learn_more" + )} + +
+ `, + }); + } + + private _addBlueprint() { + showAddBlueprintDialog(this, { importedCallback: () => this._reload() }); + } + + private _reload() { + fireEvent(this, "reload-blueprints"); + } + + private _createNew(ev) { + const blueprint = ev.currentTarget.blueprint as BlueprintMetaDataPath; + createNewFunctions[blueprint.domain](this, blueprint); + } + + private async _delete(ev) { + const blueprint = ev.currentTarget.blueprint; + if ( + !(await showConfirmationDialog(this, { + title: this.hass.localize( + "ui.panel.config.blueprint.overview.confirm_delete_header" + ), + text: this.hass.localize( + "ui.panel.config.blueprint.overview.confirm_delete_text" + ), + })) + ) { + return; + } + await deleteBlueprint(this.hass, blueprint.domain, blueprint.path); + fireEvent(this, "reload-blueprints"); + } + + static get styles(): CSSResult { + return haStyle; + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-blueprint-overview": HaBlueprintOverview; + } +} diff --git a/src/panels/config/blueprint/ha-config-blueprint.ts b/src/panels/config/blueprint/ha-config-blueprint.ts new file mode 100644 index 0000000000..12e3bbc35f --- /dev/null +++ b/src/panels/config/blueprint/ha-config-blueprint.ts @@ -0,0 +1,76 @@ +import { customElement, property, PropertyValues } from "lit-element"; +import { + HassRouterPage, + RouterOptions, +} from "../../../layouts/hass-router-page"; +import "./ha-blueprint-overview"; +import { HomeAssistant } from "../../../types"; +import { Blueprints, fetchBlueprints } from "../../../data/blueprint"; + +declare global { + // for fire event + interface HASSDomEvents { + "reload-blueprints": undefined; + } +} + +@customElement("ha-config-blueprint") +class HaConfigBlueprint extends HassRouterPage { + @property({ attribute: false }) public hass!: HomeAssistant; + + @property() public narrow!: boolean; + + @property() public isWide!: boolean; + + @property() public showAdvanced!: boolean; + + @property() public blueprints: Blueprints = {}; + + protected routerOptions: RouterOptions = { + defaultPage: "dashboard", + routes: { + dashboard: { + tag: "ha-blueprint-overview", + cache: true, + }, + edit: { + tag: "ha-blueprint-editor", + }, + }, + }; + + private async _getBlueprints() { + this.blueprints = await fetchBlueprints(this.hass, "automation"); + } + + protected firstUpdated(changedProps) { + super.firstUpdated(changedProps); + this.addEventListener("reload-blueprints", () => { + this._getBlueprints(); + }); + this._getBlueprints(); + } + + protected updatePageEl(pageEl, changedProps: PropertyValues) { + pageEl.hass = this.hass; + pageEl.narrow = this.narrow; + pageEl.isWide = this.isWide; + pageEl.route = this.routeTail; + pageEl.showAdvanced = this.showAdvanced; + pageEl.blueprints = this.blueprints; + + if ( + (!changedProps || changedProps.has("route")) && + this._currentPage === "edit" + ) { + const blueprintId = this.routeTail.path.substr(1); + pageEl.blueprintId = blueprintId === "new" ? null : blueprintId; + } + } +} + +declare global { + interface HTMLElementTagNameMap { + "ha-config-blueprint": HaConfigBlueprint; + } +} diff --git a/src/panels/config/blueprint/show-dialog-import-blueprint.ts b/src/panels/config/blueprint/show-dialog-import-blueprint.ts new file mode 100644 index 0000000000..0fec45cf4c --- /dev/null +++ b/src/panels/config/blueprint/show-dialog-import-blueprint.ts @@ -0,0 +1,17 @@ +import { fireEvent } from "../../../common/dom/fire_event"; + +export const loadImportBlueprintDialog = () => + import( + /* webpackChunkName: "add-blueprint-dialog" */ "./dialog-import-blueprint" + ); + +export const showAddBlueprintDialog = ( + element: HTMLElement, + dialogParams +): void => { + fireEvent(element, "show-dialog", { + dialogTag: "ha-dialog-import-blueprint", + dialogImport: loadImportBlueprintDialog, + dialogParams, + }); +}; diff --git a/src/panels/config/ha-panel-config.ts b/src/panels/config/ha-panel-config.ts index 457f9bf1c8..b57805382e 100644 --- a/src/panels/config/ha-panel-config.ts +++ b/src/panels/config/ha-panel-config.ts @@ -33,6 +33,7 @@ import { mdiMathLog, mdiPencil, mdiNfcVariant, + mdiPaletteSwatch, } from "@mdi/js"; declare global { @@ -74,6 +75,12 @@ export const configSections: { [name: string]: PageNavigation[] } = { }, ], automation: [ + { + component: "blueprint", + path: "/config/blueprint", + translationKey: "ui.panel.config.blueprint.caption", + iconPath: mdiPaletteSwatch, + }, { component: "automation", path: "/config/automation", @@ -92,6 +99,8 @@ export const configSections: { [name: string]: PageNavigation[] } = { translationKey: "ui.panel.config.script.caption", iconPath: mdiScriptText, }, + ], + helpers: [ { component: "helpers", path: "/config/helpers", @@ -206,6 +215,13 @@ class HaPanelConfig extends HassRouterPage { /* webpackChunkName: "panel-config-automation" */ "./automation/ha-config-automation" ), }, + blueprint: { + tag: "ha-config-blueprint", + load: () => + import( + /* webpackChunkName: "panel-config-blueprint" */ "./blueprint/ha-config-blueprint" + ), + }, tags: { tag: "ha-config-tags", load: () => diff --git a/src/translations/en.json b/src/translations/en.json index ab628679f5..b70531caf7 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -339,6 +339,11 @@ "add_user": "Add user", "remove_user": "Remove user" }, + "blueprint-picker": { + "select_blueprint": "Select a Blueprint", + "add_user": "Add user", + "remove_user": "Remove user" + }, "device-picker": { "clear": "Clear", "toggle": "Toggle", @@ -1110,6 +1115,19 @@ "name": "Name" } }, + "dialog_new": { + "header": "Create a new automation", + "how": "How do you want to create your new automation?", + + "blueprint": { "use_blueprint": "Use a blueprint" }, + "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" + }, "editor": { "enable_disable": "Enable/Disable automation", "introduction": "Use automations to bring your home alive.", @@ -1125,6 +1143,14 @@ "label": "Description", "placeholder": "Optional description" }, + "blueprint": { + "header": "Blueprint", + "blueprint_to_use": "Blueprint to use", + "no_blueprints": "You don't have any blueprints", + "manage_blueprints": "Manage Blueprints", + "inputs": "Inputs", + "no_inputs": "This blueprint doesn't have any inputs." + }, "modes": { "label": "Mode", "description": "The mode controls what happens when the automation is triggered while the actions are still running from a previous trigger. Check the {documentation_link} for more info.", @@ -1414,6 +1440,31 @@ } } }, + "blueprint": { + "caption": "Blueprints", + "description": "Manage blueprints", + "overview": { + "header": "Blueprint Editor", + "introduction": "The blueprint editor allows you to create and edit blueprints.", + "learn_more": "Learn more about blueprints", + "headers": { + "name": "Name" + }, + "confirm_delete_header": "Delete this Blueprint?", + "confirm_delete_text": "Are you sure you want to delete this Blueprint" + }, + "add": { + "header": "Add new blueprint", + "import_header": "Import {name} ({domain})", + "import_introduction": "You can import Blueprints of other users from Github and the community forums. Enter the url of the Blueprint below.", + "url": "Url of the blueprint", + "importing": "Importing blueprint...", + "import_btn": "Import blueprint", + "saving": "Saving blueprint...", + "save_btn": "Save blueprint", + "error_no_url": "Please enter the url of the blueprint." + } + }, "script": { "caption": "Scripts", "description": "Manage scripts",