feat: add document pause and resume functionality (#21894)
This commit is contained in:
@@ -11,6 +11,8 @@ import {
|
||||
RiEqualizer2Line,
|
||||
RiLoopLeftLine,
|
||||
RiMoreFill,
|
||||
RiPauseCircleLine,
|
||||
RiPlayCircleLine,
|
||||
} from '@remixicon/react'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import { useRouter } from 'next/navigation'
|
||||
@@ -42,7 +44,7 @@ import { useDatasetDetailContextWithSelector as useDatasetDetailContext } from '
|
||||
import type { Props as PaginationProps } from '@/app/components/base/pagination'
|
||||
import Pagination from '@/app/components/base/pagination'
|
||||
import Checkbox from '@/app/components/base/checkbox'
|
||||
import { useDocumentArchive, useDocumentDelete, useDocumentDisable, useDocumentEnable, useDocumentUnArchive, useSyncDocument, useSyncWebsite } from '@/service/knowledge/use-document'
|
||||
import { useDocumentArchive, useDocumentDelete, useDocumentDisable, useDocumentEnable, useDocumentPause, useDocumentResume, useDocumentUnArchive, useSyncDocument, useSyncWebsite } from '@/service/knowledge/use-document'
|
||||
import { extensionToFileType } from '@/app/components/datasets/hit-testing/utils/extension-to-file-type'
|
||||
import useBatchEditDocumentMetadata from '../metadata/hooks/use-batch-edit-document-metadata'
|
||||
import EditMetadataBatchModal from '@/app/components/datasets/metadata/edit-metadata-batch/modal'
|
||||
@@ -168,7 +170,7 @@ export const StatusItem: FC<{
|
||||
</div>
|
||||
}
|
||||
|
||||
type OperationName = 'delete' | 'archive' | 'enable' | 'disable' | 'sync' | 'un_archive'
|
||||
type OperationName = 'delete' | 'archive' | 'enable' | 'disable' | 'sync' | 'un_archive' | 'pause' | 'resume'
|
||||
|
||||
// operation action for list and detail
|
||||
export const OperationAction: FC<{
|
||||
@@ -180,13 +182,14 @@ export const OperationAction: FC<{
|
||||
id: string
|
||||
data_source_type: string
|
||||
doc_form: string
|
||||
display_status?: string
|
||||
}
|
||||
datasetId: string
|
||||
onUpdate: (operationName?: string) => void
|
||||
scene?: 'list' | 'detail'
|
||||
className?: string
|
||||
}> = ({ embeddingAvailable, datasetId, detail, onUpdate, scene = 'list', className = '' }) => {
|
||||
const { id, enabled = false, archived = false, data_source_type } = detail || {}
|
||||
const { id, enabled = false, archived = false, data_source_type, display_status } = detail || {}
|
||||
const [showModal, setShowModal] = useState(false)
|
||||
const [deleting, setDeleting] = useState(false)
|
||||
const { notify } = useContext(ToastContext)
|
||||
@@ -199,6 +202,8 @@ export const OperationAction: FC<{
|
||||
const { mutateAsync: deleteDocument } = useDocumentDelete()
|
||||
const { mutateAsync: syncDocument } = useSyncDocument()
|
||||
const { mutateAsync: syncWebsite } = useSyncWebsite()
|
||||
const { mutateAsync: pauseDocument } = useDocumentPause()
|
||||
const { mutateAsync: resumeDocument } = useDocumentResume()
|
||||
const isListScene = scene === 'list'
|
||||
|
||||
const onOperate = async (operationName: OperationName) => {
|
||||
@@ -222,6 +227,12 @@ export const OperationAction: FC<{
|
||||
else
|
||||
opApi = syncWebsite
|
||||
break
|
||||
case 'pause':
|
||||
opApi = pauseDocument
|
||||
break
|
||||
case 'resume':
|
||||
opApi = resumeDocument
|
||||
break
|
||||
default:
|
||||
opApi = deleteDocument
|
||||
setDeleting(true)
|
||||
@@ -323,6 +334,18 @@ export const OperationAction: FC<{
|
||||
<Divider className='my-1' />
|
||||
</>
|
||||
)}
|
||||
{!archived && display_status?.toLowerCase() === 'indexing' && (
|
||||
<div className={s.actionItem} onClick={() => onOperate('pause')}>
|
||||
<RiPauseCircleLine className='h-4 w-4 text-text-tertiary' />
|
||||
<span className={s.actionName}>{t('datasetDocuments.list.action.pause')}</span>
|
||||
</div>
|
||||
)}
|
||||
{!archived && display_status?.toLowerCase() === 'paused' && (
|
||||
<div className={s.actionItem} onClick={() => onOperate('resume')}>
|
||||
<RiPlayCircleLine className='h-4 w-4 text-text-tertiary' />
|
||||
<span className={s.actionName}>{t('datasetDocuments.list.action.resume')}</span>
|
||||
</div>
|
||||
)}
|
||||
{!archived && <div className={s.actionItem} onClick={() => onOperate('archive')}>
|
||||
<RiArchive2Line className='h-4 w-4 text-text-tertiary' />
|
||||
<span className={s.actionName}>{t('datasetDocuments.list.action.archive')}</span>
|
||||
@@ -626,7 +649,7 @@ const DocumentList: FC<IDocumentListProps> = ({
|
||||
<OperationAction
|
||||
embeddingAvailable={embeddingAvailable}
|
||||
datasetId={datasetId}
|
||||
detail={pick(doc, ['name', 'enabled', 'archived', 'id', 'data_source_type', 'doc_form'])}
|
||||
detail={pick(doc, ['name', 'enabled', 'archived', 'id', 'data_source_type', 'doc_form', 'display_status'])}
|
||||
onUpdate={onUpdate}
|
||||
/>
|
||||
</td>
|
||||
|
@@ -28,6 +28,8 @@ const translation = {
|
||||
delete: 'Löschen',
|
||||
enableWarning: 'Archivierte Datei kann nicht aktiviert werden',
|
||||
sync: 'Synchronisieren',
|
||||
resume: 'Fortsetzen',
|
||||
pause: 'Pause',
|
||||
},
|
||||
index: {
|
||||
enable: 'Aktivieren',
|
||||
|
@@ -30,6 +30,8 @@ const translation = {
|
||||
delete: 'Delete',
|
||||
enableWarning: 'Archived file cannot be enabled',
|
||||
sync: 'Sync',
|
||||
pause: 'Pause',
|
||||
resume: 'Resume',
|
||||
},
|
||||
index: {
|
||||
enable: 'Enable',
|
||||
|
@@ -29,6 +29,8 @@ const translation = {
|
||||
delete: 'Eliminar',
|
||||
enableWarning: 'El archivo archivado no puede habilitarse',
|
||||
sync: 'Sincronizar',
|
||||
resume: 'Reanudar',
|
||||
pause: 'Pausa',
|
||||
},
|
||||
index: {
|
||||
enable: 'Habilitar',
|
||||
|
@@ -29,6 +29,8 @@ const translation = {
|
||||
delete: 'حذف',
|
||||
enableWarning: 'فایل بایگانی شده نمیتواند فعال شود',
|
||||
sync: 'همگامسازی',
|
||||
resume: 'رزومه',
|
||||
pause: 'مکث',
|
||||
},
|
||||
index: {
|
||||
enable: 'فعال کردن',
|
||||
|
@@ -28,6 +28,8 @@ const translation = {
|
||||
delete: 'Supprimer',
|
||||
enableWarning: 'Le fichier archivé ne peut pas être activé',
|
||||
sync: 'Synchroniser',
|
||||
pause: 'Pause',
|
||||
resume: 'Reprendre',
|
||||
},
|
||||
index: {
|
||||
enable: 'Activer',
|
||||
|
@@ -29,6 +29,8 @@ const translation = {
|
||||
delete: 'हटाएँ',
|
||||
enableWarning: 'संग्रहित फाइल को सक्रिय नहीं किया जा सकता',
|
||||
sync: 'सिंक्रोनाइज़ करें',
|
||||
resume: 'रिज़्यूमे',
|
||||
pause: 'रोकें',
|
||||
},
|
||||
index: {
|
||||
enable: 'सक्रिय करें',
|
||||
|
@@ -29,6 +29,8 @@ const translation = {
|
||||
delete: 'Elimina',
|
||||
enableWarning: 'Il file archiviato non può essere abilitato',
|
||||
sync: 'Sincronizza',
|
||||
resume: 'Riassumere',
|
||||
pause: 'Pausa',
|
||||
},
|
||||
index: {
|
||||
enable: 'Abilita',
|
||||
|
@@ -30,6 +30,8 @@ const translation = {
|
||||
delete: '削除',
|
||||
enableWarning: 'アーカイブされたファイルは有効にできません',
|
||||
sync: '同期',
|
||||
pause: '一時停止',
|
||||
resume: '履歴書',
|
||||
},
|
||||
index: {
|
||||
enable: '有効にする',
|
||||
|
@@ -28,6 +28,8 @@ const translation = {
|
||||
delete: '삭제',
|
||||
enableWarning: '아카이브된 파일은 활성화할 수 없습니다.',
|
||||
sync: '동기화',
|
||||
resume: '이력서',
|
||||
pause: '일시 중지',
|
||||
},
|
||||
index: {
|
||||
enable: '활성화',
|
||||
|
@@ -28,6 +28,8 @@ const translation = {
|
||||
delete: 'Usuń',
|
||||
enableWarning: 'Zarchiwizowany plik nie może zostać włączony',
|
||||
sync: 'Synchronizuj',
|
||||
resume: 'Wznawiać',
|
||||
pause: 'Pauza',
|
||||
},
|
||||
index: {
|
||||
enable: 'Włącz',
|
||||
|
@@ -28,6 +28,8 @@ const translation = {
|
||||
delete: 'Excluir',
|
||||
enableWarning: 'O arquivo arquivado não pode ser habilitado',
|
||||
sync: 'Sincronizar',
|
||||
resume: 'Retomar',
|
||||
pause: 'Pausa',
|
||||
},
|
||||
index: {
|
||||
enable: 'Habilitar',
|
||||
|
@@ -28,6 +28,8 @@ const translation = {
|
||||
delete: 'Șterge',
|
||||
enableWarning: 'Fișierul arhivat nu poate fi activat',
|
||||
sync: 'Sincronizează',
|
||||
pause: 'Pauză',
|
||||
resume: 'Relua',
|
||||
},
|
||||
index: {
|
||||
enable: 'Activează',
|
||||
|
@@ -29,6 +29,8 @@ const translation = {
|
||||
delete: 'Удалить',
|
||||
enableWarning: 'Архивный файл не может быть включен',
|
||||
sync: 'Синхронизировать',
|
||||
resume: 'Резюме',
|
||||
pause: 'Пауза',
|
||||
},
|
||||
index: {
|
||||
enable: 'Включить',
|
||||
|
@@ -29,6 +29,8 @@ const translation = {
|
||||
delete: 'Izbriši',
|
||||
enableWarning: 'Arhivirane datoteke ni mogoče omogočiti',
|
||||
sync: 'Sinhroniziraj',
|
||||
pause: 'Pavza',
|
||||
resume: 'Življenjepis',
|
||||
},
|
||||
index: {
|
||||
enable: 'Omogoči',
|
||||
|
@@ -29,6 +29,8 @@ const translation = {
|
||||
delete: 'ลบ',
|
||||
enableWarning: 'ไม่สามารถเปิดใช้งานไฟล์ที่เก็บถาวรได้',
|
||||
sync: 'ซิงค์',
|
||||
pause: 'หยุด',
|
||||
resume: 'ดำเนิน',
|
||||
},
|
||||
index: {
|
||||
enable: 'เปิด',
|
||||
|
@@ -29,6 +29,8 @@ const translation = {
|
||||
delete: 'Sil',
|
||||
enableWarning: 'Arşivlenmiş dosya etkinleştirilemez',
|
||||
sync: 'Senkronize et',
|
||||
pause: 'Duraklat',
|
||||
resume: 'Özgeçmiş',
|
||||
},
|
||||
index: {
|
||||
enable: 'Etkinleştir',
|
||||
|
@@ -28,6 +28,8 @@ const translation = {
|
||||
delete: 'Видалити',
|
||||
enableWarning: 'Архівований файл неможливо активувати',
|
||||
sync: 'Синхронізувати',
|
||||
pause: 'Пауза',
|
||||
resume: 'Резюме',
|
||||
},
|
||||
index: {
|
||||
enable: 'Активувати',
|
||||
|
@@ -28,6 +28,8 @@ const translation = {
|
||||
delete: 'Xóa',
|
||||
enableWarning: 'Tệp đã lưu trữ không thể được kích hoạt',
|
||||
sync: 'Đồng bộ',
|
||||
pause: 'Tạm dừng',
|
||||
resume: 'Tiếp tục',
|
||||
},
|
||||
index: {
|
||||
enable: 'Kích hoạt',
|
||||
|
@@ -30,6 +30,8 @@ const translation = {
|
||||
delete: '删除',
|
||||
enableWarning: '归档的文件无法启用',
|
||||
sync: '同步',
|
||||
pause: '暂停',
|
||||
resume: '恢复',
|
||||
},
|
||||
index: {
|
||||
enable: '启用中',
|
||||
|
@@ -28,6 +28,8 @@ const translation = {
|
||||
delete: '刪除',
|
||||
enableWarning: '歸檔的檔案無法啟用',
|
||||
sync: '同步',
|
||||
resume: '恢復',
|
||||
pause: '暫停',
|
||||
},
|
||||
index: {
|
||||
enable: '啟用中',
|
||||
|
@@ -5,6 +5,7 @@ import {
|
||||
import { del, get, patch } from '../base'
|
||||
import { useInvalid } from '../use-base'
|
||||
import type { MetadataType, SortType } from '../datasets'
|
||||
import { pauseDocIndexing, resumeDocIndexing } from '../datasets'
|
||||
import type { DocumentDetailResponse, DocumentListResponse, UpdateDocumentBatchParams } from '@/models/datasets'
|
||||
import { DocumentActionType } from '@/models/datasets'
|
||||
import type { CommonResponse } from '@/models/common'
|
||||
@@ -130,3 +131,23 @@ export const useDocumentMetadata = (payload: {
|
||||
export const useInvalidDocumentDetailKey = () => {
|
||||
return useInvalid(useDocumentDetailKey)
|
||||
}
|
||||
|
||||
export const useDocumentPause = () => {
|
||||
return useMutation({
|
||||
mutationFn: ({ datasetId, documentId }: UpdateDocumentBatchParams) => {
|
||||
if (!datasetId || !documentId)
|
||||
throw new Error('datasetId and documentId are required')
|
||||
return pauseDocIndexing({ datasetId, documentId }) as Promise<CommonResponse>
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const useDocumentResume = () => {
|
||||
return useMutation({
|
||||
mutationFn: ({ datasetId, documentId }: UpdateDocumentBatchParams) => {
|
||||
if (!datasetId || !documentId)
|
||||
throw new Error('datasetId and documentId are required')
|
||||
return resumeDocIndexing({ datasetId, documentId }) as Promise<CommonResponse>
|
||||
},
|
||||
})
|
||||
}
|
||||
|
Reference in New Issue
Block a user