From 5a1159f9ab9a91143be76705746f210437fc6b0e Mon Sep 17 00:00:00 2001 From: twwu Date: Thu, 12 Dec 2024 15:33:54 +0800 Subject: [PATCH] feat: update child chunk handling and improve UI interactions --- .../detail/completed/child-segment-list.tsx | 2 +- .../documents/detail/completed/index.tsx | 35 +++++++++++++------ .../detail/completed/new-child-segment.tsx | 32 +++++++++++------ .../datasets/documents/detail/new-segment.tsx | 2 +- web/i18n/en-US/common.ts | 1 + web/i18n/en-US/dataset-documents.ts | 2 +- web/i18n/zh-Hans/common.ts | 1 + web/i18n/zh-Hans/dataset-documents.ts | 2 +- web/models/datasets.ts | 1 + 9 files changed, 53 insertions(+), 25 deletions(-) diff --git a/web/app/components/datasets/documents/detail/completed/child-segment-list.tsx b/web/app/components/datasets/documents/detail/completed/child-segment-list.tsx index f4e14b9b76..34cbd1c96e 100644 --- a/web/app/components/datasets/documents/detail/completed/child-segment-list.tsx +++ b/web/app/components/datasets/documents/detail/completed/child-segment-list.tsx @@ -91,7 +91,7 @@ const ChildSegmentList: FC = ({ {isParagraphMode && }
{childChunks.map((childChunk) => { - const edited = childChunk.type === 'customized' + const edited = childChunk.updated_at !== childChunk.created_at return = ({ // 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 = ({ 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 = ({ }, ) // 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 = ({ const { mutateAsync: updateChildSegment } = useUpdateChildSegment() - const handleUpdateChildChunk = async ( + const handleUpdateChildChunk = useCallback(async ( segmentId: string, childChunkId: string, content: string, @@ -418,6 +433,7 @@ const Completed: FC = ({ 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 = ({ 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 = ({ finally { eventEmitter?.emit('update-child-segment-done') } - } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [segments, childSegments, datasetId, documentId, parentMode]) return ( = ({ setShowNewChildSegmentModal(false) setFullScreen(false) }} - onSave={() => { - if (parentMode === 'paragraph') - resetList() - else - resetChildList() - }} + onSave={onSaveNewChildChunk} viewNewlyAddedChildChunk={viewNewlyAddedChildChunk} /> diff --git a/web/app/components/datasets/documents/detail/completed/new-child-segment.tsx b/web/app/components/datasets/documents/detail/completed/new-child-segment.tsx index 1f8133fe5c..98d498560e 100644 --- a/web/app/components/datasets/documents/detail/completed/new-child-segment.tsx +++ b/web/app/components/datasets/documents/detail/completed/new-child-segment.tsx @@ -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 = ({ const { appSidebarExpand } = useAppStore(useShallow(state => ({ appSidebarExpand: state.appSidebarExpand, }))) + const parentMode = useDocumentContext(s => s.parentMode) + const refreshTimer = useRef(null) + const isFullDocMode = useMemo(() => { + return parentMode === 'full-doc' + }, [parentMode]) + const CustomButton = <> @@ -72,18 +79,23 @@ const NewChildSegmentModal: FC = ({ 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) diff --git a/web/app/components/datasets/documents/detail/new-segment.tsx b/web/app/components/datasets/documents/detail/new-segment.tsx index 43a76cb08d..cadab9ce84 100644 --- a/web/app/components/datasets/documents/detail/new-segment.tsx +++ b/web/app/components/datasets/documents/detail/new-segment.tsx @@ -55,7 +55,7 @@ const NewSegmentModal: FC = ({ clearTimeout(refreshTimer.current) viewNewlyAddedChunk() }}> - {t('datasetDocuments.segment.viewAddedChunk')} + {t('common.operation.view')} diff --git a/web/i18n/en-US/common.ts b/web/i18n/en-US/common.ts index 82fa6ce01e..ebffdbe3a9 100644 --- a/web/i18n/en-US/common.ts +++ b/web/i18n/en-US/common.ts @@ -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', }, diff --git a/web/i18n/en-US/dataset-documents.ts b/web/i18n/en-US/dataset-documents.ts index e074054815..d9e0bb77e3 100644 --- a/web/i18n/en-US/dataset-documents.ts +++ b/web/i18n/en-US/dataset-documents.ts @@ -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', diff --git a/web/i18n/zh-Hans/common.ts b/web/i18n/zh-Hans/common.ts index 1af56d0cfe..9fdeaa703c 100644 --- a/web/i18n/zh-Hans/common.ts +++ b/web/i18n/zh-Hans/common.ts @@ -44,6 +44,7 @@ const translation = { openInNewTab: '在新标签页打开', saveAndRegenerate: '保存并重新生成子分段', close: '关闭', + view: '查看', viewMore: '查看更多', regenerate: '重新生成', }, diff --git a/web/i18n/zh-Hans/dataset-documents.ts b/web/i18n/zh-Hans/dataset-documents.ts index e06ae3f628..9299ee8acb 100644 --- a/web/i18n/zh-Hans/dataset-documents.ts +++ b/web/i18n/zh-Hans/dataset-documents.ts @@ -351,7 +351,7 @@ const translation = { addAnother: '连续新增', delete: '删除这个分段?', chunkAdded: '新增一个分段', - viewAddedChunk: '查看', + childChunkAdded: '新增一个子分段', regenerationConfirmTitle: '是否需要重新生成子分段?', regenerationConfirmMessage: '重新生成的子分段将会覆盖当前的子分段,包括编辑过的分段和新添加的分段。重新生成操作无法撤销。', regeneratingTitle: '正在生成子分段', diff --git a/web/models/datasets.ts b/web/models/datasets.ts index ac2484ef79..0dbc2938a2 100644 --- a/web/models/datasets.ts +++ b/web/models/datasets.ts @@ -627,6 +627,7 @@ export type ChildChunkDetail = { content: string word_count: number created_at: number + updated_at: number type: ChildChunkType }