11'use client'
22import type { FC } from 'react'
3- import React , { useRef , useState } from 'react'
4- import { useGetState , useInfiniteScroll } from 'ahooks'
3+ import React , { useEffect , useMemo , useRef , useState } from 'react'
4+ import { useInfiniteScroll } from 'ahooks'
55import { useTranslation } from 'react-i18next'
66import Link from 'next/link'
77import Modal from '@/app/components/base/modal'
88import type { DataSet } from '@/models/datasets'
99import Button from '@/app/components/base/button'
10- import { fetchDatasets } from '@/service/datasets'
1110import Loading from '@/app/components/base/loading'
1211import Badge from '@/app/components/base/badge'
1312import { useKnowledge } from '@/hooks/use-knowledge'
1413import cn from '@/utils/classnames'
1514import AppIcon from '@/app/components/base/app-icon'
15+ import { useInfiniteDatasets } from '@/service/knowledge/use-dataset'
1616import { ModelFeatureEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
1717import FeatureIcon from '@/app/components/header/account-setting/model-provider-page/model-selector/feature-icon'
1818
@@ -30,51 +30,70 @@ const SelectDataSet: FC<ISelectDataSetProps> = ({
3030 onSelect,
3131} ) => {
3232 const { t } = useTranslation ( )
33- const [ selected , setSelected ] = React . useState < DataSet [ ] > ( [ ] )
34- const [ loaded , setLoaded ] = React . useState ( false )
35- const [ datasets , setDataSets ] = React . useState < DataSet [ ] | null > ( null )
36- const [ hasInitialized , setHasInitialized ] = React . useState ( false )
37- const hasNoData = ! datasets || datasets ?. length === 0
33+ const [ selected , setSelected ] = useState < DataSet [ ] > ( [ ] )
3834 const canSelectMulti = true
35+ const { formatIndexingTechniqueAndMethod } = useKnowledge ( )
36+ const { data, isLoading, isFetchingNextPage, fetchNextPage, hasNextPage } = useInfiniteDatasets (
37+ { page : 1 } ,
38+ { enabled : isShow , staleTime : 0 , refetchOnMount : 'always' } ,
39+ )
40+ const pages = data ?. pages || [ ]
41+ const datasets = useMemo ( ( ) => {
42+ return pages . flatMap ( page => page . data . filter ( item => item . indexing_technique || item . provider === 'external' ) )
43+ } , [ pages ] )
44+ const hasNoData = ! isLoading && datasets . length === 0
3945
4046 const listRef = useRef < HTMLDivElement > ( null )
41- const [ page , setPage , getPage ] = useGetState ( 1 )
42- const [ isNoMore , setIsNoMore ] = useState ( false )
43- const { formatIndexingTechniqueAndMethod } = useKnowledge ( )
47+ const isNoMore = hasNextPage === false
4448
4549 useInfiniteScroll (
4650 async ( ) => {
47- if ( ! isNoMore ) {
48- const { data, has_more } = await fetchDatasets ( { url : '/datasets' , params : { page } } )
49- setPage ( getPage ( ) + 1 )
50- setIsNoMore ( ! has_more )
51- const newList = [ ...( datasets || [ ] ) , ...data . filter ( item => item . indexing_technique || item . provider === 'external' ) ]
52- setDataSets ( newList )
53- setLoaded ( true )
54-
55- // Initialize selected datasets based on selectedIds and available datasets
56- if ( ! hasInitialized ) {
57- if ( selectedIds . length > 0 ) {
58- const validSelectedDatasets = selectedIds
59- . map ( id => newList . find ( item => item . id === id ) )
60- . filter ( Boolean ) as DataSet [ ]
61- setSelected ( validSelectedDatasets )
62- }
63- setHasInitialized ( true )
64- }
65- }
51+ if ( ! hasNextPage || isFetchingNextPage )
52+ return { list : [ ] }
53+ await fetchNextPage ( )
6654 return { list : [ ] }
6755 } ,
6856 {
6957 target : listRef ,
70- isNoMore : ( ) => {
71- return isNoMore
72- } ,
73- reloadDeps : [ isNoMore ] ,
58+ isNoMore : ( ) => isNoMore ,
59+ reloadDeps : [ isNoMore , isFetchingNextPage ] ,
7460 } ,
7561 )
7662
63+ const prevSelectedIdsRef = useRef < string [ ] > ( [ ] )
64+ const hasUserModifiedSelectionRef = useRef ( false )
65+ useEffect ( ( ) => {
66+ if ( isShow )
67+ hasUserModifiedSelectionRef . current = false
68+ } , [ isShow ] )
69+ useEffect ( ( ) => {
70+ const prevSelectedIds = prevSelectedIdsRef . current
71+ const idsChanged = selectedIds . length !== prevSelectedIds . length
72+ || selectedIds . some ( ( id , idx ) => id !== prevSelectedIds [ idx ] )
73+
74+ if ( ! selectedIds . length && ( ! hasUserModifiedSelectionRef . current || idsChanged ) ) {
75+ setSelected ( [ ] )
76+ prevSelectedIdsRef . current = selectedIds
77+ hasUserModifiedSelectionRef . current = false
78+ return
79+ }
80+
81+ if ( ! idsChanged && hasUserModifiedSelectionRef . current )
82+ return
83+
84+ setSelected ( ( prev ) => {
85+ const prevMap = new Map ( prev . map ( item => [ item . id , item ] ) )
86+ const nextSelected = selectedIds
87+ . map ( id => datasets . find ( item => item . id === id ) || prevMap . get ( id ) )
88+ . filter ( Boolean ) as DataSet [ ]
89+ return nextSelected
90+ } )
91+ prevSelectedIdsRef . current = selectedIds
92+ hasUserModifiedSelectionRef . current = false
93+ } , [ datasets , selectedIds ] )
94+
7795 const toggleSelect = ( dataSet : DataSet ) => {
96+ hasUserModifiedSelectionRef . current = true
7897 const isSelected = selected . some ( item => item . id === dataSet . id )
7998 if ( isSelected ) {
8099 setSelected ( selected . filter ( item => item . id !== dataSet . id ) )
@@ -98,13 +117,13 @@ const SelectDataSet: FC<ISelectDataSetProps> = ({
98117 className = 'w-[400px]'
99118 title = { t ( 'appDebug.feature.dataSet.selectTitle' ) }
100119 >
101- { ! loaded && (
120+ { ( isLoading && datasets . length === 0 ) && (
102121 < div className = 'flex h-[200px]' >
103122 < Loading type = 'area' />
104123 </ div >
105124 ) }
106125
107- { ( loaded && hasNoData ) && (
126+ { hasNoData && (
108127 < div className = 'mt-6 flex h-[128px] items-center justify-center space-x-1 rounded-lg border text-[13px]'
109128 style = { {
110129 background : 'rgba(0, 0, 0, 0.02)' ,
@@ -116,7 +135,7 @@ const SelectDataSet: FC<ISelectDataSetProps> = ({
116135 </ div >
117136 ) }
118137
119- { datasets && datasets ? .length > 0 && (
138+ { datasets . length > 0 && (
120139 < >
121140 < div ref = { listRef } className = 'mt-7 max-h-[286px] space-y-1 overflow-y-auto' >
122141 { datasets . map ( item => (
@@ -171,7 +190,7 @@ const SelectDataSet: FC<ISelectDataSetProps> = ({
171190 </ div >
172191 </ >
173192 ) }
174- { loaded && (
193+ { ! isLoading && (
175194 < div className = 'mt-8 flex items-center justify-between' >
176195 < div className = 'text-sm font-medium text-text-secondary' >
177196 { selected . length > 0 && `${ selected . length } ${ t ( 'appDebug.feature.dataSet.selected' ) } ` }
0 commit comments