From 6eb2c884a232ebfd21a9183e350b27347c05a1e1 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Tue, 22 Jul 2025 19:36:52 +0530 Subject: [PATCH] (refactor) separation in chunks/files view --- frontend/src/assets/search.svg | 3 + frontend/src/components/DocumentChunks.tsx | 316 +++++++++--------- frontend/src/components/FileTreeComponent.tsx | 186 ++++++----- frontend/src/settings/Documents.tsx | 1 - 4 files changed, 274 insertions(+), 232 deletions(-) create mode 100644 frontend/src/assets/search.svg diff --git a/frontend/src/assets/search.svg b/frontend/src/assets/search.svg new file mode 100644 index 00000000..2f3d57c4 --- /dev/null +++ b/frontend/src/assets/search.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/components/DocumentChunks.tsx b/frontend/src/components/DocumentChunks.tsx index 1cdef63f..e4dbc4a8 100644 --- a/frontend/src/components/DocumentChunks.tsx +++ b/frontend/src/components/DocumentChunks.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useRef } from 'react'; import { useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; import { selectToken } from '../preferences/preferenceSlice'; @@ -19,16 +19,16 @@ interface DocumentChunksProps { documentId: string; documentName?: string; handleGoBack: () => void; - showHeader?: boolean; path?: string; + renderFileSearch?: () => React.ReactNode; } const DocumentChunks: React.FC = ({ documentId, documentName, handleGoBack, - showHeader = true, path, + renderFileSearch }) => { const { t } = useTranslation(); const token = useSelector(selectToken); @@ -45,6 +45,8 @@ const DocumentChunks: React.FC = ({ chunk: ChunkType | null; }>({ state: 'INACTIVE', chunk: null }); + + const pathParts = path ? path.split('/') : []; const fetchChunks = () => { @@ -149,159 +151,173 @@ const DocumentChunks: React.FC = ({ .includes(searchTerm.toLowerCase()); }); - return ( -
- {showHeader && ( -
- - -
- source - - {documentName} - - - {pathParts.length > 0 && ( - <> - / - {pathParts.map((part, index) => ( - - - {part} - - {index < pathParts.length - 1 && ( - / - )} - - ))} - - )} -
-
- )} - -
-
-
- {totalChunks > 999999 - ? `${(totalChunks / 1000000).toFixed(2)}M` - : totalChunks > 999 - ? `${(totalChunks / 1000).toFixed(2)}K` - : totalChunks} {t('settings.documents.chunks')} -
-
-
- setSearchTerm(e.target.value)} - className="w-full h-full px-3 py-2 bg-transparent border-none outline-none font-normal text-[13.56px] leading-[100%] dark:text-[#E0E0E0]" - /> -
-
+ const renderPathNavigation = () => { + return ( +
-
- {loading ? ( -
- -
-) : ( -
- {filteredChunks.length === 0 ? ( -
- {t('settings.documents.noChunksAlt')} - {t('settings.documents.noChunks')} -
- ) : ( - filteredChunks.map((chunk, index) => ( -
-
-
-
- {chunk.metadata.token_count ? chunk.metadata.token_count.toLocaleString() : '-'} tokens -
- -
-
-

- {chunk.text} -

-
-
-
- )) + +
+ source + + {documentName} + + + {pathParts.length > 0 && ( + <> + / + {pathParts.map((part, index) => ( + + + {part} + + {index < pathParts.length - 1 && ( + / + )} + + ))} + )}
- )} +
+ ); + }; - {!loading && filteredChunks.length > 0 && ( - { - setPerPage(rows); - setPage(1); - }} - /> - )} + return ( +
+
+ {renderPathNavigation()} +
+
+ {renderFileSearch && ( + renderFileSearch() + )} - - {editModal.chunk && ( - - setEditModal((prev) => ({ ...prev, state })) - } - handleSubmit={(title, text) => { - handleUpdateChunk(title, text, editModal.chunk as ChunkType); - }} - originalText={editModal.chunk?.text ?? ''} - originalTitle={editModal.chunk?.metadata?.title ?? ''} - handleDelete={() => { - handleDeleteChunk(editModal.chunk as ChunkType); - }} - /> - )} -
- ); + {/* Right side: Chunks content */} +
+
+
+
+ {totalChunks > 999999 + ? `${(totalChunks / 1000000).toFixed(2)}M` + : totalChunks > 999 + ? `${(totalChunks / 1000).toFixed(2)}K` + : totalChunks} {t('settings.documents.chunks')} +
+
+
+ setSearchTerm(e.target.value)} + className="w-full h-full px-3 py-2 bg-transparent border-none outline-none font-normal text-[13.56px] leading-[100%] dark:text-[#E0E0E0]" + /> +
+
+ +
+ {loading ? ( +
+ +
+ ) : ( +
+ {filteredChunks.length === 0 ? ( +
+ {t('settings.documents.noChunksAlt')} + {t('settings.documents.noChunks')} +
+ ) : ( + filteredChunks.map((chunk, index) => ( +
+
+
+
+ {chunk.metadata.token_count ? chunk.metadata.token_count.toLocaleString() : '-'} tokens +
+ +
+
+

+ {chunk.text} +

+
+
+
+ )) + )} +
+ )} + + {!loading && filteredChunks.length > 0 && ( + { + setPerPage(rows); + setPage(1); + }} + /> + )} + + + {editModal.chunk && ( + + setEditModal((prev) => ({ ...prev, state })) + } + handleSubmit={(title, text) => { + handleUpdateChunk(title, text, editModal.chunk as ChunkType); + }} + originalText={editModal.chunk?.text ?? ''} + originalTitle={editModal.chunk?.metadata?.title ?? ''} + handleDelete={() => { + handleDeleteChunk(editModal.chunk as ChunkType); + }} + /> + )} +
+
+
+ ); }; -export default DocumentChunks; + export default DocumentChunks; diff --git a/frontend/src/components/FileTreeComponent.tsx b/frontend/src/components/FileTreeComponent.tsx index 64a8e4b1..8cdbb4f3 100644 --- a/frontend/src/components/FileTreeComponent.tsx +++ b/frontend/src/components/FileTreeComponent.tsx @@ -12,6 +12,7 @@ import EyeView from '../assets/eye-view.svg'; import OutlineSource from '../assets/outline-source.svg'; import Trash from '../assets/red-trash.svg'; import SearchIcon from '../assets/search.svg'; +import { useOutsideAlerter } from '../hooks'; interface FileNode { type?: string; @@ -58,6 +59,17 @@ const FileTreeComponent: React.FC = ({ } | null>(null); const [searchQuery, setSearchQuery] = useState(''); const [searchResults, setSearchResults] = useState([]); + const searchDropdownRef = useRef(null); + + useOutsideAlerter( + searchDropdownRef, + () => { + setSearchQuery(''); + setSearchResults([]); + }, + [], + false + ); const handleFileClick = (fileName: string) => { const fullPath = [...currentPath, fileName].join('/'); @@ -435,103 +447,115 @@ const FileTreeComponent: React.FC = ({ setSearchQuery(''); setSearchResults([]); }; + const renderFileSearch = () => { + return ( +
+
+ { + setSearchQuery(e.target.value); + if (directoryStructure) { + setSearchResults(searchFiles(e.target.value, directoryStructure)); + } + }} + placeholder={t('settings.documents.searchFiles')} + className={`w-full px-4 py-2 pl-10 border border-[#D1D9E0] dark:border-[#6A6A6A] ${ + searchQuery ? 'rounded-t-md rounded-b-none border-b-0' : 'rounded-md' + } bg-transparent dark:text-[#E0E0E0] focus:outline-none`} + /> + Search + + {searchQuery && ( +
+ {searchResults.length === 0 ? ( +
+ {t('settings.documents.noResults')} +
+ ) : ( + searchResults.map((result, index) => ( +
handleSearchSelect(result)} + title={result.path} + className={`flex items-center px-3 py-2 cursor-pointer hover:bg-[#ECEEEF] dark:hover:bg-[#27282D] ${ + index !== searchResults.length - 1 ? "border-b border-[#D1D9E0] dark:border-[#6A6A6A]" : "" + }`} + > + {result.isFile + + {result.path.split('/').pop() || result.path} + +
+ )) + )} +
+ )} +
+
+ ); + }; return ( <> -
{renderPathNavigation()}
{selectedFile ? (
- {/* Search Panel */} -
-
- { - setSearchQuery(e.target.value); - if (directoryStructure) { - setSearchResults(searchFiles(e.target.value, directoryStructure)); - } - }} - placeholder={t('settings.documents.searchFiles')} - className={`w-full px-4 py-2 pl-10 border border-[#D1D9E0] dark:border-[#6A6A6A] ${searchQuery ? 'rounded-t-md rounded-b-none border-b-0' : 'rounded-md' - } bg-transparent dark:text-[#E0E0E0] focus:outline-none`} - /> - - Search - - {searchQuery && ( -
- {searchResults.map((result, index) => { - const name = result.path.split('/').pop() || result.path; - - return ( -
handleSearchSelect(result)} - title={result.path} - className={`flex items-center px-3 py-2 cursor-pointer hover:bg-[#ECEEEF] dark:hover:bg-[#27282D] ${index !== searchResults.length - 1 ? "border-b border-[#D1D9E0] dark:border-[#6A6A6A]" : "" - }`} - > - {result.isFile - - {name} - -
- ); - })} - {searchResults.length === 0 && ( -
- {t('settings.documents.noResults')} -
- )} -
- )} -
-
setSelectedFile(null)} path={selectedFile.id} - showHeader={false} + renderFileSearch={renderFileSearch} />
) : ( -
-
- - - - - - - - - - - {renderFileTree(currentDirectory)} - -
- Name - - Tokens - - Size - - Actions -
+
+
+ {renderPathNavigation()} +
+ +
+ {/* Left side: Search dropdown */} + {renderFileSearch()} + + {/* Right side: File table */} +
+
+ + + + + + + + + + + {renderFileTree(currentDirectory)} + +
+ Name + + Tokens + + Size + + Actions +
+
+
)} diff --git a/frontend/src/settings/Documents.tsx b/frontend/src/settings/Documents.tsx index 9a8e4195..30f71f26 100644 --- a/frontend/src/settings/Documents.tsx +++ b/frontend/src/settings/Documents.tsx @@ -272,7 +272,6 @@ export default function Documents({ documentId={documentToView.id || ''} documentName={documentToView.name} handleGoBack={() => setDocumentToView(undefined)} - showHeader={true} /> )}