-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1c948b3
commit 48eedd1
Showing
17 changed files
with
1,121 additions
and
3 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { FilterOptions } from '../components/Filters' | ||
|
||
export const mockDynamicFilterOptions = [ | ||
{ | ||
id: '5391d028-d5fe-4c33-a4c9-8719191aaeb1', | ||
name: 'Ingestion Dev Account' | ||
}, | ||
{ | ||
id: '5391d028-d5fe-4c33-a4c9-8719191aaeb8', | ||
name: 'Ingestion Prod Account' | ||
} | ||
] | ||
|
||
export const mockFilterOptions: FilterOptions = [ | ||
{ | ||
filterKey: 'name', | ||
options: [ | ||
'Dev account', | ||
'Prod account 1', | ||
'Prod account 2', | ||
'Test account' | ||
], | ||
staticFilter: false | ||
}, | ||
{ | ||
filterKey: 'service', | ||
options: [ | ||
'EC2', | ||
'S3', | ||
'RDS', | ||
'Amazon Keyspaces (for Apache Cassandra)', | ||
'EKS' | ||
], | ||
staticFilter: true | ||
}, | ||
{ | ||
filterKey: 'model', | ||
options: ['instance', 'bucket', 'table'], | ||
staticFilter: true | ||
}, | ||
{ | ||
filterKey: 'region', | ||
options: ['us-west-1', 'us-east-2', 'ap-south-1'], | ||
staticFilter: true | ||
} | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './filter_mock_data' | ||
export * from './table_mock_data' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import { Button } from 'components/Button' | ||
import { faFilter } from '@fortawesome/free-solid-svg-icons' | ||
import FilterUnit from './FilterUnit' | ||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' | ||
import { Link } from 'components/Link' | ||
import { Popover } from 'components/Popover' | ||
import { SelectOption } from 'components/Select' | ||
import { usePopoverStyles } from './utils' | ||
import { FiltersList, OnSearchWrapper, ProcessedFilters } from './types' | ||
import { IconButton, IconSizes } from 'components/IconButton' | ||
import React, { FC } from 'react' | ||
|
||
interface FilterPopoverProps { | ||
allFilters: ProcessedFilters | ||
closePopover: () => void | ||
dynamicOptions?: SelectOption[] | ||
dynamicSearchVal: string | ||
filtersList: FiltersList | ||
onVisibleChange: (visible: boolean) => void | ||
onClickAddFilter: () => void | ||
onDelete: (selectedId: string) => void | ||
onFilterChange: (selectedId: string, selection: string | string[]) => void | ||
onSearchWrapper: OnSearchWrapper | ||
pending: boolean | ||
setFiltersList: React.Dispatch<React.SetStateAction<FiltersList>> | ||
visible?: boolean | ||
} | ||
|
||
export const FilterPopover: FC<FilterPopoverProps> = ({ | ||
allFilters, | ||
closePopover, | ||
dynamicOptions, | ||
dynamicSearchVal, | ||
filtersList, | ||
onVisibleChange, | ||
onClickAddFilter, | ||
onDelete, | ||
onFilterChange, | ||
onSearchWrapper, | ||
pending, | ||
setFiltersList, | ||
visible = false | ||
}: FilterPopoverProps) => { | ||
const classes = usePopoverStyles() | ||
|
||
return ( | ||
<Popover | ||
classes={[classes.popover]} | ||
content={ | ||
<div className={classes.popoverContent}> | ||
<IconButton | ||
classes={[classes.closeButton]} | ||
onClick={closePopover} | ||
size={IconSizes.sm} | ||
/> | ||
<div className={classes.popoverControls}> | ||
<div className={classes.popoverControlsChild}> | ||
<FontAwesomeIcon icon={faFilter} /> | ||
</div> | ||
<Button | ||
classes={[classes.popoverControlsChild]} | ||
disabled={ | ||
filtersList.length >= | ||
Object.keys(allFilters).length | ||
} | ||
onClick={onClickAddFilter} | ||
> | ||
+ Add Filter | ||
</Button> | ||
{filtersList.length > 0 && ( | ||
<Link | ||
classes={[classes.popoverControlsChild]} | ||
onClick={() => setFiltersList([])} | ||
> | ||
Clear Filters | ||
</Link> | ||
)} | ||
</div> | ||
<div className={classes.filtersList}> | ||
{filtersList.map((filterItem, i) => ( | ||
<FilterUnit | ||
allFilters={allFilters} | ||
dynamicOptions={dynamicOptions} | ||
dynamicSearchVal={dynamicSearchVal} | ||
filtersList={filtersList} | ||
id={filterItem.id} | ||
key={filterItem.id} | ||
onDelete={onDelete} | ||
onFilterChange={onFilterChange} | ||
onSearchWrapper={onSearchWrapper} | ||
pending={pending} | ||
selectedFilterKey={filtersList[i].selectedKey} | ||
/> | ||
))} | ||
</div> | ||
</div> | ||
} | ||
onVisibleChange={onVisibleChange} | ||
placement='bottomLeft' | ||
popupContainerSelector='#filters-popup-wrapper' | ||
popupTriggerClasses={[classes.popoverTrigger]} | ||
trigger='click' | ||
visible={visible} | ||
> | ||
<i /> | ||
</Popover> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
import { faEquals } from '@fortawesome/free-solid-svg-icons' | ||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' | ||
import { IconButton } from 'components/IconButton' | ||
import uniq from 'lodash/uniq' | ||
import { | ||
FilterOption, | ||
FiltersList, | ||
OnSearchWrapper, | ||
ProcessedFilters | ||
} from './types' | ||
import { | ||
formatFilterOptions, | ||
getFilterKeysOptions, | ||
useFilterUnitStyles | ||
} from './utils' | ||
import { MultiSelect, Select, SelectOption } from 'components/Select' | ||
import React, { FC } from 'react' | ||
|
||
interface FilterUnitProps { | ||
id: string | ||
allFilters: ProcessedFilters | ||
dynamicOptions?: SelectOption[] | ||
dynamicSearchVal: string | ||
onDelete: (selectedId: string) => void | ||
onFilterChange: (selectedId: string, selection: string | string[]) => void | ||
filtersList: FiltersList | ||
onSearchWrapper: OnSearchWrapper | ||
pending: boolean | ||
selectedFilterKey?: string | ||
} | ||
|
||
const FilterUnit: FC<FilterUnitProps> = ({ | ||
id, | ||
allFilters = {}, | ||
dynamicOptions, | ||
dynamicSearchVal, | ||
filtersList = [], | ||
onDelete, | ||
onFilterChange, | ||
onSearchWrapper, | ||
pending, | ||
selectedFilterKey = '' | ||
}: FilterUnitProps) => { | ||
const classes = useFilterUnitStyles() | ||
|
||
const renderKey = () => ( | ||
<Select | ||
disabled={!!selectedFilterKey} | ||
matchSelectedContentWidth={125} | ||
onChange={selectedValue => | ||
onFilterChange(id, (selectedValue as unknown) as string) | ||
} | ||
options={formatFilterOptions( | ||
getFilterKeysOptions(allFilters, filtersList) | ||
)} | ||
placeholder='Select Value' | ||
showSearch | ||
/> | ||
) | ||
|
||
const renderValues = () => { | ||
const filterOption: FilterOption = allFilters[selectedFilterKey] | ||
|
||
let options: SelectOption[] = [] | ||
let dynamicFilterProps = {} | ||
|
||
if (selectedFilterKey && filterOption.options) { | ||
// if filter is static, options will be the opts that BE initially gave | ||
if (filterOption.staticFilter) { | ||
options = formatFilterOptions(filterOption.options) | ||
} else { | ||
// if filter is dynamic & state is pending, data is still being fetched so options will be empty []. So only get options if status isn't pending | ||
if (!pending) { | ||
// if dynamic opts don't exist, options will be same as for static with the opts that BE initially gave | ||
if (!dynamicOptions) { | ||
options = formatFilterOptions(filterOption.options) | ||
} else { | ||
// if you send empty string to BE (e.g. after typing something and clearing it), it'll send back an empty [] but if there's no search val, we want to display the list of options that BE initially gave so only show the dynamic opts if search val exists | ||
if (dynamicSearchVal) options = dynamicOptions | ||
// if there is no search val but dynamic options exist - along with options that BE initially gave, make sure to add the selected values(if they exist) | ||
else { | ||
const filtersListItem = filtersList.find( | ||
item => item.selectedKey === selectedFilterKey | ||
) | ||
|
||
let selectedVals: string[] = [] | ||
|
||
if ( | ||
filtersListItem && | ||
filtersListItem.selectedValues | ||
) | ||
selectedVals = filtersListItem.selectedValues | ||
|
||
options = formatFilterOptions( | ||
uniq([...filterOption.options, ...selectedVals]) | ||
) | ||
} | ||
} | ||
} | ||
|
||
// these dynamic filter props should be there for all dynamic filters | ||
dynamicFilterProps = { | ||
onSearch: onSearchWrapper(selectedFilterKey), | ||
pending, | ||
searchPlaceholder: 'This one hits BE...' | ||
} | ||
} | ||
} | ||
|
||
return ( | ||
<MultiSelect | ||
disabled={!options.length && !pending} | ||
matchSelectedContentWidth={225} | ||
maxTagCount={5} | ||
onChange={(values: string[]) => onFilterChange(id, values)} | ||
options={options} | ||
placeholder='Select field' | ||
searchPlaceholder='Search' | ||
showSearch | ||
{...dynamicFilterProps} | ||
/> | ||
) | ||
} | ||
|
||
return ( | ||
<div className={classes.container}> | ||
<div className={classes.singleSelectContainer}>{renderKey()}</div> | ||
<FontAwesomeIcon icon={faEquals} size='xs' /> | ||
<div className={classes.multiSelectContainer}>{renderValues()}</div> | ||
<IconButton onClick={() => onDelete(id)} /> | ||
</div> | ||
) | ||
} | ||
|
||
export default FilterUnit |
Oops, something went wrong.