diff --git a/web/src/__tests__/components/DatasetsPagination.test.tsx b/web/src/__tests__/components/DatasetsPagination.test.tsx
new file mode 100644
index 0000000000..5899128fd4
--- /dev/null
+++ b/web/src/__tests__/components/DatasetsPagination.test.tsx
@@ -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()
+
+ it('should render', () => {
+ expect(wrapper.exists()).toBe(true)
+ })
+
+ it('should find Tooltip elements containing IconButton elements', () => {
+ expect(
+ wrapper
+ .find(Tooltip)
+ ).toContain(IconButton)
+ })
+})
\ No newline at end of file
diff --git a/web/src/routes/datasets/Datasets.tsx b/web/src/routes/datasets/Datasets.tsx
index 97ca472508..1eb0200822 100644
--- a/web/src/routes/datasets/Datasets.tsx
+++ b/web/src/routes/datasets/Datasets.tsx
@@ -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,21 +42,47 @@ interface DispatchProps {
resetDatasets: typeof resetDatasets
}
+interface DatasetsState {
+ datasets: Dataset[]
+ page: number
+ pageIsLast: boolean
+}
+
type DatasetsProps = WithStyles & StateProps & DispatchProps
-class Datasets extends React.Component {
+class Datasets extends React.Component {
+
+ 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) {
+ 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
+ })
}
}
@@ -56,9 +90,43 @@ class Datasets extends React.Component {
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 (
@@ -68,11 +136,35 @@ class Datasets extends React.Component {
{i18next.t('datasets_route.empty_body')}
-
+
) : (
<>
-
- {i18next.t('datasets_route.heading')}
+
+
+ {i18next.t('datasets_route.heading')}
+ Page: {this.pageNavigation()}
+
+
+
+ this.handleClickPage('prev')}
+ >
+
+
+
+
+ this.handleClickPage('next')}
+ >
+
+
+
+
@@ -95,7 +187,7 @@ class Datasets extends React.Component {
- {datasets
+ {this.getDatasets()
.filter(dataset => !dataset.deleted)
.map(dataset => {
return (
@@ -137,6 +229,27 @@ class Datasets extends React.Component {
>
)}
+
+
+ this.handleClickPage('prev')}
+ >
+
+
+
+
+ this.handleClickPage('next')}
+ >
+
+
+
+
>
@@ -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))
\ No newline at end of file
diff --git a/web/src/store/actionCreators/index.ts b/web/src/store/actionCreators/index.ts
index 4e8c5043c9..520748ae42 100644
--- a/web/src/store/actionCreators/index.ts
+++ b/web/src/store/actionCreators/index.ts
@@ -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
}
})