aboutsummaryrefslogtreecommitdiffstats
path: root/webui/src/list/Filter.js
diff options
context:
space:
mode:
Diffstat (limited to 'webui/src/list/Filter.js')
-rw-r--r--webui/src/list/Filter.js73
1 files changed, 70 insertions, 3 deletions
diff --git a/webui/src/list/Filter.js b/webui/src/list/Filter.js
index ce457d03..c93b2d35 100644
--- a/webui/src/list/Filter.js
+++ b/webui/src/list/Filter.js
@@ -1,6 +1,58 @@
import React from 'react';
+import { Link } from 'react-router-dom';
import { makeStyles } from '@material-ui/styles';
+function parse(query) {
+ // TODO: extract the rest of the query?
+ const params = {};
+
+ // TODO: support escaping without quotes
+ const re = /(\w+):(\w+|(["'])(([^\3]|\\.)*)\3)+/g;
+ let matches;
+ while ((matches = re.exec(query)) !== null) {
+ if (!params[matches[1]]) {
+ params[matches[1]] = [];
+ }
+
+ let value;
+ if (matches[4]) {
+ value = matches[4];
+ } else {
+ value = matches[2];
+ }
+ value = value.replace(/\\(.)/g, '$1');
+ params[matches[1]].push(value);
+ }
+ return params;
+}
+
+function quote(value) {
+ const hasSingle = value.includes("'");
+ const hasDouble = value.includes('"');
+ const hasSpaces = value.includes(' ');
+ if (!hasSingle && !hasDouble && !hasSpaces) {
+ return value;
+ }
+
+ if (!hasDouble) {
+ return `"${value}"`;
+ }
+
+ if (!hasSingle) {
+ return `'${value}'`;
+ }
+
+ value = value.replace(/"/g, '\\"');
+ return `"${value}"`;
+}
+
+function stringify(params) {
+ const parts = Object.entries(params).map(([key, values]) => {
+ return values.map(value => `${key}:${quote(value)}`);
+ });
+ return [].concat(...parts).join(' ');
+}
+
const useStyles = makeStyles(theme => ({
element: {
...theme.typography.body2,
@@ -18,15 +70,30 @@ const useStyles = makeStyles(theme => ({
},
}));
-function Filter({ active, children, icon: Icon, end, ...props }) {
+function Filter({ active, to, children, icon: Icon, end, ...props }) {
const classes = useStyles({ active, end });
- return (
- <button {...props} className={classes.element}>
+ const content = (
+ <>
{Icon && <Icon fontSize="small" classes={{ root: classes.icon }} />}
<div>{children}</div>
+ </>
+ );
+
+ if (to) {
+ return (
+ <Link to={to} {...props} className={classes.element}>
+ {content}
+ </Link>
+ );
+ }
+
+ return (
+ <button {...props} className={classes.element}>
+ {content}
</button>
);
}
export default Filter;
+export { parse, stringify, quote };