Skip to content

Commit

Permalink
feat(advanced search): Add component to show all advanced search filt…
Browse files Browse the repository at this point in the history
…ers & add new filter (#6058)

* adding select value modal

* expanding gql model and adding advanced search filter component

* adding advanced search filters component

* removing console logs

* improve readability

* responding to comments
  • Loading branch information
gabe-lyons authored Sep 30, 2022
1 parent 4792ac5 commit 7359d92
Show file tree
Hide file tree
Showing 3 changed files with 219 additions and 0 deletions.
51 changes: 51 additions & 0 deletions datahub-web-react/src/app/search/AdvancedSearchAddFilterSelect.tsx
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')}
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]};
}
`;

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'}
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>
</>
);
};
124 changes: 124 additions & 0 deletions datahub-web-react/src/app/search/AdvancedSearchFilters.tsx
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
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>
);
};

0 comments on commit 7359d92

Please sign in to comment.