Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add pagination to datasets #2512

Merged
merged 9 commits into from
Jun 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions web/src/__tests__/components/DatasetsPagination.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import * as React from 'react'
import { mount } from 'enzyme'
import Datasets from '../../routes/datasets/Datasets'
import { Tooltip } from '@material-ui/core'
import IconButton from '@material-ui/core/IconButton'

test.skip('DatasetsPagination Component', () => {

const wrapper = mount(<Datasets />)

it('should render', () => {
expect(wrapper.exists()).toBe(true)
})

it('should find Tooltip elements containing IconButton elements', () => {
expect(
wrapper
.find(Tooltip)
).toContain(IconButton)
})
})
135 changes: 124 additions & 11 deletions web/src/routes/datasets/Datasets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
// SPDX-License-Identifier: Apache-2.0

import * as Redux from 'redux'
import { Container, Table, TableBody, TableCell, TableHead, TableRow } from '@material-ui/core'
import { Container, Table, TableBody, TableCell, TableHead, TableRow, Theme, Tooltip } from '@material-ui/core'
import { ChevronLeftRounded, ChevronRightRounded } from '@material-ui/icons'
import IconButton from '@material-ui/core/IconButton'
import { Dataset } from '../../types/api'
import { IState } from '../../store/reducers'
import { MqScreenLoad } from '../../components/core/screen-load/MqScreenLoad'
Expand All @@ -20,7 +22,13 @@ import React from 'react'
import createStyles from '@material-ui/core/styles/createStyles'
import withStyles, { WithStyles } from '@material-ui/core/styles/withStyles'

const styles = () => createStyles({})
const PAGE_SIZE = 20

const styles = (theme: Theme) => createStyles({
ml2: {
marginLeft: theme.spacing(2)
}
})

