mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-08-28 19:05:53 +00:00
* 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:
parent
bdd436871c
commit
366a9fbc7c
@ -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
|
||||
|
@ -21,6 +21,7 @@ export interface AdvancedSearchProps {
|
||||
onChangeQueryFilter: (
|
||||
queryFilter: Record<string, unknown> | undefined
|
||||
) => void;
|
||||
onAppliedFilterChange: (value: string) => void;
|
||||
}
|
||||
|
||||
export type FilterObject = Record<string, string[]>;
|
||||
|
@ -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}
|
||||
/>
|
||||
|
@ -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;
|
||||
}
|
@ -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;
|
@ -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}
|
||||
|
@ -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>
|
||||
);
|
||||
|
@ -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,
|
||||
},
|
||||
|
@ -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.",
|
||||
|
Loading…
x
Reference in New Issue
Block a user