🔨 Fixed timestamps

This commit is contained in:
2026-03-05 11:48:43 -05:00
parent 07f5e6efe6
commit ec52906eca

View File

@@ -11,24 +11,15 @@ import {
useStartIncrementalImportMutation useStartIncrementalImportMutation
} from "../../graphql/generated"; } from "../../graphql/generated";
interface IProps { interface ImportProps {
matches?: unknown;
fetchComicMetadata?: any;
path: string; path: string;
covers?: any;
} }
/** /**
* Component to facilitate the import of comics to the ThreeTwo library * Import component for adding comics to the ThreeTwo library.
* * Provides preview statistics, smart import, and queue management.
* @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: ImportProps): ReactElement => {
export const Import = (props: IProps): ReactElement => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const [socketReconnectTrigger, setSocketReconnectTrigger] = useState(0); const [socketReconnectTrigger, setSocketReconnectTrigger] = useState(0);
const [showPreview, setShowPreview] = useState(false); const [showPreview, setShowPreview] = useState(false);
@@ -40,7 +31,6 @@ export const Import = (props: IProps): ReactElement => {
})), })),
); );
// Query to get import statistics (preview)
const { const {
data: importStats, data: importStats,
isLoading: isLoadingStats, isLoading: isLoadingStats,
@@ -53,7 +43,6 @@ export const Import = (props: IProps): ReactElement => {
} }
); );
// Mutation for incremental import (smart import)
const { mutate: startIncrementalImport, isPending: isStartingImport } = useStartIncrementalImportMutation({ const { mutate: startIncrementalImport, isPending: isStartingImport } = useStartIncrementalImportMutation({
onSuccess: (data) => { onSuccess: (data) => {
if (data.startIncrementalImport.success) { if (data.startIncrementalImport.success) {
@@ -76,19 +65,10 @@ export const Import = (props: IProps): ReactElement => {
const { data, isError, isLoading, refetch } = useGetJobResultStatisticsQuery(); const { data, isError, isLoading, refetch } = useGetJobResultStatisticsQuery();
// Ensure socket connection is established and listen for import completion
useEffect(() => { useEffect(() => {
const socket = getSocket("/"); const socket = getSocket("/");
const handleQueueDrained = () => refetch();
// Listen for import queue drained event to refresh the table const handleCoverExtracted = () => refetch();
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_IMPORT_QUEUE_DRAINED", handleQueueDrained);
socket.on("LS_COVER_EXTRACTED", handleCoverExtracted); socket.on("LS_COVER_EXTRACTED", handleCoverExtracted);
@@ -99,6 +79,9 @@ export const Import = (props: IProps): ReactElement => {
}; };
}, [getSocket, refetch, socketReconnectTrigger]); }, [getSocket, refetch, socketReconnectTrigger]);
/**
* Toggles import queue pause/resume state
*/
const toggleQueue = (queueAction: string, queueStatus: string) => { const toggleQueue = (queueAction: string, queueStatus: string) => {
const socket = getSocket("/"); const socket = getSocket("/");
socket.emit( socket.emit(
@@ -116,18 +99,16 @@ export const Import = (props: IProps): ReactElement => {
refetchStats(); refetchStats();
}; };
/**
* Starts smart import, resetting session if queue was drained
*/
const handleStartSmartImport = () => { const handleStartSmartImport = () => {
// Clear old sessionId when starting a new import after queue is drained
if (importJobQueue.status === "drained") { if (importJobQueue.status === "drained") {
localStorage.removeItem("sessionId"); localStorage.removeItem("sessionId");
// Disconnect and reconnect socket to get new sessionId
disconnectSocket("/"); disconnectSocket("/");
// Wait for socket to reconnect and get new sessionId before starting import
setTimeout(() => { setTimeout(() => {
getSocket("/"); getSocket("/");
// Trigger useEffect to re-attach event listeners
setSocketReconnectTrigger(prev => prev + 1); setSocketReconnectTrigger(prev => prev + 1);
// Wait a bit more for sessionInitialized event to fire
setTimeout(() => { setTimeout(() => {
const sessionId = localStorage.getItem("sessionId") || ""; const sessionId = localStorage.getItem("sessionId") || "";
startIncrementalImport({ sessionId }); startIncrementalImport({ sessionId });
@@ -140,11 +121,7 @@ export const Import = (props: IProps): ReactElement => {
}; };
/** /**
* Method to render import job queue pause/resume controls on the UI * Renders pause/resume controls based on queue status
*
* @param status The `string` status (either `"pause"` or `"resume"`)
* @returns ReactElement A `<button/>` that toggles queue status
* @remarks Sets the global `importJobQueue.status` state upon toggling
*/ */
const renderQueueControls = (status: string): ReactElement | null => { const renderQueueControls = (status: string): ReactElement | null => {
switch (status) { switch (status) {
@@ -230,7 +207,6 @@ export const Import = (props: IProps): ReactElement => {
</div> </div>
</article> </article>
{/* Import Preview Section */}
{!showPreview && (importJobQueue.status === "drained" || importJobQueue.status === undefined) && ( {!showPreview && (importJobQueue.status === "drained" || importJobQueue.status === undefined) && (
<div className="my-4 flex gap-3"> <div className="my-4 flex gap-3">
<button <button
@@ -244,8 +220,7 @@ export const Import = (props: IProps): ReactElement => {
</button> </button>
</div> </div>
)} )}
{/* Import Preview Panel */}
{/* Preview Statistics */}
{showPreview && !isLoadingStats && importStats?.getImportStatistics && ( {showPreview && !isLoadingStats && importStats?.getImportStatistics && (
<div className="my-6 max-w-screen-lg"> <div className="my-6 max-w-screen-lg">
<span className="flex items-center my-5"> <span className="flex items-center my-5">
@@ -362,7 +337,6 @@ export const Import = (props: IProps): ReactElement => {
</div> </div>
)} )}
{/* Loading state for preview */}
{showPreview && isLoadingStats && ( {showPreview && isLoadingStats && (
<div className="my-6 flex justify-center items-center"> <div className="my-6 flex justify-center items-center">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-500"></div> <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-500"></div>
@@ -372,7 +346,6 @@ export const Import = (props: IProps): ReactElement => {
</div> </div>
)} )}
{/* Activity */}
{(importJobQueue.status === "running" || {(importJobQueue.status === "running" ||
importJobQueue.status === "paused") && ( importJobQueue.status === "paused") && (
<> <>
@@ -384,7 +357,6 @@ export const Import = (props: IProps): ReactElement => {
</span> </span>
<div className="mt-5 flex flex-col gap-4 sm:mt-0 sm:flex-row sm:items-center"> <div className="mt-5 flex flex-col gap-4 sm:mt-0 sm:flex-row sm:items-center">
<dl className="grid grid-cols-2 gap-4 sm:grid-cols-2"> <dl className="grid grid-cols-2 gap-4 sm:grid-cols-2">
{/* Successful import counts */}
<div className="flex flex-col rounded-lg bg-green-100 dark:bg-green-200 px-4 py-6 text-center"> <div className="flex flex-col rounded-lg bg-green-100 dark:bg-green-200 px-4 py-6 text-center">
<dd className="text-3xl text-green-600 md:text-5xl"> <dd className="text-3xl text-green-600 md:text-5xl">
{importJobQueue.successfulJobCount} {importJobQueue.successfulJobCount}
@@ -393,7 +365,6 @@ export const Import = (props: IProps): ReactElement => {
imported imported
</dt> </dt>
</div> </div>
{/* Failed job counts */}
<div className="flex flex-col rounded-lg bg-red-100 dark:bg-red-200 px-4 py-6 text-center"> <div className="flex flex-col rounded-lg bg-red-100 dark:bg-red-200 px-4 py-6 text-center">
<dd className="text-3xl text-red-600 md:text-5xl"> <dd className="text-3xl text-red-600 md:text-5xl">
{importJobQueue.failedJobCount} {importJobQueue.failedJobCount}
@@ -416,7 +387,6 @@ export const Import = (props: IProps): ReactElement => {
</> </>
)} )}
{/* Past imports */}
{!isLoading && !isEmpty(data?.getJobResultStatistics) && ( {!isLoading && !isEmpty(data?.getJobResultStatistics) && (
<div className="max-w-screen-lg"> <div className="max-w-screen-lg">
<span className="flex items-center mt-6"> <span className="flex items-center mt-6">
@@ -456,9 +426,9 @@ export const Import = (props: IProps): ReactElement => {
{index + 1} {index + 1}
</td> </td>
<td className="whitespace-nowrap px-2 py-2 text-gray-700 dark:text-slate-300"> <td className="whitespace-nowrap px-2 py-2 text-gray-700 dark:text-slate-300">
{jobResult.earliestTimestamp && !isNaN(new Date(jobResult.earliestTimestamp).getTime()) {jobResult.earliestTimestamp && !isNaN(parseInt(jobResult.earliestTimestamp))
? format( ? format(
new Date(jobResult.earliestTimestamp), new Date(parseInt(jobResult.earliestTimestamp)),
"EEEE, hh:mma, do LLLL y", "EEEE, hh:mma, do LLLL y",
) )
: "N/A"} : "N/A"}