implemented bulk deletion of cases

This commit is contained in:
Takeshi Kimata
2024-03-24 14:09:18 +09:00
parent a85e85c67c
commit a86d166d26
4 changed files with 96 additions and 14 deletions

View File

@@ -55,11 +55,13 @@ const casesShowRoute = require("./routes/cases/show")(sequelize);
const casesNewRoute = require("./routes/cases/new")(sequelize);
const casesEditRoute = require("./routes/cases/edit")(sequelize);
const casesDeleteRoute = require("./routes/cases/delete")(sequelize);
const casesBulkDeleteRoute = require("./routes/cases/bulkDelete")(sequelize);
app.use("/cases", casesIndexRoute);
app.use("/cases", casesShowRoute);
app.use("/cases", casesNewRoute);
app.use("/cases", casesEditRoute);
app.use("/cases", casesDeleteRoute);
app.use("/cases", casesBulkDeleteRoute);
// "/steps"
const stepsNewRoute = require("./routes/steps/new")(sequelize);

View File

@@ -0,0 +1,25 @@
const express = require("express");
const router = express.Router();
const defineCase = require("../../models/cases");
const { DataTypes } = require("sequelize");
module.exports = function (sequelize) {
const Case = defineCase(sequelize, DataTypes);
router.post("/bulkdelete", async (req, res) => {
const { caseIds } = req.body;
if (!caseIds || !Array.isArray(caseIds)) {
return res.status(400).send("Invalid caseIds array");
}
try {
await Case.destroy({ where: { id: caseIds } });
res.status(204).send();
} catch (error) {
console.error(error);
res.status(500).send("Internal Server Error");
}
});
return router;
};

View File

@@ -89,6 +89,28 @@ async function fetchDeleteCase(caseId: number) {
}
}
async function fetchDeleteCases(deleteCases: string[]) {
const fetchOptions = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ caseIds: deleteCases }),
};
const url = `${apiServer}/cases/bulkdelete`;
try {
const response = await fetch(url, fetchOptions);
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
} catch (error) {
console.error("Error deleting cases:", error);
throw error;
}
}
export default function Page({
params,
}: {
@@ -123,6 +145,12 @@ export default function Page({
setCases(data);
};
const handleDeleteCases = async (deleteCases: string[]) => {
await fetchDeleteCases(deleteCases);
const data = await fetchCases(url);
setCases(data);
}
return (
<>
<TestCaseTable
@@ -130,6 +158,7 @@ export default function Page({
cases={cases}
onCreateCase={() => handleCreateCase(params.folderId)}
onDeleteCase={handleDeleteCase}
onDeleteCases={handleDeleteCases}
/>
</>
);

View File

@@ -16,7 +16,7 @@ import {
SortDescriptor,
Link,
} from "@nextui-org/react";
import { Plus, MoreVertical } from "lucide-react";
import { Plus, MoreVertical, Trash } from "lucide-react";
const headerColumns = [
{ name: "ID", uid: "id", sortable: true },
@@ -48,9 +48,16 @@ type Props = {
cases: Case[];
onCreateCase: () => void;
onDeleteCase: (caseId: number) => void;
onDeleteCases: (selectedCases: string[]) => void;
};
export default function TestCaseTable({ projectId, cases, onCreateCase, onDeleteCase }: Props) {
export default function TestCaseTable({
projectId,
cases,
onCreateCase,
onDeleteCase,
onDeleteCases,
}: Props) {
const [selectedKeys, setSelectedKeys] = useState<Selection>(new Set([]));
const [sortDescriptor, setSortDescriptor] = useState<SortDescriptor>({
column: "id",
@@ -102,7 +109,10 @@ export default function TestCaseTable({ projectId, cases, onCreateCase, onDelete
</Button>
</DropdownTrigger>
<DropdownMenu aria-label="test case actions">
<DropdownItem className="text-danger" onClick={() => onDeleteCase(testCase.id)}>
<DropdownItem
className="text-danger"
onClick={() => onDeleteCase(testCase.id)}
>
Delete test case
</DropdownItem>
</DropdownMenu>
@@ -132,12 +142,27 @@ export default function TestCaseTable({ projectId, cases, onCreateCase, onDelete
[]
);
const onDeleteCasesClick = async() => {
setSelectedKeys(new Set([]));
onDeleteCases([...selectedKeys])
}
return (
<>
<div className="border-b-1 dark:border-neutral-700 w-full p-3 flex items-center justify-between">
<h3 className="font-bold">
Cases
</h3>
<h3 className="font-bold">Cases</h3>
<div>
{selectedKeys.size > 0 && (
<Button
startContent={<Trash size={16} />}
size="sm"
color="danger"
className="me-2"
onClick={onDeleteCasesClick}
>
Delete
</Button>
)}
<Button
startContent={<Plus size={16} />}
size="sm"
@@ -147,6 +172,7 @@ export default function TestCaseTable({ projectId, cases, onCreateCase, onDelete
New Test Case
</Button>
</div>
</div>
<Table
isCompact