yangdx commited on
Commit
7540325
·
1 Parent(s): 73acfd2

feat: Add file name display in WebUI

Browse files

Backend:
- Add file_path field to DocStatusResponse
- Update document status response creation

Frontend:
- Remove metadata column
- Improve filename display with truncation and tooltips
- Add show/hide filename toggle with proper styling
- Update translations for all supported languages"

lightrag/api/routers/document_routes.py CHANGED
@@ -91,6 +91,7 @@ class DocStatusResponse(BaseModel):
91
  chunks_count: Optional[int] = None
92
  error: Optional[str] = None
93
  metadata: Optional[dict[str, Any]] = None
 
94
 
95
 
96
  class DocsStatusesResponse(BaseModel):
@@ -890,6 +891,7 @@ def create_document_routes(
890
  chunks_count=doc_status.chunks_count,
891
  error=doc_status.error,
892
  metadata=doc_status.metadata,
 
893
  )
894
  )
895
  return response
 
91
  chunks_count: Optional[int] = None
92
  error: Optional[str] = None
93
  metadata: Optional[dict[str, Any]] = None
94
+ file_path: str
95
 
96
 
97
  class DocsStatusesResponse(BaseModel):
 
891
  chunks_count=doc_status.chunks_count,
892
  error=doc_status.error,
893
  metadata=doc_status.metadata,
894
+ file_path=doc_status.file_path,
895
  )
896
  )
897
  return response
lightrag_webui/src/api/lightrag.ts CHANGED
@@ -124,6 +124,7 @@ export type DocStatusResponse = {
124
  chunks_count?: number
125
  error?: string
126
  metadata?: Record<string, any>
 
127
  }
128
 
129
  export type DocsStatusesResponse = {
 
124
  chunks_count?: number
125
  error?: string
126
  metadata?: Record<string, any>
127
+ file_path: string
128
  }
129
 
