feat: add duplication action for items (#926)

This commit is contained in:
Meier Lukas
2024-08-08 20:37:41 +02:00
committed by GitHub
parent 365e267b8d
commit 81946e50a9
3 changed files with 44 additions and 2 deletions

View File

@@ -45,6 +45,10 @@ interface CreateItem {
kind: WidgetKind; kind: WidgetKind;
} }
interface DuplicateItem {
itemId: string;
}
export const useItemActions = () => { export const useItemActions = () => {
const { updateBoard } = useUpdateBoard(); const { updateBoard } = useUpdateBoard();
@@ -87,6 +91,38 @@ export const useItemActions = () => {
[updateBoard], [updateBoard],
); );
const duplicateItem = useCallback(
({ itemId }: DuplicateItem) => {
updateBoard((previous) => {
const itemToDuplicate = previous.sections
.flatMap((section) => section.items)
.find((item) => item.id === itemId);
if (!itemToDuplicate) return previous;
const newItem = {
...itemToDuplicate,
id: createId(),
yOffset: undefined,
xOffset: undefined,
} satisfies Omit<Item, "yOffset" | "xOffset"> & { yOffset?: number; xOffset?: number };
return {
...previous,
sections: previous.sections.map((section) => {
// Return same section if item is not in it
if (!section.items.some((item) => item.id === itemId)) return section;
return {
...section,
items: section.items.concat(newItem as unknown as Item),
};
}),
};
});
},
[updateBoard],
);
const updateItemOptions = useCallback( const updateItemOptions = useCallback(
({ itemId, newOptions }: UpdateItemOptions) => { ({ itemId, newOptions }: UpdateItemOptions) => {
updateBoard((previous) => { updateBoard((previous) => {
@@ -258,6 +294,7 @@ export const useItemActions = () => {
updateItemOptions, updateItemOptions,
updateItemAdvancedOptions, updateItemAdvancedOptions,
updateItemIntegrations, updateItemIntegrations,
duplicateItem,
createItem, createItem,
}; };
}; };

View File

@@ -2,7 +2,7 @@ import type { RefObject } from "react";
import { useEffect, useMemo, useRef } from "react"; import { useEffect, useMemo, useRef } from "react";
import { ActionIcon, Card, Menu } from "@mantine/core"; import { ActionIcon, Card, Menu } from "@mantine/core";
import { useElementSize } from "@mantine/hooks"; import { useElementSize } from "@mantine/hooks";
import { IconDotsVertical, IconLayoutKanban, IconPencil, IconTrash } from "@tabler/icons-react"; import { IconCopy, IconDotsVertical, IconLayoutKanban, IconPencil, IconTrash } from "@tabler/icons-react";
import { QueryErrorResetBoundary } from "@tanstack/react-query"; import { QueryErrorResetBoundary } from "@tanstack/react-query";
import combineClasses from "clsx"; import combineClasses from "clsx";
import { ErrorBoundary } from "react-error-boundary"; import { ErrorBoundary } from "react-error-boundary";
@@ -147,7 +147,8 @@ const ItemMenu = ({
const { openModal } = useModalAction(WidgetEditModal); const { openModal } = useModalAction(WidgetEditModal);
const { openConfirmModal } = useConfirmModal(); const { openConfirmModal } = useConfirmModal();
const [isEditMode] = useEditMode(); const [isEditMode] = useEditMode();
const { updateItemOptions, updateItemAdvancedOptions, updateItemIntegrations, removeItem } = useItemActions(); const { updateItemOptions, updateItemAdvancedOptions, updateItemIntegrations, duplicateItem, removeItem } =
useItemActions();
const { data: integrationData, isPending } = clientApi.integration.all.useQuery(); const { data: integrationData, isPending } = clientApi.integration.all.useQuery();
const currentDefinition = useMemo(() => widgetImports[item.kind].definition, [item.kind]); const currentDefinition = useMemo(() => widgetImports[item.kind].definition, [item.kind]);
@@ -216,6 +217,9 @@ const ItemMenu = ({
{tItem("action.edit")} {tItem("action.edit")}
</Menu.Item> </Menu.Item>
<Menu.Item leftSection={<IconLayoutKanban size={16} />}>{tItem("action.move")}</Menu.Item> <Menu.Item leftSection={<IconLayoutKanban size={16} />}>{tItem("action.move")}</Menu.Item>
<Menu.Item leftSection={<IconCopy size={16} />} onClick={() => duplicateItem({ itemId: item.id })}>
{tItem("action.duplicate")}
</Menu.Item>
<Menu.Divider /> <Menu.Divider />
<Menu.Label c="red.6">{t("common.dangerZone")}</Menu.Label> <Menu.Label c="red.6">{t("common.dangerZone")}</Menu.Label>
<Menu.Item c="red.6" leftSection={<IconTrash size={16} />} onClick={openRemoveModal}> <Menu.Item c="red.6" leftSection={<IconTrash size={16} />} onClick={openRemoveModal}>

View File

@@ -662,6 +662,7 @@ export default {
import: "Import item", import: "Import item",
edit: "Edit item", edit: "Edit item",
move: "Move item", move: "Move item",
duplicate: "Duplicate item",
remove: "Remove item", remove: "Remove item",
}, },
menu: { menu: {