diff --git a/web/app/components/datasets/documents/index.tsx b/web/app/components/datasets/documents/index.tsx index 1f9f36e7b..68b39b89e 100644 --- a/web/app/components/datasets/documents/index.tsx +++ b/web/app/components/datasets/documents/index.tsx @@ -24,6 +24,7 @@ import IndexFailed from '@/app/components/datasets/common/document-status-with-a import { useProviderContext } from '@/context/provider-context' import cn from '@/utils/classnames' import { useDocumentList, useInvalidDocumentDetailKey, useInvalidDocumentList } from '@/service/knowledge/use-document' +import { useIndexStatus } from './list' import { useInvalid } from '@/service/use-base' import { useChildSegmentListKey, useSegmentListKey } from '@/service/knowledge/use-segment' import useDocumentListQueryState from './hooks/use-document-list-query-state' @@ -32,6 +33,9 @@ import DatasetMetadataDrawer from '../metadata/metadata-dataset/dataset-metadata import StatusWithAction from '../common/document-status-with-action/status-with-action' import { useDocLink } from '@/context/i18n' import { useFetchDefaultProcessRule } from '@/service/knowledge/use-create-dataset' +import { SimpleSelect } from '../../base/select' +import StatusItem from './detail/completed/status-item' +import type { Item } from '@/app/components/base/select' const FolderPlusIcon = ({ className }: React.SVGProps) => { return @@ -91,6 +95,8 @@ const Documents: FC = ({ datasetId }) => { const isFreePlan = plan.type === 'sandbox' const [inputValue, setInputValue] = useState('') // the input value const [searchValue, setSearchValue] = useState('') + const [statusFilter, setStatusFilter] = useState({ value: 'all', name: 'All Status' }) + const DOC_INDEX_STATUS_MAP = useIndexStatus() // Use the new hook for URL state management const { query, updateQuery } = useDocumentListQueryState() @@ -107,6 +113,18 @@ const Documents: FC = ({ datasetId }) => { const embeddingAvailable = !!dataset?.embedding_available const debouncedSearchValue = useDebounce(searchValue, { wait: 500 }) + const statusFilterItems: Item[] = useMemo(() => [ + { value: 'all', name: 'All Status' }, + { value: 'queuing', name: DOC_INDEX_STATUS_MAP.queuing.text }, + { value: 'indexing', name: DOC_INDEX_STATUS_MAP.indexing.text }, + { value: 'paused', name: DOC_INDEX_STATUS_MAP.paused.text }, + { value: 'error', name: DOC_INDEX_STATUS_MAP.error.text }, + { value: 'available', name: DOC_INDEX_STATUS_MAP.available.text }, + { value: 'enabled', name: DOC_INDEX_STATUS_MAP.enabled.text }, + { value: 'disabled', name: DOC_INDEX_STATUS_MAP.disabled.text }, + { value: 'archived', name: DOC_INDEX_STATUS_MAP.archived.text }, + ], [DOC_INDEX_STATUS_MAP, t]) + // Initialize search value from URL on mount useEffect(() => { if (query.keyword) { @@ -322,14 +340,28 @@ const Documents: FC = ({ datasetId }) => {
- handleInputChange(e.target.value)} - onClear={() => handleInputChange('')} - /> +
+ { + setStatusFilter(item) + }} + items={statusFilterItems} + defaultValue={statusFilter.value} + wrapperClassName='w-[160px] h-8' + renderOption={({ item, selected }) => } + optionClassName='p-0' + notClearable + /> + handleInputChange(e.target.value)} + onClear={() => handleInputChange('')} + /> +
{!isFreePlan && } @@ -372,6 +404,8 @@ const Documents: FC = ({ datasetId }) => { onUpdate={handleUpdate} selectedIds={selectedIds} onSelectedIdChange={setSelectedIds} + statusFilter={statusFilter} + onStatusFilterChange={setStatusFilter} pagination={{ total, limit, diff --git a/web/app/components/datasets/documents/list.tsx b/web/app/components/datasets/documents/list.tsx index fc7093606..4660847c9 100644 --- a/web/app/components/datasets/documents/list.tsx +++ b/web/app/components/datasets/documents/list.tsx @@ -30,6 +30,7 @@ import Popover from '@/app/components/base/popover' import Confirm from '@/app/components/base/confirm' import Tooltip from '@/app/components/base/tooltip' import Toast, { ToastContext } from '@/app/components/base/toast' +import type { Item } from '@/app/components/base/select' import type { ColorMap, IndicatorProps } from '@/app/components/header/indicator' import Indicator from '@/app/components/header/indicator' import { asyncRunSafe } from '@/utils' @@ -426,6 +427,8 @@ type IDocumentListProps = { pagination: PaginationProps onUpdate: () => void onManageMetadata: () => void + statusFilter: Item + onStatusFilterChange: (filter: string) => void } /** @@ -440,6 +443,7 @@ const DocumentList: FC = ({ pagination, onUpdate, onManageMetadata, + statusFilter, }) => { const { t } = useTranslation() const { formatTime } = useTimestamp() @@ -451,6 +455,7 @@ const DocumentList: FC = ({ const [localDocs, setLocalDocs] = useState(documents) const [sortField, setSortField] = useState<'name' | 'word_count' | 'hit_count' | 'created_at' | null>('created_at') const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('desc') + const { isShowEditModal, showEditModal, @@ -465,12 +470,22 @@ const DocumentList: FC = ({ }) useEffect(() => { + let filteredDocs = documents + + if (statusFilter.value !== 'all') { + filteredDocs = filteredDocs.filter(doc => + typeof doc.display_status === 'string' + && typeof statusFilter.value === 'string' + && doc.display_status.toLowerCase() === statusFilter.value.toLowerCase(), + ) + } + if (!sortField) { - setLocalDocs(documents) + setLocalDocs(filteredDocs) return } - const sortedDocs = [...documents].sort((a, b) => { + const sortedDocs = [...filteredDocs].sort((a, b) => { let aValue: any let bValue: any @@ -506,7 +521,7 @@ const DocumentList: FC = ({ }) setLocalDocs(sortedDocs) - }, [documents, sortField, sortOrder]) + }, [documents, sortField, sortOrder, statusFilter]) const handleSort = (field: 'name' | 'word_count' | 'hit_count' | 'created_at') => { if (sortField === field) {