feat: 조직 이동 기능 작업
This commit is contained in:
@@ -3,7 +3,7 @@ import { ENDPOINT } from "@/shared/config";
|
||||
import type {
|
||||
MenuAuthorityList,
|
||||
MenuAuthorityParams,
|
||||
MenuAuthorityPayloadData,
|
||||
MenuAuthorityPayload,
|
||||
MenuAuthorityService,
|
||||
} from "../model/menu-authority-interface";
|
||||
|
||||
@@ -18,9 +18,7 @@ export class MenuAuthorityApiService implements MenuAuthorityService {
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async saveMenuAuthority(
|
||||
data: MenuAuthorityPayloadData[],
|
||||
): Promise<void> {
|
||||
public async saveMenuAuthority(data: MenuAuthorityPayload[]): Promise<void> {
|
||||
const response = await client.post<void>(
|
||||
`${ENDPOINT.CMS_SERVICE.MENU_AUTHRTS}`,
|
||||
data,
|
||||
|
||||
@@ -30,12 +30,10 @@ export const menuAuthorityFormSchema = z.object({
|
||||
|
||||
export type MenuAuthority = z.infer<typeof menuAuthoritySchema>;
|
||||
export type MenuAuthorityList = PageableList<MenuAuthority>;
|
||||
export type MenuAuthorityPayloadData = z.infer<
|
||||
typeof menuAuthorityPayloadSchema
|
||||
>;
|
||||
export type MenuAuthorityPayload = z.infer<typeof menuAuthorityPayloadSchema>;
|
||||
export type MenuAuthorityFormData = z.infer<typeof menuAuthorityFormSchema>;
|
||||
|
||||
export interface MenuAuthorityService {
|
||||
getMenuAuthorityList(params: MenuAuthorityParams): Promise<MenuAuthorityList>;
|
||||
saveMenuAuthority(data: MenuAuthorityPayloadData[]): Promise<void>;
|
||||
saveMenuAuthority(data: MenuAuthorityPayload[]): Promise<void>;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Checkbox } from "@common/components/ui";
|
||||
import type {
|
||||
MenuAuthority,
|
||||
MenuAuthorityFormData,
|
||||
MenuAuthorityPayloadData,
|
||||
MenuAuthorityPayload,
|
||||
} from "./menu-authority-interface";
|
||||
|
||||
export const createColumns = (
|
||||
@@ -13,7 +13,7 @@ export const createColumns = (
|
||||
const getCurrentRow = (i: number) => form.watch("menuAuthority")[i];
|
||||
|
||||
const handleCheckedChange =
|
||||
(i: number, key: keyof MenuAuthorityPayloadData) => (checked: boolean) => {
|
||||
(i: number, key: keyof MenuAuthorityPayload) => (checked: boolean) => {
|
||||
if (getCurrentRow(i)?.mode === "R") {
|
||||
form.setValue(`menuAuthority.${i}.mode`, "U");
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import { useAlertStore } from "@/shared/lib/use-alert-store";
|
||||
import {
|
||||
menuAuthorityFormSchema,
|
||||
type MenuAuthorityFormData,
|
||||
type MenuAuthorityPayloadData,
|
||||
type MenuAuthorityPayload,
|
||||
} from "../model/menu-authority-interface";
|
||||
import { createColumns } from "../model/menu-authority-table-columns";
|
||||
import { MenuAuthorityApi } from "../api/menu-authority-service";
|
||||
@@ -42,7 +42,7 @@ function ManagementAuthorityDialog({
|
||||
});
|
||||
|
||||
const { mutateAsync: saveMenuAuthority } = useMutation({
|
||||
mutationFn: (data: MenuAuthorityPayloadData[]) =>
|
||||
mutationFn: (data: MenuAuthorityPayload[]) =>
|
||||
MenuAuthorityApi.saveMenuAuthority(data),
|
||||
onSuccess: () => {
|
||||
alert("저장되었습니다.");
|
||||
|
||||
@@ -5,7 +5,7 @@ import type {
|
||||
PostService,
|
||||
PostingParams,
|
||||
Post,
|
||||
PostPayloadData,
|
||||
PostPayload,
|
||||
} from "../model/posting-interface";
|
||||
|
||||
export class PostingApiService implements PostService {
|
||||
@@ -19,7 +19,7 @@ export class PostingApiService implements PostService {
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async savePosting(data: PostPayloadData[]): Promise<Post[]> {
|
||||
public async savePosting(data: PostPayload[]): Promise<Post[]> {
|
||||
const response = await client.post<Post[]>(
|
||||
`${ENDPOINT.CMS_SERVICE.POSTINGS}`,
|
||||
data,
|
||||
|
||||
@@ -2,6 +2,6 @@ export { PostingApi } from "./api/posting-service";
|
||||
export {
|
||||
POSTING_TYPE,
|
||||
type Post,
|
||||
type PostPayloadData,
|
||||
type PostPayload,
|
||||
} from "./model/posting-interface";
|
||||
export { PostingDialog } from "./ui/posting-dialog";
|
||||
|
||||
@@ -41,10 +41,10 @@ export const postingFormSchema = z.object({
|
||||
});
|
||||
|
||||
export type Post = z.infer<typeof postSchema>;
|
||||
export type PostPayloadData = z.infer<typeof postPayloadSchema>;
|
||||
export type PostPayload = z.infer<typeof postPayloadSchema>;
|
||||
export type PostingFormData = z.infer<typeof postingFormSchema>;
|
||||
|
||||
export interface PostService {
|
||||
getPostingHistory: (params: PostingParams) => Promise<PageableList<Post>>;
|
||||
savePosting: (data: PostPayloadData[]) => Promise<Post[]>;
|
||||
savePosting: (data: PostPayload[]) => Promise<Post[]>;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ import {
|
||||
postingFormSchema,
|
||||
type PostingFormData,
|
||||
type PostingType,
|
||||
type PostPayloadData,
|
||||
type PostPayload,
|
||||
} from "../model/posting-interface";
|
||||
import { useAlertStore } from "@/shared/lib/use-alert-store";
|
||||
|
||||
@@ -76,7 +76,7 @@ function PostingDialog({ postingType, postingTargets }: PostingDialogProps) {
|
||||
});
|
||||
|
||||
const { mutateAsync: savePosting } = useMutation({
|
||||
mutationFn: (data: PostPayloadData[]) => PostingApi.savePosting(data),
|
||||
mutationFn: (data: PostPayload[]) => PostingApi.savePosting(data),
|
||||
onSuccess: () => {
|
||||
alert("저장되었습니다.");
|
||||
},
|
||||
|
||||
@@ -5,10 +5,11 @@ import type {
|
||||
UserOrganizationParams,
|
||||
UserOrganizationList,
|
||||
UserOrganizationService,
|
||||
UserOrganizationPayloadData,
|
||||
UserOrganizationPayload,
|
||||
SearchUserParams,
|
||||
SearchUserList,
|
||||
User,
|
||||
MoveUserOrganizationPayload,
|
||||
} from "../model/user-organization-interface";
|
||||
|
||||
export class UserOrganizationApiService implements UserOrganizationService {
|
||||
@@ -38,7 +39,7 @@ export class UserOrganizationApiService implements UserOrganizationService {
|
||||
}
|
||||
|
||||
public async saveUserOrganization(
|
||||
data: UserOrganizationPayloadData[],
|
||||
data: UserOrganizationPayload[],
|
||||
): Promise<User[]> {
|
||||
const response = await client.post<User[]>(
|
||||
`${ENDPOINT.CMS_SERVICE.USER_ORGANIZATION}`,
|
||||
@@ -46,6 +47,16 @@ export class UserOrganizationApiService implements UserOrganizationService {
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
public async moveUserOrganization(
|
||||
data: MoveUserOrganizationPayload[],
|
||||
): Promise<User[]> {
|
||||
const response = await client.post<User[]>(
|
||||
`${ENDPOINT.CMS_SERVICE.USER_ORGANIZATION}/move-ognz`,
|
||||
data,
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
}
|
||||
|
||||
export const UserOrganizationApi = new UserOrganizationApiService();
|
||||
|
||||
@@ -4,7 +4,8 @@ export {
|
||||
type TreeUserOrganization,
|
||||
type TreeUser,
|
||||
type UserOrganizationFormData,
|
||||
type UserOrganizationPayloadData,
|
||||
type UserOrganizationPayload,
|
||||
type User,
|
||||
type SearchUser,
|
||||
type MoveUserOrganizationPayload,
|
||||
} from "./model/user-organization-interface";
|
||||
|
||||
@@ -53,6 +53,12 @@ export interface TreeUserOrganization {
|
||||
children: TreeUserOrganization[];
|
||||
}
|
||||
|
||||
export interface MoveUserOrganizationPayload {
|
||||
ognzSn: number;
|
||||
toOgnzSn: number;
|
||||
userUnqId: string;
|
||||
}
|
||||
|
||||
export const userOrganizationPayloadSchema = z.object({
|
||||
mode: z.string(),
|
||||
ognzSn: z.number(),
|
||||
@@ -68,7 +74,7 @@ export const userOrganizationFormSchema = z.object({
|
||||
|
||||
export type UserOrganizationList = PageableList<User>;
|
||||
export type SearchUserList = PageableList<SearchUser>;
|
||||
export type UserOrganizationPayloadData = z.infer<
|
||||
export type UserOrganizationPayload = z.infer<
|
||||
typeof userOrganizationPayloadSchema
|
||||
>;
|
||||
export type UserOrganizationFormData = z.infer<
|
||||
@@ -81,5 +87,6 @@ export interface UserOrganizationService {
|
||||
): Promise<UserOrganizationList>;
|
||||
getUserOrganizationTreeList(): Promise<TreeUserOrganization[]>;
|
||||
searchUser(params: SearchUserParams): Promise<SearchUserList>;
|
||||
saveUserOrganization(data: UserOrganizationPayloadData[]): Promise<User[]>;
|
||||
saveUserOrganization(data: UserOrganizationPayload[]): Promise<User[]>;
|
||||
moveUserOrganization(data: MoveUserOrganizationPayload[]): Promise<User[]>;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
} from "@tanstack/react-table";
|
||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||
import { Button, DataTable } from "@common/components/ui";
|
||||
import { PostingApi, type PostPayloadData } from "@/entities/posting";
|
||||
import { PostingApi, type PostPayload } from "@/entities/posting";
|
||||
import { useAlertStore } from "@/shared/lib/use-alert-store";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import {
|
||||
@@ -58,7 +58,7 @@ function ModifyPage({ sequential }: { sequential: string }) {
|
||||
});
|
||||
|
||||
const { mutateAsync: savePosting } = useMutation({
|
||||
mutationFn: (data: PostPayloadData[]) => PostingApi.savePosting(data),
|
||||
mutationFn: (data: PostPayload[]) => PostingApi.savePosting(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: [ENDPOINT.CMS_SERVICE.POSTINGS, sequential],
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
} from "@tanstack/react-table";
|
||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||
import { Button, DataTable } from "@common/components/ui";
|
||||
import { PostingApi, type PostPayloadData } from "@/entities/posting";
|
||||
import { PostingApi, type PostPayload } from "@/entities/posting";
|
||||
import { useAlertStore } from "@/shared/lib/use-alert-store";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import { imageFormSchema, type ImageFormData } from "../model/image-interface";
|
||||
@@ -54,7 +54,7 @@ function ModifyPage({ sequential }: { sequential: string }) {
|
||||
});
|
||||
|
||||
const { mutateAsync: savePosting } = useMutation({
|
||||
mutationFn: (data: PostPayloadData[]) => PostingApi.savePosting(data),
|
||||
mutationFn: (data: PostPayload[]) => PostingApi.savePosting(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: [ENDPOINT.CMS_SERVICE.POSTINGS, sequential],
|
||||
|
||||
@@ -71,7 +71,7 @@ function AdditionalUserDialog({
|
||||
return (
|
||||
<Dialog {...props} open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button size="sm" color="gray">
|
||||
<Button size="sm" color="green">
|
||||
사용자 추가
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
import { useState } from "react";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import type { NodeModel } from "@minoru/react-dnd-treeview";
|
||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@common/components/ui";
|
||||
import { DndTree } from "@/widgets/dnd-tree";
|
||||
import {
|
||||
generateOrganizationTreeData,
|
||||
type OrganizationTree,
|
||||
} from "@/entities/organization";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
|
||||
type MoveOrganizationDialogProps = {
|
||||
buttonDisabled?: boolean;
|
||||
handleMoveOrganization: (organization: OrganizationTree) => Promise<void>;
|
||||
};
|
||||
|
||||
function MoveOrganizationDialog({
|
||||
buttonDisabled,
|
||||
handleMoveOrganization,
|
||||
}: MoveOrganizationDialogProps) {
|
||||
const { confirm } = useConfirm();
|
||||
const queryClient = useQueryClient();
|
||||
const queryData = queryClient.getQueryData<OrganizationTree[]>([
|
||||
ENDPOINT.CMS_SERVICE.ORGANIZATIONS,
|
||||
]);
|
||||
const organizationTreeData = generateOrganizationTreeData(queryData ?? []);
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [selectedOrganization, setSelectedOrganization] =
|
||||
useState<OrganizationTree | null>(null);
|
||||
|
||||
const handleNodeSelect = (node: NodeModel<OrganizationTree>) => {
|
||||
if (!node.data) return;
|
||||
setSelectedOrganization(node.data);
|
||||
};
|
||||
|
||||
const onMoveOrganization = async () => {
|
||||
if (await confirm("이동하시겠습니까?")) {
|
||||
await handleMoveOrganization(selectedOrganization as OrganizationTree);
|
||||
setOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button size="sm" color="white" disabled={buttonDisabled}>
|
||||
조직 이동
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent aria-describedby={undefined}>
|
||||
<DialogHeader>
|
||||
<DialogTitle>조직 이동</DialogTitle>
|
||||
</DialogHeader>
|
||||
<DndTree
|
||||
tree={organizationTreeData ?? []}
|
||||
selectedNodeId={selectedOrganization?.ognzSn ?? 0}
|
||||
handleSelectNode={handleNodeSelect}
|
||||
classes={{
|
||||
root: "p-0",
|
||||
}}
|
||||
/>
|
||||
<DialogFooter className="!justify-center">
|
||||
<DialogClose asChild>
|
||||
<Button color="white">취소</Button>
|
||||
</DialogClose>
|
||||
<Button onClick={onMoveOrganization}>저장</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
export { MoveOrganizationDialog };
|
||||
@@ -30,14 +30,17 @@ import {
|
||||
UserOrganizationApi,
|
||||
userOrganizationFormSchema,
|
||||
type UserOrganizationFormData,
|
||||
type UserOrganizationPayloadData,
|
||||
type UserOrganizationPayload,
|
||||
type User,
|
||||
type SearchUser,
|
||||
type MoveUserOrganizationPayload,
|
||||
} from "@/entities/user-organization";
|
||||
import { CodeApi, type ICode } from "@/entities/code";
|
||||
import type { OrganizationTree } from "@/entities/organization";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import { useAlertStore } from "@/shared/lib/use-alert-store";
|
||||
import { AdditionalUserDialog } from "./additional-user-dialog";
|
||||
import { MoveOrganizationDialog } from "./move-organization-dialog";
|
||||
|
||||
type UserOrganizationSectionProps = {
|
||||
ognzSn: number;
|
||||
@@ -72,7 +75,7 @@ function UserOrganizationSection({ ognzSn }: UserOrganizationSectionProps) {
|
||||
});
|
||||
|
||||
const { mutate: saveUserOrganization } = useMutation({
|
||||
mutationFn: (data: UserOrganizationPayloadData[]) =>
|
||||
mutationFn: (data: UserOrganizationPayload[]) =>
|
||||
UserOrganizationApi.saveUserOrganization(data),
|
||||
onSuccess: () => {
|
||||
alert("저장되었습니다.");
|
||||
@@ -82,6 +85,17 @@ function UserOrganizationSection({ ognzSn }: UserOrganizationSectionProps) {
|
||||
},
|
||||
});
|
||||
|
||||
const { mutate: moveUserOrganization } = useMutation({
|
||||
mutationFn: (data: MoveUserOrganizationPayload[]) =>
|
||||
UserOrganizationApi.moveUserOrganization(data),
|
||||
onSuccess: () => {
|
||||
alert("이동되었습니다.");
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: [ENDPOINT.CMS_SERVICE.USER_ORGANIZATION, ognzSn],
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const form = useForm<UserOrganizationFormData>({
|
||||
resolver: zodResolver(userOrganizationFormSchema),
|
||||
values: {
|
||||
@@ -172,6 +186,17 @@ function UserOrganizationSection({ ognzSn }: UserOrganizationSectionProps) {
|
||||
}
|
||||
};
|
||||
|
||||
const handleMoveOrganization = async (organization: OrganizationTree) => {
|
||||
const payloadData: MoveUserOrganizationPayload[] = selectedUsers.map(
|
||||
(user) => ({
|
||||
ognzSn: user.ognzSn,
|
||||
toOgnzSn: organization.ognzSn!,
|
||||
userUnqId: user.userUnqId,
|
||||
}),
|
||||
);
|
||||
moveUserOrganization(payloadData);
|
||||
};
|
||||
|
||||
const isUserSelected = useCallback(
|
||||
(userUnqId: string) =>
|
||||
selectedUsers.some((item) => item.userUnqId === userUnqId),
|
||||
@@ -181,6 +206,7 @@ function UserOrganizationSection({ ognzSn }: UserOrganizationSectionProps) {
|
||||
useEffect(() => {
|
||||
if (userOrganizationList?.content) {
|
||||
setUserList(userOrganizationList.content);
|
||||
setSelectedUsers([]);
|
||||
}
|
||||
}, [userOrganizationList]);
|
||||
|
||||
@@ -189,6 +215,13 @@ function UserOrganizationSection({ ognzSn }: UserOrganizationSectionProps) {
|
||||
<div className="card-header">
|
||||
<h3 className="text-2xl font-medium text-label">소속원 목록</h3>
|
||||
<div className="flex gap-2">
|
||||
<MoveOrganizationDialog
|
||||
buttonDisabled={
|
||||
userOrganizationList?.content.length === 0 ||
|
||||
selectedUsers.length === 0
|
||||
}
|
||||
handleMoveOrganization={handleMoveOrganization}
|
||||
/>
|
||||
<AdditionalUserDialog onAddUsers={handleAddUsers} />
|
||||
<Button
|
||||
size="sm"
|
||||
|
||||
@@ -15,6 +15,7 @@ type CustomNodeProps<T extends TreeData> = {
|
||||
isSelected: boolean;
|
||||
isAdditionalParent: boolean;
|
||||
treeMethods: TreeMethods | null;
|
||||
readOnly: boolean;
|
||||
onToggle: (id: NodeModel["id"]) => void;
|
||||
onSelect: (node: NodeModel<T>) => void;
|
||||
updateNodeName: (id: NodeModel["id"], nodeName: string) => Promise<void>;
|
||||
@@ -27,6 +28,7 @@ function CustomNode<T extends TreeData>({
|
||||
isSelected,
|
||||
isAdditionalParent,
|
||||
treeMethods,
|
||||
readOnly,
|
||||
onToggle,
|
||||
onSelect,
|
||||
updateNodeName,
|
||||
@@ -58,8 +60,9 @@ function CustomNode<T extends TreeData>({
|
||||
<div
|
||||
style={{ paddingInlineStart: indent }}
|
||||
className={cn(
|
||||
"group flex cursor-pointer items-center justify-between gap-2 rounded-sm p-2 hover:bg-accent",
|
||||
"flex cursor-pointer items-center justify-between gap-2 rounded-sm p-2 hover:bg-accent",
|
||||
isSelected && "!bg-[rgba(32,148,250,0.2)]",
|
||||
!readOnly && "group",
|
||||
)}
|
||||
>
|
||||
{editMode ? (
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
type NodeModel,
|
||||
type TreeMethods,
|
||||
type DropOptions,
|
||||
type Classes,
|
||||
} from "@minoru/react-dnd-treeview";
|
||||
import { Button } from "@common/components/ui";
|
||||
import { cn } from "@common/components/lib";
|
||||
@@ -22,14 +23,14 @@ type EditableNodeProps = { depth: number };
|
||||
|
||||
type DndTreeProps<T extends TreeData> = {
|
||||
tree: NodeModel<T>[];
|
||||
selectedNodeId: number;
|
||||
selectedNodeId?: number;
|
||||
classes?: {
|
||||
wrapper: string;
|
||||
};
|
||||
renderEditableNode: (props: EditableNodeProps) => ReactElement;
|
||||
handleSelectNode: (node: NodeModel<T>) => void;
|
||||
handleDropNode: (newTree: NodeModel<T>[], options: DropOptions<T>) => void;
|
||||
updateNodeName: (id: NodeModel["id"], nodeName: string) => Promise<void>;
|
||||
wrapper?: string;
|
||||
} & Classes<T>;
|
||||
renderEditableNode?: (props: EditableNodeProps) => ReactElement;
|
||||
handleSelectNode?: (node: NodeModel<T>) => void;
|
||||
handleDropNode?: (newTree: NodeModel<T>[], options: DropOptions<T>) => void;
|
||||
updateNodeName?: (id: NodeModel["id"], nodeName: string) => Promise<void>;
|
||||
};
|
||||
|
||||
function DndTree<T extends TreeData>({
|
||||
@@ -63,7 +64,8 @@ function DndTree<T extends TreeData>({
|
||||
rootId={0}
|
||||
ref={treeMethods}
|
||||
render={(node: NodeModel<T>, { depth, isOpen, onToggle }) => {
|
||||
if (node.id === -1) return renderEditableNode({ depth });
|
||||
if (node.id === -1)
|
||||
return renderEditableNode?.({ depth }) ?? <></>;
|
||||
return (
|
||||
<CustomNode
|
||||
node={node}
|
||||
@@ -72,18 +74,22 @@ function DndTree<T extends TreeData>({
|
||||
isOpen={isOpen}
|
||||
isSelected={selectedNodeId === node.id}
|
||||
isAdditionalParent={isAdditionalParent(node)}
|
||||
readOnly={typeof updateNodeName === "undefined"}
|
||||
onToggle={onToggle}
|
||||
onSelect={handleSelectNode}
|
||||
updateNodeName={updateNodeName}
|
||||
onSelect={(node) => handleSelectNode?.(node)}
|
||||
updateNodeName={(id, nodeName) =>
|
||||
updateNodeName?.(id, nodeName) ?? Promise.resolve()
|
||||
}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
onDrop={handleDropNode}
|
||||
onDrop={(newTree, options) => handleDropNode?.(newTree, options)}
|
||||
classes={{
|
||||
root: "p-4",
|
||||
container: "flex flex-col",
|
||||
dropTarget: "!bg-[rgba(32,148,250,0.5)] rounded-sm",
|
||||
placeholder: "relative",
|
||||
...classes,
|
||||
}}
|
||||
sort={false}
|
||||
dropTargetOffset={5}
|
||||
|
||||
Reference in New Issue
Block a user