diff --git a/src/components/profile/rule-item.tsx b/src/components/profile/rule-item.tsx index e5c55396..2b30f42c 100644 --- a/src/components/profile/rule-item.tsx +++ b/src/components/profile/rule-item.tsx @@ -8,6 +8,8 @@ import { alpha, } from "@mui/material"; import { DeleteForeverRounded, UndoRounded } from "@mui/icons-material"; +import { useSortable } from "@dnd-kit/sortable"; +import { CSS } from "@dnd-kit/utilities"; interface Props { type: "prepend" | "original" | "delete" | "append"; ruleRaw: string; @@ -17,7 +19,8 @@ interface Props { export const RuleItem = (props: Props) => { let { type, ruleRaw, onDelete } = props; const rule = ruleRaw.replace(",no-resolve", "").split(","); - + const { attributes, listeners, setNodeRef, transform, transition } = + useSortable({ id: ruleRaw }); return ( ({ @@ -31,9 +34,14 @@ export const RuleItem = (props: Props) => { ? alpha(palette.error.main, 0.5) : alpha(palette.success.main, 0.5), mb: 1, + transform: CSS.Transform.toString(transform), + transition, })} > diff --git a/src/components/profile/rules-editor-viewer.tsx b/src/components/profile/rules-editor-viewer.tsx index c9c0248f..aab7dc27 100644 --- a/src/components/profile/rules-editor-viewer.tsx +++ b/src/components/profile/rules-editor-viewer.tsx @@ -2,7 +2,19 @@ import { ReactNode, useEffect, useState } from "react"; import { useLockFn } from "ahooks"; import yaml from "js-yaml"; import { useTranslation } from "react-i18next"; - +import { + DndContext, + closestCenter, + KeyboardSensor, + PointerSensor, + useSensor, + useSensors, + DragEndEvent, +} from "@dnd-kit/core"; +import { + SortableContext, + sortableKeyboardCoordinates, +} from "@dnd-kit/sortable"; import { Autocomplete, Button, @@ -134,6 +146,38 @@ export const RulesEditorViewer = (props: Props) => { const [appendSeq, setAppendSeq] = useState([]); const [deleteSeq, setDeleteSeq] = useState([]); + const sensors = useSensors( + useSensor(PointerSensor), + useSensor(KeyboardSensor, { + coordinateGetter: sortableKeyboardCoordinates, + }) + ); + const reorder = (list: string[], startIndex: number, endIndex: number) => { + const result = Array.from(list); + const [removed] = result.splice(startIndex, 1); + result.splice(endIndex, 0, removed); + return result; + }; + const onPrependDragEnd = async (event: DragEndEvent) => { + const { active, over } = event; + if (over) { + if (active.id !== over.id) { + let activeIndex = prependSeq.indexOf(active.id.toString()); + let overIndex = prependSeq.indexOf(over.id.toString()); + setPrependSeq(reorder(prependSeq, activeIndex, overIndex)); + } + } + }; + const onAppendDragEnd = async (event: DragEndEvent) => { + const { active, over } = event; + if (over) { + if (active.id !== over.id) { + let activeIndex = appendSeq.indexOf(active.id.toString()); + let overIndex = appendSeq.indexOf(over.id.toString()); + setAppendSeq(reorder(appendSeq, activeIndex, overIndex)); + } + } + }; const fetchContent = async () => { let data = await readProfileFile(property); let obj = yaml.load(data) as { prepend: []; append: []; delete: [] }; @@ -325,20 +369,32 @@ export const RulesEditorViewer = (props: Props) => { }} > {prependSeq.length > 0 && ( - - {prependSeq.map((item, index) => { - return ( - { - setPrependSeq(prependSeq.filter((v) => v !== item)); - }} - /> - ); - })} - + + + { + return x; + })} + > + {prependSeq.map((item, index) => { + return ( + { + setPrependSeq(prependSeq.filter((v) => v !== item)); + }} + /> + ); + })} + + + )} @@ -361,20 +417,32 @@ export const RulesEditorViewer = (props: Props) => { {appendSeq.length > 0 && ( - - {appendSeq.map((item, index) => { - return ( - { - setAppendSeq(appendSeq.filter((v) => v !== item)); - }} - /> - ); - })} - + + { + return x; + })} + > + + {appendSeq.map((item, index) => { + return ( + { + setAppendSeq(appendSeq.filter((v) => v !== item)); + }} + /> + ); + })} + + + )}