| @@ -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> | |||
| }, | |||
| }) | |||
| } | |||