mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-09-03 06:03:12 +00:00
fix: explore quick filters should behave like facet filters (#12206)
* fix: explore quick filters * fix: code smells
This commit is contained in:
parent
1e1ab31e9c
commit
f7fe9ff75d
@ -1,12 +1,22 @@
|
|||||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
|
|
||||||
<svg width="800px" height="800px" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" fill="#7147E8" stroke="#7147E8">
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
|
||||||
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
|
<svg width="800px" height="800px" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" fill="#0968da" stroke="#0968da">
|
||||||
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
|
|
||||||
<g id="SVGRepo_iconCarrier">
|
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
|
||||||
<title>ionicons-v5-m</title>
|
|
||||||
<path d="M448,256c0-106-86-192-192-192S64,150,64,256s86,192,192,192S448,362,448,256Z" style="fill:none;stroke:#7147E8;stroke-miterlimit:10;stroke-width:32px"/>
|
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
<line x1="320" y1="320" x2="192" y2="192" style="fill:none;stroke:#7147E8;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/>
|
|
||||||
<line x1="192" y1="320" x2="320" y2="192" style="fill:none;stroke:#7147E8;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/>
|
<g id="SVGRepo_iconCarrier">
|
||||||
</g>
|
|
||||||
</svg>
|
<title>ionicons-v5-m</title>
|
||||||
|
|
||||||
|
<path d="M448,256c0-106-86-192-192-192S64,150,64,256s86,192,192,192S448,362,448,256Z" style="fill:none;stroke:#0968da;stroke-miterlimit:10;stroke-width:32px"/>
|
||||||
|
|
||||||
|
<line x1="320" y1="320" x2="192" y2="192" style="fill:none;stroke:#0968da;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/>
|
||||||
|
|
||||||
|
<line x1="192" y1="320" x2="320" y2="192" style="fill:none;stroke:#0968da;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/>
|
||||||
|
|
||||||
|
</g>
|
||||||
|
|
||||||
|
</svg>
|
Before Width: | Height: | Size: 948 B After Width: | Height: | Size: 948 B |
@ -514,9 +514,9 @@ export const DataAssetsHeader = ({
|
|||||||
<Typography.Text>{followers}</Typography.Text>
|
<Typography.Text>{followers}</Typography.Text>
|
||||||
</Button>
|
</Button>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
|
open={!isEmpty(copyTooltip)}
|
||||||
placement="bottomRight"
|
placement="bottomRight"
|
||||||
title={copyTooltip}
|
title={copyTooltip}>
|
||||||
visible={!isEmpty(copyTooltip)}>
|
|
||||||
<Button
|
<Button
|
||||||
icon={<Icon component={ShareIcon} />}
|
icon={<Icon component={ShareIcon} />}
|
||||||
onClick={handleShareButtonClick}
|
onClick={handleShareButtonClick}
|
||||||
|
@ -63,7 +63,7 @@ const KPILatestResultsV1: FC<Props> = ({ kpiLatestResultsRecord }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Row key={name}>
|
<Row key={name}>
|
||||||
<Col className="flex-center" span={24}>
|
<Col className="d-flex items-center" span={24}>
|
||||||
<div
|
<div
|
||||||
className="kpi-days-section"
|
className="kpi-days-section"
|
||||||
style={{
|
style={{
|
||||||
@ -77,7 +77,7 @@ const KPILatestResultsV1: FC<Props> = ({ kpiLatestResultsRecord }) => {
|
|||||||
{t('label.day-left', { day: 'days' })}
|
{t('label.day-left', { day: 'days' })}
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
</div>
|
</div>
|
||||||
<div className="m-l-sm">
|
<div className="m-l-sm flex-1">
|
||||||
<Typography.Text className="text-xs">
|
<Typography.Text className="text-xs">
|
||||||
{resultData.displayName ?? name}
|
{resultData.displayName ?? name}
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
|
|
||||||
@import url('../../styles/variables.less');
|
@import url('../../styles/variables.less');
|
||||||
|
|
||||||
|
@sidebar-width: 100px;
|
||||||
|
|
||||||
.custom-react-flow {
|
.custom-react-flow {
|
||||||
.react-flow__node-input.selectable.selected {
|
.react-flow__node-input.selectable.selected {
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
@ -90,8 +92,8 @@
|
|||||||
width: 400px;
|
width: 400px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
}
|
}
|
||||||
.custom-control-search-box-edit-mode {
|
.ant-select.custom-control-search-box-edit-mode {
|
||||||
margin-left: 83px;
|
margin-left: @sidebar-width;
|
||||||
}
|
}
|
||||||
.custom-control-basic-button {
|
.custom-control-basic-button {
|
||||||
padding-left: 4px;
|
padding-left: 4px;
|
||||||
@ -157,3 +159,24 @@
|
|||||||
.lineage-card .react-flow__edge.animated path {
|
.lineage-card .react-flow__edge.animated path {
|
||||||
animation: none;
|
animation: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.entity-lineage.sidebar {
|
||||||
|
height: 110%;
|
||||||
|
background: @white;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: @sidebar-width;
|
||||||
|
z-index: 200;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 8px;
|
||||||
|
transform: translateX(100%);
|
||||||
|
display: none;
|
||||||
|
border-right: 1px solid @border-color;
|
||||||
|
transition: transform 0.3s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.entity-lineage.sidebar.open {
|
||||||
|
transform: translateX(0);
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
@ -11,12 +11,14 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { Aggregations } from 'interface/search.interface';
|
||||||
import { SearchIndex } from '../../enums/search.enum';
|
import { SearchIndex } from '../../enums/search.enum';
|
||||||
import { ExploreQuickFilterField } from './explore.interface';
|
import { ExploreQuickFilterField } from './explore.interface';
|
||||||
|
|
||||||
export interface ExploreQuickFiltersProps {
|
export interface ExploreQuickFiltersProps {
|
||||||
index: SearchIndex;
|
index: SearchIndex;
|
||||||
fields: Array<ExploreQuickFilterField>;
|
fields: Array<ExploreQuickFilterField>;
|
||||||
|
aggregations?: Aggregations;
|
||||||
onFieldValueSelect: (field: ExploreQuickFilterField) => void;
|
onFieldValueSelect: (field: ExploreQuickFilterField) => void;
|
||||||
onAdvanceSearch: () => void;
|
onAdvanceSearch: () => void;
|
||||||
showDeleted?: boolean;
|
showDeleted?: boolean;
|
||||||
|
@ -15,6 +15,7 @@ import { Space } from 'antd';
|
|||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
import { SearchIndex } from 'enums/search.enum';
|
import { SearchIndex } from 'enums/search.enum';
|
||||||
import { isEqual, isUndefined, uniqWith } from 'lodash';
|
import { isEqual, isUndefined, uniqWith } from 'lodash';
|
||||||
|
import { Bucket } from 'Models';
|
||||||
import React, { FC, useState } from 'react';
|
import React, { FC, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
getAdvancedFieldDefaultOptions,
|
getAdvancedFieldDefaultOptions,
|
||||||
@ -29,6 +30,7 @@ import {
|
|||||||
} from '../../constants/AdvancedSearch.constants';
|
} from '../../constants/AdvancedSearch.constants';
|
||||||
import {
|
import {
|
||||||
getAdvancedField,
|
getAdvancedField,
|
||||||
|
getOptionsFromAggregationBucket,
|
||||||
getOptionTextFromKey,
|
getOptionTextFromKey,
|
||||||
} from '../../utils/AdvancedSearchUtils';
|
} from '../../utils/AdvancedSearchUtils';
|
||||||
import { showErrorToast } from '../../utils/ToastUtils';
|
import { showErrorToast } from '../../utils/ToastUtils';
|
||||||
@ -39,48 +41,51 @@ import { ExploreQuickFiltersProps } from './ExploreQuickFilters.interface';
|
|||||||
const ExploreQuickFilters: FC<ExploreQuickFiltersProps> = ({
|
const ExploreQuickFilters: FC<ExploreQuickFiltersProps> = ({
|
||||||
fields,
|
fields,
|
||||||
index,
|
index,
|
||||||
|
aggregations,
|
||||||
onFieldValueSelect,
|
onFieldValueSelect,
|
||||||
}) => {
|
}) => {
|
||||||
const [options, setOptions] = useState<SearchDropdownOption[]>();
|
const [options, setOptions] = useState<SearchDropdownOption[]>();
|
||||||
const [isOptionsLoading, setIsOptionsLoading] = useState<boolean>(false);
|
const [isOptionsLoading, setIsOptionsLoading] = useState<boolean>(false);
|
||||||
|
const [tierOptions, setTierOptions] = useState<SearchDropdownOption[]>();
|
||||||
|
|
||||||
const fetchDefaultOptions = async (
|
const fetchDefaultOptions = async (
|
||||||
index: SearchIndex | SearchIndex[],
|
index: SearchIndex | SearchIndex[],
|
||||||
key: string
|
key: string
|
||||||
) => {
|
) => {
|
||||||
const [res, tierTags] = await Promise.all([
|
let buckets: Bucket[] = [];
|
||||||
getAdvancedFieldDefaultOptions(index, key),
|
|
||||||
key === 'tier.tagFQN'
|
|
||||||
? getTags({ parent: 'Tier' })
|
|
||||||
: Promise.resolve(null),
|
|
||||||
]);
|
|
||||||
|
|
||||||
const buckets = res.data.aggregations[`sterms#${key}`].buckets;
|
if (aggregations?.[key] && key !== 'tier.tagFQN') {
|
||||||
|
buckets = aggregations[key].buckets;
|
||||||
const optionsArray = buckets.map((option) => ({
|
|
||||||
key: option.key,
|
|
||||||
label: option.key,
|
|
||||||
count: option.doc_count ?? 0,
|
|
||||||
}));
|
|
||||||
|
|
||||||
let options;
|
|
||||||
if (key === 'tier.tagFQN' && tierTags) {
|
|
||||||
options = tierTags.data.map((option) => {
|
|
||||||
const bucketItem = buckets.find(
|
|
||||||
(item) => item.key === option.fullyQualifiedName
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
key: option.fullyQualifiedName ?? '',
|
|
||||||
label: option.name,
|
|
||||||
count: bucketItem?.doc_count ?? 0,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
options = optionsArray;
|
const [res, tierTags] = await Promise.all([
|
||||||
|
getAdvancedFieldDefaultOptions(index, key),
|
||||||
|
key === 'tier.tagFQN'
|
||||||
|
? getTags({ parent: 'Tier' })
|
||||||
|
: Promise.resolve(null),
|
||||||
|
]);
|
||||||
|
|
||||||
|
buckets = res.data.aggregations[`sterms#${key}`].buckets;
|
||||||
|
|
||||||
|
if (key === 'tier.tagFQN' && tierTags) {
|
||||||
|
const options = tierTags.data.map((option) => {
|
||||||
|
const bucketItem = buckets.find(
|
||||||
|
(item) => item.key === option.fullyQualifiedName
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
key: option.fullyQualifiedName ?? '',
|
||||||
|
label: option.name,
|
||||||
|
count: bucketItem?.doc_count ?? 0,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
setTierOptions(uniqWith(options, isEqual));
|
||||||
|
setOptions(uniqWith(options, isEqual));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setOptions(uniqWith(options, isEqual));
|
setOptions(uniqWith(getOptionsFromAggregationBucket(buckets), isEqual));
|
||||||
};
|
};
|
||||||
|
|
||||||
const getInitialOptions = async (key: string) => {
|
const getInitialOptions = async (key: string) => {
|
||||||
@ -106,61 +111,69 @@ const ExploreQuickFilters: FC<ExploreQuickFiltersProps> = ({
|
|||||||
setIsOptionsLoading(true);
|
setIsOptionsLoading(true);
|
||||||
setOptions([]);
|
setOptions([]);
|
||||||
try {
|
try {
|
||||||
if (value) {
|
if (!value) {
|
||||||
const advancedField = getAdvancedField(key);
|
|
||||||
if (!MISC_FIELDS.includes(key)) {
|
|
||||||
const res = await getAdvancedFieldOptions(
|
|
||||||
value,
|
|
||||||
index,
|
|
||||||
advancedField
|
|
||||||
);
|
|
||||||
|
|
||||||
const suggestOptions =
|
|
||||||
res.data.suggest['metadata-suggest'][0].options ?? [];
|
|
||||||
|
|
||||||
const formattedSuggestions = suggestOptions.map((option) => {
|
|
||||||
const optionsText = getOptionTextFromKey(index, option, key);
|
|
||||||
|
|
||||||
return {
|
|
||||||
key: optionsText,
|
|
||||||
label: optionsText,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
setOptions(uniqWith(formattedSuggestions, isEqual));
|
|
||||||
} else {
|
|
||||||
if (key === 'tags.tagFQN') {
|
|
||||||
const res = await getTagSuggestions(value);
|
|
||||||
|
|
||||||
const suggestOptions =
|
|
||||||
res.data.suggest['metadata-suggest'][0].options ?? [];
|
|
||||||
|
|
||||||
const formattedSuggestions = suggestOptions
|
|
||||||
.filter((op) => !isUndefined(op._source.fullyQualifiedName))
|
|
||||||
.map((op) => op._source.fullyQualifiedName as string);
|
|
||||||
|
|
||||||
const optionsArray = formattedSuggestions.map((op) => ({
|
|
||||||
key: op,
|
|
||||||
label: op,
|
|
||||||
}));
|
|
||||||
|
|
||||||
setOptions(uniqWith(optionsArray, isEqual));
|
|
||||||
} else {
|
|
||||||
const res = await getUserSuggestions(value);
|
|
||||||
|
|
||||||
const suggestOptions =
|
|
||||||
res.data.suggest['metadata-suggest'][0].options ?? [];
|
|
||||||
|
|
||||||
const formattedSuggestions = suggestOptions.map((op) => ({
|
|
||||||
key: op._source.displayName ?? op._source.name,
|
|
||||||
label: op._source.displayName ?? op._source.name,
|
|
||||||
}));
|
|
||||||
|
|
||||||
setOptions(uniqWith(formattedSuggestions, isEqual));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
getInitialOptions(key);
|
getInitialOptions(key);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (aggregations?.[key] && key !== 'tier.tagFQN') {
|
||||||
|
const defaultOptions = getOptionsFromAggregationBucket(
|
||||||
|
aggregations[key].buckets
|
||||||
|
);
|
||||||
|
const filteredOptions = defaultOptions.filter((option) => {
|
||||||
|
return option.label.toLowerCase().includes(value.toLowerCase());
|
||||||
|
});
|
||||||
|
setOptions(filteredOptions);
|
||||||
|
} else if (key === 'tier.tagFQN') {
|
||||||
|
const filteredOptions = tierOptions?.filter((option) => {
|
||||||
|
return option.label.toLowerCase().includes(value.toLowerCase());
|
||||||
|
});
|
||||||
|
setOptions(filteredOptions);
|
||||||
|
} else if (!MISC_FIELDS.includes(key)) {
|
||||||
|
const advancedField = getAdvancedField(key);
|
||||||
|
const res = await getAdvancedFieldOptions(value, index, advancedField);
|
||||||
|
|
||||||
|
const suggestOptions =
|
||||||
|
res.data.suggest['metadata-suggest'][0].options ?? [];
|
||||||
|
|
||||||
|
const formattedSuggestions = suggestOptions.map((option) => {
|
||||||
|
const optionsText = getOptionTextFromKey(index, option, key);
|
||||||
|
|
||||||
|
return {
|
||||||
|
key: optionsText,
|
||||||
|
label: optionsText,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
setOptions(uniqWith(formattedSuggestions, isEqual));
|
||||||
|
} else if (key === 'tags.tagFQN') {
|
||||||
|
const res = await getTagSuggestions(value);
|
||||||
|
|
||||||
|
const suggestOptions =
|
||||||
|
res.data.suggest['metadata-suggest'][0].options ?? [];
|
||||||
|
|
||||||
|
const formattedSuggestions = suggestOptions
|
||||||
|
.filter((op) => !isUndefined(op._source.fullyQualifiedName))
|
||||||
|
.map((op) => op._source.fullyQualifiedName as string);
|
||||||
|
|
||||||
|
const optionsArray = formattedSuggestions.map((op) => ({
|
||||||
|
key: op,
|
||||||
|
label: op,
|
||||||
|
}));
|
||||||
|
|
||||||
|
setOptions(uniqWith(optionsArray, isEqual));
|
||||||
|
} else {
|
||||||
|
const res = await getUserSuggestions(value);
|
||||||
|
|
||||||
|
const suggestOptions =
|
||||||
|
res.data.suggest['metadata-suggest'][0].options ?? [];
|
||||||
|
|
||||||
|
const formattedSuggestions = suggestOptions.map((op) => ({
|
||||||
|
key: op._source.displayName ?? op._source.name,
|
||||||
|
label: op._source.displayName ?? op._source.name,
|
||||||
|
}));
|
||||||
|
|
||||||
|
setOptions(uniqWith(formattedSuggestions, isEqual));
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showErrorToast(error as AxiosError);
|
showErrorToast(error as AxiosError);
|
||||||
|
@ -29,7 +29,6 @@ import { Table } from '../../generated/entity/data/table';
|
|||||||
import { Topic } from '../../generated/entity/data/topic';
|
import { Topic } from '../../generated/entity/data/topic';
|
||||||
import { Aggregations, SearchResponse } from '../../interface/search.interface';
|
import { Aggregations, SearchResponse } from '../../interface/search.interface';
|
||||||
import { SearchDropdownOption } from '../SearchDropdown/SearchDropdown.interface';
|
import { SearchDropdownOption } from '../SearchDropdown/SearchDropdown.interface';
|
||||||
import { FilterObject } from './AdvanceSearchProvider/AdvanceSearchProvider.interface';
|
|
||||||
|
|
||||||
export type UrlParams = {
|
export type UrlParams = {
|
||||||
searchQuery: string;
|
searchQuery: string;
|
||||||
@ -67,9 +66,6 @@ export interface ExploreProps {
|
|||||||
queryFilter: QueryFilterInterface | undefined
|
queryFilter: QueryFilterInterface | undefined
|
||||||
) => void;
|
) => void;
|
||||||
|
|
||||||
facetFilters?: FilterObject;
|
|
||||||
onChangeFacetFilters: (filter: FilterObject) => void;
|
|
||||||
|
|
||||||
searchIndex: ExploreSearchIndex;
|
searchIndex: ExploreSearchIndex;
|
||||||
onChangeSearchIndex: (searchIndex: ExploreSearchIndex) => void;
|
onChangeSearchIndex: (searchIndex: ExploreSearchIndex) => void;
|
||||||
|
|
||||||
|
@ -61,10 +61,10 @@ import Loader from '../Loader/Loader';
|
|||||||
import './ExploreV1.style.less';
|
import './ExploreV1.style.less';
|
||||||
|
|
||||||
const ExploreV1: React.FC<ExploreProps> = ({
|
const ExploreV1: React.FC<ExploreProps> = ({
|
||||||
|
aggregations,
|
||||||
searchResults,
|
searchResults,
|
||||||
tabCounts,
|
tabCounts,
|
||||||
onChangeAdvancedSearchQuickFilters,
|
onChangeAdvancedSearchQuickFilters,
|
||||||
facetFilters,
|
|
||||||
searchIndex,
|
searchIndex,
|
||||||
onChangeSearchIndex,
|
onChangeSearchIndex,
|
||||||
sortOrder,
|
sortOrder,
|
||||||
@ -79,7 +79,6 @@ const ExploreV1: React.FC<ExploreProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { tab } = useParams<{ tab: string }>();
|
const { tab } = useParams<{ tab: string }>();
|
||||||
|
|
||||||
const [selectedQuickFilters, setSelectedQuickFilters] = useState<
|
const [selectedQuickFilters, setSelectedQuickFilters] = useState<
|
||||||
ExploreQuickFilterField[]
|
ExploreQuickFilterField[]
|
||||||
>([] as ExploreQuickFilterField[]);
|
>([] as ExploreQuickFilterField[]);
|
||||||
@ -144,7 +143,7 @@ const ExploreV1: React.FC<ExploreProps> = ({
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
return searchQueryParam && !facetFilters
|
return searchQueryParam
|
||||||
? items.filter((tabItem) => {
|
? items.filter((tabItem) => {
|
||||||
return tabItem.count > 0 || tabItem.key === searchCriteria;
|
return tabItem.count > 0 || tabItem.key === searchCriteria;
|
||||||
})
|
})
|
||||||
@ -287,157 +286,161 @@ const ExploreV1: React.FC<ExploreProps> = ({
|
|||||||
<div className="explore-page bg-white">
|
<div className="explore-page bg-white">
|
||||||
<div className="w-full h-full">
|
<div className="w-full h-full">
|
||||||
{tabItems.length > 0 && (
|
{tabItems.length > 0 && (
|
||||||
<Row gutter={[8, 0]} wrap={false}>
|
<>
|
||||||
<Col span={24}>
|
<Row gutter={[8, 0]} wrap={false}>
|
||||||
<Tabs
|
<Col span={24}>
|
||||||
activeKey={activeTabKey}
|
<Tabs
|
||||||
className="explore-page-tabs"
|
activeKey={activeTabKey}
|
||||||
defaultActiveKey={defaultActiveTab}
|
className="explore-page-tabs"
|
||||||
items={tabItems}
|
defaultActiveKey={defaultActiveTab}
|
||||||
onChange={(tab) => {
|
items={tabItems}
|
||||||
tab && onChangeSearchIndex(tab as ExploreSearchIndex);
|
onChange={(tab) => {
|
||||||
setShowSummaryPanel(false);
|
tab && onChangeSearchIndex(tab as ExploreSearchIndex);
|
||||||
}}
|
setShowSummaryPanel(false);
|
||||||
/>
|
}}
|
||||||
<Row className="filters-row">
|
/>
|
||||||
<Col className="searched-data-container w-full">
|
<Row className="filters-row">
|
||||||
<Row gutter={[16, 16]}>
|
<Col className="searched-data-container w-full">
|
||||||
<Col
|
<Row gutter={[16, 16]}>
|
||||||
className="d-flex items-center justify-between"
|
<Col
|
||||||
span={24}>
|
className="d-flex items-center justify-between"
|
||||||
{showFilters && (
|
span={24}>
|
||||||
<ExploreQuickFilters
|
{showFilters && (
|
||||||
fields={selectedQuickFilters}
|
<ExploreQuickFilters
|
||||||
index={activeTabKey}
|
aggregations={aggregations}
|
||||||
showDeleted={showDeleted}
|
fields={selectedQuickFilters}
|
||||||
onAdvanceSearch={() => toggleModal(true)}
|
index={activeTabKey}
|
||||||
onChangeShowDeleted={onChangeShowDeleted}
|
showDeleted={showDeleted}
|
||||||
onFieldValueSelect={handleQuickFiltersValueSelect}
|
onAdvanceSearch={() => toggleModal(true)}
|
||||||
/>
|
onChangeShowDeleted={onChangeShowDeleted}
|
||||||
)}
|
onFieldValueSelect={handleQuickFiltersValueSelect}
|
||||||
<div className="d-flex items-center gap-4 m-l-auto m-r-xs">
|
|
||||||
<span className="flex-center">
|
|
||||||
<Switch
|
|
||||||
checked={showDeleted}
|
|
||||||
data-testid="show-deleted"
|
|
||||||
onChange={onChangeShowDeleted}
|
|
||||||
/>
|
/>
|
||||||
<Typography.Text className="p-l-xs text-grey-muted">
|
)}
|
||||||
{t('label.deleted')}
|
<div className="d-flex items-center gap-4 m-l-auto m-r-xs">
|
||||||
</Typography.Text>
|
<span className="flex-center">
|
||||||
</span>
|
<Switch
|
||||||
{(quickFilters || sqlQuery) && (
|
checked={showDeleted}
|
||||||
|
data-testid="show-deleted"
|
||||||
|
onChange={onChangeShowDeleted}
|
||||||
|
/>
|
||||||
|
<Typography.Text className="p-l-xs text-grey-muted">
|
||||||
|
{t('label.deleted')}
|
||||||
|
</Typography.Text>
|
||||||
|
</span>
|
||||||
|
{(quickFilters || sqlQuery) && (
|
||||||
|
<Typography.Text
|
||||||
|
className="text-primary self-center cursor-pointer"
|
||||||
|
onClick={() => clearFilters()}>
|
||||||
|
{t('label.clear-entity', {
|
||||||
|
entity: '',
|
||||||
|
})}
|
||||||
|
</Typography.Text>
|
||||||
|
)}
|
||||||
|
|
||||||
<Typography.Text
|
<Typography.Text
|
||||||
className="text-primary self-center cursor-pointer"
|
className="text-primary self-center cursor-pointer"
|
||||||
onClick={() => clearFilters()}>
|
data-testid="advance-search-button"
|
||||||
{t('label.clear-entity', {
|
onClick={() => toggleModal(true)}>
|
||||||
|
{t('label.advanced-entity', {
|
||||||
entity: '',
|
entity: '',
|
||||||
})}
|
})}
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
)}
|
<span className="sorting-dropdown-container">
|
||||||
|
<SortingDropDown
|
||||||
<Typography.Text
|
fieldList={tabsInfo[searchIndex].sortingFields}
|
||||||
className="text-primary self-center cursor-pointer"
|
handleFieldDropDown={onChangeSortValue}
|
||||||
data-testid="advance-search-button"
|
sortField={sortValue}
|
||||||
onClick={() => toggleModal(true)}>
|
/>
|
||||||
{t('label.advanced-entity', {
|
<Button
|
||||||
entity: '',
|
className="p-0"
|
||||||
})}
|
size="small"
|
||||||
</Typography.Text>
|
type="text"
|
||||||
<span className="sorting-dropdown-container">
|
onClick={() =>
|
||||||
<SortingDropDown
|
onChangeSortOder(
|
||||||
fieldList={tabsInfo[searchIndex].sortingFields}
|
isAscSortOrder
|
||||||
handleFieldDropDown={onChangeSortValue}
|
? SORT_ORDER.DESC
|
||||||
sortField={sortValue}
|
: SORT_ORDER.ASC
|
||||||
/>
|
)
|
||||||
<Button
|
}>
|
||||||
className="p-0"
|
{isAscSortOrder ? (
|
||||||
size="small"
|
<SortAscendingOutlined
|
||||||
type="text"
|
style={{ fontSize: '14px' }}
|
||||||
onClick={() =>
|
{...sortProps}
|
||||||
onChangeSortOder(
|
/>
|
||||||
isAscSortOrder
|
) : (
|
||||||
? SORT_ORDER.DESC
|
<SortDescendingOutlined
|
||||||
: SORT_ORDER.ASC
|
style={{ fontSize: '14px' }}
|
||||||
)
|
{...sortProps}
|
||||||
}>
|
/>
|
||||||
{isAscSortOrder ? (
|
)}
|
||||||
<SortAscendingOutlined
|
</Button>
|
||||||
style={{ fontSize: '14px' }}
|
</span>
|
||||||
{...sortProps}
|
</div>
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<SortDescendingOutlined
|
|
||||||
style={{ fontSize: '14px' }}
|
|
||||||
{...sortProps}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Button>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</Col>
|
|
||||||
|
|
||||||
{sqlQuery && (
|
|
||||||
<Col span={24}>
|
|
||||||
<AppliedFilterText
|
|
||||||
filterText={sqlQuery}
|
|
||||||
onEdit={() => toggleModal(true)}
|
|
||||||
/>
|
|
||||||
</Col>
|
</Col>
|
||||||
)}
|
|
||||||
</Row>
|
{sqlQuery && (
|
||||||
|
<Col span={24}>
|
||||||
|
<AppliedFilterText
|
||||||
|
filterText={sqlQuery}
|
||||||
|
onEdit={() => toggleModal(true)}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
)}
|
||||||
|
</Row>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<PageLayoutV1
|
||||||
|
className="p-0 explore-page-layout"
|
||||||
|
pageTitle={t('label.explore')}
|
||||||
|
rightPanel={
|
||||||
|
showSummaryPanel &&
|
||||||
|
entityDetails && (
|
||||||
|
<EntitySummaryPanel
|
||||||
|
entityDetails={{ details: entityDetails }}
|
||||||
|
handleClosePanel={handleClosePanel}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
rightPanelWidth={400}>
|
||||||
|
<Row className="p-t-xs">
|
||||||
|
<Col lg={{ offset: 3, span: 18 }} md={{ offset: 0, span: 24 }}>
|
||||||
|
{!loading ? (
|
||||||
|
<SearchedData
|
||||||
|
isFilterSelected
|
||||||
|
data={searchResults?.hits.hits ?? []}
|
||||||
|
filter={parsedSearch}
|
||||||
|
handleSummaryPanelDisplay={handleSummaryPanelDisplay}
|
||||||
|
isSummaryPanelVisible={showSummaryPanel}
|
||||||
|
selectedEntityId={entityDetails?.id || ''}
|
||||||
|
totalValue={searchResults?.hits.total.value ?? 0}
|
||||||
|
onPaginationChange={onChangePage}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Loader />
|
||||||
|
)}
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</Col>
|
</PageLayoutV1>
|
||||||
</Row>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<PageLayoutV1
|
|
||||||
className="p-0 explore-page-layout"
|
{searchQueryParam && tabItems.length === 0 && !loading && (
|
||||||
pageTitle={t('label.explore')}
|
<Space
|
||||||
rightPanel={
|
align="center"
|
||||||
showSummaryPanel &&
|
className="w-full flex-center full-height"
|
||||||
entityDetails && (
|
data-testid="no-search-results"
|
||||||
<EntitySummaryPanel
|
direction="vertical"
|
||||||
entityDetails={{ details: entityDetails }}
|
size={48}>
|
||||||
handleClosePanel={handleClosePanel}
|
<ErrorPlaceHolder
|
||||||
/>
|
className="mt-0-important"
|
||||||
)
|
type={ERROR_PLACEHOLDER_TYPE.FILTER}
|
||||||
}
|
/>
|
||||||
rightPanelWidth={400}>
|
</Space>
|
||||||
<Row className="p-t-xs">
|
)}
|
||||||
<Col lg={{ offset: 3, span: 18 }} md={{ offset: 0, span: 24 }}>
|
{searchQueryParam && tabItems.length === 0 && loading && <Loader />}
|
||||||
{!loading ? (
|
|
||||||
<SearchedData
|
|
||||||
isFilterSelected
|
|
||||||
data={searchResults?.hits.hits ?? []}
|
|
||||||
filter={parsedSearch}
|
|
||||||
handleSummaryPanelDisplay={handleSummaryPanelDisplay}
|
|
||||||
isSummaryPanelVisible={showSummaryPanel}
|
|
||||||
selectedEntityId={entityDetails?.id || ''}
|
|
||||||
totalValue={searchResults?.hits.total.value ?? 0}
|
|
||||||
onPaginationChange={onChangePage}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<Loader />
|
|
||||||
)}
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
{searchQueryParam && tabItems.length === 0 && !loading && (
|
|
||||||
<Space
|
|
||||||
align="center"
|
|
||||||
className="w-full h-full flex-center"
|
|
||||||
data-testid="no-search-results"
|
|
||||||
direction="vertical"
|
|
||||||
size={48}>
|
|
||||||
<ErrorPlaceHolder
|
|
||||||
className="mt-0-important"
|
|
||||||
type={ERROR_PLACEHOLDER_TYPE.FILTER}
|
|
||||||
/>
|
|
||||||
</Space>
|
|
||||||
)}
|
|
||||||
{searchQueryParam && tabItems.length === 0 && loading && <Loader />}
|
|
||||||
</PageLayoutV1>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -44,18 +44,18 @@ export const COMMON_DROPDOWN_ITEMS = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('label.service'),
|
label: t('label.service'),
|
||||||
key: 'service.name',
|
key: 'service.name.keyword',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const TABLE_DROPDOWN_ITEMS = [
|
export const TABLE_DROPDOWN_ITEMS = [
|
||||||
{
|
{
|
||||||
label: t('label.database'),
|
label: t('label.database'),
|
||||||
key: 'database.name',
|
key: 'database.name.keyword',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('label.schema'),
|
label: t('label.schema'),
|
||||||
key: 'databaseSchema.name',
|
key: 'databaseSchema.name.keyword',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('label.column'),
|
label: t('label.column'),
|
||||||
|
@ -1040,9 +1040,7 @@ const TagsPage = () => {
|
|||||||
{isUpdateLoading ? (
|
{isUpdateLoading ? (
|
||||||
<Loader />
|
<Loader />
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div className="p-x-md" data-testid="tags-container">
|
||||||
className="full-height page-container"
|
|
||||||
data-testid="tags-container">
|
|
||||||
{currentClassification && (
|
{currentClassification && (
|
||||||
<Row data-testid="header" wrap={false}>
|
<Row data-testid="header" wrap={false}>
|
||||||
<Col flex="auto">
|
<Col flex="auto">
|
||||||
|
@ -37,7 +37,6 @@ import React, {
|
|||||||
} from 'react';
|
} from 'react';
|
||||||
import { useHistory, useLocation, useParams } from 'react-router-dom';
|
import { useHistory, useLocation, useParams } from 'react-router-dom';
|
||||||
import { searchQuery } from 'rest/searchAPI';
|
import { searchQuery } from 'rest/searchAPI';
|
||||||
import useDeepCompareEffect from 'use-deep-compare-effect';
|
|
||||||
import {
|
import {
|
||||||
getCombinedQueryFilterObject,
|
getCombinedQueryFilterObject,
|
||||||
getUpdatedAggregateFieldValue,
|
getUpdatedAggregateFieldValue,
|
||||||
@ -51,10 +50,6 @@ import {
|
|||||||
} from '../../constants/explore.constants';
|
} from '../../constants/explore.constants';
|
||||||
import { SearchIndex } from '../../enums/search.enum';
|
import { SearchIndex } from '../../enums/search.enum';
|
||||||
import { Aggregations, SearchResponse } from '../../interface/search.interface';
|
import { Aggregations, SearchResponse } from '../../interface/search.interface';
|
||||||
import {
|
|
||||||
filterObjectToElasticsearchQuery,
|
|
||||||
isFilterObject,
|
|
||||||
} from '../../utils/FilterUtils';
|
|
||||||
import { showErrorToast } from '../../utils/ToastUtils';
|
import { showErrorToast } from '../../utils/ToastUtils';
|
||||||
import {
|
import {
|
||||||
QueryFieldInterface,
|
QueryFieldInterface,
|
||||||
@ -109,19 +104,6 @@ const ExplorePageV1: FunctionComponent = () => {
|
|||||||
[location.search]
|
[location.search]
|
||||||
);
|
);
|
||||||
|
|
||||||
const facetFilters = useMemo(
|
|
||||||
() =>
|
|
||||||
isFilterObject(parsedSearch.facetFilter)
|
|
||||||
? parsedSearch.facetFilter
|
|
||||||
: undefined,
|
|
||||||
[parsedSearch.facetFilter]
|
|
||||||
);
|
|
||||||
|
|
||||||
const elasticsearchQueryFilter = useMemo(
|
|
||||||
() => filterObjectToElasticsearchQuery(facetFilters),
|
|
||||||
[facetFilters]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handlePageChange: ExploreProps['onChangePage'] = (page, size) => {
|
const handlePageChange: ExploreProps['onChangePage'] = (page, size) => {
|
||||||
history.push({
|
history.push({
|
||||||
search: Qs.stringify({ ...parsedSearch, page, size: size ?? PAGE_SIZE }),
|
search: Qs.stringify({ ...parsedSearch, page, size: size ?? PAGE_SIZE }),
|
||||||
@ -197,14 +179,6 @@ const ExplorePageV1: FunctionComponent = () => {
|
|||||||
[history, parsedSearch]
|
[history, parsedSearch]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleFacetFilterChange: ExploreProps['onChangeFacetFilters'] = (
|
|
||||||
facetFilter
|
|
||||||
) => {
|
|
||||||
history.push({
|
|
||||||
search: Qs.stringify({ ...parsedSearch, facetFilter, page: 1 }),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleShowDeletedChange: ExploreProps['onChangeShowDeleted'] = (
|
const handleShowDeletedChange: ExploreProps['onChangeShowDeleted'] = (
|
||||||
showDeleted
|
showDeleted
|
||||||
) => {
|
) => {
|
||||||
@ -301,11 +275,10 @@ const ExplorePageV1: FunctionComponent = () => {
|
|||||||
fetchFilterAggregationsWithoutFilters();
|
fetchFilterAggregationsWithoutFilters();
|
||||||
}, [searchIndex]);
|
}, [searchIndex]);
|
||||||
|
|
||||||
useDeepCompareEffect(() => {
|
useEffect(() => {
|
||||||
const updatedQuickFilters = getAdvancedSearchQuickFilters();
|
const updatedQuickFilters = getAdvancedSearchQuickFilters();
|
||||||
|
|
||||||
const combinedQueryFilter = getCombinedQueryFilterObject(
|
const combinedQueryFilter = getCombinedQueryFilterObject(
|
||||||
elasticsearchQueryFilter as unknown as QueryFilterInterface,
|
|
||||||
updatedQuickFilters as QueryFilterInterface,
|
updatedQuickFilters as QueryFilterInterface,
|
||||||
queryFilter as unknown as QueryFilterInterface
|
queryFilter as unknown as QueryFilterInterface
|
||||||
);
|
);
|
||||||
@ -390,7 +363,6 @@ const ExplorePageV1: FunctionComponent = () => {
|
|||||||
sortValue,
|
sortValue,
|
||||||
sortOrder,
|
sortOrder,
|
||||||
showDeleted,
|
showDeleted,
|
||||||
elasticsearchQueryFilter,
|
|
||||||
searchIndex,
|
searchIndex,
|
||||||
page,
|
page,
|
||||||
size,
|
size,
|
||||||
@ -440,7 +412,6 @@ const ExplorePageV1: FunctionComponent = () => {
|
|||||||
return (
|
return (
|
||||||
<ExploreV1
|
<ExploreV1
|
||||||
aggregations={updatedAggregations}
|
aggregations={updatedAggregations}
|
||||||
facetFilters={facetFilters}
|
|
||||||
loading={isLoading && !isTourOpen}
|
loading={isLoading && !isTourOpen}
|
||||||
quickFilters={advancesSearchQuickFilters}
|
quickFilters={advancesSearchQuickFilters}
|
||||||
searchIndex={searchIndex}
|
searchIndex={searchIndex}
|
||||||
@ -454,7 +425,6 @@ const ExplorePageV1: FunctionComponent = () => {
|
|||||||
sortValue={sortValue}
|
sortValue={sortValue}
|
||||||
tabCounts={searchHitCounts}
|
tabCounts={searchHitCounts}
|
||||||
onChangeAdvancedSearchQuickFilters={handleAdvanceSearchQuickFiltersChange}
|
onChangeAdvancedSearchQuickFilters={handleAdvanceSearchQuickFiltersChange}
|
||||||
onChangeFacetFilters={handleFacetFilterChange}
|
|
||||||
onChangePage={handlePageChange}
|
onChangePage={handlePageChange}
|
||||||
onChangeSearchIndex={handleSearchIndexChange}
|
onChangeSearchIndex={handleSearchIndexChange}
|
||||||
onChangeShowDeleted={handleShowDeletedChange}
|
onChangeShowDeleted={handleShowDeletedChange}
|
||||||
|
@ -439,3 +439,7 @@ a[href].link-text-grey,
|
|||||||
.global-border-radius {
|
.global-border-radius {
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.full-height {
|
||||||
|
height: calc(100vh - 64px); // removing only navbar height
|
||||||
|
}
|
||||||
|
@ -828,27 +828,6 @@ body .list-option.rdw-option-active {
|
|||||||
|
|
||||||
/* EntityLineage Sidebar CSS */
|
/* EntityLineage Sidebar CSS */
|
||||||
|
|
||||||
.entity-lineage.sidebar {
|
|
||||||
height: 110%;
|
|
||||||
background: white;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100px;
|
|
||||||
z-index: 200;
|
|
||||||
overflow-y: auto;
|
|
||||||
padding: 8px;
|
|
||||||
transform: translateX(100%);
|
|
||||||
display: none;
|
|
||||||
border-right: 1px solid #d9ceee;
|
|
||||||
transition: transform 0.3s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.entity-lineage.sidebar.open {
|
|
||||||
transform: translateX(0);
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* login slider */
|
/* login slider */
|
||||||
|
|
||||||
.login-slider.slick-dots li.slick-active button:before {
|
.login-slider.slick-dots li.slick-active button:before {
|
||||||
|
@ -709,12 +709,6 @@ body .profiler-graph .recharts-active-dot circle {
|
|||||||
width: calc(100% - 330px);
|
width: calc(100% - 330px);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* page-container v1 */
|
|
||||||
|
|
||||||
.full-height {
|
|
||||||
height: calc(100vh - 110px);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 64 header + ( 16 + 16 )spacing Y = 96*/
|
/* 64 header + ( 16 + 16 )spacing Y = 96*/
|
||||||
#left-panel {
|
#left-panel {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
@ -17,6 +17,7 @@ import ProfilePicture from 'components/common/ProfilePicture/ProfilePicture';
|
|||||||
import { SearchDropdownOption } from 'components/SearchDropdown/SearchDropdown.interface';
|
import { SearchDropdownOption } from 'components/SearchDropdown/SearchDropdown.interface';
|
||||||
import i18next from 'i18next';
|
import i18next from 'i18next';
|
||||||
import {
|
import {
|
||||||
|
Bucket,
|
||||||
ContainerSearchSource,
|
ContainerSearchSource,
|
||||||
DashboardSearchSource,
|
DashboardSearchSource,
|
||||||
ExploreSearchSource,
|
ExploreSearchSource,
|
||||||
@ -389,3 +390,15 @@ export const getOptionTextFromKey = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getOptionsFromAggregationBucket = (buckets: Bucket[]) => {
|
||||||
|
if (!buckets) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return buckets.map((option) => ({
|
||||||
|
key: option.key,
|
||||||
|
label: option.key,
|
||||||
|
count: option.doc_count ?? 0,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user