'use client' import type { FC } from 'react' import type { ProcessStatus } from '../segment-add' import type { SegmentListContextValue } from './segment-list-context' import { useCallback, useMemo, useState } from 'react' import Divider from '@/app/components/base/divider' import Pagination from '@/app/components/base/pagination' import { useChunkListAllKey, useChunkListDisabledKey, useChunkListEnabledKey, } from '@/service/knowledge/use-segment' import { useInvalid } from '@/service/use-base' import { useDocumentContext } from '../context' import BatchAction from './common/batch-action' import { DrawerGroup, FullDocModeContent, GeneralModeContent, MenuBar } from './components' import { useChildSegmentData, useModalState, useSearchFilter, useSegmentListData, useSegmentSelection, } from './hooks' import { SegmentListContext, useSegmentListContext, } from './segment-list-context' const DEFAULT_LIMIT = 10 type ICompletedProps = { embeddingAvailable: boolean showNewSegmentModal: boolean onNewSegmentModalChange: (state: boolean) => void importStatus: ProcessStatus | string | undefined archived?: boolean } /** * Embedding done, show list of all segments * Support search and filter */ const Completed: FC = ({ embeddingAvailable, showNewSegmentModal, onNewSegmentModalChange, importStatus, archived, }) => { const docForm = useDocumentContext(s => s.docForm) // Pagination state const [currentPage, setCurrentPage] = useState(1) const [limit, setLimit] = useState(DEFAULT_LIMIT) // Search and filter state const searchFilter = useSearchFilter({ onPageChange: setCurrentPage, }) // Modal state const modalState = useModalState({ onNewSegmentModalChange, }) // Selection state (need segments first, so we use a placeholder initially) const [segmentsForSelection, setSegmentsForSelection] = useState([]) // Invalidation hooks for child segment data const invalidChunkListAll = useInvalid(useChunkListAllKey) const invalidChunkListEnabled = useInvalid(useChunkListEnabledKey) const invalidChunkListDisabled = useInvalid(useChunkListDisabledKey) const refreshChunkListDataWithDetailChanged = useCallback(() => { const refreshMap: Record void> = { all: () => { invalidChunkListDisabled() invalidChunkListEnabled() }, true: () => { invalidChunkListAll() invalidChunkListDisabled() }, false: () => { invalidChunkListAll() invalidChunkListEnabled() }, } refreshMap[String(searchFilter.selectedStatus)]?.() }, [searchFilter.selectedStatus, invalidChunkListDisabled, invalidChunkListEnabled, invalidChunkListAll]) // Segment list data const segmentListDataHook = useSegmentListData({ searchValue: searchFilter.searchValue, selectedStatus: searchFilter.selectedStatus, selectedSegmentIds: segmentsForSelection, importStatus, currentPage, limit, onCloseSegmentDetail: modalState.onCloseSegmentDetail, clearSelection: () => setSegmentsForSelection([]), }) // Selection state (with actual segments) const selectionState = useSegmentSelection(segmentListDataHook.segments) // Sync selection state for segment list data hook useMemo(() => { setSegmentsForSelection(selectionState.selectedSegmentIds) }, [selectionState.selectedSegmentIds]) // Child segment data const childSegmentDataHook = useChildSegmentData({ searchValue: searchFilter.searchValue, currentPage, limit, segments: segmentListDataHook.segments, currChunkId: modalState.currChunkId, isFullDocMode: segmentListDataHook.isFullDocMode, onCloseChildSegmentDetail: modalState.onCloseChildSegmentDetail, refreshChunkListDataWithDetailChanged, updateSegmentInCache: segmentListDataHook.updateSegmentInCache, }) // Compute total for pagination const paginationTotal = useMemo(() => { if (segmentListDataHook.isFullDocMode) return childSegmentDataHook.childChunkListData?.total || 0 return segmentListDataHook.segmentListData?.total || 0 }, [segmentListDataHook.isFullDocMode, childSegmentDataHook.childChunkListData, segmentListDataHook.segmentListData]) // Handle page change const handlePageChange = useCallback((page: number) => { setCurrentPage(page + 1) }, []) // Context value const contextValue = useMemo(() => ({ isCollapsed: modalState.isCollapsed, fullScreen: modalState.fullScreen, toggleFullScreen: modalState.toggleFullScreen, currSegment: modalState.currSegment, currChildChunk: modalState.currChildChunk, }), [ modalState.isCollapsed, modalState.fullScreen, modalState.toggleFullScreen, modalState.currSegment, modalState.currChildChunk, ]) return ( {/* Menu Bar */} {!segmentListDataHook.isFullDocMode && ( )} {/* Segment list */} {segmentListDataHook.isFullDocMode ? ( ) : ( )} {/* Pagination */} {/* Drawer Group - only render when docForm is available */} {docForm && ( )} {/* Batch Action Buttons */} {selectionState.selectedSegmentIds.length > 0 && ( segmentListDataHook.onChangeSwitch(true, '')} onBatchDisable={() => segmentListDataHook.onChangeSwitch(false, '')} onBatchDelete={() => segmentListDataHook.onDelete('')} onCancel={selectionState.onCancelBatchOperation} /> )} ) } export { useSegmentListContext } export type { SegmentListContextValue } export default Completed