From 92ce861fabe0fde3dd180cf4b795355093597a90 Mon Sep 17 00:00:00 2001 From: Aien Saidi Date: Wed, 24 Mar 2021 00:37:04 +0100 Subject: feat: multiple label filter - add search functionality in menu items --- webui/src/pages/list/Filter.tsx | 60 ++++++++++++++++++++++++++-------- webui/src/pages/list/FilterToolbar.tsx | 34 +++++++++++++------ 2 files changed, 71 insertions(+), 23 deletions(-) (limited to 'webui/src/pages') diff --git a/webui/src/pages/list/Filter.tsx b/webui/src/pages/list/Filter.tsx index 66702078..154d0f94 100644 --- a/webui/src/pages/list/Filter.tsx +++ b/webui/src/pages/list/Filter.tsx @@ -1,14 +1,26 @@ import clsx from 'clsx'; import { LocationDescriptor } from 'history'; -import React, { useState, useRef } from 'react'; +import React, { useRef, useState } from 'react'; import { Link } from 'react-router-dom'; import Menu from '@material-ui/core/Menu'; import MenuItem from '@material-ui/core/MenuItem'; import { SvgIconProps } from '@material-ui/core/SvgIcon'; -import { makeStyles } from '@material-ui/core/styles'; +import TextField from '@material-ui/core/TextField'; +import { makeStyles, withStyles } from '@material-ui/core/styles'; import ArrowDropDown from '@material-ui/icons/ArrowDropDown'; +const CustomTextField = withStyles({ + root: { + margin: '0 8px 12px 8px', + '& label.Mui-focused': { + margin: '0 2px', + }, + }, +})(TextField); + +const ITEM_HEIGHT = 48; + export type Query = { [key: string]: string[] }; function parse(query: string): Query { @@ -90,6 +102,7 @@ type FilterDropdownProps = { itemActive: (key: string) => boolean; icon?: React.ComponentType; to: (key: string) => LocationDescriptor; + hasFilter?: boolean; } & React.ButtonHTMLAttributes; function FilterDropdown({ @@ -98,9 +111,11 @@ function FilterDropdown({ itemActive, icon: Icon, to, + hasFilter, ...props }: FilterDropdownProps) { const [open, setOpen] = useState(false); + const [filter, setFilter] = useState(''); const buttonRef = useRef(null); const classes = useStyles({ active: false }); @@ -135,18 +150,36 @@ function FilterDropdown({ open={open} onClose={() => setOpen(false)} anchorEl={buttonRef.current} + PaperProps={{ + style: { + maxHeight: ITEM_HEIGHT * 4.5, + width: '20ch', + }, + }} > - {dropdown.map(([key, value]) => ( - setOpen(false)} - key={key} - > - {value} - - ))} + {hasFilter && ( + { + const { value } = e.target; + setFilter(value); + }} + value={filter} + label={`Filter ${children}`} + /> + )} + {dropdown + .filter((d) => d[1].toLowerCase().includes(filter.toLowerCase())) + .map(([key, value]) => ( + setOpen(false)} + key={key} + > + {value} + + ))} ); @@ -158,6 +191,7 @@ export type FilterProps = { icon?: React.ComponentType; children: React.ReactNode; }; + function Filter({ active, to, children, icon: Icon }: FilterProps) { const classes = useStyles(); diff --git a/webui/src/pages/list/FilterToolbar.tsx b/webui/src/pages/list/FilterToolbar.tsx index 3046d9d8..1af96d0f 100644 --- a/webui/src/pages/list/FilterToolbar.tsx +++ b/webui/src/pages/list/FilterToolbar.tsx @@ -109,6 +109,20 @@ function FilterToolbar({ query, queryLocation }: Props) { ...params, [key]: params[key] && params[key].includes(value) ? [] : [value], }); + const toggleOrAddParam = (key: string, value: string) => ( + params: Query + ): Query => { + const values = params[key]; + return { + ...params, + [key]: + params[key] && params[key].includes(value) + ? values.filter((v) => v !== value) + : values + ? [...values, value] + : [value], + }; + }; const clearParam = (key: string) => (params: Query): Query => ({ ...params, [key]: [], @@ -150,18 +164,18 @@ function FilterToolbar({ query, queryLocation }: Props) { dropdown={identities} itemActive={(key) => hasValue('author', key)} to={(key) => pipe(replaceParam('author', key), loc)(params)} + hasFilter > Author - {labels.length ? ( - hasValue('label', key)} - to={(key) => pipe(replaceParam('label', key), loc)(params)} - > - Label - - ) : null} + hasValue('label', key)} + to={(key) => pipe(toggleOrAddParam('label', key), loc)(params)} + hasFilter + > + Label + hasValue('sort', key)} - to={(key) => pipe(replaceParam('sort', key), loc)(params)} + to={(key) => pipe(toggleParam('sort', key), loc)(params)} > Sort -- cgit