1
1
import { MinimalOnyxDocument , OnyxDocument } from "@/lib/search/interfaces" ;
2
2
import { ChatDocumentDisplay } from "./ChatDocumentDisplay" ;
3
3
import { removeDuplicateDocs } from "@/lib/documentUtils" ;
4
- import { ChatFileType } from "@/app/chat/interfaces" ;
5
4
import {
6
5
Dispatch ,
7
6
ForwardedRef ,
@@ -16,6 +15,31 @@ import {
16
15
useCurrentMessageTree ,
17
16
useSelectedNodeForDocDisplay ,
18
17
} from "../../stores/useChatSessionStore" ;
18
+ import type { ProjectFile } from "@/app/chat/projects/projectsService" ;
19
+
20
+ // Build an OnyxDocument from basic file info
21
+ const buildOnyxDocumentFromFile = (
22
+ id : string ,
23
+ name ?: string | null ,
24
+ appendProjectPrefix ?: boolean
25
+ ) : OnyxDocument => {
26
+ const document_id = appendProjectPrefix ? `project_file__${ id } ` : id ;
27
+ return {
28
+ document_id,
29
+ semantic_identifier : name || id ,
30
+ link : "" ,
31
+ source_type : "file" as any ,
32
+ blurb : "" ,
33
+ boost : 0 ,
34
+ hidden : false ,
35
+ score : 1 ,
36
+ chunk_ind : 0 ,
37
+ match_highlights : [ ] ,
38
+ metadata : { } ,
39
+ updated_at : null ,
40
+ is_internet : false ,
41
+ } as any ;
42
+ } ;
19
43
20
44
interface DocumentResultsProps {
21
45
closeSidebar : ( ) => void ;
@@ -29,6 +53,7 @@ interface DocumentResultsProps {
29
53
isSharedChat ?: boolean ;
30
54
modal : boolean ;
31
55
setPresentingDocument : Dispatch < SetStateAction < MinimalOnyxDocument | null > > ;
56
+ projectFiles ?: ProjectFile [ ] ;
32
57
}
33
58
34
59
const DocumentResultsComponent = (
@@ -44,6 +69,7 @@ const DocumentResultsComponent = (
44
69
isSharedChat,
45
70
isOpen,
46
71
setPresentingDocument,
72
+ projectFiles = [ ] ,
47
73
} : DocumentResultsProps ,
48
74
ref : ForwardedRef < HTMLDivElement >
49
75
) => {
@@ -80,7 +106,7 @@ const DocumentResultsComponent = (
80
106
: null ;
81
107
82
108
const humanFileDescriptors = humanMessage ?. files . filter (
83
- ( file ) => file . type == ChatFileType . USER_KNOWLEDGE
109
+ ( file ) => file . user_file_id ! == null
84
110
) ;
85
111
const selectedDocumentIds =
86
112
selectedDocuments ?. map ( ( document ) => document . document_id ) || [ ] ;
@@ -103,6 +129,15 @@ const DocumentResultsComponent = (
103
129
! citedDocumentIds . has ( doc . document_id )
104
130
) ;
105
131
132
+ const hasDocs = dedupedDocuments . length > 0 ;
133
+ const hasCited = citedDocuments . length > 0 ;
134
+ const hasOther = otherDocuments . length > 0 ;
135
+ const hasHumanFiles = ( humanFileDescriptors ?. length || 0 ) > 0 ;
136
+ const hasProjectFiles = ( projectFiles ?. length || 0 ) > 0 ;
137
+ const showCloseInUserFiles = ! hasCited && ! hasOther && hasHumanFiles ;
138
+ const showCloseInProjectFiles =
139
+ ! hasCited && ! hasOther && ! hasHumanFiles && hasProjectFiles ;
140
+
106
141
return (
107
142
< >
108
143
< div
@@ -127,10 +162,11 @@ const DocumentResultsComponent = (
127
162
>
128
163
< div className = "flex flex-col h-full" >
129
164
< div className = "overflow-y-auto h-fit mb-8 pb-8 sm:mx-0 flex-grow gap-y-0 default-scrollbar dark-scrollbar flex flex-col" >
130
- { dedupedDocuments . length > 0 ? (
165
+ { /* Documents Sections */ }
166
+ { hasDocs && (
131
167
< >
132
168
{ /* Cited Documents Section */ }
133
- { citedDocuments . length > 0 && (
169
+ { hasCited && (
134
170
< div className = "mt-4" >
135
171
< div className = "px-4 pb-3 pt-2 flex justify-between border-b border-border" >
136
172
< h3 className = "text-base font-semibold text-text-700" >
@@ -175,7 +211,7 @@ const DocumentResultsComponent = (
175
211
) }
176
212
177
213
{ /* Other Documents Section */ }
178
- { otherDocuments . length > 0 && (
214
+ { hasOther && (
179
215
< div className = "mt-4" >
180
216
< >
181
217
< div className = "px-4 pb-3 pt-2 border-b border-border" >
@@ -215,7 +251,90 @@ const DocumentResultsComponent = (
215
251
</ div >
216
252
) }
217
253
</ >
218
- ) : null }
254
+ ) }
255
+
256
+ { /* Human Files Section */ }
257
+ { humanFileDescriptors && humanFileDescriptors . length > 0 && (
258
+ < div className = "mt-4" >
259
+ < div className = "px-4 pb-3 pt-2 flex justify-between border-b border-border" >
260
+ < h3 className = "text-base font-semibold text-text-700" >
261
+ User Files
262
+ </ h3 >
263
+ { showCloseInUserFiles && (
264
+ < button
265
+ aria-label = "Close sidebar"
266
+ title = "Close"
267
+ className = "my-auto p-1 rounded transition-colors hover:bg-neutral-200 dark:hover:bg-neutral-700"
268
+ onClick = { closeSidebar }
269
+ >
270
+ < XIcon size = { 16 } />
271
+ </ button >
272
+ ) }
273
+ </ div >
274
+ { humanFileDescriptors . map ( ( f ) => (
275
+ < div key = { f . id } className = { `desktop:px-2 w-full mb-2` } >
276
+ < ChatDocumentDisplay
277
+ setPresentingDocument = { setPresentingDocument }
278
+ closeSidebar = { closeSidebar }
279
+ modal = { modal }
280
+ document = { buildOnyxDocumentFromFile (
281
+ f . id ,
282
+ f . name ,
283
+ false
284
+ ) }
285
+ isSelected = { false }
286
+ handleSelect = { ( ) => { } }
287
+ hideSelection = { true }
288
+ tokenLimitReached = { false }
289
+ />
290
+ </ div >
291
+ ) ) }
292
+ </ div >
293
+ ) }
294
+
295
+ { /* Project Files Section */ }
296
+ { projectFiles && projectFiles . length > 0 && (
297
+ < div className = "mt-4" >
298
+ < div className = "px-4 pb-3 pt-2 flex justify-between border-b border-border" >
299
+ < h3 className = "text-base font-semibold text-text-700" >
300
+ Project Files
301
+ </ h3 >
302
+ { showCloseInProjectFiles && (
303
+ < button
304
+ aria-label = "Close sidebar"
305
+ title = "Close"
306
+ className = "my-auto p-1 rounded transition-colors hover:bg-neutral-200 dark:hover:bg-neutral-700"
307
+ onClick = { closeSidebar }
308
+ >
309
+ < XIcon size = { 16 } />
310
+ </ button >
311
+ ) }
312
+ </ div >
313
+ { projectFiles . slice ( 0 , 20 ) . map ( ( f ) => (
314
+ < div key = { f . id } className = { `desktop:px-2 w-full mb-2` } >
315
+ < ChatDocumentDisplay
316
+ setPresentingDocument = { setPresentingDocument }
317
+ closeSidebar = { closeSidebar }
318
+ modal = { modal }
319
+ document = { buildOnyxDocumentFromFile (
320
+ f . file_id ,
321
+ f . name ,
322
+ true
323
+ ) }
324
+ isSelected = { false }
325
+ handleSelect = { ( ) => { } }
326
+ hideSelection = { true }
327
+ tokenLimitReached = { false }
328
+ />
329
+ </ div >
330
+ ) ) }
331
+ { projectFiles . length > 20 && (
332
+ < div className = "text-text-500 px-4 py-2 text-xs" >
333
+ +{ projectFiles . length - 20 } more
334
+ </ div >
335
+ ) }
336
+ </ div >
337
+ ) }
219
338
</ div >
220
339
</ div >
221
340
</ div >
0 commit comments