diff --git a/src/components/ha-icon-overflow-menu.ts b/src/components/ha-icon-overflow-menu.ts index e8d48ea67e..ef682477ec 100644 --- a/src/components/ha-icon-overflow-menu.ts +++ b/src/components/ha-icon-overflow-menu.ts @@ -1,6 +1,5 @@ -import "@material/mwc-list/mwc-list-item"; -import { mdiDotsVertical } from "@mdi/js"; import "@lrnwebcomponents/simple-tooltip/simple-tooltip"; +import { mdiDotsVertical } from "@mdi/js"; import { css, html, LitElement, TemplateResult } from "lit"; import { customElement, property } from "lit/decorators"; import { classMap } from "lit/directives/class-map"; @@ -8,6 +7,7 @@ import { haStyle } from "../resources/styles"; import { HomeAssistant } from "../types"; import "./ha-button-menu"; import "./ha-icon-button"; +import "./ha-list-item"; import "./ha-svg-icon"; export interface IconOverflowMenuItem { @@ -49,7 +49,7 @@ export class HaIconOverflowMenu extends LitElement { ${this.items.map((item) => item.divider ? html`
  • ` - : html` ${item.label} - ` + ` )} ` : html` @@ -126,6 +126,9 @@ export class HaIconOverflowMenu extends LitElement { border-right: 1px solid var(--divider-color); width: 1px; } + ha-list-item[disabled] ha-svg-icon { + color: var(--disabled-text-color); + } `, ]; } diff --git a/src/panels/config/blueprint/ha-blueprint-overview.ts b/src/panels/config/blueprint/ha-blueprint-overview.ts index 8a307680ec..1123e51d03 100644 --- a/src/panels/config/blueprint/ha-blueprint-overview.ts +++ b/src/panels/config/blueprint/ha-blueprint-overview.ts @@ -26,15 +26,19 @@ import { RowClickedEvent, } from "../../../components/data-table/ha-data-table"; import "../../../components/entity/ha-entity-toggle"; +import "../../../components/ha-button"; import "../../../components/ha-fab"; import "../../../components/ha-icon-button"; import "../../../components/ha-icon-overflow-menu"; import "../../../components/ha-svg-icon"; import { showAutomationEditor } from "../../../data/automation"; import { + BlueprintImportResult, BlueprintMetaData, Blueprints, deleteBlueprint, + importBlueprint, + saveBlueprint, } from "../../../data/blueprint"; import { showScriptEditor } from "../../../data/script"; import { findRelated } from "../../../data/search"; @@ -46,6 +50,7 @@ import "../../../layouts/hass-tabs-subpage-data-table"; import { haStyle } from "../../../resources/styles"; import { HomeAssistant, Route } from "../../../types"; import { documentationUrl } from "../../../util/documentation-url"; +import { showToast } from "../../../util/toast"; import { configSections } from "../ha-panel-config"; import { showAddBlueprintDialog } from "./show-dialog-import-blueprint"; @@ -199,6 +204,16 @@ class HaBlueprintOverview extends LitElement { ), action: () => this._share(blueprint), }, + { + path: mdiDownload, + disabled: !blueprint.source_url, + label: this.hass.localize( + blueprint.source_url + ? "ui.panel.config.blueprint.overview.re_import_blueprint" + : "ui.panel.config.blueprint.overview.re_import_blueprint_no_url" + ), + action: () => this._reImport(blueprint), + }, { divider: true, }, @@ -256,10 +271,10 @@ class HaBlueprintOverview extends LitElement { target="_blank" rel="noreferrer noopener" > - ${this.hass.localize( "ui.panel.config.blueprint.overview.discover_more" - )} `} @@ -359,6 +374,67 @@ class HaBlueprintOverview extends LitElement { ); }; + private _reImport = async (blueprint: BlueprintMetaDataPath) => { + const result = await showConfirmationDialog(this, { + title: this.hass.localize( + "ui.panel.config.blueprint.overview.re_import_confirm_title" + ), + text: html` + ${this.hass.localize( + "ui.panel.config.blueprint.overview.re_import_confirm_text" + )} + `, + confirmText: this.hass.localize( + "ui.panel.config.blueprint.overview.re_import_confirm_action" + ), + warning: true, + }); + + if (!result) { + return; + } + + let importResult: BlueprintImportResult; + try { + importResult = await importBlueprint(this.hass, blueprint.source_url!); + } catch (err) { + showToast(this, { + message: this.hass.localize( + "ui.panel.config.blueprint.overview.re_import_error_source_not_found" + ), + }); + throw err; + } + + try { + await saveBlueprint( + this.hass, + blueprint.domain, + blueprint.path, + importResult!.raw_data, + blueprint.source_url, + true + ); + } catch (err: any) { + showToast(this, { + message: this.hass.localize( + "ui.panel.config.blueprint.overview.re_import_error_save", + { error: err.message } + ), + }); + throw err; + } + + fireEvent(this, "reload-blueprints"); + + showToast(this, { + message: this.hass.localize( + "ui.panel.config.blueprint.overview.re_import_success", + { name: importResult!.blueprint.metadata.name } + ), + }); + }; + private _delete = async (blueprint: BlueprintMetaDataPath) => { const related = await findRelated( this.hass, diff --git a/src/translations/en.json b/src/translations/en.json index 201358d7c7..cd9d34cb2d 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -2963,6 +2963,14 @@ "delete_blueprint": "Delete blueprint", "share_blueprint": "Share blueprint", "share_blueprint_no_url": "Unable to share blueprint: no source url", + "re_import_blueprint": "Re-import blueprint", + "re_import_blueprint_no_url": "Unable to re-import blueprint: no source url", + "re_import_confirm_title": "Re-import blueprint", + "re_import_confirm_text": "[%key:ui::panel::config::blueprint::add::override_description%]", + "re_import_confirm_action": "Re-import", + "re_import_error_source_not_found": "Unable to re-import the blueprint: source not found.", + "re_import_error_save": "Unable to re-import the blueprint: {error}.", + "re_import_success": "{name} has been successfully re-imported.", "discover_more": "Discover more blueprints" }, "add": {