mirror of
https://github.com/home-assistant/frontend.git
synced 2026-04-02 00:27:49 +01:00
Add ability to duplicate a section (#30265)
* Add ability to duplicate a section * Move section edit mode buttons to overflow menu * Fix typing for concat and push parameters * Fix incorrect clipboard typing for badges
This commit is contained in:
committed by
GitHub
parent
10c90d222d
commit
bbda7affdc
@@ -198,7 +198,7 @@ export default class HaAutomationAction extends AutomationSortableListMixin<Acti
|
||||
private _addAction = (action: string, target?: HassServiceTarget) => {
|
||||
let actions: Action[];
|
||||
if (action === PASTE_VALUE) {
|
||||
actions = this.actions.concat(deepClone(this._clipboard!.action));
|
||||
actions = this.actions.concat(deepClone(this._clipboard!.action!));
|
||||
} else if (action in VIRTUAL_ACTIONS) {
|
||||
actions = this.actions.concat(VIRTUAL_ACTIONS[action]);
|
||||
} else if (isDynamic(action)) {
|
||||
|
||||
@@ -287,7 +287,7 @@ export default class HaAutomationCondition extends AutomationSortableListMixin<C
|
||||
let conditions: Condition[];
|
||||
if (value === PASTE_VALUE) {
|
||||
conditions = this.conditions.concat(
|
||||
deepClone(this._clipboard!.condition)
|
||||
deepClone(this._clipboard!.condition!)
|
||||
);
|
||||
} else if (isDynamic(value)) {
|
||||
conditions = this.conditions.concat({
|
||||
|
||||
@@ -203,7 +203,7 @@ export default class HaAutomationTrigger extends AutomationSortableListMixin<Tri
|
||||
private _addTrigger = (value: string, target?: HassServiceTarget) => {
|
||||
let triggers: Trigger[];
|
||||
if (value === PASTE_VALUE) {
|
||||
triggers = this.triggers.concat(deepClone(this._clipboard!.trigger));
|
||||
triggers = this.triggers.concat(deepClone(this._clipboard!.trigger!));
|
||||
} else if (isDynamic(value)) {
|
||||
triggers = this.triggers.concat({
|
||||
trigger: getValueFromDynamic(value),
|
||||
|
||||
@@ -19,8 +19,10 @@ import type { HaDropdownSelectEvent } from "../../../components/ha-dropdown";
|
||||
import "../../../components/ha-dropdown-item";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import { ensureBadgeConfig } from "../../../data/lovelace/config/badge";
|
||||
import type { LovelaceCardConfig } from "../../../data/lovelace/config/card";
|
||||
import {
|
||||
ensureBadgeConfig,
|
||||
type LovelaceBadgeConfig,
|
||||
} from "../../../data/lovelace/config/badge";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { showEditBadgeDialog } from "../editor/badge-editor/show-edit-badge-dialog";
|
||||
@@ -58,7 +60,7 @@ export class HuiBadgeEditMode extends LitElement {
|
||||
subscribe: false,
|
||||
storage: "sessionStorage",
|
||||
})
|
||||
protected _clipboard?: LovelaceCardConfig;
|
||||
protected _clipboard?: string | Partial<LovelaceBadgeConfig>;
|
||||
|
||||
private get _badges() {
|
||||
const containerPath = getLovelaceContainerPath(this.path!);
|
||||
|
||||
@@ -1,13 +1,23 @@
|
||||
import { mdiDelete, mdiDragHorizontalVariant, mdiPencil } from "@mdi/js";
|
||||
import "@home-assistant/webawesome/dist/components/divider/divider";
|
||||
import {
|
||||
mdiDelete,
|
||||
mdiDotsVertical,
|
||||
mdiDragHorizontalVariant,
|
||||
mdiPencil,
|
||||
mdiPlusCircleMultipleOutline,
|
||||
} from "@mdi/js";
|
||||
import type { CSSResultGroup, TemplateResult } from "lit";
|
||||
import { LitElement, css, html } from "lit";
|
||||
import { customElement, property } from "lit/decorators";
|
||||
import "../../../components/ha-dropdown";
|
||||
import type { HaDropdownSelectEvent } from "../../../components/ha-dropdown";
|
||||
import "../../../components/ha-dropdown-item";
|
||||
import "../../../components/ha-icon-button";
|
||||
import "../../../components/ha-svg-icon";
|
||||
import { showConfirmationDialog } from "../../../dialogs/generic/show-dialog-box";
|
||||
import { haStyle } from "../../../resources/styles";
|
||||
import type { HomeAssistant } from "../../../types";
|
||||
import { deleteSection } from "../editor/config-util";
|
||||
import { deleteSection, duplicateSection } from "../editor/config-util";
|
||||
import { findLovelaceContainer } from "../editor/lovelace-path";
|
||||
import { showEditSectionDialog } from "../editor/section-editor/show-edit-section-dialog";
|
||||
import type { Lovelace } from "../types";
|
||||
@@ -31,16 +41,32 @@ export class HuiSectionEditMode extends LitElement {
|
||||
class="handle"
|
||||
.path=${mdiDragHorizontalVariant}
|
||||
></ha-svg-icon>
|
||||
<ha-icon-button
|
||||
.label=${this.hass.localize("ui.common.edit")}
|
||||
@click=${this._editSection}
|
||||
.path=${mdiPencil}
|
||||
></ha-icon-button>
|
||||
<ha-icon-button
|
||||
.label=${this.hass.localize("ui.common.delete")}
|
||||
@click=${this._deleteSection}
|
||||
.path=${mdiDelete}
|
||||
></ha-icon-button>
|
||||
<ha-dropdown
|
||||
placement="bottom-end"
|
||||
@wa-select=${this._handleDropdownSelect}
|
||||
>
|
||||
<ha-icon-button
|
||||
slot="trigger"
|
||||
.label=${this.hass.localize("ui.common.menu")}
|
||||
.path=${mdiDotsVertical}
|
||||
></ha-icon-button>
|
||||
<ha-dropdown-item value="edit">
|
||||
<ha-svg-icon slot="icon" .path=${mdiPencil}></ha-svg-icon>
|
||||
${this.hass.localize("ui.common.edit")}
|
||||
</ha-dropdown-item>
|
||||
<ha-dropdown-item value="duplicate">
|
||||
<ha-svg-icon
|
||||
slot="icon"
|
||||
.path=${mdiPlusCircleMultipleOutline}
|
||||
></ha-svg-icon>
|
||||
${this.hass.localize("ui.common.duplicate")}
|
||||
</ha-dropdown-item>
|
||||
<wa-divider></wa-divider>
|
||||
<ha-dropdown-item value="delete" variant="danger">
|
||||
<ha-svg-icon slot="icon" .path=${mdiDelete}></ha-svg-icon>
|
||||
${this.hass.localize("ui.common.delete")}
|
||||
</ha-dropdown-item>
|
||||
</ha-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section-wrapper">
|
||||
@@ -49,8 +75,23 @@ export class HuiSectionEditMode extends LitElement {
|
||||
`;
|
||||
}
|
||||
|
||||
private async _editSection(ev) {
|
||||
ev.stopPropagation();
|
||||
private _handleDropdownSelect(ev: HaDropdownSelectEvent): void {
|
||||
const action = ev.detail?.item?.value;
|
||||
if (!action) return;
|
||||
switch (action) {
|
||||
case "edit":
|
||||
this._editSection();
|
||||
break;
|
||||
case "duplicate":
|
||||
this._duplicateSection();
|
||||
break;
|
||||
case "delete":
|
||||
this._deleteSection();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private async _editSection() {
|
||||
showEditSectionDialog(this, {
|
||||
lovelace: this.lovelace!,
|
||||
lovelaceConfig: this.lovelace!.config,
|
||||
@@ -62,8 +103,16 @@ export class HuiSectionEditMode extends LitElement {
|
||||
});
|
||||
}
|
||||
|
||||
private async _deleteSection(ev) {
|
||||
ev.stopPropagation();
|
||||
private _duplicateSection(): void {
|
||||
const newConfig = duplicateSection(
|
||||
this.lovelace!.config,
|
||||
this.viewIndex,
|
||||
this.index
|
||||
);
|
||||
this.lovelace!.saveConfig(newConfig);
|
||||
}
|
||||
|
||||
private async _deleteSection() {
|
||||
const path = [this.viewIndex, this.index] as [number, number];
|
||||
|
||||
const section = findLovelaceContainer(this.lovelace!.config, path);
|
||||
|
||||
@@ -153,7 +153,7 @@ export class HaCardConditionsEditor extends LitElement {
|
||||
}
|
||||
|
||||
if (condition === "paste") {
|
||||
const newCondition = deepClone(this._clipboard);
|
||||
const newCondition = deepClone(this._clipboard!);
|
||||
conditions.push(newCondition);
|
||||
} else {
|
||||
const elClass = customElements.get(`ha-card-condition-${condition}`) as
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import deepClone from "deep-clone-simple";
|
||||
import type { LovelaceBadgeConfig } from "../../../data/lovelace/config/badge";
|
||||
import { ensureBadgeConfig } from "../../../data/lovelace/config/badge";
|
||||
import type { LovelaceCardConfig } from "../../../data/lovelace/config/card";
|
||||
@@ -303,6 +304,19 @@ export const deleteSection = (
|
||||
return newConfig;
|
||||
};
|
||||
|
||||
export const duplicateSection = (
|
||||
config: LovelaceConfig,
|
||||
viewIndex: number,
|
||||
sectionIndex: number
|
||||
): LovelaceConfig => {
|
||||
const view = findLovelaceContainer(config, [viewIndex]);
|
||||
if (isStrategyView(view)) {
|
||||
throw new Error("Duplicating sections in a strategy is not supported.");
|
||||
}
|
||||
const clone = deepClone(view.sections![sectionIndex]);
|
||||
return insertSection(config, viewIndex, sectionIndex + 1, clone);
|
||||
};
|
||||
|
||||
export const insertSection = (
|
||||
config: LovelaceConfig,
|
||||
viewIndex: number,
|
||||
|
||||
3
src/types/deep-clone-simple.d.ts
vendored
Normal file
3
src/types/deep-clone-simple.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare module "deep-clone-simple" {
|
||||
export default function deepClone<T>(data: T): T;
|
||||
}
|
||||
Reference in New Issue
Block a user