diff options
author | Quentin Gliech <quentingliech@gmail.com> | 2020-02-04 20:57:43 +0100 |
---|---|---|
committer | Quentin Gliech <quentingliech@gmail.com> | 2020-02-11 20:54:37 +0100 |
commit | 6a502c145bd8f2e2e1a9c0b103c11f0433c60737 (patch) | |
tree | 72c3a23aa6c5df8013d53523fa4125a3e28063a8 /webui/src/list/ListQuery.js | |
parent | 9c570cac725fe7048ddd1d181b33b8fa1808e401 (diff) | |
download | git-bug-6a502c145bd8f2e2e1a9c0b103c11f0433c60737.tar.gz |
webui: convert bug list to typescript
Diffstat (limited to 'webui/src/list/ListQuery.js')
-rw-r--r-- | webui/src/list/ListQuery.js | 333 |
1 files changed, 0 insertions, 333 deletions
diff --git a/webui/src/list/ListQuery.js b/webui/src/list/ListQuery.js deleted file mode 100644 index 8eeec240..00000000 --- a/webui/src/list/ListQuery.js +++ /dev/null @@ -1,333 +0,0 @@ -import { fade, makeStyles } from '@material-ui/core/styles'; -import IconButton from '@material-ui/core/IconButton'; -import KeyboardArrowLeft from '@material-ui/icons/KeyboardArrowLeft'; -import KeyboardArrowRight from '@material-ui/icons/KeyboardArrowRight'; -import ErrorOutline from '@material-ui/icons/ErrorOutline'; -import Paper from '@material-ui/core/Paper'; -import InputBase from '@material-ui/core/InputBase'; -import Skeleton from '@material-ui/lab/Skeleton'; -import gql from 'graphql-tag'; -import React, { useState, useEffect, useRef } from 'react'; -import { useQuery } from '@apollo/react-hooks'; -import { useLocation, useHistory, Link } from 'react-router-dom'; -import BugRow from './BugRow'; -import List from './List'; -import FilterToolbar from './FilterToolbar'; - -const useStyles = makeStyles(theme => ({ - main: { - maxWidth: 800, - margin: 'auto', - marginTop: theme.spacing(4), - marginBottom: theme.spacing(4), - overflow: 'hidden', - }, - pagination: { - ...theme.typography.overline, - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - }, - header: { - display: 'flex', - padding: theme.spacing(2), - '& > h1': { - ...theme.typography.h6, - margin: theme.spacing(0, 2), - }, - alignItems: 'center', - justifyContent: 'space-between', - }, - search: { - borderRadius: theme.shape.borderRadius, - borderColor: fade(theme.palette.primary.main, 0.2), - borderStyle: 'solid', - borderWidth: '1px', - backgroundColor: fade(theme.palette.primary.main, 0.05), - padding: theme.spacing(0, 1), - width: ({ searching }) => (searching ? '20rem' : '15rem'), - transition: theme.transitions.create(), - }, - searchFocused: { - borderColor: fade(theme.palette.primary.main, 0.4), - backgroundColor: theme.palette.background.paper, - width: '20rem!important', - }, - placeholderRow: { - padding: theme.spacing(1), - borderBottomColor: theme.palette.grey['300'], - borderBottomWidth: '1px', - borderBottomStyle: 'solid', - display: 'flex', - alignItems: 'center', - }, - placeholderRowStatus: { - margin: theme.spacing(1, 2), - }, - placeholderRowText: { - flex: 1, - }, - message: { - ...theme.typography.h5, - padding: theme.spacing(8), - textAlign: 'center', - borderBottomColor: theme.palette.grey['300'], - borderBottomWidth: '1px', - borderBottomStyle: 'solid', - '& > p': { - margin: '0', - }, - }, - errorBox: { - color: theme.palette.error.main, - '& > pre': { - fontSize: '1rem', - textAlign: 'left', - backgroundColor: theme.palette.grey['900'], - color: theme.palette.common.white, - marginTop: theme.spacing(4), - padding: theme.spacing(2, 3), - }, - }, -})); - -const QUERY = gql` - query( - $first: Int - $last: Int - $after: String - $before: String - $query: String - ) { - defaultRepository { - bugs: allBugs( - first: $first - last: $last - after: $after - before: $before - query: $query - ) { - totalCount - edges { - cursor - node { - ...BugRow - } - } - pageInfo { - hasNextPage - hasPreviousPage - startCursor - endCursor - } - } - } - } - - ${BugRow.fragment} -`; - -function editParams(params, callback) { - const cloned = new URLSearchParams(params.toString()); - callback(cloned); - return cloned; -} - -// TODO: factor this out -const Placeholder = ({ count }) => { - const classes = useStyles(); - return ( - <> - {new Array(count).fill(null).map((_, i) => ( - <div key={i} className={classes.placeholderRow}> - <Skeleton - className={classes.placeholderRowStatus} - variant="circle" - width={20} - height={20} - /> - <div className={classes.placeholderRowText}> - <Skeleton height={22} /> - <Skeleton height={24} width="60%" /> - </div> - </div> - ))} - </> - ); -}; - -// TODO: factor this out -const NoBug = () => { - const classes = useStyles(); - return ( - <div className={classes.message}> - <ErrorOutline fontSize="large" /> - <p>No results matched your search.</p> - </div> - ); -}; - -const Error = ({ error }) => { - const classes = useStyles(); - return ( - <div className={[classes.errorBox, classes.message].join(' ')}> - <ErrorOutline fontSize="large" /> - <p>There was an error while fetching bug.</p> - <p> - <em>{error.message}</em> - </p> - <pre> - <code>{JSON.stringify(error, null, 2)}</code> - </pre> - </div> - ); -}; - -function ListQuery() { - const location = useLocation(); - const history = useHistory(); - const params = new URLSearchParams(location.search); - const query = params.get('q') || ''; - - const [input, setInput] = useState(query); - - const classes = useStyles({ searching: !!input }); - - // TODO is this the right way to do it? - const lastQuery = useRef(); - useEffect(() => { - if (query !== lastQuery.current) { - setInput(query); - } - lastQuery.current = query; - }, [query, input, lastQuery]); - - const page = { - first: params.get('first'), - last: params.get('last'), - after: params.get('after'), - before: params.get('before'), - }; - - // If nothing set, show the first 10 items - if (!page.first && !page.last) { - page.first = 10; - } - - const perPage = page.first || page.last; - - const { loading, error, data } = useQuery(QUERY, { - variables: { - ...page, - query, - }, - }); - - let nextPage = null; - let previousPage = null; - let hasNextPage = false; - let hasPreviousPage = false; - let count = 0; - if (!loading && !error && data.defaultRepository.bugs) { - const bugs = data.defaultRepository.bugs; - hasNextPage = bugs.pageInfo.hasNextPage; - hasPreviousPage = bugs.pageInfo.hasPreviousPage; - count = bugs.totalCount; - // This computes the URL for the next page - nextPage = { - ...location, - search: editParams(params, p => { - p.delete('last'); - p.delete('before'); - p.set('first', perPage); - p.set('after', bugs.pageInfo.endCursor); - }).toString(), - }; - // and this for the previous page - previousPage = { - ...location, - search: editParams(params, p => { - p.delete('first'); - p.delete('after'); - p.set('last', perPage); - p.set('before', bugs.pageInfo.startCursor); - }).toString(), - }; - } - - // Prepare params without paging for editing filters - const paramsWithoutPaging = editParams(params, p => { - p.delete('first'); - p.delete('last'); - p.delete('before'); - p.delete('after'); - }); - // Returns a new location with the `q` param edited - const queryLocation = query => ({ - ...location, - search: editParams(paramsWithoutPaging, p => p.set('q', query)).toString(), - }); - - let content; - if (loading) { - content = <Placeholder count={10} />; - } else if (error) { - content = <Error error={error} />; - } else { - const bugs = data.defaultRepository.bugs; - - if (bugs.totalCount === 0) { - content = <NoBug />; - } else { - content = <List bugs={bugs} />; - } - } - - const formSubmit = e => { - e.preventDefault(); - history.push(queryLocation(input)); - }; - - return ( - <Paper className={classes.main}> - <header className={classes.header}> - <h1>Issues</h1> - <form onSubmit={formSubmit}> - <InputBase - placeholder="Filter" - value={input} - onInput={e => setInput(e.target.value)} - classes={{ - root: classes.search, - focused: classes.searchFocused, - }} - /> - <button type="submit" hidden> - Search - </button> - </form> - </header> - <FilterToolbar query={query} queryLocation={queryLocation} /> - {content} - <div className={classes.pagination}> - <IconButton - component={hasPreviousPage ? Link : 'button'} - to={previousPage} - disabled={!hasPreviousPage} - > - <KeyboardArrowLeft /> - </IconButton> - <div>{loading ? 'Loading' : `Total: ${count}`}</div> - <IconButton - component={hasNextPage ? Link : 'button'} - to={nextPage} - disabled={!hasNextPage} - > - <KeyboardArrowRight /> - </IconButton> - </div> - </Paper> - ); -} - -export default ListQuery; |