From 15fe8eb3eaf7b7933dad9bbf1301df0eaaab5076 Mon Sep 17 00:00:00 2001 From: Jayden Pyles Date: Sun, 7 Jul 2024 16:27:12 -0500 Subject: [PATCH] feat: add delete and select all button --- .github/workflows/docker-image.yml | 4 +- api/backend/app.py | 19 ++++++- api/backend/job.py | 8 +++ api/backend/models.py | 4 ++ src/components/JobTable.tsx | 88 +++++++++++++++++++++++++++--- src/pages/jobs.tsx | 26 +++++---- src/styles/themes.ts | 4 ++ 7 files changed, 130 insertions(+), 23 deletions(-) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index ab650a4..0f3fb3c 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -2,8 +2,8 @@ name: ci on: push: branches: ["master"] - pull_request: - branches: ["master"] + # pull_request: + # branches: ["master"] jobs: build: runs-on: ubuntu-latest diff --git a/api/backend/app.py b/api/backend/app.py index 217d011..913b723 100644 --- a/api/backend/app.py +++ b/api/backend/app.py @@ -12,8 +12,13 @@ from fastapi.staticfiles import StaticFiles from fastapi.middleware.cors import CORSMiddleware # LOCAL -from api.backend.job import query, insert -from api.backend.models import DownloadJob, SubmitScrapeJob, RetrieveScrapeJobs +from api.backend.job import query, insert, delete_jobs +from api.backend.models import ( + DownloadJob, + SubmitScrapeJob, + DeleteScrapeJobs, + RetrieveScrapeJobs, +) from api.backend.scraping import scrape from api.backend.auth.auth_router import auth_router @@ -116,3 +121,13 @@ async def download(download_job: DownloadJob): except Exception as e: LOG.error(f"Exception occurred: {e}") return {"error": str(e)} + + +@app.post("/api/delete-scrape-jobs") +async def delete(delete_scrape_jobs: DeleteScrapeJobs): + result = await delete_jobs(delete_scrape_jobs.ids) + return ( + JSONResponse(content={"message": "Jobs successfully deleted."}) + if result + else JSONResponse({"error": "Jobs not deleted."}) + ) diff --git a/api/backend/job.py b/api/backend/job.py index 27db04f..7ae530a 100644 --- a/api/backend/job.py +++ b/api/backend/job.py @@ -24,3 +24,11 @@ async def query(filter: dict[str, Any]) -> list[dict[str, Any]]: results.append(document) return results + + +async def delete_jobs(jobs: list[str]): + collection = get_job_collection() + result = await collection.delete_many({"id": {"$in": jobs}}) + LOG.info(f"RESULT: {result.deleted_count} documents deleted") + + return True if result.deleted_count > 0 else False diff --git a/api/backend/models.py b/api/backend/models.py index 25eb5ea..38769b2 100644 --- a/api/backend/models.py +++ b/api/backend/models.py @@ -32,3 +32,7 @@ class RetrieveScrapeJobs(pydantic.BaseModel): class DownloadJob(pydantic.BaseModel): id: str + + +class DeleteScrapeJobs(pydantic.BaseModel): + ids: list[str] diff --git a/src/components/JobTable.tsx b/src/components/JobTable.tsx index 7d6153a..df3846e 100644 --- a/src/components/JobTable.tsx +++ b/src/components/JobTable.tsx @@ -1,19 +1,24 @@ -import React from "react"; +import React, { useState } from "react"; import { Table, TableBody, TableCell, TableHead, TableRow, - Button, + IconButton, Box, Typography, Accordion, AccordionSummary, AccordionDetails, + Checkbox, + Tooltip, + Button, } from "@mui/material"; -import { useRouter } from "next/router"; +import DeleteIcon from "@mui/icons-material/Delete"; +import SelectAllIcon from "@mui/icons-material/SelectAll"; import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; +import { useRouter } from "next/router"; interface Job { id: string; @@ -25,13 +30,15 @@ interface Job { interface JobTableProps { jobs: Job[]; + fetchJobs: () => void; } -const JobTable: React.FC = ({ jobs }) => { +const JobTable: React.FC = ({ jobs, fetchJobs }) => { + const [selectedJobs, setSelectedJobs] = useState>(new Set()); + const [allSelected, setAllSelected] = useState(false); const router = useRouter(); const handleDownload = async (id: string) => { - console.log(id); const response = await fetch("/api/download", { method: "POST", headers: { "Content-Type": "application/json" }, @@ -63,6 +70,41 @@ const JobTable: React.FC = ({ jobs }) => { }); }; + const handleSelectJob = (id: string) => { + setSelectedJobs((prevSelected) => { + const newSelected = new Set(prevSelected); + if (newSelected.has(id)) { + newSelected.delete(id); + } else { + newSelected.add(id); + } + return newSelected; + }); + }; + + const handleSelectAll = () => { + if (allSelected) { + setSelectedJobs(new Set()); + } else { + const allJobIds = new Set(jobs.map((job) => job.id)); + setSelectedJobs(allJobIds); + } + setAllSelected(!allSelected); + }; + + const handleDeleteSelected = async () => { + const response = await fetch("/api/delete-scrape-jobs", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ ids: Array.from(selectedJobs) }), + }); + + if (response.ok) { + fetchJobs(); + setSelectedJobs(new Set()); + } + }; + return ( = ({ jobs }) => { bgcolor="background.default" overflow="auto" > - - Scrape Jobs - + + + Scrape Jobs + + + + + + + + + + + + + + + + + Select Id Url Elements @@ -97,6 +163,12 @@ const JobTable: React.FC = ({ jobs }) => { {jobs.map((row, index) => ( + + handleSelectJob(row.id)} + /> + {row.id} diff --git a/src/pages/jobs.tsx b/src/pages/jobs.tsx index 7ceefac..485dbbb 100644 --- a/src/pages/jobs.tsx +++ b/src/pages/jobs.tsx @@ -7,18 +7,22 @@ const Jobs = () => { const { user } = useAuth(); const [jobs, setJobs] = useState([]); + const fetchJobs = () => { + fetch("/api/retrieve-scrape-jobs", { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ user: user?.email }), + }) + .then((response) => response.json()) + .then((data) => setJobs(data)) + .catch((error) => { + console.error("Error fetching jobs:", error); + }); + }; + useEffect(() => { if (user) { - fetch("/api/retrieve-scrape-jobs", { - method: "POST", - headers: { "content-type": "application/json" }, - body: JSON.stringify({ user: user?.email }), - }) - .then((response) => response.json()) - .then((data) => setJobs(data)) - .catch((error) => { - console.error("Error fetching jobs:", error); - }); + fetchJobs(); } else { setJobs([]); } @@ -27,7 +31,7 @@ const Jobs = () => { return ( <> {user ? ( - + ) : (