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": {