feat: update child chunk handling and improve UI interactions

pull/12097/head
twwu 1 year ago
parent c1d1960215
commit 5a1159f9ab

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

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

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

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

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

@ -353,7 +353,7 @@ const translation = {
addAnother: 'Add another', addAnother: 'Add another',
delete: 'Delete this chunk ?', delete: 'Delete this chunk ?',
chunkAdded: '1 chunk added', chunkAdded: '1 chunk added',
viewAddedChunk: 'View', childChunkAdded: '1 child chunk added',
regenerationConfirmTitle: 'Do you want to regenerate child chunks?', 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.', 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', regeneratingTitle: 'Regenerating child chunks',

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

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

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

Loading…
Cancel
Save