feat: update child chunk handling and improve UI interactions

This commit is contained in:
twwu 2024-12-12 15:33:54 +08:00
parent c1d1960215
commit 5a1159f9ab
9 changed files with 53 additions and 25 deletions

View File

@ -91,7 +91,7 @@ const ChildSegmentList: FC<IChildSegmentCardProps> = ({
{isParagraphMode && <Divider type='vertical' className='h-auto w-[2px] mx-[7px] bg-text-accent-secondary' />}
<div className={classNames('w-full !leading-5 flex flex-col', isParagraphMode ? 'gap-y-2' : 'gap-y-3')}>
{childChunks.map((childChunk) => {
const edited = childChunk.type === 'customized'
const edited = childChunk.updated_at !== childChunk.created_at
return <EditSlice
key={childChunk.id}
label={`C-${childChunk.position}${edited ? '·EDITED' : ''}`}

View File

@ -229,7 +229,7 @@ const Completed: FC<ICompletedProps> = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [datasetId, documentId, selectedSegmentIds])
const handleUpdateSegment = async (
const handleUpdateSegment = useCallback(async (
segmentId: string,
question: string,
answer: string,
@ -283,7 +283,8 @@ const Completed: FC<ICompletedProps> = ({
finally {
eventEmitter?.emit('update-segment-done')
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [segments, datasetId, documentId])
useEffect(() => {
if (importStatus === ProcessStatus.COMPLETED)
@ -360,13 +361,27 @@ const Completed: FC<ICompletedProps> = ({
},
)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [datasetId, documentId])
}, [datasetId, documentId, parentMode])
const handleAddNewChildChunk = useCallback((parentChunkId: string) => {
setShowNewChildSegmentModal(true)
setCurrChunkId(parentChunkId)
}, [])
const onSaveNewChildChunk = useCallback((newChildChunk?: ChildChunkDetail) => {
if (parentMode === 'paragraph') {
for (const seg of segments) {
if (seg.id === currChunkId)
seg.child_chunks?.push(newChildChunk!)
}
setSegments([...segments])
}
else {
resetChildList()
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [parentMode, currChunkId, segments])
const viewNewlyAddedChildChunk = useCallback(() => {
const totalPages = childChunkListData?.total_pages || 0
const total = childChunkListData?.total || 0
@ -394,7 +409,7 @@ const Completed: FC<ICompletedProps> = ({
const { mutateAsync: updateChildSegment } = useUpdateChildSegment()
const handleUpdateChildChunk = async (
const handleUpdateChildChunk = useCallback(async (
segmentId: string,
childChunkId: string,
content: string,
@ -418,6 +433,7 @@ const Completed: FC<ICompletedProps> = ({
childSeg.content = res.data.content
childSeg.type = res.data.type
childSeg.word_count = res.data.word_count
childSeg.updated_at = res.data.updated_at
}
}
}
@ -430,6 +446,7 @@ const Completed: FC<ICompletedProps> = ({
childSeg.content = res.data.content
childSeg.type = res.data.type
childSeg.word_count = res.data.word_count
childSeg.updated_at = res.data.updated_at
}
}
setChildSegments([...childSegments])
@ -438,7 +455,8 @@ const Completed: FC<ICompletedProps> = ({
finally {
eventEmitter?.emit('update-child-segment-done')
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [segments, childSegments, datasetId, documentId, parentMode])
return (
<SegmentListContext.Provider value={{
@ -571,12 +589,7 @@ const Completed: FC<ICompletedProps> = ({
setShowNewChildSegmentModal(false)
setFullScreen(false)
}}
onSave={() => {
if (parentMode === 'paragraph')
resetList()
else
resetChildList()
}}
onSave={onSaveNewChildChunk}
viewNewlyAddedChildChunk={viewNewlyAddedChildChunk}
/>
</FullScreenDrawer>

View File

@ -1,10 +1,11 @@
import { memo, useRef, useState } from 'react'
import { memo, useMemo, useRef, useState } from 'react'
import type { FC } from 'react'
import { useTranslation } from 'react-i18next'
import { useContext } from 'use-context-selector'
import { useParams } from 'next/navigation'
import { RiCloseLine, RiExpandDiagonalLine } from '@remixicon/react'
import { useShallow } from 'zustand/react/shallow'
import { useDocumentContext } from '../index'
import { SegmentIndexTag } from './common/segment-index-tag'
import ActionButtons from './common/action-buttons'
import ChunkContent from './common/chunk-content'
@ -13,7 +14,7 @@ import Dot from './common/dot'
import { useSegmentListContext } from './index'
import { useStore as useAppStore } from '@/app/components/app/store'
import { ToastContext } from '@/app/components/base/toast'
import type { SegmentUpdater } from '@/models/datasets'
import type { ChildChunkDetail, SegmentUpdater } from '@/models/datasets'
import classNames from '@/utils/classnames'
import { formatNumber } from '@/utils/format'
import Divider from '@/app/components/base/divider'
@ -22,7 +23,7 @@ import { useAddChildSegment } from '@/service/knowledge/use-segment'
type NewChildSegmentModalProps = {
chunkId: string
onCancel: () => void
onSave: () => void
onSave: (ChildChunk?: ChildChunkDetail) => void
viewNewlyAddedChildChunk?: () => void
}
@ -42,15 +43,21 @@ const NewChildSegmentModal: FC<NewChildSegmentModalProps> = ({
const { appSidebarExpand } = useAppStore(useShallow(state => ({
appSidebarExpand: state.appSidebarExpand,
})))
const parentMode = useDocumentContext(s => s.parentMode)
const refreshTimer = useRef<any>(null)
const isFullDocMode = useMemo(() => {
return parentMode === 'full-doc'
}, [parentMode])
const CustomButton = <>
<Divider type='vertical' className='h-3 mx-1 bg-divider-regular' />
<button className='text-text-accent system-xs-semibold' onClick={() => {
clearTimeout(refreshTimer.current)
viewNewlyAddedChildChunk?.()
}}>
{t('datasetDocuments.segment.viewAddedChunk')}
{t('common.operation.view')}
</button>
</>
@ -72,18 +79,23 @@ const NewChildSegmentModal: FC<NewChildSegmentModalProps> = ({
setLoading(true)
try {
await addChildSegment({ datasetId, documentId, segmentId: chunkId, body: params })
const res = await addChildSegment({ datasetId, documentId, segmentId: chunkId, body: params })
notify({
type: 'success',
message: t('datasetDocuments.segment.chunkAdded'),
message: t('datasetDocuments.segment.childChunkAdded'),
className: `!w-[296px] !bottom-0 ${appSidebarExpand === 'expand' ? '!left-[216px]' : '!left-14'}
!top-auto !right-auto !mb-[52px] !ml-11`,
customComponent: CustomButton,
customComponent: isFullDocMode && CustomButton,
})
handleCancel('add')
refreshTimer.current = setTimeout(() => {
onSave()
}, 3000)
if (isFullDocMode) {
refreshTimer.current = setTimeout(() => {
onSave()
}, 3000)
}
else {
onSave(res.data)
}
}
finally {
setLoading(false)

View File

@ -55,7 +55,7 @@ const NewSegmentModal: FC<NewSegmentModalProps> = ({
clearTimeout(refreshTimer.current)
viewNewlyAddedChunk()
}}>
{t('datasetDocuments.segment.viewAddedChunk')}
{t('common.operation.view')}
</button>
</>

View File

@ -44,6 +44,7 @@ const translation = {
openInNewTab: 'Open in new tab',
saveAndRegenerate: 'Save & Regenerate Child Chunks',
close: 'Close',
view: 'View',
viewMore: 'VIEW MORE',
regenerate: 'Regenerate',
},

View File

@ -353,7 +353,7 @@ const translation = {
addAnother: 'Add another',
delete: 'Delete this chunk ?',
chunkAdded: '1 chunk added',
viewAddedChunk: 'View',
childChunkAdded: '1 child chunk added',
regenerationConfirmTitle: 'Do you want to regenerate child chunks?',
regenerationConfirmMessage: 'Regenerating child chunks will overwrite the current child chunks, including edited chunks and newly added chunks. The regeneration cannot be undone.',
regeneratingTitle: 'Regenerating child chunks',

View File

@ -44,6 +44,7 @@ const translation = {
openInNewTab: '在新标签页打开',
saveAndRegenerate: '保存并重新生成子分段',
close: '关闭',
view: '查看',
viewMore: '查看更多',
regenerate: '重新生成',
},

View File

@ -351,7 +351,7 @@ const translation = {
addAnother: '连续新增',
delete: '删除这个分段?',
chunkAdded: '新增一个分段',
viewAddedChunk: '查看',
childChunkAdded: '新增一个子分段',
regenerationConfirmTitle: '是否需要重新生成子分段?',
regenerationConfirmMessage: '重新生成的子分段将会覆盖当前的子分段,包括编辑过的分段和新添加的分段。重新生成操作无法撤销。',
regeneratingTitle: '正在生成子分段',

View File

@ -627,6 +627,7 @@ export type ChildChunkDetail = {
content: string
word_count: number
created_at: number
updated_at: number
type: ChildChunkType
}