mirror of
https://github.com/langgenius/dify.git
synced 2026-07-23 03:58:31 +08:00
223 lines
7.9 KiB
TypeScript
223 lines
7.9 KiB
TypeScript
'use client'
|
|
import type { FC } from 'react'
|
|
import type {
|
|
BuiltInMetadataItem,
|
|
MetadataItemWithValueLength,
|
|
} from '@/app/components/datasets/metadata/types'
|
|
import type { SortType } from '@/service/datasets'
|
|
import { Button } from '@langgenius/dify-ui/button'
|
|
import { useMemo } from 'react'
|
|
import { useTranslation } from 'react-i18next'
|
|
import Chip from '@/app/components/base/chip'
|
|
import Input from '@/app/components/base/input'
|
|
import Sort from '@/app/components/base/sort'
|
|
import AutoDisabledDocument from '@/app/components/datasets/common/document-status-with-action/auto-disabled-document'
|
|
import IndexFailed from '@/app/components/datasets/common/document-status-with-action/index-failed'
|
|
import StatusWithAction from '@/app/components/datasets/common/document-status-with-action/status-with-action'
|
|
import DatasetMetadataDrawer from '@/app/components/datasets/metadata/metadata-dataset/dataset-metadata-drawer'
|
|
import { useDocLink } from '@/context/i18n'
|
|
import { DataSourceType } from '@/models/datasets'
|
|
import { useIndexStatus } from '../status-item/hooks'
|
|
|
|
type SelectOption = {
|
|
value: string | number
|
|
name: string
|
|
}
|
|
|
|
type DocumentsHeaderProps = {
|
|
// Dataset info
|
|
datasetId: string
|
|
dataSourceType?: DataSourceType
|
|
embeddingAvailable: boolean
|
|
canManageMetadata?: boolean
|
|
canAddDocument?: boolean
|
|
canEditDocument?: boolean
|
|
isFreePlan: boolean
|
|
|
|
// Filter & sort
|
|
statusFilterValue: string
|
|
sortValue: SortType
|
|
inputValue: string
|
|
onStatusFilterChange: (value: string) => void
|
|
onStatusFilterClear: () => void
|
|
onSortChange: (value: string) => void
|
|
onInputChange: (value: string) => void
|
|
|
|
// Metadata modal
|
|
isShowEditMetadataModal: boolean
|
|
showEditMetadataModal: () => void
|
|
hideEditMetadataModal: () => void
|
|
datasetMetaData?: MetadataItemWithValueLength[]
|
|
builtInMetaData?: BuiltInMetadataItem[]
|
|
builtInEnabled: boolean
|
|
onAddMetaData: (payload: BuiltInMetadataItem) => Promise<void>
|
|
onRenameMetaData: (payload: MetadataItemWithValueLength) => Promise<void>
|
|
onDeleteMetaData: (metaDataId: string) => Promise<void>
|
|
onBuiltInEnabledChange: (enabled: boolean) => void
|
|
|
|
// Actions
|
|
onAddDocument: () => void
|
|
}
|
|
|
|
const DocumentsHeader: FC<DocumentsHeaderProps> = ({
|
|
datasetId,
|
|
dataSourceType,
|
|
embeddingAvailable,
|
|
canManageMetadata = false,
|
|
canAddDocument = false,
|
|
canEditDocument = false,
|
|
isFreePlan,
|
|
statusFilterValue,
|
|
sortValue,
|
|
inputValue,
|
|
onStatusFilterChange,
|
|
onStatusFilterClear,
|
|
onSortChange,
|
|
onInputChange,
|
|
isShowEditMetadataModal,
|
|
showEditMetadataModal,
|
|
hideEditMetadataModal,
|
|
datasetMetaData,
|
|
builtInMetaData,
|
|
builtInEnabled,
|
|
onAddMetaData,
|
|
onRenameMetaData,
|
|
onDeleteMetaData,
|
|
onBuiltInEnabledChange,
|
|
onAddDocument,
|
|
}) => {
|
|
const { t } = useTranslation()
|
|
const docLink = useDocLink()
|
|
const DOC_INDEX_STATUS_MAP = useIndexStatus()
|
|
|
|
const isDataSourceNotion = dataSourceType === DataSourceType.NOTION
|
|
const isDataSourceWeb = dataSourceType === DataSourceType.WEB
|
|
|
|
const statusFilterItems: SelectOption[] = useMemo(
|
|
() => [
|
|
{ value: 'all', name: t(($) => $['list.index.all'], { ns: 'datasetDocuments' }) as string },
|
|
{ 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],
|
|
)
|
|
|
|
const sortItems: SelectOption[] = useMemo(
|
|
() => [
|
|
{
|
|
value: 'created_at',
|
|
name: t(($) => $['list.sort.uploadTime'], { ns: 'datasetDocuments' }) as string,
|
|
},
|
|
{
|
|
value: 'hit_count',
|
|
name: t(($) => $['list.sort.hitCount'], { ns: 'datasetDocuments' }) as string,
|
|
},
|
|
],
|
|
[t],
|
|
)
|
|
|
|
// Determine add button text based on data source type
|
|
const addButtonText = useMemo(() => {
|
|
if (isDataSourceNotion) return t(($) => $['list.addPages'], { ns: 'datasetDocuments' })
|
|
if (isDataSourceWeb) return t(($) => $['list.addUrl'], { ns: 'datasetDocuments' })
|
|
return t(($) => $['list.addFile'], { ns: 'datasetDocuments' })
|
|
}, [isDataSourceNotion, isDataSourceWeb, t])
|
|
|
|
return (
|
|
<>
|
|
{/* Title section */}
|
|
<div className="flex flex-col justify-center gap-1 px-6 pt-4">
|
|
<h1 className="text-base font-semibold text-text-primary">
|
|
{t(($) => $['list.title'], { ns: 'datasetDocuments' })}
|
|
</h1>
|
|
<div className="flex items-center space-x-0.5 text-sm font-normal text-text-tertiary">
|
|
<span>{t(($) => $['list.desc'], { ns: 'datasetDocuments' })}</span>
|
|
<a
|
|
className="flex items-center text-text-accent"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
href={docLink('/use-dify/knowledge/integrate-knowledge-within-application')}
|
|
>
|
|
<span>{t(($) => $['list.learnMore'], { ns: 'datasetDocuments' })}</span>
|
|
<span className="i-ri-external-link-line size-3" />
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Toolbar section */}
|
|
<div className="flex flex-wrap items-center justify-between px-6 pt-4">
|
|
{/* Left: Filters */}
|
|
<div className="flex items-center gap-2">
|
|
<Chip
|
|
className="w-[160px]"
|
|
showLeftIcon={false}
|
|
value={statusFilterValue}
|
|
items={statusFilterItems}
|
|
onSelect={(item) => onStatusFilterChange(item?.value ? String(item.value) : '')}
|
|
onClear={onStatusFilterClear}
|
|
/>
|
|
<Input
|
|
showLeftIcon
|
|
showClearIcon
|
|
wrapperClassName="w-[200px]!"
|
|
value={inputValue}
|
|
onChange={(e) => onInputChange(e.target.value)}
|
|
onClear={() => onInputChange('')}
|
|
/>
|
|
<div className="h-3.5 w-px bg-divider-regular"></div>
|
|
<Sort
|
|
order={sortValue.startsWith('-') ? '-' : ''}
|
|
value={sortValue.replace('-', '')}
|
|
items={sortItems}
|
|
onSelect={(value) => onSortChange(String(value))}
|
|
/>
|
|
</div>
|
|
|
|
{/* Right: Actions */}
|
|
<div className="flex h-8! items-center justify-center gap-2">
|
|
{!isFreePlan && canEditDocument && <AutoDisabledDocument datasetId={datasetId} />}
|
|
{canEditDocument && <IndexFailed datasetId={datasetId} />}
|
|
{!embeddingAvailable && (
|
|
<StatusWithAction
|
|
type="warning"
|
|
description={t(($) => $.embeddingModelNotAvailable, { ns: 'dataset' })}
|
|
/>
|
|
)}
|
|
{embeddingAvailable && canManageMetadata && (
|
|
<Button variant="secondary" className="shrink-0" onClick={showEditMetadataModal}>
|
|
<span className="mr-1 i-ri-draft-line size-4" />
|
|
{t(($) => $['metadata.metadata'], { ns: 'dataset' })}
|
|
</Button>
|
|
)}
|
|
{isShowEditMetadataModal && (
|
|
<DatasetMetadataDrawer
|
|
userMetadata={datasetMetaData ?? []}
|
|
onClose={hideEditMetadataModal}
|
|
onAdd={onAddMetaData}
|
|
onRename={onRenameMetaData}
|
|
onRemove={onDeleteMetaData}
|
|
builtInMetadata={builtInMetaData ?? []}
|
|
isBuiltInEnabled={builtInEnabled}
|
|
onIsBuiltInEnabledChange={onBuiltInEnabledChange}
|
|
/>
|
|
)}
|
|
{embeddingAvailable && canAddDocument && (
|
|
<Button variant="primary" onClick={onAddDocument} className="shrink-0">
|
|
<span className="mr-2 i-heroicons-plus-solid size-4 stroke-current" />
|
|
{addButtonText}
|
|
</Button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</>
|
|
)
|
|
}
|
|
|
|
export default DocumentsHeader
|