diff options
-rw-r--r-- | webui/src/list/FilterToolbar.js | 82 | ||||
-rw-r--r-- | webui/src/list/ListQuery.js | 2 |
2 files changed, 68 insertions, 16 deletions
diff --git a/webui/src/list/FilterToolbar.js b/webui/src/list/FilterToolbar.js index 9f5f14c5..4d0b52b1 100644 --- a/webui/src/list/FilterToolbar.js +++ b/webui/src/list/FilterToolbar.js @@ -1,10 +1,17 @@ import { makeStyles } from '@material-ui/styles'; +import { useQuery } from '@apollo/react-hooks'; +import gql from 'graphql-tag'; import React from 'react'; import Toolbar from '@material-ui/core/Toolbar'; import ErrorOutline from '@material-ui/icons/ErrorOutline'; import CheckCircleOutline from '@material-ui/icons/CheckCircleOutline'; import Filter, { parse, stringify } from './Filter'; +// simple pipe operator +// pipe(o, f, g, h) <=> h(g(f(o))) +// TODO: move this out? +const pipe = (initial, ...funcs) => funcs.reduce((acc, f) => f(acc), initial); + const useStyles = makeStyles(theme => ({ toolbar: { backgroundColor: theme.palette.grey['100'], @@ -18,40 +25,85 @@ const useStyles = makeStyles(theme => ({ }, })); +const BUG_COUNT_QUERY = gql` + query($query: String) { + defaultRepository { + bugs: allBugs(query: $query) { + totalCount + } + } + } +`; + +// This prepends the filter text with a count +function CountingFilter({ query, children, ...props }) { + const { data, loading, error } = useQuery(BUG_COUNT_QUERY, { + variables: { query }, + }); + + var prefix; + if (loading) prefix = '...'; + else if (error) prefix = '???'; + // TODO: better prefixes & error handling + else prefix = data.defaultRepository.bugs.totalCount; + + return ( + <Filter {...props}> + {prefix} {children} + </Filter> + ); +} + function FilterToolbar({ query, queryLocation }) { const classes = useStyles(); const params = parse(query); + const hasKey = key => params[key] && params[key].length > 0; const hasValue = (key, value) => hasKey(key) && params[key].includes(value); - const replaceParam = (key, value) => { - const p = { - ...params, - [key]: [value], - }; - return queryLocation(stringify(p)); - }; + const loc = params => pipe(params, stringify, queryLocation); + const replaceParam = (key, value) => params => ({ + ...params, + [key]: [value], + }); + const clearParam = key => params => ({ + ...params, + [key]: [], + }); - // TODO: open/closed count // TODO: author/label filters return ( <Toolbar className={classes.toolbar}> - <Filter + <CountingFilter active={hasValue('status', 'open')} - to={replaceParam('status', 'open')} + query={pipe( + params, + replaceParam('status', 'open'), + clearParam('sort'), + stringify + )} + to={pipe(params, replaceParam('status', 'open'), loc)} icon={ErrorOutline} > open - </Filter> - <Filter + </CountingFilter> + <CountingFilter active={hasValue('status', 'closed')} - to={replaceParam('status', 'closed')} + query={pipe( + params, + replaceParam('status', 'closed'), + clearParam('sort'), + stringify + )} + to={pipe(params, replaceParam('status', 'closed'), loc)} icon={CheckCircleOutline} > closed - </Filter> + </CountingFilter> <div className={classes.spacer} /> + {/* <Filter active={hasKey('author')}>Author</Filter> <Filter active={hasKey('label')}>Label</Filter> + */} <Filter dropdown={[ ['id', 'ID'], @@ -62,7 +114,7 @@ function FilterToolbar({ query, queryLocation }) { ]} active={hasKey('sort')} itemActive={key => hasValue('sort', key)} - to={key => replaceParam('sort', key)} + to={key => pipe(params, replaceParam('sort', key), loc)} > Sort </Filter> diff --git a/webui/src/list/ListQuery.js b/webui/src/list/ListQuery.js index 01113f6c..8eeec240 100644 --- a/webui/src/list/ListQuery.js +++ b/webui/src/list/ListQuery.js @@ -187,7 +187,7 @@ function ListQuery() { const location = useLocation(); const history = useHistory(); const params = new URLSearchParams(location.search); - const query = params.get('q'); + const query = params.get('q') || ''; const [input, setInput] = useState(query); |