feat(board): add board duplication (#1856)

Co-authored-by: Manuel <30572287+manuel-rw@users.noreply.github.com>
This commit is contained in:
Meier Lukas
2025-01-04 19:53:57 +01:00
committed by GitHub
parent d98552540a
commit 49d10f7ad0
6 changed files with 251 additions and 3 deletions

View File

@@ -0,0 +1,96 @@
import { Button, Group, Stack, Text, TextInput } from "@mantine/core";
import { clientApi } from "@homarr/api/client";
import type { MaybePromise } from "@homarr/common/types";
import { useZodForm } from "@homarr/form";
import { showErrorNotification, showSuccessNotification } from "@homarr/notifications";
import { useI18n } from "@homarr/translation/client";
import { validation } from "@homarr/validation";
import { createModal } from "../../../modals/src/creator";
import { useBoardNameStatus } from "./add-board-modal";
interface InnerProps {
board: {
id: string;
name: string;
};
onSuccess: () => MaybePromise<void>;
}
export const DuplicateBoardModal = createModal<InnerProps>(({ actions, innerProps }) => {
const t = useI18n();
const form = useZodForm(validation.board.duplicate.omit({ id: true }), {
mode: "controlled",
initialValues: {
name: innerProps.board.name,
},
});
const boardNameStatus = useBoardNameStatus(form.values.name);
const { mutateAsync, isPending } = clientApi.board.duplicateBoard.useMutation();
return (
<form
onSubmit={form.onSubmit(async (values) => {
// Prevent submit before name availability check
if (!boardNameStatus.canSubmit) return;
await mutateAsync(
{
...values,
id: innerProps.board.id,
},
{
async onSuccess() {
actions.closeModal();
showSuccessNotification({
title: t("board.action.duplicate.notification.success.title"),
message: t("board.action.duplicate.notification.success.message"),
});
await innerProps.onSuccess();
},
onError() {
showErrorNotification({
title: t("board.action.duplicate.notification.error.title"),
message: t("board.action.duplicate.notification.error.message"),
});
},
},
);
})}
>
<Stack>
<Text size="sm" c="gray.6">
{t("board.action.duplicate.message", { name: innerProps.board.name })}
</Text>
<TextInput
label={t("board.field.name.label")}
data-autofocus
{...form.getInputProps("name")}
description={
boardNameStatus.description ? (
<Group c={boardNameStatus.description.color} gap="xs" align="center">
{boardNameStatus.description.icon ? <boardNameStatus.description.icon size={16} /> : null}
<span>{boardNameStatus.description.label}</span>
</Group>
) : null
}
withAsterisk
/>
<Group justify="end">
<Button variant="subtle" color="gray" onClick={actions.closeModal}>
{t("common.action.cancel")}
</Button>
<Button type="submit" loading={isPending}>
{t("common.action.create")}
</Button>
</Group>
</Stack>
</form>
);
}).withOptions({
defaultTitle(t) {
return t("board.action.duplicate.title");
},
});

View File

@@ -1,2 +1,3 @@
export { AddBoardModal } from "./add-board-modal";
export { ImportBoardModal } from "./import-board-modal";
export { DuplicateBoardModal } from "./duplicate-board-modal";