Added local file chip for local metadata

This commit is contained in:
2026-04-21 23:16:54 -04:00
parent 4b8693fe68
commit cff391dc1d
4 changed files with 47 additions and 16 deletions

View File

@@ -96,7 +96,8 @@ export const ComicDetail = (data: ComicDetailProps): ReactElement => {
const hasAnyMetadata = const hasAnyMetadata =
isComicBookMetadataAvailable || isComicBookMetadataAvailable ||
!isEmpty(comicInfo) || !isEmpty(comicInfo) ||
!isNil(locg); !isNil(locg) ||
areRawFileDetailsAvailable;
const areRawFileDetailsAvailable = const areRawFileDetailsAvailable =
!isUndefined(rawFileDetails) && !isEmpty(rawFileDetails); !isUndefined(rawFileDetails) && !isEmpty(rawFileDetails);

View File

@@ -6,6 +6,7 @@ import { ReconcilerDrawer } from "./ReconcilerDrawer";
import { fetcher } from "../../../graphql/fetcher"; import { fetcher } from "../../../graphql/fetcher";
import { useGetComicByIdQuery } from "../../../graphql/generated"; import { useGetComicByIdQuery } from "../../../graphql/generated";
import type { CanonicalRecord } from "./useReconciler"; import type { CanonicalRecord } from "./useReconciler";
import type { RawFileDetails as RawFileDetailsType } from "../../../graphql/generated";
interface ComicVineMetadata { interface ComicVineMetadata {
volumeInformation?: Record<string, unknown>; volumeInformation?: Record<string, unknown>;
@@ -28,6 +29,8 @@ interface VolumeInformationData {
id?: string; id?: string;
sourcedMetadata?: SourcedMetadata; sourcedMetadata?: SourcedMetadata;
inferredMetadata?: { issue?: unknown }; inferredMetadata?: { issue?: unknown };
rawFileDetails?: RawFileDetailsType;
createdAt?: string;
updatedAt?: string; updatedAt?: string;
} }
@@ -166,34 +169,37 @@ export const VolumeInformation = (
); );
return true; return true;
}); });
if ( const hasLocalFile =
!isNil(data?.inferredMetadata?.issue) && (!isNil(data?.rawFileDetails) && !isEmpty(data?.rawFileDetails)) ||
!isEmpty(data?.inferredMetadata?.issue) (!isNil(data?.inferredMetadata?.issue) && !isEmpty(data?.inferredMetadata?.issue));
) { if (hasLocalFile) {
sources.push("inferredMetadata"); sources.push("inferredMetadata");
} }
return sources; return sources;
}, [data?.sourcedMetadata, data?.inferredMetadata]); }, [data?.sourcedMetadata, data?.inferredMetadata, data?.rawFileDetails]);
const onlyComicvine =
presentSources.length === 1 &&
!!data.sourcedMetadata?.comicvine?.volumeInformation;
return ( return (
<div key={1}> <div key={1}>
{presentSources.length > 1 && ( {(presentSources.length > 1 || (presentSources.length === 1 && !onlyComicvine)) && (
<MetadataSourceChips <MetadataSourceChips
sources={presentSources} sources={presentSources}
onOpenReconciler={() => setReconcilerOpen(true)} onOpenReconciler={() => setReconcilerOpen(true)}
/> />
)} )}
{presentSources.length === 1 && {onlyComicvine && (
data.sourcedMetadata?.comicvine?.volumeInformation && ( <ComicVineDetails
<ComicVineDetails data={data.sourcedMetadata!.comicvine!}
data={data.sourcedMetadata.comicvine} updatedAt={data.updatedAt}
updatedAt={data.updatedAt} />
/> )}
)}
<ReconcilerDrawer <ReconcilerDrawer
open={isReconcilerOpen} open={isReconcilerOpen}
onOpenChange={setReconcilerOpen} onOpenChange={setReconcilerOpen}
sourcedMetadata={(data.sourcedMetadata ?? {}) as import("./useReconciler").RawSourcedMetadata} sourcedMetadata={(data.sourcedMetadata ?? {}) as unknown as import("./useReconciler").RawSourcedMetadata}
inferredMetadata={data.inferredMetadata as import("./useReconciler").RawInferredMetadata | undefined} inferredMetadata={data.inferredMetadata as import("./useReconciler").RawInferredMetadata | undefined}
onSave={saveCanonical} onSave={saveCanonical}
/> />

View File

@@ -145,7 +145,14 @@ export const Import = (): ReactElement => {
}, [getSocket, queryClient]); }, [getSocket, queryClient]);
/** /**
* Handles force re-import - re-imports all files to fix indexing issues * Initiates a force re-import of all library files.
*
* When the queue is already drained, disconnects and reconnects the socket
* before triggering the import — ensures the backend receives a fresh session
* rather than reusing a stale one that would be ignored.
*
* Validates directory availability and active session state before proceeding
* to prevent duplicate or broken imports.
*/ */
const handleForceReImport = async () => { const handleForceReImport = async () => {
setImportError(null); setImportError(null);
@@ -194,6 +201,7 @@ export const Import = (): ReactElement => {
} }
}; };
// `undefined` covers the initial state before any import has ever run in this session
const canStartImport = const canStartImport =
!hasActiveSession && !hasActiveSession &&
(importJobQueue.status === "drained" || importJobQueue.status === undefined); (importJobQueue.status === "drained" || importJobQueue.status === undefined);

View File

@@ -1,3 +1,9 @@
/**
* @fileoverview Weekly Pull List page — displays comics releasing this week
* that the user has marked to follow.
* @module components/PullList/PullList
*/
import React, { ReactElement, useEffect, useMemo, useState } from "react"; import React, { ReactElement, useEffect, useMemo, useState } from "react";
import T2Table from "../shared/T2Table"; import T2Table from "../shared/T2Table";
import Card from "../shared/Carda"; import Card from "../shared/Carda";
@@ -16,6 +22,15 @@ interface PullListComic {
}; };
} }
/**
* Weekly Pull List page component.
*
* Displays comics releasing this week that the user tracks.
* Fetching is not yet implemented — state is initialised to `null`
* so the table renders only when data is available, avoiding an empty-table flash.
*
* @returns {ReactElement} The pull list page UI
*/
export const PullList = (): ReactElement => { export const PullList = (): ReactElement => {
// Placeholder for pull list comics - would come from API/store // Placeholder for pull list comics - would come from API/store
const [pullListComics, setPullListComics] = useState<PullListComic[] | null>(null); const [pullListComics, setPullListComics] = useState<PullListComic[] | null>(null);
@@ -32,6 +47,7 @@ export const PullList = (): ReactElement => {
}, []); }, []);
const nextPageHandler = () => {}; const nextPageHandler = () => {};
const previousPageHandler = () => {}; const previousPageHandler = () => {};
// Column def memoised — shape is static, no deps needed
const columnData = useMemo( const columnData = useMemo(
() => [ () => [
{ {