1- import { useEffect , useState } from 'react' ;
1+ import { useEffect , useRef , useState } from 'react' ;
22import { InputNumber , Tooltip , Dropdown } from 'antd' ;
33import { IResultConfig } from '@/typings' ;
44import i18n from '@/i18n' ;
55import _ from 'lodash' ;
66import { IconButton , ToolbarBtn } from '@chat2db/ui' ;
77import LoadingGracile from '@/components/Loading/LoadingGracile' ;
88import { useStyles } from './style' ;
9- import { DownOutlined } from '@ant-design/icons' ;
9+ import { CheckOutlined , DownOutlined } from '@ant-design/icons' ;
10+ import { RESULT_PAGE_SIZE_OPTIONS } from '@/constants/pagination' ;
11+ import { useGlobalStore } from '@/store/global' ;
12+ import { settingSelectors } from '@/store/global/selectors' ;
1013
1114interface IProps {
1215 onPageSizeChange ?: ( pageSize : number ) => void ;
@@ -23,6 +26,13 @@ export default function Pagination(props: IProps) {
2326 const { styles } = useStyles ( { inputNumberWidth } ) ;
2427 const [ inputValue , setInputValue ] = useState < number | null > ( 1 ) ;
2528 const [ totalLoading , setTotalLoading ] = useState ( false ) ;
29+ const [ pageSizeMenuOpen , setPageSizeMenuOpen ] = useState ( false ) ;
30+ const [ customPageSize , setCustomPageSize ] = useState < number | null > ( null ) ;
31+ const keepPageSizeMenuOpenRef = useRef ( false ) ;
32+ const { defaultPageSize, setBaseSetting } = useGlobalStore ( ( state ) => ( {
33+ defaultPageSize : settingSelectors . currentBaseSetting ( state ) . defaultPageSize ,
34+ setBaseSetting : state . setBaseSetting ,
35+ } ) ) ;
2636
2737 useEffect ( ( ) => {
2838 setInputValue ( paginationConfig ?. pageNo ?? 1 ) ;
@@ -115,72 +125,102 @@ export default function Pagination(props: IProps) {
115125 return true ;
116126 } ;
117127
118- const items : any = [
119- {
120- label : '10' ,
121- value : 10 ,
122- onClick : ( ) => {
123- onPageSizeChange && onPageSizeChange ( 10 ) ;
124- } ,
125- } ,
126- {
127- label : '100' ,
128- value : 100 ,
129- onClick : ( ) => {
130- onPageSizeChange && onPageSizeChange ( 100 ) ;
131- } ,
132- } ,
133- {
134- label : '200' ,
135- value : 200 ,
136- onClick : ( ) => {
137- onPageSizeChange && onPageSizeChange ( 200 ) ;
138- } ,
139- } ,
140- {
141- label : '500' ,
142- value : 500 ,
143- onClick : ( ) => {
144- onPageSizeChange && onPageSizeChange ( 500 ) ;
145- } ,
146- } ,
147- {
148- label : '1000' ,
149- value : 1000 ,
150- onClick : ( ) => {
151- onPageSizeChange && onPageSizeChange ( 1000 ) ;
152- } ,
153- } ,
154- {
155- label : '5000' ,
156- value : 5000 ,
157- onClick : ( ) => {
158- onPageSizeChange && onPageSizeChange ( 5000 ) ;
159- } ,
160- } ,
161- {
162- label : '10000' ,
163- value : 10000 ,
164- onClick : ( ) => {
165- onPageSizeChange && onPageSizeChange ( 10000 ) ;
166- } ,
167- } ,
128+ const isPresetDefaultPageSize = RESULT_PAGE_SIZE_OPTIONS . some ( ( pageSize ) => pageSize === defaultPageSize ) ;
129+
130+ const items = [
131+ ...RESULT_PAGE_SIZE_OPTIONS . map ( ( pageSize ) => ( {
132+ key : String ( pageSize ) ,
133+ label : (
134+ < div className = { styles . pageSizeOption } >
135+ < span > { pageSize } </ span >
136+ { pageSize === defaultPageSize && (
137+ < span className = { styles . defaultPageSize } >
138+ < CheckOutlined />
139+ { i18n ( 'workspace.table.defaultPageSize' ) }
140+ </ span >
141+ ) }
142+ </ div >
143+ ) ,
144+ } ) ) ,
145+ { type : 'divider' as const } ,
168146 {
169- label : '50000' ,
170- value : 50000 ,
171- onClick : ( ) => {
172- onPageSizeChange && onPageSizeChange ( 50000 ) ;
173- } ,
147+ key : 'custom' ,
148+ label : (
149+ < div
150+ className = { styles . customPageSize }
151+ onClick = { ( event ) => event . stopPropagation ( ) }
152+ onKeyDown = { ( event ) => event . stopPropagation ( ) }
153+ >
154+ < InputNumber
155+ className = { styles . customPageSizeInput }
156+ size = "small"
157+ min = { 1 }
158+ max = { 100000 }
159+ precision = { 0 }
160+ controls = { false }
161+ autoFocus
162+ value = { customPageSize }
163+ placeholder = { i18n ( 'workspace.table.customPageSize' ) }
164+ onChange = { setCustomPageSize }
165+ onPressEnter = { ( ) => handleApplyCustomPageSize ( ) }
166+ />
167+ { ! isPresetDefaultPageSize && customPageSize === defaultPageSize && (
168+ < span className = { styles . defaultPageSize } >
169+ < CheckOutlined />
170+ { i18n ( 'workspace.table.defaultPageSize' ) }
171+ </ span >
172+ ) }
173+ </ div >
174+ ) ,
174175 } ,
176+ { type : 'divider' as const } ,
175177 {
176- label : '100000' ,
177- value : 100000 ,
178- onClick : ( ) => {
179- onPageSizeChange && onPageSizeChange ( 100000 ) ;
180- } ,
178+ key : 'set-default' ,
179+ label : i18n ( 'workspace.table.setDefaultPageSize' ) ,
180+ disabled : paginationConfig . pageSize === defaultPageSize ,
181181 } ,
182182 ] ;
183183
184+ function handleApplyCustomPageSize ( ) {
185+ if ( ! customPageSize ) {
186+ return ;
187+ }
188+ keepPageSizeMenuOpenRef . current = true ;
189+ setPageSizeMenuOpen ( true ) ;
190+ setBaseSetting ( { defaultPageSize : customPageSize } ) ;
191+ onPageSizeChange ?.( customPageSize ) ;
192+ }
193+
194+ const handlePageSizeMenuClick = ( { key } : { key : string } ) => {
195+ if ( key === 'set-default' ) {
196+ setBaseSetting ( { defaultPageSize : paginationConfig . pageSize } ) ;
197+ setPageSizeMenuOpen ( false ) ;
198+ return ;
199+ }
200+ keepPageSizeMenuOpenRef . current = true ;
201+ setPageSizeMenuOpen ( true ) ;
202+ onPageSizeChange ?.( Number ( key ) ) ;
203+ } ;
204+
205+ const handlePageSizeMenuOpenChange = ( open : boolean , info : { source : 'trigger' | 'menu' } ) => {
206+ if ( open ) {
207+ const isPresetCurrentPageSize = RESULT_PAGE_SIZE_OPTIONS . some (
208+ ( pageSize ) => pageSize === paginationConfig . pageSize ,
209+ ) ;
210+ setCustomPageSize (
211+ ! isPresetDefaultPageSize ? defaultPageSize : ! isPresetCurrentPageSize ? paginationConfig . pageSize : null ,
212+ ) ;
213+ }
214+ if ( ! open && info . source === 'menu' && keepPageSizeMenuOpenRef . current ) {
215+ keepPageSizeMenuOpenRef . current = false ;
216+ return ;
217+ }
218+ if ( ! open ) {
219+ keepPageSizeMenuOpenRef . current = false ;
220+ }
221+ setPageSizeMenuOpen ( open ) ;
222+ } ;
223+
184224 return (
185225 < div className = { styles . paginationWrapper } >
186226 < IconButton
@@ -218,7 +258,12 @@ export default function Pagination(props: IProps) {
218258 onClick = { ( ) => handleClickIcon ( 'last' ) }
219259 />
220260
221- < Dropdown destroyPopupOnHide menu = { { items } } >
261+ < Dropdown
262+ destroyPopupOnHide
263+ open = { pageSizeMenuOpen }
264+ onOpenChange = { handlePageSizeMenuOpenChange }
265+ menu = { { items, selectedKeys : [ String ( paginationConfig . pageSize ) ] , onClick : handlePageSizeMenuClick } }
266+ >
222267 < div className = { styles . selectSize } >
223268 { paginationConfig ?. pageSize ?? 200 }
224269 < DownOutlined />
0 commit comments