interface StateProps {
datasets: Dataset[]
Expand All @@ -34,31 +42,91 @@ interface DispatchProps {
resetDatasets: typeof resetDatasets
}

interface DatasetsState {
datasets: Dataset[]
page: number
pageIsLast: boolean
}

type DatasetsProps = WithStyles<typeof styles> & StateProps & DispatchProps

class Datasets extends React.Component<DatasetsProps> {
class Datasets extends React.Component<DatasetsProps, DatasetsState> {

constructor(props: DatasetsProps) {
super(props)
this.state = {
datasets: [],
page: 1,
pageIsLast: false
}
}

componentDidMount() {
if (this.props.selectedNamespace) {
this.props.fetchDatasets(this.props.selectedNamespace)
this.props.fetchDatasets(this.props.selectedNamespace, PAGE_SIZE)
}
}

componentDidUpdate(prevProps: Readonly<DatasetsProps>) {
const { datasets: datasetsState, page } = this.state
const { datasets: datasetsProps } = this.props

if (
prevProps.selectedNamespace !== this.props.selectedNamespace &&
this.props.selectedNamespace
) {
this.props.fetchDatasets(this.props.selectedNamespace)
this.props.fetchDatasets(this.props.selectedNamespace, PAGE_SIZE)
}

if (datasetsProps !== datasetsState) {
this.setState({
datasets: datasetsProps,
pageIsLast: datasetsProps.length < page * PAGE_SIZE
})
}
}

componentWillUnmount() {
this.props.resetDatasets()
}

getDatasets() {
const { datasets, page } = this.state
return datasets.slice((page - 1) * PAGE_SIZE, PAGE_SIZE + (page - 1) * PAGE_SIZE)
}

pageNavigation() {
const { datasets, page, pageIsLast } = this.state
const titlePos = datasets.length < PAGE_SIZE && page === 1
? `1 - ${datasets.length}`
: datasets.length > PAGE_SIZE && page === 1
? `1 - ${PAGE_SIZE}`
: datasets.length && page > 1 && pageIsLast === false
? `${PAGE_SIZE * page - PAGE_SIZE + 1} - ${PAGE_SIZE * page}`
: datasets.length && page > 1 && pageIsLast
? `${PAGE_SIZE * page - PAGE_SIZE + 1} - ${datasets.length}`
: `${datasets.length}`
return `${page} (${titlePos})`
}

handleClickPage(direction: 'prev' | 'next') {
const { page } = this.state
const directionPage = direction === 'next' ? page + 1 : page - 1

if (this.props.selectedNamespace) {
this.props.fetchDatasets(
this.props.selectedNamespace,
PAGE_SIZE * directionPage
)
}
this.setState({ page: directionPage })
}

render() {
const { datasets, isDatasetsLoading, isDatasetsInit } = this.props
const { isDatasetsLoading, isDatasetsInit, classes } = this.props
const { datasets, page, pageIsLast } = this.state
const i18next = require('i18next')

return (
<Container maxWidth={'lg'} disableGutters>
<MqScreenLoad loading={isDatasetsLoading || !isDatasetsInit}>
Expand All @@ -68,11 +136,35 @@ class Datasets extends React.Component<DatasetsProps> {
<MqEmpty title={i18next.t('datasets_route.empty_title')}>
<MqText subdued>{i18next.t('datasets_route.empty_body')}</MqText>
</MqEmpty>
</Box>
</Box>
) : (
<>
<Box p={2}>
<MqText heading>{i18next.t('datasets_route.heading')}</MqText>
<Box p={2} display={'flex'} justifyContent={'space-between'}>
<Box>
<MqText heading>{i18next.t('datasets_route.heading')}</MqText>
Page: {this.pageNavigation()}
</Box>
<Box>
<Tooltip title={i18next.t('events_route.previous_page')}>
<IconButton
className={classes.ml2}
color='primary'
disabled={page === 1}
onClick={() => this.handleClickPage('prev')}
>
<ChevronLeftRounded />
</IconButton>
</Tooltip>
<Tooltip title={i18next.t('events_route.next_page')}>
<IconButton
color='primary'
disabled={pageIsLast}
onClick={() => this.handleClickPage('next')}
>
<ChevronRightRounded />
</IconButton>
</Tooltip>
</Box>
</Box>
<Table size='small'>
<TableHead>
Expand All @@ -95,7 +187,7 @@ class Datasets extends React.Component<DatasetsProps> {
</TableRow>
</TableHead>
<TableBody>
{datasets
{this.getDatasets()
.filter(dataset => !dataset.deleted)
.map(dataset => {
return (
Expand Down Expand Up @@ -137,6 +229,27 @@ class Datasets extends React.Component<DatasetsProps> {
</Table>
</>
)}
<Box display={'flex'} justifyContent={'flex-end'} mb={2}>
<Tooltip title={i18next.t('events_route.previous_page')}>
<IconButton
className={classes.ml2}
color='primary'
disabled={page === 1}
onClick={() => this.handleClickPage('prev')}
>
<ChevronLeftRounded />
</IconButton>
</Tooltip>
<Tooltip title={i18next.t('events_route.next_page')}>
<IconButton
color='primary'
disabled={pageIsLast}
onClick={() => this.handleClickPage('next')}
>
<ChevronRightRounded />
</IconButton>
</Tooltip>
</Box>
</>
</MqScreenLoad>
</Container>
Expand All @@ -160,4 +273,4 @@ const mapDispatchToProps = (dispatch: Redux.Dispatch) =>
dispatch
)

export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(Datasets))
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(Datasets))
5 changes: 3 additions & 2 deletions web/src/store/actionCreators/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,11 @@ export const resetEvents = () => ({
type: actionTypes.RESET_EVENTS
})

export const fetchDatasets = (namespace: string) => ({
export const fetchDatasets = (namespace: string, limit: number) => ({
type: actionTypes.FETCH_DATASETS,
payload: {
namespace
namespace,
limit
}
})

Expand Down