🔢 Fix for filesize on disk on Dashboard
This commit is contained in:
@@ -1,105 +1,106 @@
|
|||||||
import React, { ReactElement } from "react";
|
import React, { ReactElement } from "react";
|
||||||
import { isEmpty, isUndefined, map } from "lodash";
|
|
||||||
import Header from "../shared/Header";
|
import Header from "../shared/Header";
|
||||||
import { GetLibraryStatisticsQuery } from "../../graphql/generated";
|
import { GetLibraryStatisticsQuery, DirectorySize } from "../../graphql/generated";
|
||||||
|
|
||||||
type LibraryStatisticsProps = {
|
type Stats = Omit<GetLibraryStatisticsQuery["getLibraryStatistics"], "comicDirectorySize"> & {
|
||||||
stats: GetLibraryStatisticsQuery['getLibraryStatistics'];
|
comicDirectorySize: DirectorySize;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const LibraryStatistics = (
|
/** Props for {@link LibraryStatistics}. */
|
||||||
props: LibraryStatisticsProps,
|
interface LibraryStatisticsProps {
|
||||||
): ReactElement => {
|
stats: Stats | null | undefined;
|
||||||
const { stats } = props;
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a snapshot of library metrics: total comic files, tagging coverage,
|
||||||
|
* file-type breakdown, and the publisher with the most issues.
|
||||||
|
*
|
||||||
|
* Returns `null` when `stats` is absent or the statistics array is empty.
|
||||||
|
*/
|
||||||
|
export const LibraryStatistics = ({ stats }: LibraryStatisticsProps): ReactElement | null => {
|
||||||
|
if (!stats) return null;
|
||||||
|
|
||||||
|
const facet = stats.statistics?.[0];
|
||||||
|
if (!facet) return null;
|
||||||
|
|
||||||
|
const { issues, issuesWithComicInfoXML, fileTypes, publisherWithMostComicsInLibrary, fileLessComics } = facet;
|
||||||
|
const topPublisher = publisherWithMostComicsInLibrary?.[0];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mt-5">
|
<div className="mt-5">
|
||||||
<Header
|
<Header
|
||||||
headerContent="Your Library In Numbers"
|
headerContent="Your Library In Numbers"
|
||||||
subHeaderContent={
|
subHeaderContent={<span className="text-md">A brief snapshot of your library.</span>}
|
||||||
<span className="text-md">A brief snapshot of your library.</span>
|
|
||||||
}
|
|
||||||
iconClassNames="fa-solid fa-binoculars mr-2"
|
iconClassNames="fa-solid fa-binoculars mr-2"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="mt-3">
|
<div className="mt-3 flex flex-row gap-5">
|
||||||
<div className="flex flex-row gap-5">
|
{/* Total records in database */}
|
||||||
<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">
|
||||||
<dt className="text-lg font-medium text-gray-500">Library size</dt>
|
<dt className="text-lg font-medium text-gray-500">In database</dt>
|
||||||
<dd className="text-3xl text-green-600 md:text-5xl">
|
<dd className="text-3xl text-green-600 md:text-5xl">
|
||||||
{props.stats.totalDocuments} files
|
{stats.totalDocuments} comics
|
||||||
</dd>
|
</dd>
|
||||||
{props.stats.comicDirectorySize?.fileCount && (
|
|
||||||
<dd>
|
|
||||||
<span className="text-2xl text-green-600">
|
|
||||||
{props.stats.comicDirectorySize.fileCount} comic files
|
|
||||||
</span>
|
|
||||||
</dd>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{/* comicinfo and comicvine tagged issues */}
|
|
||||||
<div className="flex flex-col gap-4">
|
|
||||||
{!isUndefined(props.stats.statistics) &&
|
|
||||||
!isEmpty(props.stats.statistics?.[0]?.issues) && (
|
|
||||||
<div className="flex flex-col h-fit rounded-lg bg-green-100 dark:bg-green-200 px-4 py-3 text-center">
|
|
||||||
<span className="text-xl">
|
|
||||||
{props.stats.statistics?.[0]?.issues?.length || 0}
|
|
||||||
</span>{" "}
|
|
||||||
tagged with ComicVine
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{!isUndefined(props.stats.statistics) &&
|
|
||||||
!isEmpty(props.stats.statistics?.[0]?.issuesWithComicInfoXML) && (
|
|
||||||
<div className="flex flex-col h-fit rounded-lg bg-green-100 dark:bg-green-200 px-4 py-3 text-center">
|
|
||||||
<span className="text-xl">
|
|
||||||
{props.stats.statistics?.[0]?.issuesWithComicInfoXML?.length || 0}
|
|
||||||
</span>{" "}
|
|
||||||
<span className="tag is-warning has-text-weight-bold mr-2 ml-1">
|
|
||||||
with ComicInfo.xml
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="">
|
|
||||||
{!isUndefined(props.stats.statistics) &&
|
|
||||||
!isEmpty(props.stats.statistics?.[0]?.fileTypes) &&
|
|
||||||
map(props.stats.statistics?.[0]?.fileTypes, (fileType, idx) => {
|
|
||||||
return (
|
|
||||||
<span
|
|
||||||
key={idx}
|
|
||||||
className="flex flex-col mb-4 h-fit text-xl rounded-lg bg-green-100 dark:bg-green-200 px-4 py-3 text-center"
|
|
||||||
>
|
|
||||||
{fileType.data.length} {fileType.id}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* file types */}
|
|
||||||
<div className="flex flex-col h-fit text-lg rounded-lg bg-green-100 dark:bg-green-200 px-4 py-3">
|
|
||||||
{/* publisher with most issues */}
|
|
||||||
{!isUndefined(props.stats.statistics) &&
|
|
||||||
!isEmpty(
|
|
||||||
props.stats.statistics?.[0]?.publisherWithMostComicsInLibrary?.[0],
|
|
||||||
) && (
|
|
||||||
<>
|
|
||||||
<span className="">
|
|
||||||
{
|
|
||||||
props.stats.statistics?.[0]
|
|
||||||
?.publisherWithMostComicsInLibrary?.[0]?.id
|
|
||||||
}
|
|
||||||
</span>
|
|
||||||
{" has the most issues "}
|
|
||||||
<span className="">
|
|
||||||
{
|
|
||||||
props.stats.statistics?.[0]
|
|
||||||
?.publisherWithMostComicsInLibrary?.[0]?.count
|
|
||||||
}
|
|
||||||
</span>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Missing files */}
|
||||||
|
{fileLessComics && fileLessComics.length > 0 && (
|
||||||
|
<div className="flex flex-col rounded-lg bg-red-100 dark:bg-red-200 px-4 py-6 text-center">
|
||||||
|
<dt className="text-lg font-medium text-gray-500">Missing files</dt>
|
||||||
|
<dd className="text-3xl text-red-600 md:text-5xl">
|
||||||
|
{fileLessComics.length}
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Disk space consumed */}
|
||||||
|
{stats.comicDirectorySize.totalSizeInGB != null && (
|
||||||
|
<div className="flex flex-col rounded-lg bg-green-100 dark:bg-green-200 px-4 py-6 text-center">
|
||||||
|
<dt className="text-lg font-medium text-gray-500">Size on disk</dt>
|
||||||
|
<dd className="text-3xl text-green-600 md:text-5xl">
|
||||||
|
{stats.comicDirectorySize.totalSizeInGB.toFixed(2)} GB
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Tagging coverage */}
|
||||||
|
<div className="flex flex-col gap-4">
|
||||||
|
{issues && issues.length > 0 && (
|
||||||
|
<div className="flex flex-col h-fit rounded-lg bg-green-100 dark:bg-green-200 px-4 py-3 text-center">
|
||||||
|
<span className="text-xl">{issues.length}</span>
|
||||||
|
tagged with ComicVine
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{issuesWithComicInfoXML && issuesWithComicInfoXML.length > 0 && (
|
||||||
|
<div className="flex flex-col h-fit rounded-lg bg-green-100 dark:bg-green-200 px-4 py-3 text-center">
|
||||||
|
<span className="text-xl">{issuesWithComicInfoXML.length}</span>
|
||||||
|
with ComicInfo.xml
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* File-type breakdown */}
|
||||||
|
{fileTypes && fileTypes.length > 0 && (
|
||||||
|
<div>
|
||||||
|
{fileTypes.map((ft) => (
|
||||||
|
<span
|
||||||
|
key={ft.id}
|
||||||
|
className="flex flex-col mb-4 h-fit text-xl rounded-lg bg-green-100 dark:bg-green-200 px-4 py-3 text-center"
|
||||||
|
>
|
||||||
|
{ft.data.length} {ft.id}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Publisher with most issues */}
|
||||||
|
{topPublisher && (
|
||||||
|
<div className="flex flex-col h-fit text-lg rounded-lg bg-green-100 dark:bg-green-200 px-4 py-3">
|
||||||
|
<span>{topPublisher.id}</span>
|
||||||
|
{" has the most issues "}
|
||||||
|
<span>{topPublisher.count}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,55 +1,51 @@
|
|||||||
import React, { ReactElement, useMemo, useState, useRef, useEffect, useLayoutEffect } from "react";
|
import React, { ReactElement, ReactNode, useMemo, useState, useRef, useEffect, useLayoutEffect } from "react";
|
||||||
import {
|
import {
|
||||||
ColumnDef,
|
ColumnDef,
|
||||||
|
Row,
|
||||||
flexRender,
|
flexRender,
|
||||||
getCoreRowModel,
|
getCoreRowModel,
|
||||||
getFilteredRowModel,
|
|
||||||
useReactTable,
|
useReactTable,
|
||||||
PaginationState,
|
PaginationState,
|
||||||
} from "@tanstack/react-table";
|
} from "@tanstack/react-table";
|
||||||
|
|
||||||
/**
|
/** Props for {@link T2Table}. */
|
||||||
* Props for {@link T2Table}.
|
interface T2TableProps<TData> {
|
||||||
*/
|
|
||||||
interface T2TableProps {
|
|
||||||
/** Row data to render. */
|
/** Row data to render. */
|
||||||
sourceData?: unknown[];
|
sourceData?: TData[];
|
||||||
/** Total number of records across all pages, used for pagination display. */
|
/** Total number of records across all pages, used for pagination display. */
|
||||||
totalPages?: number;
|
totalPages?: number;
|
||||||
/** Column definitions (TanStack Table {@link ColumnDef} array). */
|
/** Column definitions (TanStack Table {@link ColumnDef} array). */
|
||||||
columns?: unknown[];
|
columns?: ColumnDef<TData>[];
|
||||||
/** Callbacks for navigating between pages. */
|
/** Callbacks for navigating between pages. */
|
||||||
paginationHandlers?: {
|
paginationHandlers?: {
|
||||||
nextPage?(...args: unknown[]): unknown;
|
nextPage?(pageIndex: number, pageSize: number): void;
|
||||||
previousPage?(...args: unknown[]): unknown;
|
previousPage?(pageIndex: number, pageSize: number): void;
|
||||||
};
|
};
|
||||||
/** Called with the TanStack row object when a row is clicked. */
|
/** Called with the TanStack row object when a row is clicked. */
|
||||||
rowClickHandler?(...args: unknown[]): unknown;
|
rowClickHandler?(row: Row<TData>): void;
|
||||||
/** Returns additional CSS classes for a given row (e.g. for highlight states). */
|
/** Returns additional CSS classes for a given row (e.g. for highlight states). */
|
||||||
getRowClassName?(row: any): string;
|
getRowClassName?(row: Row<TData>): string;
|
||||||
/** Optional slot rendered in the toolbar area (e.g. a search input). */
|
/** Optional slot rendered in the toolbar area (e.g. a search input). */
|
||||||
children?: any;
|
children?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A paginated data table with a two-row sticky header.
|
* A paginated data table with a two-row sticky header.
|
||||||
*
|
*
|
||||||
* The header rounds its corners only while stuck to the top of the scroll
|
* Header stickiness is detected via {@link IntersectionObserver} on a sentinel
|
||||||
* container, detected via {@link IntersectionObserver} on a sentinel element
|
* element placed immediately before the table. The second header row's `top`
|
||||||
* placed immediately before the table. The second header row's `top` offset
|
* offset is measured at mount time so both rows stay flush regardless of font
|
||||||
* is measured from the DOM at mount time so the two rows stay flush regardless
|
* size or padding changes.
|
||||||
* of font size or padding changes.
|
|
||||||
*/
|
*/
|
||||||
export const T2Table = (tableOptions: T2TableProps): ReactElement => {
|
export const T2Table = <TData,>({
|
||||||
const {
|
sourceData = [],
|
||||||
sourceData,
|
columns = [],
|
||||||
columns,
|
paginationHandlers: { nextPage, previousPage } = {},
|
||||||
paginationHandlers: { nextPage, previousPage },
|
totalPages = 0,
|
||||||
totalPages,
|
rowClickHandler,
|
||||||
rowClickHandler,
|
getRowClassName,
|
||||||
getRowClassName,
|
children,
|
||||||
} = tableOptions;
|
}: T2TableProps<TData>): ReactElement => {
|
||||||
|
|
||||||
const sentinelRef = useRef<HTMLDivElement>(null);
|
const sentinelRef = useRef<HTMLDivElement>(null);
|
||||||
const firstHeaderRowRef = useRef<HTMLTableRowElement>(null);
|
const firstHeaderRowRef = useRef<HTMLTableRowElement>(null);
|
||||||
const [isSticky, setIsSticky] = useState(false);
|
const [isSticky, setIsSticky] = useState(false);
|
||||||
@@ -76,30 +72,18 @@ export const T2Table = (tableOptions: T2TableProps): ReactElement => {
|
|||||||
pageSize: 15,
|
pageSize: 15,
|
||||||
});
|
});
|
||||||
|
|
||||||
const pagination = useMemo(
|
const pagination = useMemo(() => ({ pageIndex, pageSize }), [pageIndex, pageSize]);
|
||||||
() => ({
|
|
||||||
pageIndex,
|
|
||||||
pageSize,
|
|
||||||
}),
|
|
||||||
[pageIndex, pageSize],
|
|
||||||
);
|
|
||||||
|
|
||||||
/** Advances to the next page and notifies the parent via {@link T2TableProps.paginationHandlers}. */
|
/** Advances to the next page and notifies the parent. */
|
||||||
const goToNextPage = () => {
|
const goToNextPage = () => {
|
||||||
setPagination({
|
setPagination({ pageIndex: pageIndex + 1, pageSize });
|
||||||
pageIndex: pageIndex + 1,
|
nextPage?.(pageIndex, pageSize);
|
||||||
pageSize,
|
|
||||||
});
|
|
||||||
nextPage(pageIndex, pageSize);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Goes back one page and notifies the parent via {@link T2TableProps.paginationHandlers}. */
|
/** Goes back one page and notifies the parent. */
|
||||||
const goToPreviousPage = () => {
|
const goToPreviousPage = () => {
|
||||||
setPagination({
|
setPagination({ pageIndex: pageIndex - 1, pageSize });
|
||||||
pageIndex: pageIndex - 1,
|
previousPage?.(pageIndex, pageSize);
|
||||||
pageSize,
|
|
||||||
});
|
|
||||||
previousPage(pageIndex, pageSize);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
@@ -108,43 +92,37 @@ export const T2Table = (tableOptions: T2TableProps): ReactElement => {
|
|||||||
manualPagination: true,
|
manualPagination: true,
|
||||||
getCoreRowModel: getCoreRowModel(),
|
getCoreRowModel: getCoreRowModel(),
|
||||||
pageCount: sourceData.length ?? -1,
|
pageCount: sourceData.length ?? -1,
|
||||||
state: {
|
state: { pagination },
|
||||||
pagination,
|
|
||||||
},
|
|
||||||
onPaginationChange: setPagination,
|
onPaginationChange: setPagination,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container max-w-fit">
|
<div className="container max-w-fit">
|
||||||
<div>
|
<div className="flex flex-row gap-2 justify-between mt-6 mb-4">
|
||||||
<div className="flex flex-row gap-2 justify-between mt-6 mb-4">
|
{children}
|
||||||
{/* Search bar */}
|
|
||||||
{tableOptions.children}
|
|
||||||
|
|
||||||
{/* Pagination controls */}
|
<div className="text-sm text-gray-800 dark:text-slate-200">
|
||||||
<div className="text-sm text-gray-800 dark:text-slate-200">
|
<div className="mb-1">
|
||||||
<div className="mb-1">
|
Page {pageIndex} of {Math.ceil(totalPages / pageSize)}
|
||||||
Page {pageIndex} of {Math.ceil(totalPages / pageSize)}
|
</div>
|
||||||
</div>
|
<p className="text-xs text-gray-600 dark:text-slate-400">
|
||||||
<p className="text-xs text-gray-600 dark:text-slate-400">
|
{totalPages} comics in all
|
||||||
{totalPages} comics in all
|
</p>
|
||||||
</p>
|
<div className="inline-flex flex-row mt-3">
|
||||||
<div className="inline-flex flex-row mt-3">
|
<button
|
||||||
<button
|
onClick={goToPreviousPage}
|
||||||
onClick={() => goToPreviousPage()}
|
disabled={pageIndex === 1}
|
||||||
disabled={pageIndex === 1}
|
className="dark:bg-slate-400 bg-gray-300 rounded-l px-2 py-1 border-r border-slate-600"
|
||||||
className="dark:bg-slate-400 bg-gray-300 rounded-l px-2 py-1 border-r border-slate-600"
|
>
|
||||||
>
|
<i className="icon-[solar--arrow-left-linear] h-5 w-5" />
|
||||||
<i className="icon-[solar--arrow-left-linear] h-5 w-5"></i>
|
</button>
|
||||||
</button>
|
<button
|
||||||
<button
|
onClick={goToNextPage}
|
||||||
className="dark:bg-slate-400 bg-gray-300 rounded-r px-2 py-1"
|
disabled={pageIndex > Math.floor(totalPages / pageSize)}
|
||||||
onClick={() => goToNextPage()}
|
className="dark:bg-slate-400 bg-gray-300 rounded-r px-2 py-1"
|
||||||
disabled={pageIndex > Math.floor(totalPages / pageSize)}
|
>
|
||||||
>
|
<i className="icon-[solar--arrow-right-linear] h-5 w-5" />
|
||||||
<i className="icon-[solar--arrow-right-linear] h-5 w-5"></i>
|
</button>
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -152,37 +130,35 @@ export const T2Table = (tableOptions: T2TableProps): ReactElement => {
|
|||||||
<div ref={sentinelRef} />
|
<div ref={sentinelRef} />
|
||||||
<table className="table-auto w-full text-sm text-gray-900 dark:text-slate-100">
|
<table className="table-auto w-full text-sm text-gray-900 dark:text-slate-100">
|
||||||
<thead>
|
<thead>
|
||||||
{table.getHeaderGroups().map((headerGroup, groupIndex) => {
|
{table.getHeaderGroups().map((headerGroup, groupIndex) => (
|
||||||
return (
|
<tr key={headerGroup.id} ref={groupIndex === 0 ? firstHeaderRowRef : undefined}>
|
||||||
<tr key={headerGroup.id} ref={groupIndex === 0 ? firstHeaderRowRef : undefined}>
|
{headerGroup.headers.map((header) => (
|
||||||
{headerGroup.headers.map((header) => (
|
<th
|
||||||
<th
|
key={header.id}
|
||||||
key={header.id}
|
colSpan={header.colSpan}
|
||||||
colSpan={header.colSpan}
|
style={groupIndex === 1 ? { top: firstRowHeight } : undefined}
|
||||||
style={groupIndex === 1 ? { top: firstRowHeight } : undefined}
|
className={[
|
||||||
className={[
|
'sticky z-10 px-3 py-2 text-[11px] font-semibold tracking-wide uppercase text-left',
|
||||||
'sticky z-10 px-3 py-2 text-[11px] font-semibold tracking-wide uppercase text-left',
|
'text-gray-500 dark:text-slate-400 bg-white dark:bg-slate-900',
|
||||||
'text-gray-500 dark:text-slate-400 bg-white dark:bg-slate-900',
|
groupIndex === 0
|
||||||
groupIndex === 0
|
? `top-0 ${isSticky ? 'first:rounded-tl-xl last:rounded-tr-xl' : ''}`
|
||||||
? `top-0 ${isSticky ? 'first:rounded-tl-xl last:rounded-tr-xl' : ''}`
|
: `border-b-2 border-gray-200 dark:border-slate-600 shadow-md ${isSticky ? 'first:rounded-bl-xl last:rounded-br-xl' : ''}`,
|
||||||
: `border-b-2 border-gray-200 dark:border-slate-600 shadow-md ${isSticky ? 'first:rounded-bl-xl last:rounded-br-xl' : ''}`,
|
].join(' ')}
|
||||||
].join(' ')}
|
>
|
||||||
>
|
{header.isPlaceholder
|
||||||
{header.isPlaceholder
|
? null
|
||||||
? null
|
: flexRender(header.column.columnDef.header, header.getContext())}
|
||||||
: flexRender(header.column.columnDef.header, header.getContext())}
|
</th>
|
||||||
</th>
|
))}
|
||||||
))}
|
</tr>
|
||||||
</tr>
|
))}
|
||||||
);
|
|
||||||
})}
|
|
||||||
</thead>
|
</thead>
|
||||||
|
|
||||||
<tbody>
|
<tbody>
|
||||||
{table.getRowModel().rows.map((row, rowIndex) => (
|
{table.getRowModel().rows.map((row) => (
|
||||||
<tr
|
<tr
|
||||||
key={row.id}
|
key={row.id}
|
||||||
onClick={() => rowClickHandler(row)}
|
onClick={() => rowClickHandler?.(row)}
|
||||||
className={`border-b border-gray-200 dark:border-slate-700 transition-colors cursor-pointer ${getRowClassName ? getRowClassName(row) : "hover:bg-slate-100/30 dark:hover:bg-slate-700/20"}`}
|
className={`border-b border-gray-200 dark:border-slate-700 transition-colors cursor-pointer ${getRowClassName ? getRowClassName(row) : "hover:bg-slate-100/30 dark:hover:bg-slate-700/20"}`}
|
||||||
>
|
>
|
||||||
{row.getVisibleCells().map((cell) => (
|
{row.getVisibleCells().map((cell) => (
|
||||||
|
|||||||
@@ -1302,7 +1302,7 @@ export type GetVolumeGroupsQuery = { __typename?: 'Query', getComicBookGroups: A
|
|||||||
export type GetLibraryStatisticsQueryVariables = Exact<{ [key: string]: never; }>;
|
export type GetLibraryStatisticsQueryVariables = Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
|
|
||||||
export type GetLibraryStatisticsQuery = { __typename?: 'Query', getLibraryStatistics: { __typename?: 'LibraryStatistics', totalDocuments: number, comicDirectorySize: { __typename?: 'DirectorySize', fileCount: number }, statistics: Array<{ __typename?: 'StatisticsFacet', fileTypes?: Array<{ __typename?: 'FileTypeStats', id: string, data: Array<string> }> | null, issues?: Array<{ __typename?: 'IssueStats', data: Array<string>, id?: { __typename?: 'VolumeInfo', id?: number | null, name?: string | null } | null }> | null, fileLessComics?: Array<{ __typename?: 'Comic', id: string }> | null, issuesWithComicInfoXML?: Array<{ __typename?: 'Comic', id: string }> | null, publisherWithMostComicsInLibrary?: Array<{ __typename?: 'PublisherStats', id: string, count: number }> | null }> } };
|
export type GetLibraryStatisticsQuery = { __typename?: 'Query', getLibraryStatistics: { __typename?: 'LibraryStatistics', totalDocuments: number, comicDirectorySize: { __typename?: 'DirectorySize', fileCount: number, totalSizeInGB: number }, statistics: Array<{ __typename?: 'StatisticsFacet', fileTypes?: Array<{ __typename?: 'FileTypeStats', id: string, data: Array<string> }> | null, issues?: Array<{ __typename?: 'IssueStats', data: Array<string>, id?: { __typename?: 'VolumeInfo', id?: number | null, name?: string | null } | null }> | null, fileLessComics?: Array<{ __typename?: 'Comic', id: string }> | null, issuesWithComicInfoXML?: Array<{ __typename?: 'Comic', id: string }> | null, publisherWithMostComicsInLibrary?: Array<{ __typename?: 'PublisherStats', id: string, count: number }> | null }> } };
|
||||||
|
|
||||||
export type GetWeeklyPullListQueryVariables = Exact<{
|
export type GetWeeklyPullListQueryVariables = Exact<{
|
||||||
input: WeeklyPullListInput;
|
input: WeeklyPullListInput;
|
||||||
@@ -1945,6 +1945,7 @@ export const GetLibraryStatisticsDocument = `
|
|||||||
totalDocuments
|
totalDocuments
|
||||||
comicDirectorySize {
|
comicDirectorySize {
|
||||||
fileCount
|
fileCount
|
||||||
|
totalSizeInGB
|
||||||
}
|
}
|
||||||
statistics {
|
statistics {
|
||||||
fileTypes {
|
fileTypes {
|
||||||
|
|||||||
@@ -181,6 +181,7 @@ query GetLibraryStatistics {
|
|||||||
totalDocuments
|
totalDocuments
|
||||||
comicDirectorySize {
|
comicDirectorySize {
|
||||||
fileCount
|
fileCount
|
||||||
|
totalSizeInGB
|
||||||
}
|
}
|
||||||
statistics {
|
statistics {
|
||||||
fileTypes {
|
fileTypes {
|
||||||
|
|||||||
Reference in New Issue
Block a user