aboutsummaryrefslogtreecommitdiffstats
path: root/webui/src
diff options
context:
space:
mode:
Diffstat (limited to 'webui/src')
-rw-r--r--webui/src/App.js48
-rw-r--r--webui/src/Label.js21
-rw-r--r--webui/src/bug/Bug.js65
-rw-r--r--webui/src/bug/LabelChange.js13
-rw-r--r--webui/src/bug/Message.js43
-rw-r--r--webui/src/bug/SetStatus.js13
-rw-r--r--webui/src/bug/SetTitle.js13
-rw-r--r--webui/src/bug/Timeline.js60
-rw-r--r--webui/src/index.js19
-rw-r--r--webui/src/list/BugRow.js67
-rw-r--r--webui/src/list/List.js160
-rw-r--r--webui/src/list/ListQuery.js39
12 files changed, 255 insertions, 306 deletions
diff --git a/webui/src/App.js b/webui/src/App.js
index 3a693dcb..b2eb6bf0 100644
--- a/webui/src/App.js
+++ b/webui/src/App.js
@@ -1,39 +1,39 @@
import AppBar from '@material-ui/core/AppBar';
import CssBaseline from '@material-ui/core/CssBaseline';
-import { withStyles } from '@material-ui/core/styles';
+import { makeStyles } from '@material-ui/styles';
import Toolbar from '@material-ui/core/Toolbar';
-import Typography from '@material-ui/core/Typography';
import React from 'react';
-import { Route, Switch, withRouter } from 'react-router';
+import { Route, Switch } from 'react-router';
import { Link } from 'react-router-dom';
import BugQuery from './bug/BugQuery';
import ListQuery from './list/ListQuery';
-const styles = theme => ({
+const useStyles = makeStyles(theme => ({
appTitle: {
+ ...theme.typography.title,
color: 'white',
textDecoration: 'none',
},
-});
+}));
-const App = ({ location, classes }) => (
- <React.Fragment>
- <CssBaseline />
- <AppBar position="static" color="primary">
- <Toolbar>
- <Link to="/" className={classes.appTitle}>
- <Typography variant="title" color="inherit">
- git-bug webui
- </Typography>
- </Link>
- </Toolbar>
- </AppBar>
- <Switch>
- <Route path="/" exact component={ListQuery} />
- <Route path="/bug/:id" exact component={BugQuery} />
- </Switch>
- </React.Fragment>
-);
+export default function App() {
+ const classes = useStyles();
-export default withStyles(styles)(withRouter(App));
+ return (
+ <>
+ <CssBaseline />
+ <AppBar position="static" color="primary">
+ <Toolbar>
+ <Link to="/" className={classes.appTitle}>
+ git-bug webui
+ </Link>
+ </Toolbar>
+ </AppBar>
+ <Switch>
+ <Route path="/" exact component={ListQuery} />
+ <Route path="/bug/:id" exact component={BugQuery} />
+ </Switch>
+ </>
+ );
+}
diff --git a/webui/src/Label.js b/webui/src/Label.js
index e7c25c23..826d21f5 100644
--- a/webui/src/Label.js
+++ b/webui/src/Label.js
@@ -1,5 +1,5 @@
import React from 'react';
-import { withStyles } from '@material-ui/core/styles';
+import { makeStyles } from '@material-ui/styles';
import {
getContrastRatio,
darken,
@@ -42,7 +42,7 @@ const _genStyle = background => ({
// Generate a style object (text, background and border colors) from the label
const genStyle = label => _genStyle(getColor(label));
-const styles = theme => ({
+const useStyles = makeStyles(theme => ({
label: {
...theme.typography.body2,
padding: '0 6px',
@@ -53,12 +53,15 @@ const styles = theme => ({
borderBottom: 'solid 1.5px',
verticalAlign: 'bottom',
},
-});
+}));
-const Label = ({ label, classes }) => (
- <span className={classes.label} style={genStyle(label)}>
- {label}
- </span>
-);
+function Label({ label }) {
+ const classes = useStyles();
+ return (
+ <span className={classes.label} style={genStyle(label)}>
+ {label}
+ </span>
+ );
+}
-export default withStyles(styles)(Label);
+export default Label;
diff --git a/webui/src/bug/Bug.js b/webui/src/bug/Bug.js
index 9b5f84ad..829a4af2 100644
--- a/webui/src/bug/Bug.js
+++ b/webui/src/bug/Bug.js
@@ -1,4 +1,4 @@
-import { withStyles } from '@material-ui/core/styles';
+import { makeStyles } from '@material-ui/styles';
import Typography from '@material-ui/core/Typography/Typography';
import gql from 'graphql-tag';
import React from 'react';
@@ -7,7 +7,7 @@ import Date from '../Date';
import TimelineQuery from './TimelineQuery';
import Label from '../Label';
-const styles = theme => ({
+const useStyles = makeStyles(theme => ({
main: {
maxWidth: 800,
margin: 'auto',
@@ -48,38 +48,41 @@ const styles = theme => ({
display: 'block',
},
},
-});
+}));
-const Bug = ({ bug, classes }) => (
- <main className={classes.main}>
- <div className={classes.header}>
- <span className={classes.title}>{bug.title}</span>
- <span className={classes.id}>{bug.humanId}</span>
+function Bug({ bug }) {
+ const classes = useStyles();
+ return (
+ <main className={classes.main}>
+ <div className={classes.header}>
+ <span className={classes.title}>{bug.title}</span>
+ <span className={classes.id}>{bug.humanId}</span>
- <Typography color={'textSecondary'}>
- <Author author={bug.author} />
- {' opened this bug '}
- <Date date={bug.createdAt} />
- </Typography>
- </div>
-
- <div className={classes.container}>
- <div className={classes.timeline}>
- <TimelineQuery id={bug.id} />
+ <Typography color={'textSecondary'}>
+ <Author author={bug.author} />
+ {' opened this bug '}
+ <Date date={bug.createdAt} />
+ </Typography>
</div>
- <div className={classes.sidebar}>
- <Typography variant={'subheading'}>Labels</Typography>
- <ul className={classes.labelList}>
- {bug.labels.map(l => (
- <li className={classes.label}>
- <Label label={l} key={l} />
- </li>
- ))}
- </ul>
+
+ <div className={classes.container}>
+ <div className={classes.timeline}>
+ <TimelineQuery id={bug.id} />
+ </div>
+ <div className={classes.sidebar}>
+ <Typography variant={'subheading'}>Labels</Typography>
+ <ul className={classes.labelList}>
+ {bug.labels.map(l => (
+ <li className={classes.label}>
+ <Label label={l} key={l} />
+ </li>
+ ))}
+ </ul>
+ </div>
</div>
- </div>
- </main>
-);
+ </main>
+ );
+}
Bug.fragment = gql`
fragment Bug on Bug {
@@ -97,4 +100,4 @@ Bug.fragment = gql`
}
`;
-export default withStyles(styles)(Bug);
+export default Bug;
diff --git a/webui/src/bug/LabelChange.js b/webui/src/bug/LabelChange.js
index 6301f35f..76b6e6e2 100644
--- a/webui/src/bug/LabelChange.js
+++ b/webui/src/bug/LabelChange.js
@@ -1,11 +1,11 @@
-import { withStyles } from '@material-ui/core/styles';
+import { makeStyles } from '@material-ui/styles';
import gql from 'graphql-tag';
import React from 'react';
import Author from '../Author';
import Date from '../Date';
import Label from '../Label';
-const styles = theme => ({
+const useStyles = makeStyles(theme => ({
main: {
...theme.typography.body2,
marginLeft: theme.spacing.unit + 40,
@@ -13,10 +13,11 @@ const styles = theme => ({
author: {
fontWeight: 'bold',
},
-});
+}));
-const LabelChange = ({ op, classes }) => {
+function LabelChange({ op }) {
const { added, removed } = op;
+ const classes = useStyles();
return (
<div className={classes.main}>
<Author author={op.author} className={classes.author} />
@@ -37,7 +38,7 @@ const LabelChange = ({ op, classes }) => {
<Date date={op.date} />
</div>
);
-};
+}
LabelChange.fragment = gql`
fragment LabelChange on TimelineItem {
@@ -54,4 +55,4 @@ LabelChange.fragment = gql`
}
`;
-export default withStyles(styles)(LabelChange);
+export default LabelChange;
diff --git a/webui/src/bug/Message.js b/webui/src/bug/Message.js
index 493de8ee..ff039444 100644
--- a/webui/src/bug/Message.js
+++ b/webui/src/bug/Message.js
@@ -1,4 +1,4 @@
-import { withStyles } from '@material-ui/core/styles';
+import { makeStyles } from '@material-ui/styles';
import Paper from '@material-ui/core/Paper';
import gql from 'graphql-tag';
import React from 'react';
@@ -6,7 +6,7 @@ import Author from '../Author';
import { Avatar } from '../Author';
import Date from '../Date';
-const styles = theme => ({
+const useStyles = makeStyles(theme => ({
author: {
fontWeight: 'bold',
},
@@ -44,24 +44,27 @@ const styles = theme => ({
padding: '1rem',
whiteSpace: 'pre-wrap',
},
-});
+}));
-const Message = ({ op, classes }) => (
- <article className={classes.container}>
- <Avatar author={op.author} className={classes.avatar} />
- <Paper elevation={1} className={classes.bubble}>
- <header className={classes.header}>
- <div className={classes.title}>
- <Author className={classes.author} author={op.author} />
- <span> commented </span>
- <Date date={op.createdAt} />
- </div>
- {op.edited && <div className={classes.tag}>Edited</div>}
- </header>
- <section className={classes.body}>{op.message}</section>
- </Paper>
- </article>
-);
+function Message({ op }) {
+ const classes = useStyles();
+ return (
+ <article className={classes.container}>
+ <Avatar author={op.author} className={classes.avatar} />
+ <Paper elevation={1} className={classes.bubble}>
+ <header className={classes.header}>
+ <div className={classes.title}>
+ <Author className={classes.author} author={op.author} />
+ <span> commented </span>
+ <Date date={op.createdAt} />
+ </div>
+ {op.edited && <div className={classes.tag}>Edited</div>}
+ </header>
+ <section className={classes.body}>{op.message}</section>
+ </Paper>
+ </article>
+ );
+}
Message.createFragment = gql`
fragment Create on TimelineItem {
@@ -95,4 +98,4 @@ Message.commentFragment = gql`
}
`;
-export default withStyles(styles)(Message);
+export default Message;
diff --git a/webui/src/bug/SetStatus.js b/webui/src/bug/SetStatus.js
index 58b81630..ab591038 100644
--- a/webui/src/bug/SetStatus.js
+++ b/webui/src/bug/SetStatus.js
@@ -1,17 +1,18 @@
-import { withStyles } from '@material-ui/core/styles';
+import { makeStyles } from '@material-ui/styles';
import gql from 'graphql-tag';
import React from 'react';
import Author from '../Author';
import Date from '../Date';
-const styles = theme => ({
+const useStyles = makeStyles(theme => ({
main: {
...theme.typography.body2,
marginLeft: theme.spacing.unit + 40,
},
-});
+}));
-const SetStatus = ({ op, classes }) => {
+function SetStatus({ op }) {
+ const classes = useStyles();
return (
<div className={classes.main}>
<Author author={op.author} bold />
@@ -19,7 +20,7 @@ const SetStatus = ({ op, classes }) => {
<Date date={op.date} />
</div>
);
-};
+}
SetStatus.fragment = gql`
fragment SetStatus on TimelineItem {
@@ -35,4 +36,4 @@ SetStatus.fragment = gql`
}
`;
-export default withStyles(styles)(SetStatus);
+export default SetStatus;
diff --git a/webui/src/bug/SetTitle.js b/webui/src/bug/SetTitle.js
index f5c48568..d9a09ad5 100644
--- a/webui/src/bug/SetTitle.js
+++ b/webui/src/bug/SetTitle.js
@@ -1,10 +1,10 @@
-import { withStyles } from '@material-ui/core/styles';
+import { makeStyles } from '@material-ui/styles';
import gql from 'graphql-tag';
import React from 'react';
import Author from '../Author';
import Date from '../Date';
-const styles = theme => ({
+const useStyles = makeStyles(theme => ({
main: {
...theme.typography.body2,
marginLeft: theme.spacing.unit + 40,
@@ -12,9 +12,10 @@ const styles = theme => ({
bold: {
fontWeight: 'bold',
},
-});
+}));
-const SetTitle = ({ op, classes }) => {
+function SetTitle({ op }) {
+ const classes = useStyles();
return (
<div className={classes.main}>
<Author author={op.author} className={classes.bold} />
@@ -25,7 +26,7 @@ const SetTitle = ({ op, classes }) => {
<Date date={op.date} />
</div>
);
-};
+}
SetTitle.fragment = gql`
fragment SetTitle on TimelineItem {
@@ -42,4 +43,4 @@ SetTitle.fragment = gql`
}
`;
-export default withStyles(styles)(SetTitle);
+export default SetTitle;
diff --git a/webui/src/bug/Timeline.js b/webui/src/bug/Timeline.js
index 3123f45f..d77e0d4b 100644
--- a/webui/src/bug/Timeline.js
+++ b/webui/src/bug/Timeline.js
@@ -1,51 +1,43 @@
-import { withStyles } from '@material-ui/core/styles';
+import { makeStyles } from '@material-ui/styles';
import React from 'react';
import LabelChange from './LabelChange';
import Message from './Message';
import SetStatus from './SetStatus';
import SetTitle from './SetTitle';
-const styles = theme => ({
+const useStyles = makeStyles(theme => ({
main: {
'& > *:not(:last-child)': {
marginBottom: theme.spacing.unit * 2,
},
},
-});
+}));
-class Timeline extends React.Component {
- props: {
- ops: Array,
- fetchMore: any => any,
- classes: any,
- };
+const componentMap = {
+ CreateTimelineItem: Message,
+ AddCommentTimelineItem: Message,
+ LabelChangeTimelineItem: LabelChange,
+ SetTitleTimelineItem: SetTitle,
+ SetStatusTimelineItem: SetStatus,
+};
- render() {
- const { ops, classes } = this.props;
+function Timeline({ ops }) {
+ const classes = useStyles();
- return (
- <div className={classes.main}>
- {ops.map((op, index) => {
- switch (op.__typename) {
- case 'CreateTimelineItem':
- return <Message key={index} op={op} />;
- case 'AddCommentTimelineItem':
- return <Message key={index} op={op} />;
- case 'LabelChangeTimelineItem':
- return <LabelChange key={index} op={op} />;
- case 'SetTitleTimelineItem':
- return <SetTitle key={index} op={op} />;
- case 'SetStatusTimelineItem':
- return <SetStatus key={index} op={op} />;
+ return (
+ <div className={classes.main}>
+ {ops.map((op, index) => {
+ const Component = componentMap[op.__typename];
- default:
- console.log('unsupported operation type ' + op.__typename);
- return null;
- }
- })}
- </div>
- );
- }
+ if (!Component) {
+ console.warn('unsupported operation type ' + op.__typename);
+ return null;
+ }
+
+ return <Component key={index} op={op} />;
+ })}
+ </div>
+ );
}
-export default withStyles(styles)(Timeline);
+export default Timeline;
diff --git a/webui/src/index.js b/webui/src/index.js
index f5d95ccc..885911f5 100644
--- a/webui/src/index.js
+++ b/webui/src/index.js
@@ -1,22 +1,31 @@
+import { install } from '@material-ui/styles';
+import ThemeProvider from '@material-ui/styles/ThemeProvider';
+import { createMuiTheme } from '@material-ui/core/styles';
import ApolloClient from 'apollo-boost';
import React from 'react';
import { ApolloProvider } from 'react-apollo';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
-import App from './App';
+install();
+
+// TODO(sandhose): this is temporary until Material-UI v4 goes out
+const App = React.lazy(() => import('./App'));
+
+const theme = createMuiTheme();
const client = new ApolloClient({
uri: '/graphql',
- connectToDevTools: true,
});
ReactDOM.render(
<ApolloProvider client={client}>
<BrowserRouter>
- <React.Fragment>
- <App />
- </React.Fragment>
+ <ThemeProvider theme={theme}>
+ <React.Suspense fallback={'Loading…'}>
+ <App />
+ </React.Suspense>
+ </ThemeProvider>
</BrowserRouter>
</ApolloProvider>,
document.getElementById('root')
diff --git a/webui/src/list/BugRow.js b/webui/src/list/BugRow.js
index a045770b..e82d81db 100644
--- a/webui/src/list/BugRow.js
+++ b/webui/src/list/BugRow.js
@@ -1,4 +1,4 @@
-import { withStyles } from '@material-ui/core/styles';
+import { makeStyles } from '@material-ui/styles';
import TableCell from '@material-ui/core/TableCell/TableCell';
import TableRow from '@material-ui/core/TableRow/TableRow';
import Tooltip from '@material-ui/core/Tooltip/Tooltip';
@@ -33,7 +33,7 @@ const Status = ({ status, className }) => {
}
};
-const styles = theme => ({
+const useStyles = makeStyles(theme => ({
cell: {
display: 'flex',
alignItems: 'center',
@@ -53,36 +53,39 @@ const styles = theme => ({
labels: {
paddingLeft: theme.spacing.unit,
},
-});
+}));
-const BugRow = ({ bug, classes }) => (
- <TableRow hover>
- <TableCell className={classes.cell}>
- <Status status={bug.status} className={classes.status} />
- <div className={classes.expand}>
- <Link to={'bug/' + bug.humanId}>
- <div className={classes.expand}>
- <Typography variant={'title'} className={classes.title}>
- {bug.title}
- </Typography>
- {bug.labels.length > 0 && (
- <span className={classes.labels}>
- {bug.labels.map(l => (
- <Label key={l} label={l} />
- ))}
- </span>
- )}
- </div>
- </Link>
- <Typography color={'textSecondary'}>
- {bug.humanId} opened
- <Date date={bug.createdAt} />
- by {bug.author.displayName}
- </Typography>
- </div>
- </TableCell>
- </TableRow>
-);
+function BugRow({ bug }) {
+ const classes = useStyles();
+ return (
+ <TableRow hover>
+ <TableCell className={classes.cell}>
+ <Status status={bug.status} className={classes.status} />
+ <div className={classes.expand}>
+ <Link to={'bug/' + bug.humanId}>
+ <div className={classes.expand}>
+ <Typography variant={'title'} className={classes.title}>
+ {bug.title}
+ </Typography>
+ {bug.labels.length > 0 && (
+ <span className={classes.labels}>
+ {bug.labels.map(l => (
+ <Label key={l} label={l} />
+ ))}
+ </span>
+ )}
+ </div>
+ </Link>
+ <Typography color={'textSecondary'}>
+ {bug.humanId} opened
+ <Date date={bug.createdAt} />
+ by {bug.author.displayName}
+ </Typography>
+ </div>
+ </TableCell>
+ </TableRow>
+ );
+}
BugRow.fragment = gql`
fragment BugRow on Bug {
@@ -99,4 +102,4 @@ BugRow.fragment = gql`
}
`;
-export default withStyles(styles)(BugRow);
+export default BugRow;
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;