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 casesNewRoute = require("./routes/cases/new")(sequelize);
const casesEditRoute = require("./routes/cases/edit")(sequelize); const casesEditRoute = require("./routes/cases/edit")(sequelize);
const casesDeleteRoute = require("./routes/cases/delete")(sequelize); const casesDeleteRoute = require("./routes/cases/delete")(sequelize);
const casesBulkDeleteRoute = require("./routes/cases/bulkDelete")(sequelize);
app.use("/cases", casesIndexRoute); app.use("/cases", casesIndexRoute);
app.use("/cases", casesShowRoute); app.use("/cases", casesShowRoute);
app.use("/cases", casesNewRoute); app.use("/cases", casesNewRoute);
app.use("/cases", casesEditRoute); app.use("/cases", casesEditRoute);
app.use("/cases", casesDeleteRoute); app.use("/cases", casesDeleteRoute);
app.use("/cases", casesBulkDeleteRoute);
// "/steps" // "/steps"
const stepsNewRoute = require("./routes/steps/new")(sequelize); 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({ export default function Page({
params, params,
}: { }: {
@@ -123,6 +145,12 @@ export default function Page({
setCases(data); setCases(data);
}; };
const handleDeleteCases = async (deleteCases: string[]) => {
await fetchDeleteCases(deleteCases);
const data = await fetchCases(url);
setCases(data);
}
return ( return (
<> <>
<TestCaseTable <TestCaseTable
@@ -130,6 +158,7 @@ export default function Page({
cases={cases} cases={cases}
onCreateCase={() => handleCreateCase(params.folderId)} onCreateCase={() => handleCreateCase(params.folderId)}
onDeleteCase={handleDeleteCase} onDeleteCase={handleDeleteCase}
onDeleteCases={handleDeleteCases}
/> />
</> </>
); );

View File

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