aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--webui/src/list/FilterToolbar.js82
-rw-r--r--webui/src/list/ListQuery.js2
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);