From ddaa066dc71fb6ddfb4206d06a0312fd687bc655 Mon Sep 17 00:00:00 2001 From: glax Date: Tue, 20 May 2025 03:14:37 +0200 Subject: [PATCH] Jobs List --- tranga-website/src/Components/Jobs.tsx | 163 +++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 tranga-website/src/Components/Jobs.tsx diff --git a/tranga-website/src/Components/Jobs.tsx b/tranga-website/src/Components/Jobs.tsx new file mode 100644 index 0000000..c576bd1 --- /dev/null +++ b/tranga-website/src/Components/Jobs.tsx @@ -0,0 +1,163 @@ +import { + Card, + CardContent, + Chip, + DialogContent, DialogTitle, + Drawer, + Input, + Option, + Select, + Stack, + Tooltip, + Typography +} from "@mui/joy"; +import {GetAllJobs} from "../api/Job.tsx"; +import * as React from "react"; +import {useCallback, useContext, useEffect, useState} from "react"; +import {ApiUriContext} from "../api/fetchApi.tsx"; +import IJob, {JobState, JobType} from "../api/types/Jobs/IJob.ts"; +import IJobWithMangaId from "../api/types/Jobs/IJobWithMangaId.ts"; +import {MangaFromId} from "./Manga.tsx"; +import ModalClose from "@mui/joy/ModalClose"; +import IJobWithChapterId from "../api/types/Jobs/IJobWithChapterId.tsx"; +import {ChapterFromId} from "./Chapter.tsx"; + +export default function JobsDrawer({open, connected, setOpen} : {open: boolean, connected: boolean, setOpen:React.Dispatch>}) { + const apiUri = useContext(ApiUriContext); + + const [allJobs, setAllJobs] = useState([]); + + const [filterState, setFilterState] = useState(null); + const [filterType, setFilterType] = useState(null); + + const pageSize = 10; + const [page, setPage] = useState(1); + + const updateDisplayJobs = useCallback(() => { + if(!connected) + return; + GetAllJobs(apiUri).then(setAllJobs); + }, [apiUri, connected]); + + const timerRef = React.useRef>(undefined); + const updateTimer = useCallback(() => { + if(!connected){ + clearTimeout(timerRef.current); + return; + }else{ + if(timerRef.current === undefined) { + console.log("Added timer!"); + updateDisplayJobs(); + timerRef.current = setInterval(() => { + updateDisplayJobs(); + }, 2000); + } + } + }, [open, connected]); + + const FilterJobs = (jobs? : IJob[] | undefined) : IJob[] => { + if(jobs === undefined) + return []; + let ret = jobs; + if(filterState != undefined) + ret = ret.filter(job => job.state == filterState); + if(filterType != undefined) + ret = ret.filter(job => job.jobType == filterType); + return ret.sort((a, b) => new Date(a.nextExecution).getDate() - new Date(b.nextExecution).getDate()); + } + + const handleChangeState = ( + _: React.SyntheticEvent | null, + newValue: string | null, + ) => { + setFilterState(newValue); + setPage(1); + }; + const handleChangeType = ( + _: React.SyntheticEvent | null, + newValue: string | null, + ) => { + setFilterType(newValue); + setPage(1); + }; + + useEffect(() => { + updateTimer(); + }, [open, connected]); + + return ( + setOpen(false)}> + + Jobs + + + + setPage(parseInt(e.target.value))} + slotProps={{input: { min: 1, max: Math.ceil(FilterJobs(allJobs).length / pageSize)}}} + startDecorator={Page} + endDecorator={/{Math.ceil(FilterJobs(allJobs).length / pageSize)}}/> + + + + {FilterJobs(allJobs).splice(pageSize*(page-1), pageSize).map(job => )} + + + + ) +} + +function FormatJob({job} : {job: IJob}) { + + return ( + + + + {job.jobType} + + + + + + {new Date(job.lastExecution).toLocaleString()} + + + {new Date(job.nextExecution).toLocaleString()} + + {job.state} + + + + {ExtraContent(job)} + + + ); +} + +function ExtraContent(job: IJob){ + switch(job.jobType){ + case JobType.DownloadAvailableChaptersJob: + case JobType.DownloadMangaCoverJob: + case JobType.RetrieveChaptersJob: + case JobType.UpdateChaptersDownloadedJob: + case JobType.UpdateCoverJob: + case JobType.MoveMangaLibraryJob: + return ; + case JobType.DownloadSingleChapterJob: + case JobType.UpdateSingleChapterDownloadedJob: + return + default: + return null; + } +} \ No newline at end of file