Skip to content
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

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 }}
Copy link
Contributor

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?

Copy link
Contributor Author

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

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')}
Copy link
Contributor

Choose a reason for hiding this comment

The 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]};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this 4 vs 4.5 make a substantial visual difference?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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'}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we make these strings consts?

Copy link
Contributor Author

@gabe-lyons gabe-lyons Sep 29, 2022

Choose a reason for hiding this comment

The 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>
</>
);
};
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this a todo for after this pr?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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>
);
};