/* eslint-disable no-mixed-operators */
'use client'
import type { FC } from 'react'
import React, { useEffect, useState } from 'react'
import { ArrowDownIcon, TrashIcon } from '@heroicons/react/24/outline'
import { ExclamationCircleIcon } from '@heroicons/react/24/solid'
import dayjs from 'dayjs'
import { pick } from 'lodash-es'
import { useContext } from 'use-context-selector'
import { useRouter } from 'next/navigation'
import { useTranslation } from 'react-i18next'
import cn from 'classnames'
import s from './style.module.css'
import Switch from '@/app/components/base/switch'
import Divider from '@/app/components/base/divider'
import Popover from '@/app/components/base/popover'
import Modal from '@/app/components/base/modal'
import Button from '@/app/components/base/button'
import Tooltip from '@/app/components/base/tooltip'
import { ToastContext } from '@/app/components/base/toast'
import type { IndicatorProps } from '@/app/components/header/indicator'
import Indicator from '@/app/components/header/indicator'
import { asyncRunSafe } from '@/utils'
import { formatNumber } from '@/utils/format'
import { archiveDocument, deleteDocument, disableDocument, enableDocument } from '@/service/datasets'
import type { DocumentDisplayStatus, DocumentListResponse } from '@/models/datasets'
import type { CommonResponse } from '@/models/common'
export const SettingsIcon: FC<{ className?: string }> = ({ className }) => {
return
}
export const FilePlusIcon: FC<{ className?: string }> = ({ className }) => {
return
}
export const ArchiveIcon: FC<{ className?: string }> = ({ className }) => {
return
}
export const useIndexStatus = () => {
const { t } = useTranslation()
return {
queuing: { color: 'orange', text: t('datasetDocuments.list.status.queuing') }, // waiting
indexing: { color: 'blue', text: t('datasetDocuments.list.status.indexing') }, // indexing splitting parsing cleaning
paused: { color: 'orange', text: t('datasetDocuments.list.status.parsed') }, // paused
error: { color: 'red', text: t('datasetDocuments.list.status.error') }, // error
available: { color: 'green', text: t('datasetDocuments.list.status.available') }, // completed,archived = false,enabled = true
enabled: { color: 'green', text: t('datasetDocuments.list.status.enabled') }, // completed,archived = false,enabled = true
disabled: { color: 'gray', text: t('datasetDocuments.list.status.disabled') }, // completed,archived = false,enabled = false
archived: { color: 'gray', text: t('datasetDocuments.list.status.archived') }, // completed,archived = true
}
}
// status item for list
export const StatusItem: FC<{
status: DocumentDisplayStatus
reverse?: boolean
scene?: 'list' | 'detail'
textCls?: string
}> = ({ status, reverse = false, scene = 'list', textCls = '' }) => {
const DOC_INDEX_STATUS_MAP = useIndexStatus()
const localStatus = status.toLowerCase() as keyof typeof DOC_INDEX_STATUS_MAP
return
{DOC_INDEX_STATUS_MAP[localStatus]?.text}
}
type OperationName = 'delete' | 'archive' | 'enable' | 'disable'
// operation action for list and detail
export const OperationAction: FC<{
detail: {
enabled: boolean
archived: boolean
id: string
}
datasetId: string
onUpdate: () => void
scene?: 'list' | 'detail'
className?: string
}> = ({ datasetId, detail, onUpdate, scene = 'list', className = '' }) => {
const { id, enabled = false, archived = false } = detail || {}
const [showModal, setShowModal] = useState(false)
const { notify } = useContext(ToastContext)
const { t } = useTranslation()
const router = useRouter()
const isListScene = scene === 'list'
const onOperate = async (operationName: OperationName) => {
let opApi = deleteDocument
switch (operationName) {
case 'archive':
opApi = archiveDocument
break
case 'enable':
opApi = enableDocument
break
case 'disable':
opApi = disableDocument
break
default:
opApi = deleteDocument
break
}
const [e] = await asyncRunSafe(opApi({ datasetId, documentId: id }) as Promise)
if (!e)
notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
else
notify({ type: 'error', message: t('common.actionMsg.modificationFailed') })
onUpdate()
}
return e.stopPropagation()}
>
{isListScene && <>
{archived
?
{ }} disabled={true} size='md' />
:
onOperate(v ? 'enable' : 'disable')} size='md' />
}
>}
{!isListScene && <>
{!archived && enabled ? t('datasetDocuments.list.index.enable') : t('datasetDocuments.list.index.disable')}
!archived && onOperate(v ? 'enable' : 'disable')}
disabled={archived}
size='md'
/>
{!archived && enabled ? t('datasetDocuments.list.index.enableTip') : t('datasetDocuments.list.index.disableTip')}
>}
{!archived && (
<>
router.push(`/datasets/${datasetId}/documents/${detail.id}/settings`)}>
{t('datasetDocuments.list.action.settings')}
{/* router.push(`/datasets/${datasetId}/documents/create`)}>
{t('datasetDocuments.list.action.uploadFile')}
*/}
>
)}
{!archived && onOperate('archive')}>
{t('datasetDocuments.list.action.archive')}
}
setShowModal(true)}>
{t('datasetDocuments.list.action.delete')}
}
trigger='click'
position='br'
btnElement={}
btnClassName={open => cn(isListScene ? s.actionIconWrapperList : s.actionIconWrapperDetail, open ? '!bg-gray-100 !shadow-none' : '!bg-transparent')}
className={`!w-[200px] h-fit !z-20 ${className}`}
/>
{showModal && setShowModal(false)} className={s.delModal} closable>
{t('datasetDocuments.list.delete.title')}
{t('datasetDocuments.list.delete.content')}
}
}
export const renderTdValue = (value: string | number | null, isEmptyStyle = false) => {
return (
{value ?? '-'}
)
}
const renderCount = (count: number | undefined) => {
if (!count)
return renderTdValue(0, true)
if (count < 1000)
return count
return `${formatNumber((count / 1000).toFixed(1))}k`
}
type IDocumentListProps = {
documents: DocumentListResponse['data']
datasetId: string
onUpdate: () => void
}
/**
* Document list component including basic information
*/
const DocumentList: FC = ({ documents = [], datasetId, onUpdate }) => {
const { t } = useTranslation()
const router = useRouter()
const [localDocs, setLocalDocs] = useState(documents)
const [enableSort, setEnableSort] = useState(false)
useEffect(() => {
setLocalDocs(documents)
}, [documents])
const onClickSort = () => {
setEnableSort(!enableSort)
if (!enableSort) {
const sortedDocs = [...localDocs].sort((a, b) => dayjs(a.created_at).isBefore(dayjs(b.created_at)) ? -1 : 1)
setLocalDocs(sortedDocs)
}
else {
setLocalDocs(documents)
}
}
return (
<>
# |
{t('datasetDocuments.list.table.header.fileName')} |
{t('datasetDocuments.list.table.header.words')} |
{t('datasetDocuments.list.table.header.hitCount')} |
{t('datasetDocuments.list.table.header.uploadTime')}
|
{t('datasetDocuments.list.table.header.status')} |
{t('datasetDocuments.list.table.header.action')} |
{localDocs.map((doc) => {
const suffix = doc.name.split('.').pop() || 'txt'
return {
router.push(`datasets/${datasetId}/documents/${doc.id}`)
}}>
{doc.position} |
{doc?.name?.replace(/\.[^/.]+$/, '')}.{suffix}
|
{renderCount(doc.word_count)} |
{renderCount(doc.hit_count)} |
{dayjs.unix(doc.created_at).format(t('datasetHitTesting.dateTimeFormat') as string)}
|
|
|
})}
>
)
}
export default DocumentList