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.
This commit is contained in:
parent
e60c26ea77
commit
0eac1a883a
9 changed files with 40 additions and 11 deletions
|
|
@ -510,7 +510,7 @@ class DocumentsRequest(BaseModel):
|
||||||
page_size: int = Field(
|
page_size: int = Field(
|
||||||
default=50, ge=10, le=200, description="Number of documents per page (10-200)"
|
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"
|
default="updated_at", description="Field to sort by"
|
||||||
)
|
)
|
||||||
sort_direction: Literal["asc", "desc"] = Field(
|
sort_direction: Literal["asc", "desc"] = Field(
|
||||||
|
|
|
||||||
|
|
@ -201,7 +201,7 @@ class JsonDocStatusStorage(DocStatusStorage):
|
||||||
elif page_size > 200:
|
elif page_size > 200:
|
||||||
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"
|
sort_field = "updated_at"
|
||||||
|
|
||||||
if sort_direction.lower() not in ["asc", "desc"]:
|
if sort_direction.lower() not in ["asc", "desc"]:
|
||||||
|
|
|
||||||
|
|
@ -503,6 +503,7 @@ class MongoDocStatusStorage(DocStatusStorage):
|
||||||
{"name": "updated_at", "keys": [("updated_at", -1)]},
|
{"name": "updated_at", "keys": [("updated_at", -1)]},
|
||||||
{"name": "created_at", "keys": [("created_at", -1)]},
|
{"name": "created_at", "keys": [("created_at", -1)]},
|
||||||
{"name": "id", "keys": [("_id", 1)]},
|
{"name": "id", "keys": [("_id", 1)]},
|
||||||
|
{"name": "file_path", "keys": [("file_path", 1)]},
|
||||||
]
|
]
|
||||||
|
|
||||||
# Check which indexes already exist
|
# Check which indexes already exist
|
||||||
|
|
@ -553,7 +554,7 @@ class MongoDocStatusStorage(DocStatusStorage):
|
||||||
elif page_size > 200:
|
elif page_size > 200:
|
||||||
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"
|
sort_field = "updated_at"
|
||||||
|
|
||||||
if sort_direction.lower() not in ["asc", "desc"]:
|
if sort_direction.lower() not in ["asc", "desc"]:
|
||||||
|
|
|
||||||
|
|
@ -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)",
|
"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",
|
"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:
|
for index in indexes:
|
||||||
|
|
@ -2066,7 +2071,7 @@ class PGDocStatusStorage(DocStatusStorage):
|
||||||
elif page_size > 200:
|
elif page_size > 200:
|
||||||
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"
|
sort_field = "updated_at"
|
||||||
|
|
||||||
if sort_direction.lower() not in ["asc", "desc"]:
|
if sort_direction.lower() not in ["asc", "desc"]:
|
||||||
|
|
|
||||||
|
|
@ -947,7 +947,7 @@ class RedisDocStatusStorage(DocStatusStorage):
|
||||||
elif page_size > 200:
|
elif page_size > 200:
|
||||||
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"
|
sort_field = "updated_at"
|
||||||
|
|
||||||
if sort_direction.lower() not in ["asc", "desc"]:
|
if sort_direction.lower() not in ["asc", "desc"]:
|
||||||
|
|
|
||||||
|
|
@ -189,7 +189,7 @@ export type DocumentsRequest = {
|
||||||
status_filter?: DocStatus | null
|
status_filter?: DocStatus | null
|
||||||
page: number
|
page: number
|
||||||
page_size: number
|
page_size: number
|
||||||
sort_field: 'created_at' | 'updated_at' | 'id'
|
sort_field: 'created_at' | 'updated_at' | 'id' | 'file_path'
|
||||||
sort_direction: 'asc' | 'desc'
|
sort_direction: 'asc' | 'desc'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ const pulseStyle = `
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// Type definitions for sort field and direction
|
// 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';
|
type SortDirection = 'asc' | 'desc';
|
||||||
|
|
||||||
export default function DocumentManager() {
|
export default function DocumentManager() {
|
||||||
|
|
@ -234,9 +234,16 @@ export default function DocumentManager() {
|
||||||
|
|
||||||
// Handle sort column click
|
// Handle sort column click
|
||||||
const handleSort = (field: SortField) => {
|
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);
|
setSortDirection(newDirection);
|
||||||
|
|
||||||
// Reset page to 1 when sorting changes
|
// Reset page to 1 when sorting changes
|
||||||
|
|
@ -600,6 +607,17 @@ export default function DocumentManager() {
|
||||||
}, [fetchDocuments])
|
}, [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
|
// Central effect to handle all data fetching
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (currentTab === 'documents') {
|
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"
|
className="cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-800 select-none"
|
||||||
>
|
>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
{t('documentPanel.documentManager.columns.id')}
|
{showFileName
|
||||||
{sortField === 'id' && (
|
? t('documentPanel.documentManager.columns.fileName')
|
||||||
|
: t('documentPanel.documentManager.columns.id')
|
||||||
|
}
|
||||||
|
{((sortField === 'id' && !showFileName) || (sortField === 'file_path' && showFileName)) && (
|
||||||
<span className="ml-1">
|
<span className="ml-1">
|
||||||
{sortDirection === 'asc' ? <ArrowUpIcon size={14} /> : <ArrowDownIcon size={14} />}
|
{sortDirection === 'asc' ? <ArrowUpIcon size={14} /> : <ArrowDownIcon size={14} />}
|
||||||
</span>
|
</span>
|
||||||
|
|
|
||||||
|
|
@ -125,6 +125,7 @@
|
||||||
"emptyDescription": "There are no uploaded documents yet.",
|
"emptyDescription": "There are no uploaded documents yet.",
|
||||||
"columns": {
|
"columns": {
|
||||||
"id": "ID",
|
"id": "ID",
|
||||||
|
"fileName": "File Name",
|
||||||
"summary": "Summary",
|
"summary": "Summary",
|
||||||
"status": "Status",
|
"status": "Status",
|
||||||
"length": "Length",
|
"length": "Length",
|
||||||
|
|
|
||||||
|
|
@ -125,6 +125,7 @@
|
||||||
"emptyDescription": "还没有上传任何文档",
|
"emptyDescription": "还没有上传任何文档",
|
||||||
"columns": {
|
"columns": {
|
||||||
"id": "ID",
|
"id": "ID",
|
||||||
|
"fileName": "文件名",
|
||||||
"summary": "摘要",
|
"summary": "摘要",
|
||||||
"status": "状态",
|
"status": "状态",
|
||||||
"length": "长度",
|
"length": "长度",
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue