import React, { ReactElement, useCallback, useEffect, useState } from "react"; import { format } from "date-fns"; import Loader from "react-loader-spinner"; import { isEmpty, isNil, isUndefined } from "lodash"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { useStore } from "../../store"; import { useShallow } from "zustand/react/shallow"; import axios from "axios"; interface IProps { matches?: unknown; fetchComicMetadata?: any; path: string; covers?: any; } /** * Component to facilitate the import of comics to the ThreeTwo library * * @param x - The first input number * @param y - The second input number * @returns The arithmetic mean of `x` and `y` * * @beta */ export const Import = (props: IProps): ReactElement => { const queryClient = useQueryClient(); const [socketReconnectTrigger, setSocketReconnectTrigger] = useState(0); const { importJobQueue, getSocket, disconnectSocket } = useStore( useShallow((state) => ({ importJobQueue: state.importJobQueue, getSocket: state.getSocket, disconnectSocket: state.disconnectSocket, })), ); const { mutate: initiateImport } = useMutation({ mutationFn: async () => { const sessionId = localStorage.getItem("sessionId"); return await axios.request({ url: `http://localhost:3000/api/library/newImport`, method: "POST", data: { sessionId }, }); }, }); const { data, isError, isLoading, refetch } = useQuery({ queryKey: ["allImportJobResults"], queryFn: async () => { const response = await axios({ method: "GET", url: "http://localhost:3000/api/jobqueue/getJobResultStatistics", params: { _t: Date.now() }, // Cache busting }); return response; }, refetchOnWindowFocus: false, staleTime: 0, // Always consider data stale gcTime: 0, // Don't cache the data (formerly cacheTime) }); // Ensure socket connection is established and listen for import completion useEffect(() => { const socket = getSocket("/"); // Listen for import queue drained event to refresh the table const handleQueueDrained = () => { refetch(); }; // Listen for individual import completions to refresh the table const handleCoverExtracted = () => { refetch(); }; socket.on("LS_IMPORT_QUEUE_DRAINED", handleQueueDrained); socket.on("LS_COVER_EXTRACTED", handleCoverExtracted); return () => { socket.off("LS_IMPORT_QUEUE_DRAINED", handleQueueDrained); socket.off("LS_COVER_EXTRACTED", handleCoverExtracted); }; }, [getSocket, refetch, socketReconnectTrigger]); const toggleQueue = (queueAction: string, queueStatus: string) => { const socket = getSocket("/"); socket.emit( "call", "socket.setQueueStatus", { queueAction, queueStatus, }, ); }; /** * Method to render import job queue pause/resume controls on the UI * * @param status The `string` status (either `"pause"` or `"resume"`) * @returns ReactElement A ` ); case "paused": return (
); case "drained": return null; default: return null; } }; return (

Import

Import comics into the ThreeTwo library.

Importing will add comics identified from the mapped folder into ThreeTwo's database.

Metadata from ComicInfo.xml, if present, will also be extracted.

This process could take a while, if you have a lot of comics, or are importing over a network connection.

{(importJobQueue.status === "drained" || importJobQueue.status === undefined) && ( )}
{/* Activity */} {(importJobQueue.status === "running" || importJobQueue.status === "paused") && ( <> Import Activity
{/* Successful import counts */}
{importJobQueue.successfulJobCount}
imported
{/* Failed job counts */}
{importJobQueue.failedJobCount}
failed
{renderQueueControls(importJobQueue.status)}
Imported: {importJobQueue.mostRecentImport}
)} {/* Past imports */} {!isLoading && !isEmpty(data?.data) && (
Past Imports
{data?.data.map((jobResult: any, index: number) => { return ( ); })}
# Time Started Session Id Imported Failed
{index + 1} {format( new Date(jobResult.earliestTimestamp), "EEEE, hh:mma, do LLLL Y", )} {jobResult.sessionId}

{jobResult.completedJobs}

{jobResult.failedJobs}

)}
); }; export default Import;