130
  export type DocsStatusesResponse = {
lightrag_webui/src/features/DocumentManager.tsx CHANGED
@@ -12,7 +12,6 @@ import {
12
  } from '@/components/ui/Table'
13
  import { Card, CardHeader, CardTitle, CardContent, CardDescription } from '@/components/ui/Card'
14
  import EmptyCard from '@/components/ui/EmptyCard'
15
- import Text from '@/components/ui/Text'
16
  import UploadDocumentsDialog from '@/components/documents/UploadDocumentsDialog'
17
  import ClearDocumentsDialog from '@/components/documents/ClearDocumentsDialog'
18
 
@@ -22,12 +21,36 @@ import { toast } from 'sonner'
22
  import { useBackendState } from '@/stores/state'
23
 
24
  import { RefreshCwIcon } from 'lucide-react'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
  export default function DocumentManager() {
27
  const { t } = useTranslation()
28
  const health = useBackendState.use.health()
29
  const [docs, setDocs] = useState<DocsStatusesResponse | null>(null)
30
  const currentTab = useSettingsStore.use.currentTab()
 
 
31
 
32
  const fetchDocuments = useCallback(async () => {
33
  try {
@@ -107,7 +130,23 @@ export default function DocumentManager() {
107
 
108
  <Card>
109
  <CardHeader>
110
- <CardTitle>{t('documentPanel.documentManager.uploadedTitle')}</CardTitle>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  <CardDescription>{t('documentPanel.documentManager.uploadedDescription')}</CardDescription>
112
  </CardHeader>
113
 
@@ -135,13 +174,39 @@ export default function DocumentManager() {
135
  {Object.entries(docs.statuses).map(([status, documents]) =>
136
  documents.map((doc) => (
137
  <TableRow key={doc.id}>
138
- <TableCell className="truncate font-mono">{doc.id}</TableCell>
139
- <TableCell className="max-w-xs min-w-24 truncate">
140
- <Text
141
- text={doc.content_summary}
142
- tooltip={doc.content_summary}
143
- tooltipClassName="max-w-none overflow-visible block"
144
- />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
  </TableCell>
146
  <TableCell>
147
  {status === 'processed' && (
 
12
  } from '@/components/ui/Table'
13
  import { Card, CardHeader, CardTitle, CardContent, CardDescription } from '@/components/ui/Card'
14
  import EmptyCard from '@/components/ui/EmptyCard'
 
15
  import UploadDocumentsDialog from '@/components/documents/UploadDocumentsDialog'
16
  import ClearDocumentsDialog from '@/components/documents/ClearDocumentsDialog'
17
 
 
21
  import { useBackendState } from '@/stores/state'
22
 
23
  import { RefreshCwIcon } from 'lucide-react'
24
+ import { DocStatusResponse } from '@/api/lightrag'
25
+
26
+ const getDisplayFileName = (doc: DocStatusResponse, maxLength: number = 20): string => {
27
+ // Check if file_path exists and is a non-empty string
28
+ if (!doc.file_path || typeof doc.file_path !== 'string' || doc.file_path.trim() === '') {
29
+ return doc.id;
30
+ }
31
+
32
+ // Try to extract filename from path
33
+ const parts = doc.file_path.split('/');
34
+ const fileName = parts[parts.length - 1];
35
+
36
+ // Ensure extracted filename is valid
37
+ if (!fileName || fileName.trim() === '') {
38
+ return doc.id;
39
+ }
40
+
41
+ // If filename is longer than maxLength, truncate it and add ellipsis
42
+ return fileName.length > maxLength
43
+ ? fileName.slice(0, maxLength) + '...'
44
+ : fileName;
45
+ };
46
 
47
  export default function DocumentManager() {
48
  const { t } = useTranslation()
49
  const health = useBackendState.use.health()
50
  const [docs, setDocs] = useState<DocsStatusesResponse | null>(null)
51
  const currentTab = useSettingsStore.use.currentTab()
52
+ const showFileName = useSettingsStore.use.showFileName()
53
+ const setShowFileName = useSettingsStore.use.setShowFileName()
54
 
55
  const fetchDocuments = useCallback(async () => {
56
  try {
 
130
 
131
  <Card>
132
  <CardHeader>
133
+ <div className="flex justify-between items-center">
134
+ <CardTitle>{t('documentPanel.documentManager.uploadedTitle')}</CardTitle>
135
+ <div className="flex items-center gap-2">
136
+ <span className="text-sm text-gray-500">{t('documentPanel.documentManager.fileNameLabel')}</span>
137
+ <Button
138
+ variant="outline"
139
+ size="sm"
140
+ onClick={() => setShowFileName(!showFileName)}
141
+ className="border-gray-200 dark:border-gray-700 hover:bg-gray-100 dark:hover:bg-gray-800"
142
+ >
143
+ {showFileName
144
+ ? t('documentPanel.documentManager.hideButton')
145
+ : t('documentPanel.documentManager.showButton')
146
+ }
147
+ </Button>
148
+ </div>
149
+ </div>
150
  <CardDescription>{t('documentPanel.documentManager.uploadedDescription')}</CardDescription>
151
  </CardHeader>
152
 
 
174
  {Object.entries(docs.statuses).map(([status, documents]) =>
175
  documents.map((doc) => (
176
  <TableRow key={doc.id}>
177
+ <TableCell className="truncate font-mono overflow-visible">
178
+ {showFileName ? (
179
+ <>
180
+ <div className="group relative overflow-visible">
181
+ <div className="truncate">
182
+ {getDisplayFileName(doc, 35)}
183
+ </div>
184
+ <div className="invisible group-hover:visible fixed z-[9999] mt-1 max-w-[800px] whitespace-normal break-all rounded-md bg-black/95 px-3 py-2 text-sm text-white shadow-lg dark:bg-white/95 dark:text-black">
185
+ {doc.file_path}
186
+ </div>
187
+ </div>
188
+ <div className="text-xs text-gray-500">{doc.id}</div>
189
+ </>
190
+ ) : (
191
+ <div className="group relative overflow-visible">
192
+ <div className="truncate">
193
+ {doc.id}
194
+ </div>
195
+ <div className="invisible group-hover:visible fixed z-[9999] mt-1 max-w-[800px] whitespace-normal break-all rounded-md bg-black/95 px-3 py-2 text-sm text-white shadow-lg dark:bg-white/95 dark:text-black">
196
+ {doc.file_path}
197
+ </div>
198
+ </div>
199
+ )}
200
+ </TableCell>
201
+ <TableCell className="max-w-xs min-w-24 truncate overflow-visible">
202
+ <div className="group relative overflow-visible">
203
+ <div className="truncate">
204
+ {doc.content_summary}
205
+ </div>
206
+ <div className="invisible group-hover:visible fixed z-[9999] mt-1 max-w-[800px] whitespace-normal break-all rounded-md bg-black/95 px-3 py-2 text-sm text-white shadow-lg dark:bg-white/95 dark:text-black">
207
+ {doc.content_summary}
208
+ </div>
209
+ </div>
210
  </TableCell>
211
  <TableCell>
212
  {status === 'processed' && (
lightrag_webui/src/locales/ar.json CHANGED
@@ -81,9 +81,14 @@
81
  },
82
  "errors": {
83
  "loadFailed": "فشل تحميل المستندات\n{{error}}",
84
- "scanFailed": "فشل المسح الضوئي للمستندات\n{{error}}",
85
- "scanProgressFailed": "فشل الحصول على تقدم المسح الضوئي\n{{error}}"
86
- }
 
 
 
 
 
87
  }
88
  },
89
  "graphPanel": {
 
81
  },
82
  "errors": {
83
  "loadFailed": "فشل تحميل المستندات\n{{error}}",
84
+ "scanFailed": "فشل مسح المستندات\n{{error}}",
85
+ "scanProgressFailed": "فشل الحصول على تقدم المسح\n{{error}}"
86
+ },
87
+ "fileNameLabel": "اسم الملف",
88
+ "showButton": "عرض",
89
+ "hideButton": "إخفاء",
90
+ "showFileNameTooltip": "عرض اسم الملف",
91
+ "hideFileNameTooltip": "إخفاء اسم الملف"
92
  }
93
  },
94
  "graphPanel": {
lightrag_webui/src/locales/en.json CHANGED
@@ -83,7 +83,12 @@
83
  "loadFailed": "Failed to load documents\n{{error}}",
84
  "scanFailed": "Failed to scan documents\n{{error}}",
85
  "scanProgressFailed": "Failed to get scan progress\n{{error}}"
86
- }
 
 
 
 
 
87
  }
88
  },
89
  "graphPanel": {
 
83
  "loadFailed": "Failed to load documents\n{{error}}",
84
  "scanFailed": "Failed to scan documents\n{{error}}",
85
  "scanProgressFailed": "Failed to get scan progress\n{{error}}"
86
+ },
87
+ "fileNameLabel": "File Name",
88
+ "showButton": "Show",
89
+ "hideButton": "Hide",
90
+ "showFileNameTooltip": "Show file name",
91
+ "hideFileNameTooltip": "Hide file name"
92
  }
93
  },
94
  "graphPanel": {
lightrag_webui/src/locales/zh.json CHANGED
@@ -83,7 +83,12 @@
83
  "loadFailed": "加载文档失败\n{{error}}",
84
  "scanFailed": "扫描文档失败\n{{error}}",
85
  "scanProgressFailed": "获取扫描进度失败\n{{error}}"
86
- }
 
 
 
 
 
87
  }
88
  },
89
  "graphPanel": {
 
83
  "loadFailed": "加载文档失败\n{{error}}",
84
  "scanFailed": "扫描文档失败\n{{error}}",
85
  "scanProgressFailed": "获取扫描进度失败\n{{error}}"
86
+ },
87
+ "fileNameLabel": "文件名",
88
+ "showButton": "显示",
89
+ "hideButton": "隐藏",
90
+ "showFileNameTooltip": "显示文件名",
91
+ "hideFileNameTooltip": "隐藏文件名"
92
  }
93
  },
94
  "graphPanel": {
lightrag_webui/src/stores/settings.ts CHANGED
@@ -9,6 +9,10 @@ type Language = 'en' | 'zh' | 'fr' | 'ar'
9
  type Tab = 'documents' | 'knowledge-graph' | 'retrieval' | 'api'
10
 
11
  interface SettingsState {
 
 
 
 
12
  // Graph viewer settings
13
  showPropertyPanel: boolean
14
  showNodeSearchBar: boolean
@@ -83,6 +87,7 @@ const useSettingsStoreBase = create<SettingsState>()(
83
  apiKey: null,
84
 
85
  currentTab: 'documents',
 
86
 
87
  retrievalHistory: [],
88
 
@@ -138,12 +143,14 @@ const useSettingsStoreBase = create<SettingsState>()(
138
  updateQuerySettings: (settings: Partial<QueryRequest>) =>
139
  set((state) => ({
140
  querySettings: { ...state.querySettings, ...settings }
141
- }))
 
 
142
  }),
143
  {
144
  name: 'settings-storage',
145
  storage: createJSONStorage(() => localStorage),
146
- version: 8,
147
  migrate: (state: any, version: number) => {
148
  if (version < 2) {
149
  state.showEdgeLabel = false
@@ -186,6 +193,9 @@ const useSettingsStoreBase = create<SettingsState>()(
186
  state.graphMinDegree = 0
187
  state.language = 'en'
188
  }
 
 
 
189
  return state
190
  }
191
  }
 
9
  type Tab = 'documents' | 'knowledge-graph' | 'retrieval' | 'api'
10
 
11
  interface SettingsState {
12
+ // Document manager settings
13
+ showFileName: boolean
14
+ setShowFileName: (show: boolean) => void
15
+
16
  // Graph viewer settings
17
  showPropertyPanel: boolean
18
  showNodeSearchBar: boolean
 
87
  apiKey: null,
88
 
89
  currentTab: 'documents',
90
+ showFileName: false,
91
 
92
  retrievalHistory: [],
93
 
 
143
  updateQuerySettings: (settings: Partial<QueryRequest>) =>
144
  set((state) => ({
145
  querySettings: { ...state.querySettings, ...settings }
146
+ })),
147
+
148
+ setShowFileName: (show: boolean) => set({ showFileName: show })
149
  }),
150
  {
151
  name: 'settings-storage',
152
  storage: createJSONStorage(() => localStorage),
153
+ version: 9,
154
  migrate: (state: any, version: number) => {
155
  if (version < 2) {
156
  state.showEdgeLabel = false
 
193
  state.graphMinDegree = 0
194
  state.language = 'en'
195
  }
196
+ if (version < 9) {
197
+ state.showFileName = false
198
+ }
199
  return state
200
  }
201
  }