Fix (#9087) : Search, show the condition after user applies the Advanced Search (#9303)

* Fix (#9087) : Search, show the condition after user applies the Advanced Search

* chore : show owner as default field

* chore : add advanced search text component
This commit is contained in:
Sachin Chaurasiya 2022-12-15 18:16:01 +05:30 committed by GitHub
parent bdd436871c
commit 366a9fbc7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 222 additions and 189 deletions

View File

@ -30,6 +30,7 @@ const AdvancedSearch: React.FC<AdvancedSearchProps> = ({
onChangeJsonTree,
onChangeQueryFilter,
searchIndex,
onAppliedFilterChange,
}) => {
const [config, setConfig] = useState<Config>(getQbConfigs(searchIndex));
@ -40,13 +41,12 @@ const AdvancedSearch: React.FC<AdvancedSearchProps> = ({
useEffect(() => setConfig(getQbConfigs(searchIndex)), [searchIndex]);
useEffect(
() =>
useEffect(() => {
onAppliedFilterChange(QbUtils.sqlFormat(immutableTree, config) ?? '');
onChangeQueryFilter({
query: elasticSearchFormat(immutableTree, config),
}),
[immutableTree, config]
);
});
}, [immutableTree, config]);
return (
<Query

View File

@ -21,6 +21,7 @@ export interface AdvancedSearchProps {
onChangeQueryFilter: (
queryFilter: Record<string, unknown> | undefined
) => void;
onAppliedFilterChange: (value: string) => void;
}
export type FilterObject = Record<string, string[]>;

View File

@ -1,4 +1,4 @@
import { Button, Modal, Space } from 'antd';
import { Button, Modal, Space, Typography } from 'antd';
import { delay } from 'lodash';
import React, { FunctionComponent, useState } from 'react';
import { JsonTree } from 'react-awesome-query-builder';
@ -13,6 +13,7 @@ interface Props {
searchIndex: SearchIndex;
onChangeJsonTree: (tree?: JsonTree) => void;
jsonTree?: JsonTree;
onAppliedFilterChange: (value: string) => void;
}
export const AdvancedSearchModal: FunctionComponent<Props> = ({
@ -22,6 +23,7 @@ export const AdvancedSearchModal: FunctionComponent<Props> = ({
searchIndex,
onChangeJsonTree,
jsonTree,
onAppliedFilterChange,
}: Props) => {
const [queryFilter, setQueryFilter] = useState<
Record<string, unknown> | undefined
@ -62,9 +64,13 @@ export const AdvancedSearchModal: FunctionComponent<Props> = ({
title={t('label.advanced-search')}
visible={visible}
width={950}>
<Typography.Text data-testid="advanced-search-message">
{t('message.advanced-search-message')}
</Typography.Text>
<AdvancedSearch
jsonTree={jsonTree}
searchIndex={searchIndex}
onAppliedFilterChange={onAppliedFilterChange}
onChangeJsonTree={(nTree) => onChangeJsonTree(nTree)}
onChangeQueryFilter={setQueryFilter}
/>

View File

@ -0,0 +1,20 @@
/*
* Copyright 2021 Collate
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@gray-color: #dde3ea;
.advanced-filter-text {
background: @gray-color;
border-radius: 4px;
padding: 4px 8px;
}

View File

@ -0,0 +1,60 @@
/*
* Copyright 2021 Collate
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Button, Space, Typography } from 'antd';
import React, { FC } from 'react';
import { useTranslation } from 'react-i18next';
import SVGIcons, { Icons } from '../../../utils/SvgUtils';
import './AppliedFilterText.less';
interface AppliedFilterTextProps {
filterText: string;
onEdit: () => void;
}
const AppliedFilterText: FC<AppliedFilterTextProps> = ({
filterText,
onEdit,
}) => {
const { t } = useTranslation();
return (
<Space className="w-full" direction="vertical">
<Typography.Text className="text-grey-muted">
{t('label.applied-advanced-search')}
</Typography.Text>
<Space
align="center"
className="w-full advanced-filter-text justify-between">
<Space className="w-full">
<SVGIcons
alt="success-badge"
icon={Icons.SUCCESS_BADGE}
width="16px"
/>
<Typography>{filterText}</Typography>
</Space>
<Button
className="p-0"
icon={
<SVGIcons alt="edit" icon={Icons.IC_EDIT_PRIMARY} width="16px" />
}
type="text"
onClick={onEdit}
/>
</Space>
</Space>
);
};
export default AppliedFilterText;

View File

@ -60,6 +60,7 @@ import {
TableTestsType,
} from '../TableProfiler/TableProfiler.interface';
import { AdvancedSearchModal } from './AdvanceSearchModal.component';
import AppliedFilterText from './AppliedFilterText/AppliedFilterText';
import EntitySummaryPanel from './EntitySummaryPanel/EntitySummaryPanel.component';
import {
ExploreProps,
@ -104,6 +105,12 @@ const Explore: React.FC<ExploreProps> = ({
results: INITIAL_TEST_RESULT_SUMMARY,
});
const [appliedFilterSQLFormat, setAppliedFilterSQLFormat] =
useState<string>('');
const handleAppliedFilterChange = (value: string) =>
setAppliedFilterSQLFormat(value);
const handleClosePanel = () => {
setShowSummaryPanel(false);
};
@ -382,6 +389,15 @@ const Explore: React.FC<ExploreProps> = ({
onFieldValueSelect={handleAdvanceFieldValueSelect}
/>
</Col>
{appliedFilterSQLFormat && (
<Col span={24}>
<AppliedFilterText
filterText={appliedFilterSQLFormat}
onEdit={() => setShowAdvanceSearchModal(true)}
/>
</Col>
)}
<Col span={24}>
{!loading ? (
<SearchedData
@ -421,6 +437,7 @@ const Explore: React.FC<ExploreProps> = ({
jsonTree={advancedSearchJsonTree}
searchIndex={searchIndex}
visible={showAdvanceSearchModal}
onAppliedFilterChange={handleAppliedFilterChange}
onCancel={() => setShowAdvanceSearchModal(false)}
onChangeJsonTree={onChangeAdvancedSearchJsonTree}
onSubmit={onChangeAdvancedSearchQueryFilter}

View File

@ -15,6 +15,7 @@ import { Divider, Space } from 'antd';
import { AxiosError } from 'axios';
import { isUndefined } from 'lodash';
import React, { FC, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
getAdvancedFieldDefaultOptions,
getAdvancedFieldOptions,
@ -33,6 +34,7 @@ const ExploreQuickFilters: FC<ExploreQuickFiltersProps> = ({
index,
onFieldValueSelect,
}) => {
const { t } = useTranslation();
const [options, setOptions] = useState<string[]>();
const [isOptionsLoading, setIsOptionsLoading] = useState<boolean>(false);
@ -112,7 +114,7 @@ const ExploreQuickFilters: FC<ExploreQuickFiltersProps> = ({
className="tw-text-primary tw-self-center tw-cursor-pointer"
data-testid="advance-search-button"
onClick={onAdvanceSearch}>
Advance Search
{t('label.advanced-search')}
</span>
</Space>
);

View File

@ -101,10 +101,11 @@ export const emptyJsonTree: JsonTree = {
[QbUtils.uuid()]: {
type: 'rule',
properties: {
field: null,
// owner is common field , so setting owner as default field here
field: 'owner.name',
operator: null,
value: [],
valueSrc: [],
valueSrc: ['value'],
},
},
},
@ -147,36 +148,14 @@ const commonQueryBuilderFields: Fields = {
defaultValue: true,
},
owner: {
'owner.name': {
label: 'Owner',
type: '!struct',
subfields: {
name: {
label: 'username',
type: 'select',
mainWidgetProps,
fieldSettings: {
asyncFetch: autocomplete([SearchIndex.USER, SearchIndex.TEAM]),
},
},
displayName: {
label: 'name',
type: 'text',
mainWidgetProps,
},
type: {
label: 'type',
type: 'select',
mainWidgetProps,
fieldSettings: {
listValues: [
{ value: 'user', title: 'User' },
{ value: 'team', title: 'Team' },
],
},
},
},
},
'tags.tagFQN': {
label: 'Tags',
@ -201,110 +180,53 @@ const commonQueryBuilderFields: Fields = {
* Fields specific to services
*/
const serviceQueryBuilderFields: Fields = {
service: {
'service.name': {
label: 'Service',
type: '!struct',
subfields: {
name: {
label: 'name',
type: 'select',
mainWidgetProps,
fieldSettings: {
asyncFetch: autocomplete(SearchIndex.TABLE, SuggestionField.SERVICE),
},
},
deleted: {
label: 'deleted',
type: 'boolean',
defaultValue: true,
},
},
},
};
/**
* Fields specific to tables
*/
const tableQueryBuilderFields: Fields = {
database: {
'database.name': {
label: 'Database',
type: '!struct',
subfields: {
name: {
label: 'name',
type: 'select',
mainWidgetProps,
fieldSettings: {
asyncFetch: autocomplete(SearchIndex.TABLE, SuggestionField.DATABASE),
},
},
deleted: {
label: 'deleted',
type: 'boolean',
defaultValue: true,
},
},
},
databaseSchema: {
'databaseSchema.name': {
label: 'Database Schema',
type: '!struct',
subfields: {
name: {
label: 'name',
type: 'select',
mainWidgetProps,
fieldSettings: {
asyncFetch: autocomplete(SearchIndex.TABLE, SuggestionField.SCHEMA),
},
},
deleted: {
label: 'deleted',
type: 'boolean',
defaultValue: true,
},
},
},
name: {
label: 'Table',
type: 'select',
mainWidgetProps,
fieldSettings: {
asyncFetch: autocomplete(SearchIndex.TABLE, SuggestionField.ROOT),
},
},
columns: {
'columns.name': {
label: 'Column',
type: '!struct',
subfields: {
name: {
label: 'name',
type: 'select',
mainWidgetProps,
fieldSettings: {
asyncFetch: autocomplete(SearchIndex.TABLE, SuggestionField.COLUMN),
},
},
dataType: {
label: 'data type',
type: 'text',
mainWidgetProps,
},
constraint: {
label: 'constraint',
type: 'text',
mainWidgetProps,
},
},
},
};
/**
* Overriding default configurations.
* Basic attributes that fields inherit from.
*/
const getInitialConfigWithoutFields = () => {
const initialConfigWithoutFields: BasicConfig = {
...BaseConfig,
types: {
@ -379,6 +301,9 @@ const initialConfigWithoutFields: BasicConfig = {
},
};
return initialConfigWithoutFields;
};
/**
* Builds search index specific configuration for the query builder
*/
@ -388,7 +313,7 @@ export const getQbConfigs: (searchIndex: SearchIndex) => BasicConfig = (
switch (searchIndex) {
case SearchIndex.MLMODEL:
return {
...initialConfigWithoutFields,
...getInitialConfigWithoutFields(),
fields: {
...commonQueryBuilderFields,
...serviceQueryBuilderFields,
@ -397,7 +322,7 @@ export const getQbConfigs: (searchIndex: SearchIndex) => BasicConfig = (
case SearchIndex.PIPELINE:
return {
...initialConfigWithoutFields,
...getInitialConfigWithoutFields(),
fields: {
...commonQueryBuilderFields,
...serviceQueryBuilderFields,
@ -406,7 +331,7 @@ export const getQbConfigs: (searchIndex: SearchIndex) => BasicConfig = (
case SearchIndex.DASHBOARD:
return {
...initialConfigWithoutFields,
...getInitialConfigWithoutFields(),
fields: {
...commonQueryBuilderFields,
...serviceQueryBuilderFields,
@ -415,7 +340,7 @@ export const getQbConfigs: (searchIndex: SearchIndex) => BasicConfig = (
case SearchIndex.TABLE:
return {
...initialConfigWithoutFields,
...getInitialConfigWithoutFields(),
fields: {
...commonQueryBuilderFields,
...serviceQueryBuilderFields,
@ -425,7 +350,7 @@ export const getQbConfigs: (searchIndex: SearchIndex) => BasicConfig = (
case SearchIndex.TOPIC:
return {
...initialConfigWithoutFields,
...getInitialConfigWithoutFields(),
fields: {
...commonQueryBuilderFields,
...serviceQueryBuilderFields,
@ -434,7 +359,7 @@ export const getQbConfigs: (searchIndex: SearchIndex) => BasicConfig = (
default:
return {
...initialConfigWithoutFields,
...getInitialConfigWithoutFields(),
fields: {
...commonQueryBuilderFields,
},

View File

@ -512,7 +512,8 @@
"insert": "Insert",
"update": "Update",
"table-profile": "Table Profile",
"column-profile": "Column Profile"
"column-profile": "Column Profile",
"applied-advanced-search": "Applied advanced search"
},
"message": {
"service-email-required": "Service account Email is required",
@ -628,7 +629,8 @@
"permanently-delete-metadata-and-dependents": "Permanently deleting this {{entityName}} will remove its metadata, as well as the metadata of {{dependents}} from OpenMetadata permanently.",
"permanently-delete-metadata": "Permanently deleting this {{entityName}} will remove its metadata from OpenMetadata permanently.",
"announcement-created-successfully": "Announcement created successfully!",
"no-profiler-message": "Data Profiler is an optional configuration in Ingestion. Please enable the data profiler by following the documentation"
"no-profiler-message": "Data Profiler is an optional configuration in Ingestion. Please enable the data profiler by following the documentation",
"advanced-search-message": "Discover the right data assets using the syntax editor with and/or conditions."
},
"server": {
"you-have-not-action-anything-yet": "You have not {{action}} anything yet.",