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
Changes from 7 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)
})
})
129 changes: 118 additions & 11 deletions web/src/routes/datasets/Datasets.tsx
Original file line number Diff line number Diff line change
@@ -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'
@@ -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[]
@@ -34,31 +42,85 @@ 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 } = this.state
const titlePos = datasets.length
? `${PAGE_SIZE * page - PAGE_SIZE} - ${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}>
@@ -68,11 +130,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>
@@ -95,7 +181,7 @@ class Datasets extends React.Component<DatasetsProps> {
</TableRow>
</TableHead>
<TableBody>
{datasets
{this.getDatasets()
.filter(dataset => !dataset.deleted)
.map(dataset => {
return (
@@ -137,6 +223,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>
@@ -160,4 +267,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
@@ -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
}
})