feat: drag to reorder rules

This commit is contained in:
MystiPanda 2024-06-30 23:16:21 +08:00
parent 720b46d790
commit 51a49b94d8
No known key found for this signature in database
2 changed files with 106 additions and 30 deletions

View File

@ -8,6 +8,8 @@ import {
alpha, alpha,
} from "@mui/material"; } from "@mui/material";
import { DeleteForeverRounded, UndoRounded } from "@mui/icons-material"; import { DeleteForeverRounded, UndoRounded } from "@mui/icons-material";
import { useSortable } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
interface Props { interface Props {
type: "prepend" | "original" | "delete" | "append"; type: "prepend" | "original" | "delete" | "append";
ruleRaw: string; ruleRaw: string;
@ -17,7 +19,8 @@ interface Props {
export const RuleItem = (props: Props) => { export const RuleItem = (props: Props) => {
let { type, ruleRaw, onDelete } = props; let { type, ruleRaw, onDelete } = props;
const rule = ruleRaw.replace(",no-resolve", "").split(","); const rule = ruleRaw.replace(",no-resolve", "").split(",");
const { attributes, listeners, setNodeRef, transform, transition } =
useSortable({ id: ruleRaw });
return ( return (
<ListItem <ListItem
sx={({ palette }) => ({ sx={({ palette }) => ({
@ -31,9 +34,14 @@ export const RuleItem = (props: Props) => {
? alpha(palette.error.main, 0.5) ? alpha(palette.error.main, 0.5)
: alpha(palette.success.main, 0.5), : alpha(palette.success.main, 0.5),
mb: 1, mb: 1,
transform: CSS.Transform.toString(transform),
transition,
})} })}
> >
<ListItemText <ListItemText
{...attributes}
{...listeners}
ref={setNodeRef}
sx={{ px: 1 }} sx={{ px: 1 }}
primary={ primary={
<> <>

View File

@ -2,7 +2,19 @@ import { ReactNode, useEffect, useState } from "react";
import { useLockFn } from "ahooks"; import { useLockFn } from "ahooks";
import yaml from "js-yaml"; import yaml from "js-yaml";
import { useTranslation } from "react-i18next"; 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 { import {
Autocomplete, Autocomplete,
Button, Button,
@ -134,6 +146,38 @@ export const RulesEditorViewer = (props: Props) => {
const [appendSeq, setAppendSeq] = useState<string[]>([]); const [appendSeq, setAppendSeq] = useState<string[]>([]);
const [deleteSeq, setDeleteSeq] = useState<string[]>([]); const [deleteSeq, setDeleteSeq] = useState<string[]>([]);
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 () => { const fetchContent = async () => {
let data = await readProfileFile(property); let data = await readProfileFile(property);
let obj = yaml.load(data) as { prepend: []; append: []; delete: [] }; let obj = yaml.load(data) as { prepend: []; append: []; delete: [] };
@ -325,20 +369,32 @@ export const RulesEditorViewer = (props: Props) => {
}} }}
> >
{prependSeq.length > 0 && ( {prependSeq.length > 0 && (
<List sx={{ borderBottom: "solid 1px var(--divider-color)" }}> <DndContext
{prependSeq.map((item, index) => { sensors={sensors}
return ( collisionDetection={closestCenter}
<RuleItem onDragEnd={onPrependDragEnd}
key={`${item}-${index}`} >
type="prepend" <List sx={{ borderBottom: "solid 1px var(--divider-color)" }}>
ruleRaw={item} <SortableContext
onDelete={() => { items={prependSeq.map((x) => {
setPrependSeq(prependSeq.filter((v) => v !== item)); return x;
}} })}
/> >
); {prependSeq.map((item, index) => {
})} return (
</List> <RuleItem
key={`${item}-${index}`}
type="prepend"
ruleRaw={item}
onDelete={() => {
setPrependSeq(prependSeq.filter((v) => v !== item));
}}
/>
);
})}
</SortableContext>
</List>
</DndContext>
)} )}
<List> <List>
@ -361,20 +417,32 @@ export const RulesEditorViewer = (props: Props) => {
</List> </List>
{appendSeq.length > 0 && ( {appendSeq.length > 0 && (
<List sx={{ borderTop: "solid 1px var(--divider-color)" }}> <DndContext
{appendSeq.map((item, index) => { sensors={sensors}
return ( collisionDetection={closestCenter}
<RuleItem onDragEnd={onAppendDragEnd}
key={`${item}-${index}`} >
type="append" <SortableContext
ruleRaw={item} items={appendSeq.map((x) => {
onDelete={() => { return x;
setAppendSeq(appendSeq.filter((v) => v !== item)); })}
}} >
/> <List sx={{ borderTop: "solid 1px var(--divider-color)" }}>
); {appendSeq.map((item, index) => {
})} return (
</List> <RuleItem
key={`${item}-${index}`}
type="append"
ruleRaw={item}
onDelete={() => {
setAppendSeq(appendSeq.filter((v) => v !== item));
}}
/>
);
})}
</List>
</SortableContext>
</DndContext>
)} )}
</div> </div>
</DialogContent> </DialogContent>