Explorar o código

fix: segment error tip & save segment disable when loading (#949)

zxhlyh hai 1 ano
pai
achega
9d5299e9ec

+ 34 - 15
web/app/components/datasets/documents/detail/completed/index.tsx

@@ -28,6 +28,7 @@ import AutoHeightTextarea from '@/app/components/base/auto-height-textarea/commo
 import Button from '@/app/components/base/button'
 import NewSegmentModal from '@/app/components/datasets/documents/detail/new-segment-modal'
 import TagInput from '@/app/components/base/tag-input'
+import { useEventEmitterContextContext } from '@/context/event-emitter'
 
 export const SegmentIndexTag: FC<{ positionId: string | number; className?: string }> = ({ positionId, className }) => {
   const localPositionId = useMemo(() => {
@@ -66,6 +67,15 @@ export const SegmentDetail: FC<ISegmentDetailProps> = memo(({
   const [question, setQuestion] = useState(segInfo?.content || '')
   const [answer, setAnswer] = useState(segInfo?.answer || '')
   const [keywords, setKeywords] = useState<string[]>(segInfo?.keywords || [])
+  const { eventEmitter } = useEventEmitterContextContext()
+  const [loading, setLoading] = useState(false)
+
+  eventEmitter?.useSubscription((v) => {
+    if (v === 'update-segment')
+      setLoading(true)
+    else
+      setLoading(false)
+  })
 
   const handleCancel = () => {
     setIsEditing(false)
@@ -129,7 +139,9 @@ export const SegmentDetail: FC<ISegmentDetailProps> = memo(({
             <Button
               type='primary'
               className='!h-7 !px-3 !py-[5px] text-xs font-medium !rounded-md'
-              onClick={handleSave}>
+              onClick={handleSave}
+              disabled={loading}
+            >
               {t('common.operation.save')}
             </Button>
           </>
@@ -225,6 +237,7 @@ const Completed: FC<ICompletedProps> = ({
   const [allSegments, setAllSegments] = useState<Array<SegmentDetailModel[]>>([]) // all segments data
   const [loading, setLoading] = useState(false)
   const [total, setTotal] = useState<number | undefined>()
+  const { eventEmitter } = useEventEmitterContextContext()
 
   const onChangeStatus = ({ value }: Item) => {
     setSelectedStatus(value === 'all' ? 'all' : !!value)
@@ -318,23 +331,29 @@ const Completed: FC<ICompletedProps> = ({
     if (keywords.length)
       params.keywords = keywords
 
-    const res = await updateSegment({ datasetId, documentId, segmentId, body: params })
-    notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
-    onCloseModal()
-    for (const item of allSegments) {
-      for (const seg of item) {
-        if (seg.id === segmentId) {
-          seg.answer = res.data.answer
-          seg.content = res.data.content
-          seg.keywords = res.data.keywords
-          seg.word_count = res.data.word_count
-          seg.hit_count = res.data.hit_count
-          seg.index_node_hash = res.data.index_node_hash
-          seg.enabled = res.data.enabled
+    try {
+      eventEmitter?.emit('update-segment')
+      const res = await updateSegment({ datasetId, documentId, segmentId, body: params })
+      notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+      onCloseModal()
+      for (const item of allSegments) {
+        for (const seg of item) {
+          if (seg.id === segmentId) {
+            seg.answer = res.data.answer
+            seg.content = res.data.content
+            seg.keywords = res.data.keywords
+            seg.word_count = res.data.word_count
+            seg.hit_count = res.data.hit_count
+            seg.index_node_hash = res.data.index_node_hash
+            seg.enabled = res.data.enabled
+          }
         }
       }
+      setAllSegments([...allSegments])
+    }
+    finally {
+      eventEmitter?.emit('')
     }
-    setAllSegments([...allSegments])
   }
 
   useEffect(() => {

+ 14 - 5
web/app/components/datasets/documents/detail/new-segment-modal.tsx

@@ -31,6 +31,7 @@ const NewSegmentModal: FC<NewSegmentModalProps> = memo(({
   const [answer, setAnswer] = useState('')
   const { datasetId, documentId } = useParams()
   const [keywords, setKeywords] = useState<string[]>([])
+  const [loading, setLoading] = useState(false)
 
   const handleCancel = () => {
     setQuestion('')
@@ -60,10 +61,16 @@ const NewSegmentModal: FC<NewSegmentModalProps> = memo(({
     if (keywords?.length)
       params.keywords = keywords
 
-    await addSegment({ datasetId, documentId, body: params })
-    notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
-    handleCancel()
-    onSave()
+    setLoading(true)
+    try {
+      await addSegment({ datasetId, documentId, body: params })
+      notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
+      handleCancel()
+      onSave()
+    }
+    finally {
+      setLoading(false)
+    }
   }
 
   const renderContent = () => {
@@ -136,7 +143,9 @@ const NewSegmentModal: FC<NewSegmentModalProps> = memo(({
           <Button
             type='primary'
             className='!h-9 !px-4 !py-2 text-sm font-medium !rounded-lg'
-            onClick={handleSave}>
+            onClick={handleSave}
+            disabled={loading}
+          >
             {t('common.operation.save')}
           </Button>
         </div>

+ 3 - 69
web/app/components/datasets/documents/list.tsx

@@ -27,7 +27,6 @@ import NotionIcon from '@/app/components/base/notion-icon'
 import ProgressBar from '@/app/components/base/progress-bar'
 import { DataSourceType, type DocumentDisplayStatus, type SimpleDocumentDetail } from '@/models/datasets'
 import type { CommonResponse } from '@/models/common'
-import { FilePlus02 } from '@/app/components/base/icons/src/vender/line/files'
 import { DotsHorizontal, HelpCircle } from '@/app/components/base/icons/src/vender/line/general'
 
 export const SettingsIcon: FC<{ className?: string }> = ({ className }) => {
@@ -89,7 +88,9 @@ export const StatusItem: FC<{
       errorMessage && (
         <Tooltip
           selector='dataset-document-detail-item-status'
-          content={errorMessage}
+          htmlContent={
+            <div className='max-w-[260px]'>{errorMessage}</div>
+          }
         >
           <HelpCircle className='ml-1 w-[14px] h-[14px] text-gray-700' />
         </Tooltip>
@@ -152,73 +153,6 @@ export const OperationAction: FC<{
     onUpdate(operationName)
   }
 
-  const Operations = (props: any) => <div className='w-full py-1'>
-    {!isListScene && <>
-      <div className='flex justify-between items-center mx-4 pt-2'>
-        <span className={cn(s.actionName, 'font-medium')}>
-          {!archived && enabled ? t('datasetDocuments.list.index.enable') : t('datasetDocuments.list.index.disable')}
-        </span>
-        <Tooltip
-          selector={`detail-switch-${id}`}
-          content={t('datasetDocuments.list.action.enableWarning') as string}
-          className='!font-semibold'
-          disabled={!archived}
-        >
-          <div>
-            <Switch
-              defaultValue={archived ? false : enabled}
-              onChange={v => !archived && onOperate(v ? 'enable' : 'disable')}
-              disabled={archived}
-              size='md'
-            />
-          </div>
-        </Tooltip>
-      </div>
-      <div className='mx-4 pb-1 pt-0.5 text-xs text-gray-500'>
-        {!archived && enabled ? t('datasetDocuments.list.index.enableTip') : t('datasetDocuments.list.index.disableTip')}
-      </div>
-      <Divider />
-    </>}
-    {!archived && (
-      <>
-        <div className={s.actionItem} onClick={() => router.push(`/datasets/${datasetId}/documents/${detail.id}/settings`)}>
-          <SettingsIcon />
-          <span className={s.actionName}>{t('datasetDocuments.list.action.settings')}</span>
-        </div>
-        {
-          !isListScene && (
-            <div className={s.actionItem} onClick={showNewSegmentModal}>
-              <FilePlus02 className='w-4 h-4 text-gray-500' />
-              <span className={s.actionName}>{t('datasetDocuments.list.action.add')}</span>
-            </div>
-          )
-        }
-        {
-          data_source_type === 'notion_import' && (
-            <div className={s.actionItem} onClick={() => onOperate('sync')}>
-              <SyncIcon />
-              <span className={s.actionName}>{t('datasetDocuments.list.action.sync')}</span>
-            </div>
-          )
-        }
-        <Divider className='my-1' />
-      </>
-    )}
-    {!archived && <div className={s.actionItem} onClick={() => onOperate('archive')}>
-      <ArchiveIcon />
-      <span className={s.actionName}>{t('datasetDocuments.list.action.archive')}</span>
-    </div>}
-    <div
-      className={cn(s.actionItem, s.deleteActionItem, 'group')}
-      onClick={() => {
-        setShowModal(true)
-        props?.onClose()
-      }}>
-      <TrashIcon className={'w-4 h-4 stroke-current text-gray-500 stroke-2 group-hover:text-red-500'} />
-      <span className={cn(s.actionName, 'group-hover:text-red-500')}>{t('datasetDocuments.list.action.delete')}</span>
-    </div>
-  </div>
-
   return <div className='flex items-center' onClick={e => e.stopPropagation()}>
     {isListScene && <>
       {archived