feat: mod delete

This commit is contained in:
Kentai Radiquum 2025-05-06 05:38:57 +05:00
parent e453f336a8
commit 34df17d4dd
Signed by: Radiquum
GPG key ID: 858E8EE696525EED
3 changed files with 133 additions and 399 deletions

View file

@ -1,4 +1,7 @@
import { MOD_ENDPOINT } from "@/api/ENDPOINTS";
import { Mod } from "@/types/mod";
import { import {
Button,
Checkbox, Checkbox,
Table, Table,
TableBody, TableBody,
@ -7,8 +10,33 @@ import {
TableHeadCell, TableHeadCell,
TableRow, TableRow,
} from "flowbite-react"; } from "flowbite-react";
import { HiDownload, HiTrash } from "react-icons/hi";
import { toast } from "react-toastify";
export const ModTable = (props: {
mods: Mod[];
updatePack: () => void;
packID: string;
}) => {
async function deleteMod(slug: string, title: string) {
if (!window) return;
if (window.confirm(`Delete mod ${title}?`)) {
const res = await fetch(MOD_ENDPOINT("deleteMod", props.packID, slug));
const data = await res.json();
if (data.status != "ok") {
toast.error(data.message, {
autoClose: 2500,
closeOnClick: true,
draggable: true,
});
return;
}
props.updatePack();
}
}
export const ModTable = () => {
return ( return (
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<Table hoverable> <Table hoverable>
@ -17,395 +45,66 @@ export const ModTable = () => {
<TableHeadCell className="p-4"> <TableHeadCell className="p-4">
<Checkbox /> <Checkbox />
</TableHeadCell> </TableHeadCell>
<TableHeadCell>Product name</TableHeadCell> <TableHeadCell>Icon</TableHeadCell>
<TableHeadCell>Color</TableHeadCell> <TableHeadCell>Title</TableHeadCell>
<TableHeadCell>Category</TableHeadCell> <TableHeadCell>Version</TableHeadCell>
<TableHeadCell>Price</TableHeadCell> <TableHeadCell>Developer</TableHeadCell>
<TableHeadCell>Source</TableHeadCell>
<TableHeadCell>Source URL</TableHeadCell>
<TableHeadCell> <TableHeadCell>
<span className="sr-only">Edit</span> <span className="sr-only">Actions</span>
</TableHeadCell> </TableHeadCell>
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody className="divide-y"> <TableBody className="divide-y">
<TableRow className="bg-white dark:border-gray-700 dark:bg-gray-800"> {props.mods &&
<TableCell className="p-4"> props.mods.length > 0 &&
<Checkbox /> props.mods.map((mod) => {
</TableCell> return (
<TableCell className="whitespace-nowrap font-medium text-gray-900 dark:text-white"> <TableRow
Apple MacBook Pro 17 key={`mod-${mod.slug}`}
</TableCell> className="bg-white dark:border-gray-700 dark:bg-gray-800"
<TableCell>Sliver</TableCell> >
<TableCell>Laptop</TableCell> <TableCell className="p-4">
<TableCell>$2999</TableCell> <Checkbox />
<TableCell> </TableCell>
<a <TableCell>
href="#" {/* eslint-disable-next-line @next/next/no-img-element */}
className="font-medium text-cyan-600 hover:underline dark:text-cyan-500" <img alt="" src={mod.icon} className="w-8 h-8 rounded-lg" />
> </TableCell>
Edit <TableCell className="whitespace-nowrap font-medium text-gray-900 dark:text-white">
</a> {mod.title}
</TableCell> </TableCell>
</TableRow> <TableCell>{mod.file.version}</TableCell>
<TableRow className="bg-white dark:border-gray-700 dark:bg-gray-800"> <TableCell>{mod.developers.join(", ")}</TableCell>
<TableCell className="p-4"> <TableCell>{mod.source}</TableCell>
<Checkbox /> <TableCell>{mod.url}</TableCell>
</TableCell> <TableCell>
<TableCell className="whitespace-nowrap font-medium text-gray-900 dark:text-white"> <div className="flex gap-2">
Microsoft Surface Pro <Button size="sm">
</TableCell> Download <HiDownload className="ml-2 h-4 w-4" />
<TableCell>White</TableCell> </Button>
<TableCell>Laptop PC</TableCell> <Button
<TableCell>$1999</TableCell> color={"red"}
<TableCell> size="sm"
<a onClick={() => deleteMod(mod.slug, mod.title)}
href="#" >
className="font-medium text-cyan-600 hover:underline dark:text-cyan-500" Delete <HiTrash className="ml-2 h-4 w-4" />
> </Button>
Edit </div>
</a> </TableCell>
</TableCell> </TableRow>
</TableRow> );
<TableRow className="bg-white dark:border-gray-700 dark:bg-gray-800"> })}
<TableCell className="p-4"> <TableRow className="bg-white dark:bg-[#374151] hover:bg-white! hover:dark:bg-[#374151]! dark:border-gray-700">
<Checkbox /> <TableCell className="p-4"></TableCell>
</TableCell> <TableCell></TableCell>
<TableCell className="whitespace-nowrap font-medium text-gray-900 dark:text-white"> <TableCell></TableCell>
Magic Mouse 2 <TableCell></TableCell>
</TableCell> <TableCell></TableCell>
<TableCell>Black</TableCell> <TableCell></TableCell>
<TableCell>Accessories</TableCell> <TableCell></TableCell>
<TableCell>$99</TableCell> <TableCell></TableCell>
<TableCell>
<a
href="#"
className="font-medium text-cyan-600 hover:underline dark:text-cyan-500"
>
Edit
</a>
</TableCell>
</TableRow>
<TableRow className="bg-white dark:border-gray-700 dark:bg-gray-800">
<TableCell className="p-4">
<Checkbox />
</TableCell>
<TableCell className="whitespace-nowrap font-medium text-gray-900 dark:text-white">
Magic Mouse 2
</TableCell>
<TableCell>Black</TableCell>
<TableCell>Accessories</TableCell>
<TableCell>$99</TableCell>
<TableCell>
<a
href="#"
className="font-medium text-cyan-600 hover:underline dark:text-cyan-500"
>
Edit
</a>
</TableCell>
</TableRow>
<TableRow className="bg-white dark:border-gray-700 dark:bg-gray-800">
<TableCell className="p-4">
<Checkbox />
</TableCell>
<TableCell className="whitespace-nowrap font-medium text-gray-900 dark:text-white">
Magic Mouse 2
</TableCell>
<TableCell>Black</TableCell>
<TableCell>Accessories</TableCell>
<TableCell>$99</TableCell>
<TableCell>
<a
href="#"
className="font-medium text-cyan-600 hover:underline dark:text-cyan-500"
>
Edit
</a>
</TableCell>
</TableRow>
<TableRow className="bg-white dark:border-gray-700 dark:bg-gray-800">
<TableCell className="p-4">
<Checkbox />
</TableCell>
<TableCell className="whitespace-nowrap font-medium text-gray-900 dark:text-white">
Magic Mouse 2
</TableCell>
<TableCell>Black</TableCell>
<TableCell>Accessories</TableCell>
<TableCell>$99</TableCell>
<TableCell>
<a
href="#"
className="font-medium text-cyan-600 hover:underline dark:text-cyan-500"
>
Edit
</a>
</TableCell>
</TableRow>
<TableRow className="bg-white dark:border-gray-700 dark:bg-gray-800">
<TableCell className="p-4">
<Checkbox />
</TableCell>
<TableCell className="whitespace-nowrap font-medium text-gray-900 dark:text-white">
Magic Mouse 2
</TableCell>
<TableCell>Black</TableCell>
<TableCell>Accessories</TableCell>
<TableCell>$99</TableCell>
<TableCell>
<a
href="#"
className="font-medium text-cyan-600 hover:underline dark:text-cyan-500"
>
Edit
</a>
</TableCell>
</TableRow>
<TableRow className="bg-white dark:border-gray-700 dark:bg-gray-800">
<TableCell className="p-4">
<Checkbox />
</TableCell>
<TableCell className="whitespace-nowrap font-medium text-gray-900 dark:text-white">
Magic Mouse 2
</TableCell>
<TableCell>Black</TableCell>
<TableCell>Accessories</TableCell>
<TableCell>$99</TableCell>
<TableCell>
<a
href="#"
className="font-medium text-cyan-600 hover:underline dark:text-cyan-500"
>
Edit
</a>
</TableCell>
</TableRow>
<TableRow className="bg-white dark:border-gray-700 dark:bg-gray-800">
<TableCell className="p-4">
<Checkbox />
</TableCell>
<TableCell className="whitespace-nowrap font-medium text-gray-900 dark:text-white">
Magic Mouse 2
</TableCell>
<TableCell>Black</TableCell>
<TableCell>Accessories</TableCell>
<TableCell>$99</TableCell>
<TableCell>
<a
href="#"
className="font-medium text-cyan-600 hover:underline dark:text-cyan-500"
>
Edit
</a>
</TableCell>
</TableRow>
<TableRow className="bg-white dark:border-gray-700 dark:bg-gray-800">
<TableCell className="p-4">
<Checkbox />
</TableCell>
<TableCell className="whitespace-nowrap font-medium text-gray-900 dark:text-white">
Magic Mouse 2
</TableCell>
<TableCell>Black</TableCell>
<TableCell>Accessories</TableCell>
<TableCell>$99</TableCell>
<TableCell>
<a
href="#"
className="font-medium text-cyan-600 hover:underline dark:text-cyan-500"
>
Edit
</a>
</TableCell>
</TableRow>
<TableRow className="bg-white dark:border-gray-700 dark:bg-gray-800">
<TableCell className="p-4">
<Checkbox />
</TableCell>
<TableCell className="whitespace-nowrap font-medium text-gray-900 dark:text-white">
Magic Mouse 2
</TableCell>
<TableCell>Black</TableCell>
<TableCell>Accessories</TableCell>
<TableCell>$99</TableCell>
<TableCell>
<a
href="#"
className="font-medium text-cyan-600 hover:underline dark:text-cyan-500"
>
Edit
</a>
</TableCell>
</TableRow>
<TableRow className="bg-white dark:border-gray-700 dark:bg-gray-800">
<TableCell className="p-4">
<Checkbox />
</TableCell>
<TableCell className="whitespace-nowrap font-medium text-gray-900 dark:text-white">
Magic Mouse 2
</TableCell>
<TableCell>Black</TableCell>
<TableCell>Accessories</TableCell>
<TableCell>$99</TableCell>
<TableCell>
<a
href="#"
className="font-medium text-cyan-600 hover:underline dark:text-cyan-500"
>
Edit
</a>
</TableCell>
</TableRow>
<TableRow className="bg-white dark:border-gray-700 dark:bg-gray-800">
<TableCell className="p-4">
<Checkbox />
</TableCell>
<TableCell className="whitespace-nowrap font-medium text-gray-900 dark:text-white">
Magic Mouse 2
</TableCell>
<TableCell>Black</TableCell>
<TableCell>Accessories</TableCell>
<TableCell>$99</TableCell>
<TableCell>
<a
href="#"
className="font-medium text-cyan-600 hover:underline dark:text-cyan-500"
>
Edit
</a>
</TableCell>
</TableRow>
<TableRow className="bg-white dark:border-gray-700 dark:bg-gray-800">
<TableCell className="p-4">
<Checkbox />
</TableCell>
<TableCell className="whitespace-nowrap font-medium text-gray-900 dark:text-white">
Magic Mouse 2
</TableCell>
<TableCell>Black</TableCell>
<TableCell>Accessories</TableCell>
<TableCell>$99</TableCell>
<TableCell>
<a
href="#"
className="font-medium text-cyan-600 hover:underline dark:text-cyan-500"
>
Edit
</a>
</TableCell>
</TableRow>
<TableRow className="bg-white dark:border-gray-700 dark:bg-gray-800">
<TableCell className="p-4">
<Checkbox />
</TableCell>
<TableCell className="whitespace-nowrap font-medium text-gray-900 dark:text-white">
Magic Mouse 2
</TableCell>
<TableCell>Black</TableCell>
<TableCell>Accessories</TableCell>
<TableCell>$99</TableCell>
<TableCell>
<a
href="#"
className="font-medium text-cyan-600 hover:underline dark:text-cyan-500"
>
Edit
</a>
</TableCell>
</TableRow>
<TableRow className="bg-white dark:border-gray-700 dark:bg-gray-800">
<TableCell className="p-4">
<Checkbox />
</TableCell>
<TableCell className="whitespace-nowrap font-medium text-gray-900 dark:text-white">
Magic Mouse 2
</TableCell>
<TableCell>Black</TableCell>
<TableCell>Accessories</TableCell>
<TableCell>$99</TableCell>
<TableCell>
<a
href="#"
className="font-medium text-cyan-600 hover:underline dark:text-cyan-500"
>
Edit
</a>
</TableCell>
</TableRow>
<TableRow className="bg-white dark:border-gray-700 dark:bg-gray-800">
<TableCell className="p-4">
<Checkbox />
</TableCell>
<TableCell className="whitespace-nowrap font-medium text-gray-900 dark:text-white">
Magic Mouse 2
</TableCell>
<TableCell>Black</TableCell>
<TableCell>Accessories</TableCell>
<TableCell>$99</TableCell>
<TableCell>
<a
href="#"
className="font-medium text-cyan-600 hover:underline dark:text-cyan-500"
>
Edit
</a>
</TableCell>
</TableRow>
<TableRow className="bg-white dark:border-gray-700 dark:bg-gray-800">
<TableCell className="p-4">
<Checkbox />
</TableCell>
<TableCell className="whitespace-nowrap font-medium text-gray-900 dark:text-white">
Magic Mouse 2
</TableCell>
<TableCell>Black</TableCell>
<TableCell>Accessories</TableCell>
<TableCell>$99</TableCell>
<TableCell>
<a
href="#"
className="font-medium text-cyan-600 hover:underline dark:text-cyan-500"
>
Edit
</a>
</TableCell>
</TableRow>
<TableRow className="bg-white dark:border-gray-700 dark:bg-gray-800">
<TableCell className="p-4">
<Checkbox />
</TableCell>
<TableCell className="whitespace-nowrap font-medium text-gray-900 dark:text-white">
Magic Mouse 2
</TableCell>
<TableCell>Black</TableCell>
<TableCell>Accessories</TableCell>
<TableCell>$99</TableCell>
<TableCell>
<a
href="#"
className="font-medium text-cyan-600 hover:underline dark:text-cyan-500"
>
Edit
</a>
</TableCell>
</TableRow>
<TableRow className="bg-white dark:border-gray-700 dark:bg-gray-800">
<TableCell className="p-4">
<Checkbox />
</TableCell>
<TableCell className="whitespace-nowrap font-medium text-gray-900 dark:text-white">
Magic Mouse 2
</TableCell>
<TableCell>Black</TableCell>
<TableCell>Accessories</TableCell>
<TableCell>$99</TableCell>
<TableCell>
<a
href="#"
className="font-medium text-cyan-600 hover:underline dark:text-cyan-500"
>
Edit
</a>
</TableCell>
</TableRow> </TableRow>
</TableBody> </TableBody>
</Table> </Table>

View file

@ -18,11 +18,9 @@ import { Modal, ModalBody, ModalFooter, ModalHeader } from "flowbite-react";
import { HiDownload, HiPlusCircle, HiTrash } from "react-icons/hi"; import { HiDownload, HiPlusCircle, HiTrash } from "react-icons/hi";
import { ModTable } from "../components/ModTable"; import { ModTable } from "../components/ModTable";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
import { Mod } from "@/types/mod";
export default function PackPage() { export default function PackPage() {
const [packData, setPackData] = useState<Pack | null>(null); const [packData, setPackData] = useState<Pack | null>(null);
const [packMods, setPackMods] = useState<Mod[]>([]);
const [packDataLoading, setPackDataLoading] = useState(true); const [packDataLoading, setPackDataLoading] = useState(true);
const router = useRouter(); const router = useRouter();
const id = useSearchParams().get("id") || ""; const id = useSearchParams().get("id") || "";
@ -43,15 +41,15 @@ export default function PackPage() {
// version: null, // version: null,
// }); // });
async function _getPacksData() {
const res = await fetch(PACK_ENDPOINT("getPack", id));
if (!res.ok) router.push("/404");
const data: Pack = await res.json();
setPackData(data);
setPackDataLoading(false);
}
useEffect(() => { useEffect(() => {
async function _getPacksData() {
const res = await fetch(PACK_ENDPOINT("getPack", id));
if (!res.ok) router.push("/404");
const data: Pack = await res.json();
setPackData(data);
setPackMods(data.mods);
setPackDataLoading(false);
}
if (id) { if (id) {
_getPacksData(); _getPacksData();
} else { } else {
@ -205,7 +203,6 @@ export default function PackPage() {
return; return;
} }
setPackMods([...packMods, data.mod]);
toast.update(tid, { toast.update(tid, {
render: data.message, render: data.message,
type: "success", type: "success",
@ -214,7 +211,9 @@ export default function PackPage() {
closeOnClick: true, closeOnClick: true,
draggable: true, draggable: true,
}); });
setModUrl({ ...modUrl, value: "" }) setModUrl({ ...modUrl, value: "" });
_getPacksData();
} }
return ( return (
@ -253,7 +252,15 @@ export default function PackPage() {
<p className="text-sm text-gray-400">by {packData.author}</p> <p className="text-sm text-gray-400">by {packData.author}</p>
</div> </div>
</div> </div>
<div className="flex gap-2"> <div className="flex gap-2 items-center">
<div>
<p className="text-lg font-semibold">
{packData.mods.length} mods
</p>
<p className="text-sm text-gray-400">
v{packData.modpackVersion}
</p>
</div>
<Button onClick={() => setAddModModalOpen(true)}> <Button onClick={() => setAddModModalOpen(true)}>
Add mod <HiPlusCircle className="ml-2 h-5 w-5" /> Add mod <HiPlusCircle className="ml-2 h-5 w-5" />
</Button> </Button>
@ -267,7 +274,7 @@ export default function PackPage() {
</div> </div>
</Card> </Card>
<div className="mt-4"> <div className="mt-4">
<ModTable /> <ModTable mods={packData.mods} updatePack={_getPacksData} packID={id} />
</div> </div>
</div> </div>
)} )}

View file

@ -106,3 +106,31 @@ def addMod(id):
"mod": mod.get("mod"), "mod": mod.get("mod"),
} }
) )
@apiPack.route("/<id>/mod/<slug>/delete", methods=["GET"])
def deleteMod(id, slug):
pack = {}
with open(f"{PACKS_FOLDER}/{id}/packfile.json") as fp:
pack = json.load(fp)
fp.close()
for mod in pack.get("mods"):
if mod.get("slug") == slug:
pack["mods"].remove(mod)
pack["modpackVersion"] += 1
if os.path.exists(
f"{PACKS_FOLDER}/{id}/mods/{mod.get('file').get('filename')}"
):
os.remove(f"{PACKS_FOLDER}/{id}/mods/{mod.get('file').get('filename')}")
with open(f"{PACKS_FOLDER}/{id}/packfile.json", mode="w", encoding="utf-8") as fp:
json.dump(pack, fp)
fp.close()
return jsonify(
{
"status": "ok",
"message": f"mod {slug} has been removed",
}
)