Feat list query (#21907)
This commit is contained in:
@@ -0,0 +1,83 @@
|
|||||||
|
import { type ReadonlyURLSearchParams, usePathname, useRouter, useSearchParams } from 'next/navigation'
|
||||||
|
import { useCallback, useMemo } from 'react'
|
||||||
|
|
||||||
|
export type DocumentListQuery = {
|
||||||
|
page: number
|
||||||
|
limit: number
|
||||||
|
keyword: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEFAULT_QUERY: DocumentListQuery = {
|
||||||
|
page: 1,
|
||||||
|
limit: 10,
|
||||||
|
keyword: '',
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the query parameters from the URL search string.
|
||||||
|
function parseParams(params: ReadonlyURLSearchParams): DocumentListQuery {
|
||||||
|
const page = Number.parseInt(params.get('page') || '1', 10)
|
||||||
|
const limit = Number.parseInt(params.get('limit') || '10', 10)
|
||||||
|
const keyword = params.get('keyword') || ''
|
||||||
|
|
||||||
|
return {
|
||||||
|
page: page > 0 ? page : 1,
|
||||||
|
limit: (limit > 0 && limit <= 100) ? limit : 10,
|
||||||
|
keyword: keyword ? decodeURIComponent(keyword) : '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the URL search string with the given query parameters.
|
||||||
|
function updateSearchParams(query: DocumentListQuery, searchParams: URLSearchParams) {
|
||||||
|
const { page, limit, keyword } = query || {}
|
||||||
|
|
||||||
|
const hasNonDefaultParams = (page && page > 1) || (limit && limit !== 10) || (keyword && keyword.trim())
|
||||||
|
|
||||||
|
if (hasNonDefaultParams) {
|
||||||
|
searchParams.set('page', (page || 1).toString())
|
||||||
|
searchParams.set('limit', (limit || 10).toString())
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
searchParams.delete('page')
|
||||||
|
searchParams.delete('limit')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyword && keyword.trim())
|
||||||
|
searchParams.set('keyword', encodeURIComponent(keyword))
|
||||||
|
else
|
||||||
|
searchParams.delete('keyword')
|
||||||
|
}
|
||||||
|
|
||||||
|
function useDocumentListQueryState() {
|
||||||
|
const searchParams = useSearchParams()
|
||||||
|
const query = useMemo(() => parseParams(searchParams), [searchParams])
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
const pathname = usePathname()
|
||||||
|
|
||||||
|
// Helper function to update specific query parameters
|
||||||
|
const updateQuery = useCallback((updates: Partial<DocumentListQuery>) => {
|
||||||
|
const newQuery = { ...query, ...updates }
|
||||||
|
const params = new URLSearchParams()
|
||||||
|
updateSearchParams(newQuery, params)
|
||||||
|
const search = params.toString()
|
||||||
|
const queryString = search ? `?${search}` : ''
|
||||||
|
router.push(`${pathname}${queryString}`, { scroll: false })
|
||||||
|
}, [query, router, pathname])
|
||||||
|
|
||||||
|
// Helper function to reset query to defaults
|
||||||
|
const resetQuery = useCallback(() => {
|
||||||
|
const params = new URLSearchParams()
|
||||||
|
updateSearchParams(DEFAULT_QUERY, params)
|
||||||
|
const search = params.toString()
|
||||||
|
const queryString = search ? `?${search}` : ''
|
||||||
|
router.push(`${pathname}${queryString}`, { scroll: false })
|
||||||
|
}, [router, pathname])
|
||||||
|
|
||||||
|
return useMemo(() => ({
|
||||||
|
query,
|
||||||
|
updateQuery,
|
||||||
|
resetQuery,
|
||||||
|
}), [query, updateQuery, resetQuery])
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useDocumentListQueryState
|
@@ -26,6 +26,7 @@ import cn from '@/utils/classnames'
|
|||||||
import { useDocumentList, useInvalidDocumentDetailKey, useInvalidDocumentList } from '@/service/knowledge/use-document'
|
import { useDocumentList, useInvalidDocumentDetailKey, useInvalidDocumentList } from '@/service/knowledge/use-document'
|
||||||
import { useInvalid } from '@/service/use-base'
|
import { useInvalid } from '@/service/use-base'
|
||||||
import { useChildSegmentListKey, useSegmentListKey } from '@/service/knowledge/use-segment'
|
import { useChildSegmentListKey, useSegmentListKey } from '@/service/knowledge/use-segment'
|
||||||
|
import useDocumentListQueryState from './hooks/use-document-list-query-state'
|
||||||
import useEditDocumentMetadata from '../metadata/hooks/use-edit-dataset-metadata'
|
import useEditDocumentMetadata from '../metadata/hooks/use-edit-dataset-metadata'
|
||||||
import DatasetMetadataDrawer from '../metadata/metadata-dataset/dataset-metadata-drawer'
|
import DatasetMetadataDrawer from '../metadata/metadata-dataset/dataset-metadata-drawer'
|
||||||
import StatusWithAction from '../common/document-status-with-action/status-with-action'
|
import StatusWithAction from '../common/document-status-with-action/status-with-action'
|
||||||
@@ -82,7 +83,6 @@ type IDocumentsProps = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const fetcher = (url: string) => get(url, {}, {})
|
export const fetcher = (url: string) => get(url, {}, {})
|
||||||
const DEFAULT_LIMIT = 10
|
|
||||||
|
|
||||||
const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
|
const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
@@ -91,8 +91,12 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
|
|||||||
const isFreePlan = plan.type === 'sandbox'
|
const isFreePlan = plan.type === 'sandbox'
|
||||||
const [inputValue, setInputValue] = useState<string>('') // the input value
|
const [inputValue, setInputValue] = useState<string>('') // the input value
|
||||||
const [searchValue, setSearchValue] = useState<string>('')
|
const [searchValue, setSearchValue] = useState<string>('')
|
||||||
const [currPage, setCurrPage] = React.useState<number>(0)
|
|
||||||
const [limit, setLimit] = useState<number>(DEFAULT_LIMIT)
|
// Use the new hook for URL state management
|
||||||
|
const { query, updateQuery } = useDocumentListQueryState()
|
||||||
|
const [currPage, setCurrPage] = React.useState<number>(query.page - 1) // Convert to 0-based index
|
||||||
|
const [limit, setLimit] = useState<number>(query.limit)
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { dataset } = useDatasetDetailContext()
|
const { dataset } = useDatasetDetailContext()
|
||||||
const [notionPageSelectorModalVisible, setNotionPageSelectorModalVisible] = useState(false)
|
const [notionPageSelectorModalVisible, setNotionPageSelectorModalVisible] = useState(false)
|
||||||
@@ -103,6 +107,45 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
|
|||||||
const embeddingAvailable = !!dataset?.embedding_available
|
const embeddingAvailable = !!dataset?.embedding_available
|
||||||
const debouncedSearchValue = useDebounce(searchValue, { wait: 500 })
|
const debouncedSearchValue = useDebounce(searchValue, { wait: 500 })
|
||||||
|
|
||||||
|
// Initialize search value from URL on mount
|
||||||
|
useEffect(() => {
|
||||||
|
if (query.keyword) {
|
||||||
|
setInputValue(query.keyword)
|
||||||
|
setSearchValue(query.keyword)
|
||||||
|
}
|
||||||
|
}, []) // Only run on mount
|
||||||
|
|
||||||
|
// Sync local state with URL query changes
|
||||||
|
useEffect(() => {
|
||||||
|
setCurrPage(query.page - 1)
|
||||||
|
setLimit(query.limit)
|
||||||
|
if (query.keyword !== searchValue) {
|
||||||
|
setInputValue(query.keyword)
|
||||||
|
setSearchValue(query.keyword)
|
||||||
|
}
|
||||||
|
}, [query])
|
||||||
|
|
||||||
|
// Update URL when pagination changes
|
||||||
|
const handlePageChange = (newPage: number) => {
|
||||||
|
setCurrPage(newPage)
|
||||||
|
updateQuery({ page: newPage + 1 }) // Convert to 1-based index
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update URL when limit changes
|
||||||
|
const handleLimitChange = (newLimit: number) => {
|
||||||
|
setLimit(newLimit)
|
||||||
|
setCurrPage(0) // Reset to first page when limit changes
|
||||||
|
updateQuery({ limit: newLimit, page: 1 })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update URL when search changes
|
||||||
|
useEffect(() => {
|
||||||
|
if (debouncedSearchValue !== query.keyword) {
|
||||||
|
setCurrPage(0) // Reset to first page when search changes
|
||||||
|
updateQuery({ keyword: debouncedSearchValue, page: 1 })
|
||||||
|
}
|
||||||
|
}, [debouncedSearchValue, query.keyword, updateQuery])
|
||||||
|
|
||||||
const { data: documentsRes, isFetching: isListLoading } = useDocumentList({
|
const { data: documentsRes, isFetching: isListLoading } = useDocumentList({
|
||||||
datasetId,
|
datasetId,
|
||||||
query: {
|
query: {
|
||||||
@@ -327,9 +370,9 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
|
|||||||
pagination={{
|
pagination={{
|
||||||
total,
|
total,
|
||||||
limit,
|
limit,
|
||||||
onLimitChange: setLimit,
|
onLimitChange: handleLimitChange,
|
||||||
current: currPage,
|
current: currPage,
|
||||||
onChange: setCurrPage,
|
onChange: handlePageChange,
|
||||||
}}
|
}}
|
||||||
onManageMetadata={showEditMetadataModal}
|
onManageMetadata={showEditMetadataModal}
|
||||||
/>
|
/>
|
||||||
|
@@ -598,7 +598,6 @@ const DocumentList: FC<IDocumentListProps> = ({
|
|||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{/* {doc.position} */}
|
|
||||||
{index + 1}
|
{index + 1}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
Reference in New Issue
Block a user