aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQuentin Gliech <quentingliech@gmail.com>2019-05-22 19:51:33 +0200
committerQuentin Gliech <quentingliech@gmail.com>2019-05-22 19:52:01 +0200
commit51ca8527dc94dbe619da98e84836340313326f7d (patch)
treec8e858dc9506d568578040c32b93d928cb101916
parentd79ef7a7945ba82caeec62cad44dad134c9edfbc (diff)
downloadgit-bug-51ca8527dc94dbe619da98e84836340313326f7d.tar.gz
webui: Rework pagination
-rw-r--r--webui/package-lock.json192
-rw-r--r--webui/package.json1
-rw-r--r--webui/src/list/List.js160
-rw-r--r--webui/src/list/ListQuery.js39
4 files changed, 237 insertions, 155 deletions
diff --git a/webui/package-lock.json b/webui/package-lock.json
index 50f8d797..268525c3 100644
--- a/webui/package-lock.json
+++ b/webui/package-lock.json
@@ -849,6 +849,11 @@
"resolved": "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz",
"integrity": "sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw=="
},
+ "@emotion/hash": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.7.1.tgz",
+ "integrity": "sha512-OYpa/Sg+2GDX+jibUfpZVn1YqSVRpYmTLF2eyAfrFTIJSbwyIrc+YscayoykvaOME/wV4BV0Sa0yqdMrgse6mA=="
+ },
"@material-ui/core": {
"version": "3.9.3",
"resolved": "https://registry.npmjs.org/@material-ui/core/-/core-3.9.3.tgz",
@@ -892,6 +897,41 @@
"recompose": "0.28.0 - 0.30.0"
}
},
+ "@material-ui/styles": {
+ "version": "3.0.0-alpha.10",
+ "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-3.0.0-alpha.10.tgz",
+ "integrity": "sha512-qJ5eiupBPRCNlMCDZ2G5h8auBtBtm8uT/oCUAJ/FqhO5oC7POLmmvDN1Cq1cgAmqQnaL6uN5mAM1Gc90GpKr9A==",
+ "requires": {
+ "@babel/runtime": "^7.2.0",
+ "@emotion/hash": "^0.7.1",
+ "@material-ui/utils": "^3.0.0-alpha.2",
+ "classnames": "^2.2.5",
+ "deepmerge": "^3.0.0",
+ "hoist-non-react-statics": "^3.2.1",
+ "jss": "^10.0.0-alpha.7",
+ "jss-plugin-camel-case": "^10.0.0-alpha.7",
+ "jss-plugin-default-unit": "^10.0.0-alpha.7",
+ "jss-plugin-global": "^10.0.0-alpha.7",
+ "jss-plugin-nested": "^10.0.0-alpha.7",
+ "jss-plugin-props-sort": "^10.0.0-alpha.7",
+ "jss-plugin-rule-value-function": "^10.0.0-alpha.7",
+ "jss-plugin-vendor-prefixer": "^10.0.0-alpha.7",
+ "prop-types": "^15.6.0",
+ "warning": "^4.0.1"
+ },
+ "dependencies": {
+ "jss": {
+ "version": "10.0.0-alpha.16",
+ "resolved": "https://registry.npmjs.org/jss/-/jss-10.0.0-alpha.16.tgz",
+ "integrity": "sha512-HmKNNnr82TR5jkWjBcbrx/uim2ief588pWp7zsf4GQpL125zRkEaWYL1SXv5bR6bBvAoTtvJsTAOxDIlLxUNZg==",
+ "requires": {
+ "@babel/runtime": "^7.3.1",
+ "is-in-browser": "^1.1.3",
+ "tiny-warning": "^1.0.2"
+ }
+ }
+ }
+ },
"@material-ui/system": {
"version": "3.0.0-alpha.2",
"resolved": "https://registry.npmjs.org/@material-ui/system/-/system-3.0.0-alpha.2.tgz",
@@ -3103,7 +3143,8 @@
},
"ansi-regex": {
"version": "2.1.1",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"aproba": {
"version": "1.2.0",
@@ -3121,11 +3162,13 @@
},
"balanced-match": {
"version": "1.0.0",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
+ "optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -3138,15 +3181,18 @@
},
"code-point-at": {
"version": "1.1.0",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"concat-map": {
"version": "0.0.1",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"console-control-strings": {
"version": "1.1.0",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"core-util-is": {
"version": "1.0.2",
@@ -3249,7 +3295,8 @@
},
"inherits": {
"version": "2.0.3",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"ini": {
"version": "1.3.5",
@@ -3259,6 +3306,7 @@
"is-fullwidth-code-point": {
"version": "1.0.0",
"bundled": true,
+ "optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -3271,17 +3319,20 @@
"minimatch": {
"version": "3.0.4",
"bundled": true,
+ "optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "0.0.8",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"minipass": {
"version": "2.3.5",
"bundled": true,
+ "optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@@ -3298,6 +3349,7 @@
"mkdirp": {
"version": "0.5.1",
"bundled": true,
+ "optional": true,
"requires": {
"minimist": "0.0.8"
}
@@ -3370,7 +3422,8 @@
},
"number-is-nan": {
"version": "1.0.1",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"object-assign": {
"version": "4.1.1",
@@ -3380,6 +3433,7 @@
"once": {
"version": "1.4.0",
"bundled": true,
+ "optional": true,
"requires": {
"wrappy": "1"
}
@@ -3455,7 +3509,8 @@
},
"safe-buffer": {
"version": "5.1.2",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"safer-buffer": {
"version": "2.1.2",
@@ -3485,6 +3540,7 @@
"string-width": {
"version": "1.0.2",
"bundled": true,
+ "optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@@ -3502,6 +3558,7 @@
"strip-ansi": {
"version": "3.0.1",
"bundled": true,
+ "optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@@ -3540,11 +3597,13 @@
},
"wrappy": {
"version": "1.0.2",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"yallist": {
"version": "3.0.3",
- "bundled": true
+ "bundled": true,
+ "optional": true
}
}
},
@@ -6721,7 +6780,8 @@
},
"ansi-regex": {
"version": "2.1.1",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"aproba": {
"version": "1.2.0",
@@ -6739,11 +6799,13 @@
},
"balanced-match": {
"version": "1.0.0",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
+ "optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -6756,15 +6818,18 @@
},
"code-point-at": {
"version": "1.1.0",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"concat-map": {
"version": "0.0.1",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"console-control-strings": {
"version": "1.1.0",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"core-util-is": {
"version": "1.0.2",
@@ -6867,7 +6932,8 @@
},
"inherits": {
"version": "2.0.3",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"ini": {
"version": "1.3.5",
@@ -6877,6 +6943,7 @@
"is-fullwidth-code-point": {
"version": "1.0.0",
"bundled": true,
+ "optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -6889,17 +6956,20 @@
"minimatch": {
"version": "3.0.4",
"bundled": true,
+ "optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "0.0.8",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"minipass": {
"version": "2.2.4",
"bundled": true,
+ "optional": true,
"requires": {
"safe-buffer": "^5.1.1",
"yallist": "^3.0.0"
@@ -6916,6 +6986,7 @@
"mkdirp": {
"version": "0.5.1",
"bundled": true,
+ "optional": true,
"requires": {
"minimist": "0.0.8"
}
@@ -6988,7 +7059,8 @@
},
"number-is-nan": {
"version": "1.0.1",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"object-assign": {
"version": "4.1.1",
@@ -6998,6 +7070,7 @@
"once": {
"version": "1.4.0",
"bundled": true,
+ "optional": true,
"requires": {
"wrappy": "1"
}
@@ -7073,7 +7146,8 @@
},
"safe-buffer": {
"version": "5.1.1",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"safer-buffer": {
"version": "2.1.2",
@@ -7103,6 +7177,7 @@
"string-width": {
"version": "1.0.2",
"bundled": true,
+ "optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@@ -7120,6 +7195,7 @@
"strip-ansi": {
"version": "3.0.1",
"bundled": true,
+ "optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@@ -7158,11 +7234,13 @@
},
"wrappy": {
"version": "1.0.2",
- "bundled": true
+ "bundled": true,
+ "optional": true
},
"yallist": {
"version": "3.0.2",
- "bundled": true
+ "bundled": true,
+ "optional": true
}
}
},
@@ -9380,6 +9458,76 @@
}
}
},
+ "jss-plugin-camel-case": {
+ "version": "10.0.0-alpha.7",
+ "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.0.0-alpha.7.tgz",
+ "integrity": "sha512-Bwrav1ZB0XywdJW6TaEuFhKe1ZpZvUlESh3jsFOvebA9aFTYNCkmHMEqjA5+u9VMxksl3u77nnZHtukpxkzrBA==",
+ "requires": {
+ "@babel/runtime": "^7.0.0",
+ "hyphenate-style-name": "^1.0.2"
+ }
+ },
+ "jss-plugin-default-unit": {
+ "version": "10.0.0-alpha.7",
+ "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.0.0-alpha.7.tgz",
+ "integrity": "sha512-auuJUbQaWMxoHOVFPrfZNZpZm9ab8PZeDyvey8nMt2lbokkmZ53UyAnM/1kNsg5BdAXTItcLDxDB3I4gwNU84g==",
+ "requires": {
+ "@babel/runtime": "^7.0.0"
+ }
+ },
+ "jss-plugin-global": {
+ "version": "10.0.0-alpha.7",
+ "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.0.0-alpha.7.tgz",
+ "integrity": "sha512-OWeoW4szLDgRUKviST+xfilqa8O5uXJCW+O3YonheCRTRJg6rRzlE/b5pfYPoU9UtwvY9n7JvwBX5r3c1lMsEQ==",
+ "requires": {
+ "@babel/runtime": "^7.0.0"
+ }
+ },
+ "jss-plugin-nested": {
+ "version": "10.0.0-alpha.7",
+ "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.0.0-alpha.7.tgz",
+ "integrity": "sha512-wsRzuIZXAc6WMjc61mREW9cUrDxgSI7dK/fx5c7a06IDUfSn+83NJ30J/RB4oBnbQW9SijV/muujz7IJqpn9Gw==",
+ "requires": {
+ "@babel/runtime": "^7.0.0",
+ "tiny-warning": "^1.0.2"
+ }
+ },
+ "jss-plugin-props-sort": {
+ "version": "10.0.0-alpha.7",
+ "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.0.0-alpha.7.tgz",
+ "integrity": "sha512-KXOCaHUk1+KXqE0z3q66/w1fDoy+VsZvI77gLxOqTsTrvIKFLX0jarwXogW3CDlaPQQFTZ6JykJJXtPRTBlstA==",
+ "requires": {
+ "@babel/runtime": "^7.0.0"
+ }
+ },
+ "jss-plugin-rule-value-function": {
+ "version": "10.0.0-alpha.7",
+ "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.0.0-alpha.7.tgz",
+ "integrity": "sha512-ett83hvIM69/LknmrWndrrdiDlfLfP+rneU5qP7gTOWJ7g1P9GuEL1Tc4CWdZUWBX+T58tgIBP0V1pzWCkP0QA==",
+ "requires": {
+ "@babel/runtime": "^7.0.0"
+ }
+ },
+ "jss-plugin-vendor-prefixer": {
+ "version": "10.0.0-alpha.7",
+ "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.0.0-alpha.7.tgz",
+ "integrity": "sha512-YbIVgqq+dLimOBOEYggho1Iuc0roz4PJSZYyaok9n8JnXVIqPnxYJbr8+bMbvzJ5CL3eeJij/e7L2IPCceRKrA==",
+ "requires": {
+ "@babel/runtime": "^7.0.0",
+ "css-vendor": "^1.1.0"
+ },
+ "dependencies": {
+ "css-vendor": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-1.2.1.tgz",
+ "integrity": "sha512-ZpwiWxn5jWNJ7NF3DAb/Dc/+c2lRu+fnovej/adCv3VJsULJSjdXEpUwRcq4fnpAAh98Hi7b0GDnlyoNFcdv1g==",
+ "requires": {
+ "@babel/runtime": "^7.3.1",
+ "is-in-browser": "^1.0.2"
+ }
+ }
+ }
+ },
"jss-props-sort": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/jss-props-sort/-/jss-props-sort-6.0.0.tgz",
diff --git a/webui/package.json b/webui/package.json
index c5ccef9a..e8ebebac 100644
--- a/webui/package.json
+++ b/webui/package.json
@@ -5,6 +5,7 @@
"dependencies": {
"@material-ui/core": "^3.9.3",
"@material-ui/icons": "^3.0.2",
+ "@material-ui/styles": "^3.0.0-alpha.10",
"apollo-boost": "^0.3.1",
"graphql": "^14.2.0",
"moment": "^2.24.0",
diff --git a/webui/src/list/List.js b/webui/src/list/List.js
index d36be8a1..45c2c963 100644
--- a/webui/src/list/List.js
+++ b/webui/src/list/List.js
@@ -1,134 +1,50 @@
-import { withStyles } from '@material-ui/core/styles';
+import { makeStyles } from '@material-ui/styles';
+import IconButton from '@material-ui/core/IconButton';
import Table from '@material-ui/core/Table/Table';
import TableBody from '@material-ui/core/TableBody/TableBody';
-import TablePagination from '@material-ui/core/TablePagination/TablePagination';
+import KeyboardArrowLeft from '@material-ui/icons/KeyboardArrowLeft';
+import KeyboardArrowRight from '@material-ui/icons/KeyboardArrowRight';
import React from 'react';
import BugRow from './BugRow';
-const styles = theme => ({
+const useStyles = makeStyles(theme => ({
main: {
maxWidth: 600,
margin: 'auto',
marginTop: theme.spacing.unit * 4,
},
-});
-
-class List extends React.Component {
- props: {
- bugs: Array,
- fetchMore: any => any,
- classes: any,
- };
-
- state = {
- page: 0,
- rowsPerPage: 10,
- lastQuery: {},
- };
-
- handleChangePage = (event, page) => {
- const { bugs, fetchMore } = this.props;
- const { rowsPerPage } = this.state;
- const pageInfo = bugs.pageInfo;
-
- if (page === this.state.page + 1) {
- if (!pageInfo.hasNextPage) {
- return;
- }
-
- const variables = {
- after: pageInfo.endCursor,
- first: rowsPerPage,
- };
-
- fetchMore({
- variables,
- updateQuery: this.updateQuery,
- });
-
- this.setState({ page, lastQuery: variables });
- return;
- }
-
- if (page === this.state.page - 1) {
- if (!pageInfo.hasPreviousPage) {
- return;
- }
-
- const variables = {
- before: pageInfo.startCursor,
- last: rowsPerPage,
- };
-
- fetchMore({
- variables,
- updateQuery: this.updateQuery,
- });
-
- this.setState({ page, lastQuery: variables });
- return;
- }
-
- throw new Error('non neighbour page pagination is not supported');
- };
-
- handleChangeRowsPerPage = event => {
- const { fetchMore } = this.props;
- const { lastQuery } = this.state;
- const rowsPerPage = event.target.value;
-
- const variables = lastQuery;
-
- if (lastQuery.first) {
- variables.first = rowsPerPage;
- } else if (lastQuery.last) {
- variables.last = rowsPerPage;
- } else {
- variables.first = rowsPerPage;
- }
-
- fetchMore({
- variables,
- updateQuery: this.updateQuery,
- });
-
- this.setState({ rowsPerPage, lastQuery: variables });
- };
-
- updateQuery = (previousResult, { fetchMoreResult }) => {
- return fetchMoreResult ? fetchMoreResult : previousResult;
- };
-
- render() {
- const { classes, bugs } = this.props;
- const { page, rowsPerPage } = this.state;
-
- return (
- <main className={classes.main}>
- <Table className={classes.table}>
- <TableBody>
- {bugs.edges.map(({ cursor, node }) => (
- <BugRow bug={node} key={cursor} />
- ))}
- </TableBody>
- </Table>
- <TablePagination
- component="div"
- count={bugs.totalCount}
- rowsPerPage={rowsPerPage}
- page={page}
- backIconButtonProps={{
- 'aria-label': 'Previous Page',
- }}
- nextIconButtonProps={{
- 'aria-label': 'Next Page',
- }}
- onChangePage={this.handleChangePage}
- onChangeRowsPerPage={this.handleChangeRowsPerPage}
- />
- </main>
- );
- }
+ pagination: {
+ ...theme.typography.overline,
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'flex-end',
+ },
+}));
+
+function List({ bugs, nextPage, prevPage }) {
+ const classes = useStyles();
+ const { hasNextPage, hasPreviousPage } = bugs.pageInfo;
+ return (
+ <main className={classes.main}>
+ <Table className={classes.table}>
+ <TableBody>
+ {bugs.edges.map(({ cursor, node }) => (
+ <BugRow bug={node} key={cursor} />
+ ))}
+ </TableBody>
+ </Table>
+
+ <div className={classes.pagination}>
+ <div>Total: {bugs.totalCount}</div>
+ <IconButton onClick={prevPage} disabled={!hasPreviousPage}>
+ <KeyboardArrowLeft />
+ </IconButton>
+ <IconButton onClick={nextPage} disabled={!hasNextPage}>
+ <KeyboardArrowRight />
+ </IconButton>
+ </div>
+ </main>
+ );
}
-export default withStyles(styles)(List);
+export default List;
diff --git a/webui/src/list/ListQuery.js b/webui/src/list/ListQuery.js
index 9dbe4e53..869bca79 100644
--- a/webui/src/list/ListQuery.js
+++ b/webui/src/list/ListQuery.js
@@ -1,13 +1,13 @@
// @flow
import CircularProgress from '@material-ui/core/CircularProgress';
import gql from 'graphql-tag';
-import React from 'react';
+import React, { useState } from 'react';
import { Query } from 'react-apollo';
import BugRow from './BugRow';
import List from './List';
const QUERY = gql`
- query($first: Int = 10, $last: Int, $after: String, $before: String) {
+ query($first: Int, $last: Int, $after: String, $before: String) {
defaultRepository {
bugs: allBugs(
first: $first
@@ -35,14 +35,31 @@ const QUERY = gql`
${BugRow.fragment}
`;
-const ListQuery = () => (
- <Query query={QUERY}>
- {({ loading, error, data, fetchMore }) => {
- if (loading) return <CircularProgress />;
- if (error) return <p>Error: {error}</p>;
- return <List bugs={data.defaultRepository.bugs} fetchMore={fetchMore} />;
- }}
- </Query>
-);
+function ListQuery() {
+ const [page, setPage] = useState({ first: 10, after: null });
+
+ const perPage = page.first || page.last;
+ const nextPage = pageInfo =>
+ setPage({ first: perPage, after: pageInfo.endCursor });
+ const prevPage = pageInfo =>
+ setPage({ last: perPage, before: pageInfo.startCursor });
+
+ return (
+ <Query query={QUERY} variables={page}>
+ {({ loading, error, data }) => {
+ if (loading) return <CircularProgress />;
+ if (error) return <p>Error: {error}</p>;
+ const bugs = data.defaultRepository.bugs;
+ return (
+ <List
+ bugs={bugs}
+ nextPage={() => nextPage(bugs.pageInfo)}
+ prevPage={() => prevPage(bugs.pageInfo)}
+ />
+ );
+ }}
+ </Query>
+ );
+}
export default ListQuery;