diff --git a/admin/app/services/zim_service.ts b/admin/app/services/zim_service.ts index 5a362e0..c305939 100644 --- a/admin/app/services/zim_service.ts +++ b/admin/app/services/zim_service.ts @@ -164,6 +164,13 @@ export class ZimService { download_url, author: entry.author.name, file_name, + language: entry.language, + category: entry.category, + tags: entry.tags, + article_count: entry.articleCount, + media_count: entry.mediaCount, + publisher: entry.publisher?.name, + issued: entry['dc:issued'], }) } diff --git a/admin/inertia/pages/settings/zim/remote-explorer.tsx b/admin/inertia/pages/settings/zim/remote-explorer.tsx index a19d9b3..2d66862 100644 --- a/admin/inertia/pages/settings/zim/remote-explorer.tsx +++ b/admin/inertia/pages/settings/zim/remote-explorer.tsx @@ -7,7 +7,6 @@ import { } from '@tanstack/react-query' import api from '~/lib/api' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' -import { useVirtualizer } from '@tanstack/react-virtual' import StyledTable from '~/components/StyledTable' import SettingsLayout from '~/layouts/SettingsLayout' import { Head } from '@inertiajs/react' @@ -191,13 +190,6 @@ export default function ZimRemoteExplorer() { [fetchNextPage, isFetching, hasMore] ) - const virtualizer = useVirtualizer({ - count: flatData.length, - estimateSize: () => 48, // Estimate row height - getScrollElement: () => tableParentRef.current, - overscan: 5, // Number of items to render outside the visible area - }) - //a check on mount and after a fetch to see if the table is already scrolled to the bottom and immediately needs to fetch more data useEffect(() => { fetchOnBottomReached(tableParentRef.current) @@ -591,14 +583,7 @@ export default function ZimRemoteExplorer() { /> - data={flatData.map((i, idx) => { - const row = virtualizer.getVirtualItems().find((v) => v.index === idx) - return { - ...i, - height: `${row?.size || 48}px`, - translateY: row?.start || 0, - } - })} + data={flatData} ref={tableParentRef} loading={isLoading} columns={[ @@ -610,6 +595,13 @@ export default function ZimRemoteExplorer() { }, { accessor: 'summary', + render(record) { + return ( + + {record.summary} + + ) + }, }, { accessor: 'updated', @@ -644,11 +636,95 @@ export default function ZimRemoteExplorer() { }, }, ]} - className="relative overflow-x-auto overflow-y-auto h-[600px] w-full mt-4" - tableBodyStyle={{ - position: 'relative', - height: `${virtualizer.getTotalSize()}px`, + expandable={{ + expandedRowRender(record) { + return ( +
+

{record.summary}

+
+ {record.author && ( +
+ Author: + {record.author} +
+ )} + {record.publisher && ( +
+ Publisher: + {record.publisher} +
+ )} + {record.language && ( +
+ Language: + {record.language} +
+ )} + {record.category && ( +
+ Category: + {record.category} +
+ )} + {record.article_count != null && record.article_count > 0 && ( +
+ Articles: + + {record.article_count.toLocaleString()} + +
+ )} + {record.media_count != null && record.media_count > 0 && ( +
+ Media: + + {record.media_count.toLocaleString()} + +
+ )} + {record.issued && ( +
+ Issued: + + {new Intl.DateTimeFormat('en-US', { + dateStyle: 'medium', + }).format(new Date(record.issued))} + +
+ )} + {record.size_bytes > 0 && ( +
+ Size: + {formatBytes(record.size_bytes)} +
+ )} +
+ {record.tags && ( +
+ {record.tags + .split(';') + .filter(Boolean) + .map((tag, i) => ( + + {tag.trim()} + + ))} +
+ )} + {record.file_name && ( +
+ File: + {record.file_name} +
+ )} +
+ ) + }, }} + className="overflow-y-auto h-[600px] w-full mt-4" containerProps={{ onScroll: (e) => fetchOnBottomReached(e.currentTarget as HTMLDivElement), }} @@ -760,7 +836,6 @@ export default function ZimRemoteExplorer() { )} )} - {/* Manage Custom Libraries Modal */} diff --git a/admin/types/zim.ts b/admin/types/zim.ts index 96ed081..eb6e2b4 100644 --- a/admin/types/zim.ts +++ b/admin/types/zim.ts @@ -64,6 +64,13 @@ export type RemoteZimFileEntry = { download_url: string author: string file_name: string + language?: string + category?: string + tags?: string + article_count?: number + media_count?: number + publisher?: string + issued?: string } export type ExtractZIMContentOptions = { @@ -71,8 +78,8 @@ export type ExtractZIMContentOptions = { maxArticles?: number onProgress?: (processedArticles: number, totalArticles: number) => void // Batch processing options to avoid lock timeouts - startOffset?: number // Article index to start from for resuming - batchSize?: number // Max articles to process in this batch + startOffset?: number // Article index to start from for resuming + batchSize?: number // Max articles to process in this batch } export type ExtractZIMChunkingStrategy = 'structured' | 'simple' @@ -108,4 +115,4 @@ export type ZIMContentChunk = { // Extraction metadata strategy: ExtractZIMChunkingStrategy -} \ No newline at end of file +}