From 0eac1a883a324e125792cbad01c6b7a462c1a6cc Mon Sep 17 00:00:00 2001 From: yangdx Date: Wed, 30 Jul 2025 18:46:55 +0800 Subject: [PATCH] Feat: add file path sorting for document manager - Add file_path sorting support to all database backends (JSON, Redis, PostgreSQL, MongoDB) - Implement smart column header switching between "ID" and "File Name" based on display mode - Add automatic sort field switching when toggling between ID and file name display - Create composite indexes for workspace+file_path in PostgreSQL and MongoDB for better query performance - Update frontend to maintain sort state when switching display modes - Add internationalization support for "fileName" in English and Chinese locales This enhancement improves user experience by providing intuitive file-based sorting while maintaining performance through optimized database indexes. --- lightrag/api/routers/document_routes.py | 2 +- lightrag/kg/json_doc_status_impl.py | 2 +- lightrag/kg/mongo_impl.py | 3 +- lightrag/kg/postgres_impl.py | 7 ++++- lightrag/kg/redis_impl.py | 2 +- lightrag_webui/src/api/lightrag.ts | 2 +- .../src/features/DocumentManager.tsx | 31 ++++++++++++++++--- lightrag_webui/src/locales/en.json | 1 + lightrag_webui/src/locales/zh.json | 1 + 9 files changed, 40 insertions(+), 11 deletions(-) diff --git a/lightrag/api/routers/document_routes.py b/lightrag/api/routers/document_routes.py index 9dfaa710..4dc17dc3 100644 --- a/lightrag/api/routers/document_routes.py +++ b/lightrag/api/routers/document_routes.py @@ -510,7 +510,7 @@ class DocumentsRequest(BaseModel): page_size: int = Field( default=50, ge=10, le=200, description="Number of documents per page (10-200)" ) - sort_field: Literal["created_at", "updated_at", "id"] = Field( + sort_field: Literal["created_at", "updated_at", "id", "file_path"] = Field( default="updated_at", description="Field to sort by" ) sort_direction: Literal["asc", "desc"] = Field( diff --git a/lightrag/kg/json_doc_status_impl.py b/lightrag/kg/json_doc_status_impl.py index f183a358..b563bee6 100644 --- a/lightrag/kg/json_doc_status_impl.py +++ b/lightrag/kg/json_doc_status_impl.py @@ -201,7 +201,7 @@ class JsonDocStatusStorage(DocStatusStorage): elif page_size > 200: page_size = 200 - if sort_field not in ["created_at", "updated_at", "id"]: + if sort_field not in ["created_at", "updated_at", "id", "file_path"]: sort_field = "updated_at" if sort_direction.lower() not in ["asc", "desc"]: diff --git a/lightrag/kg/mongo_impl.py b/lightrag/kg/mongo_impl.py index 2cdd04ca..fd7935b9 100644 --- a/lightrag/kg/mongo_impl.py +++ b/lightrag/kg/mongo_impl.py @@ -503,6 +503,7 @@ class MongoDocStatusStorage(DocStatusStorage): {"name": "updated_at", "keys": [("updated_at", -1)]}, {"name": "created_at", "keys": [("created_at", -1)]}, {"name": "id", "keys": [("_id", 1)]}, + {"name": "file_path", "keys": [("file_path", 1)]}, ] # Check which indexes already exist @@ -553,7 +554,7 @@ class MongoDocStatusStorage(DocStatusStorage): elif page_size > 200: page_size = 200 - if sort_field not in ["created_at", "updated_at", "_id"]: + if sort_field not in ["created_at", "updated_at", "_id", "file_path"]: sort_field = "updated_at" if sort_direction.lower() not in ["asc", "desc"]: diff --git a/lightrag/kg/postgres_impl.py b/lightrag/kg/postgres_impl.py index a1cc19c9..fb2d114d 100644 --- a/lightrag/kg/postgres_impl.py +++ b/lightrag/kg/postgres_impl.py @@ -948,6 +948,11 @@ class PostgreSQLDB: "sql": "CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_lightrag_doc_status_workspace_id ON LIGHTRAG_DOC_STATUS (workspace, id)", "description": "Index for workspace + id sorting", }, + { + "name": "idx_lightrag_doc_status_workspace_file_path", + "sql": "CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_lightrag_doc_status_workspace_file_path ON LIGHTRAG_DOC_STATUS (workspace, file_path)", + "description": "Index for workspace + file_path sorting", + }, ] for index in indexes: @@ -2066,7 +2071,7 @@ class PGDocStatusStorage(DocStatusStorage): elif page_size > 200: page_size = 200 - if sort_field not in ["created_at", "updated_at", "id"]: + if sort_field not in ["created_at", "updated_at", "id", "file_path"]: sort_field = "updated_at" if sort_direction.lower() not in ["asc", "desc"]: diff --git a/lightrag/kg/redis_impl.py b/lightrag/kg/redis_impl.py index 2d9c4383..796d8410 100644 --- a/lightrag/kg/redis_impl.py +++ b/lightrag/kg/redis_impl.py @@ -947,7 +947,7 @@ class RedisDocStatusStorage(DocStatusStorage): elif page_size > 200: page_size = 200 - if sort_field not in ["created_at", "updated_at", "id"]: + if sort_field not in ["created_at", "updated_at", "id", "file_path"]: sort_field = "updated_at" if sort_direction.lower() not in ["asc", "desc"]: diff --git a/lightrag_webui/src/api/lightrag.ts b/lightrag_webui/src/api/lightrag.ts index 187db25e..b2bf1bf5 100644 --- a/lightrag_webui/src/api/lightrag.ts +++ b/lightrag_webui/src/api/lightrag.ts @@ -189,7 +189,7 @@ export type DocumentsRequest = { status_filter?: DocStatus | null page: number page_size: number - sort_field: 'created_at' | 'updated_at' | 'id' + sort_field: 'created_at' | 'updated_at' | 'id' | 'file_path' sort_direction: 'asc' | 'desc' } diff --git a/lightrag_webui/src/features/DocumentManager.tsx b/lightrag_webui/src/features/DocumentManager.tsx index 57bd7814..11d3b239 100644 --- a/lightrag_webui/src/features/DocumentManager.tsx +++ b/lightrag_webui/src/features/DocumentManager.tsx @@ -145,7 +145,7 @@ const pulseStyle = ` `; // Type definitions for sort field and direction -type SortField = 'created_at' | 'updated_at' | 'id'; +type SortField = 'created_at' | 'updated_at' | 'id' | 'file_path'; type SortDirection = 'asc' | 'desc'; export default function DocumentManager() { @@ -234,9 +234,16 @@ export default function DocumentManager() { // Handle sort column click const handleSort = (field: SortField) => { - const newDirection = (sortField === field && sortDirection === 'desc') ? 'asc' : 'desc'; + let actualField = field; - setSortField(field); + // When clicking the first column, determine the actual sort field based on showFileName + if (field === 'id') { + actualField = showFileName ? 'file_path' : 'id'; + } + + const newDirection = (sortField === actualField && sortDirection === 'desc') ? 'asc' : 'desc'; + + setSortField(actualField); setSortDirection(newDirection); // Reset page to 1 when sorting changes @@ -600,6 +607,17 @@ export default function DocumentManager() { }, [fetchDocuments]) + // Handle showFileName change - switch sort field if currently sorting by first column + useEffect(() => { + // Only switch if currently sorting by the first column (id or file_path) + if (sortField === 'id' || sortField === 'file_path') { + const newSortField = showFileName ? 'file_path' : 'id'; + if (sortField !== newSortField) { + setSortField(newSortField); + } + } + }, [showFileName, sortField]); + // Central effect to handle all data fetching useEffect(() => { if (currentTab === 'documents') { @@ -796,8 +814,11 @@ export default function DocumentManager() { className="cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-800 select-none" >
- {t('documentPanel.documentManager.columns.id')} - {sortField === 'id' && ( + {showFileName + ? t('documentPanel.documentManager.columns.fileName') + : t('documentPanel.documentManager.columns.id') + } + {((sortField === 'id' && !showFileName) || (sortField === 'file_path' && showFileName)) && ( {sortDirection === 'asc' ? : } diff --git a/lightrag_webui/src/locales/en.json b/lightrag_webui/src/locales/en.json index 48765d5f..0b0ba8e9 100644 --- a/lightrag_webui/src/locales/en.json +++ b/lightrag_webui/src/locales/en.json @@ -125,6 +125,7 @@ "emptyDescription": "There are no uploaded documents yet.", "columns": { "id": "ID", + "fileName": "File Name", "summary": "Summary", "status": "Status", "length": "Length", diff --git a/lightrag_webui/src/locales/zh.json b/lightrag_webui/src/locales/zh.json index 29b064f4..d695e949 100644 --- a/lightrag_webui/src/locales/zh.json +++ b/lightrag_webui/src/locales/zh.json @@ -125,6 +125,7 @@ "emptyDescription": "还没有上传任何文档", "columns": { "id": "ID", + "fileName": "文件名", "summary": "摘要", "status": "状态", "length": "长度",