hiden dataset source (#4152)

* hiden dataset source

* perf: reader
This commit is contained in:
Archer 2025-03-13 21:30:40 +08:00 committed by GitHub
parent 7ec4ba7067
commit 3e21030536
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 157 additions and 262 deletions

View File

@ -1,10 +1,11 @@
import { useCallback, useEffect, useRef, useState, ReactNode } from 'react'; import { useEffect, useRef, useState, ReactNode, useCallback } from 'react';
import { LinkedListResponse, LinkedPaginationProps } from '../common/fetch/type'; import { LinkedListResponse, LinkedPaginationProps } from '../common/fetch/type';
import { Box, BoxProps } from '@chakra-ui/react'; import { Box, BoxProps } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { useScroll, useMemoizedFn, useDebounceEffect } from 'ahooks'; import { useScroll, useMemoizedFn, useDebounceEffect } from 'ahooks';
import MyBox from '../components/common/MyBox'; import MyBox from '../components/common/MyBox';
import { useRequest2 } from './useRequest'; import { useRequest2 } from './useRequest';
import { delay } from '../../global/common/system/utils';
const threshold = 100; const threshold = 100;
@ -14,92 +15,95 @@ export function useLinkedScroll<
>( >(
api: (data: TParams) => Promise<TData>, api: (data: TParams) => Promise<TData>,
{ {
refreshDeps = [],
pageSize = 15, pageSize = 15,
params = {}, params = {},
initialId, currentData
initialIndex,
canLoadData = false
}: { }: {
refreshDeps?: any[];
pageSize?: number; pageSize?: number;
params?: Record<string, any>; params?: Record<string, any>;
initialId?: string; currentData?: { id: string; index: number };
initialIndex?: number;
canLoadData?: boolean;
} }
) { ) {
const { t } = useTranslation(); const { t } = useTranslation();
const [dataList, setDataList] = useState<TData['list']>([]); const [dataList, setDataList] = useState<TData['list']>([]);
const [hasMorePrev, setHasMorePrev] = useState(true); const [hasMorePrev, setHasMorePrev] = useState(true);
const [hasMoreNext, setHasMoreNext] = useState(true); const [hasMoreNext, setHasMoreNext] = useState(true);
const [initialLoadDone, setInitialLoadDone] = useState(false);
const hasScrolledToInitial = useRef(false);
const anchorRef = useRef({ const anchorRef = useRef({
top: null as { _id: string; index: number } | null, top: null as { _id: string; index: number } | null,
bottom: null as { _id: string; index: number } | null bottom: null as { _id: string; index: number } | null
}); });
const containerRef = useRef<HTMLDivElement>(null); const containerRef = useRef<HTMLDivElement>(null);
const itemRefs = useRef<(HTMLElement | null)[]>([]); const itemRefs = useRef<(HTMLElement | null)[]>([]);
const { runAsync: callApi, loading: isLoading } = useRequest2( const scrollToItem = async (id: string, retry = 3) => {
async (apiParams: TParams) => await api(apiParams), const itemIndex = dataList.findIndex((item) => item._id === id);
{ if (itemIndex === -1) return;
onError: (error) => {
return Promise.reject(error);
}
}
);
const loadData = useCallback( const element = itemRefs.current[itemIndex];
async ({
id, if (!element || !containerRef.current) {
index, if (retry > 0) {
isInitialLoad = false await delay(500);
}: { return scrollToItem(id, retry - 1);
id: string; }
index: number; return;
isInitialLoad?: boolean; }
}) => {
if (isLoading) return null; const elementRect = element.getBoundingClientRect();
const containerRect = containerRef.current.getBoundingClientRect();
const scrollTop = containerRef.current.scrollTop + elementRect.top - containerRect.top;
containerRef.current.scrollTo({
top: scrollTop
});
};
const { runAsync: callApi, loading: isLoading } = useRequest2(api);
let scroolSign = useRef(false);
const { runAsync: loadInitData } = useRequest2(
async (scrollWhenFinish = true) => {
if (!currentData || isLoading) return;
const item = dataList.find((item) => item._id === currentData.id);
if (item) {
scrollToItem(item._id);
return;
}
const response = await callApi({ const response = await callApi({
initialId: id, initialId: currentData.id,
initialIndex: index, initialIndex: currentData.index,
pageSize, pageSize,
isInitialLoad,
...params ...params
} as TParams); } as TParams);
if (!response) return null;
setHasMorePrev(response.hasMorePrev); setHasMorePrev(response.hasMorePrev);
setHasMoreNext(response.hasMoreNext); setHasMoreNext(response.hasMoreNext);
scroolSign.current = scrollWhenFinish;
setDataList(response.list); setDataList(response.list);
if (response.list.length > 0) { if (response.list.length > 0) {
anchorRef.current.top = response.list[0]; anchorRef.current.top = response.list[0];
anchorRef.current.bottom = response.list[response.list.length - 1]; anchorRef.current.bottom = response.list[response.list.length - 1];
} }
setInitialLoadDone(true);
const scrollIndex = response.list.findIndex((item) => item._id === id);
if (scrollIndex !== -1 && itemRefs.current?.[scrollIndex]) {
setTimeout(() => {
scrollToItem(scrollIndex);
}, 100);
}
return response;
}, },
[callApi, params, dataList, hasMorePrev, hasMoreNext, isLoading] {
refreshDeps: [currentData],
manual: false
}
); );
useEffect(() => {
if (scroolSign.current && currentData) {
scroolSign.current = false;
scrollToItem(currentData.id);
}
}, [dataList]);
const loadPrevData = useCallback( const { runAsync: loadPrevData, loading: prevLoading } = useRequest2(
async (scrollRef = containerRef) => { async (scrollRef = containerRef) => {
if (!anchorRef.current.top || !hasMorePrev || isLoading) return; if (!anchorRef.current.top || !hasMorePrev || isLoading) return;
@ -132,10 +136,12 @@ export function useLinkedScroll<
return response; return response;
}, },
[callApi, hasMorePrev, isLoading, params, pageSize] {
refreshDeps: [hasMorePrev, isLoading, params, pageSize]
}
); );
const loadNextData = useCallback( const { runAsync: loadNextData, loading: nextLoading } = useRequest2(
async (scrollRef = containerRef) => { async (scrollRef = containerRef) => {
if (!anchorRef.current.bottom || !hasMoreNext || isLoading) return; if (!anchorRef.current.bottom || !hasMoreNext || isLoading) return;
@ -165,85 +171,17 @@ export function useLinkedScroll<
return response; return response;
}, },
[callApi, hasMoreNext, isLoading, params, pageSize] {
); refreshDeps: [hasMoreNext, isLoading, params, pageSize]
const scrollToItem = useCallback(
(itemIndex: number) => {
if (itemIndex >= 0 && itemIndex < dataList.length && itemRefs.current?.[itemIndex]) {
try {
const element = itemRefs.current[itemIndex];
if (!element) {
return false;
}
setTimeout(() => {
if (element && containerRef.current) {
const elementRect = element.getBoundingClientRect();
const containerRect = containerRef.current.getBoundingClientRect();
const relativeTop = elementRect.top - containerRect.top;
const scrollTop =
containerRef.current.scrollTop +
relativeTop -
containerRect.height / 2 +
elementRect.height / 2;
containerRef.current.scrollTo({
top: scrollTop,
behavior: 'smooth'
});
}
}, 50);
return true;
} catch (error) {
console.error('Error scrolling to item:', error);
return false;
}
}
return false;
},
[dataList.length]
);
// 初始加载
useEffect(() => {
if (canLoadData) {
setInitialLoadDone(false);
hasScrolledToInitial.current = false;
loadData({
id: initialId || '',
index: initialIndex || 0,
isInitialLoad: true
});
} }
}, [canLoadData, ...refreshDeps]); );
// 监听初始加载完成,执行初始滚动
useEffect(() => {
if (initialLoadDone && dataList.length > 0 && !hasScrolledToInitial.current) {
const foundIndex = dataList.findIndex((item) => item._id === initialId);
if (foundIndex >= 0) {
hasScrolledToInitial.current = true;
setTimeout(() => {
scrollToItem(foundIndex);
}, 200);
}
}
}, [initialLoadDone, ...refreshDeps]);
const ScrollData = useMemoizedFn( const ScrollData = useMemoizedFn(
({ ({
children, children,
ScrollContainerRef, ScrollContainerRef,
isLoading: externalLoading,
...props ...props
}: { }: {
isLoading?: boolean;
children: ReactNode; children: ReactNode;
ScrollContainerRef?: React.RefObject<HTMLDivElement>; ScrollContainerRef?: React.RefObject<HTMLDivElement>;
} & BoxProps) => { } & BoxProps) => {
@ -252,17 +190,17 @@ export function useLinkedScroll<
useDebounceEffect( useDebounceEffect(
() => { () => {
if (!ref?.current || isLoading || !initialLoadDone) return; if (!ref?.current || isLoading) return;
const { scrollTop, scrollHeight, clientHeight } = ref.current; const { scrollTop, scrollHeight, clientHeight } = ref.current;
// 滚动到底部附近,加载更多下方数据 // 滚动到底部附近,加载更多下方数据
if (scrollTop + clientHeight >= scrollHeight - threshold && hasMoreNext) { if (scrollTop + clientHeight >= scrollHeight - threshold) {
loadNextData(ref); loadNextData(ref);
} }
// 滚动到顶部附近,加载更多上方数据 // 滚动到顶部附近,加载更多上方数据
if (scrollTop <= threshold && hasMorePrev) { if (scrollTop <= threshold) {
loadPrevData(ref); loadPrevData(ref);
} }
}, },
@ -271,20 +209,14 @@ export function useLinkedScroll<
); );
return ( return (
<MyBox <MyBox ref={ref} h={'100%'} overflow={'auto'} isLoading={isLoading} {...props}>
ref={ref} {hasMorePrev && prevLoading && (
h={'100%'}
overflow={'auto'}
isLoading={externalLoading || isLoading}
{...props}
>
{hasMorePrev && isLoading && initialLoadDone && (
<Box mt={2} fontSize={'xs'} color={'blackAlpha.500'} textAlign={'center'}> <Box mt={2} fontSize={'xs'} color={'blackAlpha.500'} textAlign={'center'}>
{t('common:common.is_requesting')} {t('common:common.is_requesting')}
</Box> </Box>
)} )}
{children} {children}
{hasMoreNext && isLoading && initialLoadDone && ( {hasMoreNext && nextLoading && (
<Box mt={2} fontSize={'xs'} color={'blackAlpha.500'} textAlign={'center'}> <Box mt={2} fontSize={'xs'} color={'blackAlpha.500'} textAlign={'center'}>
{t('common:common.is_requesting')} {t('common:common.is_requesting')}
</Box> </Box>
@ -298,7 +230,7 @@ export function useLinkedScroll<
dataList, dataList,
setDataList, setDataList,
isLoading, isLoading,
loadData, loadInitData,
ScrollData, ScrollData,
itemRefs, itemRefs,
scrollToItem scrollToItem

View File

@ -18,6 +18,7 @@
"contextual_preview": "Contextual Preview {{num}} Items", "contextual_preview": "Contextual Preview {{num}} Items",
"csv_input_lexicon_tip": "Only CSV batch import is supported, click to download the template", "csv_input_lexicon_tip": "Only CSV batch import is supported, click to download the template",
"custom_input_guide_url": "Custom Lexicon URL", "custom_input_guide_url": "Custom Lexicon URL",
"data_source": "Source Dataset: {{name}}",
"dataset_quote_type error": "Knowledge base reference type is wrong, correct type: { datasetId: string }[]", "dataset_quote_type error": "Knowledge base reference type is wrong, correct type: { datasetId: string }[]",
"delete_all_input_guide_confirm": "Are you sure you want to clear the input guide lexicon?", "delete_all_input_guide_confirm": "Are you sure you want to clear the input guide lexicon?",
"download_chunks": "Download data", "download_chunks": "Download data",

View File

@ -457,7 +457,6 @@
"core.chat.quote.Read Quote": "View Quote", "core.chat.quote.Read Quote": "View Quote",
"core.chat.quote.afterUpdate": "After update", "core.chat.quote.afterUpdate": "After update",
"core.chat.quote.beforeUpdate": "Before update", "core.chat.quote.beforeUpdate": "Before update",
"core.chat.quote.source": "From: {{source}}",
"core.chat.response.Complete Response": "Complete Response", "core.chat.response.Complete Response": "Complete Response",
"core.chat.response.Extension model": "Question Optimization Model", "core.chat.response.Extension model": "Question Optimization Model",
"core.chat.response.Read complete response": "View Details", "core.chat.response.Read complete response": "View Details",

View File

@ -18,6 +18,7 @@
"contextual_preview": "上下文预览 {{num}} 条", "contextual_preview": "上下文预览 {{num}} 条",
"csv_input_lexicon_tip": "仅支持 CSV 批量导入,点击下载模板", "csv_input_lexicon_tip": "仅支持 CSV 批量导入,点击下载模板",
"custom_input_guide_url": "自定义词库地址", "custom_input_guide_url": "自定义词库地址",
"data_source": "来源知识库: {{name}}",
"dataset_quote_type error": "知识库引用类型错误,正确类型:{ datasetId: string }[]", "dataset_quote_type error": "知识库引用类型错误,正确类型:{ datasetId: string }[]",
"delete_all_input_guide_confirm": "确定要清空输入引导词库吗?", "delete_all_input_guide_confirm": "确定要清空输入引导词库吗?",
"download_chunks": "下载数据", "download_chunks": "下载数据",

View File

@ -460,7 +460,6 @@
"core.chat.quote.Read Quote": "查看引用", "core.chat.quote.Read Quote": "查看引用",
"core.chat.quote.afterUpdate": "更新后", "core.chat.quote.afterUpdate": "更新后",
"core.chat.quote.beforeUpdate": "更新前", "core.chat.quote.beforeUpdate": "更新前",
"core.chat.quote.source": "来源:{{source}}",
"core.chat.response.Complete Response": "完整响应", "core.chat.response.Complete Response": "完整响应",
"core.chat.response.Extension model": "问题优化模型", "core.chat.response.Extension model": "问题优化模型",
"core.chat.response.Read complete response": "查看详情", "core.chat.response.Read complete response": "查看详情",

View File

@ -18,6 +18,7 @@
"contextual_preview": "上下文預覽 {{num}} 筆", "contextual_preview": "上下文預覽 {{num}} 筆",
"csv_input_lexicon_tip": "僅支援 CSV 批次匯入,點選下載範本", "csv_input_lexicon_tip": "僅支援 CSV 批次匯入,點選下載範本",
"custom_input_guide_url": "自訂詞彙庫網址", "custom_input_guide_url": "自訂詞彙庫網址",
"data_source": "來源知識庫: {{name}}",
"dataset_quote_type error": "知識庫引用類型錯誤,正確類型:{ datasetId: string }[]", "dataset_quote_type error": "知識庫引用類型錯誤,正確類型:{ datasetId: string }[]",
"delete_all_input_guide_confirm": "確定要清除輸入導引詞彙庫嗎?", "delete_all_input_guide_confirm": "確定要清除輸入導引詞彙庫嗎?",
"download_chunks": "下載數據", "download_chunks": "下載數據",

View File

@ -456,7 +456,6 @@
"core.chat.quote.Read Quote": "檢視引用", "core.chat.quote.Read Quote": "檢視引用",
"core.chat.quote.afterUpdate": "更新後", "core.chat.quote.afterUpdate": "更新後",
"core.chat.quote.beforeUpdate": "更新前", "core.chat.quote.beforeUpdate": "更新前",
"core.chat.quote.source": "來源:{{source}}",
"core.chat.response.Complete Response": "完整回應", "core.chat.response.Complete Response": "完整回應",
"core.chat.response.Extension model": "問題最佳化模型", "core.chat.response.Extension model": "問題最佳化模型",
"core.chat.response.Read complete response": "檢視詳細資料", "core.chat.response.Read complete response": "檢視詳細資料",

View File

@ -175,10 +175,7 @@ const CollectionQuoteItem = ({
{editInputData && ( {editInputData && (
<InputDataModal <InputDataModal
onClose={() => setEditInputData(undefined)} onClose={() => setEditInputData(undefined)}
onSuccess={() => { onSuccess={refreshList}
console.log('onSuccess');
refreshList();
}}
dataId={editInputData.dataId} dataId={editInputData.dataId}
collectionId={editInputData.collectionId} collectionId={editInputData.collectionId}
/> />

View File

@ -7,7 +7,7 @@ import { useTranslation } from 'react-i18next';
import DownloadButton from './DownloadButton'; import DownloadButton from './DownloadButton';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import { downloadFetch } from '@/web/common/system/utils'; import { downloadFetch } from '@/web/common/system/utils';
import { useCallback, useEffect, useMemo, useState } from 'react'; import { useMemo, useState } from 'react';
import { getDatasetDataPermission } from '@/web/core/dataset/api'; import { getDatasetDataPermission } from '@/web/core/dataset/api';
import ScoreTag from './ScoreTag'; import ScoreTag from './ScoreTag';
import { formatScore } from '@/components/core/dataset/QuoteItem'; import { formatScore } from '@/components/core/dataset/QuoteItem';
@ -39,51 +39,53 @@ const CollectionReader = ({
const [quoteIndex, setQuoteIndex] = useState(0); const [quoteIndex, setQuoteIndex] = useState(0);
// Get dataset permission // Get dataset permission
const { data: datasetData, loading: isPermissionLoading } = useRequest2( const { data: datasetData } = useRequest2(async () => await getDatasetDataPermission(datasetId), {
async () => await getDatasetDataPermission(datasetId), manual: !userInfo || !datasetId,
{ refreshDeps: [datasetId, userInfo]
manual: !userInfo || !datasetId, });
refreshDeps: [datasetId, userInfo]
}
);
const filterResults = useMemo(() => { const filterResults = useMemo(() => {
const results = rawSearch.filter( setQuoteIndex(0);
(item) => item.collectionId === metadata.collectionId && item.sourceId === metadata.sourceId return rawSearch
); .filter((item) => item.collectionId === collectionId)
.sort((a, b) => (a.chunkIndex || 0) - (b.chunkIndex || 0));
return results.sort((a, b) => (a.chunkIndex || 0) - (b.chunkIndex || 0)); }, [collectionId, rawSearch]);
}, [metadata, rawSearch]); const currentQuoteItem = useMemo(() => {
const item = filterResults[quoteIndex];
const currentQuoteItem = filterResults[quoteIndex]; if (item) {
return {
id: item.id,
index: item.chunkIndex,
score: item.score
};
}
}, [filterResults, quoteIndex]);
// Get quote list // Get quote list
const { const params = useMemo(
dataList: datasetDataList, () => ({
setDataList: setDatasetDataList,
isLoading,
loadData,
ScrollData,
itemRefs,
scrollToItem
} = useLinkedScroll(getCollectionQuote, {
refreshDeps: [collectionId],
params: {
collectionId, collectionId,
chatItemDataId, chatItemDataId,
chatId: metadata.chatId, chatId: metadata.chatId,
appId: metadata.appId, appId: metadata.appId,
...metadata.outLinkAuthData ...metadata.outLinkAuthData
}, }),
initialId: currentQuoteItem?.id, [metadata]
initialIndex: currentQuoteItem?.chunkIndex, );
canLoadData: !!currentQuoteItem?.id && !isPermissionLoading const {
dataList: datasetDataList,
isLoading,
ScrollData,
itemRefs,
loadInitData
} = useLinkedScroll(getCollectionQuote, {
params,
currentData: currentQuoteItem
}); });
const loading = isLoading || isPermissionLoading;
const isDeleted = useMemo( const isDeleted = useMemo(
() => !datasetDataList.find((item) => item._id === currentQuoteItem?.id), () => !isLoading && !datasetDataList.find((item) => item._id === currentQuoteItem?.id),
[datasetDataList, currentQuoteItem?.id] [datasetDataList, currentQuoteItem?.id, isLoading]
); );
const formatedDataList = useMemo( const formatedDataList = useMemo(
@ -101,11 +103,6 @@ const CollectionReader = ({
[currentQuoteItem?.id, datasetDataList, filterResults] [currentQuoteItem?.id, datasetDataList, filterResults]
); );
useEffect(() => {
setQuoteIndex(0);
setDatasetDataList([]);
}, [collectionId, setDatasetDataList]);
const { runAsync: handleDownload } = useRequest2(async () => { const { runAsync: handleDownload } = useRequest2(async () => {
await downloadFetch({ await downloadFetch({
url: '/api/core/dataset/collection/export', url: '/api/core/dataset/collection/export',
@ -119,30 +116,6 @@ const CollectionReader = ({
const handleRead = getCollectionSourceAndOpen(metadata); const handleRead = getCollectionSourceAndOpen(metadata);
const handleNavigate = useCallback(
async (targetIndex: number) => {
if (targetIndex < 0 || targetIndex >= filterResults.length) return;
const targetItemId = filterResults[targetIndex].id;
const targetItemIndex = filterResults[targetIndex].chunkIndex;
setQuoteIndex(targetIndex);
const dataIndex = datasetDataList.findIndex((item) => item._id === targetItemId);
if (dataIndex !== -1) {
setTimeout(() => {
scrollToItem(dataIndex);
}, 50);
} else {
try {
await loadData({ id: targetItemId, index: targetItemIndex });
} catch (error) {
console.error('Failed to navigate:', error);
}
}
},
[filterResults, datasetDataList, scrollToItem, loadData]
);
return ( return (
<MyBox display={'flex'} flexDirection={'column'} h={'full'}> <MyBox display={'flex'} flexDirection={'column'} h={'full'}>
{/* title */} {/* title */}
@ -163,6 +136,16 @@ const CollectionReader = ({
fontSize={'sm'} fontSize={'sm'}
color={'myGray.900'} color={'myGray.900'}
fontWeight={'medium'} fontWeight={'medium'}
{...(!!userInfo &&
datasetData?.permission?.hasReadPer && {
cursor: 'pointer',
_hover: { color: 'primary.600', textDecoration: 'underline' },
onClick: () => {
router.push(
`/dataset/detail?datasetId=${datasetId}&currentTab=dataCard&collectionId=${collectionId}`
);
}
})}
> >
{sourceName || t('common:common.UnKnow Source')} {sourceName || t('common:common.UnKnow Source')}
</Box> </Box>
@ -181,26 +164,22 @@ const CollectionReader = ({
onClick={onClose} onClick={onClose}
/> />
</HStack> </HStack>
{!isPermissionLoading && ( {datasetData?.permission?.hasReadPer && (
<Box <Box
fontSize={'mini'} fontSize={'mini'}
color={'myGray.500'} color={'myGray.500'}
onClick={() => { {...(!!userInfo
if (!!userInfo && datasetData?.permission?.hasReadPer) {
router.push(
`/dataset/detail?datasetId=${datasetId}&currentTab=dataCard&collectionId=${collectionId}`
);
}
}}
{...(!!userInfo && datasetData?.permission?.hasReadPer
? { ? {
cursor: 'pointer', cursor: 'pointer',
_hover: { color: 'primary.600', textDecoration: 'underline' } _hover: { color: 'primary.600', textDecoration: 'underline' },
onClick: () => {
router.push(`/dataset/detail?datasetId=${datasetId}`);
}
} }
: {})} : {})}
> >
{t('common:core.chat.quote.source', { {t('chat:data_source', {
source: datasetData?.datasetName name: datasetData.datasetName
})} })}
</Box> </Box>
)} )}
@ -231,23 +210,22 @@ const CollectionReader = ({
</Flex> </Flex>
{/* 检索分数 */} {/* 检索分数 */}
{!loading && {currentQuoteItem?.score ? (
(!isDeleted ? ( <ScoreTag {...formatScore(currentQuoteItem?.score)} />
<ScoreTag {...formatScore(currentQuoteItem?.score)} /> ) : isDeleted ? (
) : ( <Flex
<Flex borderRadius={'sm'}
borderRadius={'sm'} py={1}
py={1} px={2}
px={2} color={'red.600'}
color={'red.600'} bg={'red.50'}
bg={'red.50'} alignItems={'center'}
alignItems={'center'} fontSize={'11px'}
fontSize={'11px'} >
> <MyIcon name="common/info" w={'14px'} mr={1} color={'red.600'} />
<MyIcon name="common/info" w={'14px'} mr={1} color={'red.600'} /> {t('chat:chat.quote.deleted')}
{t('chat:chat.quote.deleted')} </Flex>
</Flex> ) : null}
))}
<Box flex={1} /> <Box flex={1} />
@ -256,12 +234,12 @@ const CollectionReader = ({
<NavButton <NavButton
direction="up" direction="up"
isDisabled={quoteIndex === 0} isDisabled={quoteIndex === 0}
onClick={() => handleNavigate(quoteIndex - 1)} onClick={() => setQuoteIndex(quoteIndex - 1)}
/> />
<NavButton <NavButton
direction="down" direction="down"
isDisabled={quoteIndex === filterResults.length - 1} isDisabled={quoteIndex === filterResults.length - 1}
onClick={() => handleNavigate(quoteIndex + 1)} onClick={() => setQuoteIndex(quoteIndex + 1)}
/> />
</Flex> </Flex>
</Flex> </Flex>
@ -272,8 +250,8 @@ const CollectionReader = ({
)} )}
{/* quote list */} {/* quote list */}
{loading || datasetDataList.length > 0 ? ( {isLoading || datasetDataList.length > 0 ? (
<ScrollData flex={'1 0 0'} mt={2} px={5} py={1} isLoading={loading}> <ScrollData flex={'1 0 0'} mt={2} px={5} py={1}>
<Flex flexDir={'column'}> <Flex flexDir={'column'}>
{formatedDataList.map((item, index) => ( {formatedDataList.map((item, index) => (
<CollectionQuoteItem <CollectionQuoteItem
@ -282,10 +260,7 @@ const CollectionReader = ({
quoteRefs={itemRefs as React.MutableRefObject<(HTMLDivElement | null)[]>} quoteRefs={itemRefs as React.MutableRefObject<(HTMLDivElement | null)[]>}
quoteIndex={item.quoteIndex} quoteIndex={item.quoteIndex}
setQuoteIndex={setQuoteIndex} setQuoteIndex={setQuoteIndex}
refreshList={() => refreshList={() => loadInitData(false)}
currentQuoteItem?.id &&
loadData({ id: currentQuoteItem.id, index: currentQuoteItem.chunkIndex })
}
updated={item.updated} updated={item.updated}
isCurrentSelected={item.isCurrentSelected} isCurrentSelected={item.isCurrentSelected}
q={item.q} q={item.q}

View File

@ -13,7 +13,6 @@ export type GetCollectionQuoteProps = LinkedPaginationProps & {
chatId: string; chatId: string;
chatItemDataId: string; chatItemDataId: string;
isInitialLoad: boolean;
collectionId: string; collectionId: string;
appId: string; appId: string;
@ -37,7 +36,6 @@ async function handler(
prevIndex, prevIndex,
nextId, nextId,
nextIndex, nextIndex,
isInitialLoad,
collectionId, collectionId,
chatItemDataId, chatItemDataId,
@ -84,7 +82,6 @@ async function handler(
initialIndex, initialIndex,
pageSize: limitedPageSize, pageSize: limitedPageSize,
chatTime: chatItem.time, chatTime: chatItem.time,
isInitialLoad,
baseMatch baseMatch
}); });
} }
@ -111,14 +108,12 @@ async function handleInitialLoad({
initialIndex, initialIndex,
pageSize, pageSize,
chatTime, chatTime,
isInitialLoad,
baseMatch baseMatch
}: { }: {
initialId: string; initialId: string;
initialIndex: number; initialIndex: number;
pageSize: number; pageSize: number;
chatTime: Date; chatTime: Date;
isInitialLoad: boolean;
baseMatch: BaseMatchType; baseMatch: BaseMatchType;
}): Promise<GetCollectionQuoteRes> { }): Promise<GetCollectionQuoteRes> {
const centerNode = await MongoDatasetData.findOne( const centerNode = await MongoDatasetData.findOne(
@ -129,22 +124,18 @@ async function handleInitialLoad({
).lean(); ).lean();
if (!centerNode) { if (!centerNode) {
if (isInitialLoad) { const list = await MongoDatasetData.find(baseMatch, quoteDataFieldSelector)
const list = await MongoDatasetData.find(baseMatch, quoteDataFieldSelector) .sort({ chunkIndex: 1, _id: -1 })
.sort({ chunkIndex: 1, _id: -1 }) .limit(pageSize)
.limit(pageSize) .lean();
.lean();
const hasMoreNext = list.length === pageSize; const hasMoreNext = list.length === pageSize;
return { return {
list: processChatTimeFilter(list, chatTime), list: processChatTimeFilter(list, chatTime),
hasMorePrev: false, hasMorePrev: false,
hasMoreNext hasMoreNext
}; };
}
return Promise.reject('centerNode not found');
} }
const prevHalfSize = Math.floor(pageSize / 2); const prevHalfSize = Math.floor(pageSize / 2);