diff --git a/web/src/hooks/chunk-hooks.ts b/web/src/hooks/chunk-hooks.ts index a5c330907..65433e029 100644 --- a/web/src/hooks/chunk-hooks.ts +++ b/web/src/hooks/chunk-hooks.ts @@ -1,12 +1,17 @@ -import { useCallback } from 'react'; +import { ResponseGetType } from '@/interfaces/database/base'; +import { IChunk, IKnowledgeFile } from '@/interfaces/database/knowledge'; +import kbService from '@/services/knowledge-service'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; +import { useDebounce } from 'ahooks'; +import { PaginationProps } from 'antd'; +import { useCallback, useState } from 'react'; import { useDispatch } from 'umi'; +import { + useGetPaginationWithRouter, + useHandleSearchChange, +} from './logic-hooks'; import { useGetKnowledgeSearchParams } from './route-hook'; -interface PayloadType { - doc_id: string; - keywords?: string; -} - export const useFetchChunkList = () => { const dispatch = useDispatch(); const { documentId } = useGetKnowledgeSearchParams(); @@ -22,3 +27,104 @@ export const useFetchChunkList = () => { return fetchChunkList; }; + +export interface IChunkListResult { + searchString?: string; + handleInputChange?: React.ChangeEventHandler; + pagination: PaginationProps; + setPagination?: (pagination: { page: number; pageSize: number }) => void; + available: number | undefined; + handleSetAvailable: (available: number | undefined) => void; +} + +export const useFetchNextChunkList = (): ResponseGetType<{ + data: IChunk[]; + total: number; + documentInfo: IKnowledgeFile; +}> & + IChunkListResult => { + const { pagination, setPagination } = useGetPaginationWithRouter(); + const { documentId } = useGetKnowledgeSearchParams(); + const { searchString, handleInputChange } = useHandleSearchChange(); + const [available, setAvailable] = useState(); + const debouncedSearchString = useDebounce(searchString, { wait: 500 }); + + const { data, isFetching: loading } = useQuery({ + queryKey: [ + 'fetchChunkList', + documentId, + pagination.current, + pagination.pageSize, + debouncedSearchString, + available, + ], + + initialData: { data: [], total: 0, documentInfo: {} }, + // placeholderData: keepPreviousData, + gcTime: 0, + queryFn: async () => { + const { data } = await kbService.chunk_list({ + doc_id: documentId, + page: pagination.current, + size: pagination.pageSize, + available_int: available, + keywords: searchString, + }); + if (data.retcode === 0) { + const res = data.data; + return { + data: res.chunks, + total: res.total, + documentInfo: res.doc, + }; + } + + return ( + data?.data ?? { + data: [], + total: 0, + documentInfo: {}, + } + ); + }, + }); + + const onInputChange: React.ChangeEventHandler = useCallback( + (e) => { + setPagination({ page: 1 }); + handleInputChange(e); + }, + [handleInputChange, setPagination], + ); + + const handleSetAvailable = useCallback( + (a: number | undefined) => { + setPagination({ page: 1 }); + setAvailable(a); + }, + [setAvailable, setPagination], + ); + + return { + data, + loading, + pagination, + setPagination, + searchString, + handleInputChange: onInputChange, + available, + handleSetAvailable, + }; +}; + +export const useSelectChunkList = () => { + const queryClient = useQueryClient(); + const data = queryClient.getQueriesData<{ + data: IChunk[]; + total: number; + documentInfo: IKnowledgeFile; + }>({ queryKey: ['fetchChunkList'] }); + + // console.log('🚀 ~ useSelectChunkList ~ data:', data); + return data?.at(-1)?.[1]; +}; diff --git a/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-card/index.less b/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-card/index.less index b4ac9050e..02e74426c 100644 --- a/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-card/index.less +++ b/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-card/index.less @@ -17,8 +17,9 @@ .contentEllipsis { .multipleLineEllipsis(3); } + .contentText { - word-break: break-all; + word-break: break-all !important; } .chunkCard { diff --git a/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-toolbar/index.tsx b/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-toolbar/index.tsx index 02edef27a..18d8c76f8 100644 --- a/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-toolbar/index.tsx +++ b/web/src/pages/add-knowledge/components/knowledge-chunk/components/chunk-toolbar/index.tsx @@ -1,5 +1,6 @@ import { ReactComponent as FilterIcon } from '@/assets/filter.svg'; import { KnowledgeRouteKey } from '@/constants/knowledge'; +import { IChunkListResult, useSelectChunkList } from '@/hooks/chunk-hooks'; import { useTranslate } from '@/hooks/common-hooks'; import { useKnowledgeBaseId } from '@/hooks/knowledge-hooks'; import { @@ -27,16 +28,18 @@ import { Space, Typography, } from 'antd'; -import { ChangeEventHandler, useCallback, useMemo, useState } from 'react'; -import { Link, useDispatch, useSelector } from 'umi'; +import { useCallback, useMemo, useState } from 'react'; +import { Link } from 'umi'; import { ChunkTextMode } from '../../constant'; -import { ChunkModelState } from '../../model'; const { Text } = Typography; -interface IProps { +interface IProps + extends Pick< + IChunkListResult, + 'searchString' | 'handleInputChange' | 'available' | 'handleSetAvailable' + > { checked: boolean; - getChunkList: () => void; selectAllChunk: (checked: boolean) => void; createChunk: () => void; removeChunk: () => void; @@ -45,17 +48,19 @@ interface IProps { } const ChunkToolBar = ({ - getChunkList, selectAllChunk, checked, createChunk, removeChunk, switchChunk, changeChunkTextMode, + available, + handleSetAvailable, + searchString, + handleInputChange, }: IProps) => { - const { documentInfo, available, searchString }: ChunkModelState = - useSelector((state: any) => state.chunkModel); - const dispatch = useDispatch(); + const data = useSelectChunkList(); + const documentInfo = data?.documentInfo; const knowledgeBaseId = useKnowledgeBaseId(); const [isShowSearchBox, setIsShowSearchBox] = useState(false); const { t } = useTranslate('chunk'); @@ -71,17 +76,17 @@ const ChunkToolBar = ({ setIsShowSearchBox(true); }; - const handleSearchChange: ChangeEventHandler = (e) => { - const val = e.target.value; - dispatch({ type: 'chunkModel/setSearchString', payload: val }); - dispatch({ - type: 'chunkModel/throttledGetChunkList', - payload: documentInfo.id, - }); - }; + // const handleSearchChange: ChangeEventHandler = (e) => { + // const val = e.target.value; + // dispatch({ type: 'chunkModel/setSearchString', payload: val }); + // dispatch({ + // type: 'chunkModel/throttledGetChunkList', + // payload: documentInfo.id, + // }); + // }; const handleSearchBlur = () => { - if (!searchString.trim()) { + if (!searchString?.trim()) { setIsShowSearchBox(false); } }; @@ -155,8 +160,7 @@ const ChunkToolBar = ({ const handleFilterChange = (e: RadioChangeEvent) => { selectAllChunk(false); - dispatch({ type: 'chunkModel/setAvailable', payload: e.target.value }); - getChunkList(); + handleSetAvailable(e.target.value); }; const filterContent = ( @@ -178,8 +182,8 @@ const ChunkToolBar = ({ - - {documentInfo.name} + + {documentInfo?.name} @@ -202,7 +206,7 @@ const ChunkToolBar = ({ placeholder={t('search')} prefix={} allowClear - onChange={handleSearchChange} + onChange={handleInputChange} onBlur={handleSearchBlur} value={searchString} /> diff --git a/web/src/pages/add-knowledge/components/knowledge-chunk/components/document-preview/preview.tsx b/web/src/pages/add-knowledge/components/knowledge-chunk/components/document-preview/preview.tsx index 14860042c..b8409c1b4 100644 --- a/web/src/pages/add-knowledge/components/knowledge-chunk/components/document-preview/preview.tsx +++ b/web/src/pages/add-knowledge/components/knowledge-chunk/components/document-preview/preview.tsx @@ -1,5 +1,5 @@ import { Skeleton } from 'antd'; -import { useEffect, useRef } from 'react'; +import { memo, useEffect, useRef } from 'react'; import { AreaHighlight, Highlight, @@ -8,7 +8,6 @@ import { PdfLoader, Popup, } from 'react-pdf-highlighter'; -import { useGetChunkHighlights } from '../../hooks'; import { useGetDocumentUrl } from './hooks'; import { useCatchDocumentError } from '@/components/pdf-previewer/hooks'; @@ -16,7 +15,8 @@ import FileError from '@/pages/document-viewer/file-error'; import styles from './index.less'; interface IProps { - selectedChunkId: string; + highlights: IHighlight[]; + setWidthAndHeight: (width: number, height: number) => void; } const HighlightPopup = ({ comment, @@ -30,11 +30,10 @@ const HighlightPopup = ({ ) : null; // TODO: merge with DocumentPreviewer -const Preview = ({ selectedChunkId }: IProps) => { +const Preview = ({ highlights: state, setWidthAndHeight }: IProps) => { const url = useGetDocumentUrl(); useCatchDocumentError(url); - const { highlights: state, setWidthAndHeight } = - useGetChunkHighlights(selectedChunkId); + const ref = useRef<(highlight: IHighlight) => void>(() => {}); const error = useCatchDocumentError(url); @@ -120,4 +119,12 @@ const Preview = ({ selectedChunkId }: IProps) => { ); }; -export default Preview; +const compare = (oldProps: IProps, newProps: IProps) => { + const arePropsEqual = + oldProps.highlights === newProps.highlights || + (oldProps.highlights.length === 0 && newProps.highlights.length === 0); + + return arePropsEqual; +}; + +export default memo(Preview); diff --git a/web/src/pages/add-knowledge/components/knowledge-chunk/hooks.ts b/web/src/pages/add-knowledge/components/knowledge-chunk/hooks.ts index 310d146e0..7f66e2721 100644 --- a/web/src/pages/add-knowledge/components/knowledge-chunk/hooks.ts +++ b/web/src/pages/add-knowledge/components/knowledge-chunk/hooks.ts @@ -1,24 +1,17 @@ +import { useSelectChunkList } from '@/hooks/chunk-hooks'; import { useOneNamespaceEffectsLoading } from '@/hooks/store-hooks'; -import { IChunk, IKnowledgeFile } from '@/interfaces/database/knowledge'; +import { IChunk } from '@/interfaces/database/knowledge'; import { buildChunkHighlights } from '@/utils/document-util'; import { useCallback, useMemo, useState } from 'react'; import { IHighlight } from 'react-pdf-highlighter'; -import { useSelector } from 'umi'; import { ChunkTextMode } from './constant'; -export const useSelectDocumentInfo = () => { - const documentInfo: IKnowledgeFile = useSelector( - (state: any) => state.chunkModel.documentInfo, - ); - return documentInfo; -}; - -export const useSelectChunkList = () => { - const chunkList: IChunk[] = useSelector( - (state: any) => state.chunkModel.data, - ); - return chunkList; -}; +// export const useSelectChunkList = () => { +// const chunkList: IChunk[] = useSelector( +// (state: any) => state.chunkModel.data, +// ); +// return chunkList; +// }; export const useHandleChunkCardClick = () => { const [selectedChunkId, setSelectedChunkId] = useState(''); @@ -31,9 +24,9 @@ export const useHandleChunkCardClick = () => { }; export const useGetSelectedChunk = (selectedChunkId: string) => { - const chunkList: IChunk[] = useSelectChunkList(); + const data = useSelectChunkList(); return ( - chunkList.find((x) => x.chunk_id === selectedChunkId) ?? ({} as IChunk) + data?.data?.find((x) => x.chunk_id === selectedChunkId) ?? ({} as IChunk) ); }; @@ -45,14 +38,14 @@ export const useGetChunkHighlights = (selectedChunkId: string) => { return buildChunkHighlights(selectedChunk, size); }, [selectedChunk, size]); - const setWidthAndHeight = (width: number, height: number) => { + const setWidthAndHeight = useCallback((width: number, height: number) => { setSize((pre) => { if (pre.height !== height || pre.width !== width) { return { height, width }; } return pre; }); - }; + }, []); return { highlights, setWidthAndHeight }; }; diff --git a/web/src/pages/add-knowledge/components/knowledge-chunk/index.tsx b/web/src/pages/add-knowledge/components/knowledge-chunk/index.tsx index f5b8ff57c..b7ade5e5b 100644 --- a/web/src/pages/add-knowledge/components/knowledge-chunk/index.tsx +++ b/web/src/pages/add-knowledge/components/knowledge-chunk/index.tsx @@ -1,45 +1,46 @@ -import { useFetchChunkList } from '@/hooks/chunk-hooks'; +import { useFetchNextChunkList } from '@/hooks/chunk-hooks'; import { useDeleteChunkByIds } from '@/hooks/knowledge-hooks'; import type { PaginationProps } from 'antd'; import { Divider, Flex, Pagination, Space, Spin, message } from 'antd'; import classNames from 'classnames'; import { useCallback, useEffect, useState } from 'react'; -import { useDispatch, useSearchParams, useSelector } from 'umi'; +import { useDispatch, useSearchParams } from 'umi'; import ChunkCard from './components/chunk-card'; import CreatingModal from './components/chunk-creating-modal'; import ChunkToolBar from './components/chunk-toolbar'; import DocumentPreview from './components/document-preview/preview'; import { useChangeChunkTextMode, + useGetChunkHighlights, useHandleChunkCardClick, - useSelectChunkListLoading, - useSelectDocumentInfo, } from './hooks'; -import { ChunkModelState } from './model'; import { useTranslation } from 'react-i18next'; import styles from './index.less'; const Chunk = () => { const dispatch = useDispatch(); - const chunkModel: ChunkModelState = useSelector( - (state: any) => state.chunkModel, - ); + const [selectedChunkIds, setSelectedChunkIds] = useState([]); const [searchParams] = useSearchParams(); - const { data = [], total, pagination } = chunkModel; - const loading = useSelectChunkListLoading(); + // const loading = useSelectChunkListLoading(); const documentId: string = searchParams.get('doc_id') || ''; const [chunkId, setChunkId] = useState(); const { removeChunk } = useDeleteChunkByIds(); - const documentInfo = useSelectDocumentInfo(); + const { + data: { documentInfo, data = [], total }, + pagination, + loading, + searchString, + handleInputChange, + available, + handleSetAvailable, + } = useFetchNextChunkList(); const { handleChunkCardClick, selectedChunkId } = useHandleChunkCardClick(); - const isPdf = documentInfo.type === 'pdf'; + const isPdf = documentInfo?.type === 'pdf'; const { t } = useTranslation(); const { changeChunkTextMode, textMode } = useChangeChunkTextMode(); - const getChunkList = useFetchChunkList(); - const handleEditChunk = useCallback( (chunk_id?: string) => { setChunkId(chunk_id); @@ -57,14 +58,8 @@ const Chunk = () => { size, ) => { setSelectedChunkIds([]); - dispatch({ - type: 'chunkModel/setPagination', - payload: { - current: page, - pageSize: size, - }, - }); - getChunkList(); + pagination.onChange?.(page, size); + // getChunkList(); }; const selectAllChunk = useCallback( @@ -125,38 +120,44 @@ const Chunk = () => { }, }); if (!chunkIds && resCode === 0) { - getChunkList(); + // getChunkList(); } }, [ dispatch, documentId, - getChunkList, + // getChunkList, selectedChunkIds, showSelectedChunkWarning, ], ); + const { highlights, setWidthAndHeight } = + useGetChunkHighlights(selectedChunkId); + useEffect(() => { - getChunkList(); + // getChunkList(); return () => { dispatch({ type: 'chunkModel/resetFilter', // TODO: need to reset state uniformly }); }; - }, [dispatch, getChunkList]); + }, [dispatch]); return ( <>
@@ -193,33 +194,22 @@ const Chunk = () => {
( - - {t('total', { keyPrefix: 'common' })} - {total} - - )} + size={'small'} + onChange={onPaginationChange} />
- {isPdf && ( + {
- )} + }
diff --git a/web/src/pages/force-graph.tsx b/web/src/pages/force-graph.tsx index e69de29bb..c3285abf3 100644 --- a/web/src/pages/force-graph.tsx +++ b/web/src/pages/force-graph.tsx @@ -0,0 +1,33 @@ +import { memo, useState } from 'react'; + +function compare(oldProps, newProps) { + return true; +} + +const Greeting = memo(function Greeting({ name }) { + console.log('Greeting was rendered at', new Date().toLocaleTimeString()); + return ( +

+ Hello{name && ', '} + {name}! +

+ ); +}, compare); + +export default function MyApp() { + const [name, setName] = useState(''); + const [address, setAddress] = useState(''); + return ( + <> + + + + + ); +} diff --git a/web/src/routes.ts b/web/src/routes.ts index 879b6716d..bcb2ce04b 100644 --- a/web/src/routes.ts +++ b/web/src/routes.ts @@ -98,6 +98,11 @@ const routes = [ component: '@/pages/document-viewer', layout: false, }, + { + path: 'force', + component: '@/pages/force-graph', + layout: false, + }, { path: '/*', component: '@/pages/404',