1- import { LinearProgress , Typography } from '@material-ui/core'
1+ import {
2+ createStyles ,
3+ FormControl ,
4+ IconButton ,
5+ LinearProgress ,
6+ makeStyles ,
7+ MenuItem ,
8+ Select ,
9+ TextField ,
10+ Typography ,
11+ } from '@material-ui/core'
12+ import { ChevronLeft , ChevronRight } from '@material-ui/icons'
213import { ConstantContent , ODataFieldParameter } from '@sensenet/client-core'
314import { GenericContent } from '@sensenet/default-content-types'
415import {
@@ -11,48 +22,95 @@ import React, { useContext } from 'react'
1122import { useHistory } from 'react-router-dom'
1223import { ResponsivePersonalSettings } from '../../context'
1324import { useSearch } from '../../context/search'
14- import { useLocalization , useSelectionService , useSnRoute } from '../../hooks'
25+ import { useSelectionService , useSnRoute } from '../../hooks'
1526import { getPrimaryActionUrl } from '../../services'
16- import { ContentList } from '../content-list'
27+ import { searchColumnDefs } from '../grid/Cols/ColumnDefs.'
28+ import { Grid } from '../grid/Grid'
29+
30+ const useStyles = makeStyles ( ( ) =>
31+ createStyles ( {
32+ paginationControls : {
33+ display : 'flex' ,
34+ alignItems : 'center' ,
35+ justifyContent : 'space-between' ,
36+ flexWrap : 'wrap' ,
37+ padding : '0 10px' ,
38+ } ,
39+ noSpin : {
40+ '& input[type=number]::-webkit-inner-spin-button' : {
41+ WebkitAppearance : 'none' ,
42+ margin : 0 ,
43+ } ,
44+ '& input[type=number]::-webkit-outer-spin-button' : {
45+ WebkitAppearance : 'none' ,
46+ margin : 0 ,
47+ } ,
48+ '& input[type=number]' : {
49+ MozAppearance : 'textfield' ,
50+ } ,
51+ } ,
52+ containerRelative : {
53+ position : 'relative' ,
54+ height : '100%' ,
55+ display : 'flex' ,
56+ flexDirection : 'column' ,
57+ } ,
58+ linearProgressOverlay : {
59+ position : 'absolute' ,
60+ top : 0 ,
61+ left : 0 ,
62+ right : 0 ,
63+ zIndex : 99 ,
64+ } ,
65+ } ) ,
66+ )
1767
18- export const SearchResults = ( ) => {
68+ export const SearchResults = ( {
69+ currentPage,
70+ setCurrentPage,
71+ maxSearchResult,
72+ setMaxSearchResult,
73+ } : {
74+ currentPage : number
75+ setCurrentPage : ( val : number ) => void
76+ maxSearchResult : number
77+ setMaxSearchResult : ( val : number ) => void
78+ } ) => {
1979 const repository = useRepository ( )
20- const localization = useLocalization ( ) . search
2180 const history = useHistory ( )
2281 const { location } = history
2382 const selectionService = useSelectionService ( )
2483 const uiSettings = useContext ( ResponsivePersonalSettings )
2584 const snRoute = useSnRoute ( )
26-
85+ const classes = useStyles ( )
2786 const searchState = useSearch ( )
2887
88+ const totalPages = Math . ceil ( searchState . resultCount / maxSearchResult )
89+ const startItem = ( currentPage - 1 ) * maxSearchResult + 1
90+ const endItem = Math . min ( currentPage * maxSearchResult , searchState . resultCount )
91+
92+ const handlePageInputChange = ( e : React . ChangeEvent < HTMLInputElement > ) => {
93+ let value = Number ( e . target . value )
94+ if ( isNaN ( value ) ) return
95+ value = Math . min ( Math . max ( 1 , value ) , totalPages )
96+ setCurrentPage ( value )
97+ }
98+
2999 return (
30- < >
100+ < div className = { classes . containerRelative } >
31101 { searchState . error ? (
32102 < Typography color = "error" variant = "caption" style = { { margin : '0 1rem 1rem' } } >
33103 { searchState . error }
34104 </ Typography >
35105 ) : null }
36106
37- { searchState . isLoading && < LinearProgress style = { { margin : '15px 15px 0' } } /> }
38-
39- < Typography style = { { margin : '1rem' } } >
40- { localization . resultCount ( searchState . resultCount ) +
41- ( searchState . resultCount > searchState . maxSearchResult
42- ? localization . onlyResultCountDisplayed ( searchState . maxSearchResult )
43- : '' ) }
44- </ Typography >
107+ { searchState . isLoading && < LinearProgress className = { classes . linearProgressOverlay } /> }
45108
46109 < CurrentContentContext . Provider value = { ConstantContent . PORTAL_ROOT } >
47110 < CurrentChildrenContext . Provider value = { searchState . result } >
48111 < CurrentAncestorsContext . Provider value = { [ ] } >
49- < ContentList
50- style = { {
51- height : '100%' ,
52- overflow : 'auto' ,
53- } }
54- fieldsToDisplay = { [ { field : 'DisplayName' } , { field : 'Path' } , { field : 'ModifiedBy' } ] }
55- enableBreadcrumbs = { false }
112+ < Grid
113+ colDef = { searchColumnDefs }
56114 parentIdOrPath = { 0 }
57115 onParentChange = { ( p ) => {
58116 history . push ( getPrimaryActionUrl ( { content : p , repository, uiSettings, location, snRoute } ) )
@@ -79,6 +137,73 @@ export const SearchResults = () => {
79137 </ CurrentAncestorsContext . Provider >
80138 </ CurrentChildrenContext . Provider >
81139 </ CurrentContentContext . Provider >
82- </ >
140+
141+ { /* Pagination Controls */ }
142+ < div className = { classes . paginationControls } >
143+ < div style = { { display : 'flex' , alignItems : 'center' , gap : '12px' } } >
144+ < Typography variant = "body2" component = "label" htmlFor = "per-page" style = { { fontWeight : '500' } } >
145+ Items per page
146+ </ Typography >
147+ < FormControl variant = "outlined" size = "small" style = { { minWidth : 70 } } >
148+ < Select
149+ labelId = "per-page-label"
150+ id = "per-page"
151+ value = { maxSearchResult }
152+ onChange = { ( e ) => {
153+ setMaxSearchResult ( Number ( e . target . value ) )
154+ setCurrentPage ( 1 )
155+ } } >
156+ { [ 50 , 100 , 200 , 500 ] . map ( ( value ) => (
157+ < MenuItem key = { value } value = { value } >
158+ { value }
159+ </ MenuItem >
160+ ) ) }
161+ </ Select >
162+ </ FormControl >
163+
164+ < Typography variant = "body2" component = "span" style = { { fontWeight : '500' } } >
165+ { startItem } -{ endItem } of { searchState . resultCount }
166+ </ Typography >
167+ </ div >
168+
169+ < div style = { { display : 'flex' , alignItems : 'center' , gap : '8px' } } >
170+ < IconButton
171+ onClick = { ( ) => setCurrentPage ( Math . max ( 1 , currentPage - 1 ) ) }
172+ disabled = { currentPage <= 1 }
173+ size = "small" >
174+ < ChevronLeft />
175+ </ IconButton >
176+
177+ < TextField
178+ type = "number"
179+ inputProps = { {
180+ min : 1 ,
181+ max : totalPages ,
182+ style : { textAlign : 'center' } ,
183+ } }
184+ value = { currentPage }
185+ onChange = { handlePageInputChange }
186+ variant = "outlined"
187+ size = "small"
188+ className = { classes . noSpin }
189+ style = { {
190+ width : 50 ,
191+ padding : 4 ,
192+ borderRadius : 4 ,
193+ } }
194+ />
195+ < Typography variant = "body1" component = "span" style = { { fontWeight : '500' } } >
196+ of { totalPages }
197+ </ Typography >
198+
199+ < IconButton
200+ onClick = { ( ) => setCurrentPage ( Math . min ( totalPages , currentPage + 1 ) ) }
201+ disabled = { currentPage >= totalPages }
202+ size = "small" >
203+ < ChevronRight />
204+ </ IconButton >
205+ </ div >
206+ </ div >
207+ </ div >
83208 )
84209}
0 commit comments