-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(advanced search): Add component to show all advanced search filters & add new filter #6058
Changes from all commits
9deb900
0a07a69
6184d80
87610fe
bb34f3c
fc95022
7741e84
1cb0d20
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import { Select } from 'antd'; | ||
import * as React from 'react'; | ||
import styled from 'styled-components'; | ||
import { PlusOutlined } from '@ant-design/icons'; | ||
|
||
import { FacetFilterInput } from '../../types.generated'; | ||
import { FIELD_TO_LABEL } from './utils/constants'; | ||
|
||
const StyledPlus = styled(PlusOutlined)` | ||
margin-right: 6px; | ||
`; | ||
|
||
interface Props { | ||
selectedFilters: Array<FacetFilterInput>; | ||
onFilterFieldSelect: (value) => void; | ||
} | ||
|
||
const { Option } = Select; | ||
|
||
export const AdvancedSearchAddFilterSelect = ({ selectedFilters, onFilterFieldSelect }: Props) => { | ||
return ( | ||
<Select | ||
value={{ | ||
value: 'value', | ||
label: ( | ||
<div> | ||
<StyledPlus /> | ||
Add Filter | ||
</div> | ||
), | ||
}} | ||
labelInValue | ||
style={{ padding: 6, fontWeight: 500 }} | ||
onChange={onFilterFieldSelect} | ||
dropdownMatchSelectWidth={false} | ||
filterOption={(_, option) => option?.value === 'null'} | ||
> | ||
{Object.keys(FIELD_TO_LABEL) | ||
.sort((a, b) => FIELD_TO_LABEL[a].localeCompare(FIELD_TO_LABEL[b])) | ||
.map((key) => ( | ||
<Option | ||
// disable the `entity` option if they already have an entity filter selected | ||
disabled={key === 'entity' && !!selectedFilters.find((filter) => filter.field === 'entity')} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what is this function doing? It's a bit hard to tell what's going on |
||
value={key} | ||
> | ||
{FIELD_TO_LABEL[key]} | ||
</Option> | ||
))} | ||
</Select> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { Select } from 'antd'; | ||
import React from 'react'; | ||
import styled from 'styled-components/macro'; | ||
|
||
import { ANTD_GRAY } from '../entity/shared/constants'; | ||
import { UnionType } from './utils/constants'; | ||
|
||
type Props = { | ||
unionType: UnionType; | ||
onUpdate: (newValue: UnionType) => void; | ||
}; | ||
|
||
const { Option } = Select; | ||
|
||
const StyledSelect = styled(Select)` | ||
border-radius: 5px; | ||
background: ${ANTD_GRAY[4]}; | ||
:hover { | ||
background: ${ANTD_GRAY[4.5]}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does this 4 vs 4.5 make a substantial visual difference? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes! |
||
} | ||
`; | ||
|
||
export const AdvancedSearchFilterOverallUnionTypeSelect = ({ unionType, onUpdate }: Props) => { | ||
return ( | ||
<> | ||
<StyledSelect | ||
showArrow={false} | ||
bordered={false} | ||
// these values are just for display purposes- the actual value is the unionType prop | ||
value={unionType === UnionType.AND ? 'all filters' : 'any filter'} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we make these strings consts? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is just for display purposes, so i dont think thats needed (the actual constant is UnionType). Adding a comment |
||
onChange={(newValue) => { | ||
if ((newValue as any) !== unionType) { | ||
onUpdate(newValue as any); | ||
} | ||
}} | ||
size="small" | ||
dropdownMatchSelectWidth={false} | ||
> | ||
<Option value={UnionType.AND}>all filters</Option> | ||
<Option value={UnionType.OR}>any filter</Option> | ||
</StyledSelect> | ||
</> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
import * as React from 'react'; | ||
import { useState } from 'react'; | ||
import styled from 'styled-components'; | ||
|
||
import { FacetFilterInput, FacetMetadata, SearchCondition } from '../../types.generated'; | ||
import { ANTD_GRAY } from '../entity/shared/constants'; | ||
import { AdvancedSearchFilter } from './AdvancedSearchFilter'; | ||
import { AdvancedSearchFilterOverallUnionTypeSelect } from './AdvancedSearchFilterOverallUnionTypeSelect'; | ||
import { AdvancedFilterSelectValueModal } from './AdvancedFilterSelectValueModal'; | ||
import { FIELDS_THAT_USE_CONTAINS_OPERATOR, UnionType } from './utils/constants'; | ||
import { AdvancedSearchAddFilterSelect } from './AdvancedSearchAddFilterSelect'; | ||
|
||
export const SearchFilterWrapper = styled.div` | ||
min-height: 100%; | ||
overflow: auto; | ||
margin-top: 6px; | ||
margin-left: 12px; | ||
margin-right: 12px; | ||
|
||
&::-webkit-scrollbar { | ||
height: 12px; | ||
width: 1px; | ||
background: #f2f2f2; | ||
} | ||
&::-webkit-scrollbar-thumb { | ||
background: #cccccc; | ||
-webkit-border-radius: 1ex; | ||
-webkit-box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.75); | ||
} | ||
`; | ||
|
||
const AnyAllSection = styled.div` | ||
padding: 6px; | ||
color: ${ANTD_GRAY[8]}; | ||
`; | ||
|
||
const EmptyStateSection = styled.div` | ||
border-radius: 5px; | ||
background-color: ${ANTD_GRAY[2]}; | ||
padding: 22px; | ||
margin-top: 10px; | ||
`; | ||
|
||
interface Props { | ||
selectedFilters: Array<FacetFilterInput>; | ||
facets: Array<FacetMetadata>; | ||
onFilterSelect: (newFilters: Array<FacetFilterInput>) => void; | ||
onChangeUnionType: (unionType: UnionType) => void; | ||
unionType?: UnionType; | ||
} | ||
|
||
export const AdvancedSearchFilters = ({ | ||
unionType = UnionType.AND, | ||
facets, | ||
selectedFilters, | ||
onFilterSelect, | ||
onChangeUnionType, | ||
}: Props) => { | ||
const [filterField, setFilterField] = useState<null | string>(null); | ||
|
||
const onFilterFieldSelect = (value) => { | ||
setFilterField(value.value); | ||
}; | ||
|
||
const onSelectValueFromModal = (values) => { | ||
if (!filterField) return; | ||
|
||
const newFilter: FacetFilterInput = { | ||
field: filterField, | ||
values: values as string[], | ||
value: '', // TODO(Gabe): remove once we refactor the model | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is this a todo for after this pr? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yep |
||
condition: FIELDS_THAT_USE_CONTAINS_OPERATOR.includes(filterField) | ||
? SearchCondition.Contain | ||
: SearchCondition.Equal, | ||
}; | ||
onFilterSelect([...selectedFilters, newFilter]); | ||
}; | ||
|
||
return ( | ||
<SearchFilterWrapper> | ||
<AdvancedSearchAddFilterSelect | ||
selectedFilters={selectedFilters} | ||
onFilterFieldSelect={onFilterFieldSelect} | ||
/> | ||
{selectedFilters?.length >= 2 && ( | ||
<AnyAllSection> | ||
Show results that match{' '} | ||
<AdvancedSearchFilterOverallUnionTypeSelect | ||
unionType={unionType} | ||
onUpdate={(newValue) => onChangeUnionType(newValue)} | ||
/> | ||
</AnyAllSection> | ||
)} | ||
{selectedFilters.map((filter) => ( | ||
<AdvancedSearchFilter | ||
facet={facets.find((facet) => facet.field === filter.field) || facets[0]} | ||
filter={filter} | ||
onClose={() => { | ||
onFilterSelect(selectedFilters.filter((f) => f !== filter)); | ||
}} | ||
onUpdate={(newValue) => { | ||
onFilterSelect( | ||
selectedFilters.map((f) => { | ||
if (f === filter) { | ||
return newValue; | ||
} | ||
return f; | ||
}), | ||
); | ||
}} | ||
/> | ||
))} | ||
{filterField && ( | ||
<AdvancedFilterSelectValueModal | ||
facet={facets.find((facet) => facet.field === filterField) || null} | ||
onCloseModal={() => setFilterField(null)} | ||
filterField={filterField} | ||
onSelect={onSelectValueFromModal} | ||
/> | ||
)} | ||
{selectedFilters?.length === 0 && <EmptyStateSection>No filters applied, add one above.</EmptyStateSection>} | ||
</SearchFilterWrapper> | ||
); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know we're trying to use styled components across our React app, can we do that here instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ach I wanted to do that here too but the antd
Select
was overwriting them