mirror of
https://github.com/HKUDS/LightRAG.git
synced 2025-11-26 23:16:10 +00:00
fix(webui): preserve current page when pipeline status changes
- Add intelligent refresh function to handle boundary cases - Replace manual refresh with smart page preservation logic - Auto-redirect to last page when current page becomes invalid - Maintain user's browsing position during pipeline start/stop - Fix issue where document list would reset to first page after pipeline operations
This commit is contained in:
parent
8c6b5f4a3a
commit
ec1bf43667
@ -469,22 +469,42 @@ export default function DocumentManager() {
|
|||||||
};
|
};
|
||||||
}, [docs]);
|
}, [docs]);
|
||||||
|
|
||||||
// New paginated data fetching function
|
// Utility function to update component state
|
||||||
const fetchPaginatedDocuments = useCallback(async (
|
const updateComponentState = useCallback((response: any) => {
|
||||||
page: number,
|
setPagination(response.pagination);
|
||||||
pageSize: number,
|
setCurrentPageDocs(response.documents);
|
||||||
statusFilter: StatusFilter
|
setStatusCounts(response.status_counts);
|
||||||
|
|
||||||
|
// Update legacy docs state for backward compatibility
|
||||||
|
const legacyDocs: DocsStatusesResponse = {
|
||||||
|
statuses: {
|
||||||
|
processed: response.documents.filter((doc: DocStatusResponse) => doc.status === 'processed'),
|
||||||
|
processing: response.documents.filter((doc: DocStatusResponse) => doc.status === 'processing'),
|
||||||
|
pending: response.documents.filter((doc: DocStatusResponse) => doc.status === 'pending'),
|
||||||
|
failed: response.documents.filter((doc: DocStatusResponse) => doc.status === 'failed')
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
setDocs(response.pagination.total_count > 0 ? legacyDocs : null);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Intelligent refresh function: handles all boundary cases
|
||||||
|
const handleIntelligentRefresh = useCallback(async (
|
||||||
|
targetPage?: number, // Optional target page, defaults to current page
|
||||||
|
resetToFirst?: boolean // Whether to force reset to first page
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
if (!isMountedRef.current) return;
|
if (!isMountedRef.current) return;
|
||||||
|
|
||||||
setIsRefreshing(true);
|
setIsRefreshing(true);
|
||||||
|
|
||||||
// Prepare request parameters
|
// Determine target page
|
||||||
|
const pageToFetch = resetToFirst ? 1 : (targetPage || pagination.page);
|
||||||
|
|
||||||
const request: DocumentsRequest = {
|
const request: DocumentsRequest = {
|
||||||
status_filter: statusFilter === 'all' ? null : statusFilter,
|
status_filter: statusFilter === 'all' ? null : statusFilter,
|
||||||
page,
|
page: pageToFetch,
|
||||||
page_size: pageSize,
|
page_size: pagination.page_size,
|
||||||
sort_field: sortField,
|
sort_field: sortField,
|
||||||
sort_direction: sortDirection
|
sort_direction: sortDirection
|
||||||
};
|
};
|
||||||
@ -493,27 +513,35 @@ export default function DocumentManager() {
|
|||||||
|
|
||||||
if (!isMountedRef.current) return;
|
if (!isMountedRef.current) return;
|
||||||
|
|
||||||
// Update pagination state
|
// Boundary case handling: if target page has no data but total count > 0
|
||||||
setPagination(response.pagination);
|
if (response.documents.length === 0 && response.pagination.total_count > 0) {
|
||||||
setCurrentPageDocs(response.documents);
|
// Calculate last page
|
||||||
setStatusCounts(response.status_counts);
|
const lastPage = Math.max(1, response.pagination.total_pages);
|
||||||
|
|
||||||
// Update legacy docs state for backward compatibility
|
if (pageToFetch !== lastPage) {
|
||||||
const legacyDocs: DocsStatusesResponse = {
|
// Re-request last page
|
||||||
statuses: {
|
const lastPageRequest: DocumentsRequest = {
|
||||||
processed: response.documents.filter(doc => doc.status === 'processed'),
|
...request,
|
||||||
processing: response.documents.filter(doc => doc.status === 'processing'),
|
page: lastPage
|
||||||
pending: response.documents.filter(doc => doc.status === 'pending'),
|
};
|
||||||
failed: response.documents.filter(doc => doc.status === 'failed')
|
|
||||||
|
const lastPageResponse = await getDocumentsPaginated(lastPageRequest);
|
||||||
|
|
||||||
|
if (!isMountedRef.current) return;
|
||||||
|
|
||||||
|
// Update page state to last page
|
||||||
|
setPageByStatus(prev => ({ ...prev, [statusFilter]: lastPage }));
|
||||||
|
updateComponentState(lastPageResponse);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
if (response.pagination.total_count > 0) {
|
|
||||||
setDocs(legacyDocs);
|
|
||||||
} else {
|
|
||||||
setDocs(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Normal case: update state
|
||||||
|
if (pageToFetch !== pagination.page) {
|
||||||
|
setPageByStatus(prev => ({ ...prev, [statusFilter]: pageToFetch }));
|
||||||
|
}
|
||||||
|
updateComponentState(response);
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (isMountedRef.current) {
|
if (isMountedRef.current) {
|
||||||
toast.error(t('documentPanel.documentManager.errors.loadFailed', { error: errorMessage(err) }));
|
toast.error(t('documentPanel.documentManager.errors.loadFailed', { error: errorMessage(err) }));
|
||||||
@ -523,7 +551,20 @@ export default function DocumentManager() {
|
|||||||
setIsRefreshing(false);
|
setIsRefreshing(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [sortField, sortDirection, t]);
|
}, [statusFilter, pagination.page, pagination.page_size, sortField, sortDirection, t, updateComponentState]);
|
||||||
|
|
||||||
|
// New paginated data fetching function
|
||||||
|
const fetchPaginatedDocuments = useCallback(async (
|
||||||
|
page: number,
|
||||||
|
pageSize: number,
|
||||||
|
_statusFilter: StatusFilter // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||||
|
) => {
|
||||||
|
// Update pagination state
|
||||||
|
setPagination(prev => ({ ...prev, page, page_size: pageSize }));
|
||||||
|
|
||||||
|
// Use intelligent refresh
|
||||||
|
await handleIntelligentRefresh(page);
|
||||||
|
}, [handleIntelligentRefresh]);
|
||||||
|
|
||||||
// Legacy fetchDocuments function for backward compatibility
|
// Legacy fetchDocuments function for backward compatibility
|
||||||
const fetchDocuments = useCallback(async () => {
|
const fetchDocuments = useCallback(async () => {
|
||||||
@ -678,9 +719,10 @@ export default function DocumentManager() {
|
|||||||
if (prevPipelineBusyRef.current !== undefined && prevPipelineBusyRef.current !== pipelineBusy) {
|
if (prevPipelineBusyRef.current !== undefined && prevPipelineBusyRef.current !== pipelineBusy) {
|
||||||
// pipelineBusy state has changed, trigger immediate refresh
|
// pipelineBusy state has changed, trigger immediate refresh
|
||||||
if (currentTab === 'documents' && health && isMountedRef.current) {
|
if (currentTab === 'documents' && health && isMountedRef.current) {
|
||||||
handleManualRefresh();
|
// Use intelligent refresh to preserve current page
|
||||||
|
handleIntelligentRefresh();
|
||||||
|
|
||||||
// Reset polling timer after manual refresh
|
// Reset polling timer after intelligent refresh
|
||||||
const hasActiveDocuments = (statusCounts.processing || 0) > 0 || (statusCounts.pending || 0) > 0;
|
const hasActiveDocuments = (statusCounts.processing || 0) > 0 || (statusCounts.pending || 0) > 0;
|
||||||
const pollingInterval = hasActiveDocuments ? 5000 : 30000;
|
const pollingInterval = hasActiveDocuments ? 5000 : 30000;
|
||||||
startPollingInterval(pollingInterval);
|
startPollingInterval(pollingInterval);
|
||||||
@ -688,7 +730,7 @@ export default function DocumentManager() {
|
|||||||
}
|
}
|
||||||
// Update the previous state
|
// Update the previous state
|
||||||
prevPipelineBusyRef.current = pipelineBusy;
|
prevPipelineBusyRef.current = pipelineBusy;
|
||||||
}, [pipelineBusy, currentTab, health, handleManualRefresh, statusCounts.processing, statusCounts.pending, startPollingInterval]);
|
}, [pipelineBusy, currentTab, health, handleIntelligentRefresh, statusCounts.processing, statusCounts.pending, startPollingInterval]);
|
||||||
|
|
||||||
// Set up intelligent polling with dynamic interval based on document status
|
// Set up intelligent polling with dynamic interval based on document status
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user