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,
} 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 (
<ListItem
sx={({ palette }) => ({
@ -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,
})}
>
<ListItemText
{...attributes}
{...listeners}
ref={setNodeRef}
sx={{ px: 1 }}
primary={
<>

View File

@ -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<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 () => {
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 && (
<List sx={{ borderBottom: "solid 1px var(--divider-color)" }}>
{prependSeq.map((item, index) => {
return (
<RuleItem
key={`${item}-${index}`}
type="prepend"
ruleRaw={item}
onDelete={() => {
setPrependSeq(prependSeq.filter((v) => v !== item));
}}
/>
);
})}
</List>
<DndContext
sensors={sensors}
collisionDetection={closestCenter}
onDragEnd={onPrependDragEnd}
>
<List sx={{ borderBottom: "solid 1px var(--divider-color)" }}>
<SortableContext
items={prependSeq.map((x) => {
return x;
})}
>
{prependSeq.map((item, index) => {
return (
<RuleItem
key={`${item}-${index}`}
type="prepend"
ruleRaw={item}
onDelete={() => {
setPrependSeq(prependSeq.filter((v) => v !== item));
}}
/>
);
})}
</SortableContext>
</List>
</DndContext>
)}
<List>
@ -361,20 +417,32 @@ export const RulesEditorViewer = (props: Props) => {
</List>
{appendSeq.length > 0 && (
<List sx={{ borderTop: "solid 1px var(--divider-color)" }}>
{appendSeq.map((item, index) => {
return (
<RuleItem
key={`${item}-${index}`}
type="append"
ruleRaw={item}
onDelete={() => {
setAppendSeq(appendSeq.filter((v) => v !== item));
}}
/>
);
})}
</List>
<DndContext
sensors={sensors}
collisionDetection={closestCenter}
onDragEnd={onAppendDragEnd}
>
<SortableContext
items={appendSeq.map((x) => {
return x;
})}
>
<List sx={{ borderTop: "solid 1px var(--divider-color)" }}>
{appendSeq.map((item, index) => {
return (
<RuleItem
key={`${item}-${index}`}
type="append"
ruleRaw={item}
onDelete={() => {
setAppendSeq(appendSeq.filter((v) => v !== item));
}}
/>
);
})}
</List>
</SortableContext>
</DndContext>
)}
</div>
</DialogContent>