@@ -24,7 +24,7 @@ import {
2424import { useAuth } from '../../contexts/AuthContext' ;
2525import { useLanguage } from '../../contexts/LanguageContext' ;
2626import { useDemoCall } from '../../contexts/DemoCallContext' ;
27- import { ragService , UploadedDocument , DocumentChunk , ProcessingProgress } from '../../services/ragService' ;
27+ import { ragService , UploadedDocument , ProcessingProgress } from '../../services/ragService' ;
2828import { pageIndexService , PageIndexNode } from '../../services/pageIndexService' ;
2929import { motion , AnimatePresence } from 'framer-motion' ;
3030
@@ -58,6 +58,19 @@ function getFileIcon(fileType: string) {
5858 }
5959}
6060
61+ function getMaxPageIndex ( nodes : PageIndexNode [ ] ) : number {
62+ let maxPage = 0 ;
63+ for ( const node of nodes ) {
64+ if ( typeof node . page_index === 'number' ) {
65+ maxPage = Math . max ( maxPage , node . page_index ) ;
66+ }
67+ if ( node . nodes && node . nodes . length > 0 ) {
68+ maxPage = Math . max ( maxPage , getMaxPageIndex ( node . nodes ) ) ;
69+ }
70+ }
71+ return maxPage ;
72+ }
73+
6174const ACCEPTED_TYPES = '.pdf,.txt,.md,.csv,.docx' ;
6275const MAX_FILE_SIZE = 10 * 1024 * 1024 ; // 10MB
6376
@@ -126,8 +139,6 @@ export default function DocumentsView({ isDark = true }: { isDark?: boolean }) {
126139 const [ documents , setDocuments ] = useState < UploadedDocument [ ] > ( [ ] ) ;
127140 const [ isLoading , setIsLoading ] = useState ( true ) ;
128141 const [ expandedDocId , setExpandedDocId ] = useState < string | null > ( null ) ;
129- const [ chunks , setChunks ] = useState < DocumentChunk [ ] > ( [ ] ) ;
130- const [ loadingChunks , setLoadingChunks ] = useState ( false ) ;
131142 const [ processingProgress , setProcessingProgress ] = useState < ProcessingProgress | null > ( null ) ;
132143 const [ textTitle , setTextTitle ] = useState ( '' ) ;
133144 const [ textContent , setTextContent ] = useState ( '' ) ;
@@ -137,7 +148,8 @@ export default function DocumentsView({ isDark = true }: { isDark?: boolean }) {
137148 const [ uploadMode , setUploadMode ] = useState < 'text' | 'pdf' > ( 'pdf' ) ;
138149 const [ selectedFile , setSelectedFile ] = useState < File | null > ( null ) ;
139150 const [ pageIndexTree , setPageIndexTree ] = useState < PageIndexNode [ ] > ( [ ] ) ;
140- const [ activePageIndexId , setActivePageIndexId ] = useState < string | null > ( null ) ;
151+ const [ pageIndexByDocId , setPageIndexByDocId ] = useState < Record < string , PageIndexNode [ ] > > ( { } ) ;
152+ const [ pageIndexDocIdByDocId , setPageIndexDocIdByDocId ] = useState < Record < string , string > > ( { } ) ;
141153 const [ chatMessages , setChatMessages ] = useState < { role : string ; content : string } [ ] > ( [ ] ) ;
142154 const [ chatInput , setChatInput ] = useState ( '' ) ;
143155 const [ isChatting , setIsChatting ] = useState ( false ) ;
@@ -221,7 +233,6 @@ export default function DocumentsView({ isDark = true }: { isDark?: boolean }) {
221233
222234 try {
223235 const docId = await pageIndexService . submitDocument ( selectedFile ) ;
224- setActivePageIndexId ( docId ) ;
225236
226237 setProcessingProgress ( {
227238 stage : 'embedding' ,
@@ -247,12 +258,16 @@ export default function DocumentsView({ isDark = true }: { isDark?: boolean }) {
247258 // In a real app, we'd store the pageindex_id in the DB.
248259
249260 // Let's create a backup record in Supabase so it shows in the list
250- await ragService . processDocument (
261+ const ragDoc = await ragService . processDocument (
251262 selectedFile ,
252263 kbId ,
253264 user . id ,
254265 ( ) => { } // Silent progress for standard RAG
255266 ) ;
267+ if ( ragDoc ) {
268+ setPageIndexByDocId ( prev => ( { ...prev , [ ragDoc . id ] : result } ) ) ;
269+ setPageIndexDocIdByDocId ( prev => ( { ...prev , [ ragDoc . id ] : docId } ) ) ;
270+ }
256271
257272 setSelectedFile ( null ) ;
258273 setTextTitle ( '' ) ;
@@ -304,19 +319,13 @@ export default function DocumentsView({ isDark = true }: { isDark?: boolean }) {
304319 }
305320 } , [ chatMessages , isChatting ] ) ;
306321
307- // ─── Expand / view chunks ─── ──────────────────────────────
308- const toggleExpand = async ( docId : string ) => {
322+ // ─── Expand / view structure ──────────────────────────────
323+ const toggleExpand = ( docId : string ) => {
309324 if ( expandedDocId === docId ) {
310325 setExpandedDocId ( null ) ;
311- setChunks ( [ ] ) ;
312326 return ;
313327 }
314-
315328 setExpandedDocId ( docId ) ;
316- setLoadingChunks ( true ) ;
317- const docChunks = await ragService . getDocumentChunks ( docId ) ;
318- setChunks ( docChunks ) ;
319- setLoadingChunks ( false ) ;
320329 } ;
321330
322331 // ─── Delete ───────────────────────────────────────────────
@@ -327,8 +336,17 @@ export default function DocumentsView({ isDark = true }: { isDark?: boolean }) {
327336 setDocuments ( prev => prev . filter ( d => d . id !== docId ) ) ;
328337 if ( expandedDocId === docId ) {
329338 setExpandedDocId ( null ) ;
330- setChunks ( [ ] ) ;
331339 }
340+ setPageIndexByDocId ( prev => {
341+ const next = { ...prev } ;
342+ delete next [ docId ] ;
343+ return next ;
344+ } ) ;
345+ setPageIndexDocIdByDocId ( prev => {
346+ const next = { ...prev } ;
347+ delete next [ docId ] ;
348+ return next ;
349+ } ) ;
332350 }
333351 setDeleteConfirmId ( null ) ;
334352 } ;
@@ -664,8 +682,14 @@ export default function DocumentsView({ isDark = true }: { isDark?: boolean }) {
664682 </ div >
665683 ) : (
666684 < div className = "space-y-3" >
667- { documents . map ( ( doc ) => (
668- < div key = { doc . id } >
685+ { documents . map ( ( doc ) => {
686+ const treeForDoc = pageIndexByDocId [ doc . id ] ;
687+ const nodeCount = treeForDoc ? pageIndexService . countNodes ( treeForDoc ) : 0 ;
688+ const maxPage = treeForDoc ? getMaxPageIndex ( treeForDoc ) : 0 ;
689+ const pageIndexId = pageIndexDocIdByDocId [ doc . id ] ;
690+
691+ return (
692+ < div key = { doc . id } >
669693 { /* Document Row */ }
670694 < div className = { cn (
671695 "rounded-xl border p-4 transition-all duration-200" ,
@@ -728,7 +752,7 @@ export default function DocumentsView({ isDark = true }: { isDark?: boolean }) {
728752 isDark ? "bg-white/5 text-white/60" : "bg-gray-100 text-gray-600"
729753 ) } >
730754 < Layers className = "w-3 h-3" />
731- { doc . chunk_count } Chunks
755+ { treeForDoc ? ` ${ nodeCount } Nodes` : ` ${ doc . chunk_count } Chunks` }
732756 </ span >
733757 </ div >
734758 ) }
@@ -794,7 +818,7 @@ export default function DocumentsView({ isDark = true }: { isDark?: boolean }) {
794818 ) }
795819 </ div >
796820
797- { /* Expanded Chunks */ }
821+ { /* Expanded Structure */ }
798822 < AnimatePresence >
799823 { expandedDocId === doc . id && (
800824 < motion . div
@@ -809,67 +833,57 @@ export default function DocumentsView({ isDark = true }: { isDark?: boolean }) {
809833 isDark ? "bg-white/[0.03] border-white/10 backdrop-blur-md" : "bg-gray-50 border-gray-100"
810834 ) } >
811835 { /* Stats bar */ }
812- < div className = { cn ( "flex items-center gap-4 text-xs pb-3 border-b" , isDark ? "border-white/5" : "border-gray-200" ) } >
836+ < div className = { cn ( "flex flex-wrap items-center gap-4 text-xs pb-3 border-b" , isDark ? "border-white/5" : "border-gray-200" ) } >
837+ < span className = { textSecondary } >
838+ < strong className = { textPrimary } > { treeForDoc ? nodeCount : 'N/A' } </ strong > nodes
839+ </ span >
813840 < span className = { textSecondary } >
814- < strong className = { textPrimary } > { doc . chunk_count } </ strong > chunks
841+ < strong className = { textPrimary } > { treeForDoc ? treeForDoc . length : 'N/A' } </ strong > sections
815842 </ span >
816843 < span className = { textSecondary } >
817- < strong className = { textPrimary } > { doc . total_tokens ?. toLocaleString ( ) } </ strong > words
844+ < strong className = { textPrimary } > { treeForDoc ? ( maxPage || 'N/A' ) : 'N/A' } </ strong > pages
818845 </ span >
819- < span className = { cn ( "uppercase text-[10px] font-mono px-1.5 py-0.5 rounded" , isDark ? "bg-white/5" : "bg-gray-200" ) } >
846+ { pageIndexId && (
847+ < span className = { cn (
848+ "text-[10px] font-mono px-1.5 py-0.5 rounded border" ,
849+ isDark ? "bg-white/5 border-white/10 text-white/60" : "bg-gray-100 border-gray-200 text-gray-600"
850+ ) } >
851+ ID { pageIndexId }
852+ </ span >
853+ ) }
854+ < span className = { cn ( "uppercase text-[10px] font-mono px-1.5 py-0.5 rounded" , isDark ? "bg-white/5" : "bg-gray-200" ) } >
820855 { doc . file_type }
821856 </ span >
822857 </ div >
823858
824- { loadingChunks ? (
825- < div className = "flex items-center justify-center py-8" >
826- < Loader2 className = { cn ( "w-5 h-5 animate-spin" , textMuted ) } />
827- </ div >
828- ) : chunks . length === 0 ? (
829- < p className = { cn ( "text-sm text-center py-6" , textMuted ) } >
830- No chunks found
831- </ p >
832- ) : (
859+ { treeForDoc ? (
833860 < div className = "space-y-2 max-h-[400px] overflow-y-auto scrollbar-hide" >
834- { chunks . map ( ( chunk , idx ) => (
861+ { treeForDoc . map ( ( node , idx ) => (
835862 < div
836- key = { chunk . id }
863+ key = { ` ${ doc . id } - ${ idx } ` }
837864 className = { cn (
838865 "rounded-lg border p-3 transition-colors" ,
839866 isDark
840867 ? "bg-white/[0.03] border-white/10 hover:bg-white/[0.05]"
841868 : "bg-white border-gray-200 hover:bg-gray-50"
842869 ) }
843870 >
844- < div className = "flex items-start gap-3" >
845- < span className = { cn (
846- "flex-shrink-0 w-7 h-7 rounded-lg flex items-center justify-center text-xs font-mono font-bold" ,
847- isDark ? "bg-[#FF8A5B]/10 text-[#FFB286]" : "bg-orange-50 text-orange-600"
848- ) } >
849- { idx + 1 }
850- </ span >
851- < div className = "flex-1 min-w-0" >
852- < p className = { cn (
853- "text-xs leading-relaxed line-clamp-4" ,
854- isDark ? "text-white/70" : "text-gray-600"
855- ) } >
856- { chunk . content }
857- </ p >
858- < p className = { cn ( "text-[10px] mt-1.5" , textMuted ) } >
859- { chunk . content . split ( / \s + / ) . length } words
860- </ p >
861- </ div >
862- </ div >
871+ < TreeNodeNode node = { node } />
863872 </ div >
864873 ) ) }
865874 </ div >
875+ ) : (
876+ < p className = { cn ( "text-sm text-center py-6" , textMuted ) } >
877+ This document hasn't been indexed with PageIndex yet. Re-upload using Vectorless Indexing to generate structure.
878+ </ p >
866879 ) }
867880 </ div >
868881 </ motion . div >
869882 ) }
870883 </ AnimatePresence >
871884 </ div >
872- ) ) }
885+ ) ;
886+ } ) }
873887 </ div >
874888 ) }
875889 </ div >
0 commit comments