🔨 Fixed timestamps
This commit is contained in:
@@ -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"}
|
||||||
|
|||||||
Reference in New Issue
Block a user