diff --git a/src/panels/lovelace/components/hui-card-options.ts b/src/panels/lovelace/components/hui-card-options.ts
index a82af564df..53a8ee0ea9 100644
--- a/src/panels/lovelace/components/hui-card-options.ts
+++ b/src/panels/lovelace/components/hui-card-options.ts
@@ -8,6 +8,7 @@ import { confDeleteCard } from "../editor/delete-card";
import { HomeAssistant } from "../../../types";
import { LovelaceCardConfig } from "../../../data/lovelace";
import { Lovelace } from "../types";
+import { swapCard } from "../editor/config-util";
export class HuiCardOptions extends hassLocalizeLitMixin(LitElement) {
public cardConfig?: LovelaceCardConfig;
@@ -46,6 +47,19 @@ export class HuiCardOptions extends hassLocalizeLitMixin(LitElement) {
this.localize("ui.panel.lovelace.editor.edit_card.edit")
}
+
+
`;
}
+
private _editCard(): void {
showEditCardDialog(this, {
lovelace: this.lovelace!,
path: this.path!,
});
}
+
+ private _cardUp(): void {
+ const lovelace = this.lovelace!;
+ const path = this.path!;
+ lovelace.saveConfig(
+ swapCard(lovelace.config, path, [path[0], path[1] - 1])
+ );
+ }
+
+ private _cardDown(): void {
+ const lovelace = this.lovelace!;
+ const path = this.path!;
+ lovelace.saveConfig(
+ swapCard(lovelace.config, path, [path[0], path[1] + 1])
+ );
+ }
+
private _deleteCard(): void {
confDeleteCard(this.lovelace!, this.path!);
}
diff --git a/src/panels/lovelace/editor/config-util.ts b/src/panels/lovelace/editor/config-util.ts
index 991aec1f7c..2c87b57737 100644
--- a/src/panels/lovelace/editor/config-util.ts
+++ b/src/panels/lovelace/editor/config-util.ts
@@ -89,6 +89,38 @@ export const deleteCard = (
};
};
+export const swapCard = (
+ config: LovelaceConfig,
+ path1: [number, number],
+ path2: [number, number]
+): LovelaceConfig => {
+ const card1 = config.views[path1[0]].cards![path1[1]];
+ const card2 = config.views[path2[0]].cards![path2[1]];
+
+ const origView1 = config.views[path1[0]];
+ const newView1 = {
+ ...origView1,
+ cards: origView1.cards!.map((origCard, index) =>
+ index === path1[1] ? card2 : origCard
+ ),
+ };
+
+ const origView2 = path1[0] === path2[0] ? newView1 : config.views[path2[0]];
+ const newView2 = {
+ ...origView2,
+ cards: origView2.cards!.map((origCard, index) =>
+ index === path2[1] ? card1 : origCard
+ ),
+ };
+
+ return {
+ ...config,
+ views: config.views.map((origView, index) =>
+ index === path2[0] ? newView2 : index === path1[0] ? newView1 : origView
+ ),
+ };
+};
+
export const addView = (
config: LovelaceConfig,
viewConfig: LovelaceViewConfig
diff --git a/test-mocha/panels/lovelace/editor/config-util.spec.ts b/test-mocha/panels/lovelace/editor/config-util.spec.ts
new file mode 100644
index 0000000000..b8a9717b21
--- /dev/null
+++ b/test-mocha/panels/lovelace/editor/config-util.spec.ts
@@ -0,0 +1,54 @@
+import * as assert from "assert";
+
+import { swapCard } from "../../../../src/panels/lovelace/editor/config-util";
+import { LovelaceConfig } from "../../../../src/data/lovelace";
+
+describe("swapCard", () => {
+ it("swaps 2 cards in same view", () => {
+ const config: LovelaceConfig = {
+ views: [
+ {},
+ {
+ cards: [{ type: "card1" }, { type: "card2" }],
+ },
+ ],
+ };
+
+ const result = swapCard(config, [1, 0], [1, 1]);
+ const expected = {
+ views: [
+ {},
+ {
+ cards: [{ type: "card2" }, { type: "card1" }],
+ },
+ ],
+ };
+ assert.deepEqual(expected, result);
+ });
+
+ it("swaps 2 cards in different views", () => {
+ const config: LovelaceConfig = {
+ views: [
+ {
+ cards: [{ type: "v1-c1" }, { type: "v1-c2" }],
+ },
+ {
+ cards: [{ type: "v2-c1" }, { type: "v2-c2" }],
+ },
+ ],
+ };
+
+ const result = swapCard(config, [0, 0], [1, 1]);
+ const expected = {
+ views: [
+ {
+ cards: [{ type: "v2-c2" }, { type: "v1-c2" }],
+ },
+ {
+ cards: [{ type: "v2-c1" }, { type: "v1-c1" }],
+ },
+ ],
+ };
+ assert.deepEqual(expected, result);
+ });
+});